あなたは何にトキメキますか?

コンパイラは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();
直後に落ちてしまいます。

また、別のプロジェクトでも、最適化オプションなしなら正常に動くのですが、最適化オプションを付けると、そちらは初期化関数サイドを抜ける瞬間には落ちてしまいます。

アセンブリ出力を見ても、関数名とかはそのまま書かれている分に感じるので、どこがまずいのかよく分かりません。

これらはどのように対処すればいいのでしょうか?

あるいは、書き方自体が間違っている(未定義動作になる)部分があるのでしょうか?

A 回答 (2件)

WindowsAPIの呼び出し規約はstdcallで、VC++のデフォルトの呼び出し規約はcdeclです。


ですので、stdcallを指定しなければ、stdcallの関数をcdeclで呼んでしまいおかしなことになります。
ですので、
typedef HRESULT (__stdcall * Func)( LPVOID );
みたいにする必要があります。

WindowsAPIならこっちの方が良いかも知れません。
typedef HRESULT (WINAPI * Func)( LPVOID );

この回答への補足

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

補足日時:2010/03/23 17:20
    • good
    • 0
この回答へのお礼

なるほど!
そういえば数回無意識に触れていたようですが、呼び出し規約という概念自体、あまりよく知らなかったです。
これを機に調べてみて納得しました。

また、jgkさんのおっしゃる通りWindowsAPI用に呼び出し規約を指定することで、どちらのプロジェクトも問題なく動作するようになりました。

ただ、質問文のコードのLoadLibrary、FreeLibraryの使い方が、この場合は問題ないのかあるのかはやはり気になるので、最大で数日程度締め切りを待たせてください。

お礼日時:2010/03/23 17:17

CoInitializeとCoUninitializeを別の


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

ありがとうございます。


分かりやすくグローバルな位置(とかただの名前空間内)に持ってきて、初期化サイドから
FreeLibrary

後始末サイドから
LoadLibrary

を消して「最適化オプション付き」でやってみると、今度は「初期化関数を抜けるときに」確実に落ちるようになりました。

最適化オプションなしならやはりhDLLが同じ変数であってもなんら問題はありません。

LoadLibraryについて
http://msdn.microsoft.com/ja-jp/library/cc429241 …

HMODULEというのは文字通りモジュールハンドルなのでDLLを必要に応じてロードしたり解放したり、というのは意味的にも問題ないと思っていましたが、逆に(COMの初期化、後始末が関係するという点で)上記質問文のコードの場合は問題がある、という記述はあるのでしょうか?

いちおう質問文でのコードではアドレスが一致するか調べてみましたが


TCHAR c[100];
_stprintf_s(c,100,_T("%p"),hDLL);
_tprintf(c);


別のインスタンスで実行して、同じアドレスが得られました。

やはり最適化でどっかが浸食されてるんじゃないかな…

お礼日時:2010/03/23 15:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報