0

我有几个相关的 Windows 注册表项,我想将它们打包在 MSI 中,以便 1) 有一个卸载过程,以及 2) 这些注册表项已应用于给定计算机的事实由添加/删除程序条目记录.

问题是我可以让 Wix# 很好地做到这一点,但如果所有注册表项都在“Dir”块内,我只能让 MSI 构建,并且最终实际上创建了一个物理文件夹,我不这样做不想要,在目标系统上。

作为一种临时解决方法,我最终使用了 Dir 块,指定了一个虚拟的“Temp”文件夹。安装程序实际上确实创建了我不想要的文件夹;我想要的只是应用注册表项。

WiX 文档将其底层结构 TargetDir 描述为本质上告诉安装程序在目标系统上执行其操作。请参阅http://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/write_a_registry_entry.html

在本机 WiX XML 示例中,似乎不会在目标系统上创建无关文件夹;只会应用所需的注册表项。我可以使用什么 Wix# 语法结构来应用注册表项,同时避免在目标系统上创建实际文件夹?

到目前为止,我看到的所有 Wix# 示例似乎都具有在目标系统上创建实际文件夹的副作用,无论您是否需要。

我知道我可以通过获取注册表项的 .reg 文件,用热量将它们收集到 .wxs 文件,然后用蜡烛和光将其构建到 msi 来做到这一点。我真的很想将它保留在 C#/Wix# 世界中。在我的组织中,C# 是一项广为人知的技能;WiX 少一些。(承认 Wix# 是建立在 WiX 功能之上的,对 WiX 和 Windows Installer 有一定程度的理解是必不可少的;这是一个舒适区的事情,能够使用 C# 而不是 XML,而不是完全合乎逻辑的事情。)目前,我们手动执行了很多此类注册表设置任务,没有任何痕迹,也没有简单、可靠的卸载。

/// <summary>
/// Configure the Event Log on a Windows (server) to have MyApplication Log settings and record an entry for it in Programs and Features.
/// Note that this program creates the Windows Installer MSI that accomplishes this.  
/// This program creates a WiX XML file that is then compiled by the WiX Toolkit (Candle and Light) into the MSI file.
/// </summary>
internal class Script
{
    public static void Main()
    {
        // Define a new Installer Project object
        var project = new Project("SetupMyApplicationEventLog" ,
        // Provide dummy "Temp" install directory to satisfy WiX# Syntactical requirement. There are no actual files being installed.
        new Dir(@"Temp"),
            /*
                * Event Log Registration Entries, translated from .reg file
            */
            // First, add the root level key of the tree of keys

            //[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log]
            //"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
            new RegValue(
                RegistryHive.LocalMachine,
                @"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log",
                "",
                "") { AttributesDefinition = "Component:Win64=yes" },

            //[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\STV.DSD.HQSYS.SERVICE2]
            //"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
            new RegValue(
                RegistryHive.LocalMachine,
                @"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\" + "STV.DSD.HQSYS.SERVICE2",
                "EventMessageFile",
                "C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll") { AttributesDefinition = "Component:Win64=yes" },

            //[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\STV.VFS.ONLINE]
            //"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
            new RegValue(
                RegistryHive.LocalMachine,
                @"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\" + "STV.VFS.ONLINE",
                "EventMessageFile",
                "C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll") { AttributesDefinition = "Component:Win64=yes" } );

        // Set the properties of the setup project

        // Set UI to minimal; there are no choices to be made here.
        project.UI = WUI.WixUI_ProgressOnly;
        project.Manufacturer = "STV";
        project.OutFileName = "SetupMyApplicationEventLog";
        project.GUID = new Guid("037C625A-609C-4C2C-9689-62A075B88AD7");
        // Assign version # to setup MSI property of type System.Version 
        project.Version = new Version(4, 0, 0, 0);

        // Add the Win64 attribute to the package, to force a 64-bit MSI to be created
        project.Package.AttributesDefinition = "Platform=x64";

        // Trigger the MSI file build
        Compiler.BuildMsi(project);

        //// Also create the .wxs file so we can see what was sent to WiX to build the MSI
        Compiler.BuildWxs(project);

        Console.WriteLine("productVersion=" + project.Version);
        Console.ReadLine();
    }
}

}

4

2 回答 2

0

使用 Ryan J 提供的 Wix XML 代码,以及来自 Wix# 示例代码的示例“InjectXML”,我成功地生成了 wxs 文件并获得了一个工作 MSI,同时仍然保持在 Visual Studio 中的 Wix# 编码环境中。

这是之前在元素下生成的相关 .wxs XML:

<Directory Id="TARGETDIR" Name="SourceDir" >
  <Directory Id="INSTALLDIR" Name="%Temp%">
    <Component Id="INSTALLDIR.EmptyDirectory" Guid="037c625a-609c-4c2c-9689-62a075b88ae9">
      <CreateFolder />
    </Component>

所以需要做的是: 1) 删除 Product/Directory/Directory/Component 下的 "" 元素。Ryan J 的示例清楚地表明,它位于与要创建的第一个“目录”相关联的“组件”下,而后者又位于 Wix# 生成的 XML 中的“TARGETDIR”下。

2) 在元素产品/目录/目录/组件下插入元素语法“”。虽然我相信在此元素中引用 Id“INSTALLDIR.EmptyDirectory”也可能有效,但我使用了 Id“TARGETDIR”,它以我想要的方式工作。

这是由 Ryan J 提供的注入 XML 的生成的 Wix# 代码。

    internal class Script
    {
        public static void Main()
        {
            // Define a new Installer Project object
            var project = new Project("SetupMyApplicationEventLog" ,
            // Provide dummy "Temp" install directory to satisfy WiX# Syntactical requirement. There are no actual files being installed.
            new Dir(@"TempDeleteMe"),
...
            // Hook up a delegate to the "WixSourceGenerated" event, fires when .wxs file is fully created
            Compiler.WixSourceGenerated += InjectXMLElement;
            // Trigger the MSI file build
            Compiler.BuildMsi(project);
...

        /// Insert XML elements and attributes into the generated .wxs file
        static void InjectXMLElement(System.Xml.Linq.XDocument document)
        {
            // Remove the <CreateFolder /> tag from Directory element -- we don't want to create it
            var createFolderElement = document.Root.Select("Product/Directory/Directory/Component/CreateFolder");
            createFolderElement.Remove();
            // To cause the folder to not be created on the target system, add this element:
            // <RemoveFolder Id="RemoveTarget" Directory="TARGETDIR" On="both"/>
            var componentElement = document.Root.Select("Product/Directory/Directory/Component");
            
            componentElement.Add(new XElement("RemoveFolder",
                       new XAttribute("Id", "RemoveTarget"),
                       new XAttribute("Directory", "TARGETDIR"),
                       new XAttribute("On","both")));
        }

于 2014-10-28T03:47:30.200 回答
0

您可以通过将<RemoveFolder>标签添加到您不想保留的目录中的组件来实现您想要的。请参阅参考资料

生成的 MSI 将通过light警告LGHT1079您没有任何文件创建,但如果这是意图,则可以忽略。

显示目录的简单示例 XML 包含一个组件,该组件在安装/卸载时删除文件夹并创建注册表项,在卸载时强制删除。

<Directory Id="TARGETDIR" Name="SourceDir">
    <Component Id="ApplicationRegistry" Guid="YOUR-GUID-HERE">
         <RemoveFolder Id="RemoveTarget" Directory="TARGETDIR" On="both"/> 
         <RegistryKey Root="HKCU"
              Key="Software\Microsoft\[ProductName]"
              ForceDeleteOnUninstall="yes">
                <RegistryValue Type="integer" Name="SomeIntegerValue" Value="1" KeyPath="yes"/>
                <RegistryValue Type="string" Value="Default Value"/>
         </RegistryKey>
    </Component>
</Directory>

您只需将此名称用于您的目录,或者将 替换为您的Directory="TARGETDIR"目录名称。

安装后的结果是目标机器上没有文件夹的注册表项。 注册表项 小路

您必须弄清楚如何将该标记放入生成的 XML 中,但这就是您需要的效果。

于 2014-10-25T18:54:20.117 回答