首页 > 编程语言 >WPF打包独立运行的程序

WPF打包独立运行的程序

时间:2024-09-18 09:13:21浏览次数:6  
标签:string InstallEntity pbSchedule 程序 Visibility Value Text WPF 打包

方案一:使用Costura.Fody插件将自己写的程序打包成一个可以独立运行的EXE文件

第1步:安装Costura.Fody

首先用Visual Studio 2017打开你的解决方案,依次找到“工具”---“NuGet包管理” - “管理解决方案的NuGet程序包”,到了这一步会打开NuGet-解决方案页面,在浏览选项下面的搜索框内输入“ Costura.Fody ”,会自动搜索出Costura.Fody插件,鼠标左键单击一下Costura.Fody插件,在右边的位置会出现你的项目名称,选中你的项目名称,选择安装,到这一步Costura.Fody就成功按照到你的项目上了

第2步:编译一下你的解决方案

直接按照你平常的习惯启动一下你的项目,这个时候,Costura.Fody就会完成打包,打包好的EXE文件在你的解决方案Debug根目录下,你现在可以把这个exe文件复制到任意一台电脑上去试试,完美运行

解决办法:手动添加FodyWeavers.xml文件   这样添加:将鼠标移动到你的解决方案上面,单击右键,依次选择“添加” - “新建项目” - “ XML文件 ”,注意在新建XML文件时将文件命名为“ FodyWeavers. xml “,然后将下面这段代码复制到 FodyWeavers.xml文件里面
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<Costura />
</Weavers>

方案二:WPF制作自己的安装程序(可定制)

安装程序原理:

1、将编译好的文件打包成zip的压缩文件,

2、然后将zip以资源的方式内嵌到安装程序中

3、在安装的时候使用ICSharpCode.SharpZipLib.dll将zip文件解压到相应的目录中

4、建立相应的快捷方式,启动主程序程序

第1步:WPF中将引用的ICSharpCode.SharpZipLib.dll文件打包到exe中

在做一个打包程序中,需要引用到一个ICSharpCode.SharpZipLib.dll的第三方库,编译之后dll需要生成到目录里面exe才能使用,但是只想给用户发送一个纯exe的安装文件,不想有关联的引用,怎么办呢?

在程序入口添加程序集解析事件(wpf的App.xaml.cs文件)

查看代码
 protected override void OnStartup(StartupEventArgs e)
{
  base.OnStartup(e);
  //添加程序集解析事件
  AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;

}

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
  Assembly executingAssembly = Assembly.GetExecutingAssembly();
  var executingAssemblyName = executingAssembly.GetName();
  var resName = executingAssemblyName.Name + ".resources";

  AssemblyName assemblyName = new AssemblyName(args.Name); string path = "";
  if (resName == assemblyName.Name)
  {
    path = executingAssemblyName.Name + ".g.resources"; ;
  }
  else
  {
    path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo != null && assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
    {
      path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
    }
  }

  using (Stream stream = executingAssembly.GetManifestResourceStream(path))
  {
    if (stream == null)
      return null;

    byte[] assemblyRawBytes = new byte[stream.Length];
    stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
    return Assembly.Load(assemblyRawBytes);
  }
}

更改.csproj的项目文件

在Import节点后面添加如下代码

<Target Name="AfterResolveReferences">
<ItemGroup>
<EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
<LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>

原理:就是将dll文件以资源的方式嵌入包含到项目中,编译后目录里面仍然会编译出dll,我们将dll删除,发现程序仍然能运行,这是因为我们在入口注册了程序集解析事件

当程序集解析引用异常或有相关错误时,会进入事件,在事件中我们将嵌入的dll文件以流的方式映射加载,就相当于重新加载了删除的dll文件

第2步:解压核心代码

查看代码
 /// <summary>
    /// ZIP助手类
    /// </summary>
    public static class ZIPHelper
    {
        public static Action<double, double, string> ActionProgress;
        /// <summary>
        /// 解压缩zip文件
        /// </summary>
        /// <param name="zipFile">解压的zip文件流</param>
        /// <param name="extractPath">解压到的文件夹路径</param>
        /// <param name="bufferSize">读取文件的缓冲区大小</param>
        public static void Extract(byte[] zipFile, string extractPath, int bufferSize)
        {
            extractPath = extractPath.TrimEnd('/') + "//";
            byte[] data = new byte[bufferSize];
            int size;//缓冲区的大小(字节)
            double max = 0;//带待压文件的大小(字节)
            double osize = 0;//每次解压读取数据的大小(字节)
            using (ZipInputStream s = new ZipInputStream(new System.IO.MemoryStream(zipFile)))
            {
                ZipEntry entry;
                while ((entry = s.GetNextEntry()) != null)
                {
                    max += entry.Size;//获得待解压文件的大小
                }
            }
            using (ZipInputStream s = new ZipInputStream(new System.IO.MemoryStream(zipFile)))
            {
                ZipEntry entry;

                while ((entry = s.GetNextEntry()) != null)
                {
                    string directoryName = Path.GetDirectoryName(entry.Name);
                    string fileName = Path.GetFileName(entry.Name);

                    //先创建目录
                    if (directoryName.Length > 0)
                    {
                        Directory.CreateDirectory(extractPath + directoryName);
                    }
                    if (fileName != String.Empty)
                    {
                        using (FileStream streamWriter = File.Create(extractPath + entry.Name.Replace("/", "//")))
                        {
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    osize += size;
                                    System.Windows.Forms.Application.DoEvents();
                                    streamWriter.Write(data, 0, size);
                                    string text = Math.Round((osize / max * 100), 0).ToString() + "%";
                                    ActionProgress?.Invoke(max + 5, osize, text);

                                    System.Windows.Forms.Application.DoEvents();
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

创建快捷方式

查看代码
 /// <summary>
        /// 执行软件安装
        /// </summary>
        private void Setup()
        {
            try
            {
                IsFinished = false;
                //获取用户选择路径中的最底层文件夹名称
                string fileName = this.txtInstallationPath.Text.Split('\\')[this.txtInstallationPath.Text.Split('\\').Count() - 1];

                //当用户选择的安装路径中最底层的文件夹名称不是“XthkDecryptionTool”时,自动在创建一个“XthkDecryptionTool”文件夹,防止在删除的时候误删别的文件
                if (!fileName.Equals(InstallEntity.InstallFolderName))
                {
                    this.txtInstallationPath.Text = this.txtInstallationPath.Text + @"\" + InstallEntity.InstallFolderName;
                }
                //安装路径
                InstallPath = this.txtInstallationPath.Text;

                //显示安装进度界面
                //this.tcMain.SelectedIndex = 1;
                this.grid_one.Visibility = Visibility.Collapsed;
                this.grid_two.Visibility = Visibility.Visible;
                this.grid_three.Visibility = Visibility.Collapsed;

                //检测是否已经打开
                Process[] procCoursewareDecryptionTool = Process.GetProcessesByName(InstallEntity.AppProcessName);
                if (procCoursewareDecryptionTool.Any())
                {
                    if (MessageBox.Show("“" + InstallEntity.DisplayName + "”正在运行中,是否强制覆盖程序?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
                    {
                        Common.IsAppKill(InstallEntity.AppProcessName);
                    }
                    else
                    {
                        Application.Current.Shutdown();

                    }
                }

                //创建用户指定的安装目录文件夹
                Directory.CreateDirectory(InstallPath);
                ZIPHelper.ActionProgress -= ActionProgressResult;
                ZIPHelper.ActionProgress += ActionProgressResult;

                this.pbSchedule.Value = 0;
                this.txtSchedule.Text = "0%";

                //将软件解压到用户指定目录
                ZIPHelper.Extract(Install.SetupFiles.Setup, InstallPath, 1024 * 1204);
                //将嵌入的资源释放到用户选择的安装目录下面(卸载程序)
                string uninstallPath = this.txtInstallationPath.Text + @"\" + InstallEntity.UninstallName;
                FileStream fsUninstall = System.IO.File.Open(uninstallPath, FileMode.Create);
                fsUninstall.Write(Install.SetupFiles.Uninstall, 0, Install.SetupFiles.Uninstall.Length);
                fsUninstall.Close();

                //将嵌入的资源释放到用户选择的安装目录下面(快捷图标)
                string InstallIcoPath = this.txtInstallationPath.Text + InstallEntity.IconDirectoryPath;
                FileStream fsInstallIcoPath = System.IO.File.Open(InstallIcoPath, FileMode.Create);
                var InstallIco = Install.SetupFiles.IcoInstall;
                byte[] byInstall = Common.ImageToByteArray(InstallIco);
                fsInstallIcoPath.Write(byInstall, 0, byInstall.Length);
                fsInstallIcoPath.Close();

                //将嵌入的资源释放到用户选择的安装目录下面(快捷卸载图标)
                string UninstallIcoPath = this.txtInstallationPath.Text + InstallEntity.UninstallIconDirectoryPath;
                FileStream fsUninStallIco = System.IO.File.Open(UninstallIcoPath, FileMode.Create);
                var UnInstallIco = Install.SetupFiles.IcoUninstall;
                byte[] byUnInstall = Common.ImageToByteArray(UnInstallIco);
                fsUninStallIco.Write(byUnInstall, 0, byUnInstall.Length);
                fsUninStallIco.Close();

                //释放卸载程序完成,更新进度条
                this.pbSchedule.Value = this.pbSchedule.Value + 1;
                this.txtSchedule.Text = Math.Round((this.pbSchedule.Value / this.pbSchedule.Maximum * 100), 0).ToString() + "%";


                //添加开始菜单快捷方式
                RegistryKey HKEY_CURRENT_USER = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
                string programsPath = HKEY_CURRENT_USER.GetValue("Programs").ToString();//获取开始菜单程序文件夹路径
                Directory.CreateDirectory(programsPath + InstallEntity.MenuFolder);//在程序文件夹中创建快捷方式的文件夹

                //更新进度条
                this.pbSchedule.Value = this.pbSchedule.Value + 1;
                this.txtSchedule.Text = Math.Round((this.pbSchedule.Value / this.pbSchedule.Maximum * 100), 0).ToString() + "%";

                //快捷方式名称";
                string IconPath = InstallPath + InstallEntity.IconDirectoryPath;
                string UninstallIconPath = InstallPath + InstallEntity.UninstallIconDirectoryPath;
                string InstallExePath = InstallPath + @"\" + InstallEntity.AppExeName;
                string ExeUnInstallPath = InstallPath + @"\" + InstallEntity.UninstallName;

                //开始菜单打开快捷方式
                shortName = programsPath + InstallEntity.MenuFolder + InstallEntity.ShortcutName;
                Common.CreateShortcut(shortName, InstallExePath, IconPath);//创建快捷方式


                //更新进度条
                this.pbSchedule.Value = this.pbSchedule.Value + 1;
                this.txtSchedule.Text = Math.Round((this.pbSchedule.Value / this.pbSchedule.Maximum * 100), 0).ToString() + "%";
                //开始菜单卸载快捷方式
                Common.CreateShortcut(programsPath + InstallEntity.MenuFolder + InstallEntity.UninstallShortcutName, ExeUnInstallPath, UninstallIconPath);//创建卸载快捷方式

                //更新进度条
                this.pbSchedule.Value = this.pbSchedule.Value + 1;
                this.txtSchedule.Text = Math.Round((this.pbSchedule.Value / this.pbSchedule.Maximum * 100), 0).ToString() + "%";

                //添加桌面快捷方式
                string desktopPath = HKEY_CURRENT_USER.GetValue("Desktop").ToString();//获取桌面文件夹路径
                shortName = desktopPath + @"\" + InstallEntity.ShortcutName;
                Common.CreateShortcut(shortName, InstallExePath, IconPath);//创建快捷方式

                //常见控制面板“程序与功能”
                //可以往root里面写,root需要管理员权限,如果使用了管理员权限,主程序也会以管理员打开,如需常规打开,需要在打开进程的时候做降权处理
                RegistryKey CUKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
                var currentVersion = CUKey.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
                Dictionary<string, string> dic = new Dictionary<string, string>();
                dic.Add("DisplayIcon", InstallExePath);//显示的图标的exe
                dic.Add("DisplayName", InstallEntity.DisplayName);//名称
                dic.Add("Publisher", InstallEntity.Publisher);//发布者
                dic.Add("UninstallString", ExeUnInstallPath);//卸载的exe路径
                dic.Add("DisplayVersion", InstallEntity.VersionNumber);
                RegistryKey CurrentKey = CUKey.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\" + InstallEntity.DisplayName, true);
                if (CurrentKey == null)
                {
                    //说明这个路径不存在,需要创建
                    CUKey.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\" + InstallEntity.DisplayName);
                    CurrentKey = CUKey.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\" + InstallEntity.DisplayName, true);
                }
                foreach (var item in dic)
                {
                    CurrentKey.SetValue(item.Key, item.Value);
                }
                CurrentKey.Close();


                //更新进度条
                this.pbSchedule.Value = this.pbSchedule.Value + 1;
                this.txtSchedule.Text = Math.Round((this.pbSchedule.Value / this.pbSchedule.Maximum * 100), 0).ToString() + "%";

                //安装完毕,显示结束界面
                this.grid_one.Visibility = Visibility.Collapsed;
                this.grid_two.Visibility = Visibility.Collapsed;
                this.grid_three.Visibility = Visibility.Visible;

                IsFinished = true;
            }
            catch (Exception)
            {
                //安装完毕,显示结束界面
                this.grid_one.Visibility = Visibility.Visible;
                this.grid_two.Visibility = Visibility.Collapsed;
                this.grid_three.Visibility = Visibility.Collapsed;
                throw;
            }
        }

标签:string,InstallEntity,pbSchedule,程序,Visibility,Value,Text,WPF,打包
From: https://www.cnblogs.com/guangzhiruijie/p/18417918

相关文章

  • Java基于微信小程序的个人财务理财系统App+Vue[毕业设计]
    文末获取资源,收藏关注不迷路文章目录项目介绍技术介绍项目界面关键代码目录项目介绍时代在飞速进步,每个行业都在努力发展现在先进技术,通过这些先进的技术来提高自己的水平和优势,个人财务系统APP当然不能排除在外。个人财务系统APP是在实际应用和软件工程的开发原......
  • 用C++编写一个桌面日历程序
    前言在这篇博文中,我们将一起编写一个简单的桌面日历程序。我们的目标是创建一个可以显示当月日历的应用程序,并允许用户进行简单的导航,如查看上个月和下个月。这个程序将使用C++和一些基础的图形用户界面(GUI)库。工具和库为了实现这个任务,我们将使用以下工具和库:C++编译器:例如,GCC或者......
  • 人工智能时代,程序员如何保持核心竞争力?
    随着AIGC(如chatgpt、midjourney、claude等)大语言模型接二连三的涌现,AI辅助编程工具日益普及,程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工作,也有人认为AI是提高效率的得力助手。面对这一趋势,程序员应该如何应对?是专注于某个领域深耕细作,还是广泛学习以适......
  • 基于django+vue高校学科竞赛管理系统安全开发【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高校教育改革的深入和对学生综合素质要求的不断提高,学科竞赛作为培养学生创新能力、实践能力及团队协作精神的重要平台,其重要性日益凸......
  • 基于django+vue高校信息化迎新系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,高校教育管理正逐步向数字化、智能化转型。传统的迎新工作,涉及学生信息的录入、宿舍分配、学费缴纳、助学贷款申请......
  • 基于django+vue高校校医系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的普及与校园规模的不断扩大,高校师生的健康管理与医疗服务需求日益凸显。传统的高校校医系统往往面临信息孤岛、服务效率低下......
  • 基于django+vue高校宿舍信息管理系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的普及和高校规模的不断扩大,学生宿舍作为校园生活的重要组成部分,其管理面临着前所未有的挑战。传统的手工管理模式已难以适应......
  • 全网最简单最详细的反编译小程序教程
    一、准备工具小程序解密包(百度网盘)下载链接node.js提前下载,我上一个文章有教程二、获取wxapkg包在电脑在登录微信,找到存放小程序文件源代码的位置打开文件夹后一定要返回上一个文件打开Applet,删除所有的wx+数字的文件,确保等下找到最新运行的小程序文件,文件夹不用退出......
  • 我使用本地windows11上的VSCode远程连接到ubuntu进行RUST程序开发,我在VSCode上安装了
    当你使用VSCode的Remote-SSH扩展从本地Windows11连接到远程的Ubuntu服务器进行开发时,插件的安装有以下行为:插件的安装位置本地插件:某些插件,例如VSCode的界面插件或与本地编辑器相关的插件,安装在你的本地Windows系统上。这些插件不需要与远程服务器交互,因此它们仅......
  • 基于uniapp小程序的自助点餐系统附带文章源码部署视频讲解等
    文章目录前言详细视频演示具体实现截图核心技术介绍小程序框架Uniapp前端框架Vue持久层框架MyBaits为什么选择我代码参考数据库参考测试用例参考源码获取前言......