这两天有个需求如下:
用户已经安装应用程序为P,假如安装目录为“C:\Program(x86)\P”,后期如果程序需要升级给用户升级包,无论升级包在什么位置,用户双击升级包可以自动升级P。

以上需求分析后需要解决如下问题:
1.双击升级包可以执行。

2.找到原程序的安装路径。

针对第一个问题我想到了两种解决方案:
1.可以自己写程序生成exe文件,用户双击运行后释放文件到指定目录(也就是找到原安装路径)中,这显然不合适,因为每次升级都需要制作安装包,而且这个安装包中需要有一定的业务逻辑,制作复杂,成本较高。
2.定义一种文件格式做文件关联,关联程序为安装目录底下的update.exe,升级包采用zip压缩后将后缀改为自定义后缀,用户双击升级包时会运行时运行升级程序同时传入升级包路径。升级程序要做的就是解压、替换。
— 比较连个方案,很容易发现,方案二很快捷而且同时解决了上面的问题二(因为升级程序的路径就是原程序的安装路径)。

这边我们来看下文件关联的代码:


 [DllImport("shell32.dll")]
 public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
 /// <summary>
        /// 添加文件关联
        /// </summary>
        private void RegFileExt()
        {
            try
            {
                string boardExeFullName = AppDomain.CurrentDomain.BaseDirectory + "EUpdate.exe";
                string IcoFullName = AppDomain.CurrentDomain.BaseDirectory + "EUpdate.ico";
                if (File.Exists(boardExeFullName))
                {
                    string MyExtName = ".ez";
                    string MyType = "ez_auto_file";
                    string MyContent = "application/ez";
                    string command = "\"" + boardExeFullName + "\"" + " \"%1\"";
                    RegistryKey key = Registry.ClassesRoot.OpenSubKey(MyType);
                    if (key == null)
                    {
                        RegistryKey MyReg = Registry.ClassesRoot.CreateSubKey(MyExtName);
                        MyReg.SetValue("", MyType);
                        MyReg.SetValue("Content Type", MyContent);
                        MyReg = Registry.ClassesRoot.CreateSubKey(MyType);
                        MyReg.SetValue("", MyType);
                        MyReg = MyReg.CreateSubKey("Shell\\Open\\Command");
                        MyReg.SetValue("", command);
                        MyReg.Close();

                        //通知系统将关联文件的图标显示为Ezposter 自定义图标
                        SHChangeNotify(0x8000000, 0, IntPtr.Zero, IntPtr.Zero);
                        LogHelper.Log("设置文件关联操作成功!");
                    }
                    else
                    {
                        var myReg = key.OpenSubKey("Shell\\Open\\Command", true);
                        if (myReg != null && (myReg.GetValue("") == null || myReg.GetValue("").ToString() != command))
                        {
                            myReg.SetValue("", command);//解决因目录变化导致 注册表失效的问题
                            myReg.Close();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Log("文件关联失败");
                LogHelper.ErrorLog(ex);
            }
        }

上面我们定义了一个.ez的文件格式,通过写系统注册表实现关联到指定的exe执行,要注意下SHChangeNotify(0x8000000, 0, IntPtr.Zero, IntPtr.Zero);这行代码,如果没有这行代码,那么在做文件关联后升级包的图标仍然是系统默认的图标,除非重启电脑。执行这个代码后升级包的图标会变成update.exe的图标。