Windows Explorerシェルで複数のファイルをプログラムに渡したい

ファイルの差分表示に WinMerge (日本語版) を使っていました。TortoiseSVNにも自動で設定してくれるし、重宝してました。

一方、ubuntuとかCentOSのbashシェル内で作業しているときは、vim のdiffモードを使うことも増えてきまして、どうせならWindowsのデスクトップで作業しているときも gVim でやろうかな、と思い立ち、Windowsのレジストリをいじって関連付けしようとしました。

具体的には↓のように・・・

まぁ、でもこれは失敗します。この方法で2つファイルを選択した状態で、右クリックして opendiff をクリックするとgvimが二つ起動してそれぞれ別のgvimで開いてしまいます。失敗。
※追記 2021年6月24日 official buildのvimだと GvimExt32/GvimExt64 というシェルエクステンションが既にバンドルされてるみたいすね・・・。僕は kaoriya vim しか使ってなかったので気づかなかった💦

で、じゃぁ、%2とか%* ってのをつけ足せばいいんじゃない? って思うのですが、やってみれば分かりますが、失敗します。上記と同じように複数のgVimウィンドウが開きます。
どうやら標準で複数選択したファイルを同一のプログラムのインスタンスに渡すことはできないようです。

じゃあ、どうすればいいのか?というと、Explorerのシェルエクステンション(インプロセス COMサーバー)を書いてレジストリに登録する必要があります。(グーグル調べ)

ってことで、現実的に C++ で実装するのはヒジョーにメンドクサイ。探せばシェルエクステンション用のフレームワークみたいなものがあるとは思うのですが、今はC#をメインに使っているので、できるなら C# でできないか、調べたところ(グーグルで)、SharpShell という、C#のシェルエクステンション用のフレームワークがあるようです。

SharpShell
SharpShell makes it easy to create Windows Shell Extensions using the .NET Framework.

ショートカットメニュー用のシェルエクステンション作成とインストールはチュートリアルがあるので、この通りに進めていけば苦も無く作成できると思います。

チュートリアル(英語)

ただ、このチュートリアルはかなり古く2014年の時のものですが、基本的にはあまり変わっていません。
注意点は、SharpShellを nugetで入れる場合は、2021年2月現在最新のもの(2.7.2)を入れる場合、Server Manager などのツールも最新のものを使う必要があります。nugetで SharpShell Tools を入れると なぜか 2.2.0のものがインストールされてしまうので上記 githubサイトで配布されている 2.7.2 のものを使う方がいいと思います。

基本的には・・・Visual Studio 2019 Community を使用します。

  1. プロジェクトを .NET Framework のライブラリ(DLL)として作成。
  2. 「プロジェクト ⇒ nugetのパッケージ管理」で SharpShell をインストール
  3. チュートリアルで説明されているように、SharpContextMenu を継承したクラスを作成
  4. ショートカットメニューに必要な抽象メソッドを実装する(Visual Studio 2019のコード補完で自動的にスケルトンが出ると思います)
  5. プロジェクト・プロパティ⇒アプリケーション⇒アセンブリ情報 で「アセンブリをCOM参照可能にする」にチェック
  6. プロジェクト・プロパティ⇒署名⇒アセンブリに署名する(チェック)⇒新規作成 適当な名前をつける
  7. ビルド
  8. ServerManagerでビルドしたDLLファイルを読み込んで、Server⇒Install Server(x64) Register Server(x64) を順番に実行
  9. インストール&登録する前にテストしたければ、Test Server In Test Shell をクリックするとテスト用のエクスプローラもどきが出てくるのでそこでテストできるようです。

まぁ、そんなこんなで、やりたいことはできました(^▽^)/

※ただ一点注意しないといけないのは、.NET Frameworkのようなマネージコードをインプロセスサーバーとしてエクスプローラのプロセス内で動作させるのは未だにいいのかどうか分からないって点です。マイクロソフトの中の人も良いと言ってる人もいれば、やらない方がいいっていう人もいるようです。 この辺りは SharpShell のドキュメントでも書かれています。2021年現在、実際のところどうなんなんでしょうかね・・・・?

ただ、ショートカットメニューをクリックしてプロセスをキックするだけならあまり問題ないのかな~と思ってます。

ずっと前にC++で書いたシェルエクステンションのソースコードが残っているのでC++で書こうと思えば書けるんですが・・・やっぱりオッサンはもう頭が硬くなってるので時間がかかるんですよねぇ。

書いたコードはこんだけ。便利なライブラリに多謝・多謝。