【C#】【Windows 10】 拡張子、プロトコル、アンインストール情報をレジストリ登録

こんにちは、Takymです。
また、投稿サボってすみません。
今回は、拡張子プロトコル、ソフトウェア等のアンインストール情報がどのようにレジストリに登録されているのかを解説したいと思います。
以前にも似たような記事を書いた事があります。(その時の内容は余りにも酷かったです。)

注意事項

  • この情報は僕がレジストリエディタから独自に調べた物です。
  • 間違っている可能性があります。間違っている場合はコメント欄等で教えてください。
  • また、「Microsoft Windows 10 1709 Fall Creators Update (Redstone 4)」で動作確認をしています。
  • レジストリを改変するとコンピュータに不具合が発生する可能性があります。必ずバックアップを取って細心の注意を払ってください。

構造

まず、拡張子もプロトコルも「HKEY_CLASSES_ROOT」の直下に保存されます。 拡張子のキー名は先頭にピリオド(.)が付きます。ただし、プロトコルの場合は末尾にコロン(:)は付きません

(※疑問符(?)が付いている物は僕がまだ理解していない項目です。)

拡張子

名前 種類 内容
(限定) 文字列 (REG_SZ) ProgID と呼ばれるHKEY_CLASSES_ROOTの直下に置かれるキーの名前、ここに拡張子の詳細設定が記述される
Content Type 文字列 (REG_SZ) ファイルのMIME。
PerceivedType 文字列 (REG_SZ) MIMEのスラッシュ(/)より前の文字列(?)。

更に、このキーの直下に以下のサブキーが保存されている事があります。

  • OpenWithProgids: 「プログラムから開く」に表示される項目のProgIDの一覧(?)
  • PersistentHandler: 謎… (限定の値がクラスIDになっている)

ProgID

このキーの限定の値ファイルの説明になります。
このキーのサブキーには、DefaultIconshellが含まれています。
DefaultIconはファイルのアイコンを表しています。
shellの中には”動詞”と呼ばれるファイルを右クリックした時に現れるメニューの項目を表しています。
この”動詞”キーの限定の値はメニューに表示されます。
“動詞”キーの中には”command”キーがあり、ここにファイルの呼び出しコマンドを書きこみます。

プロトコル

プロトコルキーProgIDキーと同じ内容になっています。
因みに、拡張子の登録で利用したProgIDプロトコルとして起動する事もできます。
エクスプローラ等のアドレスバーに「txtfile:hello」と打つとメモ帳が起動してくれる筈です。
ただし、「C:\Windows\System32\txtfile:helloは存在しません」というエラーが発生します。

アンインストール情報

こちらは拡張子やプロトコルとはかなり違う仕様になっています。
アンインストール情報は「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall」に配置します。

名前 種類 内容
Comments 文字列 (REG_SZ) コメント
Contact 文字列 (REG_SZ) 開発者の連絡先のメールアドレス
DisplayIcon 文字列 (REG_SZ) 「プログラムの削除と追加」に表示されるアイコンのパス
DisplayName 文字列 (REG_SZ) アプリケーションの表示名
DisplayVersion 文字列 (REG_SZ) アプリケーションのバージョン
EstimatedSize 数値 (REG_DWORD) アプリケーションのディスク上のサイズ (?)
HelpLink 文字列 (REG_SZ) ヘルプ情報が記述されているアドレス
InstallDate 文字列 (REG_SZ) インストール日時 “yyyyMMdd”の形式で記述
InstallLocation 文字列 (REG_SZ) インストール先のディレクトリ
InstallSource 文字列 (REG_SZ) インストール元のディレクトリ (?)
ModifyPath 文字列 (REG_EXPAND_SZ) 変更用のインストーラの起動コマンド
Publisher 文字列 (REG_ESZ) 発行者
RepairPath 文字列 (REG_EXPAND_SZ) 修復用のインストーラの起動コマンド (あるかどうか分からない)
Size 文字列 (REG_ESZ) アプリケーションのディスク上のサイズ (?)
UninstallString 文字列 (REG_EXPAND_ESZ) アンインストーラの起動コマンド

2018/09/27 追記
https://docs.microsoft.com/ja-jp/windows/desktop/msi/uninstall-registry-keyにここより詳しい情報が載っています。
(この記事では、レジストリを独自に調べた為、上記の本家サイトも確認する事をお勧めします。)

プログラム

まだ準備していません。現在、作成中です。すみません。
2018/09/17 ソースコード追加
以下のExtension.cs、Protocol.cs、UninstallInfo.csはC#からプロトコル、拡張子、アンインストール情報を登録する為のサンプルプログラムです。

using System;
using System.Collections.Generic;
using Microsoft.Win32;
namespace Extprotuninst
{
public class Extension
{
public string Name { get; set; }
public Protocol ProgID { get; set; }
public string ContentType { get; set; }
public string PerceivedType { get; set; }
public List<Protocol> OpenWithProgIDs { get; set; }
public Guid PersistentHandler { get; set; }
public void Save()
{
using (var ext = Registry.ClassesRoot.CreateSubKey($".{this.Name}")) {
ext.SetValue(null, this.ProgID.Name, RegistryValueKind.String);
ext.SetValue("Content Type", this.ContentType, RegistryValueKind.String);
ext.SetValue("PerceivedType", this.PerceivedType, RegistryValueKind.String);
using (var owp = ext.CreateSubKey("OpenWithProgids")) {
foreach (var item in this.OpenWithProgIDs) {
owp.SetValue(item.Name, string.Empty, RegistryValueKind.Unknown);
}
}
using (var ph = ext.CreateSubKey("PersistentHandler")) {
ph.SetValue(null, $"{{{this.PersistentHandler}}}", RegistryValueKind.String);
}
}
}
}
}
using System.Collections.Generic;
using System.IO;
using Microsoft.Win32;
namespace Extprotuninst
{
public class Protocol
{
public string Name { get; set; }
public string Description { get; set; }
public string IconPath { get; set; }
public int IconIndex { get; set; }
public Dictionary<string, (string text, string command)> Verbs { get; set; }
public void Save()
{
using (var prot = Registry.ClassesRoot.CreateSubKey(this.Name)) {
prot.SetValue(null, this.Description, RegistryValueKind.String);
using (var icon = prot.CreateSubKey("DefaultIcon")) {
icon.SetValue(null, $"\"{Path.GetFullPath(this.IconPath)}\", {this.IconIndex}", RegistryValueKind.String);
}
using (var shell = prot.CreateSubKey("shell")) {
foreach (var item in this.Verbs) {
using (var v = shell.CreateSubKey(item.Key)) {
v.SetValue(null, item.Value.text, RegistryValueKind.String);
using (var c = v.CreateSubKey("command")) {
c.SetValue(null, item.Value.command, RegistryValueKind.String);
}
}
}
}
}
}
}
}
using System;
using System.IO;
using Microsoft.Win32;
namespace Extprotuninst
{
public class UninstallInfo
{
public string Comments { get; set; }
public string Contact { get; set; }
public string IconPath { get; set; }
public int IconIndex { get; set; }
public string Name { get; set; }
public Version Version { get; set; }
public string Location { get; set; }
public string ModifyPath { get; set; }
public string Publisher { get; set; }
public string RepairPath { get; set; } // 効果無し
public string UninstallPath { get; set; }
public string Identifier { get; set; }
public void Save()
{
// HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall に保存される場合もある。
using (var un = Registry.LocalMachine.CreateSubKey("SOFTWARE")
.CreateSubKey("Microsoft").CreateSubKey("Windows").CreateSubKey("CurrentVersion")
.CreateSubKey("Uninstall").CreateSubKey(this.Identifier)) {
un.SetValue("Comments", this.Comments, RegistryValueKind.String);
un.SetValue("Contact", this.Contact, RegistryValueKind.String);
un.SetValue("DisplayIcon", $"\"{Path.GetFullPath(this.IconPath)}\", {this.IconIndex}", RegistryValueKind.String);
un.SetValue("DisplayName", this.Name, RegistryValueKind.String);
un.SetValue("DisplayVersion", this.Version, RegistryValueKind.String);
un.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd"), RegistryValueKind.String);
un.SetValue("InstallLocation", Path.GetFullPath(this.Location), RegistryValueKind.String);
un.SetValue("ModifyPath", this.ModifyPath, RegistryValueKind.String);
un.SetValue("Publisher", this.Publisher, RegistryValueKind.String);
un.SetValue("RepairPath", this.RepairPath, RegistryValueKind.String); // 効果無し
un.SetValue("UninstallString", this.UninstallPath, RegistryValueKind.String);
}
}
}
}

ExtensionクラスではProgIDとしてProtocolクラスを流用しています。
(※注意:これらのプログラムには読み込み処理と削除処理は含まれていません。)
以下のProgramクラスの様に呼び出して利用します。

using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Extprotuninst
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < args.Length; ++i) {
Console.WriteLine($"{i}: {args[i]}");
}
Console.ReadKey(true);
Protocol p = new Protocol();
p.Name = "hello";
p.Description = "Hello, World!!";
p.IconPath = "C:\\Windows\\System32\\shell32.dll";
p.IconIndex = 41;
p.Verbs = new Dictionary<string, (string text, string command)>();
p.Verbs.Add("open", ("開く (&O)", $"\"{Application.ExecutablePath}\" OPEN %1"));
p.Verbs.Add("edit", ("編集 (&E)", $"\"{Application.ExecutablePath}\" EDIT %1"));
p.Save();
Extension e = new Extension();
e.Name = "hello";
e.ProgID = p;
e.ContentType = "hoge-fuga-piyo/hello-world";
e.PerceivedType ="hoge-fuga-piyo";
e.OpenWithProgIDs = new List<Protocol>();
e.OpenWithProgIDs.Add(p);
e.PersistentHandler = Guid.Empty;
e.Save();
UninstallInfo u = new UninstallInfo();
u.Comments = "Hello and Bye";
u.Contact = "yourname@example.com";
u.IconPath = "C:\\Windows\\System32\\shell32.dll";
u.IconIndex = 42;
u.Location = Application.StartupPath;
u.ModifyPath = $"\"{Application.ExecutablePath}\" mod";
u.Name = "Hello, World!! Software";
u.Publisher = "Greetings";
u.RepairPath = $"\"{Application.ExecutablePath}\" rep"; // 効果無し
u.UninstallPath = $"\"{Application.ExecutablePath}\" uni";
u.Version = new Version(0, 123, 456, 789);
u.Identifier = "Greetings Hello World Software";
u.Save();
Console.ReadKey(true);
}
}
}

後書き

感想・意見・質問・誤字・脱字等はこの記事のコメント欄にお願いします。
最後まで読んでくださってありがとうございました。

コメントを残す

WordPress.com で次のようなサイトをデザイン
始めてみよう