C#下使用SharpShell自定义桌面鼠标右键菜单,一次选择多个文件进行后续处理

想做一个类似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

 

posted @ 2020-12-13 00:50  ryan1985  阅读(1894)  评论(1编辑  收藏  举报