visual-studio-2015 - 使用 Visual Studio 安装项目将文件安装到现有程序的安装路径

标签 visual-studio-2015 visual-studio-setup-proje

我正在创建一个 Visual Studio 安装项目,该项目为目标计算机上的现有程序安装插件。我的文件需要进入该应用程序的安装目录。我希望能够干净地安装和卸载我的插件,而不会对应用程序本身产生不必要的影响。

现有程序的安装路径可以在注册表项中找到,并且在各个安装之间可能会有所不同。

我可以将 Visual Studio 安装项目配置为从该注册表项读取值,然后将插件文件放入注册表指定的目录(或其子目录)吗?我是否需要使用自定义操作,或者可以使用标准安装项目功能来实现吗?

我注意到,在“启动条件”窗口中,我可以设置注册表搜索启动条件,该条件根据特定注册表项设置安装程序属性。我可以使用它来检索在"file"窗口中使用的 key 的实际值,还是仅出于启动条件的目的设置真/假值?

最佳答案

啊,在MSDN documentation中找到了答案毕竟。无需自定义操作即可实现!

摘要:

  1. 在“启动条件”窗口的“搜索目标计算机”节点下,添加注册表搜索操作。配置“RegKey”和“Value”属性以指定包含插件需要安装到的安装路径的注册表项值的名称。将注册表搜索操作的“属性”属性设置为一个合理的名称,例如“产品安装路径”
  2. (可选)在启动条件节点下,添加启动条件并将其 Condition 属性设置为 [ProductInstallPath]。我认为这将在安装程序运行时检查注册表项值是否存在且不为空。
  3. 在安装项目的“文件系统”窗口中,右键单击“目标计算机上的文件系统”,然后选择“添加特殊文件夹”、“自定义文件夹”
  4. 将新文件夹的“默认位置”属性设置为 [ProductInstallPath]

编辑:叹息。这在 x64 上不起作用,因为 Visual Studio 安装项目中存在错误,该错误至少自 VS2008 以来一直存在,并且在 VS2015 中仍然存在。即使安装项目平台设置为 x64,注册表搜索操作始终搜索 x86 注册表配置单元,并且看不到 x64 HKLM\SOFTWARE 键值。

详细信息:生成的 MSI 文件中的 RegLocator 表包含注册表搜索的数据。 Type 字段包含 msidbLocatorType64bit 值,该值导致搜索为 64 位 native 注册表。添加此值以纠正该问题。手动(使用 Orca)是测试功能的快速方法。 RegLocator table

Bug Citation 1

Bug Citation 2

我获得有效安装程序的最终解决方案是使用 WiX 创建基本安装程序,并完全放弃 Visual Studio 安装项目。

但是,在完全切换到 WiX 之前,我创建了一个小型 C# 控制台应用程序,可以将其作为构建后事件调用,以编辑 Visual Studio 安装项目生成的 MSI 文件。控制台应用程序基于部署工具基础 (DTF),它包含在 WiX Toolset 中。 。 DTF 提供用于编辑 MSI 文件的 C# API。这是它的主要内容,可能对 future 的用户有用。

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();
            }
        }
    }
}

关于visual-studio-2015 - 使用 Visual Studio 安装项目将文件安装到现有程序的安装路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48273612/

相关文章:

android - visual studio 2015 中的 cordova 构建错误

visual-studio-2015 - Visual Studio 2015 无法与 Apache Cordova 工具一起使用

debugging - TypeScript 和 Visual Studio 2015 断点 - 没有为该文档加载任何符号

c# - Visual Studio 2017 安装项目错误 2727

windows-installer - 使用Visual Studio安装程序项目设置InstallPath注册表项

visual-studio - 使用 Visual Studio 创建 MSI 并强制所有用户

sqlite - 如何使用 ClickOnce 发布带有 SQLite 的 Winforms 应用程序

C++ 不包括来自先前 header 的包含

windows-installer - 尽管产品代码不同,MSIEXEC 仍无法安装产品 "a newer version of this product is already installed"

deployment - 如何使用Visual Studio 2008创建静默安装程序包