65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Shell Extensions - Shell Context Menus (右键菜单扩展)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (127投票s)

2013年1月5日

CPOL

9分钟阅读

viewsIcon

975970

downloadIcon

22689

使用 .NET 快速创建 Shell Context Menu 扩展

引言

直到 .NET 4.0,才有可能使用 .NET 代码可靠地创建 Windows Shell Extensions。随着框架的改进,现在可以使用 .NET 来创建这些扩展。在本文中,我将向您展示如何快速创建 Shell Context Menus,作为 C# 类库。

上图:示例 Shell Context Menu Extension 的截图 - “Count Lines...” 项目是本文演示如何创建的自定义 shell 扩展。

系列文章

本文是 '.NET Shell Extensions' 系列的一部分,该系列包括

  1. .NET Shell Extensions - Shell Context Menus (右键菜单扩展)
  2. .NET Shell Extensions - Shell Icon Handlers (图标处理程序)
  3. .NET Shell Extensions - Shell Info Tip Handlers (信息提示处理程序)
  4. .NET Shell Extensions - Shell Drop Handlers (拖放处理程序)
  5. .NET Shell Extensions - Shell Preview Handlers (预览处理程序)
  6. .NET Shell Extensions - Shell Icon Overlay Handlers (图标叠加处理程序)
  7. .NET Shell Extensions - Shell Thumbnail Handlers (缩略图处理程序)
  8. .NET Shell Extensions - Shell Property Sheets (属性表处理程序)
  9. .NET Shell Extensions - Deploying SharpShell Servers (部署 SharpShell 服务器)

什么是 Shell Context Menus?

Shell Context Menus 是注册在系统中的 COM 服务器,允许扩展 Shell 对象的上下文菜单。这可以是特定文件类型的上下文菜单,例如 * .txt 文件,文件类,如“文本文件”,驱动器,文件夹等。上下文菜单可用于提供可通过 Windows Explorer 快速访问的高级功能。

入门

设置 Shell Extensions 需要大量工作。必须实现特定的 COM 接口,必须构建服务器,必须以各种方式更新注册表。我们将使用我开发的一个名为“SharpShell”的库来完成所有繁重的工作 - 让我们专注于创建包含我们的扩展类的轻量级类库。

我们的目标

下面的代码创建了一个 Shell Extension,它允许您通过右键单击任何文本文件并选择“Count Lines”来计算其中的行数。在文章的其余部分,我将向您展示如何创建这样的库。代码首先显示,因为我想强调使用 SharpShell 编写这些库是多么直接。

/// <summary>
/// The CountLinesExtensions is an example shell context menu extension,
/// implemented with SharpShell. It adds the command 'Count Lines' to text
/// files.
/// </summary>
[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, ".txt")]
public class CountLinesExtension : SharpContextMenu
{
    /// <summary>
    /// Determines whether this instance can a shell
    /// context show menu, given the specified selected file list
    /// </summary>
    /// <returns>
    /// <c>true</c> if this instance should show a shell context
    /// menu for the specified file list; otherwise, <c>false</c>
    /// </returns>
    protected override bool CanShowMenu()
    {
        //  We always show the menu
        return true;
    }
 
    /// <summary>
    /// Creates the context menu. This can be a single menu item or a tree of them.
    /// </summary>
    /// <returns>
    /// The context menu for the shell context menu.
    /// </returns>
    protected override ContextMenuStrip CreateMenu()
    {
        //  Create the menu strip
        var menu = new ContextMenuStrip();
 
        //  Create a 'count lines' item
        var itemCountLines = new ToolStripMenuItem
        {
            Text = "Count Lines...",
            Image = Properties.Resources.CountLines
        };
 
        //  When we click, we'll count the lines
        itemCountLines.Click += (sender, args) => CountLines();
 
        //  Add the item to the context menu.
        menu.Items.Add(itemCountLines);
 
        //  Return the menu
        return menu;
    }
 
    /// <summary>
    /// Counts the lines in the selected files
    /// </summary>
    private void CountLines()
    {
        //  Builder for the output
        var builder = new StringBuilder();
 
        //  Go through each file.
        foreach (var filePath in SelectedItemPaths)
        {
            //  Count the lines
            builder.AppendLine(string.Format("{0} - {1} Lines", 
              Path.GetFileName(filePath), File.ReadAllLines(filePath).Length));
        }
 
        //  Show the output
        MessageBox.Show(builder.ToString());
    }
} 

这相当简洁明了 - 现在让我们详细了解如何使用 SharpShell 创建这个 Shell Context Menu。

步骤 1:创建项目

首先,创建一个新的 C# 类库项目。

提示:您可以使用 Visual Basic 而不是 C# - 在本文中,源代码是 C#,但创建 Visual Basic Shell Extension 的方法是一样的。

在此示例中,我们将项目命名为 'CountLinesExtension'。

现在添加以下引用

  1. System.Windows.Forms
  2. System.Drawing

System.Windows.Forms 是必需的,因为我们将使用 WinForms ContextMenuStrip 来定义上下文菜单。 System.Drawing 是必需的,因为我们要使用图标。

将“Class1.cs”文件重命名为“CountLinesExtension.cs”。我们现在应该有一个看起来像这样的项目结构

步骤 2:引用 SharpShell

现在我们需要添加对核心 SharpShell 库的引用。您可以通过几种不同的方式执行此操作。

添加引用

下载文章顶部的“SharpShell Library” zip 文件,并添加对下载的 SharpShell.dll 文件的引用。

提示:本文的下载在撰写本文时是正确的 - 如果您需要最新版本,请使用 Nuget(如下所述)或从 sharpshell.codeplex.com 获取该库。

使用 Nuget

如果您安装了 Nuget,只需快速搜索 SharpShell 并直接安装它 - 或在 https://nuget.net.cn/packages/SharpShell 获取包详细信息。

使用 CodePlex

而不是从本页获取库(它可能不是最新版本),您始终可以从 CodePlex 获取最新版本的库 - 在 SharpShell 主页上,即 https://sharpshell.codeplex.com。Nuget 将始终拥有最新的稳定版本 - CodePlex 可能提供测试版,而 CodeProject 文章将拥有撰写时可用的版本。

步骤 3:从 SharpContextMenu 派生

现在事情变得有趣了。从 SharpContextMenu 派生您的 CountLinesExtension

/// <summary>
/// The Count Lines Context Menu Extension
/// </summary>
public class CountLinesExtension : SharpContextMenu
{
}

现在我们必须实现类的抽象成员。右键单击行上的 SharpContextMenu 部分,然后选择“Implement Abstract Class”(实现抽象类)

这将创建两个必需函数的实现 - CanShowMenuCreateMenu

/// <summary>
/// The Count Lines Context Menu Extension
/// </summary>
public class CountLinesExtension : SharpContextMenu
{
    protected override bool CanShowMenu()
    {
        throw new NotImplementedException();
    }
 
    protected override ContextMenuStrip CreateMenu()
    {
        throw new NotImplementedException();
    }
}

通过实现这两个函数,我们可以提供所有必需的功能。它们的作用如下

CanShowMenu

调用此函数以确定是否应为给定的文件集显示上下文菜单扩展。用户选择的文件位于 SelectedItemPaths 属性中。我们可以检查这些文件路径以查看我们是否真的想显示菜单。如果应显示菜单,则返回 true。否则,返回 false

CreateMenu

调用此函数以实际创建上下文菜单。我们只需要返回一个标准的 WinForms ContextMenuStrip

以下是我们如何实现这两个函数

protected override bool CanShowMenu()
{
    //  We will always show the menu
    return true;
}
 
protected override ContextMenuStrip CreateMenu()
{
    //  Create the menu strip
    var menu = new ContextMenuStrip();
 
    //  Create a 'count lines' item
    var itemCountLines = new ToolStripMenuItem
    {
        Text = "Count Lines"
    };
 
    //  When we click, we'll call the 'CountLines' function
    itemCountLines.Click += (sender, args) => CountLines();
 
    //  Add the item to the context menu
    menu.Items.Add(itemCountLines);
 
    //  Return the menu
    return menu;
}
 
private void CountLines()
{
    //  Builder for the output
    var builder = new StringBuilder();
 
    //  Go through each file
    foreach (var filePath in SelectedItemPaths)
    {
        //  Count the lines
        builder.AppendLine(string.Format("{0} - {1} Lines", 
          Path.GetFileName(filePath), File.ReadAllLines(filePath).Length));
    }
 
    //  Show the output
    MessageBox.Show(builder.ToString());
} 

对于 CanShowMenu,我们始终返回 true - 稍后我们将看到为什么我们不需要验证我们是否选择了文本文件。对于 CreateMenu,我们构建一个只有一个项目的上下文菜单条,其标题为“Count Lines”,并调用 CountLines 函数。

CountLines 函数遍历 SelectedItemPaths 并计算每个文件中的行数 - 然后显示一个包含摘要的消息框。

步骤 4:处理 COM 注册

还有一些事情要做。首先,我们必须将 COMVisible 属性添加到我们的类。

[ComVisible(true)]
public class CountLinesExtension : SharpContextMenu

为什么?好吧,即使我们的类看起来不像,它实际上是一个 COM 服务器。如果您查看基类,您会发现我们正在实现 IShellExtInitIContextMenuISharpShellServer 等 COM 接口。我们不需要担心它们的作用,但为了让系统能够创建我们的扩展,它必须具有此属性。

接下来,我们必须为程序集提供强名称。有办法绕过此要求,但通常这是最佳方法。要做到这一点,请右键单击项目并选择“Properties”(属性)。然后转到“Signing”(签名)。选择“Sign the Assembly”(签名程序集),为密钥指定“New”(新建),然后选择一个密钥名称。您可以选择使用密码保护密钥,但不是必需的

最后一步 - 我们现在需要将我们的扩展与一些文件类型关联起来。我们可以使用 COMServerAssociation 属性(由 SharpShell 提供)来实现此目的

[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, ".txt")]
public class CountLinesExtension : SharpContextMenu

我们在这里做了什么?我们告诉 SharpShell,在注册服务器时,我们希望它与 * .txt 文件的相关联。这意味着它不仅对以 * .txt 结尾的任何内容可用,而且对任何共享相同图标的类(基本来说,最像 * .txt 文件)也可用。

您可以使用 COMServerAssociation 属性做一些非常有趣的事情 - 您可以与文件夹、驱动器、未知文件、特定扩展名等相关联。此功能的完整文档位于 COM Server Associations (COM 服务器关联) 在 SharpShell CodePlex 网站上。

就这样!构建项目会创建 CountLinesExtension 程序集,该程序集可以注册为 COM 服务器,将上下文菜单添加到系统中。注册 COM 服务器是一项调试和部署任务,因此我们将在下一节中详细讨论。

调试 Shell Extension

Shell Extension 将在 Windows Explorer 中托管 - 由于 .NET COM Server 的加载方式比较曲折,因此很难将调试器放入进程并逐步执行托管代码。但是,有一种方法可以快速调试您的扩展。SharpShell 带有一些工具,可以更轻松地处理 SharpShell COM 服务器,其中之一是 Server Manager。我们可以使用此工具来调试我们的扩展。

打开 Server Manager 工具,使用 **File > Load Server** (文件 > 加载服务器) 来加载已构建的服务器文件 (DLL)。您也可以将服务器拖到主窗口中。选择服务器将显示有关它的详细信息。

Server Manager 非常有用 - 它会告诉您服务器是否已安装(32 位或 64 位模式)以及更多详细信息。

如果加载 SharpContextMenu 服务器,然后选择它,您可以转到“Tools”(工具)菜单并选择“Test Context Menu”(测试上下文菜单)。

当您使用“Test Context Menu”(测试上下文菜单)时,您将获得一个 Test Shell Window (测试 Shell 窗口)。这是 Windows Explorer 应用程序的一个基本实现。您可以右键单击任何项目来测试 Shell Context Menu。

提示:无论您设置了哪个 COMServerAssocations,Test Shell 始终会尝试为创建的项目创建上下文菜单。

将调试器附加到 ServerManager.exe 进程将允许您调试上下文菜单并测试其功能,而无需在 Windows 中注册服务器。以下是运行 Count Line Context menu 扩展时 Test Shell 的外观。

安装和注册 Shell Extension

有多种方法可以安装和注册 SharpShell Shell Extensions。在本节中,我将详细介绍所有这些方法。

regasm 工具

您可以使用“regasm”工具来安装和注册 shell extension。使用 regasm 时,shell extension 将被安装到注册表中(即,COM Server 的 Class ID 将放在 COM Server Classes 部分,并与实际服务器文件的路径关联),它还将注册关联。

Server Manager 工具

Server Manager Tool 是我首选的安装/卸载和注册/取消注册方法,至少在开发期间是这样,因为它允许您将安装和注册作为单独的步骤。它还将允许您指定是以 32 位还是 64 位模式安装/卸载等。

手动注册表操作

通常是一个坏的方法,但如果您绝对必须这样做,那么 MSDN 文档(针对 Shell Extensions)描述了必须对注册表进行的更改才能手动注册 COM 服务器或托管 COM 服务器。文档列在“Useful Resources”(有用资源)部分。

有用资源

  • Creating Shortcut Menu Handlers in Windows (在 Windows 中创建快捷菜单处理程序):最重要的资源 - 有关 Windows 中 Shell Context Menu 扩展工作原理的详细信息
  • SharpShell on CodePlex (SharpShell on CodePlex):SharpShell 项目的主页 - 包括文档、讨论以及最新的源代码和发行版

下一步?

SharpShell 将随着时间的推移提供一种使用 .NET 创建所有可用 Shell Extensions 的机制。目前,Icon Handlers (图标处理程序) 已实现(我正在编写文档),Property Sheet Handlers (属性表处理程序) 也已实现(还有一些 bug 需要修复)。每种扩展类型都将有一篇文章。

希望您觉得本文有用 - 对于功能请求、bug 或评论,您可以使用下面的评论部分或 CodePlex 网站。

历史

  • 2014 年 11 月 27 日:初始版本
© . All rights reserved.