人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

【特定の条件の時だけVB6のDLL呼び出しが失敗する現象】
以下構成のプログラムでDLL1が存在しない時に、DLL2側の異常処理が予定通り動作するか
確認しようとしたのですが、

VB6製のプログラムを実行すると

>『実行時エラー'53'』:
>ファイルが見つかりません。
>c:\xxxxxxxxxxDLL3.dll

が表示されます。

DLL1が存在しない設定にする前まではDLL1?3まで正常に呼び出せることを確認していますので
原因が解りません。
また、DLL1をインストールすると上記エラーは発生しなくなります。

この現象について調査する方法(もしくは説明)などを教えて頂きたく宜しくお願いします。

<プログラムの構成>

・???製のDLL1・・・・API群のDLL(既存リソース)
・VC6製のDLL2・・・・DLL1を簡単に使うためのラッパーDLL(既存リソース)
・VC6製のDLL3・・・・DLL2をVBから呼び出すためのラッパーDLL
・VB6製のプログラム・・・DLLにパラメータを渡し処理結果を表示する

<処理の流れ>

VB6製プログラム→VC6製のDLL3→VC6製のDLL2→???製のDLL1

備考1:DLLが全て存在する場合はプログラムからDLL1?3まで正常に呼び出せることを確認している。


●質問者: harunoharuno
●カテゴリ:コンピュータ
✍キーワード:API DLL VB vb6 インストール
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● mj99
●250ポイント ベストアンサー

DLL3、DLL2は、依存するDLLに対し、pragma commentによるlib指定か、リンクオプションでlibを指定していると推測します。


これは「暗黙的リンク」と呼ばれます。

http://msdn.microsoft.com/ja-jp/library/253b8k2c(VS.80).aspx

動的にリンクされた参照を含むプログラムが起動されると、プログラムの実行可能ファイル内の情報に従って、必要な DLL を探します。DLL が見つからないと、システムは処理を停止し、ダイアログ ボックスを表示して、エラーを報告します。見つかった場合は、DLL モジュールがプロセスのアドレス空間に割り当てられます。

今回の場合、DLL3のロードで、DLL2も同時にロードされます。同様にDLL2のロードでDLL1がロードされます。


----

遅延ロードの指定を試してください。

昔は無かった機能ですが、pragmaの指定で「明示的リンク」を代替できます。

http://msdn.microsoft.com/ja-jp/library/151kt790(VS.80).aspx


DLL3のどこかに

#pragma comment(lib, "delayimp.lib")
#pragma comment(linker, "/DELAYLOAD:dll2.dll")

と、書いておき、


DLL2には

#pragma comment(lib, "delayimp.lib")
#pragma comment(linker, "/DELAYLOAD:dll1.dll")

と、書いておきます。


このpragma指定で、DLL内関数を使用する直前でDLLがロードされるようになります。

(DLL3をロードするとき、DLL2はロードされない)

(DLL2をロードするとき、DLL1はロードされない)


結果、DLL3のロードでDLL1の不在例外が上がることはありません。

(DLL1のDLL内関数を使用する直前で例外が上がる)

◎質問者からの返答

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

とりあえず

VB側にDLL呼び出し失敗のときのための

goto Errorを作成していましたが

原因が分からず、非常に気になっている問題でした。

ご指摘の通り、

以下のDLLはlibを指定してリンクしています。

・VC6製のDLL2・・・・DLL1を簡単に使うためのラッパーDLL(既存リソース)

・VC6製のDLL3・・・・DLL2をVBから呼び出すためのラッパーDLL

遅延ロードを行えば、DLL内で異常処理も記述できるのですね。

すっきりしました。


2 ● ardarim
●250ポイント

VC6のDLLは静的リンクをしているようですね。

静的リンクの場合、カーネルはプログラムの開始時にすべてのDLLをロードし、アドレス解決を行います。

そのため、VB6→DLL3→DLL2→DLL1のようにDLLが静的リンクで依存関係になっている場合、ロード順(アドレス解決順)は、DLL1→DLL2→DLL3→VB6の順番で行われます。(DLL1が一番最初にロードされる)


そのため、DLL1自体が存在しない場合は、DLL2がロードできず、DLL2がロードできないとDLL3がロードできず、DLL3がロードできないため、結果的に「DLL3がロードできない」というエラーになります。(「ファイルが見つからない」というのは本来あまり適切なメッセージではありません。正しくは、「リンクしているDLLのいずれかのファイルが見つからない」とでも言うべきです)


DLL1が存在しないことをDLL2で検出して異常処理を行いたいということであれば、DLL2からDLL1を静的リンクせず実行時リンクを行う必要があります。


静的リンクの場合は、カーネルがすべてのアドレス解決を行いますので、DLLが存在しない場合は検出できません(プログラム自体起動できない)

実行時リンクは、DLLのアドレス解決をカーネルに任せるのではなく、自分自身が行う必要があります。LoadLibraryでDLLを指定してロードし、GetProcAddressでDLL内の関数へのポインタを取得します。DLLが存在しない場合はLoadLibraryがエラーコードを返しますので、適切な異常処理を行うことができます。


静的リンクではなく実行時リンクを使うには、例えば以下のようなページを参考にしてください。

VC++「DLL作成/呼出方法」メモ(Hishidama's VC++Memo "DLL")

実行時リンク LoadLibrary」等のキーワードで検索してもたくさん見つかります。




なお、DLL内のDllMainは、そのDLLが完全にロード完了(静的リンクしているすべてのDLLがロードされアドレス解決された状態)した後に初めて呼び出されますので、静的リンクしているDLLの1つでもロードできなかった場合はロードが完了しない為DllMainも呼ばれません。

◎質問者からの返答

解りやすい解説ありがとうございます。

原因が分からず、非常に気になっていたのですが、

静的リンクの場合は、

『プログラムの開始時にすべてのDLLをロードし、アドレス解決』を行っていたのですね。

アドレス解決の順序などもしらなかったためエラーメッセージに首をかしげていたのですが

お蔭様で少し納得することができました。

>>DLL2からDLL1を静的リンクせず実行時リンクを行う必要があります。

具体的なご指摘ありがとうございます。

DLL2は既存リソースなので手を加えない予定ですが、

対応方法が分かっただけでも嬉しいです。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ