实现内容

  1. 1 鼠标右键点击单个.xlsx或.xls文件,显示与左边文件进行对比

  1. 2 选中两个文件,点击鼠标右键,显示表格对比

代码

using Microsoft.Win32;
using SharpShell.Attributes;
using SharpShell.SharpContextMenu;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ExcelCompareExtension
{
    // 声明COM可见性
    [ComVisible(true)]
    // 关联文件类型
    [COMServerAssociation(AssociationType.ClassOfExtension, ".xlsx")]
    [COMServerAssociation(AssociationType.ClassOfExtension, ".xls")]
    

    public class ExcelCompareExtension : SharpContextMenu
    {
        
        static string dllPath = typeof(ExcelCompareExtension).Assembly.Location;
        static string dllDirectory = Path.GetDirectoryName(dllPath);
        string exeFullPath = Path.Combine(dllDirectory, "Excel Compare.exe");
        
        /// <summary>
        /// 决定是否显示菜单项
        /// </summary>
        protected override bool CanShowMenu()
        {
            // 这里可以添加更复杂的逻辑,例如检查选中文件的数量或类型
            // SelectedItemPaths 是 SharpShell 提供的属性,包含所有选中文件的路径
            return SelectedItemPaths.Count() > 0;
        }

        /// <summary>
        /// 创建并返回上下文菜单
        /// </summary>
        protected override ContextMenuStrip CreateMenu()
        {
            var menu = new ContextMenuStrip();

            if (SelectedItemPaths.Count() == 1)
            {
                var leftValue = RegistryHelper.ReadValue("SaveLeftExcel");
                if (leftValue == "")
                {
                    var itemChooseLeftCompare = new ToolStripMenuItem
                    {
                        Text = "选择左边文件进行比较"
                        // 如果有图标资源,可以在此处设置 Image 属性
                        // Image = Properties.Resources.CountLines 
                    };
                    itemChooseLeftCompare.Click += (sender, args) => WriteLeftvalue();
                    menu.Items.Add(itemChooseLeftCompare);
                }
                else
                {
                    var itemChooseLeftCompare = new ToolStripMenuItem
                    {
                        Text = "选择左边文件进行比较"
                    };
                    itemChooseLeftCompare.Click += (sender, args) => WriteLeftvalue();
                    menu.Items.Add(itemChooseLeftCompare);

                    var itemWithLeftCompare = new ToolStripMenuItem
                    {
                        Text = $"与{Path.GetFileName(leftValue)}进行比较"
                    };
                    itemWithLeftCompare.Click += (sender, args) => CompareExcel();
                    menu.Items.Add(itemWithLeftCompare);
                }
            }

            if (SelectedItemPaths.Count() == 2)
            {
                var itenExcleCompare = new ToolStripMenuItem
                {
                    Text = "表格对比"
                };
                itenExcleCompare.Click += (sender, args) => CompareExcel2();
                menu.Items.Add(itenExcleCompare);
            }
            return menu;
        }

        private void WriteLeftvalue()
        {
            foreach (var filePath in SelectedItemPaths)
                RegistryHelper.WriteValue("SaveLeftExcel", filePath);
        }

        private void CompareExcel()
        {
            string excelPath = "";
            foreach (var filePath in SelectedItemPaths)
                excelPath = filePath;
            var LeftExclePath = RegistryHelper.ReadValue("SaveLeftExcel");
            string exePath = exeFullPath;
            string executeArgs = $"{LeftExclePath} {excelPath}";
            ExecuteExternalExe(exePath, executeArgs);
            //注册表SaveLeftExcel值写空
            RegistryHelper.WriteValue("SaveLeftExcel", "");
        }

        private void CompareExcel2()
        {
            string exePath = exeFullPath;
            string executeArgs = "";
            foreach (var filePath in SelectedItemPaths)
            {
                executeArgs += $"{filePath} ";
            }
            ExecuteExternalExe(exePath, executeArgs);
        }

        public class RegistryHelper
        {
            private const string SubKey = @"SOFTWARE\MyShellExtension";

            // 读取值
            public static string ReadValue(string valueName, string defaultValue = "")
            {
                try
                {
                    // 优先检查当前用户配置,若无则检查本地机器
                    using (var key = Registry.CurrentUser.OpenSubKey(SubKey))
                    {
                        if (key != null)
                        {
                            return key.GetValue(valueName, defaultValue)?.ToString() ?? defaultValue;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // 记录日志,避免崩溃
                    System.Diagnostics.Debug.WriteLine($"Read Reg Error: {ex.Message}");
                }
                return defaultValue;
            }

            // 写入值
            public static void WriteValue(string valueName, string value)
            {
                try
                {
                    // CreateSubKey 若不存在则创建,存在则打开
                    using (var key = Registry.CurrentUser.CreateSubKey(SubKey))
                    {
                        if (key != null)
                        {
                            key.SetValue(valueName, value, RegistryValueKind.String);
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"Write Reg Error: {ex.Message}");
                }
            }

        }
        public void ExecuteExternalExe(string exePath, string arguments)
        {
            try
            {
                var startInfo = new ProcessStartInfo
                {
                    FileName = exePath,
                    Arguments = arguments,
                    UseShellExecute = false, // 必须为 false 才能重定向输出或隐藏窗口
                    CreateNoWindow = true,   // 不显示控制台窗口
                    RedirectStandardOutput = true, // 如需获取返回结果
                    RedirectStandardError = true
                };

                using (var process = Process.Start(startInfo))
                {
                    // 同步等待(慎用,可能导致资源管理器假死)
                    // process.WaitForExit(); 

                    // 推荐:异步读取或仅启动后忽略
                    string output = process.StandardOutput.ReadToEnd();
                    string error = process.StandardError.ReadToEnd();

                    // 记录日志或处理结果
                }
            }
            catch (Exception ex)
            {
                // 记录异常,防止崩溃
            }
        }
    }
}
   
        


    

windows注册

编译代码生成DLL,使用regasm手动处理注册表项以让资源管理器识别,"%DLL_PATH%",DLL_PATH为DLL文件绝对路径

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /codebase "%DLL_PATH%"

取消注册

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /u "%DLL_PATH%"

更多推荐