• ベストアンサー

最適化オプションと LoadLibrary(あるいはCoInitialize関連?)などを組み合わせると…

コンパイラはVisual C++ 2008 Express Editionです。 以下のようなコードを書くと #include <windows.h> #include <stdio.h> #include <tchar.h> #include <commctrl.h> #pragma comment ( lib, "comctl32.lib") HRESULT InitCOM_Ole32(){ //初期化 HMODULE hDLL( LoadLibrary(_T("Ole32.dll")) ); if (!hDLL) return E_FAIL; typedef HRESULT (*Func)( LPVOID ); Func func = (Func)GetProcAddress(hDLL,"CoInitialize"); HRESULT hr( func( 0 ) ); FreeLibrary( hDLL ); return hr; } void UnInitCOM_Ole32(){ //後始末 HMODULE hDLL( LoadLibrary(_T("Ole32.dll")) ); if (!hDLL) return; void (*func)() = (void (*)())GetProcAddress(hDLL,"CoUninitialize"); func(); FreeLibrary( hDLL ); } int main(){ InitCOM_Ole32(); InitCommonControls(); UnInitCOM_Ole32(); getchar(); return 0; } 最適化オプションが無効なら問題ないのですが、最適化オプションを付けると getchar(); 直後に落ちてしまいます。 また、別のプロジェクトでも、最適化オプションなしなら正常に動くのですが、最適化オプションを付けると、そちらは初期化関数サイドを抜ける瞬間には落ちてしまいます。 アセンブリ出力を見ても、関数名とかはそのまま書かれている分に感じるので、どこがまずいのかよく分かりません。 これらはどのように対処すればいいのでしょうか? あるいは、書き方自体が間違っている(未定義動作になる)部分があるのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • jgk
  • ベストアンサー率75% (104/138)
回答No.2

WindowsAPIの呼び出し規約はstdcallで、VC++のデフォルトの呼び出し規約はcdeclです。 ですので、stdcallを指定しなければ、stdcallの関数をcdeclで呼んでしまいおかしなことになります。 ですので、 typedef HRESULT (__stdcall * Func)( LPVOID ); みたいにする必要があります。 WindowsAPIならこっちの方が良いかも知れません。 typedef HRESULT (WINAPI * Func)( LPVOID );

LongSecret
質問者

お礼

なるほど! そういえば数回無意識に触れていたようですが、呼び出し規約という概念自体、あまりよく知らなかったです。 これを機に調べてみて納得しました。 また、jgkさんのおっしゃる通りWindowsAPI用に呼び出し規約を指定することで、どちらのプロジェクトも問題なく動作するようになりました。 ただ、質問文のコードのLoadLibrary、FreeLibraryの使い方が、この場合は問題ないのかあるのかはやはり気になるので、最大で数日程度締め切りを待たせてください。

LongSecret
質問者

補足

あ、あまりにgoodjobすぎて書き忘れてましたw ありがとうございます♪

その他の回答 (1)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.1

CoInitializeとCoUninitializeを別の インスタンスで実行して大丈夫なんですか? 普通に考えると気持ち悪いですね。 何かMSのドキュメントで保証されているので しょうか? 同じインスタンスで実行するようにhDLLを 大域変数として、後処理でのみFreeLibraryを 実行するように修正してみたらどうなりますか?

LongSecret
質問者

お礼

ありがとうございます。 分かりやすくグローバルな位置(とかただの名前空間内)に持ってきて、初期化サイドから FreeLibrary を 後始末サイドから LoadLibrary を消して「最適化オプション付き」でやってみると、今度は「初期化関数を抜けるときに」確実に落ちるようになりました。 最適化オプションなしならやはりhDLLが同じ変数であってもなんら問題はありません。 LoadLibraryについて http://msdn.microsoft.com/ja-jp/library/cc429241.aspx HMODULEというのは文字通りモジュールハンドルなのでDLLを必要に応じてロードしたり解放したり、というのは意味的にも問題ないと思っていましたが、逆に(COMの初期化、後始末が関係するという点で)上記質問文のコードの場合は問題がある、という記述はあるのでしょうか? いちおう質問文でのコードではアドレスが一致するか調べてみましたが TCHAR c[100]; _stprintf_s(c,100,_T("%p"),hDLL); _tprintf(c); 別のインスタンスで実行して、同じアドレスが得られました。 やはり最適化でどっかが浸食されてるんじゃないかな…

関連するQ&A