How do I make a 64 bit MSI?

2019-04-12 23:03发布

问题:

I've specified:

  • -arch x64 when running candle.exe.
  • Platform=x64 on the Package.
  • ProgramFiles64Folder as the Directory id where things get installed.

and still, when the app gets installed, it goes to C:\Program Files (x86).

There are some other wxs generated by heat.exe. I tried adding -platform x64 and -platform win64 to the calls to heat.exe, but it made no difference.

I read

  • https://msdn.microsoft.com/en-us/library/gg513929.aspx
  • The section on 64 bit installer in the Wix Cookbook
  • How do I get WiX to generate a 64-bit MSI?

and I think I'm doing everything that was described there.

What am I missing?

I've came up with a minimum case that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="Project X" Manufacturer="X LLC" Language="1033" Version="1.0.0.0"
             UpgradeCode="5bf2131c-4068-4cb3-adac-bc9c79ed8ce3">
        <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64"/>
        <Property Id="ApplicationFolderName" Value="Project X"/>
        <Property Id="WixAppFolder" Value="WixPerMachineFolder"/>
        <UI>
            <UIRef Id="WixUI_Advanced"/>
        </UI>
    </Product>
</Wix>

and I compile it like this:

 candle.exe -arch x64 -ext WixUIExtension -ext WixUtilExtension ProjectX.wxs

 light.exe -ext WixUIExtension -ext WixUtilExtension -out ProjectX-1.0.0-beta.3-win64.msi ProjectX.wixobj

It obviously complaints about the media table being empty:

> candle.exe -arch x64 -ext WixUIExtension -ext WixUtilExtension ProjectX.wxs
Windows Installer XML Toolset Compiler version 3.11.0.1701
Copyright (c) .NET Foundation and contributors. All rights reserved.

ProjectX.wxs

> light.exe -ext WixUIExtension -ext WixUtilExtension -out ProjectX-1.0.0-beta.3-win64.msi ProjectX.wixobj
Windows Installer XML Toolset Linker version 3.11.0.1701
Copyright (c) .NET Foundation and contributors. All rights reserved.

C:\Users\pupeno\AppData\Local\Temp\h1k0echv\ProjectX-1.0.0-beta.3-win64.msi : warning LGHT1076 : ICE71: The Media table has no entries.

But the installer is still generated and it still points to C:\Program Files (x86):

The full .wxs looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Product Id="*" Name="ProjectX" Manufacturer="X Inc" Language="1033"
             Version="$(var.MSIProductVersion)" UpgradeCode="">
        <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64"/>

        <MediaTemplate EmbedCab="yes"/>

        <Icon Id="Icon_ProjectX.ico" SourceFile="src\main\installer\ProjectX.ico"/>

        <WixVariable Id="WixUISupportPerUser" Value="0"/>
        <Property Id="ApplicationFolderName" Value="X Inc\ProjectX"/>
        <Property Id="WixAppFolder" Value="WixPerMachineFolder"/>
        <Property Id="ARPPRODUCTICON" Value="Icon_ProjectX.ico"/>
        <WixVariable Id="WixUILicenseRtf" Value="src\main\installer\eula.rtf"/>
        <WixVariable Id="WixUIBannerBmp" Value="src\main\installer\WixUIBannerBmp.bmp"/>
        <WixVariable Id="WixUIDialogBmp" Value="src\main\installer\WixUIDialogBmp.bmp"/>
        <Property Id="AUTO_CONNECT_TO">
            <RegistrySearch Id="AutoConnectTo" Root="HKLM" Key="Software\X Inc\ProjectX" Name="AutoConnectTo"
                            Type="raw"/>
        </Property>
        <Property Id="RUN_ProjectX_ON_EXIT" Value="true"/>
        <Property Id="INSTALL_SCREENSAVER_ON_EXIT" Value="true"/>
        <Property Id="STAGING_DIR" Value="undefined"/>
        <Property Id="ARCH" Value="undefined"/>

        <UI>
            <UIRef Id="DM_WixUI_Advanced"/>

            <Publish Dialog="DM_ExitDialog" Control="Finish" Event="DoAction" Value="CA_Run_ProjectX">
                RUN_ProjectX_ON_EXIT and <![CDATA[&Ftr_Configurator=3]]> and NOT Installed
            </Publish>

            <Publish Dialog="DM_ExitDialog" Control="Finish" Event="DoAction" Value="CA_Install_Screensaver">
                INSTALL_SCREENSAVER_ON_EXIT and <![CDATA[&Ftr_Screensaver=3]]> and NOT Installed
            </Publish>

            <Dialog Id="DM_ExitDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)">
                <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes"
                         Text="!(loc.WixUIFinish)"/>
                <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes"
                         Text="!(loc.WixUICancel)"/>
                <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no"
                         Text="!(loc.ExitDialogBitmap)"/>
                <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes"
                         Text="!(loc.WixUIBack)"/>
                <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0"/>
                <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes"
                         NoPrefix="yes"
                         Text="Thank you for choosing ProjectX. We sincerely hope it satisfies your needs."/>
                <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"
                         Text="!(loc.ExitDialogTitle)"/>
                <Control Id="RunProjectXCheckBox" Type="CheckBox" X="135" Y="150" Width="220" Height="40" Hidden="yes"
                         Property="RUN_ProjectX_ON_EXIT" CheckBoxValue="1" Text="Run ProjectX Configurator">
                    <Condition Action="show"><![CDATA[&Ftr_Configurator=3]]></Condition>
                </Control>
                <Control Id="InstallScreensaverCheckBox" Type="CheckBox" X="135" Y="190" Width="220" Height="40"
                         Hidden="yes" Property="INSTALL_SCREENSAVER_ON_EXIT" CheckBoxValue="1"
                         Text="Install ProjectX as your screensaver">
                    <Condition Action="show"><![CDATA[&Ftr_Screensaver=3]]></Condition>
                </Control>
            </Dialog>

            <InstallUISequence>
                <Show Dialog="DM_ExitDialog" OnExit="success" Overridable="yes"/>
            </InstallUISequence>

            <AdminUISequence>
                <Show Dialog="DM_ExitDialog" OnExit="success" Overridable="yes"/>
            </AdminUISequence>
        </UI>

        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed."/>

        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFiles64Folder">
                <Directory Id="APPLICATIONFOLDER">
                    <Directory Id="Dir_jre" Name="jre"/>
                    <Directory Id="Dir_jars" Name="jars"/>
                </Directory>
            </Directory>

            <Directory Id="ProgramMenuFolder">
                <Directory Id="Dir_Menu_ProjectX" Name="ProjectX"/>
            </Directory>

            <Component Id="Cmp_Auto_Connect_to" Win64="yes">
                <RegistryValue Root="HKLM" Key="Software\X Inc\ProjectX" Name="AutoConnectTo" Type="string"
                               Value="[AUTO_CONNECT_TO]"/>
            </Component>

            <Directory Id="SystemFolder"/>
        </Directory>

        <DirectoryRef Id="APPLICATIONFOLDER">
            <Component Id="Cmp_ProjectX_Configurator_exe" Guid="" Win64="yes">
                <File Id="File_FT_D_ProjectX_Configurator_exe"
                      Source="$(var.STAGING_DIR)\ProjectX Configurator.exe" KeyPath="yes">
                    <Shortcut Id="Shrt_ProjectX_Configurator" Name="ProjectX Configurator" Directory="Dir_Menu_ProjectX"
                              Advertise="yes" Icon="Icon_ProjectX.ico"/>
                </File>
                <RemoveFolder Id="Rm_Menu_ProjectX_1" Directory="Dir_Menu_ProjectX" On="uninstall"/>
            </Component>
            <Component Id="Cmp_ProjectX_Displayer_exe" Guid="" Win64="yes">
                <File Id="File_FT_D_ProjectX_Displayer_exe" Source="$(var.STAGING_DIR)\ProjectX Displayer.exe"
                      KeyPath="yes">
                    <Shortcut Id="Shrt_ProjectX_Displayer" Name="ProjectX Displayer" Directory="Dir_Menu_ProjectX"
                              Advertise="yes" Icon="Icon_ProjectX.ico"/>
                </File>
                <RemoveFolder Id="Rm_Menu_ProjectX_2" Directory="Dir_Menu_ProjectX" On="uninstall"/>
            </Component>
            <Component Id="Cmp_ProjectX_Renderer_exe" Guid="" Win64="yes">
                <File Id="File_FT_D_ProjectX_Renderer_exe" Source="$(var.STAGING_DIR)\ProjectX Renderer.exe"
                      KeyPath="yes">
                    <Shortcut Id="Shrt_ProjectX_Renderer" Name="ProjectX Renderer" Directory="Dir_Menu_ProjectX"
                              Advertise="yes" Icon="Icon_ProjectX.ico"/>
                </File>
                <RemoveFolder Id="Rm_Menu_ProjectX_3" Directory="Dir_Menu_ProjectX" On="uninstall"/>
            </Component>
            <Component Id="Cmp_Prosaver_scr" Guid="" Win64="yes">
                <File Id="File_FT_D_Prosaver_scr" Source="$(var.STAGING_DIR)\Prosaver.scr" KeyPath="yes"/>
            </Component>
            <Component Id="Cmp_Icon" Guid="" Win64="yes">
                <File Id="File_Icon" Source="src\main\installer\ProjectX.ico" KeyPath="yes"/>
            </Component>
        </DirectoryRef>

        <DirectoryRef Id="Dir_Menu_ProjectX">
            <Component Id="Cmp_Install_Screensaver" Guid="" Win64="yes">
                <Shortcut Id="Shrt_Install_Screensaver" Name="Install ProjectX Screensaver"
                          WorkingDirectory="SystemFolder" Icon="Icon_ProjectX.ico"
                          Target="[SystemFolder]rundll32.exe"
                          Arguments="desk.cpl,InstallScreenSaver [#File_FT_D_Prosaver_scr]"/>
                <RemoveFolder Id="Rm_Menu_ProjectX_4" On="uninstall"/>
                <RegistryValue Root="HKCU" Key="Software\X Inc\ProjectX" Name="installed" Type="integer"
                               Value="1" KeyPath="yes"/>
            </Component>
            <Component Id="Cmp_ProjectX_Support" Guid="" Win64="yes">
                <util:InternetShortcut Id="IShrt_ProjectX_Support" Name="ProjectX Support" IconFile="[#File_Icon]"
                                       Target="https://support.ProjectX.tech"/>
                <RemoveFolder Id="Rm_Menu_ProjectX_5" On="uninstall"/>
                <RegistryValue Root="HKCU" Key="Software\X Inc\ProjectX" Name="installed" Type="integer"
                               Value="1" KeyPath="yes"/>
            </Component>
        </DirectoryRef>

        <CustomAction Id="CA_Run_ProjectX" Directory="APPLICATIONFOLDER" Return="asyncNoWait"
                      ExeCommand="[#File_FT_D_ProjectX_Configurator_exe]"/>
        <CustomAction Id="CA_Install_Screensaver" Directory="SystemFolder" Return="asyncNoWait"
                      ExeCommand="[SystemFolder]rundll32.exe desk.cpl,InstallScreenSaver [#File_FT_D_Prosaver_scr]"/>

        <Feature Id="ProductFeature" Title="ProjectX" Level="1" Display="expand"
                 Description="ProjectX.">
            <ComponentGroupRef Id="ComGrp_JRE"/>
            <ComponentGroupRef Id="ComGrp_JARS"/>
            <ComponentRef Id="Cmp_Auto_Connect_to"/>
            <ComponentRef Id="Cmp_ProjectX_Support"/>
            <ComponentRef Id="Cmp_Icon"/>

            <Feature Id="Ftr_Configurator" Title="Configurator" Level="1"
                     Description="This is the application you use to register a new account as well as configure what websites are displayed, what displayers and renderers have access, etc. You need this in at least one computer to control your account.">
                <ComponentRef Id="Cmp_ProjectX_Configurator_exe"/>
            </Feature>
            <Feature Id="Ftr_Displayer" Title="Displayer" Level="1"
                     Description="This is what displays web sites. You need this (or the screensaver) on all the computers connected to screens that displays web sites.">
                <ComponentRef Id="Cmp_ProjectX_Displayer_exe"/>
            </Feature>
            <Feature Id="Ftr_Renderer" Title="Renderer" Level="1"
                     Description="This accesses your websites and generates the screenshots for the displayers. You need at least one of these although the Configurator can also act as a Renderer.">

                <ComponentRef Id="Cmp_ProjectX_Renderer_exe"/>
            </Feature>
            <Feature Id="Ftr_Screensaver" Title="Screensaver" Level="1"
                     Description="This is what displays web sites as the screensaver. You need this (or the displayer) on all the computers connected to screens that displays web sites.">
                <ComponentRef Id="Cmp_Prosaver_scr"/>
                <ComponentRef Id="Cmp_Install_Screensaver"/>
            </Feature>
        </Feature>
    </Product>
</Wix>

The summary information for the generated MSI looks like this (GUID changed):

and the directory points to the use of ProgramFiles64Folder. I can't find anything wrong:

%ProgramFiles% still points to the correct place:

>echo %ProgramFiles%
C:\Program Files

and I also had this fail on two separate computers in the same way (installing to C:\Program Files (x86)).

If I change the Directory to be ProgramFilesFolder instead of ProgramFiles64Folder, then, I get the expected errors:

error LGHT0204 : ICE80: This 64BitComponent cmpCBBF8379128F087B61BD92F8113C95D6 uses 32BitDirectory dir451F8F132CB17CBF5649679474428CE4

Just in case, I open the registry editor and removed all mentions of C:\Program Files (x86)\X LCC. That made no difference :(

I tried specifying a name to the directory, as an experiment:

<Directory Id="ProgramFiles64Folder" Name="Program Files">

and that made no difference either.

回答1:

Very rushed: In your compiled MSI, maybe try to change the below entry in the Custom Action table first (use Orca to hotfix after compilation):

change:

  • WixSetDefaultPerMachineFolder, 51, WixPerMachineFolder, [ProgramFilesFolder], [ApplicationFolderName]

into:

  • WixSetDefaultPerMachineFolder, 51, WixPerMachineFolder, [ProgramFiles64Folder], ApplicationFolderName]

I don't have time to test the above properly, but if you look in the CustomAction table you will see that WixSetDefaultPerMachineFolder assigns [ProgramFilesFolder][ApplicationFolderName] to WixPerMachineFolder. Then you have lots of stuff going on in the ControlEvent table with WixAppFolder = "WixPerMachineFolder" etc... Quite confusing. Then it looks like WixPerMachineFolder is assigned to APPLICATIONFOLDER. The actual property used in the dialog seems to be WIXUI_INSTALLDIR. Can't track it all right now - please try the simple hack above (just set the path to ProgramFiles64Folder) - it might yank the paths into submission. Then test the whole thing to death in all installation mode (install, repair, self-repair, modify, uninstall, major upgrade, patch, admin install, etc...).

Sorry for the rush, good luck.



回答2:

What does your directory table look like? Are you using ProgramFilesFolder or ProgramFilesFolder64?

You'll also need to mark your components as 64 bit. Since the media table is complaining I'm guessing you don't have any component data yet.