LoginSignup
2
2

More than 5 years have passed since last update.

WOW64 のファイル システム リダイレクタを制御するクラス

Posted at

このクラスの責務

  • 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;
};

変更点

  • DisableRedirectionRevertRedirectionprivateに変更
  • publicUsingDisableを追加
  • UsingDisableで実行される関数オブジェクトtypedef std::function<void()> DisableScopeFunctionを追加

使いかた

Wow64FsRedirectionService FsRedirecta;
FsRedirecta.UsingDisable( [](){
  // リダイレクトされてしまうファイルパスへのアクセスはここに。
});

なにがよくなった?

  1. Disable→Revertのスコープを一定にできた
  2. 有効化し忘れることがなくなった
  3. タイプ数が減った
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2