想做一个类似Winrar的右键菜单,用来处理日常桌面文档,研究了好几天。
一种比较简单的实现就是自定义注册表。比如对所有文件都适用的右键菜单,可以在HKEY_CLASSES_ROOT\*\shell注册表项下新建一个项目A,项目A下设置一个子项目Command,Command下设置一个后续处理参数C:\XXX.exe "%1"。这种网上有很多例子,可以自行检索「右键菜单 注册表」,也可以自定义菜单图标,多级菜单。
为什么最终没有用这种静态注册表的方式呢?因为这种方式不支持一次性获取多个文件或目录,并作为一个「大参数列表」传递给后续应用处理。
网上又扒了扒,得知需要实现这种需求,涉及到Windows Shell编程,不过资料并不是很多。后面参考了一篇国外大神的文章http://www.codeproject.com/Articles/512956/NET-Shell-Extensions-Shell-Context-Menus,在C#开发环境下得以实现,遂略作记录。
1、在VS中创建一个类库项目
2、管理NuGet程序包,搜索SharpShell,并安装
3、默认cs文件示例代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Diagnostics; using System.IO; using System.Reflection; using SharpShell.SharpContextMenu; using SharpShell.Attributes; namespace AuroraContextMenu { [ComVisible(true)] //如果按文件类型,按以下设置 //[COMServerAssociation(AssociationType.ClassOfExtension, ".xlsx", ".xls")] //设置对全部文件和目录可用 [COMServerAssociation(AssociationType.AllFiles), COMServerAssociation(AssociationType.Directory)] public class ArrContextMenu : SharpContextMenu { /// <summary> /// 判断菜单是否需要被激活显示 /// </summary> /// <returns></returns> protected override bool CanShowMenu() { return true; } /// <summary> /// 创建一个菜单,包含菜单项,设置ICON /// </summary> /// <returns></returns> protected override ContextMenuStrip CreateMenu() { var menu = new ContextMenuStrip(); //设定菜单项显示文字 var item = new ToolStripMenuItem("Aurora右键助手"); //添加监听事件 //item.Click += Item_Click; //设置图像及位置 item.Image = Properties.Resources.logo; item.ImageScaling = ToolStripItemImageScaling.None; item.ImageTransparentColor = System.Drawing.Color.White; item.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; //设置次级菜单 Dictionary<string, string> subItemsInfo = new Dictionary<string, string>() { { "复制完整路径", "copyPath" }, { "合并Excel报表", "mergeExcelReport" }, { "合并Excel工作表", "mergeExcelSheet" }, { "转换为PDF文件...", "mergeExcelSheet" }, { "以邮件附件发送...", "mailTo" }, { "批量打印文档...", "batchPrint" } }; foreach (KeyValuePair<string,string> kv in subItemsInfo) { var subItem = new ToolStripMenuItem(kv.Key); subItem.Click += (o, e) => { Item_Click(o, e, kv.Value); }; item.DropDownItems.Add(subItem); } menu.Items.Add(item); return menu; } //菜单动作 private void Item_Click(object sender, EventArgs e, string arg) { string rootPath = getRootPath(); string appFile = string.Format(@"{0}\{1}", rootPath, "AuroraTools.exe"); if (!File.Exists(appFile)) { MessageBox.Show(string.Format("找不到程序路径:{0}{1}", Environment.NewLine, appFile), "出错了", MessageBoxButtons.OK); return; } List<string> paths = SelectedItemPaths.ToList(); paths.Add(arg); string args = string.Join(" ", paths); Process.Start(appFile, args); } //获取当前dll所在路径 private string getRootPath() { string codeBase = Assembly.GetExecutingAssembly().CodeBase; UriBuilder uri = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path); } } }
该例子中设置了菜单图标,可以自己在PS中绘制一个24像素以内的png图片,放到资源文件中直接使用
4、选择强名称密钥文件,对程序集进行签名
5、Release项目,打开Release目录,可以看到升成的dll文件
6、用RegAsm.exe注册该dll文件,可以在自己电脑上搜一下该文件,将其COPY到dll同一目录,这里我写了一段bat注册和反注册代码
注册
@echo off cd /d %~dp0 echo 检查dll set dllfile=AuroraContextMenu.dll if not exist %dllfile% ( echo %dllfile% is not exist! pause>nul exit ) ".\RegAsm.exe" /codebase %dllfile% pause exit
反注册,反注册后需要重启资源管理器
@echo off cd /d %~dp0 echo 检查dll set dllfile=AuroraContextMenu.dll if not exist %dllfile% ( echo %dllfile% is not exist! pause>nul exit ) ".\RegAsm.exe" /codebase %dllfile% /u echo 重启资源管理器 taskkill /f /im explorer.exe & start explorer.exe pause exit
7、注册成功后的效果
右键菜单dll只是一个中间件程序,对接的后续处理程序可以是c# wpf,python等各种应用程序,但需要接受命令行参数
以wpf为例,要使其接受命令行,需要在App.xaml中加上 Startup="Application_Startup"
<Application x:Class="AuroraTools.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:AuroraTools" StartupUri="MainWindow.xaml" Startup="Application_Startup"> <Application.Resources> </Application.Resources> </Application>
并在App.xaml.cs中对Application_Startup进行定义,前面右键菜单传来的参数列表体现在e.Args中
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace AuroraTools { /// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { string s = string.Empty; MessageBox.Show(string.Join(Environment.NewLine, e.Args)); App.Current.Shutdown(); } } }
完整的DEMO下载地址:
https://download.csdn.net/download/sinat_29203953/13669717