Win32/64技術 005 レジストリ操作

提供:yonewiki
2024年1月27日 (土) 23:40時点におけるYo-net (トーク | 投稿記録)による版 (→‎RegSetValueExW)

Win32/64_アプリケーション開発に戻る。

前の記事:Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例

次の記事:[[Win32/64技術 006]]

概要

 レジストリ操作の処理に関わる部分についての記事です。レジストリの個々の役割についての情報自体は別の項目でまとめ上げる必要があると感じてはいます。しかし、レジストリの役割やレジストリの技術概要を述べるだけでも一冊の本になってもおかしくない内容になります。ここでは、その全体像の中から、C++(Cpp)プログラムでの操作についてのみ纏めたいと思います。


 操作するプログラムを走らせる場合は、システムを壊してしまう可能性があります。すべてのレジストリ項目についてバックアップを取った上で操作することが必要で、レジストリ構造が壊れてしまった場合はWindowsが一切機能しなくなる可能性もゼロではありません。それでも説明している側にはなんら責任はないことを理解して下さい。安全確認は開発者個人で進める必要があります。なめてると痛い目に逢う。それがレジストリ操作です。このたぐいのだいたいのSiteでもこのような注意書きがあるはずです。それと同じです。


 レジストリでキーを作成するには以下の関数を使います。


RegCreateKeyExW

■RegCreateKeyExW(HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, CONST LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD)

第1引数:HKEY hKey

 レジストリ操作をする大分類のキー構造のトップキーの種類について指定する部分です。HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_CONFIG が代表的な値です。Windows.hを読み込んでいれば読み込まれるwinreg.hにIDが定義されたマクロが定義されています。あるいは、この関数の実行により得られるハンドル値を指定すると前回作成したキー値に対しての相対パスのようなキー構造の指定ができるようになります。


第2引数:LPCWSTR lpSubKey

 作成するキー構造について文字列で指定します。下のサンプルでは、LR""リテラルに文字列を定義しています。リテラルの種類に関してはリテラルの記事を参考にして下さい。


第3引数:DWORD Reserved

 このパラメーターは予約されており、0 である必要があります。


第4引数:LPWSTR lpClass

 このキーのユーザー定義クラス型。このパラメーターは無視できます。このパラメーターは、NULL(nullptrの利用を推奨) でもかまいません。


第5引数:DWORD dwOptions

 規定値はREG_OPTION_NON_VOLATILEで0です。揮発性でないレジストリキー作成であることを意味します。そのほかの意味を持たせる場合はそれ以外の値を指定します。REG_OPTION_VOLATILEで揮発性のレジストリキーを作成し、保存されないけど、アプリケーション実行中だけ存在するレジストリキーとすることができます。REG_OPTION_CREATE_LINKでシンボリックリンク、REG_OPTION_BACKUP_RESTOREで第6引数のキーのバックアップ、復元をするのに必要な権限で操作します。


第6引数:REGSAM samDesired  様々なアクセス権設定フラグが準備されています。キーや値を作成するにはKEY_WRITEの権限が必要です。その他の権限の説明についてはマイクロソフト公式の説明に今のところは譲っておきます。https://learn.microsoft.com/ja-jp/windows/win32/sysinfo/registry-key-security-and-access-rights


第7引数:CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes

 SECURITY_ATTRIBUTES型の変数で例えばsaなら&saとポインタを指定すると、そのメンバ変数sa.bInheritHandle = TRUEのように設定した値であったなら、子プロセスの継承が許可できます。このようにしてキーの作成をすると、プログラムで子プロセスを生成したときに継承を許可していれば、作成したキーが継承されて参照できるようになります。


第8引数:PHKEY phkResult

 HKEY型のポインタを指定すると、作成したキーへのハンドル値のようなものを得ることができます。これを使って、作成したキーへの相対的なキー構造操作を実現します。HKEY型のeventlabelsという変数を作ったなら、&eventlabelsのように指定するとよいです。


第9引数:LPDWORD lpdwDisposition

いずれかの処理値を受け取る変数へのDWORD型のロングポインターを設定すると、その中身にREG_CREATED_NEW_KEY(1)かREG_OPENED_EXISTING_KEY(2)が返ります。1ならキーが存在せず作成されましたことを意味していて、2ならキーは存在し変更されずに単純に開かれたことを意味します。


 HKEY_CURRENT_USERのAppEvents\EventLabelsを作る。既に存在している場合は何もしないプログラムは以下のようになります。


サンプルプログラム

if (HKEY eventlabels; RegCreateKeyExW(/*1*/ HKEY_CURRENT_USER, /*2*/ LR"(AppEvents\EventLabels)", /*3*/ 0, 
                                      /*4*/ nullptr, /*5*/ 0, /*6*/ KEY_WRITE, 
                                      /*7*/ nullptr, /*8*/ &eventlabels, /*9*/ nullptr) == ERROR_SUCCESS){
  if (HKEY key; RegCreateKeyExW(/*1*/ eventlabels, /*2*/ LR"(Sample_Connected)", /*3*/ 0,
                                /*4*/ nullptr, /*5*/ 0, /*6*/ KEY_SET_VALUE,
                                /*7*/ nullptr, /*8*/ &key, /*9*/ nullptr) == ERROR_SUCCESS) {
    RegCloseKey(key);
  }
  RegCloseKey(eventlabels);
}


 RegCreateKeyExW関数を正常に実行できた場合、レジストリ編集をする必要がなくなった時にRegCloseKey関数を実行しないと、リソースリークが起きたままになります。必要がなくなったら、RegCloseKey関数を実行しましょう。簡単な関数ですが重要です。次の項目で紹介します。

 

RegCloseKey

 キーに対する操作を閉じる処理です。

■RegCloseKey(HKEY)

第1引数:HKEY hKey

 RegCreateKeyExWでレジストリキー操作をしたときの第8引数に設定したHKEY型のポインタの実体の変数を設定すると、キー操作したときのキーハンドルを閉じることができます。実行しない場合はキーをオープンするために使用するリソースが解放されないままになってしまいます。必要がなくなったら閉じましょう。


 コードのサンプルはひとつ前の項目で示したので省略します。

RegSetValueExW

 第1引数に設定したキーハンドルに対して、第2引数に設定した値の名前と第5引数に設定したデータ値を設定する関数です。


■RegSetValueExW(HKEY, LPCWSTR, DWORD, DWORD, CONST BYTE*, DWORD)

第1引数:HKEY hKey

RegCreateKeyExWでレジストリキー操作をしたときの第8引数に設定したHKEY型のポインタの実体の変数を設定すると、そのキーに対する値の設定処理ができる。


第2引数:LPCWSTR lpValueName

 設定する名前。NULL(NULLにする場合nullptr値の設定を推奨)を設定すると関数はキーの名前なしまたは既定値の型とデータを設定。レジストリのキー(フォルダみたいに表示されるもの)には、その中の値として、名前とデータというものが対になって設定できます。データには形式(文字列、バイナリ、DWORD、QWORD、複数行文字列、展開可能文字列)というものが設定できます。名前の値を設定するのがこの引数の役目です。


第3引数:DWORD Reserved

このパラメーターは予約されており、0 である必要があります。


第4引数:DWORD dwType

 第5引数によって設定される値のデータの型(文字列、バイナリ、DWORD、QWORD、複数行文字列、展開可能文字列)。

  • REG_NONE ( 0ul ) // 型無し。レジストリエディタでは設定できない。
  • REG_SZ ( 1ul ) // Unicode NULL終端文字列
  • REG_EXPAND_SZ ( 2ul ) // Unicode NULL終端文字列 環境変数展開可能文字列
  • REG_BINARY ( 3ul ) // バイナリー
  • REG_DWORD ( 4ul ) // 32-bit 数値 リトルエンディアン。
  • REG_DWORD_LITTLE_ENDIAN ( 4ul ) // 32-bit 数値 リトルエンディアン。REG_DWORDと同じ意味
  • REG_DWORD_BIG_ENDIAN ( 5ul ) // 32-bit 数値 ビッグエンディアン。レジストリエディタでは設定できない。
  • REG_LINK ( 6ul ) // シンボリックリンク (unicode)。レジストリエディタでは設定できない。
  • REG_MULTI_SZ ( 7ul ) // 複数行文字列
  • REG_RESOURCE_LIST ( 8ul ) // リソースマップリソース一覧。レジストリエディタでは設定できない。
  • REG_FULL_RESOURCE_DESCRIPTOR ( 9ul ) // ハードウェアリソース一覧。レジストリエディタでは設定できない。
  • REG_RESOURCE_REQUIREMENTS_LIST ( 10ul ) //リソース要求一覧。レジストリエディタでは設定できない。
  • REG_QWORD ( 11ul ) // 64-bit 数値 リトルエンディアン。
  • REG_QWORD_LITTLE_ENDIAN ( 11ul ) // 64-bit 数値 リトルエンディアン。REG_QWORDと同じ意味


 リソースエディタでも表示できないような型に関する情報についての説明はかなり難しい内容になります。ハードウェアドライバに関する知識が必要となるようです。


第5引数:CONST BYTE* lpData

 reinterpret_cast<const BYTE*>(文字列変数)のように変換して、ヌル終端文字列を設定すると文字列を指定できますし、数値変数も同様に設定します。

第6引数:DWORD cbData

 第5引数が指す情報のサイズ (バイト単位)。ヌル終端文字列の場合、最後のヌル文字に使うバイトも含める必要があります。


サンプル

if (HKEY eventlabels; RegCreateKeyExW(HKEY_CURRENT_USER, LR"(AppEvents\EventLabels)", 0, 
                                      nullptr, 0, KEY_WRITE, 
                                      nullptr, &eventlabels, nullptr) == ERROR_SUCCESS){
  if (HKEY key; RegCreateKeyExW(eventlabels, LR"(Sample_Connected)", 0,
                                nullptr, 0, KEY_SET_VALUE,
                                nullptr, &key, nullptr) == ERROR_SUCCESS) {
    RegSetValueExW(/*1*/ key,
                   /*2*/ nullptr,
                   /*3*/ 0,
                   /*4*/ REG_SZ,
                   /*5*/ reinterpret_cast<const BYTE*>(name),
                   /*6*/ ((DWORD)wcslen(name) + 1) * sizeof(wchar_t));
    RegCloseKey(key);
  }
  RegCloseKey(eventlabels);
}

 

前の記事:Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例

次の記事:[[Win32/64技術 006]]

Win32/64_アプリケーション開発に戻る。