エクスプローラーなどでファイルを右クリックしたときに出てくる「送る」メニュー。
この送るメニューにアプリケーションを登録しておくと、選択したファイルの情報を
アプリケーションに渡して起動できるため、使い方によっては便利な機能。
例えば、logファイルを”メモ帳”に送って起動するといったことができる。
で、この「送る」メニューに登録するためには、特定のフォルダにショートカットをコピーする必要がある。
例えば、Windows8の場合、以下のフォルダにショートカットを置く。
C:\Users\<ユーザー名>\AppData\Roaming\Microsoft\Windows\SendTo
でもこれ、OS毎にパスが異なったりするので、人に説明するのは厄介だったりする。
知っている人なら、何てことない「送る」メニューへの登録でも、初心者にとっては分かりにくいし煩わしい。
なので、これをプログラム側から簡単に登録できないか調べてみた。
いろいろやり方はあると思うけど、4つほどご紹介します。
方法1:インストーラから登録する方法
セットアップする際に、「送る」メニューへ登録させる方法。
これが一番簡単だけどVisual Studioの場合、Professional Editionなどでなければセットアップを作れないし、インストーラ付きアプリは敬遠されがちなので今回は割愛。
方法2:WSHを使用しショートカット作成する方法
Visual Studio からプロジェクト>参照を追加>COM から、「Windows Script Host Object Model」
を追加し、ショートカットを作成する方法。
まず、Visual Studioのソリューションエクスプローラからプロジェクトを選択し「参照の追加」。
参照マネージャダイアログでCOMの中にある「Windows Script Host Object Model」をチェックし追加する。
これでショートカット作成に必要な、IWshRuntimeLibrary.IWshShortcutなどが使用できるようになる。
「送る」フォルダのパス自体は、
System.Environment.GetFolderPath(Environment.SpecialFolder.SendTo)
で取得できるので、あとは、これのショートカットを登録する。
ショートカット作成方法詳細は、こちらが参考になるかも。
http://dobon.net/vb/dotnet/file/createshortcut.html
が、しかし、何故か.NET Framework 4以降を利用するとビルドできなかったため、この方法での実装は止めておくことにした。
方法3:WSHのスクリプトを実行して登録する方法
アプリ(exe)とは関係なく、WSHのスクリプト実行のみで「送る」メニューに登録する方法。
以下の例では、同一フォルダ内の”sendTo.exe”を「送る」メニューに登録(ショートカット作成)します。
- Sample.js
ws = WScript.CreateObject('WScript.Shell'); ln = ws.SpecialFolders('SendTo') + '\\' + 'テスト.lnk'; sc = ws.CreateShortcut(ln); sc.TargetPath = ws.CurrentDirectory + '\\sendTo.exe'; sc.Save();
これはシンプルだけど、exeと、jsファイル2つを配布しなければならない。
ちょっとカッコ悪いし、スクリプトを別に実行してくれとも言いにくいので、この方法はパスすることにした。
方法4:exeだけで実現する方法
方法3を応用した形で、C#のアプリ内でWSHのスクリプトファイルを吐き出し、それを実行するという方法。
実行後は後始末も行う。
サンプルは以下の通り。
ちょっと雑だけど、これなら利用者は簡単に「送る」メニューに登録することができそう。
- Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; // 追加 using System.IO; using System.Reflection; using System.Diagnostics; namespace sendTo { public partial class Form1 : Form { private string aplTitle = null; // アプリ名 private string exeFile = null; // exeファイル名 private string jsFile = null; // スクリプトファイル名 private string lnkFile = null; // リンク名 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // プロジェクト>プロパティ>アセンブリ情報 で指定した「タイトル」を取得 var assembly = Assembly.GetExecutingAssembly(); var attribute = Attribute.GetCustomAttribute( assembly, typeof(AssemblyTitleAttribute) ) as AssemblyTitleAttribute; aplTitle = attribute.Title; this.Text = aplTitle; // 自身のexeファイル名を取得 exeFile = Path.GetFileName(Application.ExecutablePath); // WSHスクリプト名 jsFile = Directory.GetCurrentDirectory() + "\\sendtoAdd.js"; // ショートカットのリンク名 lnkFile = Environment.GetFolderPath(Environment.SpecialFolder.SendTo) + "\\" + aplTitle + ".lnk"; // [送る]フォルダのパスをtextBox1に表示 textBox1.Text = Environment.GetFolderPath(Environment.SpecialFolder.SendTo); textBox1.ReadOnly = true; // ボタンマスク処理 maskButton(); // 起動時にコマンドライン引数指定があればメッセージボックス表示 string[] args = Environment.GetCommandLineArgs(); string msg = null; for (int i = 1; i < args.Length; i++) { msg += args[i] + "\n"; } if (msg != null) { MessageBox.Show( "起動時にコマンドライン引数を受け取りました。\n\n" + msg, aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } } // [登録]ボタン private void button1_Click(object sender, EventArgs e) { // [送る]フォルダにショートカット作成 try { // WSHファイル作成 using (StreamWriter w = new StreamWriter( jsFile, false, System.Text.Encoding.GetEncoding("shift_jis"))) { w.WriteLine("ws = WScript.CreateObject('WScript.Shell');"); w.WriteLine("ln = ws.SpecialFolders('SendTo') + '\\\\' + '" + aplTitle + ".lnk';"); w.WriteLine("sc = ws.CreateShortcut(ln);"); w.WriteLine("sc.TargetPath = ws.CurrentDirectory + '\\\\" + exeFile + "';"); w.WriteLine("sc.Save();"); } // sendtoAdd.jsを実行し[送る]メニューにショートカット作成 if (File.Exists(jsFile)) { Process p = Process.Start(jsFile); p.WaitForExit(10000); // 終了まで待つ(最大10秒) File.Delete(jsFile); } // [送る]フォルダに登録されたか確認 if (File.Exists(lnkFile)) { MessageBox.Show( "[送る]メニューに登録しました。\n\n" + lnkFile, aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show( "[送る]メニューの登録に失敗しました。\n\n" + lnkFile, aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); } } catch (Exception ex) { MessageBox.Show( "[送る]メニューの登録に失敗しました。\n\n" + ex.Message, aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); } maskButton(); } // [解除]ボタン private void button2_Click(object sender, EventArgs e) { // [送る]フォルダに登録済みか確認 if (File.Exists(lnkFile)) { try { File.Delete(lnkFile); MessageBox.Show( "[送る]メニューからショートカットを削除しました。", aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (IOException ex) { MessageBox.Show( "ショートカットの削除に失敗しました。\n\n" + ex.Message, aplTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); } } maskButton(); } // ボタンマスク private void maskButton() { // [送る]フォルダに登録済みか確認 if (File.Exists(lnkFile)) { button1.Enabled = false; button2.Enabled = true; } else { button1.Enabled = true; button2.Enabled = false; } } } }
画面デザイン。
textBox1、button1、button2を用意。
あと、プロジェクト>プロパティ>アセンブリ情報 内の「タイトル」に「送るサンプル」と指定。
実行時画面。
一応、登録済みならボタンをマスク処理とかもしている。
「登録」をクリックすると、[送る]フォルダで示したパス配下に、「送るサンプル」のショートカットを登録する。
あと、「送る」から起動された場合、送られてきた情報をメッセージボックスで表示する。
ちなみに、この方法4を「画像振り分けツール」で採用してたりする。
追記
上記の方法4で完璧。
・・と思い込んでいたら、*.jsファイルの関連付けが異なる環境では以下のようなメッセージが出て実行できない場合があった。
この種類のファイル(.js)を開くには、どのアプリを使いますか?
ファイル拡張子”.js”を持つスクリプトエンジンはありません。
関連付けが出来ていない環境でも動くよう、”cscript”を直接呼び出し実行する。
具体的には、上記ソースの84行目の「Process p = Process.Start(jsFile);」を以下のように書き換えることで解決できた。
//Process p = Process.Start(jsFile); ProcessStartInfo psi = (new ProcessStartInfo()); psi.FileName = "cscript"; psi.Arguments = @"//e:jscript " + jsFile; psi.WindowStyle = ProcessWindowStyle.Hidden; Process p = Process.Start(psi);