コンテンツ
2. cmd.exeに移動し、zippy32を使用してコントロールを手動で登録します
3. ReactOSオープンソースコードに移動して、zippy32の実装を確認し、問題を解決するための手がかりを見つけます
3.1。ReactOSオープンソースオペレーティングシステムの概要
3.2. Source Insightを使用してReactOSソースコードを開き、zippy32.exeプログラムのコードを見つけます
4. Microsoft MSDNにアクセスして、LOAD_WITH_ALTERED_SEARCH_PATHパラメーターの意味を確認します。
場合によっては、LoadLibraryを呼び出してdllライブラリを動的にロードし、dllライブラリのインターフェイスを取得する必要があります。ただし、ロードに失敗する場合があります。dllライブラリのフルパスを渡してもロードに失敗します。プロジェクトでこのような問題が複数回発生しています。今日は、この問題を解決する方法を見ていきます。
1.問題の例
インストールパッケージはコードで作成され、 inno setupやinstallshieldなどのパッケージツール は使用されなくなりました。ファイルのコピー、レジストリの読み取りと書き込み、インストールパッケージへのコントロールの登録などの操作はすべてコードで行われます。テスト中に、コントロールの登録に失敗したことが判明しました。コントロールを登録するためのコードは次のとおりです。
void RegCtrl( LPCTSTR lpszDllPath )
{
if ( lpszDllPath == NULL )
{
return;
}
CString strLog;
strLog.Format( _T("[RegCtrl] lpszDllPath: %s."), lpszDllPath );
WriteLog( strLog );
// 1、先将库动态加载起来
HINSTANCE hInstance = LoadLibrary( lpszDllPath )
if ( NULL == hInstance )
{
strLog.Format( _T("[RegCtrl] load dll failed, GetLastError: %d."), GetLastError() );
WriteLog( strLog );
}
// 2、获取库中的DllRegisterServer函数接口,调用该接口去完成控件的注册
typedef HRESULT (*DllRegisterServerFunc)(void);
DllRegisterServerFunc dllRegisterServerFun = (DllRegisterServerFunc)GetProcAddress( hInstance, "DllRegisterServer" );
if ( dllRegisterServerFun != NULL )
{
HRESULT hr = dllRegisterServerFun();
strLog.Format( _T("[RegCtrl] DllRegisterServer return: %d"), hr );
WriteLog( strLog );
}
else
{
strLog.Format( _T("[RegCtrl] Get DllRegisterServer address failed. GetLastError: %d"), GetLastError() );
WriteLog( strLog );
}
FreeLibrary( hInstance );
}
コードで、dllファイルのフルパスを介してコントロールdllをロードし、コントロールdllでDllRegisterServerインターフェイスを取得し、DllRegisterServerインターフェイスを呼び出してコントロールの登録を完了します。
印刷されたログによると、LoadLibraryを呼び出してコントロールdllライブラリをロードするときに失敗しました。コントロールdllのフルパスをLoadLibraryインターフェイスに渡しました。コントロールdllファイルもこのパスにあります。これは少し紛らわしいですが、明らかに、コントロールdllのフルパスが渡され、コントロールdllファイルもパスに存在します。dllライブラリの読み込みに失敗するのはなぜですか。これは少し奇妙すぎます!
2. cmd.exeに移動し、zippy32を使用してコントロールを手動で登録します
インストールパッケージプログラムはdllライブラリを読み込めませんでした。cmdウィンドウに移動し、zippy32を使用してdllコントロールを手動で登録することができると考えました。cmdウィンドウを開き、dllファイルをcmdウィンドウに手動でドラッグしてdllファイルのパスを取得し、Enterキーを押してコントロールを登録します(例として、FeiqiuのImageOle.dllコントロールを示します)。
zippy32 "C:\ Program Files \ feiq \ GifDll \ ImageOle.dll"
手動登録は正常に登録できます。zippy32を使用して手動で登録する場合、システムのzippy32.exeプログラムが呼び出されます。zippy32.exeプログラムも制御dllファイルをロードする必要があります。zippy32.exeプログラムがライブラリをロードする方法が、パッケージプログラムをインストールする方法と異なる可能性がありますか?
3. ReactOSオープンソースコードに移動して、zippy32の実装を確認し、問題を解決するための手がかりを見つけます
以前にオープンソースオペレーティングシステムReactOSのソースコードをダウンロードしました。ReactOSのシステムライブラリの内部実装はWindowsのそれと非常に似ており、提供されるシステムAPIインターフェイスは基本的に同じです。開発プロセスで発生した問題のトラブルシューティングを支援するために、Windowsシステムの内部実装を理解するために、ReactOSのAPI関数と基盤となるライブラリの内部実装を頻繁にチェックします。
3.1。ReactOSオープンソースオペレーティングシステムの概要
ReactOSは、WindowsNTアーキテクチャに基づくWindowsXPシステムと同様の無料のオープンソースオペレーティングシステムです。NTおよびWindowsオペレーティングシステムバイナリとの完全なアプリケーションおよびドライバデバイスの互換性を実現することを目的としています。同様のアーキテクチャを使用し、完全なパブリックインターフェイスを提供します。
ReactOSは継続的にメンテナンスされています。ReactOSソースコードのダウンロードアドレスはreactosの公式Webサイトで確認でき、svnを使用してReactOSソースコードをダウンロードできます。
ReactOSオープンソースコードは、Windowsソフトウェア開発者にとって非常に便利です。API関数の内部実装、システムexeの内部実装、およびReactOSシステム内の任意のモジュールの実装コードを表示できます。ReactOSはWindowsシステムに比較的近いです。ReactOSコードを表示することで、Windowsシステムの内部実装の一般的な理解を得ることができます。これは、Windowsソフトウェアの問題のトラブルシューティングに非常に役立ちます。
3.2. Source Insightを使用してReactOSソースコードを開き、zippy32.exeプログラムのコードを見つけます
ReactOSソースコードにVisualStudioプロジェクトファイルがありません。VisualStudioを使用してソースコードを開いて表示することはできません。SourceInsightを使用してソースコードを表示できます。Source Insightの使用方法については、以前にSourceInsightについて書いた記事を参照してください。
Source Insightを使用して、ソースコードを表示および編集しますhttps://blog.csdn.net/chenlycly/article/details/124347857 zippy32は関数ではなく独立したexeであるため、プログラムに対応する.cソースファイルを見つける必要があります。そこで、zippy32をキーワードにしたファイルリストを検索してみたところ、zippy32.cファイル。次のように、ファイルで_tWinMainを見つけ、関数でdllライブラリファイルをロードするコードを確認します。
コードでは、 LoadLibraryExインターフェイスが呼び出されてdllライブラリが読み込まれ、着信パラメータはLOAD_WITH_ALTERED_SEARCH_PATHであり、dllコントロールライブラリのDllRegisterServerも登録用に取得されます。
zippy32.exeがこのメソッドを使用してライブラリファイルをロードすることは合理的であるはずです。そのため、以下に示すように、そのプラクティスを参照し、dllライブラリをロードするためのコードを変更してLoadLibraryExを呼び出し、LOAD_WITH_ALTERED_SEARCH_PATHを渡します。
HINSTANCE hInstance = LoadLibraryEx( lpszDllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
if ( NULL == hInstance )
{
strLog.Format( _T("[RegCtrl] load dll failed, GetLastError: %d."), GetLastError() );
WriteLog( strLog );
}
上記のコードに変更した後、ライブラリの読み込みエラーの問題は発生しなくなりました。上記のコードは本当に便利です。
その後、他のモジュールでもライブラリの読み込みに失敗する問題が発生し、上記のコードに置き換えられた結果、再度問題は発生しませんでした。ライブラリの絶対パスを介してライブラリをロードできないというこの問題は必須ではなく、個々のマシンでのみ発生します。
4. Microsoft MSDNにアクセスして、LOAD_WITH_ALTERED_SEARCH_PATHパラメーターの意味を確認します。
LOAD_WITH_ALTERED_SEARCH_PATHパラメーターの意味を理解するために、 Microsoft MSDNにアクセスして、 LoadLibraryEx API関数の説明ページを表示し、LOAD_WITH_ALTERED_SEARCH_PATHパラメーターの説明を見つけました。
LOAD_WITH_ALTERED_SEARCH_PATH:(0x00000008)
この値が使用され、lpFileNameが絶対パスを指定する場合、システムは、備考セクションで説明されている代替ファイル検索戦略を使用して、指定されたモジュールがロードされる関連する実行可能モジュールを検索します。この値が使用され、lpFileNameが相対パスを指定している場合、動作は未定義です。
この値が使用されていない場合、またはlpFileNameでパスが指定されていない場合、システムは「備考」セクションで説明されている標準の検索戦略を使用して、指定されたモジュールがロードされる関連の実行可能モジュールを検索します。この値は、LOAD_LIBRARY_SEARCHフラグと組み合わせることはできません。
上記の説明から、LOAD_WITH_ALTERED_SEARCH_PATHパラメーターが設定されている場合、システムは代替ファイル検索戦略検索戦略を使用することがわかります。この検索戦略はどのようになりますか?
引き続きLoadLibraryEx関数の説明ページを見下ろし、ダイナミックリンクライブラリのロード順序の詳細な説明ページである「ダイナミックリンクライブラリの検索順序」ハイパーリンクを参照してください。このページから、LOAD_WITH_ALTERED_SEARCH_PATHパラメーターが設定されていない場合、デスクトップアプリケーションの標準検索順序が使用されていることがわかります。
1、アプリケーションのロード元のディレクトリ。
2、システムディレクトリ。GetSystemDirectory関数を使用して、このディレクトリのパスを取得します。
3、16ビットシステムディレクトリ。このディレクトリのパスを取得する関数はありませんが、検索されます。
4、Windowsディレクトリ。GetWindowsDirectory関数を使用して、このディレクトリのパスを取得します。
5、現在のディレクトリ。
6、PATH環境変数にリストされているディレクトリ。これには、AppPathsレジストリキーで指定されたアプリケーションごとのパスは含まれないことに注意してください。DLL検索パスを計算する場合、AppPathsキーは使用されません。
LOAD_WITH_ALTERED_SEARCH_PATHパラメーターが設定されている場合、システムはデスクトップアプリケーションの代替検索順序を使用します。
1、lpFileNameで指定されたディレクトリ。
2、システムディレクトリ。GetSystemDirectory関数を使用して、このディレクトリのパスを取得します。
3、16ビットシステムディレクトリ。このディレクトリのパスを取得する関数はありませんが、検索されます。
4、Windowsディレクトリ。GetWindowsDirectory関数を使用して、このディレクトリのパスを取得します。
5、現在のディレクトリ。
6、PATH環境変数にリストされているディレクトリ。これには、AppPathsレジストリキーで指定されたアプリケーションごとのパスは含まれないことに注意してください。DLL検索パスを計算する場合、AppPathsキーは使用されません。
LOAD_WITH_ALTERED_SEARCH_PATHパラメータを設定すると、デスクトップアプリケーションの代替検索順序が使用され、設定されたフルパスが最初にdllライブラリのロードに使用されます。