none
DLLのエクスポート関数が修飾(?)されてしまう RRS feed

  • 質問

  • お世話になります。

    VS2008のWIN32プロジェクト(C++)でDLLを作成しました。

    ・実体
    extern "C" long WINAPI FuncA( void )
    {
     return 0;
    }
    ・DEFファイル

    LIBRARY "InstHelper"
    EXPORTS
       FuncA @1


    このDLLのメソッドFuncAを、別のプロジェクトからLoadLibrary,GetProcAddressを使用してコールしようとしているのですが、
    GetProcAddressで、関数名を渡すと失敗します。
    //失敗する
    GetProcAddress(hDLL,(LPCSTR)_T("FuncA"));
    //成功する
    GetProcAddress(hDLL,(LPCSTR)1);

    取得に成功するほうで、変数をウォッチ式でみると ”_FuncA@0”となっていました。

    dumpbinでは、

      ordinal hint RVA      name

             1    0 00011109 FuncA = @ILT+260(_FuncA@0)

    となっており、修飾されているように思えます。


    修飾されないようにするには同氏らよいでしょうか。


    2010年1月20日 5:32

回答

  • 一番チェックが楽なのは、Dependency Walker ですかね。VS2008からは添付されていませんが、オリジナルが公開されていますので入手は可能です。

    コンパイルオプションをデフォルトのままとしているのであれば、MSVCR90.DLL が必要ですので、スタティックリンクするように変更する必要があると思います。
    もちろん、必須コンポーネントなどであらかじめ入れてしまえばその限りではありませんが...
    おそらく引っ掛かるとしたらこのあたりでしょう。
    それと、当り前ですが、デバッグ版は再配布できませんのでそのあたりも注意が必要です。

    基本はそのあたりかなぁ?
    プラットフォームの依存度という点では、Native C++のプロジェクトに限って言えば、そのソリューション構成が参照できる人以外誰にもわかりません。
    それくらい、どうにでもできてしまう自由度があるということでもあるわけですが。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク OTAKA 2010年1月21日 0:27
    2010年1月20日 7:28
  • 回答ついてるけど。。。

    msvcr90.dll など、Native C++ の実行に必要なランタイムインストーラは、vcredist_x86.exe というやつがあります。
    ISでも事前インストールは可能です。

    ですが
    ISから使う=インストーラで利用する=インストーラの動作するタイミングは強制できない=いつどんなタイミングで実行されても困らないようにしておく必要がある
    という方程式があります。

    ですので、スタティックリンクしておく必要があります。
    ただし、それはあくまでもインストーラから利用するDLLの話であり、インストールするアプリケーションについては、
    マージモジュールがあるので、それを付けてインストーラを作ることをお勧めします。

    また、その場合、必ず PerMachine でインストールする必要があるので、その点も注意してください。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク OTAKA 2010年1月21日 4:38
    2010年1月21日 1:44
  • ご返事ありがとうございます。

    確かに、msvcr90.dllがないために実行できないことがわかりました。

    しかし、msvcr90.dll単体ファイルは、再配布禁止ファイルらしく、
    また、NETFramework3.5をインストールすることで解決するのですが、WIN32アプリケーションで、そのようなことをしたくないので、
    コンパイルオプションを /MTにして静的リンクをおこなうことで、解決できました。

    ありがとうございました。

    自分のマシン環境からは、ISからDLLのメソッドを実行できており、テストマシンでは、「DLLが見つからない」等のメッセージが表示され、
    ISの問題かと混乱もして、行き詰っており助かりました。

    ありがとうございました。

    • 回答としてマーク OTAKA 2010年1月21日 0:21
    2010年1月21日 0:21

すべての返信

  • defファイルは正しく設定されていますか?
    プロジェクトのプロパティのリンカ-入力にある、モジュール定義ファイルに作成した def ファイルが指定されているかを確認してみてください。

    また、この場合、DLLのファイル名は、InstHelper.dll となっていなければいけませんがその部分は問題ありませんか?
    それも併せてチェックしておくとよいと思います。

    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年1月20日 5:54
  • ご返答ありがとうございます。お世話になります。

    とりあえず取得することができました。
    GetProcAddressの第2引数の関数名で_T("FuncA")としていたことに原因がありました。

    プロジェクト自体は、unicodeでコンパイルされるため、_T(””)は 、L""となり リテラル文字はUnicode文字列になり、
    GetProcAddressの第2引数が、const char*を要求しているので、合致しなかったと思われます。
    _T()をはずすと取得できました。

    ここで「とりあえず」としている理由なのですが、dumpbinでの表示では、
     1    0 00011109 FuncA = @ILT+260(_FuncA@0)となっており、修飾されているように見えますが、
    問題ないのでしょうか・・・

    このDLLの実際の使われ方は、InstallShieldから使用される予定なのです。

    2010年1月20日 6:41
  • あ...キャストしてますね。原因そっちでしたか。ちゃんと見てなかった...orz


    FuncA = ... は、この名前はどいつだ!という一種のリンクテーブルのようなものだったと記憶しています。
    呼び出しができる(ISに指定してきちんと利用できる)のであれば、特に意識するような部分ではありません。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年1月20日 6:57
  • ご返事ありがとうございます。

    VS2008で作成したDLLは、ISから呼べませんでした。
    VC6で作成したDLLは呼べています。

    VS2008で作成したDLLは、プラットフォームにどの程度依存しますか。
    依存しない方法ってありますか。

    調査するため、EXEとDLLをXPSP2にコピーして起動すると、アプリケーションの構成が・・・といわれます。

    どちらもMFCを使用しない、WIN32プロジェクトなのですが、依存関係のファイルってわかるのでしょうか。

    2010年1月20日 7:19
  • 一番チェックが楽なのは、Dependency Walker ですかね。VS2008からは添付されていませんが、オリジナルが公開されていますので入手は可能です。

    コンパイルオプションをデフォルトのままとしているのであれば、MSVCR90.DLL が必要ですので、スタティックリンクするように変更する必要があると思います。
    もちろん、必須コンポーネントなどであらかじめ入れてしまえばその限りではありませんが...
    おそらく引っ掛かるとしたらこのあたりでしょう。
    それと、当り前ですが、デバッグ版は再配布できませんのでそのあたりも注意が必要です。

    基本はそのあたりかなぁ?
    プラットフォームの依存度という点では、Native C++のプロジェクトに限って言えば、そのソリューション構成が参照できる人以外誰にもわかりません。
    それくらい、どうにでもできてしまう自由度があるということでもあるわけですが。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク OTAKA 2010年1月21日 0:27
    2010年1月20日 7:28
  • 調査するため、EXEとDLLをXPSP2にコピーして起動すると、アプリケーションの構成が・・・といわれます。
    どちらもMFCを使用しない、WIN32プロジェクトなのですが、依存関係のファイルってわかるのでしょうか。
    ランタイム(Visual C++ 2008 再頒布可能パッケージなどでインストールするもの)が入っていないことからそのエラーメッセージが表示されているのでしょう。
    先にランタイムをインストールするか、とっちゃんさんが言われているようにスタティックリンクにする必要があります。

    参考
    http://msdn.microsoft.com/ja-jp/library/2kzt1wy3.aspx
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月20日 13:52
    モデレータ
  • ご返事ありがとうございます。

    確かに、msvcr90.dllがないために実行できないことがわかりました。

    しかし、msvcr90.dll単体ファイルは、再配布禁止ファイルらしく、
    また、NETFramework3.5をインストールすることで解決するのですが、WIN32アプリケーションで、そのようなことをしたくないので、
    コンパイルオプションを /MTにして静的リンクをおこなうことで、解決できました。

    ありがとうございました。

    自分のマシン環境からは、ISからDLLのメソッドを実行できており、テストマシンでは、「DLLが見つからない」等のメッセージが表示され、
    ISの問題かと混乱もして、行き詰っており助かりました。

    ありがとうございました。

    • 回答としてマーク OTAKA 2010年1月21日 0:21
    2010年1月21日 0:21
  • 回答ついてるけど。。。

    msvcr90.dll など、Native C++ の実行に必要なランタイムインストーラは、vcredist_x86.exe というやつがあります。
    ISでも事前インストールは可能です。

    ですが
    ISから使う=インストーラで利用する=インストーラの動作するタイミングは強制できない=いつどんなタイミングで実行されても困らないようにしておく必要がある
    という方程式があります。

    ですので、スタティックリンクしておく必要があります。
    ただし、それはあくまでもインストーラから利用するDLLの話であり、インストールするアプリケーションについては、
    マージモジュールがあるので、それを付けてインストーラを作ることをお勧めします。

    また、その場合、必ず PerMachine でインストールする必要があるので、その点も注意してください。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク OTAKA 2010年1月21日 4:38
    2010年1月21日 1:44
  • ご返事ありがとうございます。

    今回のDLLはインストーラで利用するため、スタティックリンクすることにします。

    といいながら、VC6から移植するプログラムもスタティックリンクで対応しようと思っていたので、
    マージモジュールがあるという情報は助かります。

    ありがとうございました。

    2010年1月21日 4:41
  • VS2002(VC7.0)からは、VSをインストールするとマージモジュールも自動で
    [CommonFilesFolder]Merge Modules にインストールされます。<わざと msiチックな書き方してますw

    InstallShieldのバージョンによってはInstallShieldにも添付されているかもしれませんが、どのバージョンから添付してるかはわかりません。
    ISにない場合でも、ISのマージモジュールサーチリスト内に利用したいマージモジュールを入れておけば、利用できますので、どんなものがあるのかチェックしておくことをお勧めします。

    ただし!.NET Framework のマージモジュールはブロックようなので、再配布可能モジュールではありませんのでご注意を。

    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年1月21日 5:10
  • ここで「とりあえず」としている理由なのですが、dumpbinでの表示では、
     1    0 00011109 FuncA = @ILT+260(_FuncA@0)となっており、修飾されているように見えますが、
    問題ないのでしょうか・・・
    この場合 FuncA() は__stdcall呼び出し規約でコンパイルされました。
    従って、使用する場合はプロトタイプを宣言し、その宣言でFuncA()が__stdcallであることを
    「明示的に」指定する必要があります。

    typedef void ( ___stdcall *p_FuncA)(); // WINAPIが__stdcallならそれを使っても良い
       :
    p_FuncA = GetProcAddress( DLL_Instance, "FuncA");

    修飾は必ずされます。
    最もシンプルな修飾になるものは __cdecl ですが、C/C++ネイティブからしか使用できなくなります。
    何も指定しない場合のクラスメンバでない関数はコンパイラオプション/Gd、/Gz、/Gr、で指定されたものとなります。
    デフォルトは/Gdで全て __cdeclなります。

    2010年1月21日 10:30