winform程序打包发布

365足球外围网站 2026-06-29 06:36:38 admin 阅读 387
winform程序打包发布

记录一下讲winform程序打包发布的经历吧,过程中也是遇到不少问题,不过关关难过慢慢过呗,最后能顺利做完也不错。

主要遇到的问题有如下几点:

1.安装包生成过程中报错,虽然教程上步骤很清晰,但自己操作的过程中还是会遇到各种各样的问题,所以接收的知识还是最好实践一下,得到的经验才是自己的。

2.修改目标机器的注册表,将安装程序的路径写入注册表中。

3.目标机器不带C++ runtime。

4.目标机器如果是win7,不支持TLS1.2及以上版本的协议。

--打包工具:通过NuGet安装,下载完毕后要关闭VS。

2.打包过程

--首先建立setup的工程,建好工程后右键->view->文件系统

--Application Folder就是安装程序在目标机器的文件夹下写入的文件内容。

--User's Desktop就是目标机器的桌面文件夹,这里主要会放一个应用程序的快捷方式。

-- Application Folder右键添加文件,把需要的文件放进来(不过我是直接拷贝了在它上右键粘贴的,通过添加文件总是缺几个,还得去找了一个个添加),主要保证项目主输出(一般发布都是release下)的文件是全的,然后加进来,最好提前把测试生成的日志等没必要的文件清理删除。

--Application Folder右键项目输出,把启动项设置为主输出,会在文件系统中多出一个主输出项。

--在上述的主输出项上右键,创建快捷方式(Create short cut),将创建的快捷方式项拉到User's Desktop文件夹,这样就会在目标机器桌面生成快捷方式。重命名成自己定义的名称,icon选择一个心仪的将来应用程序和快捷方式的桌面图标。

--从C盘的windows/system32文件夹下,找到msiexe.exe加入到Application Folder文件夹,并为它创建Short cut(主要用于卸载该程序),为卸载的应用程序命名(此处命名为Uninstaller.exe)

--点击setup工程,在它的属性中找到 ProductCode,拷贝出来,放到Uninstaller属性Arguments下 ,格式为/x {ProductCode},这样卸载程序就配置好了。

--为了执行一些安装过程中的步骤,比如修改目标机器注册表等,创建了一个CustomActions的项目,现在将该项目也在setup项目右键->add->项目输出中添加进来,此时会在Application Folder中多一个主输出项。

--setup项目右键->view->自定义操作打开,在installer(安装)右键->自定义操作将上述的主输出CustomActions加进来。将它的属性项CustomActionData 中输入一些自定义的参数,此处为/TargetDir="[TARGETDIR]\",这样在CustomeActions项目中通过

Context.Parameters["TargetDir"]即可获取用户安装项目的路径。

--setup项目右键->view也可以看到注册表和启动条件,但是不一定能满足项目要求,所以可以自定义一些操作。

--setup项目右键属性->Prerequisites,点击打开,检测一下安装必备组件是否勾选上,此处为Microsoft .net framework 4.7.2(x64) ,因为打包的项目是这个框架。

--最后检查seup项目->属性中的TargetPlatform项,和自己的发布程序还有目标机器一致(很重要,很多安装包生成过程中的错误就是因为这个),此处目标平台是x64机器,发布程序编译也是release x64。

--setup项目,右键重新生成。成功生成后在setup项目的生成路径中找到安装程序的msi和exe。

--自行安装测试。

--CustomActions代码如下,主要是安装时将安装信息写入注册表,卸载时清理注册表。然后测试阶段因为是动态编译,会检测一下目标机器是否有C++ runtime,没有会通知让用户点击确认自动安装一个。静态编译的话,应该就不用了。

public partial class InstallerActions : System.Configuration.Install.Installer

{

public InstallerActions()

{

//InitializeComponent();

this.AfterInstall += new InstallEventHandler(InstallerDemo_AfterInstall);

this.AfterUninstall += new InstallEventHandler(InstallerDemo_AfterUnInstall);

}

public void InstallerDemo_AfterInstall(object sender, InstallEventArgs e)

{

//修改注册表

try

{

// 获取安装路径

string installPath = Context.Parameters["TargetDir"];

string exeName = "ScannerClient.exe";

string fullPath = System.IO.Path.Combine(installPath, exeName);

// 写入注册表ClassRoot

using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(@"GctAnalyseScanClient"))

{

key.SetValue("", fullPath);

key.SetValue("URL Protocol", "");

RegistryKey defaulticon = key.CreateSubKey("DefaultIcon");

defaulticon.SetValue("", $"{fullPath},1");

RegistryKey shell = key.CreateSubKey("shell");

RegistryKey open = shell.CreateSubKey("open");

RegistryKey command = open.CreateSubKey("command");

command.SetValue("", $"\"{fullPath}\" \"%1\"");

}

// 写入注册表bendiji

using (RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE"))

{

RegistryKey Wow6432Node = key.CreateSubKey("Wow6432Node");

RegistryKey Microsoft = Wow6432Node.CreateSubKey("Microsoft");

RegistryKey Windows = Microsoft.CreateSubKey("Windows");

RegistryKey CurrentVersion = Windows.CreateSubKey("CurrentVersion");

RegistryKey InternetSettings = CurrentVersion.CreateSubKey("Internet Settings");

RegistryKey WinHttp = InternetSettings.CreateSubKey("WinHttp");

WinHttp.SetValue("URL DefaultSecureProtocols", 0x00000800, RegistryValueKind.DWord);

}

}

catch (Exception ex)

{

// 捕获并处理异常

Console.WriteLine($"发生错误:{ex.Message}");

}

//

OnInstallComplete();

}

private void InstallerDemo_AfterUnInstall(object sender, InstallEventArgs e)

{

//清理注册表

try

{

using (RegistryKey rootKey = Registry.ClassesRoot)

{

if (rootKey.OpenSubKey("GctAnalyseScanClient") != null)

{

// 删除GctAnalyseScanClient键及其所有子项

rootKey.DeleteSubKeyTree("GctAnalyseScanClient");

Console.WriteLine("GctAnalyseScanClient键及其所有子项已被成功删除。");

}

else

{

Console.WriteLine("GctAnalyseScanClient键不存在。");

}

}

}

catch (Exception ex)

{

// 捕获并处理异常

Console.WriteLine($"发生错误:{ex.Message}");

}

}

private void OnInstallComplete()

{

bool install = IsVCRedist2015_2022Installed();

if (install)

{

string installPath = Context.Parameters["TargetDir"];

string exeName = "C++Runtime\\VC_redist.x64.exe";

string fullPath = System.IO.Path.Combine(installPath, exeName);

MsgBoxResult result = Interaction.MsgBox("Visual C++ 2015-2022运行时未安装,是否现在安装?", MsgBoxStyle.Question | MsgBoxStyle.YesNo, "安装Visual C++运行时");

if (result == MsgBoxResult.Yes)

{

InstallVCRedist(fullPath);

}

}

}

public static bool IsVCRedist2015_2022Installed()

{

string[] registryPaths = new string[]

{

@"SOFTWARE\Microsoft\VisualStudio\14.0\VC",

@"SOFTWARE\Microsoft\VisualStudio\15.0\VC ",

@"SOFTWARE\Microsoft\VisualStudio\16.0\VC",

@"SOFTWARE\Microsoft\VisualStudio\17.0\VC"

};

foreach (string path in registryPaths)

{

using (RegistryKey baseKey = Registry.LocalMachine)

{

using (RegistryKey key = baseKey.OpenSubKey(path))

{

if (key != null)

{

return true;

}

}

}

}

return false;

}

public static void InstallVCRedist(string installerPath)

{

try

{

// 创建一个ProcessStartInfo对象

ProcessStartInfo startInfo = new ProcessStartInfo

{

FileName = installerPath,

Arguments = "/install /quiet /norestart", // 安装参数,静默安装

UseShellExecute = false,

RedirectStandardOutput = true,

RedirectStandardError = true,

CreateNoWindow = true

};

// 启动安装程序

using (Process process = Process.Start(startInfo))

{

process.WaitForExit(); // 等待安装完成

int exitCode = process.ExitCode;

if (exitCode == 0)

{

Console.WriteLine("Visual C++ 2015-2022运行时安装成功。");

}

else

{

Console.WriteLine($"Visual C++ 2015-2022运行时安装失败,退出代码:{exitCode}");

}

}

}

catch (Exception ex)

{

Console.WriteLine($"发生错误:{ex.Message}");

}

}

}

--最后说一下目标机器如果是win7,不支持TLS1.2及以上版本的协议的问题,本来通过代码尝试让目标机器兼容TLS1.0,1.1,1.2的协议,测试发现没什么变化,可能.net通过代码没法实现。最后就是尝试在目标的win7系统上安装微软发布的补丁包,让它能够支持TLS1.2协议,这样就可以通过http请求去访问服务器上的一些资源。

相关文章

《明日之后》时装系统全解析:获取、分解、返场及优化详情
lol幸运召唤师多长时间一次(如何获得lol幸运召唤师资格?)
信标 (Beacon) - [MC]我的世界原版 (Minecraft) - MC百科