DotNet 笔记

东方欲晓,莫道君起早。

C# Winform 自动更新程序实现与使用

 源码下载:AutoUpdater.rar (894.81 kb)

项目介绍:
AutoUpdater:主要是更新对话框,下载对话框。dll形式。
AutoUpdaterBuilder:放于网站服务器中,当需要更新的时点击一次,生成新的AutoupdateService.xml文件。
AutoUpdaterDemo:测试客户端主程序例子。
AutoUpdaterTool:更新工具,生成后需要和主程序的生成文件合并文件夹。负责更新后启动主程序,下载更新文件等功能。

更新原理

对比本地的AutoUpdater.config文件与服务器的AutoupdateService.xml文件内,同一个文件的版本号大小。

一:建立更新服务器

1:重新生成AutoUpdaterBuilder项目。
2:新建一个网站(注意必须是动态网站,含有web.config),然后把【1步】生成的项目放入网站根目录内(pdb文件可删除)。


二:对更新工具设置 服务器地址、设置启动程序名字

1:修改AutoUpdaterTool项目内AutoUpdater.config文件ServerUrl节点,节点值为第二步网站中AutoupdateService.xml文件的网络地址。
如: <ServerUrl>http://localhost:8833/AutoupdateService.xml</ServerUrl>
2:修改AutoUpdaterTool项目内主配置文件【key="MainProgramName"】节点的值,值为:主程序(需要更新的的程序)的可执行文件名
如:<add key="MainProgramName" value="AutoUpdaterDemo.exe"/>


三:修改主程序(AutoUpdaterDemo),每次启动检查更新。

a:在主程序中,首先添加一个新类:

    /// <summary>
    /// 通过程序名称、版本号和路径检查程序是否已运行
    /// </summary>
    class ClassCheckProIsRun
    {
        /// 该函数设置由不同线程产生的窗口的显示状态
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分</param>
        /// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零</returns>
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        /// <summary>
        ///  该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。
        ///  系统给创建前台窗口的线程分配的权限稍高于其他线程。 
        /// </summary>
        /// <param name="hWnd">将被激活并被调入前台的窗口句柄</param>
        /// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零</returns>
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        private const int SW_SHOWNOMAL = 1;

        private static void HandleRunningInstance(Process instance)
        {
            ShowWindowAsync(instance.MainWindowHandle, SW_SHOWNOMAL);   //show已运行的更新程序
            SetForegroundWindow(instance.MainWindowHandle);     //窗口置最前
        }

        /// <summary>
        /// 检测进程中程序是否已运行,返回运行状态
        /// </summary>
        /// <param name="strPath">程序完整路径</param>
        /// <returns>运行状态</returns>
        public bool checkProcess(string strPath)
        {
            ////获取版本号
            string strVersionNumber = Application.ProductVersion;

            string strProName = strPath.Substring(strPath.LastIndexOf('\\') + 1, (strPath.LastIndexOf('.') - 1) - strPath.LastIndexOf('\\'));  //获取不带扩展名的程序名称

            bool isRun = false;      //更新程序是否已运行,默认未运行
            Process[] processes = Process.GetProcessesByName(strProName);   //同程序名的所有进程
            foreach (Process p in processes)//判断当前进程中是否已有该程序
            {
                if (p.MainModule.FileName.ToString() == strPath)//通过程序路径判断,而不能通过程序名判断
                {
                    string strVN = p.MainModule.FileVersionInfo.FileVersion;    //获取进程中正在运行的这个程序的版本号,留作判断版本时用
                    isRun = true;   //更新程序已运行
                    HandleRunningInstance(p);   //show已运行的更新程序,并置顶
                    break;
                }
            }
            return isRun;
        }

        /// <summary>
        /// 按程序名检查进程
        /// </summary>
        /// <param name="strProName">带扩展名的程序名</param>
        /// <returns>是否存在</returns>
        public bool checkProcessForProName(string strProName)
        {
            bool isRun = false;      //更新程序是否已运行,默认未运行
            Process[] processes = Process.GetProcessesByName(strProName.Substring(0, strProName.LastIndexOf('.')));   //同程序名的所有进程
            foreach (Process p in processes)//判断当前进程中是否已有该程序
            {
                if (p.MainModule.ModuleName == strProName)//通过程序路径判断,而不能通过程序名判断
                {
                    string strVN = p.MainModule.FileVersionInfo.FileVersion;    //获取进程中正在运行的这个程序的版本号
                    isRun = true;   //更新程序已运行
                    break;
                }
            }
            return isRun;
        }
    }




b:在主程序的 启动窗口程序中(第一个窗口程序) 添加两个变量

        /// <summary>
        /// 是否已经取消了更新
        /// </summary>
        public bool IsCancelUpdate { get; set; }


        /// <summary>
        /// 自动更新程序路径
        /// </summary>
        private readonly string autoUpdaterPath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdaterTool.exe";



c:然后在主程序的启动窗口程序中(第一个窗口程序) 的load函数内 添加检查更新代码代码:

        /// <summary>
        /// 检测更新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            if (!IsCancelUpdate)
            {
                try
                {
                    IAutoUpdater autoUpdater = new AutoUpdater();
                    if (autoUpdater.CheckUpdate())
                    {
                        if (new lib.ClassCheckProIsRun().checkProcess(autoUpdaterPath))
                        {
                            MessageBox.Show(@"更新程序已经运行!");
                            return;
                        }
                        System.Diagnostics.Process.Start(autoUpdaterPath);
                        Application.Exit();
                    }
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }

            }
        }

d:修改主程序的winform的main函数,作用是:在主窗口显示前,检验是否用户手动取消更新。

    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //新建“启动窗口”对象
            var mainForm = new Form1();

            //验证是否已经取消更新了
            if (args != null && args.Length > 0)
            {
                mainForm.IsCancelUpdate = Convert.ToBoolean(args[0]);
            }
            //开始运行
            Application.Run(mainForm);
        }
    }




四:整合更新程序到主程序内。

1:重新生成AutoUpdaterTool项目(pdb文件可以删除)。

2:成新生成主程序项目(本例中的AutoUpdaterDemo,生成后pdb文件可以删除)

3:拷贝【1】生成后的项目到【2】生成后的项目中。OK!可以运行了。

 

源码与示例下载:

AutoUpdater.rar (894.81 kb)

 

Loading