目录
1、在PCTD解决方案中,创建新的Setup Wizard项目PCTD_Setup
2、查看PCTD_Setup项目的File System,添加文件
3、查看PCTD_Setup项目的File System,创建快捷方式
四、在PCTD_Setup项目中,添加ExtLib项目、自定义操作
一、创建C#主项目
在PCTD解决方案下,创建PCTD_CAD类库项目,便于后面在PCTD解决方案下创建其他项目。
PCTD_CAD文件夹是PCTD_CAD项目的,PCTD.sln文件是PCTD解决方案的。
添加AutoCAD相关的引用
配置PCTD项目的属性
二、创建Setup Wizard项目,用于打包主项目。
1、在PCTD解决方案中,创建新的Setup Wizard项目PCTD_Setup
2、查看PCTD_Setup项目的File System,添加文件
查看PCTD_Setup项目的File System,安装时,会将Application Folder中的指定文件,拷贝到目标机器的指定目录下。Application Folder中包含了“主输出 from PCTD_CAD(Active)”。
在“Application Folder”中添加文件:dll、ico文件。
3、查看PCTD_Setup项目的File System,创建快捷方式
点击Application Folder后,在右侧空白区域,点击鼠标右键,创建新的快捷方式。
修改快捷方式的Name、Icon属性。
将快捷方式直接拖拽到User`s Desktop,以同样的方式创建一个新的快捷方式,然后直接拖拽到User`s Program Menu。
4、修改属性
修改Application Folder、User`s Desktop、User`s Program Menu的属性AlwaysCreate为True。
修改PCTD Setup项目的属性TargetPlatform为x64。
PCTD_Setup文件夹下的文件结构。
三、创建C#项目,用于自定义安装行为
在ExtLib项目中,添加“安装程序类”
override OnAfterInstall(),可以在安装程序安装完成后,执行此函数中的代码;override OnAfterUninstall(),可以在卸载程序卸载完成后,执行此函数中的代码。
代码块中,增加Debugger.Launch()后,安装程序、卸载程序在目标机器执行到Debugger.Launch()时,会提示是否要进行调试。
代码块中,演示了通过RegistryKey.OpenBaseKey()、RegistryKey.OpenSubKey()获取,通过RegistryKey.CreateSubKey()、RegistryKey.SetValue()写入,通过RegistryKey.DeleteSubKey()、RegistryKey.DeleteValue()删除注册表中的项。
代码块中,演示了通过在注册表中增加"DESCRIPTION"、"LOADCTRLS"、"LOADER"、"MANAGED"这些值,在启动AutoCAD时自动加载指定dll。
代码块中,SearchNewestR()是为了对最新版的AutoCAD(当目标机器中安装了多个版本的AutoCAD时)设置启动时自动加载指定dll。
using Microsoft.Win32;
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace ExtLib
{
[RunInstaller(true)]
public partial class Installer : System.Configuration.Install.Installer
{
public Installer()
{
//Debugger.Launch();
InitializeComponent();
return;
}
protected override void OnAfterInstall(IDictionary savedState)
{
//Debugger.Launch();
string targetDir = this.Context.Parameters["targetDir"];
Logger(string.Format("targetDir: {0}", targetDir));
if (targetDir != null)
{
string targetDirSub = targetDir.Substring(0, targetDir.LastIndexOf("\\") - 1);
RegistryKey applicationsKey = OpenApplicationsKey();
if (applicationsKey != null)
{
RegistryKey pctdKey = applicationsKey.CreateSubKey("PCTD", true);
if (pctdKey != null)
{
pctdKey.SetValue("DESCRIPTION", "Auto load PCTD.dll", RegistryValueKind.String);
pctdKey.SetValue("LOADCTRLS", 2, RegistryValueKind.DWord);
pctdKey.SetValue("LOADER", string.Format("{0}\\PCTD.dll", targetDirSub), RegistryValueKind.String);
pctdKey.SetValue("MANAGED", 1, RegistryValueKind.DWord);
pctdKey.Close();
}
applicationsKey.Close();
}
}
base.OnAfterInstall(savedState);
return;
}
protected override void OnAfterUninstall(IDictionary savedState)
{
//Debugger.Launch();
string targetDir = this.Context.Parameters["targetDir"];
if (targetDir != null)
{
RegistryKey applicationsKey = OpenApplicationsKey();
if (applicationsKey != null)
{
RegistryKey pctdKey = applicationsKey.OpenSubKey("PCTD", true);
if (pctdKey != null)
{
object description = pctdKey.GetValue("DESCRIPTION");
object loadctrls = pctdKey.GetValue("LOADCTRLS");
object loader = pctdKey.GetValue("LOADER");
object managed = pctdKey.GetValue("MANAGED");
if (description != null)
{
pctdKey.DeleteValue("DESCRIPTION");
}
if (loadctrls != null)
{
pctdKey.DeleteValue("LOADCTRLS");
}
if (loader != null)
{
pctdKey.DeleteValue("LOADER");
}
if (managed != null)
{
pctdKey.DeleteValue("MANAGED");
}
pctdKey.Close();
try
{
applicationsKey.DeleteSubKey("PCTD");
}
catch (System.Exception ex)
{
Logger(string.Format("Delete PCTD subKey Error: {0}", ex));
}
}
applicationsKey.Close();
}
}
base.OnAfterUninstall(savedState);
return;
}
private RegistryKey OpenApplicationsKey()
{
RegistryKey localMachineKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
if (localMachineKey != null)
{
const string autoCADKeyPath = "SOFTWARE\\Autodesk\\AutoCAD";
RegistryKey autoCADKey = localMachineKey.OpenSubKey(autoCADKeyPath, true);
if (autoCADKey != null)
{
string[] autoCADSubKeyNames = autoCADKey.GetSubKeyNames();
string autoCADSubKeyNameNewest = SearchNewestR(autoCADSubKeyNames);
if (autoCADSubKeyNameNewest != "")
{
string rKeyPath = autoCADSubKeyNameNewest;
RegistryKey rKey = autoCADKey.OpenSubKey(rKeyPath, true);
if (rKey != null)
{
string[] rSubKeyNames = rKey.GetSubKeyNames();
foreach (string item2 in rSubKeyNames)
{
if (item2.Contains("ACAD") && item2.Contains(":"))
{
string acadKeyPath = item2;
RegistryKey acadKey = rKey.OpenSubKey(acadKeyPath, true);
if (acadKey != null)
{
string[] acadSubKeyNames = acadKey.GetSubKeyNames();
foreach (string item3 in acadSubKeyNames)
{
if (item3 == "Applications")
{
string applicationsKeyPath = item3;
RegistryKey applicationsKey = acadKey.OpenSubKey(applicationsKeyPath, true);
return applicationsKey;
}
}
}
}
}
}
}
}
}
return null;
}
private static string SearchNewestR(string[] rs)
{
string newestR = "";
double newestVerNum = double.MinValue;
foreach (string r in rs)
{
if (r.Contains("R"))
{
double curVerNum = double.NaN;
if (double.TryParse(r.Substring(r.IndexOf("R") + 1), out curVerNum) &&
(!double.IsNaN(curVerNum)) &&
(curVerNum > newestVerNum))
{
newestR = r;
newestVerNum = curVerNum;
}
}
}
return newestR;
}
}
}
PCTD解决方案的文件结构。
四、在PCTD_Setup项目中,添加ExtLib项目、自定义操作
在PCTD_Setup项目中添加项目主输出,选择C#类库项目ExtLib。
添加自定义操作Custom Action,关联已经导入到PCTD_Setup的Application Folder中的ExtLib项目主输出。
关联用户界面中的变量和实现类Installer.cs中的变量,即通过将CustomActionData设置为/targetDir="[TARGETDIR]\"从安装程序中获取安装目录,给this.Context.Parameters["targetDir"]
.net安装部署“Error 1001 在初始化安装时发生异常” 的解决方法_weixin_30496751的博客-CSDN博客
当安装程序安装时,会将PCTD_Setup的File System中指定的文件、主输出(的dll、exe),拷贝到安装目录。
卸载程序执行卸载时,会去安装目录执行ExtLib.dll,如果override OnAfterUninstall()有导致卸载程序崩溃的bug,可以直接将新生成的、修复bug后的ExtLib.dll拷贝到安装目录下,然后再次执行卸载程序即可。
启动AutoCAD时自动加载指定dll,是应该指定安装程序拷贝到安装目录的PCTD_CAD.dll。
五、参考
调试:
https://www.cnblogs.com/z119977662/archive/2010/08/12/1797976.html
https://bbs.csdn.net/topics/210030905
打包项目:
https://www.cnblogs.com/1175429393wljblog/p/13229438.html
https://www.cnblogs.com/lin3615/p/16480545.html
VS2019打包生成安装文件教程(详细实操版)_vs2019打包安装程序_芸轩的博客-CSDN博客