Seasons.NET

ちょっとした技術ブログです

Undecorating names to see why a function can't be found

Undecorating names to see why a function can't be found
装飾されていない関数が見つからないエラー


元ネタ
“The Old New Thing : Undecorating names to see why a function can't be found”
http://blogs.msdn.com/oldnewthing/archive/2008/12/29/9255240.aspx



これは実際におきた問題です。

When I build my project, it compiles fine, but it fails during the link step with an unresolved external:

program.obj : error LNK2001: unresolved external symbol
"public: virtual wchar_t const * __thiscall
UILibrary::PushButton::GetName(class UILibrary::StringHolder * *)"
(?GetName@PushButton@UILibrary@@UAEPB_WPAPAVStringHolder@2@@Z)
The function I'm trying to call exists in the source code for uilibrary.lib; I'm looking at it right now. And the definition in the source code matches the declaration in the header file:

namespace UILibrary {
 ...
 class PushButton {
 public:
  virtual LPWSTR GetName(StringHolder **Holder);
 };
 ...
}
Why can't the linker find it? (Other functions in uilibrary.lib link just fine.)


何かをみつける(リンクする)には、適切な場所を探す必要があり、
実際探している物はそこにないといけない。
そしてそれがそこにある場合、確認できないといけない。


まず適切な場所をみてみると、それは正しく配置されているようにみうけられる。
リンカーはどうにかuilibrary.libの中で他のものを見つけたのでそれを見ている。


次にあなたは、本当に正しい場所を見ているだろうか?
私は、uilibrary.libをバイナリエディタで確認しましたしかし、
そこでは文字列を使う事ができません。
もしあなたが装飾文字列がほしいならば、link /dump /headersを実行します。
そして、GetName@PushButtonがそのライブラリのメンバ関数として存在するならば
当然確認できるとと思い探してみました。


確かに関数はある、だがそれは見た目だけで実は違う。
GetName@PushButton@UILibrary@@UAEPBGPAPAVStringHolder@2@@Z
あら?そのシンボルは、そこに全く存在していないのでみつからないではないか!!
表面的に似ているが実は違った装飾がされている。


私たちは、undnameを利用してこの名前をコンバートして調査をしてみた。


C:\> undname ?GetName@PushButton@UILibrary@@UAEPBGPAPAVStringHolder@2@@Z
public: virtual unsigned short const * __thiscall
UILibrary::PushButton::GetName(class UILibrary::StringHolder * *)

2つの関数をよく見てほしい。
一方は、wchar_t* const *を返すのに、片方は、unsigned short const *を
返す事になっている。


これではっきりした。
そのライブラリは、/Zc:wchar_t-* flagをつけてコンパイルされている。
これにより私達のプログラムは、wchar_tをネイティブ型として扱うが
利用したお客様のライブラリは、それが有効になっていないので、Windows.hを
includeしたときに、wchar_t -> unsigned shortとしてtypedefされたのだ。


よってあなたは、似たようなこのエラーのケースを解決する十分な知識を得た。

When I build my project, it compiles fine, but it fails during the link step with an unresolved external:
program.obj : error LNK2019: unresolved external symbol
"long __cdecl UILibrary::Initialize(bool)"
(?Initialize@UILibrary@@YAJ_N@Z)


つまりこれは、long __stdcall UILibrary::Initialize(bool)に装飾されていない為だ。


Note:
undname プログラムや/Zc:wchar_t-スイッチは、マイクロソフトのVisualStudioC++
固有のものである。
もし、他のコンパイラを使う場合は、あなたは、ユーティリティソフトや
コマンドラインスイッチを適切に指定すべきである。
VisualStudioを使う場合、C/C++言語の設定におけるwchar_tをビルトインタイプとして
扱うという設定にあたることを伝えておこう。