2

我一直在努力使用 WIX 安装 CAB 帮助文件(从 MSHC 生成)。我尝试遵循的基本配方是这里的:Installing Help with Help Library Manager and WiX

在我的特殊情况下,我并没有真正为配方而苦苦挣扎,而是在 x64/x86 目标上苦苦挣扎。我已经阅读了来自WiX 技巧和提示的 WIX 提示,它们描述了如何制作 2 个安装程序,每个目标一个。然而,由于我更喜欢​​只有一个安装程序而不是 2 个,所以我选择只实现一个 x86 目标。

当我使用 x64 平台安装时,一切正常。当我尝试为 x86 做同样的事情时,它抱怨它找不到HelpLibManager.exe. 仔细观察,这似乎是合理的,因为它安装在 64 位C:\Program Files\Microsoft Help Viewer\v1.0\HelpLibManager.exe,而 WIX 使用 x86 文件夹C:\Program Files (x86)\Microsoft Help Viewer\v1.0\HelpLibManager.exe

为了解决这个问题,我尝试从包含安装 HelpLibManager 的注册表中读取正确的路径:

<Property Id="HELPLIB">
  <RegistrySearch Id="HelpLib"
                  Root="HKLM"
                  Key="Software\Microsoft\Help\v1.0"
                  Name="AppRoot"
                  Type="raw" />
</Property>

<SetProperty Id="HELPLIBMANAGER"
         Value="[HELPLIB]HelpLibManager.exe"
         After="InstallInitialize"
         Sequence="execute"/>

当您查看注册表时,(Wow6432Node当然是在),它告诉我这个键的值是:c:\Program Files\Microsoft Help Viewer\v1.0\- 这是正确的。但是,当我查看 MSI 的日志时,它显示为"C:\Program Files (x86)\Microsoft Help Viewer\v1.0\HelpLibManager.exe",这是不正确的:

Property(S): HELPLIB = C:\Program Files (x86)\Microsoft Help Viewer\v1.0\

显然,Wix 更改了我从注册表中读取的字符串值。

谁能向我解释解决这个问题的正确方法是什么?

4

2 回答 2

2

重定向到 (x86) 文件夹是由 Windows Installer 自动完成的,而不是由 WiX 完成的。如果您也使用其他设置创作工具创建包,也会发生同样的情况。

不幸的是,32 位安装程序无法写入 x64 机器上的“Program Files”文件夹。在安装过程中,来自操作系统的 WOW 重定向控制了这一点。

要直接在 HKLM\Software 下而不是在 HKLM\Software\Wow6432Node 下创建注册表项,您只需将其组件标记为 64 位即可。不幸的是,这对文件不起作用,即即使文件的组件被标记为 64 位,操作系统仍将重定向 Program Files (x86) 下的所有文件和文件夹。

编辑:

我最惊讶的是从注册表中读取的字符串值正在被更改(请参阅转储的属性值)

我知道,当我第一次发生这种情况时,我也很惊讶。

要从该文件夹启动文件,您仍然有机会使用一个小技巧,如果您编写一个小的自定义操作 C#,并将 DLL 作为输出。您可以在自定义操作中获取搜索的值,对其进行解析,如果存在,手动删除“(x86)”部分。然后暂时禁用 WOW 重定向,启动文件,然后重新启用 WOW 重定向。

不要忘记在自定义操作上设置条件,仅设置 VersionNT64 属性,并且仅在安装时运行。

于 2013-02-21T10:09:08.690 回答
0

我想用一个例子来完成 Bogdan Mitrache 的回答。为此,我使用 C# 自定义操作来访问注册表并控制 WOW 行为。

public partial class CustomActions
    {

        #region marshalling RegCreateKeyEx RegOpenKeyEx RegCloseKey RegSetValueEx
        [Flags]
        public enum RegOption
        {
            NonVolatile = 0x0,
            Volatile = 0x1,
            CreateLink = 0x2,
            BackupRestore = 0x4,
            OpenLink = 0x8
        }

        [Flags]
        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }

        public enum RegResult
        {
            CreatedNewKey = 0x00000001,
            OpenedExistingKey = 0x00000002
        }

        //[StructLayout(LayoutKind.Sequential)]
        //public class SECURITY_ATTRIBUTES
        //{
        //    public int nLength;
        //    public unsafe byte* lpSecurityDescriptor;
        //    public int bInheritHandle;
        //}
        [StructLayout(LayoutKind.Sequential)]
        public class SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern int RegCreateKeyEx(
                    RegistryHive hKey,
                    string lpSubKey,
                    int Reserved,
                    string lpClass,
                    RegOption dwOptions,
                    RegSAM samDesired,
                    SECURITY_ATTRIBUTES lpSecurityAttributes,
                    out UIntPtr phkResult,
                    out RegResult lpdwDisposition);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyEx")]
        static extern int RegOpenKeyEx(
            RegistryHive hKey,
            string subKey,
            uint options,
            RegSAM sam,
            out UIntPtr phkResult);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern int RegCloseKey(
            UIntPtr hKey);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern uint RegSetValueEx(
             UIntPtr hKey,
             [MarshalAs(UnmanagedType.LPStr)]
     string lpValueName,
             int Reserved,
             RegistryValueKind dwType,
             [MarshalAs(UnmanagedType.LPStr)] string lpData,
             int cbData);

        const int KEY_WOW64_64KEY = 0x0100;
        const int KEY_READ = 0x20019;

        #endregion

   private static uint WriteValue_String(UIntPtr hKey, string sName, string sValue)
        {
            uint setRes = RegSetValueEx(hKey, sName, 0, Microsoft.Win32.RegistryValueKind.String, sValue, sValue.Length + 1);
            return setRes;
        }

        /// <summary>
        /// Enable AutoLogon by changing the values of the system registry keys "DefaultUserName", "DefaultPassword" and "AutoAdminLogon" 
        /// in "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
        /// </summary>
        /// <param name="session"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult EnableAutoLogon(Session session)
        {
            _session = session;
            LogUtil.WriteDebugInfo(session, "Enter Function");
            try
            {

                SECURITY_ATTRIBUTES secAttribs = new SECURITY_ATTRIBUTES();

                UIntPtr hKey;
                RegResult regResult;

                LogUtil.WriteDebugInfo(session, "RegOpenKeyEx");
                int result = RegOpenKeyEx(
                    RegistryHive.LocalMachine,
                    @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon",
                    0, //must be 0
                    RegSAM.WOW64_64Key | RegSAM.SetValue,
                    out hKey);

                LogUtil.WriteDebugInfo(session, "WriteValue_String");
                uint setRes = WriteValue_String(hKey, "DefaultUserName", "admin");
                setRes = WriteValue_String(hKey, "DefaultPassword", "admin");
                setRes = WriteValue_String(hKey, "AutoAdminLogon", "1");

                LogUtil.WriteDebugInfo(session, "RegCloseKey");
                int closeRes = RegCloseKey(hKey);           
            }
            catch (System.Exception ex)
            {
                LogUtil.WriteDebugInfo(session, "Exception occured : " + ex.Message + "\n" + ex.StackTrace);
                LogUtil.WriteDebugInfo(session, "Exit Function");
                return ActionResult.Failure;
            }
            LogUtil.WriteDebugInfo(session, "Exit Function");
            return ActionResult.Success;
        }
 }

KEY_WOW64_32KEY (0x0200) 表示 64 位 Windows 上的应用程序应在 32 位注册表视图上运行。32 位 Windows 忽略此标志。有关详细信息,请参阅访问备用注册表视图。

此标志必须使用 OR 运算符与此表中查询或访问注册表值的其他标志组合。

Windows 2000:不支持此标志。

KEY_WOW64_64KEY (0x0100) 表示 64 位 Windows 上的应用程序应在 64 位注册表视图上运行。32 位 Windows 忽略此标志。有关详细信息,请参阅访问备用注册表视图。

此标志必须使用 OR 运算符与此表中查询或访问注册表值的其他标志组合。

Windows 2000:不支持此标志。

于 2013-06-24T07:40:41.757 回答