WinXP(SP3) VC++6.0
Win32DLLを、テスト用MFCプログラムから呼び出すと下記のような現象になります。
・DebugモードでビルドしたDLLは、正常に動作する
・ReleaseモードでビルドしたDLLに置き換えて呼び出すとLoadLibrary()が0x00を返す
dumpbin /EXPORTS (DLL名)にて確認してみましたが、Debug/Release両モジュール共に
意図した関数の名前が表示されているような状況です。
呼び出し側に問題があるのか、DLL側の問題なのかすら分からず困っています。
何が原因で、どうすれば解決(Releaseモジュールの正常呼び出し)できるか
お心当たりのある方いらっしゃいましたら、ヒントだけでも宜しくお願いします。
GetLastError()又は、ウオッチでの@err,hrはなんと言ってますか(質問)。
>>仲澤@失業者さん
LoadLibrary()を実行する行にブレークポイントを挿入し、ステップ実行(F10)した直後の
@errは。。。
---
@err→1114
@err,hr→0x0000045aダイナミック リンク ライブラリ(DLL)初期化ルーチンの実行に失
敗しました。
---
でした。
DLLがDEBUGモードでビルドされているとかないですか?
>>ITOさん
「DLLがDEBUGモードでビルドされている」と、上手く動作するのですが
ReleaseモードでビルドしたDLLに置き換えると動作しないのです。><;
ちなみに、DLLがDebugモードでビルドされたモジュールであれば、
呼び出し側のテスト用MFCプログラムはDebug/Release両方で動作します。
なるほど、
となると、
・new-delete等の処理がうまくいってますか?
・GlobalAlloc、HeapAlloc等を使った後、
----Free()を呼び出していますか?
ぐらいが考えられますね。
あと、配列変数の要素数が足りないとか?
調べてみるといいかなとおもいます。
一回、暗黙的リンクで動作するか確かめてみるのもいいと思います。
>>ITOさん
ありがとうございます。
しかしながら、DLLの呼び出し部分は下記のようなコーディングとなっており
GlobalAlloc、HeapAlloc等は使用していない状況です。
暗黙的リンクも、DebugビルドのDLLで正常に動作しているので何とも。。。
---
【DLLのヘッダファイル(dll.h)】
typedef void (*LPFUNC1)(構造体A *, 構造体B *);
【呼び出し側のテスト用MFCプログラムのDLL呼び出し部分(抜粋)】
HMODULE mHandle;
LPFUNC1 pFunc;
static 構造体A paramIn;
static 構造体B paramOut;
[paramInの設定、paramOutの初期化など]
★ mHandle = ::LoadLibrary( DLL名 );
pFunc = (LPFUNC1)GetProcAddress( mHandle, 関数名 );
pFunc( ¶mIn, ¶mOut );
FreeLibrary( mHandle );
---
DebugモードでビルドしたDLLなら、想定通りにparamInの内容が
DLLの関数名で指定した処理に引き渡され、paramOutにDLL内で
設定した戻り値などが格納されて返ってくるのですが
ReleaseでビルドしたDLLに置き換えると★の行でmHandleにNULLが
返されてしまいます。。。
>GlobalAlloc、HeapAlloc等は使用していない状況です。
DLL内の処理で使っていないですか。
説明不十分でした。 DLL内の処理です。
GlobalAlloc、HeapAlloc等だけでなく、「CloseHandle」等も
呼び出していますか。
つまり、後処理を行なっていないところはないか調べておいたほうがいいと
思います。
>暗黙的リンクも、DebugビルドのDLLで正常に動作しているので何とも。。。
ReleaseでビルドしたDLLでも動作しますか?
エラー値が ERROR_DLL_INIT_FAILED なのだから DllMain()のほうも検証してみては?
FlatWestさんに一票
1.DllMain( HINSTANCE i, DWORD r, LPVOID v)の「r」に依存した
処理を全てコメントアウトしてください。なければOK。
2.エクスポートされる関数を1つだけにして、他を全て
コメントアウトしてください。
3.当然*.defファイルの定義も上と矛盾しないようにします。
4.EXE側でのGetProcAddress()は残した関数だけにします。
5.mHandle = ::LoadLibrary( DLL名 ); のDLL名の部分から
パスの指定を削除します。つまり当該DLLがMyDllなら
::LoadLibrary( MyDll.dll ); とします。
6.プロセスが残らないように、PCをリスタートします。
7.EXEの実行ファイルのあるフォルダに当該のDLL(デバッグ/リリース)が
それぞれコピーされていることを確認してデバッグ実行します。
と、やってみてはどうでしょう。
すみません。
1.DllMain( HINSTANCE i, DWORD r, LPVOID v)の「r」に依存した
処理を全てコメントアウトしてください。なければOK。
戻り値は常にTRUEにします。
に修正
直接の回答ではないですが、
私が以前にはまったのは、エクスポートされた関数の
関数実体の引数とtypedefで指定した引数が違っていたときです。
やはり、デバッグ版は正常動作し、リリース版は異常終了しました。
そのときは、
確か関数実体側でint型の省略可能な引数(= 0とか指定するやつね)を
付け足して、省略可能な引数なんだから、試しにtypedef側は指定な
しでやってみてデバッグ版が動作したから、大丈夫だ(^-^)といい気
になってて、ある日リリ-ス版が落ちたときには、そんなこと忘れて
て、大パニックになりました(笑)。
>>ITOさん
いえいえ、こちらこそ申し訳ございません。
DLL内部では、動的なメモリ確保/解放をcalloc()とfree()にて行っており
CloseHandle()は、どこにも記載されていない状態でした。
また、ReleaseでビルドしたDLLを暗黙的リンクで呼び出すと、下記のエラーとなりまし
た。。。
「アプリケーションを正しく初期化できませんでした(0xc0000142)。[OK]をクリックして
アプリケーションを終了してください。」
「ハンドルされていない例外 は テスト用MFCプログラム名.exe (NTDLL.DLL)にありま
す:0xC0000142: DLL Initialization Failed。」
>>FlatWestさん
DLL側のコーディングは下記のような状態で。。。
---
void 関数名( 構造体A *paramIn, 構造体B *paramOut )
{
(略)
}
extern C
void APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
(static変数のインクリメント処理)
break;
case DLL_PROCESS_DETACH:
(static変数のデクリメント処理)
break;
}
return;
}
---
.DEFファイルにて関数名を外部から使用できる設定にしています。
---
LIBRARY 関数名
DESCRIPTION '関数名 Win32 Dynamic Link Library'
SECTIONS
.shared1 READ WRITE SHARED
EXPORTS
; 明示的なエクスポートはここへ記述できます
関数名 @1
---
ひょっとして何か根本的に間違っていたりしますでしょうか。。。
>>仲澤@失業者さん
ありがとうございます!
ReleaseでビルドしたDLLが上手く動作しました!!!
>>1.DllMain( HINSTANCE i, DWORD r, LPVOID v)の「r」に依存した
>> 処理を全てコメントアウトしてください。なければOK。
>> 戻り値は常にTRUEにします。
>>2.エクスポートされる関数を1つだけにして、他を全て
>> コメントアウトしてください。
>>3.当然*.defファイルの定義も上と矛盾しないようにします。
>>4.EXE側でのGetProcAddress()は残した関数だけにします。
>>5.mHandle = ::LoadLibrary( DLL名 ); のDLL名の部分から
>> パスの指定を削除します。つまり当該DLLがMyDllなら
>> ::LoadLibrary( MyDll.dll ); とします。
>>6.プロセスが残らないように、PCをリスタートします。
>>7.EXEの実行ファイルのあるフォルダに当該のDLL(デバッグ/リリース)が
>> それぞれコピーされていることを確認してデバッグ実行します。
1.return;のみ残してすべてコメントアウトしてみました。
2.元の状態がDLL内に関数が1つだけだったので変更しませんでした。
3.*.defファイルも関数1つのみだったので変更しませんでした。
4.呼び出しexe側でのGetProcAddress()も関数1つのみでしたので、そのままです。
5.::LoadLibrary( DLL名 );の「DLL名」部分はパスを含んでいない記述
でしたので、これもそのままにしました。
6.PCを再起動する前に試行してみました。
7.ReleaseでビルドしたDLLが上手く動作しました!!!
さらに検証してみた所、DllMain()内の
・(static変数のインクリメント処理)
・(static変数のデクリメント処理)
の部分のみコメントアウトする事でも、ReleaseでビルドしたDLLが正常に
動作しました。
まだ根本的な理由と仕組みが理解できていない状態ではありますが
本件を「解決」にさせていただきたいと思います。
>>ご意見をくださったみなさま
ほんとうにありがとうございました。
>>bunさん
まさに
>>デバッグ版が動作したから、大丈夫だ(^-^)
の状況でした。(大汗
ありがとうございました。