我正在制作一个Visual Studio安装项目,该项目为目标计算机上的现有程序安装插件。我的文件需要进入该应用程序的安装目录。我希望能够干净地安装和卸载我的插件,而不会过多地影响应用程序本身。
现有程序的安装路径可以在注册表项中找到,并且可能因各个安装而异。
我可以配置Visual Studio安装项目以从该注册表项中读取值,然后将插件文件放入注册表指定的目录(或其子目录)中吗?我是否需要使用自定义操作,还是可以使用标准的安装项目功能来实现?
我注意到在启动条件窗口中,我可以设置注册表搜索启动条件,该条件根据特定的注册表项设置安装程序属性。我可以使用它来检索要在“文件”窗口中使用的密钥的实际值,还是仅为启动条件设置真值/假值?
答案 0 :(得分:1)
啊,毕竟在MSDN documentation找到了答案。没有自定义操作就可以!
要点:
详细信息:生成的MSI文件中的RegLocator表包含注册表搜索的数据。 Type字段包含msidbLocatorType64bit值,该值使搜索成为64位本机注册表。添加此值以更正问题。手动(使用Orca)是一种快速测试功能的方法。 RegLocator table
我获得有效安装程序的最终解决方案是使用WiX创建基本安装程序,并完全放弃Visual Studio安装项目。
然而,在完全切换到WiX之前,我创建了一个小型C#控制台应用程序,可以将其作为构建后事件调用,以编辑Visual Studio安装项目生成的MSI文件。控制台应用程序基于WiX Toolset附带的部署工具基础(DTF)。 DTF提供了一个用于编辑MSI文件的C#API。这是它的核心,可能对未来的用户有用。
using System;
using System.IO;
using Microsoft.Deployment.WindowsInstaller;
/// <summary>
/// This program patches the registry search key action in the MSI file produced by the Visual Studio Setup project,
/// to correct x64 compatibility bugs in Visual Studio Setup Projects.
/// </summary>
/// <remarks>
/// The two bugs are:
/// 1) The Visual Studio setup project incorporates the 32-bit version of InstallUtilLib.dll, which can't load x64 assemblies for reflection
/// See https://blogs.msdn.microsoft.com/heaths/2006/02/01/64-bit-managed-custom-actions-with-visual-studio/
/// 2) Registry search actions don't set the x64 bit and therefore only search the 32-bit registry
/// See https://social.msdn.microsoft.com/Forums/windows/en-US/40a2c1ee-7dd4-4289-a7d2-30b97239ae25/vs2005-setup-project-launch-conditions-registry-problem-on-x64-operating-systems
/// </remarks>
class SetupPatcher
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("ERROR: Specify the name of the MSI file as the first parameter when calling this exe");
Environment.Exit(1);
}
String msiName = args[0];
using (var db = new Database(msiName, DatabaseOpenMode.Direct))
{
PatchInstallUtilLib(db);
PatchRegLocator(db);
}
}
/// <summary>
/// Replace 32 bit InstallUtilLib.dll with x64 version
/// </summary>
/// <param name="db"></param>
private static void PatchInstallUtilLib(Database db)
{
using (View view = db.OpenView(@"UPDATE `Binary` SET `Data` = ? WHERE `Name` = 'InstallUtil'"))
{
using (Record rec = new Record(1))
{
String path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
@"Microsoft.NET\Framework64\v4.0.30319\InstallUtilLib.dll");
rec.SetStream(1, path);
view.Execute(rec);
db.Commit();
}
}
}
private static void PatchRegLocator(Database db)
{
// MSI SQL syntax documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa372021.aspx
// Schema of RegLocator table given at https://msdn.microsoft.com/EN-US/library/aa371171.aspx
// Look for reg search actions of the Raw type in the HKLM registry root
String registryKey = @"SOFTWARE\VendorName\ProductName";
using (View view =
db.OpenView(
@"UPDATE `RegLocator` SET `Type` = ? WHERE `Type` = {0} AND `Root` = {1} AND `Key` = '{2}'",
(Int32) LocatorTypes.RawValue, (Int32) RegistryRoot.LocalMachine, registryKey))
{
using (Record rec = new Record(1))
{
rec.SetInteger(1, (Int32) (LocatorTypes.SixtyFourBit | LocatorTypes.RawValue));
view.Execute(rec);
db.Commit();
}
}
}
}