2012年1月14日

SHELL32.dllにおけるWindowsバージョンの違いによる不都合。


先日、僕が公開しているファイル検索ツールFileDiverのユーザから不具合のご連絡頂いた。WindowsXPにおいて下記のようなメッセージが出て起動できないというものである。
「プロシージャーエントリーポイントSHGetKnownFolderPathがダイナミックリンクライブラリ
SHELL32.dllから見つかりませんでした。」
著者のテスト環境は現在、VistaとWindows7でXP以下についてはアプリケーションの互換モード設定を使って確認している。勿論互換モードではそのようなエラーは出ていなかったはずで、再度互換モードで確認しても再現できない。
そこで念の為、XPの入った古いパソコンを引っ張り出して、インストールしてみると・・・確かにエラーが出る。
LocalLow は、Vista以降で導入されたアプリケーションが一時的に蓄積する場所でSHGKownFolderPath()で取得する事が出来る。したがって、アプリケーションの動作しているバージョン番号をチェックして、Vista以上でSHGKownFolderPath()を呼べば良いはずである。XPではSHGKownFolderPath()はコールしていないにも関わらず・・・。
「どういうこと?」
ネットをあさってみると、やはり同じような対処方法しか書いていないが、一部海外のもので同じような現象で困って、XPで動くVista用のshell32.dllを作って取り換えるという荒技などを紹介したサイトがあった。
これはもしかしてと思い次のようなコードを書いて、Vista以降で呼ぶようにしたらXPあっさり動いた。アプリケーションが使用するWindowsの基本DLLにあるメソッドを全てリストアップして、あれば起動時にエントリーポイントをロードしているようである。
したがって、たとえ実際に動作時に1度もコールしていなくても動作環境のDLLになければエラーが発生する。これは全ての同様なアプリケーションで発生する可能性のあるワールドワイドな不都合だ。
Microsoftは、WindowsXPのSHELL32.dllにも、ダミーのSHGKownFolderPathメソッドを作成してWindowsUpdateで配るべきだと思う。
CString getLocalAppDataLow() {
typedef HRESULT ( WINAPI *FPSHGetKnownFolderPath )( const GUID&, DWORD, HANDLE, PWSTR * );
CString strPath;
HRESULT hr;
HMODULE hLib;
hLib = LoadLibrary( _T( “shell32.dll” ) );
if (hLib ) {
FPSHGetKnownFolderPath func = reinterpret_cast<FPSHGetKnownFolderPath>( GetProcAddress( hLib, “SHGetKnownFolderPath” ) );
if ( func ) {
LPWSTR pstr = NULL;
hr = ( *func )( FOLDERID_LocalAppDataLow, 0, NULL, &pstr );
if ( !FAILED( hr )) {
strPath = pstr;
}
}
FreeLibrary( hLib );
}
return strPath;
}

2 件のコメント: