Wix project references on multiple destination locations how? - wix

I'm struggling with wix setup for one project I'm working on.
I have decided to give a wix try and it is not going well so far.
I have read probably all tutorials and searched net without success.
Here is my situation:
One setup should install in program files app folder
1.) Windows forms application
2.) Web application that is used by windows application
3.) Shared lib1 used by web and win application
4.) Shared lib2 used by web and win application
... etc
I'm using project references to collect project output with heat.
I have given each project directory id so I can later use this as reference in real install location.
It looks like I can't have same project output on more than one location
I can't have same project referenced more than once also.
How can I make installer that is using project outputs on more than one destination location.
Here is example from my product.wxs
<!-- Define Directory Structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<!-- ProgramFiles -->
<Directory Id="ProgramFilesFolder">
<Directory Id="dirManufacturer" Name="TEST_[Manufacturer]">
<Directory Id="INSTALLLOCATION" Name="TEST_[ProductName]">
<!-- Filled With Referenced project -->
<Directory Id="dirControl" Name="Control">
<Directory Id="dirControlOutput" />
<Directory Id="dirSearchAndIndexOutput" />
<Directory Id="dirControlLib" />
<Directory Id="dirControlAndWebLib" />
<Directory Id="dirLuceneAnalyzersOutput" />
</Directory>
<!-- Filled With Referenced project -->
<Directory Id="dirWeb" Name="Web">
<Directory Id="dirWebOutput" />
<Directory Id="dirWebBin" Name="bin">
<Directory Id="dirUrlRewriterOutput" />
<Directory Id="dirSearchAndIndexOutput" />
<!-- TODO: Fix This
<Directory Id="dirSearchAndIndexOutput" />
<Directory Id="dirControlAndWebLib" />
<Directory Id="dirLuceneAnalyzersOutput" />
-->
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
<!-- StartMenu -->
<Directory Id="ProgramMenuFolder">
<Directory Id="dirProgramsMenu" Name="TEST_[ProductName]">
</Directory>
</Directory>
<!-- CommonApplicationData -->
</Directory>
I'm really trying to understand how all of this works but everything I have found points out that this scenario is either impossible or requires hard manual referencing files directly.
My general idea is to have Visual Studio solution that is automatically builds setup for each source change.
Thank you for help and sudgestions!
Goran

From 3. and 4. in the description I gather you need the same file installed on different places, right?
You could do it like in the example below - same file (path\to\lib1.dll on the build machine) will be installed twice on the target machine, as App\lib1.dll and as Web\lib1.dll. You just need 2 different components that reference the same source file.
<Directory Id="AppDir" Name="App">
<Component Id='lib1_app.dll' Guid='*'>
<File Id='lib1_app' Name='lib1.dll' Source='path\to\lib1.dll' KeyPath='yes'>
</Component>
</Directory>
<Directory Id="WebDir" Name="Web">
<Component Id='lib1_web.dll' Guid='*'>
<File Id='lib1_web' Name='lib1.dll' Source='path\to\lib1.dll' KeyPath='yes'>
</Component>
</Directory>

Related

How to define a directory structure (path) to use as the WorkingDirectory attribute

I already successfully created an MSI for PyCharm because the installer is not working properly in silent mode. So I had my first successful experience with WiX.
Now, I got a folder to install from our developers.
This program should go to "C:\ProgramFiles\Folder A\Folder B"
because later there will be another package that goes to "C:\ProgramFiles\Folder A\Folder C"
So, here's what I got (part of it):
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A"/>
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B"/>
</Directory>
</Directory>
I am trying now to create the shortcut
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[APPLICATIONSUBDIRECTORY]\Program B.exe" Icon="ProductIcon" WorkingDirectory="APPLICATIONSUBDIRECTORY"/>
So, my intention was that APPLICATIONSUBDIRECTORY = "C:\ProgramFiles\Folder A\Folder B" but it's going to be "C:\ProgramFiles\Folder B"
I found this:
Setting Wix shortcut with environment variable workingdirectory
But I would rather not use additional properties if there's already a directory structure.
Leaving away this:
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
and using APPLICATIONROOTDIRECTORY would work but I need a second layer of folders.
The Target attribute does not like this as well.
Using (a combination of variables)
Target="[APPLICATIONROOTDIRECTORY]\[APPLICATIONSUBDIRECTORY]\Program B.exe"
does not work but
Target="[APPLICATIONROOTDIRECTORY]\Folder B\Program B.exe"
does.
As I am new to WiX I am still struggling to define directories.
The first 2 Directory Ids are joined but the 3rd one doesn't.
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A"/>
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
</Directory>
This is my batch file:
#echo off
SET WIXPATH=C:\Program Files (x86)\WiX Toolset v3.11\bin
SET COMPONENTGROUP=MyCompGroup
SET FILEFOLDER=Files
SET FILELIST=FileList
SET MAINFILE=Main
SET MSINAME=Program B.msi
if exist FileList.wxs del FileList.wxs
if exist *.wixobj del *.wixobj
if exist *.wixpdb del *.wixpdb
if exist *.msi del *.msi
if exist *.cab del *.cab
pause
"%wixpath%\heat.exe" dir ".\%FILEFOLDER%" -cg %COMPONENTGROUP% -dr APPLICATIONROOTDIRECTORY -out %FILELIST%.wxs -gg -ke -srd -sfrag -template fragment
"%wixpath%\candle.exe" -arch x86 %MAINFILE%.wxs %FILELIST%.wxs
"%wixpath%\light.exe" -b %FILEFOLDER% -out "%MSINAME%" %MAINFILE%.wixobj %FILELIST%.wixobj
And that's the directory structure to "capture":
/--Files
/----Program B
/------File1
/------File2
etc.
Glitch in Directory Structure
It looks like there is an error in your Directory hierarchy. Maybe try to change it to look like this as a first step:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A">
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B" />
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B" />
</Directory>
</Directory>
Are you using Visual Studio? Try going Edit => Advanced => Format Document when you have your WiX source file open. See what the indentation looks like. Your sub-folders should be indented as shown above. If they don't indent, look at the /> entries. Only add these if you indicate that there are no further sub-folders.
Adding Your Shortcut
As to your shortcut. Here is how you should be able to add an advertised shortcut to a file you install:
<Shortcut Id="mysc" Advertise="yes" Directory="ApplicationProgramsFolder"
Name="My Shortcut" Description="My Shorcut Description" />
This Shortcut element should be added to the component that installs the file in question, for example like this:
<Component Id="NOTEPAD.EXE" Feature="ProductFeature">
<File Source="MyReleaseFiles\NOTEPAD.EXE" />
<Shortcut Id="mysc" Advertise="yes" Directory="ApplicationProgramsFolder"
Name="My Shortcut" Description="My Shorcut Description" />
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"
Directory="ApplicationProgramsFolder"/>
</Component>
Visual Studio
You can install the Visual Studio 2017 Community Edition for free - and I recommend this way to make WiX MSIs. You get some more help from the tool to avoid errors such as the issue with your Directory hierarchy.
I wrote a short answer on how to create a minimal "Hello World" style WiX MSI using Visual Studio:
WiX installer msi not installing the Winform app created with Visual Studio 2017.
You might want to reinstall the latest WiX version and the Visual Studio extensions (2017) if you install Visual Studio to ensure that the WiX project types and extensions are available.
Still learning how this forum works :-) To post markup I need to use "answer" instead of "comment", right?
This is how it works like #Stein Åsmul wrote:
I split every directory element into <Directory> and </Directory> instead of just <Directory />.
I know it's not necessary for the "last" one but just to make it clear for me next time I look at that code :-)
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A">
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B">
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B">
</Directory>
</Directory>
</Directory>
The shortcut part works like this:
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="*PUT-IN-GUID*">
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[APPLICATIONSUBDIRECTORY]\Program B.exe" Icon="ProductIcon" WorkingDirectory="APPLICATIONSUBDIRECTORY"/>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[blabla]\Program B" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
It's not perfect but way better than copying the whole crap by batch file...
It would be even better if our developers would use WiX instead of giving me just binaries to deploy :-)
As another workaround I was able to create a new property yesterday using a custom action. It is not upper case on purpose.
<SetProperty Id="ApplicationFullDirectory" Value="[APPLICATIONROOTDIRECTORY]Folder B" After="CostInitialize" />
This allowed me to use the new variable/property "ApplicationFullDirectory" in the shortcut element.
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[ApplicationFullDirectory]\Program B.exe" Icon="ProductIcon" WorkingDirectory="ApplicationFullDirectory"/>
But still learning :-)

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).

How to create a folder in the windows folder using wix 3.8 installer

I need to install file in the regular installation folder (i.e. c:\program files\mycompany\myapp) but I also need to copy files into a subfolder located in the windows folder i.e. c:\windows\myfolder.
While I have no problem with the "install" folder, I can't see how to create a sub-folder in c:\windows?
Any ideas?
Thanks.
Thierry
UPDATE:
I probably should have been a bit more precise and provide additional information. This is the xml I have:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="MyCompany">
<Directory Id="ClientFolder" Name="Client">
</Directory>
<Directory Id="ServerFolder" Name="Server">
</Directory>
</Directory>
</Directory>
</Directory>
<Directory Id="WindowsFolder" Name="WindowsFolder">
<Directory Id="MyFolder" Name="MyFolder"></Directory>
</Directory>
</Fragment>
When I try to compile my wix project, I get the following error:
Error 1 : The Directory with Id 'WindowsFolder' is not a valid root directory.
There may only be a single root directory per product or module and its Id attribute
value must be 'TARGETDIR' and its Name attribute value must be 'SourceDir'
PS: I'm new to this and I'm reading a book on how to use Wix, but I need this asap, so please be patient with me :). Thank you.
You create Directory elements based on System Folder Properties. Specifically the WindowsFolder property. Then create a child Directory element for your folder.
You should have very strong justification before doing this as this is an operating system area. I typically tell developers no unless they have a very, very good reason.
The penny dropped!!
You need to add a directory reference directly under
<Directory Id="TARGETDIR" Name="SourceDir">
along with the rest of your directories. You'll end up with something like this
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="MyApp">
<Directory Id="ClientFolder" Name="Client"/>
</Directory>
</Directory>
<Directory Id="WindowsFolder">
<Directory Id="MyFolder" Name="MyFolder"/>
</Directory>
</Directory>
Where the WindowsFolder will tell the installer to use the "windows" folder and to use the sub folder within it, just set the Directory your ComponentGroup (or other) to MyFolder i.e.
<ComponentGroup Id="MyFolderComponents" Directory="MyFolder">
..
..
</ComponentGroup>
That regular installation folder of yours is based on a tree that will have ProgramFilesFolder somewhere, and then your subfolder name. You do the same for the Windows folder using the standard Windows Installer property:
Windows Folder
which is one of this bunch:
Property Reference

Can you set TARGETDIR to be a command line parameter?

I have generated an msi which I'd like to be able to change the default installation directory of and I know that you can change WIX properties using command line parameters, but I can't seem to get this working for TARGETDIR like this:
Installer.msi TARGETDIR=C:\
My Directory fragment is:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="SystemFolder"/>
<!-- Desktop-->
<Directory Id="DesktopFolder"/>
<Directory Id="ProgramFilesFolder">
<Directory Id="DIR_Company" Name="Company Name">
<Directory Id="DIR_SubDir" Name="Sub Directory" >
<Directory Id="INSTALLDIR" Name="My Product">
<Directory Id="DIR_ONE" Name="ONE" />
<Directory Id="DIR_TWO" Name="TWO" />
<Directory Id="DIR_THREE" Name="THREE" />
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
Is this just not possible, or is it my syntax?
I suspect this is because you have predefined folders in your directory hierarchy, for instance, ProgramFilesFolder. Even though you set the TARGETDIR via the command line, it gets overwritten with the well-known location of your Program Files and all sub folders become relative.
As a workaround, you can set INSTALLDIR from the command line. If you give it a full path, it will overwrite the initial hierarchy you define in your WiX authoring.

"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