#title(.NETプログラミング研究 第41号)

#navi(.NET プログラミング研究)

#contents

*.NETプログラミング研究 第41号 [#zaaeee85]

**.NET Tips [#q861c369]

***OS起動時にプログラムを自動的に実行する / OS起動時に一回だけプログラムを自動的に実行する [#hee9dbb3]

#column(注意){{
この記事の最新版は「[[OS起動時にプログラムを自動的に実行する>http://dobon.net/vb/dotnet/system/osstartuprun.html]]」で公開しています。
}}

これは、.NETの知識というより、Windowsに関する知識ということになるでしょう。

OS起動時に指定したプログラムを自動的に実行されるようにするには、Windowsのプログラム内スタートアップフォルダにショートカットを作成するか、レジストリのRunキーに登録するというのが一般的な方法です。.NETではシュートカットの作成が簡単でないため、ここではレジストリのRunキーに書き込む方法を紹介します。

OS起動時に起動させるプログラムが登録されているキーには、次の4つがあります。(正確には、これらのキーに登録されたプログラムは新規ユーザーがログオンする時に実行されます。また、これ以外のキーもあります。詳しくは、下に紹介するマイクロソフトサポート技術情報をご覧ください。)

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

これらのキーの内、HKEY_LOCAL_MACHINEとHKEY_CURRENT_USERの違いは、マシン毎の設定か、ユーザー毎の設定かであり、RunキーとRunOnceキーの違いは、登録されているプログラムを新規ユーザーがログオンするたびに実行するか、始めの一回のみ実行するかです。

よって通常はRunキーを使用し、RunOnceキーは現在使用中で削除できないファイルを次回起動時に削除するなどの目的で使用します。

なお、Runキーについて詳しくは、以下のマイクロソフトサポート技術情報をご覧ください。

-[[マイクロソフト サポート技術情報 - 314866 | Windows XP レジストリの Run キーの定義>http://support.microsoft.com/default.aspx?kbid=314866]]
-[[マイクロソフト サポート技術情報 - 137367  | レジストリの RunOnce キーの定義>http://support.microsoft.com/default.aspx?kbid=137367]]
-[[マイクロソフト サポート技術情報 - 179365 | [INFO] Run、RunOnce、RunServices、RunServicesOnce レジストリ キーと [スタートアップ] フォルダの関係>http://support.microsoft.com/default.aspx?kbid=179365]]
-[[マイクロソフト サポート技術情報 - 232487 | RunOnceEx レジストリ キーについて>http://support.microsoft.com/default.aspx?kbid=232487]]

以下に、HKEY_CURRENT_USERのRunキーにアプリケーションの実行ファイルのパスを登録し、OS起動時に実行されるようにするためのコードを紹介します。Microsoft.Vsa.dllを参照に加える必要があります。

#code(vbnet){{
''' <summary>
''' CurrentUserのRunにアプリケーションの実行ファイルパスを登録する
''' </summary>
Public Shared Sub SetCurrentVersionRun()
    'Runキーを開く
    Dim regkey As Microsoft.Win32.RegistryKey = _
        Microsoft.Win32.Registry.CurrentUser.OpenSubKey( _
        "Software\Microsoft\Windows\CurrentVersion\Run", True)
    '値の名前に製品名、値のデータに実行ファイルのパスを指定し、書き込む
    regkey.SetValue( _
        Application.ProductName, Application.ExecutablePath)
    '閉じる
    regkey.Close()
End Sub
}}

#code(csharp){{
/// <summary>
/// CurrentUserのRunにアプリケーションの実行ファイルパスを登録する
/// </summary>
public static void SetCurrentVersionRun()
{
    //Runキーを開く
    Microsoft.Win32.RegistryKey regkey =
        Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
        @"Software\Microsoft\Windows\CurrentVersion\Run", true);
    //値の名前に製品名、値のデータに実行ファイルのパスを指定し、書き込む
    regkey.SetValue(Application.ProductName, Application.ExecutablePath);
    //閉じる
    regkey.Close();
}
}}

***プログラムをファイルの拡張子に関連付ける [#n02666fa]

#column(注意){{
この記事の最新版は「[[プログラムをファイルの拡張子に関連付ける>http://dobon.net/vb/dotnet/system/associatedapp.html]]」で公開しています。
}}

これもWindowsのレジストリの知識です。

拡張子に関する情報は、レジストリのHKEY_CLASSES_ROOTキー以下に登録されています。例えば、".000"という拡張子のファイルに"myapp.exe %1"というコマンドラインを"open"というアクションで関連付けるには、

HKEY_CLASSES_ROOT\.000\shell\open\command

というキーに、名前がなく、データが"myapp.exe %1"の値を作成するだけです。

これが最も簡単な方法ですが、実際にこのように関連付けを行っているアプリケーションは稀です。一般的なやり方としては、まず

HKEY_CLASSES_ROOT\.000

というキーを作成し、ここに名前がなく、データに適当な文字列(ここでは、"MyApplication"とする)を指定した値を作成し、さらに、

HKEY_CLASSES_ROOT\MyApplication\shell\open\command

というキーに、名前がなく、データがコマンドラインとなる値を作成します。

以上は最低限の設定で、さらにアイコンの設定等も必要により行う必要があります。関連付けに関する詳しい話は、次のサイトが参考になります。

-[[Jet Page - Windows レジストリ 解剖記>http://homepage2.nifty.com/kuri-page/program/winreg.htm]]

なお関連付けによりプログラムが実行された時、プログラムでファイルのパスを取得するには、コマンドライン引数を調べます。コマンドライン引数を取得する方法は、次のページをご覧ください。

-[[DOBON.NET .NET Tips - 起動時のコマンドライン引数を取得する>http://dobon.net/vb/dotnet/programing/commandline.html]]

以下に拡張子への関連付けを行うサンプルを示します。ここではアイコンの設定等も行っています。

#code(vbnet){{
'関連付ける拡張子
Dim extension As String = ".000"
'実行するコマンドライン
Dim commandline As String = """" + Application.ExecutablePath _
    + """ %1"
'ファイルタイプ名
Dim fileType As String = Application.ProductName
'説明(必要なし)
Dim description As String = "MyApplication File"
'動詞
Dim verb As String = "open"
'動詞の説明(エクスプローラのコンテキストメニューに表示される)
'(必要なし)
Dim verb_description As String = "MyApplicationで開く(&O)"
'アイコンのパスとインデックス
Dim iconPath As String = Application.ExecutablePath
Dim iconIndex As Integer = 0

'ファイルタイプを登録
Dim regkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(extension)
regkey.SetValue("", fileType)
regkey.Close()

'ファイルタイプとその説明を登録
Dim shellkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(fileType)
shellkey.SetValue("", description)

'動詞とその説明を登録
shellkey = shellkey.CreateSubKey("shell\" + verb)
shellkey.SetValue("", verb_description)

'コマンドラインを登録
shellkey = shellkey.CreateSubKey("command")
shellkey.SetValue("", commandline)
shellkey.Close()

'アイコンの登録
Dim iconkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey( _
        fileType + "\DefaultIcon")
iconkey.SetValue("", iconPath + "," + iconIndex.ToString())
iconkey.Close()
}}

#code(csharp){{
//関連付ける拡張子
string extension = ".000";
//実行するコマンドライン
string commandline = "\"" + Application.ExecutablePath + "\" %1";
//ファイルタイプ名
string fileType = Application.ProductName;
//説明(必要なし)
string description = "MyApplication File";
//動詞
string verb = "open";
//動詞の説明(エクスプローラのコンテキストメニューに表示される)
//(必要なし)
string verb_description = "MyApplicationで開く(&O)";
//アイコンのパスとインデックス
string iconPath =Application.ExecutablePath;
int iconIndex = 0;

//ファイルタイプを登録
Microsoft.Win32.RegistryKey regkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    extension);
regkey.SetValue("", fileType);
regkey.Close();

//ファイルタイプとその説明を登録
Microsoft.Win32.RegistryKey shellkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    fileType);
shellkey.SetValue("", description);

//動詞とその説明を登録
shellkey = shellkey.CreateSubKey("shell\\" + verb);
shellkey.SetValue("", verb_description);

//コマンドラインを登録
shellkey = shellkey.CreateSubKey("command");
shellkey.SetValue("", commandline);
shellkey.Close();

//アイコンの登録
Microsoft.Win32.RegistryKey iconkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    fileType + "\\DefaultIcon");
iconkey.SetValue("", iconPath + "," + iconIndex.ToString());
iconkey.Close();
}}

また、関連付けを削除するには、次のように対象となるすべてのキーを削除します。

#code(vbnet){{
'拡張子
Dim extension As String = ".000"
'ファイルタイプ名
Dim fileType As String = Application.ProductName

'レジストリキーを削除
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree(extension)
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree(fileType)
}}

#code(csharp){{
//拡張子
string extension = ".000";
//ファイルタイプ名
string fileType = Application.ProductName;

//レジストリキーを削除
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree(extension);
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree(fileType);
}}

***エクスプローラでフォルダやドライブを右クリックしたときに表示されるコンテキストメニューに項目を追加する [#m5b9e127]

#column(注意){{
この記事の最新版は「[[エクスプローラでフォルダやドライブを右クリックしたときに表示されるコンテキストメニューに項目を追加する>http://dobon.net/vb/dotnet/system/explorecontextmenu.html]]」で公開しています。
}}

エクスプローラでフォルダやドライブを右クリックしたときに表示されるコンテキストメニューには、「検索」などの項目が表示されると思いますが、ここに新たな項目を追加し、指定したプログラムを起動させる方法を紹介します。

実はこれを行うには、フォルダやドライブに関連付けを行えばよく、先に紹介した「プログラムをファイルの拡張子に関連付ける」とほとんど同じ方法で実現できます。

「プログラムをファイルの拡張子に関連付ける」では、拡張子と同じ名前のキーに情報を登録しましたが、フォルダやドライブへの関連付けでは特別な名前を使用し、フォルダの場合は"Folder"、ドライブの場合は"Drive"、ファイルフォルダの場合は"Directory"という名前のキーとなります。(「ファイルフォルダ」というのが何なのかはっきり分かりませんが、多分、一般的なローカルなフォルダ(ドライブは含まない)というような意味ではないでしょうか。また、Folderへの登録では、フォルダとドライブ、さらに、ゴミ箱、マイネットワークでも表示されるようです。)

この3つ以外にも特別な意味を持つキーがいくつかあります。例えば、"*"はすべてのファイルを意味し、"AllFileSystemObjects"はすべてのファイルとフォルダを意味します。詳しくは先に紹介した「Jet Page - Windows レジストリ 解剖記」や、次のページ等をご覧ください。

-[[MSDN - Creating Shell Extension Handlers>http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_extending/extensionhandlers/shell_ext.asp]]

フォルダへの関連付けにより、エクスプローラでフォルダを右クリックしたときに"MyApplicationで開く"を表示させるサンプルを以下に示します。

#code(vbnet){{
'実行するコマンドライン
Dim commandline As String = _
    """" + Application.ExecutablePath + """ %1"
'説明(エクスプローラのコンテキストメニューに表示される)
Dim description As String = "MyApplicationで開く"

'フォルダへの関連付けを行う
Dim regkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey( _
    "Folder\shell\" + description + "\command")
regkey.SetValue("", commandline)
regkey.Close()
}}

#code(csharp){{
//実行するコマンドライン
string commandline = "\"" + Application.ExecutablePath + "\" %1";
//説明(エクスプローラのコンテキストメニューに表示される)
string description = "MyApplicationで開く";

//フォルダへの関連付けを行う
Microsoft.Win32.RegistryKey regkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    "Folder\\shell\\" + description + "\\command");
regkey.SetValue("", commandline);
regkey.Close();
}}

***エクスプローラの新規作成メニューに項目を追加する [#p3351e44]

#column(注意){{
この記事の最新版は「[[エクスプローラの新規作成メニューに項目を追加する>http://dobon.net/vb/dotnet/system/explorenewfile.html]]」で公開しています。
}}

エクスプローラでフォルダを選び、メニューの「ファイル - 新規作成」(あるいは、右クリックによるコンテキストメニューの「新規作成」)を選択すると、指定されたタイプのファイルを新しく作成することができます。ここではこの「新規作成」メニューに独自の項目を追加する方法を紹介します。

しつこいようですが、これまた、Windowsとレジストリの知識で、その方法は次のページで詳しく紹介されています。

-[[@IT:Windows TIPS -- Tips:エクスプローラの[新規作成]メニューをカスタマイズする>http://www.atmarkit.co.jp/fwin2k/win2ktips/282filenew/filenew.html]]

まずは拡張子への関連付けが必要ですので、「プログラムをファイルの拡張子に関連付ける」により、新規作成に追加したい拡張子を登録します。

「新規作成」メニューにより作成されるファイルには2種類(注1)あり、サイズ0(空)のファイルか、テンプレートファイルを基にしたファイルになります。

サイズ0のファイルを作成する場合は簡単で、レジストリの

HKEY_CLASSES_ROOT\(拡張子)\ShellNew

というキーに名前が"NullFile"でデータが""の値を作成するだけです。

テンプレートファイルを使用する場合は、新規作成により作成されるファイルをWindowsのテンプレートフォルダ("System.Environment.GetFolderPath(Environment.SpecialFolder.Templates)"によりパスが取得できます)に置いておき、先と同じShellNewキーに名前が"FileName"でデータがテンプレートのファイル名の値を登録します。

"NullFile"と"FileName"の両方を指定することはできませんが、両方が存在する場合は、"NullFile"が優先されるようです。

以下にサンプルを示します。まずは、「新規作成」メニューによりサイズ0のファイルが作成される例です。

#code(vbnet){{
'拡張子
Dim extension As String = ".000"

'「新規作成」により、空のファイルを作成
Dim regkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey( _
    extension + "\ShellNew")
regkey.SetValue("NullFile", "")
regkey.Close()
}}

#code(csharp){{
//拡張子
string extension = ".000";

//「新規作成」により、空のファイルを作成
Microsoft.Win32.RegistryKey regkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    extension + "\\ShellNew");
regkey.SetValue("NullFile", "");
regkey.Close();
}}

次にテンプレートファイルを使用した例を示します。

#code(vbnet){{
'拡張子
Dim extension As String = ".000"
'テンプレートファイル名
Dim templateName As String = "myapp.000"
'テンプレートファイルのパス
Dim templatePath As String = _
    System.Environment.GetFolderPath( _
    Environment.SpecialFolder.Templates) + "\" + templateName
'テンプレートの中身
Dim templateText As String = "DOBON.NET"

'テンプレートファイルを作成する
Dim sw = New StreamWriter(templatePath)
sw.Write(templateText)
sw.Close()

'「新規作成」により、テンプレートファイルを作成
Dim regkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey( _
    extension + "\ShellNew")
regkey.SetValue("FileName", templateName)
regkey.Close()
}}

#code(csharp){{
//拡張子
string extension = ".000";
//テンプレートファイル名
string templateName = "myapp.000";
//テンプレートファイルのパス
string templatePath =
    System.Environment.GetFolderPath(
        Environment.SpecialFolder.Templates) +
    "\\" + templateName;
//テンプレートの中身
string templateText = "DOBON.NET";

//テンプレートファイルを作成する
System.IO.StreamWriter sw = new StreamWriter(templatePath);
sw.Write(templateText);
sw.Close();

//「新規作成」により、テンプレートファイルを作成
Microsoft.Win32.RegistryKey regkey =
    Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
    extension + "\\ShellNew");
regkey.SetValue("FileName", templateName);
regkey.Close();
}}

(注1)@IT:Windows TIPSでは2種類しか紹介されていませんが、実際にはこれ以外に"Command"と"Data"いうのもあります。

名前が"Command"でデータがコマンドラインの値を作成すると、新規作成の際、指定したコマンドラインが実行されます。これは、シュートカットを新規作成するときのように、ウィザードによりファイルを作成するときに使用します。

また、"Data"を名前とする値の場合、データにバイナリ値を指定します。

**コメント [#w8c7eb37]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2004-09-14 (火) 06:00:00,DOBON!,2010-03-21 (日) 19:32:27,DOBON!)
[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]