Reputation: 31146
I've been struggling with installing a CAB Help file (generated from a MSHC) using WIX. The basic recipe I tried to follow is the one here: Installing Help with Help Library Manager and WiX .
In my particular case I'm not really struggling with the recipe but with x64/x86 targets. I've read the WIX hints from WiX tricks and tips that describe how to make 2 installers, one for each target. However, since I prefer to have just one installer rather than 2, I chose to implement only a x86 target.
When I install using a x64 platform everything works fine. When I try to do the same thing for x86, it complains that it cannot find HelpLibManager.exe
. On closer inspection, this seems reasonable, because this is installed in the 64-bit C:\Program Files\Microsoft Help Viewer\v1.0\HelpLibManager.exe
, while WIX uses the x86 folder C:\Program Files (x86)\Microsoft Help Viewer\v1.0\HelpLibManager.exe
.
To fix this, I attempted to read the correct path from the registry that contains where HelpLibManager is installed:
<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"/>
When you look into the registry, (within the Wow6432Node
of course), it tells me that the value of this key is: c:\Program Files\Microsoft Help Viewer\v1.0\
- which is correct. However, when I look at the log of the MSI, it reads "C:\Program Files (x86)\Microsoft Help Viewer\v1.0\HelpLibManager.exe"
, which is incorrect:
Property(S): HELPLIB = C:\Program Files (x86)\Microsoft Help Viewer\v1.0\
So apparently Wix changes the string value I read from the registry.
Can anyone explain to me what the proper way is to fix this?
Upvotes: 2
Views: 1306
Reputation: 21
I'd like complete Bogdan Mitrache's answer with an exemple. To perform this i use a C# custom action to acces registry and control the WOW behavior.
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) Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
KEY_WOW64_64KEY (0x0100) Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
Upvotes: 0
Reputation: 11023
The redirection to (x86) folder is done by Windows Installer automatically, not by WiX. The same happens if you are creating the package with other setup authoring tools too.
Unfortunately a 32-bit installer cannot write in "Program Files" folder on x64 machines. WOW redirection from the OS controls this during the install.
For creating a registry entry directly under HKLM\Software and not under HKLM\Software\Wow6432Node you can simply mark its component as 64-bit. Unfortunately this does not work the same for files, i.e. even if the component of the file is marked as a 64-bit one the OS will still redirect all files and folders under Program Files (x86).
EDIT:
What I'm most surprised of is that the string value read from the registry is being changed (see the dumped property value)
I know, that surprised I was too when this happened the first time for me.
To launch a file from that folder you could still have a chance, using a little trick, if you write a small custom action C#, with a DLL as output. You could get the value of the search in the custom action, parse it, and if present, manually remove the "(x86)" portion. Then temporarily disable WOW redirection, launch your file, after which you re-enable WOW redirection.
Don't forget to set a condition on the custom action, to run only VersionNT64 property is set, and only on install.
Upvotes: 2