はじめに
以前に Delphi で Windows コントロールパネルのアプレットを作成しました。
これを VB.NET で作り直せないかと思っていました。でもちゃんと作るのは面倒そうなんですね。
そんなとき次の記事を見つけました。
How to Register Executable Control Panel Items (Windows)
通常の実行ファイルをコントロールパネルに登録できるんですね。
アプレットでなくてこれでいいんじゃないかな。
これを参考にしてプログラムを書いてみました。
コントロールパネルのアイテムに登録できる実行ファイルを作成
通常のアプリケーションプログラムを作成します。
その実行ファイルがコントロールパネルのアイテムとして登録できるようにします。
プロジェクトを作る
まず、「Windows フォーム アプリケーション」のプロジェクトを作成します。
プロジェクトにクラスを追加する
プロジェクトに「クラス」を新規追加します。ここではクラス名を「Register」にします。
以下の属性を指定しておきます。
public class Register
{
private const string ApplicationName = "SampleApp.CplSample";
private const string DisplayName = "CPL Sample";
private const string Description = "ControlPanel Item Sample";
private const string Category = "0";
Public Class Register
Private Const ApplicationName = "SampleApp.CplSample"
Private Const DisplayName = "CPL Sample"
Private Const Description = "ControlPanel Item Sample"
Private Const Category = "0"
- ApplicationName アイテムの名称。「control.exe /name ●●●●」のように実行するときに使用できる。
- DisplayName アイテムのアイコンに表示される名称
- Description アイテムのアイコンにマウスポインタを置いたときに表示される説明
- Category アイテムが表示されるコントロールパネルのカテゴリ。以下のページを参照。 Assigning Control Panel Categories (Windows)
COM サーバ登録機能を実装する
作成しているアプリケーションプログラムが COM サーバとして登録できるようにします。
まず、アセンブリを COM 参照可能にします。以下の手順で作業します。
プロジェクトの「プロパティ」を開く。
「アプリケーション」タブを選択。
「アセンブリ情報」を押下。
ダイアログボックスで「アセンブリを COM 参照可能にする」にチェック。
次に、アセンブリに署名します。以下の手順で作業します。
プロジェクトの「プロパティ」を開く。
「署名」タブを選択。
「アセンブリに署名する」をチェック。
「厳密な名前のキーファイルを選択」で「新規作成」を選択。
ダイアログボックスで「キーファイル名」に任意のファイル名を指定。
「キーファイルをパスワードで保護する」は必須ではない。
クラスに GUID を設定します。
GUID はクラスごとに新規作成して下さい。
[Guid("99999999-9999-9999-9999-9999999999")]
public class Register
<Guid("99999999-9999-9999-9999-9999999999")>
Public Class Register
GUID を作成するのはこちら
Create GUID Tool in Visual Studio - TechNet Articles - United States (English) - TechNet Wiki
登録および解除のためのメソッドを実装する
登録および解除のためのメソッドを実装します。
using Microsoft.Win32;
using System.Reflection;
using System.Runtime.InteropServices;
public class Register
{
[ComRegisterFunction]
public static void Regist(Type t)
{
try
{
if (t.GUID == Guid.Empty)
{
throw new ArgumentException("clsid must not be empty");
}
string clsid = t.GUID.ToString("B");
string path = Assembly.GetExecutingAssembly().Location;
using (RegistryKey key = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\" + clsid))
{
if (key != null)
{
key.SetValue(null, DisplayName);
}
}
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("CLSID\\" + clsid))
{
if (key != null)
{
key.SetValue(null, DisplayName);
key.SetValue("InfoTip", Description);
key.SetValue("System.ApplicationName", ApplicationName);
key.SetValue("System.ControlPanel.Category", Category);
}
}
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("CLSID\\" + clsid + "\\DefaultIcon"))
{
if (key != null)
{
key.SetValue(null, path);
}
}
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("CLSID\\" + clsid + "\\Shell\\Open\\Command"))
{
if (key != null)
{
key.SetValue(null, path, RegistryValueKind.ExpandString);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
}
[ComUnregisterFunction]
public static void Unregist(Type t)
{
try
{
if (t.GUID == Guid.Empty)
{
throw new ArgumentException("clsid must not be empty");
}
string clsid = t.GUID.ToString("B");
string path = Assembly.GetExecutingAssembly().Location;
Registry.LocalMachine.DeleteSubKeyTree("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\" + clsid, false);
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + clsid, false);
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + clsid + "\\DefaultIcon", false);
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + clsid + "\\Shell\\Open\\Command", false);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
}
Imports Microsoft.Win32
Imports System.Reflection
Imports System.Runtime.InteropServices
Public Class Register
<ComRegisterFunction()>
Public Shared Sub Regist(ByVal t As Type)
Try
If t.GUID = Guid.Empty Then
Throw New ArgumentException("clsid must not be empty")
End If
Dim clsid As String = t.GUID.ToString("B")
Dim path As String = Assembly.GetExecutingAssembly.Location
Using key As RegistryKey = Registry.LocalMachine.CreateSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel\NameSpace\" & clsid)
If key IsNot Nothing Then
key.SetValue(Nothing, DisplayName)
End If
End Using
Using key As RegistryKey = Registry.ClassesRoot.CreateSubKey("CLSID\" & clsid)
If key IsNot Nothing Then
key.SetValue(Nothing, DisplayName)
key.SetValue("InfoTip", Description)
key.SetValue("System.ApplicationName", ApplicationName)
key.SetValue("System.ControlPanel.Category", Category)
End If
End Using
Using key As RegistryKey = Registry.ClassesRoot.CreateSubKey("CLSID\" & clsid & "\DefaultIcon")
If key IsNot Nothing Then
key.SetValue(Nothing, path)
End If
End Using
Using key As RegistryKey = Registry.ClassesRoot.CreateSubKey("CLSID\" & clsid & "\Shell\Open\Command")
If key IsNot Nothing Then
key.SetValue(Nothing, path, RegistryValueKind.ExpandString)
End If
End Using
Catch ex As Exception
Console.WriteLine(ex.Message)
Throw ex
End Try
End Sub
<ComUnregisterFunction()>
Public Shared Sub Unregist(ByVal t As Type)
Try
If t.GUID = Guid.Empty Then
Throw New ArgumentException("clsid must not be empty")
End If
Dim clsid As String = t.GUID.ToString("B")
Registry.LocalMachine.DeleteSubKeyTree("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel\NameSpace\" & clsid, False)
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\" & clsid, False)
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\" & clsid & "\DefaultIcon", False)
Registry.ClassesRoot.DeleteSubKeyTree("CLSID\" & clsid & "\Shell\Open\Command", False)
Catch ex As Exception
Console.WriteLine(ex.Message)
Throw ex
End Try
End Sub
ビルドする
ビルドするとアセンブリファイルが作成されます。これを COM サーバとして Windows に登録します。
COM サーバとして登録する
C# または VB.NET で作成したアセンブリファイルを COM サーバとして登録するには、.NET Framework に同梱されている「regasm」ツールを使います。
regasm ContextMenuExtension.dll /codebase
おわりに
こんな記事を見かけました。
ついに!Windows 10から「コントロールパネル」が消える | ギズモード・ジャパン
これが本当になると、この記事も意味なくなってしまいますね。