DirectoryRef: use in 2 different folders - wix

In my installer project I have a harvested output of a referenced project which creates a fragment and, inside it, DirectoryRef element.
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="MyProject.Content">
<Directory Id="dir9B0F2CD8423EA8141263E4CAA24D1234" Name="Data">
<!-- subfolders, components etc. -->
Now, in my main wxs file I need to include MyProject.Content directory as a subfolder of two different directories.
I include <Directory Id="MyProject.Content" /> as a child of one directory and it works fine, files are added.
But if I include it in another directory I get:
error LGHT0091: Duplicate symbol 'Directory:MyProject.Content' found.
How can I reuse DirectoryRef twice?

The Id of non-Ref elements must be unique. So, somewhere in your .wxs code you have Directory Id='MyProject.Content' twice.
Unfortunately, the design of heat.exe that is part of the WiX Toolset adds a lot of identifiers preventing your scenario. You'd need to remove the Id attributes and probably still have to harvest twice to get two different ComponentGroup identifiers. This scenario just isn't in the design of heat.exe.
Contrast that with something like the WiX Expansion Pack advanced harvesting's solution where the HarvestFolder or HarvestProject element is placed directly in your .wxs code. Then you can place those elements in the appropriate directories and unique identifiers will be generated.

Related

WIX Toolset Bundle get parent directory of path returned from ComponentSearch

I am attempting to have my WIX bundle use the previous install directory if an earlier version is already installed. The previous versions did not create a registry entry for the install location. As such I tried to use a ComponentSearch (Util Extension) to find the main executable. The install directory is the parent directory of the directory containing the executable. The ComponentSearch gives me the directory C:\InstallDirectory\DirectoryContainingEXE. How can I get C:\InstallDirectory?
<?xml version="1.0" encoding="utf-8"?>
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Fragment>
<util:ComponentSearch Id="ExeComponentSearch" Guid="{COMPONENT GUID}" Result="directory" Variable="InstallFolder"/>
</Fragment>
</Include>
I found a solution. The obvious solution is to use a file whose parent is the C:\InstallDirectory. Since I don't have any files in the C:|InstallDirectory that would not work. What I did have is a component that sets permissions on the C:\InstallDirectory. I used that component to get the directory. This would probably work with other types of components that do not contain a file. Maybe a registry that is the key path of the component?
<util:ComponentSearch Id="InstallDirectoryPermissionsSearch" Guid="{COMPONENT GUID}" Result="directory" Variable="InstallFolder"/>

Wix Toolset - Variable Shared Across Projects/Solution

I am trying to share a variable across 2 of my wix projects but I am having issues.
Basically I am trying to accomplish having the version number of my bootstrapper and MSI in one file and then this referenced by the two projects.
I have three projects
Install - This is a setup project that creates an .msi file
Bootstrapper - This is a Wix Bootstrapper project that references and runs the .msi file at runtime
Shared - This is a wixlib project that contains a single variable in a fragment that is the version number
The shared project contains a single file i have called GlobalVars.wxs and looks like this
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<?define VersionNo = "6.86.123"?>
</Fragment>
</Wix>
The bootstrapper references this variable like this
<Bundle Name="ProgramName" Version="$(var.VersionNo)" Manufacturer="CompanyName" UpgradeCode="Guid" Compressed="no">
and the Install project references the variable like this - and has a reference to the .wxs from the shared project
<Product Id="*" Name="Program Name" Language="2057" Version="$(var.VersionNo)" Manufacturer="CompanyName" UpgradeCode="guid">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"/>
<?include GlobalVars.wxs ?>
Both projects have references setup to the wixlib project that contains the variable
When i attempt to build I am getting this error on both the install and bootstrapper project
Undefined preprocessor variable '$(var.VersionNo)'.
If the <?include?> tag resolved the issue I would expect the install project to build
Does anyone have any ideas as to what I might be doing wrong here?
To me it looks like the variable has not been defined by the time the build attempts to call it, but I am unsure as to show to change the order to ensure the variable is defined before anything else
Thanks for the help
I believe the answer to this question will help. I've used it and noticed that properties seem to be usable in my main wxs file.
To summarise, you need to set up a fake componentGroup in your library fragment, and use it in your installer. You do not need the include anymore, as long as the fake componentGroup from your fragment is referenced as a componentGroupRef in your main install, and your wixlib project is referenced in your installer project through VS (you said you'd already done this in your comments above).
Your library fragment might look something like this.
<Fragment id="fragment_id_may_not_be_needed">
<?define VersionNo = "6.86.123"?>
<ComponentGroup Id="c.define_version_num" />
</Fragment>
If the define for whatever reason doesn't work, try using a property instead. I'd be interested to know which works. Properties seem to work for me.
Then reference it in your main install like this:
<Feature Id="Main_installation" Title="Main installation" Level="1">
<!-- bringing in fragments from the shared libraries -->
<ComponentGroupRef Id="c.define_version_num" />
</feature>
Give it a whirl.

How can I remove a folder located in the same folder of my setup after installation in Wix?

I am trying to make a setup file for an application with Wix. After the installation of the program the setup should remove a folder located in its same folder. I don't know how to do it. All I know is that I have to use the RemoveFolder element, that must be placed inside a Component element. So far I have written this but it doesn't work.
<Component Directory="CURRENTDIR" Id="cd1">
<RemoveFolder Id="rf1" On="install" Directory="NameOfFolderToRemove"/>
</Component>
Take a look at util:RemoveFolderEx
http://wixtoolset.org/documentation/manual/v3/xsd/util/removefolderex.html
You will need to reference WixUtilExtension in your project and include
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
in your Wix tag like below:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<RemoveFolder> will only remove empty folders so if there are files in the folder the remove folder action won't work.

Setting permissions for folder and all sub folders in Wix

All of the relevant links seem to assume that I am using DirectoryRefs and CreateFolder within these. When I run heat I get a .wxs file that consists of <Directory> tags and <Component> tags but not DirectoryRefs. I'd rather not rewrite the whole 5000 line file by hand. Is there a way to edit folder permissions for these tags?
You don't have to rewrite the heat auto-generated fragment. You can reference the directories defined there with the DirectoryRef elements in another fragment.
Most likely you'd like to do the following:
First, change the ID of the root directory in a heat-generated fragment. This can be done by a -dr <DirectoryName> command line switch of heat.exe. Choose a name for the DirectoryName, e.g. MY_ROOT_FOLDER. This is necessary for a convenient reference to that directory in a DirectoryRef element
Next, author a special component (in a different fragment), which is to contain the permissions functionality only. Something like this:
<DirectoryRef Id="MY_ROOT_FOLDER">
<Component DiskId="1" Id="Permissions" Guid="GUID-GOES-HERE">
<Condition>...</Condition>
<CreateFolder>
<util:PermissionEx GenericAll="yes" User="[LOGON_ACCOUNT]" Domain="[LOGON_DOMAIN]" />
</CreateFolder>
</Component>
</DirectoryRef>
Finally, don't forget to include this component to a feature of your choice.
Note, that by default the <util:PermissionEx> element appends permissions to the folder in question and all its descendants.

How is ReuseCabinetCache used in a WIX install

Similiar question: Reusing WIX components to speed up candle/light
My project has the very same problem as the one referenced; a very large static database that never changes is compressed into the msi every time a build is required. I would like to do as the question asks: reuse a pre-compressed cab file to speed up the build time.
I started doing as the answer suggests, using the cabCache property. I added the following to the .wixproj:
<CabinetCachePath>cabs</CabinetCachePath>
<ReuseCabinetCache>True</ReuseCabinetCache>
I then seperated the static data into a fragment:
<Fragmet>
<Media Id="2" Cabinet="static.cab" EmbedCab="no" />
<Component Id="staticCab" Guid="..." >
Files ...
</Component>
And the fragment was referenced in the feature:
<ComponentRef Id="staticCab" />
This created the cab file, but left it empty. My next thought was the use a Merge Module. I created the module:
<Module Id="StaticModule" Language="1033" Version="1.0.0.0" >
<Package ...>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder" Name=".">
<Component Id="StaticFiles" Guid="...">
Files...
</ -- End all XML Tags
And then merged it:
<Directory Id="StaticDir" Name="static">
<Merge Id="StaticModule" Language="1033" src="..\Static\bin\Release\static.msm" />
</Directory>
<Feature ...>
<MergeRef Id="StaticModule"/>
</Feature>
Even after all this, the CabinetCache is still being rebuilt every time.
I guess my question would be what is the correct way to use ReuseCabinetCache. I'm still learning WIX, so I apologize if the answer is evident. I just am not sure how to use it.
Edit: A MergeModule would not be ideal since there is no need to share that logic with other msi's. It is only useful to this single project to a single development team.
I'm going to go ahead and answer my own question since it turned out to be so simple.
Change the .wxiproj to have these properties in
<CabinetCachePath>cabs</CabinetCachePath>
<ReuseCabinetCache>True</ReuseCabinetCache>
Add a media to the .wxs install
<Media Id="2" Cabinet="static.cab" EmbedCab="yes" />
In the Directory tag where you store the static files, add DiskId="2".
This will do a couple of things. First you are telling Wix that you wan't to store the cabinets in a path to reuse the cabinets. Creating a new cabinet and only storing static data in it (or data that doesn't change often) will cause Wix to use the cached version of the cabinet. Wix validates the cabinets by ensuring that:
The number of files in the cached cabinet matches the number of files being built.
The names of the files are all identical.
The order of files is identical.
The timestamps for all files all identical.
(Source: http://wix.sourceforge.net/manual-wix3/optimizing_builds.htm)
No wonder I couldn't find any documentation on it. Its so easy to do it should have been apparent to me.
Update: Also, multiple threads are used to build multiple cabinets. Creating multiple cabinets will improve the speed even more.