C#でレジストリをいじってスタートアップにする

#１行概要
C#でレジストリキーHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Runをいじって任意のプログラムをスタートアップに設定する。

#はじめに
先日、好きなプロダクトに初PR・マージされた🎉
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/5da0def8-f7ad-7e66-71cd-62b4c2a03224.png)

そのプロダクトとは、[Windowsのタスクバーでもネコ走らせてみた🐈](https://qiita.com/Kyome/items/47aac4979933dac12263)で記事になっている『**RunCat for Windows**』だ。
タスクバーに常駐し、CPU負荷率に応じてネコが走るというもの。有名なアプリなので知っている方も多いはず。

私がPRで追加したのは、アプリのメニューアイテムに**スタートアップ**オプションを加えるというもの。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/dd9470e4-74b4-1be8-fc23-4247e19a0f6e.png)

本記事はマージ記念として、実際の修正内容をベースにC#でレジストリキーをいじってスタートアップに登録する方法を記述する。

#早い話が
スタートアップに纏わるレジストリキーは4つ。

- HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
- HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce
- HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
- HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

上2つはルートが*HKEY_CURRENT_USER*でマシンの全ユーザに対象となるもの、下2つは*HKEY_CURRENT_USER*で現在ログイン中のユーザに対象となるもの。
末尾の*Run*と*RunOnce*の違いは1回きりか半永久的にかというもの。

今回は上から3つ目、**HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run**の値をいじる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/e0c79b54-db2d-db11-4815-1d56bb9b20cf.png)

#C#からレジストリをいじる
MarshalByRefObject.[RegistryKey](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.registrykey?view=dotnet-plat-ext-3.1)クラスにWindowsレジストリを扱うメソッドが用意されている。
各リファレンスは次の通り。

###[RegistryKey.GetValue](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.registrykey.getvalue?view=dotnet-plat-ext-3.1)
**public object GetValue (string name, object defaultValue, Microsoft.Win32.RegistryValueOptions options)**
指定した名前に関連付けられている値を、取得オプションを指定して取得する。 名前が見つからない場合、設定されている既定値を返す。
####パラメーター
**name** : String 取得する値の名前。 この文字列の大文字と小文字は区別されない。
**defaultValue** : Object name が存在しない場合に返す値。
**options** : RegistryValueOptions 取得した値のオプションの処理を指定する列挙値の 1 つ。
####戻り値
**Object** name に関連付けられた値を、指定した options に従って処理したもの。defaultValue が見つからなかった場合は name。

###[RegistryKey.SetValue](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.registrykey.setvalue?view=dotnet-plat-ext-3.1)
**public void SetValue (string name, object value)**
指定した名前/値ペアを設定する。

####パラメーター
**name** : String 格納する値の名前。
**value** : Object 格納するデータ。

###[RegistryKey.DeleteValue](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.registrykey.deletevalue?view=dotnet-plat-ext-3.1)
**public void DeleteValue (string name)**
指定した値をこのキーから削除する。
####パラメーター
name : String 削除する値の名前。

###[RegistryKey.Close](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.registrykey.close?view=dotnet-plat-ext-3.1)
**public void Close ()**
キーを閉じ、キーの内容が変更されている場合はディスクへフラッシュする。

#実際のコード
追加をしたメソッドは主に次の2つだ。

###SetStartup
メニューアイテムのスタートアップオプションをクリックした際に発火する処理。
ラジオチェックの値を切り替え、オン/オフに応じてレジストリキーをセット/削除する。

```Program.cs
private void SetStartup(object sender, EventArgs e)
{
    startupMenu.Checked = !startupMenu.Checked;
    string keyName = @"Software\Microsoft\Windows\CurrentVersion\Run";
    using (RegistryKey rKey = Registry.CurrentUser.OpenSubKey(keyName, true))
    {
        if (startupMenu.Checked)
        {
            rKey.SetValue(Application.ProductName, Application.ExecutablePath);
        }
        else
        {
            rKey.DeleteValue(Application.ProductName, false);
        }
        rKey.Close();
    }
}
```

###IsStartupEnabled
レジストリの値を読み込み、nullでない（=IsStartupEnabled）ならtrueを、null（=IsNotStartupEnabled）ならfalseを返す。

```Program.cs
private bool IsStartupEnabled()
{
    string keyName = @"Software\Microsoft\Windows\CurrentVersion\Run";
    using (RegistryKey rKey = Registry.CurrentUser.OpenSubKey(keyName))
    {
        return (rKey.GetValue(Application.ProductName) != null) ? true : false;
    }
}
```

#おわりに
今回はC#でレジストリキーHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Runをいじって任意のプログラムをスタートアップに設定する内容を説明した。
好きなプロダクトにPRが通ったことは素直にうれしい経験だった。