6

私は、Windows XP と Windows Vista の間のすべての Windows バージョンで動作する C++ ソフトウェアに取り組んでいます。私のコードでは、標準ライブラリ ( Qt ライブラリ) にリンクする DLL を開発しました。私のソフトウェアが展開されると、ユーザーが自分のシステムにまったく同じ Qt ビルドを持っていなくても、わずかに異なる構成を持っていることは珍しくありません。機能が無効になっている可能性があります (そのため、Qt ビルドは同じシンボル セットをエクスポートしません)、またはライブラリ バイナリが元のライブラリと互換性がなくなるような方法でライブラリが変更されている可能性もあります。

ある時点で、LoadLibrary() 呼び出しを介して DLL をロードしています。これにより、ユーザーのシステムにある Qt ライブラリが取り込まれます。運が良ければ、彼らの Qt ビルドは私が DLL の開発中に使用したものと互換性があるため、LoadLibrary() は成功します。ただし、Qt ビルドに加えた変更によっては、LoadLibrary() 呼び出しが失敗することがあります。

  • "指定されたモジュールが見つかりませんでした。"; これは通常、Qt ビルドが私の Qt ビルドよりも少ない DLL で構成されている場合に発生します。私の DLL は QtFoo.dll などを読み込もうとしますが、この dll は Qt ビルドの一部ではないため、DLL の読み込みは失敗します。
  • "指定されたプロシージャが見つかりませんでした。"; これは通常、特定の機能が無効になるように Qt ビルドを変更した場合に発生し、その結果、エクスポートされるシンボルが少なくなります。

私の質問は、これらのエラーを適切にキャッチするにはどうすればよいですか? 右、単純に GetLastError() を使用してから、上記の 2 つのメッセージのいずれかを出力します。ただし、どのモジュールが見つからないか、またはどのプロシージャが欠落しているかがわかれば、はるかに便利です。見つからない DLL にリンクするアプリケーションをエクスプローラーで実行すると、エクスプローラーは「必要なライブラリ blah.dll が見つからないため、アプリケーション foo をロードできませんでした」というメッセージを表示することに気付きました。LoadLibrary() 呼び出しが正確に失敗した理由に関する詳細情報を取得するために利用できる API はありますか?

4

6 に答える 6

2

ある時点で、LoadLibrary()呼び出しを介してDLLをロードしています。これにより、ユーザーのシステムにあるQtライブラリがすべて取り込まれます。

これをしないでください!あなたが持っているエラーの種類は幸運な種類です、それがメモリを破壊してクラッシュするのと同じくらい簡単です。Qtアプリケーションを出荷する標準的な方法は、DLLを出荷するか、静的にリンクすることです。ヘルプファイルのQtデプロイメントガイドを確認してください。

後で編集:

コメントを読んだ後でも、このアプローチを使用することはお勧めしません。DLLがロードされても、DLLがバイナリ互換であるかどうかを確認できないため、エラーの追跡が困難になる可能性があります。

それでも、LoadLibrary呼び出しをインターセプトして、どの呼び出しが失敗するかを確認できると思います。これには、 MSDetoursライブラリを使用できます。このStackoverflowの質問も参照してください。

于 2009-08-19T12:54:16.270 に答える
2

jeffamaphone の回答を拡張するには、呼び出す前にファイル バージョンの詳細を取得してみてくださいLoadLibrary。これは、次の関数を使用して行うことができます。

BOOL GetFileDetails(LPCTSTR lpszPath, LPDWORD lpMajorVersion, 
                    LPDWORD lpMinorVersion)
{
    DWORD dwVersionHandle;

    DWORD dwVersionSize = GetFileVersionInfoSize((LPTSTR)lpszPath,
                                                 &dwVersionHandle);
    if (dwVersionSize == 0)
        return FALSE;

    LPBYTE lpVersion = new BYTE[dwVersionSize];

    if (!GetFileVersionInfo((LPTSTR)lpszPath, dwVersionHandle, 
                            dwVersionSize, lpVersion))
    {
        delete [] lpVersion;
        return FALSE;
    }

    VS_FIXEDFILEINFO *pVersionInfo = NULL;
    UINT nLength;

    if (!VerQueryValue(lpVersion, _T("\\"), (LPVOID *)&pVersionInfo, &nLength))
    {
        delete [] lpVersion;
        return FALSE;
    }

    *lpMajorVersion = pVersionInfo->dwFileVersionMS;
    *lpMinorVersion = pVersionInfo->dwFileVersionLS;

    return TRUE;
}

次に、メジャー/マイナー バージョン番号を、期待するものと比較して確認できます。

于 2009-08-21T19:51:19.007 に答える
1

ImageHLP.DLLMapAndLoadからの缶が役立つ場合があります。LOADED_IMAGE 構造体を返します。

于 2009-08-25T09:59:33.703 に答える
1

デバッガーをプロセスに接続する以外に、できるとは思いません。これが発生したときに通常ポップアップするメッセージは、LoadLibrary によって内部的に生成されます。SetErrorMode は、この形式のメッセージを禁止するために多くのアプリで使用されています。アプリ フレームワークのどこかでSetErrorMode、OS メッセージを禁止するように呼び出していると思います。

dll ロードの失敗に関する独自の詳細メッセージを生成することが確認されている唯一のアプリは、MS DevStudio です。これはデバッガーとしてアタッチされているため、デバッグ イベントの特別なストリームにアクセスできます。

于 2009-08-19T08:23:31.937 に答える
0

マニフェスト ファイルを使用して、Windows でこれをチェックすることもできます。このファイルには、使用されるライブラリのバージョンの要件に関する情報が含まれています。より正確で完全な情報はmsdn サイトにあります。

マニフェスト ファイルで LoadLibrary を使用する方法については、この質問への回答をご覧ください。

Qt のドキュメントでは、VS2005 のマニフェスト ファイルの使用について簡単に説明しています。以前のバージョンでは、独自に作成する必要がありました。

于 2009-08-25T10:10:24.883 に答える
0

LoadLibrary() を呼び出す前に、より積極的に必要な QT バイナリのバージョンを確認できますか? 次に、アプリに必要なバージョンがないことをユーザーに警告し、インストール ポイントへのリンクを提供することもできます。

于 2009-08-21T17:26:54.883 に答える