我自己的前言说明:

  本文原作者为Dave Kerr,原文链接为.NET Shell Extensions - Shell Context Menus,我是在为了完成最新需求的时候查询资料的时候发现的,因为太久没有看外文资料了,所以为了锻炼一下翻译的,文中有一句未能翻译出来。

引言:

  一直到.NET 4.0为止,我们都还是不能通过.NET代码完全实现外壳扩展的功能。但是随着framework的不断提高,现在我们已经可以实现这个功能了。在本文中,我将带领你通过C#类文件快速实现右键菜单扩展功能。

(图中是已经实现的功能,“Count Lines”是我自定义的一个右键选项,文章将仔细解释如何实现该功能)

“.NET外壳扩展”索引:

  本文只是“.NET外壳扩展”的一部分,本系列还包括:

  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

什么是Shell Context Menus?

  Shell Context Menus是在系统中注册,允许扩展shell对象的Context菜单的COM服务器。这里说的对象可以明确到具体的文件类型,例如“.txt”文件,驱动,文件或者其他的文件类型。这时的Context菜单可以通过Windows管理器快速访问到更多的信息。

准备:

  实现外壳扩展功能有很多工作需要完成:我们需要实现具体的COM接口,需要提供服务,并通过各种方式更新注册表。现在我们可以调用我已经写好的一个叫做“SharpShell”库来完成这些复杂的功能,这样我们的任务就变成了只需要创建一个包含已完成延展功能类的轻量级的类库了。

我们的目标:

  下面所示代码创建了一个shell扩展,允许你通过右键并选择“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 ouput.
MessageBox.Show(builder.ToString());
}
}

  代码可以说简单清晰了,现在就让我们开始仔细研究具体的实现过程吧。

第一步:新建项目

  首先,我们需要开始一个新的C#类库项目。

    提示:你也可以除了C#,还可以使用VB,在本文中虽然所有的代码都是C#,但是方法原理均同理可得。

  在本例中,我们的项目名称是” CountLinesExtension”.

  现在我们需要添加一下的引用:

  • System.Windows.Forms
  • System.Drawing

  之所以需要System.Windows.Forms,是因为我们需要通过WinForms ContextMenuStrip来定义context菜单。而需要调用System.Drawing的原因在于我们想要用到Icons。

  将'Class1.cs'重命名为'CountLinesExtension.cs'.那么目前我们项目的就变成了这样了:

第二步:引用SharpShell

  现在我们需要添加对SharpShell的引用。你可以通过以下这些不同的方法:

添加引用:

  在文章最开始的地方下载'SharpShell Library'压缩文件,然后直接对SharpShell.dll文件添加引用即可。

    提示:文章开始的下载文件是在此文写的时候的文件,如果你想要获得最新的版本,请通过Nuget或者从sharpshell.codeplex.com获取。

Nuget

  如果你电脑有Nuget,那么就只需要简单检索SharpShell并安装即可,或者直接访问:https://www.nuget.org/packages/SharpShell

CodePlex

  从CodePlex 的里面专门的SharpShell主页sharpshell.codeplex.com中你直接可以得到最新的版本。Nuget上虽然也有最新的可靠的版本,但是CodePlex可以还有可用的已写好的betas,而且那上面的文章里面的版本基本都是可用的。

第三步:SharpContextMenu

  现在开始就开始真正的研究了,注意了哦。我们的CountLinesExtension继承于SharpContextMenu:

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

  现在我们既然继承于SharpContextMenu这个父类,那我们就要来实现这个抽象类。右键选择SharpContextMenu,然后选择'Implement Abstract Class':

  这个操作将会自动生成SharpContextMenu的两个函数-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 ouput.
MessageBox.Show(builder.ToString());
}

  对于CanShowMenu,我们常常直接返回true(很快我们就会明白为什么我们不需要验证我们的文本文件了)。对于CreateMenu,我们建立了一个显示菜单,里面只有一个选项,也就是'Count Lines',并实现读出行数的功能。

  CountLines这个功能的实现是通过SelectedItemPaths和读取每个文件的函数,然后总结好了显示在弹窗里。

第四步:处理COM注册

  现在所剩的事情不多了。首先我们需要添加COMVisible的引用到我们的类里面。

[ComVisible(true)]
public class CountLinesExtension : SharpContextMenu

  为什么呢?因为我们的类虽然看起来不像,但是他本质上也是一个COM Server.如果你了解一些基类,那么你可以看我们刚刚实现的COM接口,例如IShellExtInit, IContextMenu, 和 ISharpShellServer。我们不用了解这里到底做了什么,凡是为了保证系统能够创建我们的扩展,她就必须有这个属性。

  接下来,我们需要给程序集一个强名称。这里有很多方法实现这个要求,但是总体来说,这是最好的方法。现在我们单机程序右键,然后选择“属性”。再选择“签名”。选中“为程序集签名”,再选择“选择强名称秘钥文件”里面的“新建”,并输入新建的密钥文件名称。你可以自行选择是否需要使用密码保护密钥文件:

  最后一步,我们需要关联我们的扩展到具体的文件类型了。这个的实现可以通过对COMServerAssociation(来源于SharpShell)的引用:

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

  在这里我们做了什么呢?我们告诉了SharpShell,注册服务器时,我们想要关联任何与“.txt”相关的类。这就意味着我们不止是仅限于以.TXT结尾的文件,而是任何同类的文件。更权威的说法是,大多是与txt文件共享同样图标的东西。

  你可以用COMServerAssociation的属性来实现更多的功能,例如你还可以与文件夹,驱动,位置的文件来实现特定的扩展,等等。另外,关于COM Server Associations的详细的文献资料在SharpShell CodePlex上面。

  好了,但目前为止就搞定了!我们已经创建一个可以在作为COM server 在系统中添加自定义菜单的CountLinesExtension程序集项目了。关于注册COM Server和调试部署的任务,我们我们将在下一节,仔细讨论。

调试Shell 扩展

  这个Shell扩展功能将被加载到电脑资源管理器时,由于加载.NET COM Server时各种迂回的方式,所以可以说让调试器进入进程并但不执行托管代码几乎可以说是不可能实现的事情。当然,这里还是有一个方法可以快速实现调试。Sharp Shell有一些工具,让实现COM Server变得简单了,其中一个叫做:Server Manager。我们可以用这个工作实现调试。

  打开Server Manager工具,然后点击File,选择Load Server,再加载已生成的文件(DLL文件)。你也可以直接拖动文件到主界面中。然后被选中的文件的详细信息就会在旁边显示了。

  这个Server Manager非常好用,它可以告诉你服务是否已经安装了和其他各种信息。

  如果你要加载SharpContextMenu服务,那就选中'Tools',然后你选中再选中'Test Context Menu'。

  当你用到了'Test Context Menu'的时候,你会得到一份测试窗口。只是Windows资源管理器应用程序的基本实现。你可以通过右键单击来测试。

    提示:不管你的COMServerAssocations已经生成了,测试的窗口都会不断的重新创建。

  将调试器附加到servermanager过程将允许你调试你的上下文菜单和测试它的功能,而无需在Windows登记服务器。下面是运行Count Line上下文扩展菜单时测试shell的样子

安装和注册Shell扩展

  这里又很多方法实现安装和注册Shell扩展。在接下来的这一节里我将仔细介绍这些。

regasm

  你可以通过regasm这个工具来实现安装和祖册shell扩展。当使用regasm的时候shell会被装进注册表中(COM服务器的类ID将放在COM服务器类部分,并与实际服务器文件的路径相关联),也会创建关联。

Server Manager

  在开发过程中,服务器管理工具是我首选的安装/卸载和注册/注销的方法,因为它可以让安装和注册作为单独的步骤处理。它也将让你指定你是安装/卸载在32位还是64位模式中。

手动注册表操作

  Generally a bad approach, but if you absolutely have to then the MSDN documentation for Shell Extensions describes the changes that must be made to the registry to manually register a COM server, or a Managed COM Server(这句不会翻译)。这个文献资料被放在了下一节。

有用的资料

后记

  会逐渐通过SharpShell和.NET的使用来时间实现更多的shell扩展功能,形成一个完整的系列。目前那我正在实现图标处理程序(正在编写文档),关于属性表处理程序问题已经实现了(还有些bug正在解决)。

[翻译].NET Shell Extensions - Shell Context Menus---.net 外壳扩展-右键菜单的更多相关文章

  1. How to Use GNOME Shell Extensions

    如果没有安装Tweaks请先安装,命令如下: sudo apt install gnome-tweak-tool 1. Use gnome-shell-extensions package [easi ...

  2. (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单

    原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windo ...

  3. 转:shell 经典, shell 十三问

      原文链接:http://blog.csdn.net/freexploit/article/details/626660 我在 CU 的日子并不长,有幸在 shell 版上与大家结缘.除了跟众前辈学 ...

  4. [拾 得] 一枚迷人的贝壳 SHELL / Linux | shell 脚本初步入门

    坚持知识分享,该文章由Alopex编著, 转载请注明源地址: http://www.cnblogs.com/alopex/   索引: 什么是shell shell的分类 shell脚本的执行方式   ...

  5. Shell十三问更新总结版 -- 什么叫做 Shell?-- Shell十三问<第一问>

    Shell十三问更新总结版 简介 ChinaUnix 论坛 Shell 版名为網中人的前辈于 2004 年发布的精华贴,最近回炉这块内容,觉得很多东西讲的实在透彻,非常感谢前辈網中人,同时我个人也对这 ...

  6. (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单

    原文 (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 接上一节:(C#)Windows Shell 编程系列2 - 解释,从“桌面”开始展开这 ...

  7. CMD & Git Shell & Bash Shell

    CMD & Git Shell & Bash Shell https://mvdan.cc/sh/cmd/shfmt PC

  8. java.lang.NullPointerException at java.lang.ProcessBuilder.start(Unknown Source) at org.apache.hadoop.util.Shell.runCommand(Shell.java:482)

    1:问题出现的原因,部署好的hadoop-2.6.4进行window10操作hadoop api出现的错误,具体错误是我向hdfs上传文件,还好点,之前解决过,这里不叙述,这里说一下从hdfs下载文件 ...

  9. Linux Shell常用shell命令

    Linux Shell常用shell命令 一.文件.目录操作命令 1.ls命令 功能:显示文件和目录的信息 ls 以默认方式显示当前目录文件列表 ls -a 显示所有文件包括隐藏文件 ls -l 显示 ...

随机推荐

  1. Layui常见问题

    为什么表单不显示?当你使用表单时,Layui会对select.checkbox.radio等原始元素隐藏,从而进行美化修饰处理.但这需要依赖于form组件,所以你必须加载 form,并且执行一个实例. ...

  2. 解读JavaScript原型链

    var F = function(){}; F.prototype.a = function(){}; Object.prototype.b = function(){}; Function.prot ...

  3. iOS voip电话和sip软电话 --网络电话

    一|介绍1.两者区别: SIP软电话与IP电话在技术上属于同一类型,只是SIP软电话是使用电脑软件实现的,而IP电话有一部分是在话机中直接写入了程序,可以通过硬件直接使用.IP(简称VoIP,源自英语 ...

  4. 小白的Python之路 day4 生成器

    一.列表生成式  看下面例子: 列表生成式的作用:主要是让代码更简洁(还有装X的效果) 二.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  5. Ubuntu14.04下安装 boost (boost_1.54 最简单的方法)

    直接执行命令: sudo apt-get  install libboost-dev 测试: 创建一个 boost_test.cpp 文件,写入 #include<iostream> #i ...

  6. 使用图片地图减少HTTP请求数量

    前言 最近在看<高性能网站建设>,记录一下所学. 现在很多网站都是图片形式的导航,点击图片跳转到对应的链接.如果导航项目很多的话,图片的数量就会很多,每需要加载一张图片就会多一个HTTP请 ...

  7. java多线程(四)-自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...

  8. XCopy命令实现增量备份

    xcopy XCOPY是COPY的扩展,可以把指定的目录连文件和目录结构一并拷贝,但不能拷贝系统文件:使用时源盘符.源目标路径名.源文件名至少指定一个:选用/S时对源目录下及其子目录下的所有文件进行C ...

  9. Travis CI实现持续部署

    安装Ruby 2.0以上版本并安装travis的命令行工具 可以看出我的已经是安装好的(Ubuntu 16.04.3 LTS 系统) ruby -v ruby --) [x86_64-linux-gn ...

  10. MicroPython开发板:TPYBoard v102 播放音乐实例

    0x00前言 前段时间看到TPYBoard的技术交流群(群号:157816561,)里有人问关于TPYBoard播放音乐的问题.最近抽空看了一下文档介绍,着手做了个实验.更多MicroPython的教 ...