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

# このクラスの責務

- 32ビットアプリから、64ビットOS環境の System32や、ProgramFilesにアクセスすると、ファイルシステムにリダイレクトされます。詳細：[ファイル システム リダイレクタ(MSDN)](https://msdn.microsoft.com/ja-jp/library/Aa384187(v=VS.85).aspx)
- リダイレクト対象となるファイルの存在チェックや、exeの実行時に影響を出さないように、ON/Offする機能をもちます。


# 実装その１：無効化の寿命が不定

## 実装コード

```cpp
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;
};
```

## 使いかた・問題点

```cpp
void do()
{
  Wow64FsRedirectionService serv;
  serv.DisableRedirection();

  // リダイレクトされてしまうファイルパスへのアクセスはここに。

  serv.RevertRedirection();
}
```

この例では`do`メソッドのスコープ内で無効・有効が完結するので問題は起こらないけれど、本クラスをクラスメンバとして定義された場合、もしくはアプリの寿命と同じくらいのスコープまで無効化が伸びてしまう可能性が起こりうるのでよくない。

ドキュメントにもそう書かれている。

>詳細：[ファイル システム リダイレクタ(MSDN)](https://msdn.microsoft.com/ja-jp/library/Aa384187(v=VS.85).aspx)
ファイル システムのリダイレクトを長期にわたって無効にすると、32 ビット アプリケーションでシステム DLL が読み込まれなくなり、アプリケーションでエラーが発生することがあります。



# 実装その２：必要な処理が完了したらすぐに有効化する

## 実装コード

```cpp
#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`を追加

## 使いかた

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

## なにがよくなった？

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