C#でレジストリを読み書きする方法|RegistryKeyの使い方と権限・32/64bit対応をサンプルコードで解説
はじめに
C#では、Microsoft.Win32名前空間に用意されているRegistryKeyクラスを使用して、Windowsレジストリの読み取り、書き込み、更新、削除を行えます。
レジストリ操作は、デスクトップアプリケーションの設定保存、既存ソフトウェアの構成情報取得、Windowsとの連携機能などで利用されます。一方、操作するキーによっては管理者権限が必要になり、64bit版Windowsでは32bit用と64bit用のレジストリビューを意識しなければならない場合があります。
この記事では、C#でレジストリを読み書きする基本的な方法を、実行可能なサンプルコードとともに解説します。
なお、WindowsレジストリはOSやアプリケーションの動作に影響する重要なデータベースです。サンプルを試す際は、HKEY_CURRENT_USER\Software以下にテスト用キーを作成し、既存のシステム設定を変更しないようにしてください。
1. C#でレジストリを操作する前に知っておきたい基礎知識
1-1. Windowsレジストリとは
Windowsレジストリとは、Windows本体やアプリケーション、ユーザーごとの設定情報を階層構造で保存するデータベースです。
たとえば、次のような情報がレジストリに保存されます。
Windowsのシステム設定
インストール済みアプリケーションの情報
ファイルの関連付け
ユーザーごとのアプリケーション設定
ハードウェアやドライバーの構成情報
Windowsサービスの設定
設定ファイルと同じような用途で使われますが、Windowsによって一元的に管理される点が特徴です。
C#からレジストリを操作できるのはWindows環境です。クロスプラットフォームの.NETアプリケーションで使用する場合は、Windows上で実行されていることを確認してください。
if (!OperatingSystem.IsWindows()){Console.WriteLine("レジストリ操作はWindowsでのみ実行できます。");return;}1-2. レジストリのキー・サブキー・値の違い
レジストリは、キー、サブキー、値という要素で構成されています。
キーはフォルダーのような役割を持つ要素です。キーの中に作成されたキーをサブキーと呼びます。値は、キーに保存される実際の設定データです。
たとえば、次のレジストリパスを考えます。
HKEY_CURRENT_USER\Software\SampleCompany\SampleAppこの場合、各要素は次のように整理できます。
HKEY_CURRENT_USER ルートキー└─ Software サブキー└─ SampleCompany サブキー└─ SampleApp サブキー├─ UserName 値├─ LaunchCount 値└─ Theme 値SampleAppキーに、次のような値が登録されているイメージです。
値の名前: UserName値のデータ: Taro値の種類: REG_SZレジストリの「キーを読み取る」という表現が使われることもありますが、実際の処理では対象キーを開き、そのキーに登録されている値を取得します。
1-3. HKEY_CURRENT_USERやHKEY_LOCAL_MACHINEなど主要なルートキー
レジストリの最上位には、ルートキーと呼ばれる複数の領域があります。C#では、Registryクラスの静的プロパティやRegistryHive列挙型を使用してルートキーを指定できます。
代表的なルートキーは次のとおりです。
| ルートキー | C#での指定 | 主な用途 |
|---|---|---|
HKEY_CURRENT_USER | Registry.CurrentUser | 現在ログインしているユーザーの設定 |
HKEY_LOCAL_MACHINE | Registry.LocalMachine | コンピューター全体の設定 |
HKEY_CLASSES_ROOT | Registry.ClassesRoot | ファイルの関連付けやCOMクラス情報 |
HKEY_USERS | Registry.Users | コンピューター上のユーザー設定 |
HKEY_CURRENT_CONFIG | Registry.CurrentConfig | 現在使用中のハードウェア構成 |
Microsoftの公式ドキュメントでも、Registry.CurrentUserはユーザー設定、Registry.LocalMachineはローカルコンピューターの構成情報を格納するルートキーとして説明されています。
アプリケーション固有のユーザー設定を保存する場合は、一般的に次のような場所を使用します。
HKEY_CURRENT_USER\Software\会社名\アプリケーション名HKEY_CURRENT_USER以下の自分用のキーであれば、通常は管理者権限なしで書き込めます。
一方、HKEY_LOCAL_MACHINE以下はコンピューター全体に影響するため、キーのアクセス制御設定によっては管理者権限が必要です。書き込み権限がない状態で変更しようとすると、UnauthorizedAccessExceptionやSecurityExceptionが発生します。
アプリケーションの設定保存だけが目的であれば、管理者権限を必要とするHKEY_LOCAL_MACHINEではなく、HKEY_CURRENT_USERの利用を優先するとよいでしょう。
1-4. C#で使用するMicrosoft.Win32名前空間とRegistryKeyクラス
C#でレジストリを操作するには、Microsoft.Win32名前空間を使用します。
using Microsoft.Win32;中心となるのがRegistryKeyクラスです。主なメソッドには次のものがあります。
| メソッド | 用途 |
OpenSubKey | 既存のサブキーを開く |
CreateSubKey | サブキーを作成する、または既存のサブキーを開く |
GetValue | 値を読み取る |
SetValue | 値を書き込む、または更新する |
GetValueNames | 値名を一覧取得する |
GetSubKeyNames | サブキー名を一覧取得する |
DeleteValue | 値を削除する |
DeleteSubKey | 空のサブキーを削除する |
DeleteSubKeyTree | 子キーを含めてサブキーを削除する |
RegistryKeyは、指定されたレジストリキーへのハンドルを管理するクラスです。使い終わったら破棄する必要があるため、通常はusing文またはusing宣言を使用します。
.NETのプロジェクト構成によって参照エラーになる場合は、Microsoft.Win32.Registryパッケージが利用可能か確認してください。
dotnet add package Microsoft.Win32.Registryまた、Windows専用アプリケーションであることをプロジェクトに明示する場合は、ターゲットフレームワークに-windowsを付けられます。
<PropertyGroup><TargetFramework>net8.0-windows</TargetFramework><Nullable>enable</Nullable></PropertyGroup>32bit版と64bit版のレジストリビュー
64bit版Windowsでは、レジストリの一部が32bitアプリケーション用と64bitアプリケーション用に分けて管理されています。そのため、同じパスを指定しても、プロセスのビット数によって異なる値が見えることがあります。
RegistryView列挙型では、次のビューを指定できます。
RegistryView.Default:実行プロセスに応じた既定のビューRegistryView.Registry32:32bitレジストリビューRegistryView.Registry64:64bitレジストリビュー
Microsoftの公式ドキュメントでは、64bit版Windowsにおいて32bitアプリケーションには32bitビュー、64bitアプリケーションには64bitビューが提供されると説明されています。
特定のビューを明示して開く場合は、RegistryKey.OpenBaseKeyを使用します。
using RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,RegistryView.Registry64);using RegistryKey? key = baseKey.OpenSubKey(@"Software\SampleCompany\SampleApp");
if (key is not null){Console.WriteLine(key.GetValue("Version"));}
32bit側を参照する場合は、RegistryView.Registry32を指定します。
using RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,RegistryView.Registry32);OpenBaseKeyは、指定したルートキーとレジストリビューを持つRegistryKeyを開くメソッドです。
1-5. レジストリ操作が必要になる主なケース
C#でレジストリ操作が必要になる主なケースには、次のようなものがあります。
既存のWindowsアプリケーションの設定を読み取る
ユーザーごとのアプリケーション設定を保存する
インストール済みソフトウェアの情報を確認する
ファイルの関連付けを確認する
Windowsサービスやドライバーの構成情報を参照する
旧来のデスクトップアプリケーションとの互換性を維持する
COMコンポーネントの登録情報を確認する
ただし、新規アプリケーションの設定保存では、必ずしもレジストリを使用する必要はありません。JSON、XML、ユーザー設定ファイル、データベースなどのほうが、移植性や保守性に優れる場合もあります。
また、パスワードやAPIキーなどの機密情報を、そのままレジストリに保存してはいけません。レジストリは設定の保存場所であり、保存したデータを自動的に暗号化してくれる仕組みではないためです。
2. C#でレジストリの値を読み取る方法
2-1. RegistryKey.OpenSubKeyでレジストリキーを開く
既存のレジストリキーを開くには、OpenSubKeyメソッドを使用します。
using Microsoft.Win32;const string subKeyPath = @"Software\SampleCompany\SampleApp";
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(subKeyPath);
if (key is null){Console.WriteLine("指定したレジストリキーは存在しません。");return;}
Console.WriteLine($"キーを開きました: {key.Name}");
引数には、ルートキーからの相対パスを指定します。
Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp");このコードが開く場所は次のとおりです。
HKEY_CURRENT_USER\Software\SampleCompany\SampleApp引数を1つだけ指定するOpenSubKey(string)は、キーを読み取り専用で開きます。キーが存在しない場合は例外ではなくnullが返されるため、必ずnullを確認しましょう。
2-2. GetValueで指定した値を取得する
開いたキーから値を取得するには、GetValueメソッドを使用します。
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp");if (key is null){Console.WriteLine("キーが存在しません。");return;}
object? value = key.GetValue("UserName");
if (value is null){Console.WriteLine("値が存在しません。");}else{Console.WriteLine($"UserName: {value}");}
GetValueの戻り値はobject型です。レジストリ値の種類に応じて、実際の型が異なります。
| レジストリの種類 | RegistryValueKind | C#で取得される主な型 |
REG_SZ | String | string |
REG_EXPAND_SZ | ExpandString | string |
REG_DWORD | DWord | int |
REG_QWORD | QWord | long |
REG_MULTI_SZ | MultiString | string[] |
REG_BINARY | Binary | byte[] |
型を確認しながら取得すると安全です。
object? rawValue = key.GetValue("LaunchCount");if (rawValue is int launchCount){Console.WriteLine($"起動回数: {launchCount}");}else{Console.WriteLine("LaunchCountはDWORD値ではありません。");}
文字列として取得する場合は、Convert.ToStringも利用できます。
string userName =Convert.ToString(key.GetValue("UserName")) ?? string.Empty;ただし、数値や配列なども文字列へ変換される可能性があるため、値の種類が決まっている場合はパターンマッチングによる型確認を推奨します。
2-3. 値が存在しない場合のデフォルト値を指定する
GetValueの第2引数には、値が存在しない場合に返すデフォルト値を指定できます。
object value = key.GetValue("Theme","Light");Console.WriteLine(value);
Themeが存在すれば登録値が返り、存在しなければ"Light"が返ります。
数値のデフォルト値も指定できます。
object value = key.GetValue("LaunchCount",0);int launchCount = value is int count ? count : 0;
Console.WriteLine($"起動回数: {launchCount}");
GetValueは、指定した値が見つからない場合に第2引数のdefaultValueを返します。第2引数を指定しないオーバーロードでは、値が見つからない場合にnullが返ります。
ただし、デフォルト値と同じデータが実際に登録されている可能性もあります。値の存在そのものを判定したい場合は、GetValueNamesで値名を確認する方法があります。
bool exists = key.GetValueNames().Contains("Theme", StringComparer.OrdinalIgnoreCase);2-4. GetValueNamesで登録されている値名を一覧取得する
キーに登録されている値名を一覧取得するには、GetValueNamesメソッドを使用します。
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp");if (key is null){Console.WriteLine("キーが存在しません。");return;}
string[] valueNames = key.GetValueNames();
foreach (string valueName in valueNames){object? value = key.GetValue(valueName);
string displayName =string.IsNullOrEmpty(valueName)? "(既定)": valueName;Console.WriteLine($"{displayName}: {FormatValue(value)}");
}
static string FormatValue(object? value){return value switch{null => "(null)",string[] values => string.Join(", ", values),byte[] bytes => Convert.ToHexString(bytes),_ => value.ToString() ?? string.Empty};}
名前のない既定値が登録されている場合、値名は空文字列として返されます。
値名だけでなく、値の種類も取得できます。
foreach (string valueName in key.GetValueNames()){RegistryValueKind valueKind =key.GetValueKind(valueName);object? value = key.GetValue(valueName);Console.WriteLine($"名前: {valueName}, 種類: {valueKind}, 値: {value}");
}
2-5. GetSubKeyNamesでサブキーを一覧取得する
現在開いているキーの直下にあるサブキー名を取得するには、GetSubKeyNamesメソッドを使用します。
using RegistryKey? softwareKey =Registry.CurrentUser.OpenSubKey(@"Software");if (softwareKey is null){Console.WriteLine("Softwareキーが存在しません。");return;}
string[] subKeyNames = softwareKey.GetSubKeyNames();
foreach (string subKeyName in subKeyNames){Console.WriteLine(subKeyName);}
GetSubKeyNamesの戻り値は、現在のキー直下にあるサブキー名を格納したstring[]です。孫キー以降は自動的に列挙されません。
サブキーの内部も確認する場合は、取得した名前を使って順番に開きます。
foreach (string subKeyName in softwareKey.GetSubKeyNames()){using RegistryKey? subKey =softwareKey.OpenSubKey(subKeyName);if (subKey is null){continue;}Console.WriteLine($"{subKey.Name}: 値の数={subKey.ValueCount}");
}
2-6. using文でRegistryKeyを安全に破棄する
RegistryKeyは、Windowsレジストリキーへのハンドルを保持します。使用後はDisposeまたはCloseを呼び出して、リソースを解放する必要があります。
C#では、using宣言を使用する方法が簡潔です。
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp");if (key is null){return;}
// スコープを抜けると自動的にDisposeされるobject? value = key.GetValue("UserName");
従来形式のusing文でも構いません。
using (RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp")){if (key is null){return;}object? value = key.GetValue("UserName");Console.WriteLine(value);
}
Registry.CurrentUserやRegistry.LocalMachineの静的プロパティから取得したルートキーを直接破棄する必要は通常ありませんが、OpenSubKey、CreateSubKey、OpenBaseKeyなどで取得したRegistryKeyはusingで管理すると安全です。
2-7. レジストリ値を読み取るサンプルコード
次のコードは、ユーザー名、起動回数、テーマをレジストリから読み取るサンプルです。
using Microsoft.Win32;using System.Security;internal class Program{private const string SubKeyPath =@"Software\SampleCompany\SampleApp";
private static void Main(){if (!OperatingSystem.IsWindows()){Console.WriteLine("このプログラムはWindowsで実行してください。");return;}try{using RegistryKey? key =Registry.CurrentUser.OpenSubKey(SubKeyPath,writable: false);if (key is null){Console.WriteLine($"キーが存在しません: {SubKeyPath}");return;}string userName =key.GetValue("UserName", "未設定") as string?? "未設定";int launchCount =key.GetValue("LaunchCount", 0) is int count? count: 0;string theme =key.GetValue("Theme", "Light") as string?? "Light";Console.WriteLine($"ユーザー名: {userName}");Console.WriteLine($"起動回数: {launchCount}");Console.WriteLine($"テーマ: {theme}");Console.WriteLine();Console.WriteLine("登録されている値:");foreach (string valueName in key.GetValueNames()){object? value = key.GetValue(valueName);Console.WriteLine($"- {valueName}: {FormatValue(value)}");}Console.WriteLine();Console.WriteLine("登録されているサブキー:");foreach (string subKeyName in key.GetSubKeyNames()){Console.WriteLine($"- {subKeyName}");}}catch (UnauthorizedAccessException ex){Console.WriteLine($"レジストリへのアクセス権がありません: {ex.Message}");}catch (SecurityException ex){Console.WriteLine($"セキュリティ上の理由でアクセスできません: {ex.Message}");}catch (IOException ex){Console.WriteLine($"レジストリの読み取り中にI/Oエラーが発生しました: {ex.Message}");}}private static string FormatValue(object? value){return value switch{null => "(null)",string[] values => string.Join(", ", values),byte[] bytes => Convert.ToHexString(bytes),_ => value.ToString() ?? string.Empty};}
}
32bitまたは64bitのレジストリビューを明示して読み取る共通メソッドは、次のように作成できます。
using Microsoft.Win32;static object? ReadRegistryValue(RegistryHive hive,RegistryView view,string subKeyPath,string valueName,object? defaultValue = null){using RegistryKey baseKey =RegistryKey.OpenBaseKey(hive, view);
using RegistryKey? key =baseKey.OpenSubKey(subKeyPath,writable: false);return key?.GetValue(valueName, defaultValue)?? defaultValue;
}
呼び出し例は次のとおりです。
object? value64 = ReadRegistryValue(RegistryHive.LocalMachine,RegistryView.Registry64,@"Software\SampleCompany\SampleApp","Version","未登録");object? value32 = ReadRegistryValue(RegistryHive.LocalMachine,RegistryView.Registry32,@"Software\SampleCompany\SampleApp","Version","未登録");
Console.WriteLine($"64bitビュー: {value64}");Console.WriteLine($"32bitビュー: {value32}");
3. C#でレジストリに値を書き込む方法
3-1. CreateSubKeyでレジストリキーを作成・取得する
レジストリキーを新しく作成するには、CreateSubKeyメソッドを使用します。
using Microsoft.Win32;const string subKeyPath =@"Software\SampleCompany\SampleApp";
using RegistryKey key =Registry.CurrentUser.CreateSubKey(subKeyPath)?? throw new InvalidOperationException("レジストリキーを作成できませんでした。");
Console.WriteLine($"作成または取得したキー: {key.Name}");
指定したキーが存在しない場合は、新しいキーが作成されます。すでに存在する場合は、既存のキーが書き込み可能な状態で開かれます。
中間のサブキーが存在しない場合も、まとめて作成できます。
Registry.CurrentUser.CreateSubKey(@"Software\SampleCompany\SampleApp");この場合、SampleCompanyやSampleAppが存在しなければ自動的に作成されます。
3-2. 書き込み可能な状態でOpenSubKeyを開く
既存のキーを書き込み可能な状態で開くには、OpenSubKeyの第2引数にtrueを指定します。
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp",writable: true);if (key is null){Console.WriteLine("キーが存在しません。");return;}
key.SetValue("Theme", "Dark");
第2引数がfalseの場合は読み取り専用です。
using RegistryKey? readOnlyKey =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp",writable: false);読み取り専用で開いたキーにSetValueを実行すると、UnauthorizedAccessExceptionが発生します。writable: trueは書き込みアクセスを要求する指定であり、Windowsのアクセス権そのものを付与する指定ではありません。ユーザーに権限がなければ、書き込み可能な状態では開けません。
既存キーがなければ作成したい場合は、OpenSubKeyではなくCreateSubKeyを使用します。
3-3. SetValueで文字列や数値を書き込む
レジストリに値を書き込むには、SetValueメソッドを使用します。
文字列を書き込む例は次のとおりです。
key.SetValue("UserName", "Taro");整数を書き込む例は次のとおりです。
key.SetValue("LaunchCount", 10);第3引数を省略すると、C#側の値の型からレジストリ値の種類が推測されます。
key.SetValue("Theme", "Dark");key.SetValue("LaunchCount", 10);key.SetValue("LastFileSize", 123456789L);より意図を明確にするため、実務ではRegistryValueKindを指定する方法が推奨されます。
3-4. RegistryValueKindで値の種類を明示する
SetValueの第3引数にRegistryValueKindを指定すると、保存するレジストリ値の種類を明示できます。
key.SetValue("UserName","Taro",RegistryValueKind.String);key.SetValue("LaunchCount",10,RegistryValueKind.DWord);
key.SetValue("LastFileSize",123456789L,RegistryValueKind.QWord);
配列やバイナリデータも保存できます。
string[] recentFiles ={@"C:\Data\report.xlsx",@"C:\Data\memo.txt"};key.SetValue("RecentFiles",recentFiles,RegistryValueKind.MultiString);
byte[] binaryData ={0x01,0x02,0x03,0xFF};
key.SetValue("BinaryData",binaryData,RegistryValueKind.Binary);
環境変数を含む文字列をREG_EXPAND_SZとして保存する場合は、ExpandStringを指定します。
key.SetValue("LogDirectory",@"%LOCALAPPDATA%\SampleCompany\SampleApp\Logs",RegistryValueKind.ExpandString);SetValueでは、オーバーロードに応じてC#の値の型からデータ型を決定するか、指定したRegistryValueKindを使用して値を保存します。
3-5. 既存のレジストリ値を更新する
SetValueで指定した値名がすでに存在する場合、その値は上書きされます。
key.SetValue("Theme","Light",RegistryValueKind.String);// 同じ値名を指定すると更新されるkey.SetValue("Theme","Dark",RegistryValueKind.String);
現在の値を取得してから更新することもできます。
int currentCount =key.GetValue("LaunchCount", 0) is int count? count: 0;int newCount = checked(currentCount + 1);
key.SetValue("LaunchCount",newCount,RegistryValueKind.DWord);
checkedを使用すると、intの上限を超えた場合にOverflowExceptionが発生するため、意図しない桁あふれを検出できます。
複数のプロセスが同じレジストリ値を同時に更新する可能性がある場合、読み取りと書き込みの間に別プロセスが値を変更することがあります。カウンターなどの厳密な排他制御が必要なデータには、レジストリよりもデータベースや適切な同期機構を利用した保存方法が向いています。
3-6. アプリケーション設定を書き込むサンプルコード
次のコードは、HKEY_CURRENT_USER以下にアプリケーション設定を書き込むサンプルです。
using Microsoft.Win32;using System.Security;internal class Program{private const string SubKeyPath =@"Software\SampleCompany\SampleApp";
private static void Main(){if (!OperatingSystem.IsWindows()){Console.WriteLine("このプログラムはWindowsで実行してください。");return;}try{using RegistryKey key =Registry.CurrentUser.CreateSubKey(SubKeyPath,writable: true)?? throw new InvalidOperationException("レジストリキーを作成できませんでした。");key.SetValue("UserName","Taro",RegistryValueKind.String);key.SetValue("Theme","Dark",RegistryValueKind.String);key.SetValue("LaunchCount",1,RegistryValueKind.DWord);key.SetValue("LastFileSize",123456789L,RegistryValueKind.QWord);key.SetValue("RecentFiles",new[]{@"C:\Data\report.xlsx",@"C:\Data\memo.txt"},RegistryValueKind.MultiString);key.SetValue("LogDirectory",@"%LOCALAPPDATA%\SampleCompany\SampleApp\Logs",RegistryValueKind.ExpandString);Console.WriteLine("アプリケーション設定を書き込みました。");}catch (UnauthorizedAccessException ex){Console.WriteLine($"レジストリへの書き込み権限がありません: {ex.Message}");}catch (SecurityException ex){Console.WriteLine($"セキュリティ上の理由で書き込めません: {ex.Message}");}catch (IOException ex){Console.WriteLine($"レジストリへの書き込み中にI/Oエラーが発生しました: {ex.Message}");}catch (ArgumentException ex){Console.WriteLine($"値の名前、データ、または型が不正です: {ex.Message}");}}
}
HKEY_LOCAL_MACHINEに書き込む場合の権限
コンピューター全体の設定としてHKEY_LOCAL_MACHINEに書き込む場合は、次のようなコードになります。
using RegistryKey key =Registry.LocalMachine.CreateSubKey(@"Software\SampleCompany\SampleApp",writable: true)?? throw new InvalidOperationException("レジストリキーを作成できませんでした。");key.SetValue("InstallPath",@"C:\Program Files\SampleApp",RegistryValueKind.String);
ただし、HKEY_LOCAL_MACHINE\Software以下への書き込みは、アクセス制御設定によって管理者権限を求められるのが一般的です。
権限が必要な処理は、インストーラーや管理ツールに限定することを検討してください。通常のアプリケーション設定を保存するためだけに、アプリ全体を常に管理者として実行する設計は避けたほうが安全です。
32bit・64bitビューを明示して書き込む場合
64bitレジストリビューを明示して書き込む例は次のとおりです。
using RegistryKey baseKey =RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,RegistryView.Registry64);using RegistryKey key =baseKey.CreateSubKey(@"Software\SampleCompany\SampleApp",writable: true)?? throw new InvalidOperationException("レジストリキーを作成できませんでした。");
key.SetValue("Version","1.0.0",RegistryValueKind.String);
32bitビューに書き込む場合は、RegistryView.Registry32を指定します。
using RegistryKey baseKey =RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,RegistryView.Registry32);アプリケーションのビット数にかかわらず同じビューへアクセスさせたい場合は、RegistryView.Defaultに任せず、Registry32またはRegistry64を明示すると動作を統一できます。
3-7. 書き込み後の値を読み取って確認する方法
書き込みが完了したら、同じRegistryKeyからGetValueを呼び出して内容を確認できます。
using RegistryKey key =Registry.CurrentUser.CreateSubKey(@"Software\SampleCompany\SampleApp")?? throw new InvalidOperationException("レジストリキーを作成できませんでした。");key.SetValue("Theme","Dark",RegistryValueKind.String);
string theme =key.GetValue("Theme", "Light") as string?? "Light";
Console.WriteLine($"書き込み後の値: {theme}");
キーを一度閉じてから、読み取り専用で開き直して確認する方法もあります。
const string subKeyPath =@"Software\SampleCompany\SampleApp";using (RegistryKey writeKey =Registry.CurrentUser.CreateSubKey(subKeyPath)?? throw new InvalidOperationException("レジストリキーを作成できませんでした。")){writeKey.SetValue("Theme","Dark",RegistryValueKind.String);}
using RegistryKey? readKey =Registry.CurrentUser.OpenSubKey(subKeyPath,writable: false);
if (readKey is null){Console.WriteLine("書き込み後のキーを確認できません。");return;}
string theme =readKey.GetValue("Theme", "未設定") as string?? "未設定";
Console.WriteLine($"確認結果: {theme}");
書き込み時と読み取り時でレジストリビューが異なると、保存した値が見つからないことがあります。Registry32またはRegistry64を指定している場合は、読み書きの両方で同じビューを使用してください。
4. レジストリのキーや値を削除する方法
4-1. DeleteValueで指定した値を削除する
指定した値を削除するには、キーを書き込み可能な状態で開き、DeleteValueメソッドを使用します。
using RegistryKey? key =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany\SampleApp",writable: true);if (key is null){Console.WriteLine("キーが存在しません。");return;}
key.DeleteValue("Theme");
Console.WriteLine("Themeを削除しました。");
存在しない値を指定したときに例外を発生させたくない場合は、第2引数にfalseを指定します。
key.DeleteValue("Theme",throwOnMissingValue: false);第2引数にtrueを指定すると、値が存在しない場合にArgumentExceptionが発生します。
key.DeleteValue("Theme",throwOnMissingValue: true);DeleteValueを実行するキーは、書き込み可能な状態で開かなければなりません。読み取り専用のキーに対して実行すると、UnauthorizedAccessExceptionが発生します。
値を削除した後は、GetValueで確認できます。
object result =key.GetValue("Theme", "削除済み");Console.WriteLine(result);
4-2. DeleteSubKeyで空のサブキーを削除する
空のサブキーを削除するには、削除対象の親キーからDeleteSubKeyを呼び出します。
たとえば、次のキーを削除する場合を考えます。
HKEY_CURRENT_USER\Software\SampleCompany\SampleApp親となるSampleCompanyキーを開き、SampleAppを削除します。
using RegistryKey? parentKey =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany",writable: true);if (parentKey is null){Console.WriteLine("親キーが存在しません。");return;}
parentKey.DeleteSubKey("SampleApp",throwOnMissingSubKey: false);
Console.WriteLine("SampleAppキーを削除しました。");
DeleteSubKeyで削除できるのは、子サブキーを持たないキーだけです。削除対象に子サブキーがある場合は、InvalidOperationExceptionが発生します。
子サブキーを含めて再帰的に削除する必要がある場合は、DeleteSubKeyTreeを使用します。
using RegistryKey? parentKey =Registry.CurrentUser.OpenSubKey(@"Software\SampleCompany",writable: true);if (parentKey is null){return;}
parentKey.DeleteSubKeyTree("SampleApp",throwOnMissingSubKey: false);
DeleteSubKeyTreeは、指定したサブキーと、その配下にあるすべての子サブキーを削除します。元に戻せないため、対象パスを十分に確認してから実行してください。
削除処理をメソッド化する場合は、次のように記述できます。
using Microsoft.Win32;using System.Security;static bool DeleteApplicationSettings(){const string parentPath =@"Software\SampleCompany";
const string targetSubKey ="SampleApp";try{using RegistryKey? parentKey =Registry.CurrentUser.OpenSubKey(parentPath,writable: true);if (parentKey is null){return false;}parentKey.DeleteSubKeyTree(targetSubKey,throwOnMissingSubKey: false);return true;}catch (UnauthorizedAccessException ex){Console.WriteLine($"削除権限がありません: {ex.Message}");return false;}catch (SecurityException ex){Console.WriteLine($"セキュリティ上の理由で削除できません: {ex.Message}");return false;}catch (IOException ex){Console.WriteLine($"削除中にI/Oエラーが発生しました: {ex.Message}");return false;}
}
レジストリを削除するときは、ルートキーからの相対パスと削除対象のサブキー名を分けて指定します。誤って上位のキーを指定すると、他のアプリケーションやWindowsの設定まで削除する危険があります。
まとめ
C#でレジストリを読み書きする場合は、Microsoft.Win32名前空間のRegistryKeyクラスを使用します。
既存キーを読み取る場合はOpenSubKey、キーを作成する場合はCreateSubKeyを使用します。値の取得にはGetValue、書き込みや更新にはSetValueを使用し、値の種類はRegistryValueKindで明示できます。
値を削除するときはDeleteValue、空のサブキーを削除するときはDeleteSubKeyを使用します。子サブキーを含めて削除するDeleteSubKeyTreeは影響範囲が大きいため、特に慎重に扱う必要があります。
また、レジストリ操作では次の点が重要です。
アプリケーション設定は、可能な限り
HKEY_CURRENT_USER以下に保存するHKEY_LOCAL_MACHINEへの書き込みは権限エラーを考慮するRegistryKeyはusingで確実に破棄するOpenSubKeyがnullを返す可能性を考慮するGetValueの戻り値を適切な型へ変換する64bit版Windowsでは
Registry32とRegistry64の違いを確認する読み取り時と書き込み時で同じレジストリビューを使用する
システムや他のアプリケーションのキーを不用意に変更しない
パスワードなどの機密情報を平文で保存しない
これらを意識すれば、C#からWindowsレジストリを安全かつ確実に操作できます。

