WiX: FileSource confusion - wix

Just trying to setup an installer for the first time, bit confusing.
This code;
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="FTSM" Name="FTSM">
<Directory Id="INSTALLFOLDER" Name="FCP" FileSource="..\FCP\bin\Debug\">
<Component Id="MainExecutable">
<File Id="FCPEXE" Name="FCP.exe" Source="FCP.exe" KeyPath="yes"/>
<Shortcut Id="startMenuFCP" Directory="ProgramMenuDir" Name="FCP" WorkingDirectory="INSTALLDIR" Icon="FCP.exe" IconIndex="0" Advertise="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
Doesn't give me any success, I always get System cannot find the file 'FCP.exe'
If I take the FileSource variable and put it into the source variable, like so;
<File Id="FCPEXE" Name="FCP.exe" Source="..\FCP\bin\Debug\FCP.exe" KeyPath="yes"/>
Then everything works perfectly. I can build the WiX project without errors and it generates an installer that works as expected.
The file structure is as follows;
Main
-> FCP (Main Project)
--> bin
---> Debug
----> FCP.exe
-> Installer (WiX Project)
--> Product.wxs
Obviously not a big issue for this Project, but when I run into multiple components, it's going to be a lot handier to specify the FileSource once.

From Bob Arnson's blog-entry Choosing your payloads:
When you use the File/#Name attribute and don’t use the File/#Source
attribute, the compiler constructs an implicit path to the file based
on the file’s parent component directory plus the name you supply.
Thus when File/#Source is present WiX will use it regardless of any Directory/#FileSource, if it is not then the source path is constructed by combining Directory/#FileSource and File/#Name.

So, a bit of a lucky find really, but it turns out if you use the references folder from within the WiX project you can then do some neat referencing in the wxs file.
I referenced my project and could then do the following;
<File Id="FCPEXE" Name="FCP.exe" Source="$(var.FCP.TargetDir)\FCP.exe" KeyPath="yes"/>

Related

How do I remove files and Folders from ProgramData Folder on Uninstall

Hi there I am having a problem getting my Wix installer to remove elements on Uninstall. The problem folders and files are located on our corporate specified programdata folder 'D:\programdata'. The folders get created OK, however will not remove on Uninstall. The folder structure is as follows
D:\programdata
Company Name
App Name
Logs
QueryOutput
The following is an excerpt from the relevant section of the product.wxs file:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CommonAppDataFolder" Name="CommonAppData" >
<Directory Id="dirCompanyAppData" Name="Company Name">
<Directory Id="dirAppNameAppData" Name="AppName">
<Component Id="cmpDirCommonAppData" Guid="{F808944A-D898-43F3-BA1D-A35A3FD7DF41}" KeyPath="yes">
<CreateFolder Directory="dirAppNameAppData" />
<RemoveFile Id="PurgeAppName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirAppNameAppData" On="uninstall" Directory="dirAppNameAppData" />
</Component>
</Directory>
<Component Id="cmpDirCompanyName" Guid="{A1E7E75A-D582-40C5-BD6B-D36BFB11795E}" KeyPath="yes">
<RemoveFile Id="PurgeCompanyName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirCompanName" On="uninstall" Directory="dirCompanyNameAppData" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramFilesFolder">
... etc
Note company and application identifying elements have been replaced in the code. I have left out the remainder of the wxs file for brevity and because I believe the relevent code is included in this extract. Any assistance much appreciated, this has me stumped.
Kind Regards
Paul J.
From RemoveFolder definition:
Remove an empty folder if the parent component is selected for installation or removal.
In your case the AppData folder probably has user specific configuration in it like it is supposed to.
I think all the component planning is done first, then executed. So, RemoveFile will plan all the files in that folder to be removed and RemoveFolder will decide it shouldn't delete the folder because at the time of planning, the folder still has stuff in it that is not part of the installation included components and therefore not empty.
You will need to use util:RemoveFolderEx. Again there is another caveat to using this.
Because it might dramatically affect Windows Installer's File Costing, the temporary rows must be written before the CostInitialize standard action. Unfortunately, MSI doesn't create properties for the Directory hierarchy in your package until later, in the CostFinalize action.
So you need to manually set a directory based off of a property you probably read from the registry before the WixRemoveFoldersEx action which I think is scheduled just before CostInitialize.

Is Component/#Guid attribute is a MUST in case of producing MergeModule

In my .wxs file for components, there are only components with single file, and this is the case for generatable GUIDs.
But it seems to me that for .msm (merge module), component's GUID should be explicitly specified. Or I'm free to use Guid="*" and that would be OK?
I tried this:<Component Guid="*">
<File Id="$(var.Logger.TargetFileName)" Source="$(var.Logger.TargetPath)" KeyPath="yes" />
</Component>
And got an error from light, that
path for key file of the component is not rooted in one of the
standard directories (like ProgramFilesFolder)
...
I'm confused, because this path is rooted in ProgramFiles:<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.PlatformProgramFilesFolder)">
<Directory Id="ProductVendor" Name="$(var.BaseProductVendorDirectory)">
<Directory Id="BaseProductDirectory" Name="$(var.BaseProductName)">
<Directory Id="ConfiguratorDir" Name="Configurator" />
</Directory>
</Directory>
</Directory>
</Directory>
You should be able to use automatically generated GUIDs in merge modules with rooted directories. But changes introduced in WIX 3.6 probably makes this impossible until bug http://wixtoolset.org/issues/3810/ is fixed.
See also http://wixtoolset.org/issues/2353/.
And also http://sourceforge.net/p/wix/mailman/message/29956690/ (click the View entire thread link to see the full discussion).

Wix - Setting Install Folder correctly

I'm creating a program which is being installed by Wix, using VS 2010 and I've already got the product.wxs ready.
In my wxs file, I've got directory definitions which looks like this:
<SetDirectory Id="INSTALLFOLDER" Value="[WindowsVolume]Myapp" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="Myapp_Installer_Dir" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And then I got these file installation definitions:
<DirectoryRef Id="Myapp_Installer_Dir">
<Component Id="INSTALLER_Myapp" Guid="{94F18477-8562-4004-BC6F-5629CC19E4CB}" >
<File Source="$(var.Myapp.TargetPath)" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="BIN">
<Component Id="INSTALLER_Data" Guid="{545FB5DD-8A52-44D7-898E-7316E70A93F5}" >
<File Source="$(var.Data.TargetPath)" KeyPath="yes"/>
</Component>
...
And it continues in that manner. The files for the "ICONS" directory are defined as well.
I am also using the WixUI_InstallDir dialog set and I got these lines present as well:
<Property Id="WIXUI_INSTALLDIR" Value="Myapp_Installer_Dir" />
<UIRef Id="WixUI_InstallDir" />
The problem is when the user installs the program and changes the value of the installation folder, the files of the "Bin" and "Icons" are installed to their correct path, but the Myapp target is installed to a fix location which was defined at the start as the default installation path.
Why do only the bin and icon files installed to the correct folder the user wanted, but the myapp target does not?
I have finally figured out the problem.
After searching for a while, I came across this document:
WixUI_InstallDir Dialog Set
The relevant part: "The directory ID must be all uppercase characters because it must be passed from the UI to the execute sequence to take effect."
And as you can see in my code: "Myapp_Installer_Dir" does not meet this criteria.
After changing it to "MYAPPINSTALLERDIR", everything worked.
I'm not quite sure, but this is what I think has happened.
When you author a SetDirectory element, you basically add a custom action which sets a directory to the MSI database. As long as you do not specify the sequence it is executed in, it defaults to both, which means execute in both InstallUISequence and InstallExecuteSequence.
Now, when a user changes the installation directory in the wizard, this happens in the UI sequence. Obviously, when the installation enters the execute sequence, the value of INSTALLFOLDER is set to [WindowsVolume]Myapp as it was instructed.
So, you have to rework this somehow. Keep in mind the silent installation as well - there's only execute sequence there.
UPDATE instead of what you have, try something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsVolume">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And let the user optionally change the INSTALLFOLDER as you do now.
Additionally to the pitfall with capital letters there is also an other one:
You have to mark the ID of the changeable directory as secure. (At least when the setup runs with admin rights.)
Related to Yonatan's answer with the directory ID MYAPPINSTALLERDIR you have to add this:
<Property Id="MYAPPINSTALLERDIR" Secure="yes" />
Related to the example WixUI_InstallDir in the WiX documentation you have to add this:
<Property Id="TESTFILEPRODUCTDIR" Secure="yes" />
Unfortunately this important fact is not mentioned in the WiX example.

WIX deploy two assemblies to GAC

Using WIX, and trying to install two of the same assemblies, one for .Net35 and the other .Net40. I am using two separate components, however WIX is preventing the project from compiling.
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="47E6BD1B-25CD-466D-945E-06DCF0F2A269" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
The error I receive is:
Error 29 ICE30: The target file 'MyDll.dll' is installed in '[TARGETDIR]\GAC\' by two different components on an SFN system: 'MyDllServicesModuleGac40Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057' and 'MyDllServicesModuleGac35Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057'. This breaks component reference counting. D:\PROJECTS\MyDll.Experimental.3.0.0\Project\MyDll\MyDll.Wix.Services\MergeModule.wxs 34 1 MyDll.Wix.Services
The installer should be able to detect that the .Net35 dll gets installed to the GAC at C:\Windows\assembly, while the .Net40 dll gets installed to the GAC at C:\Windows\Microsoft.NET\assembly.
Renaming the DLLs is not an option.
Thanks!
UPDATE
Naturally I came up with a solution just after posting, seem wrapping the components in additional elements allowed me to get this to work. Later I read Tom Blodget's post so that is correct.
<Directory Id="GAC1" Name="GAC">
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
</Directory>
<Directory Id="GAC2">
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="FD74504A-6FE9-488E-9086-9DAD3024B35D" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
</Directory>
Well, hope it helps someone!
As explained by Aaron Stebner,
When you use the attribute Assembly=".net" for a file in WiX, it will
create entries in the MsiAssembly and MsiAssemblyName table for this
component and mark it as a GAC component. That means that the file
will only be installed to the GAC by this component, and it will not
install to the directory that the component is a child of. That
directory will only be used by Windows Installer to stage a copy of
that file when creating an administrative install point.
So the directories for your two components must be different since the file names are the same. If nothing else is targeted for those directories, they won't even be created. I put my GAC components under a subdirectory of my install folder:
<Directory Id="tmp_to_GAC" Name="tmp_to_GAC">
You'd need one for each GAC.

"ICE38: Component installs to user profile" error for a specific component

I am trying to write a Windows Installer script in WiX 3.6 with a per-machine and x64 architecture only setting. I have the following project structure (shortened):
<Directory Id="ProgramFiles64Folder" Name="PFiles">
<Directory Id="APPLICATIONFOLDER" Name="My Company">
<Directory Id="ProductFolder" Name="My Product">
<Component Id="MainComponent" Guid="" Win64="yes" KeyPath="yes">
...
</Component>
<Directory Id="DataFolder" Name="Data">
<Directory Id="Machine" Name="Machine" >
<Directory Id="MachinesFolder" Name="Machines">
<Component Id="Machine1" Guid="{74341536-72DF-48C3-95E8-2851D9FA8318}" Win64="yes" KeyPath="yes">
...
</Component>
</Directory>
<Directory Id="TemplateFolder" Name="Template">
<Component Id="TemplateFiles" Guid="{A0D0C225-D604-4B84-971D-41687A30EC36}" Win64="yes" KeyPath="yes">
<File Id="Template1.rsbak" Source="$(var.SolutionDir)bin\Release\File1.rsbak" />
...
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
The problem is that I receive the error ICE38: Component TemplateFiles installs to user profile. It must use a registry key under HKCU as its KeyPath, not a file for the TemplateFiles component when I compile. What confuses me is that I use a similar structure in another project (working), and have several components with the exact same setup in my project (not shown above). Why does this - and this only - component insist on installing to the user profile when all others get installed correctly, to Program Files?
Looks like there's significant difference for msi between Program Files and Users\UserName\Documents folders. The last is referenced in your example:
<Directory Id="DataFolder" Name="Data">
I came to the similar problem and found an answer in the blog post - https://robmensching.com/blog/posts/2007/4/27/how-to-create-an-uninstall-shortcut-and-pass-all-the/
In short you need to define RegistryKey on HKCU root as subelement to Component and add RemoveFolder element as subelement to Directory. See the link above for full example. In addition:
Remove KeyPath attribute from Component element
RemoveFolder possibly have to be defined for all folders. I used dummy component with no file inside for that