WiX - HeatDirectory Task generation of Registry HKCU KeyPaths when InstallScope is changed to perUser - wix

Up to now we have used the HeatDirectory msbuild task to capture the output of a 'dotnet publish' to create a file list Fragment for our WiX installer, and since our installer has an InstallScope of perMachine, this has worked because File keypaths work in this mode.
It appears that when we switch our Package InstallScope to perUser, we need to add RegistryValue keypaths in the Fragment for each Component instead of using the File as the KeyPath. I cannot see any options in the documentation for generating this as an output option. Am I missing a subtle HeatDirectory option that might do this?
If not, does anyone have a suggestion as to how this might be done. I wondered about using the HeatDirectory Transforms parameter to modify the output and inject the required nodes. We are using that to filter pdb files today but could not find a good example of this being done anywhere. Are other users doing something else or have some other suggestion?
Thank you.

Related

WiX repair from managed bootstrapper fails to fix some corrupted DLLs

I have a WiX Managed Bootstrapper Application that installs some MSIs. I also have a series of tests that exercise the various functions of the installer. The problem I'm having is with the repair test. The test purposely corrupts all the DLLs we install then calls the EXE installer with "/repair /passive" flags. Once completed around 80% of the DLLs are repaired but the remaining ones are untouched and therefore still corrupted after the repair.
If I manually run msiexec on an individual MSI with the command line args "/fa" which instructs the MSI to forcibly replace all the files it installed, it fixes 100% of the DLLs.
My question is how can I force the MBA to instruct each MSI to repair in this way? I've tried setting the REINSTALLMODE property to 'amus' on the individual MSIs in their .wxs files but the MBA overwrites them at run time as is evident in the log via this line:
PROPERTY CHANGE: Modifying REINSTALLMODE property. Its current value is 'amus'. Its new value: 'cmuse'.
I've also tried to set the properties in the MBA to pass through to each MSI but it doesn't appear to pass them and instead uses it's default values.
I see many similar questions here but none actually address this specific issue. Any help would be greatly appreciated. Rob save me!
Here's your problem right here:
[12:25:25:874]: File: C:****\estimator.dll; Won't Overwrite; Won't patch; Existing file is unversioned but modified
The installer doesn't want to overwrite a file that has changed since it was installed if it cannot verify the version or language (and maybe some other properties?). Without these properties, it decides to look at the modified date. If it is newer than when it was first installed then it won't touch it assuming instead that something changed for a reason and reverting it will cause something to fail. (You can read more here)
One thing you can do in this case is use a Companion File
Set this attribute to make this file a companion child of another file. The installation state of a companion file depends not on its own file versioning information, but on the versioning of its companion parent. A file that is the key path for its component can not be a companion file (that means this attribute cannot be set if KeyPath="yes" for this file). The Version attribute cannot be set along with this attribute since companion files are not installed based on their own version.
Basically you will set the logic for installing/uninstalling this component to be the same as the "FileID" of another component in the install. In the estimator.dll component, in the File tag, remove KeyPath="yes" and instead replace that with CompanionFile="<NameOfAnotherFileID>".
The issue with this approach is that you may have a corrupted DLL but the companionFile it was linked to was fine so it is not reinstalled.
If this is a dll you do own, I would highly suggest versioning the file! Give it any version you want and this issue should go away.
Another thing you can try, although I don't know how it works really, is giving the file a DefaultVersion
This is the default version of this file. The linker will replace this value from the value in the file if the suppress files option is not used.
This would be the quickest solution to verify. Just build a new installer with DefaultVersion="1.0" in the estimator.dll's <File> and see if it gets replaced. I think this will have the installer think the file is versioned 1.0 but the installed file is not versioned so it will replace it (see here)

How to work with HEAT.exe for dll registry

and i need to register a dll . Right now am registering the dll as below
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Impersonate='no' Execute='deferred'
ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
but all are suggesting to use HEAT.exe in internet wherever and whenever i surf . I even have gone through this link. But there they have only the syntax etc. I really dont know how to work with it just by knowing those syntax.
I need some step by step procedure or some good blog which elaborately tell how how to harvest a dll and how to impllement it in to wix code and how the registry will be done , so that i can register my dll based on conditions also.Even i tried this link alse
Regards
Registering a COM component is done through standard Windows Installer actions and tables. Numerous table entries are required so WiX provides heat.exe to harvest COM files. It works by inspecting a file for type libraries and, if the DllRegisterServer entry point is present, running it in a Registry sandbox where changes are intercepted and captured. (In the era of Windows Installer [1999-present], DllRegisterServer is effectively deprecated for any other purpose.)
As you may know, a Feature is the smallest user-selectable unit of installation. A Component is a member of one or Features in one or more Products. Heat creates a component for each file it harvests and a ComponenentGroup for each harvest run. So, you have to pick a ComponentGroup Id and reference it in one or more Features. You also have to pick a Directory Id for the destination of the ComponentGroup.
Now, it is simply a matter of editing your project file to harvest the file. To edit a project file you could use a text editor but Visual Studio is all set up for it. See How to: Edit Project Files.
Add a HarvestFile element to a new or existing ItemGroup, entering the desired ComponentGroup Id and Directory Id
<ItemGroup>
<HarvestFile Include="comserver.dll">
<ComponentGroupName>COM</ComponentGroupName>
<DirectoryRefId>ServerDir</DirectoryRefId>
</HarvestFile>
</ItemGroup>
In your Product.wxs or elsewhere, add a ComponentGroupRef to one or more Features.

WiX Bundle with dynamic MsiPackage names

I'm converting our current monolithic installer to use a WiX 3.7 Bundle/chain. We have several components that are now building into their own separately-maintainable MSI installers. My next task is to add all of these to a bootloader/bootchainer, but I've hit a snag.
A requirement for our individual installers is that they contain the version in the filename (i.e. MyApplication-5.4.22.msi). I don't see a tool like Heat for collecting MSI packages together, and I don't see a way to add an MsiPackage element with a wildcard to account for varying package names.
As a last resort, I can wrap the bundler inside of another MSBuild script that will 'autocomplete' the filenames and pass the paths in as variables to the bundler. I'm hoping someone can recommend a solution that works directly in the wxs or wixproj setting.
If the msi files are built with WiX Setup projects, the WiX Bootstrapper project can reference them, thereby creating useful WiX variables that are defined as the paths to the msi files.
See my answer here, as well as the list of variables here.
If that's not the case then you can write some MSBuild targets that run before the Build target to figure out the actual file paths. If the available standard and community MSBuild tasks aren't sufficient, you can write your own tasks, either by creating an assembly or using inline code. (And, of course, there is always the Exec task to shell out to a command-line program like cmd.exe, after which you can parse its output to extract the msi paths.)

Copy file using Burn

I am using WiX Burn to make my installer, i am bundling one exe and one msi.
And the exe needs an properties file at the time of install.
Is there a way to copy the file using burn, i tried Payload but it is not working.
Can i know the location throguh any Bundle variable where my file is copied.
Thanks
Ravi S
Make sure you are specifying the properties file as the payload for the exe and not for the bootstrapper. For example, in your bundle, your chain may look something like this:
<Chain>
<MsiPackage SourceFile="MyInstaller.msi" Id="MyInstaller" Cache="yes"/>
<ExePackage SourceFile="MyExe.exe" Id="MyExe" Cache="yes">
<Payload SourceFile="OtherFile.properties" Id="Properties"/>
</ExePackage>
</Chain>
Also, as a sanity check, which version of WiX are you using? If you are using an older build (such as RC0), you could try updating to the latest weekly build.
Update:
In WiX 3.6 it does not appear that you can get the absolute path of a payload file. There are two bugs/feature request open right now regarding the issue that are deferred to WiX 3.7:
Add burn variable to cache path - ID: 3557446
Change working folder to the cache folder - ID: 3538846
One workaround would be to use burn to write your own bootstrapper application and then programmatically determine the working directory and set the appropriate parameters, but that would be a lot of work for this one issue.

Dealing with env specific files using WIX

I am in the process of migrating all my projects one by one from Installshield to Wix and I would like to find out the best way to deal with env specific files.
Our current process is:
Using Installshield we create a base MSI and a Transform file which would install the base MSI and a directory structure with files present in the current directory. Ofcourse in my source control, I have separate config files for different environments and my Deployment script picks up the right set of files and puts them in a staging location.
For example, Current dir looks like as follows:
sample.msi
sample.mst
test\apps\docs\global.config
test\files\docs\global.config
sample.msi gets installed and the above directory structure gets copied to the target location.
During Uninstall the directory structure gets removed as well.
I tried to recreate this behavior using CopyFile element but during uninstall the copied files stay and do not get removed. Is there another way to achieve this?
I understand the way we do our packaging might not be the best way to get around our requirements. If someone has a better way to do this, please let me know.
I am still very new to Wix and I haven't looked at any of the wix extensions so wouldn't know what else is out there.
As always, any help is greatly appreciated.
Do these files really have to be seperate from the msi?
Using wix you could put them all into the msi and install them based on certain conditions like settings properties or using a custom action. Doing it that way should make it rather easy to let the msi create the directories and copy the files, and also remove them when uninstalling.
Conditions would work like this:
<Component Id='MyComponent' Guid='PUT-GUID-HERE'>
<Condition><![CDATA[YOUR-PROPERTY = "SOME_STRING"]]></Condition>
<File Id='readme' Name='readme.txt' DiskId='1' Source='readme.txt' />
</Component>
A CustomAction in Wix can be a .net dll, the manual explains how this is done here:
Adding Custom Actions
IF you have the WIX Toolkit installed you just need to create a Custom Action Project.