C#使用Microsoft Visual Studio Installer Projects打包winform

描述:在使用C#编写winform程序后,进行打包exe并进行安装,在安装完成后进行自动运行当前安装程序以及自动自启功能(注册表中添加改程序即可)

环境:vs2010(这块主要满足Microsoft .NET Framework 4.0),Microsoft Visual Studio Installer Projects

如果使用的是vs2019 需要手动安装打包插件:Microsoft Visual Studio Installer Projects

打开vs2019,选择 工具 --> 扩展和更新 --> 联机,搜索Microsoft Visual Studio Installer Projects,进行安装。安装好以后,重启vs2019,这块就不在截图了。

话不多说,直接开始:

1、在解决方案右键,选择新建项目,选择其它项目类型

2、在应用程序文件夹右键

3、选择打包程序的log图标

4、生成快捷方式

5、把生成好的快捷方式拖到用户的程序菜单中

6、设置用户桌面(vs2010(不需要创建文件夹)和vs2019(创建单独的文件夹存放桌面快捷键)区别)

7、设置操作,.NET Framework版本,这块版本根据实际需求选择即可

如果.NET Framework版本有特殊指定,在安装的时候检查是否支持当前版本,否则就下载指定的版本,可以在这块设置

8、如果在安装中不支持.NET Framework版本,可以让用户下载联网或者离线的版本即可

9、设置打包程序

10、重点的来了,想在安装完成后自动运行该程序,和自动把该程序添加到注册表中随着电脑自启动

这块注意选择视图中的自定义操作,然后在安装,提交,回滚,卸载,中都添加自定义操作,选择应用主程序即可。

注意:CustomActionData 填上参数:/targetdir="[TARGETDIR]\"  后面会使用到,这块你可以在用户界面中添加自定义的文本框或按钮,通过这块来传递参数

11、这块自定义操作,根据实现Installer来重新方法来实现安装,卸载等操作。

代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Win32;
using System.IO;
using System.Windows.Forms;


namespace IDP_Agent_Geo
{
    [RunInstaller(true)]
    public partial class CustomeInstaller : Installer
    {
        public CustomeInstaller()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 安装完成之后的操作,可以保留安装路径到
        /// 使用跨调用保留并传入 Install、Commit、Rollback和 Uninstall 方法的 IDictionary。
        /// IDictionary savedState
        /// </summary>
        /// <param name="savedState"></param>
        protected override void OnAfterInstall(IDictionary savedState)
        {
            //获取自定义安装用户界面上的端口值
            //string portId = this.Context.Parameters["PortId"];

            string path = this.Context.Parameters["targetdir"];
            Logger(string.Format("OnAfterInstall添加 targetdir savedState:{0}", path));
            //开机启动 1、硬编码,2设置Setup Projects的注册表编辑器
            //1、安装完成以后可以把硬编码把该软件写到注册表中,这样可以设置开机启动,
            //2、当然还有另外一种开机启动的方式是可以使用Setup Projects的注册表编辑器的来进行注册
            savedState.Add("savedState", path);
            Assembly asm = Assembly.GetExecutingAssembly();
            string asmpath = asm.Location.Remove(asm.Location.LastIndexOf("\\")) + "\\";
            Logger("OnAfterInstall asmpath:{asmpath}");
            SetAutoStart(true, "IDP-Agent-Geo", asmpath + "IDP-Agent-Geo.exe");
            //Process.Start(asmpath + "\\ServiceXStart.exe");//要执行的程序
            Process.Start(asmpath + "IDP-Agent-Geo.exe");//要执行的程序
            //Process.Start(path + "MyTestWinFrm.exe");//要执行的程序
            base.OnAfterInstall(savedState);
        }

        protected override void OnBeforeUninstall(IDictionary savedState)
        {
            base.OnBeforeUninstall(savedState);
            Trace.Listeners.Clear();
            Trace.AutoFlush = true;
            Trace.Listeners.Add(new TextWriterTraceListener(@"C:\IDP\OnBeforeUninstall.txt"));

            Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} OnBeforeUninstall");
            //Process[] processes = Process.GetProcessesByName("ServiceXStart");
            Process[] processes = Process.GetProcessesByName("IDP-Agent-Geo");
            foreach (Process item in processes)
            {
                Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} OnBeforeUninstall 进程:" + item);
                item.Kill();
                item.WaitForExit();
                item.Close();
            }
        }

        /// <summary>
        /// 卸载软件的时候删除多余的文件
        /// </summary>
        /// <param name="savedState"></param>
        protected override void OnAfterUninstall(IDictionary savedState)
        {
            //Install、Commit、Rollback和 Uninstall 方法并不总是在 Installer的同一实例上调用。 
            //例如,你可以使用 Installer 来安装和提交应用程序,然后释放对该 Installer的引用。 
            //稍后,卸载应用程序会创建对 Installer的新引用,这意味着 Uninstall 方法在 Installer的其他实例上调用。 
            //出于此原因,请不要在安装程序中保存计算机的状态。 
            //相反,请使用跨调用保留并传入 Install、Commit、Rollback和 Uninstall 方法的 IDictionary。

            Trace.Listeners.Clear();
            Trace.AutoFlush = true;
            Trace.Listeners.Add(new TextWriterTraceListener(@"C:\IDP\OnBeforeUninstall.txt"));

            Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} OnBeforeUninstall");
            var savedStateValue = savedState.Contains("savedState") ? savedState["savedState"] : "未获取到安装的目录";
            Trace.WriteLine("OnAfterUninstall从OnAfterInstall获取 savedState,值为:{savedStateValue}");
            string path = this.Context.Parameters["targetdir"];
            Trace.WriteLine("targetdir:{path}");
            Trace.WriteLine("开始删除目录:{path}");
            if (Directory.Exists(path))
            {
                RemoveSubDirectory(new DirectoryInfo(path));
                Trace.WriteLine(@"删除目录:{path} 成功");
            }
            Logger("OnAfterUninstall 进入。。。。");
            Trace.WriteLine("OnAfterUninstall  完成了。。。。");
            base.OnAfterUninstall(savedState);
            savedState.Add("xizai", true);
        }

        protected override void OnCommitted(IDictionary savedState)
        {
            base.OnCommitted(savedState);
            Trace.Listeners.Clear();
            Trace.AutoFlush = true;
            Trace.Listeners.Add(new TextWriterTraceListener(@"C:\IDP\OnCommitted.txt"));
            Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} OnCommitted");
            if (savedState==null)
            {
                Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} savedState={savedState}");
            }
            else
            {
                Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} 111 1111111savedState={savedState}");
            }
            var isxizai = savedState.Contains("xizai") ? savedState["xizai"] : "";
            var savedStateValue = savedState.Contains("savedState") ? savedState["savedState"] : "未获取到安装的目录";
            Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} isxizai:{isxizai}");
            Trace.WriteLine("{DateTime.Now:yyyy-MM-dd HH:mm:ss} savedStateValue:{savedStateValue}");
        }

        /// <summary>
        /// 卸载完成后删除多余的文件
        /// </summary>
        /// <param name="uper"></param>
        private static void RemoveSubDirectory(DirectoryInfo directory)
        {
            Logger(string.Format("目录信息 directory:{0}", directory));
            //foreach (FileInfo subFile in uper.GetFiles())
            //{
            //    subFile.Delete();
            //}
            foreach (DirectoryInfo sub in directory.GetDirectories())
            {
                if (sub.GetFiles().Length > 0 || sub.GetDirectories().Length > 0)
                    RemoveSubDirectory(sub);
                sub.Delete(true);
                Logger(string.Format("要删除的目录信息 sub:{0}", sub));
            }
            Logger("目录成功");
        }

        /// <summary>
        /// 将应用程序设为或不设为开机启动
        /// </summary>
        /// <param name="onOff">自启开关</param>
        /// <param name="appName">应用程序名</param>
        /// <param name="appPath">应用程序完全路径</param>
        public static bool SetAutoStart(bool onOff, string appName, string appPath)
        {
            Logger(string.Format("注册表设置的开机启动项:{0},{1},{2}", onOff, appName, appPath));
            #region MyRegion
            bool isOk = false;
            //如果从没有设为开机启动设置到要设为开机启动
            if (!IsExistKey(appName)&&onOff)
            {
                Logger("------设置注册表自动启动----不存在开机启动项,即将添加开机启动项------");
                isOk = SelfRunning(onOff, appName, @appPath);
            }
            //如果从设为开机启动设置到不要设为开机启动
            else if (IsExistKey(appName)&&!onOff)
            {
                Logger("------设置注册表自动启动----存在开机启动项,但未开启,即将开启启动项------");
                isOk = SelfRunning(onOff, appName, @appPath);
            }
            return isOk;
            #endregion
        }

        /// <summary>
        /// 判断注册键值对是否存在,即是否处于开机启动状态
        /// </summary>
        /// <param name="keyName">键值名</param>
        /// <returns></returns>
        private static bool IsExistKey(string keyName)
        {
            try
            {
                bool _exist = false;
                RegistryKey local = Registry.LocalMachine;
                RegistryKey runs = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
                if (runs == null)
                {
                    RegistryKey key2 = local.CreateSubKey("Software");
                    RegistryKey key3 = key2.CreateSubKey("Microsoft");
                    RegistryKey key4 = key3.CreateSubKey("Windows");
                    RegistryKey key5 = key4.CreateSubKey("CurrentVersion");
                    RegistryKey key6 = key5.CreateSubKey("Run");
                    runs = key6;
                }
                string[] runsName = runs.GetValueNames();
                foreach (string strName in runsName)
                {
                    if (strName.ToUpper() == keyName.ToUpper())
                    {
                        _exist = true;
                        return _exist;
                    }
                }
                return _exist;

            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 写入或删除注册表键值对,即设为开机启动或开机不启动
        /// </summary>
        /// <param name="isStart">是否开机启动</param>
        /// <param name="exeName">应用程序名</param>
        /// <param name="path">应用程序路径带程序名</param>
        /// <returns></returns>
        private static bool SelfRunning(bool isStart, string exeName, string path)
        {
            try
            {
                RegistryKey local = Registry.LocalMachine;
                RegistryKey key = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
                if (key == null)
                {
                    local.CreateSubKey("Software//Microsoft//Windows//CurrentVersion//Run");
                }
                //若开机自启动则添加键值对
                if (isStart)
                {
                    key.SetValue(exeName, path);
                    key.Close();
                    Logger("------设置注册表自动启动----开启----成功------");
                }
                else//否则删除键值对
                {
                    string[] keyNames = key.GetValueNames();
                    foreach (string keyName in keyNames)
                    {
                        if (keyName.ToUpper() == exeName.ToUpper())
                        {
                            key.DeleteValue(exeName);
                            key.Close();
                            Logger("------设置注册表自动启动----关闭----成功------");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger(string.Format("------设置注册表自动启动----异常----原因{0}------", ex));
                return false;
            }
            return true;
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="content"></param>
        public static void Logger(string content)
        {
            StreamWriter writer = null;
            try
            {
                // 检查文件夹
                string folderPath = @"C:\IDP-Logs\";
                if (false == Directory.Exists(folderPath))
                {
                    //创建文件夹
                    Directory.CreateDirectory(folderPath);
                }
                if (Directory.Exists(folderPath))
                {
                    //存在/成功创建 文件夹
                    folderPath = folderPath + @"\";
                }
                else
                {
                    //无则当前路径创建文件
                    folderPath = folderPath + @"-";
                }
                //写入日志 
                string filePath = string.Format(folderPath + @"logs{0}.txt", DateTime.Now.ToString("yyyy-MM-dd"));
                FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write);
                writer = new StreamWriter(fs);
                writer.WriteLine(string.Format("日志开始时间:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                //foreach (var item in content)
                //{
                    writer.WriteLine(content);
                //}
                writer.WriteLine("****************************************************************");
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }
            }
        }

    }
}

这块在操作注册表的时候,Registry.CurrentUser和Registry.LocalMachine的区别,在使用LocalMachine级别需要管理员才可以写入,不然会报异常。

参考网站:

https://www.cnblogs.com/java315/archive/2011/09/01/2397312.html

https://www.cnblogs.com/1175429393wljblog/p/13229438.html

https://blog.csdn.net/weixin_44790046/article/details/103016154

https://www.cnblogs.com/mingmingruyuedlut/archive/2011/01/21/1941225.html

https://www.cnblogs.com/langu/archive/2012/02/26/2368877.html

https://blog.csdn.net/u014453443/article/details/104501612

微软Visual Studio Installer Projects是一种用于创建Windows Installer(MSI)安装包的工具。要使用它,首先需要确保在安装Visual Studio时选择了安装项目工具。接下来,可以按照以下步骤使用它: 1. 打开Visual Studio,并创建一个新的安装项目。 2. 在“解决方案资源管理器”中,右键单击“解决方案”,然后选择“添加”->“新项目”。 3. 在“新建项目”对话框中,选择“其他项目类型”->“安装程序”->“Visual Studio Installer”。 4. 给项目起一个名称,然后单击“确定”。 5. 在“解决方案资源管理器”中,可以看到新创建的安装项目,包括“安装程序”和“文件夹”等文件。 6. 可以通过“文件夹”添加要在安装过程中使用的文件,比如可执行文件、文档等。 7. 双击“安装程序”,可以配置安装向导、文件、注册表、启动菜单等。 8. 在“属性”窗口中,可以设置安装程序的相关属性,如版本号、制造商等。 9. 对项目进行必要的调整和设置后,可以生成安装包。右键单击“安装程序”项目,然后选择“生成”来生成安装文件。 10. 生成完成后,在输出目录中就可以找到生成的安装文件,可以使用它来进行安装。 通过上述步骤,可以使用Microsoft Visual Studio Installer Projects创建并定制自己的安装程序。需要注意的是,Visual Studio Installer Projects虽然是一个方便的工具,但在定制复杂的安装程序时可能需要额外学习和尝试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值