一般

Windowsのレジストリアクセス(32ビットと64ビット)の実践入門

投稿日:2021年11月29日 更新日:

Windowsのレジストリは、タイムアウト値などプログラムのコンフィジュレーション情報(初期設定)を保持するために使われます。

Windowsのレジストリは、WindowsのOSが32ビット版と64ビット版では、プログラムからのアクセス方法に配慮が必要になります。


■  32ビット版と64ビット版 のOSとプログラム

WindowsのOSとプログラムには、それぞれ32ビット版と64ビット版が存在します。特に、昔に開発されたプログラムは、32ビット版のプログラムが多くなります。その一方で、WindowsのOSは、CPUの64ビット化に伴い、現在では、64ビット版しか販売されていません。

そうなると、 WindowsのOSとプログラムには、 以下の組み合わせが発生することになります。

パターンWindow OSプログラム
A64ビット64ビット
B64ビット32ビット
C32ビット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機能 の仕組みを理解した上で、プログラムの再利用を進めることがポイントです。


ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい


-一般

執筆者:


comment

メールアドレスが公開されることはありません。

関連記事

「セキュリティマネジメントマニュアル」公開

セキュリティ対策といっても、イメージできない方々も多いでしょう。 セキュリティ対策を実施するためのセキュリティマネジメントを理解するためのマニュアルを作成しました。 基本方針(トップマネジメント)と情 …

Let’s Encrypt証明書生成と手動更新の実践入門

WindowsのVPS(Virtual Private Server:仮想専用サーバー)でPython+Flaskを動作させています。あえて、ApacheやIISなどのWebサーバの配下でPython …

ショートコード販売サイト(ShortCode)開設

ShortCodeは、1,000行以下で、短くて有用なテスト済みのソースコードを安価に提供します。また、ソースコードは、作成者にテスト済みで、すぐに実行することができます。短いのでわかりやすく、あなた …

未経験者のための「プログラミング」の学び方

一般教養として、英語などの語学を学ぶ感覚で、プログラミングを習得したいと考える人が増えています。将来、仕事で使えるかもしれないと考えてるビジネスマンも多いでしょう。いきなりプログラムを書き始める前に知 …

「パイソンぜろ」発売中!!

ゼロから学ぶ スマホでパイソン直感! 見るだけ! 文字少な目! PYTHONプログラミング 初級者レッスンPythonを学ぼう! いま、人気No.1のプログラミング言語は、Pythonです。しかし、そ …

Chinese (Simplified)Chinese (Traditional)EnglishFilipinoFrenchGermanHindiJapaneseKoreanMalayThaiVietnamese