このクラスの責務
- 32ビットアプリから、64ビットOS環境の System32や、ProgramFilesにアクセスすると、ファイルシステムにリダイレクトされます。詳細:ファイル システム リダイレクタ(MSDN)
- リダイレクト対象となるファイルの存在チェックや、exeの実行時に影響を出さないように、ON/Offする機能をもちます。
実装その1:無効化の寿命が不定
実装コード
class Wow64FsRedirectionService
{
typedef BOOL ( WINAPI *fpWow64DisableWow64FsRedirection )( LPVOID* );
typedef BOOL ( WINAPI *fpWow64RevertWow64FsRedirection )( LPVOID );
public:
Wow64FsRedirectionService()
: m_lpOldVar( nullptr )
, m_fpWow64DisableWow64FsRedirection(nullptr)
, m_fpWow64RevertWow64FsRedirection(nullptr)
{
m_hModule = ::LoadLibrary( _T( "Kernel32.dll" ) );
if( m_hModule )
{
m_fpWow64DisableWow64FsRedirection = (fpWow64DisableWow64FsRedirection)::GetProcAddress( m_hModule, "Wow64DisableWow64FsRedirection" );
m_fpWow64RevertWow64FsRedirection = (fpWow64RevertWow64FsRedirection)::GetProcAddress( m_hModule, "Wow64RevertWow64FsRedirection" );
}
}
~Wow64FsRedirectionService()
{
if ( m_hModule ) {
// m_lpOldVar がnullptrではないとき => Wow64RevertWow64FsRedirection(リダイレクト有効化)が呼ばれていないので、もどしておく
RevertRedirection();
::FreeLibrary(m_hModule);
m_hModule = nullptr;
}
}
void DisableRedirection() {
if (m_fpWow64DisableWow64FsRedirection )
m_fpWow64DisableWow64FsRedirection( &m_lpOldVar );
}
void RevertRedirection() {
if (m_lpOldVar && m_fpWow64RevertWow64FsRedirection ) {
m_fpWow64RevertWow64FsRedirection( m_lpOldVar );
m_lpOldVar = nullptr;
}
}
private:
LPVOID m_lpOldVar;
HINSTANCE m_hModule;
fpWow64DisableWow64FsRedirection m_fpWow64DisableWow64FsRedirection;
fpWow64RevertWow64FsRedirection m_fpWow64RevertWow64FsRedirection;
};
使いかた・問題点
void do()
{
Wow64FsRedirectionService serv;
serv.DisableRedirection();
// リダイレクトされてしまうファイルパスへのアクセスはここに。
serv.RevertRedirection();
}
この例ではdo
メソッドのスコープ内で無効・有効が完結するので問題は起こらないけれど、本クラスをクラスメンバとして定義された場合、もしくはアプリの寿命と同じくらいのスコープまで無効化が伸びてしまう可能性が起こりうるのでよくない。
ドキュメントにもそう書かれている。
詳細:ファイル システム リダイレクタ(MSDN)
ファイル システムのリダイレクトを長期にわたって無効にすると、32 ビット アプリケーションでシステム DLL が読み込まれなくなり、アプリケーションでエラーが発生することがあります。
実装その2:必要な処理が完了したらすぐに有効化する
実装コード
#include <functional>
class Wow64FsRedirectionService
{
typedef std::function<void()> DisableScopeFunction;
typedef BOOL ( WINAPI *fpWow64DisableWow64FsRedirection )( LPVOID* );
typedef BOOL ( WINAPI *fpWow64RevertWow64FsRedirection )( LPVOID );
public:
Wow64FsRedirectionService()
: m_lpOldVar( nullptr )
, m_fpWow64DisableWow64FsRedirection(nullptr)
, m_fpWow64RevertWow64FsRedirection(nullptr)
{
m_hModule = ::LoadLibrary( _T( "Kernel32.dll" ) );
if( m_hModule )
{
m_fpWow64DisableWow64FsRedirection = (fpWow64DisableWow64FsRedirection)::GetProcAddress( m_hModule, "Wow64DisableWow64FsRedirection" );
m_fpWow64RevertWow64FsRedirection = (fpWow64RevertWow64FsRedirection)::GetProcAddress( m_hModule, "Wow64RevertWow64FsRedirection" );
}
}
~Wow64FsRedirectionService()
{
if ( m_hModule ) {
::FreeLibrary(m_hModule);
m_hModule = nullptr;
}
}
void UsingDisable(DisableScopeFunction dosomething) {
if( DisableRedirection() )
{
dosomething();
RevertRedirection();
}
}
private:
bool DisableRedirection() {
if ( !m_fpWow64DisableWow64FsRedirection )
return false;
return TRUE == m_fpWow64DisableWow64FsRedirection( &m_lpOldVar );
}
bool RevertRedirection() {
if (!m_lpOldVar || !m_fpWow64RevertWow64FsRedirection )
return false;
const BOOL result = m_fpWow64RevertWow64FsRedirection( m_lpOldVar );
m_lpOldVar = nullptr;
return TRUE == result;
}
private:
LPVOID m_lpOldVar;
HINSTANCE m_hModule;
fpWow64DisableWow64FsRedirection m_fpWow64DisableWow64FsRedirection;
fpWow64RevertWow64FsRedirection m_fpWow64RevertWow64FsRedirection;
};
変更点
-
DisableRedirection
、RevertRedirection
はprivate
に変更 -
public
にUsingDisable
を追加 -
UsingDisable
で実行される関数オブジェクトtypedef std::function<void()> DisableScopeFunction
を追加
使いかた
Wow64FsRedirectionService FsRedirecta;
FsRedirecta.UsingDisable( [](){
// リダイレクトされてしまうファイルパスへのアクセスはここに。
});
なにがよくなった?
- Disable→Revertのスコープを一定にできた
- 有効化し忘れることがなくなった
- タイプ数が減った