「Win32/64技術 005 レジストリ操作」の版間の差分
編集の要約なし |
|||
(同じ利用者による、間の18版が非表示) | |||
3行目: | 3行目: | ||
前の記事:[[Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例]] | 前の記事:[[Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例]] | ||
次の記事: | 次の記事:[[Win32/64技術 006 コンソールアプリケーションでリソースを使おう]] | ||
== '''概要''' == | == '''概要''' == | ||
レジストリ操作の処理に関わる部分についての記事です。レジストリの個々の役割についての情報自体は別の項目でまとめ上げる必要があると感じてはいます。しかし、[[Windowsレジストリ|レジストリの役割やレジストリの技術概要]]を述べるだけでも一冊の本になってもおかしくない内容になります。ここでは、その全体像の中から、C++(Cpp)プログラムでの操作についてのみ纏めたいと思います。 | |||
16行目: | 16行目: | ||
=== RegCreateKeyExW === | === RegCreateKeyExW === | ||
'''<span style="color:darkred;">■RegCreateKeyExW(LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, CONST LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD)</span>''' | '''<span style="color:darkred;">■RegCreateKeyExW(HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, CONST LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD)</span>''' | ||
'''第1引数''':HKEY hKey | '''第1引数''':HKEY hKey | ||
25行目: | 25行目: | ||
'''第2引数''':LPCWSTR lpSubKey | '''第2引数''':LPCWSTR lpSubKey | ||
作成するキー構造について文字列で指定します。下のサンプルでは、LR"" | 作成するキー構造について文字列で指定します。下のサンプルでは、LR""リテラルに文字列を定義しています。リテラルの種類に関しては[[Cpp 文字列リテラル|リテラルの記事]]を参考にして下さい。 | ||
44行目: | 44行目: | ||
'''第6引数''':REGSAM samDesired | '''第6引数''':REGSAM samDesired | ||
様々なアクセス権設定フラグが準備されています。キーや値を作成するにはKEY_WRITEの権限が必要です。その他の権限の説明についてはマイクロソフト公式の説明に今のところは譲っておきます。[https://learn.microsoft.com/ja-jp/windows/win32/sysinfo/registry-key-security-and-access-rights https://learn.microsoft.com/ja-jp/windows/win32/sysinfo/registry-key-security-and-access-rights] | |||
'''第7引数''':CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes | '''第7引数''':CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes | ||
SECURITY_ATTRIBUTES型の変数で例えばsaなら&saとポインタを指定すると、そのメンバ変数sa.bInheritHandle = TRUEのように設定した値であったなら、子プロセスの継承が許可できます。このようにしてキーの作成をすると、プログラムで子プロセスを生成したときに継承を許可していれば、作成したキーが継承されて参照できるようになります。 | |||
'''第8引数''':PHKEY phkResult | '''第8引数''':PHKEY phkResult | ||
53行目: | 58行目: | ||
'''第9引数''':LPDWORD lpdwDisposition | '''第9引数''':LPDWORD lpdwDisposition | ||
いずれかの処理値を受け取る変数へのDWORD型のロングポインターを設定すると、その中身にREG_CREATED_NEW_KEY(1)かREG_OPENED_EXISTING_KEY(2)が返ります。1ならキーが存在せず作成されましたことを意味していて、2ならキーは存在し変更されずに単純に開かれたことを意味します。 | |||
63行目: | 70行目: | ||
/*4*/ nullptr, /*5*/ 0, /*6*/ KEY_WRITE, | /*4*/ nullptr, /*5*/ 0, /*6*/ KEY_WRITE, | ||
/*7*/ nullptr, /*8*/ &eventlabels, /*9*/ nullptr) == ERROR_SUCCESS){ | /*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); | |||
} | |||
</syntaxhighlight> | |||
RegCreateKeyExW関数を正常に実行できた場合、レジストリ編集をする必要がなくなった時にRegCloseKey関数を実行しないと、リソースリークが起きたままになります。必要がなくなったら、RegCloseKey関数を実行しましょう。簡単な関数ですが重要です。次の項目で紹介します。 | |||
=== RegCloseKey === | |||
キーに対する操作を閉じる処理です。 | |||
'''<span style="color:darkred;">■RegCloseKey(HKEY)</span>''' | |||
'''第1引数''':HKEY hKey | |||
RegCreateKeyExWでレジストリキー操作をしたときの第8引数に設定したHKEY型のポインタの実体の変数を設定すると、キー操作したときのキーハンドルを閉じることができます。実行しない場合はキーをオープンするために使用するリソースが解放されないままになってしまいます。必要がなくなったら閉じましょう。 | |||
コードのサンプルはひとつ前の項目で示したので省略します。 | |||
=== RegSetValueExW === | |||
第1引数に設定したキーハンドルに対して、第2引数に設定した値の名前と第5引数に設定したデータ値を設定する関数です。 | |||
'''<span style="color:darkred;">■RegSetValueExW(HKEY, LPCWSTR, DWORD, DWORD, CONST BYTE*, DWORD)</span>''' | |||
'''第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引数が指す情報のサイズ (バイト単位)。ヌル終端文字列の場合、最後のヌル文字に使うバイトも含める必要があります。 | |||
サンプル | |||
<syntaxhighlight lang="cpp" line start="1" highlight="7-12"> | |||
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); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
70行目: | 174行目: | ||
前の記事:[[Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例]] | 前の記事:[[Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例]] | ||
次の記事: | 次の記事:[[Win32/64技術 006 コンソールアプリケーションでリソースを使おう]] | ||
[[Win32/64_アプリケーション開発#処理技術|Win32/64_アプリケーション開発]]に戻る。 | [[Win32/64_アプリケーション開発#処理技術|Win32/64_アプリケーション開発]]に戻る。 | ||
2024年2月2日 (金) 14:31時点における最新版
前の記事: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 コンソールアプリケーションでリソースを使おう