Windowsのレジストリは、タイムアウト値などプログラムのコンフィジュレーション情報(初期設定)を保持するために使われます。
Windowsのレジストリは、WindowsのOSが32ビット版と64ビット版では、プログラムからのアクセス方法に配慮が必要になります。
■ 32ビット版と64ビット版 のOSとプログラム
WindowsのOSとプログラムには、それぞれ32ビット版と64ビット版が存在します。特に、昔に開発されたプログラムは、32ビット版のプログラムが多くなります。その一方で、WindowsのOSは、CPUの64ビット化に伴い、現在では、64ビット版しか販売されていません。
そうなると、 WindowsのOSとプログラムには、 以下の組み合わせが発生することになります。
パターン | Window OS | プログラム |
A | 64ビット | 64ビット |
B | 64ビット | 32ビット |
C | 32ビット | 32ビット |
問題は、パターンBです。
64ビット版のWindowのOSには、WOW64(Windows 32bit emulation on Windows 64bit)機能があり、32ビット版のプログラムでも問題なく動作します。
出所:第2回 Win32アプリケーションを実行するWOW64
■ レジストリの場所がリダイレクトされる
ただし、特に、プログラムがアクセスするレジストリの配置に関しては、注意する必要があります。
プログラム側で何もしなければ「リダイレクト」されてしまいます。(以下を参照)
「複数のプロセッサアーキテクチャに対する Windows Windows (WOW) のサポートを含む Windows インストールの影響を受けるレジストリキー」
リダイレクト先は、CPUのアーキテクチャによって変わります。
Intel製x86のアーキテクチャでは、レジストリーキーのパスに”WOW6432Node”が挿入されます。
ARMのアーキテクチャでは、レジストリーキーのパスに”WowAA32Node”が挿入されます。
たとえば、以下のようにリダイレクトされます。
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\test
HKEY_LOCAL_MACHINE\SOFTWARE\ WowAA32Node\test
32ビット版のプログラムで何も対応しなければ、上記のようにリダイレクトされてしまいますので、もともとのレジストリをリダイレクト先に登録しておく必要があります。
■ 32ビット版プログラムでのレジストリアクセスの対応
一方、32ビット版プログラム側で、リダイレクトされないように対応すれば、リダイレクト先にレジストリを登録する必要はありません。
手順としては、以下となります。
①現プロセスのプロセスハンドルを取得する
②プロセスハンドルを指定し、現プロセスがWOW64機能下で実行されているかどうか判断する
③WOW64機能下で実行されていれば、レジストリキーをオープンする際、
「KEY_WOW64_64KEY」をアクセス権にOR指定する
例えば、以下のように、それぞれ同じキーの下にNameと言う文字列値に、”taro”と”hanako”というように別の文字列を設定しておきます。
HKEY_LOCAL_MACHINE\SOFTWARE\test
Name REG_SZ ”taro”
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\test
Name REG_SZ ”hanako”
以下の32ビット版プログラムから、WOW64機能下で動作しているかを判定し、動作している場合、 レジストリキーをオープン 時のアクセス権に「KEY_WOW64_64KEY」をOR指定します。
すると、 HKEY_LOCAL_MACHINE\SOFTWARE\test下のNameの文字列「taro」が読みだされます。
仮に、何も指定しない場合は、 レジストリキーをオープン 時のアクセス権が「KEY_WOW64_32KEY」(デフォルト)となり、 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\test 下のNameの文字列「hanako」が読みだされます。
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <windows.h>
int PrintRegistryData();
int main()
{
PrintRegistryData();
}
int PrintRegistryData()
{
// std::wcoutのロケールを設定
//std::wcout.imbue(std::locale("", std::locale::ctype));
// エラーコード
HRESULT hResult = S_OK;
{
// 戻り値
DWORD dwResult = 0;
// HKEY
HKEY hKey = NULL;
// データの読出しバッファ
char cBuf[128];
// データの読出しバッファのサイズ(文字数では無くバイト数) / 読みだしたサイズ
DWORD Size = sizeof(cBuf);
// 読みだしたデータのタイプ(RegEnumValue)
DWORD dwType = 0;
// WOW64機能のモード
DWORD wow64_mode = KEY_WOW64_32KEY;
// WOW64機能下での実行かどうかの判定結果
BOOL wow64_flag=false;
// プロセスハンドル
HANDLE hProc;
memset(cBuf, 0, sizeof(cBuf));
// 現プロセスハンドル取得
hProc = GetCurrentProcess();
// 現プロセスがWOW64機能下での実行かどうかの判定
IsWow64Process(hProc, &wow64_flag);
if (wow64_flag)
{
// KEY_WOW64_64KEYを指定し、リダイレクトさせないようにする
wow64_mode = KEY_WOW64_64KEY;
}
/*
レジストリオープン
*/
dwResult = RegOpenKeyEx(
HKEY_LOCAL_MACHINE // レジストリキー
,"SOFTWARE\\test" // レジストリサブキー
, 0 // Reserved(0固定)
, KEY_QUERY_VALUE // アクセス権
| wow64_mode // OR指定
, &hKey // キーハンドルの受け取り位置
);
if (ERROR_SUCCESS != dwResult) {
// エラー
hResult = HRESULT_FROM_WIN32(dwResult);
goto err;
}
/* レジストリの値を取得 */
dwResult = RegQueryValueEx(
hKey // キーハンドル
, "Name" // ValueName
, 0 // Reserved(0固定)
, &dwType // 読みだしたデータの型
, (LPBYTE)cBuf // 読みだし位置
, &Size // 読み出しバッファサイズ
);
if (ERROR_SUCCESS != dwResult) {
// エラー
hResult = HRESULT_FROM_WIN32(dwResult);
goto err;
}
/* 読みだした値の表示 */
printf("data = %s\n",cBuf);
err:
// キーハンドル破棄
if (NULL != hKey) {
RegCloseKey(hKey);
}
}
return(0);
}
■ まとめ
WOW64機能のおかげで過去の32ビット版のプログラム資産を活用できるますが、レジストリなど動作環境の確認・検証が必要になります。
WOW64機能 の仕組みを理解した上で、プログラムの再利用を進めることがポイントです。
ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい