LoginSignup
17

More than 5 years have passed since last update.

.NET で Windows エクスプローラのドラッグ&ドロップを拡張

Last updated at Posted at 2016-09-05

はじめに

以前に僕は Delphi で Windows のシェル拡張(Shell Extension)を使っでエクスプローラに機能を追加するアプリを作りました。
簡単エクスプローラ拡張 EzExpEx
これは残念なことに 64 ビット Windows のエクスプローラで動かないんですよね。僕が持っている Delphi では 64 ビット Windows アプリを作れないんです。
これを VB.NET で作り直したいとずっと思っていました。

そのために調べていると次の記事がありました。
.NET Shell Extensions - Shell Drop Handlers - CodeProject

これは C# で書かれています。
このまま使ってもいいのですが、僕は VB が好きなので移植することにしました。

Windows シェル拡張でドロップハンドラ

エクスプローラでドラッグしてドロップしたとき、独自の処理するよう機能を追加します。

プロジェクトを作る

まず、「クラスライブラリ」のプロジェクトを新規作成します。

ここではプロジェクト名を「DragDropExtension」にします。* 元記事と違います。

次に、プロジェクトの「参照」設定に以下のアセンブリを追加します。

  • System.Windows.Forms
  • System.Drawing

IDE が作成したソースファイル「Class1.cs」または「Class1.vb」を「DragDropExtension.cs」または「DragDropExtension.vb」にリネームします。* 好きなファイル名で構いません。

SharpShell ライブラリを使う

「SharpShell」ライブラリを使います。

以下のページで配布されています。
SharpShell - CodePlex

「SharpShel.dll」を使います。これをプロジェクトの「参照」に追加します。

これを手作業してもいいけれど、Nuget を使うのが楽です。

SharpDropHandler から派生する

「DragDropExtension」クラスを「SharpDropHandler」から派生するよう書換します。

DragDropExtension.cs
public class DragDropExtension : SharpDropHandler
{
DragDropExtension.vb
Public Class DragDropExtension
    Inherits DropHandler

IDE が「抽象クラスの実装」を助言してくるので従って以下のメソッドを実装します。

  • DragEnter
  • Drop
DragDropExtension.cs
    protected override void DragEnter(DragEventArgs dragEventArgs)
    {
        // ドラッグしたファイルの拡張子が ".txt" ならコピー可能、そうでなければコピー不可のアイコンにする
        dragEventArgs.Effect =
            DragItems.All(di => string.Compare(Path.GetExtension(di), ".txt", StringComparison.InvariantCultureIgnoreCase) == 0)
            ? DragDropEffects.Copy : DragDropEffects.None;
    }

    protected override void Drop(DragEventArgs dragEventArgs)
    {
        // ドロップしたときの処理
        CountLines();
    }
DragDropExtension.vb
    Protected Overrides Sub DragEnter(dragEventArgs As DragEventArgs)
        'ドラッグしたファイルの拡張子が ".txt" ならコピー可能、そうでなければコピー不可のアイコンにする
        dragEventArgs.Effect = DragItems.All(Function(ByVal di) _
            If(String.Compare(IO.Path.GetExtension(di), ".xml", StringComparison.InvariantCultureIgnoreCase) = 0, _
            DragDropEffects.Link, DragDropEffects.None))
    End Sub

    Protected Overrides Sub Drop(dragEventArgs As DragEventArgs)
        'ドロップしたときの処理
        CountLines()
    End Sub

主な機能は「CountLines」。選択したファイルの名称と行数を表示します。* 元記事と違います。

DragDropExtension.cs
    private void CountLines()
    {
        var builder = new StringBuilder();
        foreach (var path in DragItems)
        {
            builder.AppendLine(string.Format("{0} - {1} 行", IO.Path.GetFileName(path), IO.File.ReadAllLines(path).Length));
        }
        builder.AppendLine(String.Format("To: {0}", SelectedItemPath))
        // メッセージボックスで表示する
        MessageBox.Show(builder.ToString());
    }
DragDropExtension.vb
    Private Sub CountLines()
        Dim builder As New StringBuilder
        For Each path In DragItems
            builder.AppendLine(String.Format("{0} - {1} 行", IO.Path.GetFileName(path), IO.File.ReadAllLines(path).Length))
        Next
        builder.AppendLine(String.Format("To: {0}", SelectedItemPath))
        'メッセージボックスで表示する
        MessageBox.Show(builder.ToString)
    End Sub

SharpDropHandler クラスの DragItems で、エクスプローラで選択したファイルを取得できます。
また、SelectedItemPath で、ドロップ先のファイルまたはフォルダのパスを取得できます。

COM サーバ登録機能を実装する

作成しているクラスライブラリが COM サーバとして登録できるようにします。

まず、アセンブリを COM 参照可能にします。以下の手順で作業します。* 元記事にないようです。

プロジェクトの「プロパティ」を開く。
「アプリケーション」タブを選択。
「アセンブリ情報」を押下。
ダイアログボックスで「アセンブリを COM 参照可能にする」にチェック。

次に、アセンブリに署名します。以下の手順で作業します。

プロジェクトの「プロパティ」を開く。
「署名」タブを選択。
「アセンブリに署名する」をチェック。
「厳密な名前のキーファイルを選択」で「新規作成」を選択。
ダイアログボックスで「キーファイル名」に任意のファイル名を指定。
「キーファイルをパスワードで保護する」は必須ではない。

次に、「ComVisible」属性を設定します。

DrragDropExtension.cs
[ComVisible(true)]
public class DragDropExtension : SharpDropHandler
{
DragDropExtension.vb
<ComVisible(True)>
Public Class DragDropExtension
    Inherits SharpDropHandler

最後に、「COMServerAssociation」属性を設定します。SharpShell クラスで提供される属性です。どのファイルタイプと紐付するかを指定します。
ここでは拡張子が「.txt」のファイルと紐付するようにします。拡張子が「.txt」のファイルにドロップしたとき機能が実行されます。

DragDropExtension.cs
[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, ".txt")]
public class DragDropExtension : SharpDropHandler
{
DragDropExtension.vb
<ComVisible(True)>
<COMServerAssociation(AssociationType.ClassOfExtension, ".txt")>
Public Class DragDropExtension
    Inherits SharpDropHandler

COMServerAssociation の詳細は以下のページを参照。
SharpShell - Documentation

ビルドする

ビルドするとアセンブリファイルが作成されます。これを COM サーバとして Windows に登録します。

COM サーバとして登録する

C# または VB.NET で作成したアセンブリファイルを COM サーバとして登録するには、.NET Framework に同梱されている「regasm」ツールを使います。

regasm DragDropExtension.dll /codebase

ただしこれは、.NET Framework がインストールされた時点でパスが通っていないので、使いづらいですね。
そこで、SharpShell ライブラリの作者が配布している「srm」ツールを使います。

SharpShell - Download

srm install DragDropExtension.dll -codebase

おわりに

以下の記事も書いています。

.NET で Windows エクスプローラのコンテキストメニューを拡張 - Qiita

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17