Wix install location - wix

I have a WIX setup that allows the user to select the install location. When uninstalling, I need to run a custom action that should activate a file in the install location. I tried getting the install location from session["INSTALLDIR"] but it results in the default path and not the one given by the user.
How can I reach that location?

I've done this in my own installer - the following should work.
This adds a property to retrieve the install location value from the registry.
<Property Id="INSTALLDIR">
<RegistrySearch Id='Registry' Type='raw' Root='HKCU' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>
This sets the install location in the registry.
<Component Id="Registry" Guid="*">
<RegistryKey Root="HKCU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
<RegistryValue Name="Location"
Type="string"
Value="[INSTALLDIR]"
Action="write"
KeyPath="yes" />
</RegistryKey>
<util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />

If you want INSTALLDIR for a later time such as uninstallation you should use Remember property pattern described in link below.
"The root issue is that the Windows Installer does not save Property values for you. That means if the user enters values in the install UI or passes them on the command-line, those values will be not be present during repair, upgrade nor uninstall."
http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/

Related

Windows Installer not deleting all files on uninstall

I've seen some similar questions asked on here, but none of the solutions given were very clear or worked for me.
I have an installer (created with WiX) which installs certain files and folders. However, when running the installed application, this creates some folders and copies some files into it. These files and folders are not removed on uninstall.
Edited to Show Code so Far:
This INSTALLDIR property:
<Property Id="INSTALLDIR">
<RegistrySearch Id='Registry' Type='raw' Root='HKLM' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>
This Component which should set the install location in the registry:
<Component Id="Registry" Guid="*">
<RegistryKey Root="HKMU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
<RegistryValue Name="Location"
Type="string"
Value="[INSTALLDIR]"
Action="write"
KeyPath="yes" />
</RegistryKey>
<util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />
</Component>
This does create a record in the registry with the install location, but I'm not sure how to adapt this code to making note of the 'public' directory and removing it - I don't know where the util:RemoveFolderEx should go either (inside which component)
The clearest tutorial I've seen is this one (except that it does have an apparent error).
Replace this block:
<!--
RemoveFolderEx requires that we "remember" the path for uninstall.
Read the path value and set the APPLICATIONFOLDER property with the value.
-->
<Property Id="APPLICATIONFOLDER">
<RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>
with this one:
<!--
RemoveFolderEx requires that we "remember" the path for uninstall.
Read the path value and set the FOLDERTOREMOVE property with the value.
-->
<Property Id="FOLDERTOREMOVE">
<RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>
and this block:
<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
with this one:
<util:RemoveFolderEx On="uninstall" Property="FOLDERTOREMOVE" />
and you should have a working test.
The reason for using two different properties is given here and here (among with other places).
If you can derive the path from other values you may have set during installation that Windows Installer will preserve for you, such as ARPINSTALLLOCATION, then you can adjust the above implementation to get what you need without having to create your own registry keys.
Builds on B. Murri's answer:
Example: your application installs new files or folders in 'installdir/public'. These files aren't being deleted as they weren't added by the installer.
First, you need to create a registry value which will store where your public directory is installed. This is in case the user changes the install directory.
<!-- Note that the RegistryValue Value is being set to the 'public' directory ID -->
<DirectoryRef Id='INSTALLDIR'>
<Component Id="RemovePublicDir" Guid="your-guid-here">
<RegistryKey Root="HKCU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
<RegistryValue Name="Location"
Type="string"
Value="[PUBLIC]"
Action="write"
KeyPath="yes" />
</RegistryKey>
<CreateFolder Directory="PUBLIC"/>
<util:RemoveFolderEx Property="FINDPUBLICDIR" On="uninstall"/>
<RemoveFolder Id="PUBLIC" On="uninstall"/>
</Component>
</DirectoryRef>
You now need to add a property which will search for this registry value later on. Make sure your Root value above matches the one below:
<Property Id="FINDPUBLICDIR">
<RegistrySearch Id='Registry' Type='raw' Root='HKCU' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>
Add your manufacturer name and product name to variables, like this:
<?define Manufacturer = "My Company"?>
<?define ProductName = "Test Application"?>
Now make sure you call this Component in your Feature tag:
<Feature Id="FeatureId">
<ComponentRef Id="RemovePublicDir" />
</Feature>

Wix - Get user input to create a registry entry

I need to create an installer that gets the user input to create a registry entry. I've looked into Wix tutorials and it's very clear how to install registry entries but I need the user to give some info(in this case it's an url) so that url can be used on the registry entry.
How can I do this?
Duplicate question!?
Please take a look at this answer if it helps: https://stackoverflow.com/a/20679626/1331719
Edit - slightly modifying the answer found in the link:
Start by adding this component, notice the property in Value [USERINPUT]
<DirectoryRef Id="INSTALLDIR">
<Component Id="RegistryEntries" Guid="{YOURGUID}">
<RegistryKey Root="HKLM" Key="Software\Company123\App123" Action="create">
<RegistryValue Type="string" Name="UserInput" Value="[USERINPUT]" />
</RegistryKey>
</Component>
</DirectoryRef>
Reference the component in your feature:
<Feature>
<ComponentRef Id="RegistryEntries" />
...
</Feature>
Get user input when you install using msiexec:
msiexec /i your.msi /qb+ USERINPUT="http://urlYouWantToStoreIn.Registry"
Check registry HKLM\Software\Company123\App123\UserInput, the url should be there.

Using WiX, how to skip a component when a certain registry key does not exist?

I want to copy some files into a directory in another product's installation tree, but only if that product is installed. So I figured I could set a property based on a registry search to find that product's installation root. Then I could use the property in a condition element on the component element.
Here is my code. For some reason, I am getting an error when the other product is not installed and the registry search comes up empty since the registry key will not be found.
<Property Id="PRODUCTPATH">
<RegistrySearch Id="PRODUCTPATH" Root="HKLM" Key="_MY_KEY_" Name="_MY_NAME_" Type="raw" />
</Property>
<SetProperty Id="PRODUCTBINPATH" Value="[PRODUCTPATH]\BIN" After="AppSearch"/>
<Component Id="CommonDLLs" Guid="_MY_GUID_" Directory="INSTALLLOCATION">
<Condition>PRODUCTPATH</Condition>
<RegistryValue Id="_MY_ID_" Root="HKLM" Key="_MY_KEY_2" Name="Installed" Value="1" Type="integer" KeyPath="yes" />
<CopyFile Id="myfile1.dll" FileId="myfile1.dll" DestinationProperty="PRODUCTPATH" DestinationName="myfile1.dll"/>
<CopyFile Id="myfile2.dll" FileId="myfile2.dll" DestinationProperty="PRODUCTPATH" DestinationName="myfile2.dll"/>
</Component>
Try to use the util:RegistrySearch instead of RegistrySeach
This element comes with Util Extension. Check here if you don't know how to use extensions.
The util:RegistrySearch has an attribute (Result) for only checking if the key exists or not.
It would be like that:
<util:RegistrySearch
Id="PRODUCTPATH"
Variable="PRODUCTPATH"
Root="HKLM"
Key="_MY_KEY_"
Format="raw"
Result="exists">
Actually, all you have to do is add a condition to the SetProperty element like this:
<Property Id="PRODUCTPATH">
<SetProperty Id="PRODUCTBINPATH" Value="[PRODUCTPATH]\BIN" After="AppSearch">PRODUCTPATH</SetProperty>

Wix registry editing not displayed in the msi log

I've been working on a WIX .net project that needs to update a Microsoft registry entry to work correctly. While testing the logic, I found it difficult to debug the WIX components that updates the registry via the MSiexec.exe command line /log options. To verify the correct behaviour, I had to check the registry value manually. How do I force the WIX project to log the registry search and update logic from the following fragment in the MSI log output?
<util:RegistrySearch Id="Office2013RegistySearch"
Root="HKLM"
Key="SOFTWARE\Microsoft\Office\15.0\Access Connectivity Engine\Engines\Excel"
Value="TypeGuessRows"
Variable="Office2013GuessRowsx86Exist"
Win64="no"
Result="exists" />
<Component Id="Office2013GuessRowsx86RegComponent" Guid="CFE579F9-292A-4777-A671-B5E8E330B1A0" Win64="no">
<Condition>Office2013GuessRowsx86Exists</Condition>
<RegistryKey Root="HKLM"
Key="SOFTWARE\Microsoft\Office\15.0\Access Connectivity Engine\Engines\Excel" ForceDeleteOnUninstall="no">
<RegistryValue Type="integer" Name="TypeGuessRows" Value="0"/>
</RegistryKey>
</Component>
Try use full log
msiexec /i "dotnetproject.msi" /L*v "log.log"
or add <Property Id="MsiLogging" Value="voicewarmup"/> (for full log too)

different shortcut behavior during unattended installation

I am trying to create a Start Menu shortcut. This is the code I'm using:
<Fragment>
<SetProperty Id="MIFOLDER" Value="[INSTALLFOLDER]\MI" Before="CostFinalize"></SetProperty>
<!-- Start menu -->
<Icon Id="iconCMD" SourceFile="$(var.SharedComponents.ProjectDir)Images\Icons\cmd.ico" />
<DirectoryRef Id="STARTMENUFOLDER">
<Component Id="cmp211060161C737F50377C120FF39D7623" Guid="{E7B9FB15-4A1D-4E3E-BCDE-EB2E5638C452}" Win64="yes">
<Shortcut Id="shrtct211060161C737F50377C120FF39D7623" Name="Management Interface (MI)"
Target="[System64Folder]\cmd.exe" Icon="iconCMD" Arguments='/k "title Managment Command Line Interface (MI)"' WorkingDirectory="MIFOLDER" />
<RegistryValue Root="HKCU" Key="Software\$(var.Manufacturer)\VB\Installer\$(var.ProductName)\MI"
Name="MI" Type="string" Value="$(var.VersionNumber)" KeyPath="yes" />
<RemoveFolder Id="rem211060161C737F50377C120FF39D7623" On="uninstall"/>
</Component>
</DirectoryRef>
</Fragment>
I want this shortcut to run Command Line Interface and start it in installation folder.
When running the setup normally, it indeed works fine and all well.
When I'm installing with /q (unattended), and after installation I click the shortcut, and it leads to Windows\system32 directory and not working directory. When I look at shortcut properties, I see that it set to start at \MI as SetProperty action doesn't take place.
Any help and ideas why?
InstallUISequence will be skipped in silent installation. Use Sequenceattribute to run the SetProperty action as per your requirement(both or first).