I'm using Wix 3.9 and Wix-edit 0.7.5/Notepad++ to create a MSI installer for my application. I want to create an uninstall shortcut inside the installed folder. For instance:
C:\MySoftware\Uninstall.lnk
I tried a few things, but in all cases when I uninstall the software through that link, the program folder C:\MySoftware is not deleted. Uninstalling every other way works as expected.
First I tried to create it as a Component inside the <Directory> tag. Looks to me a bit hacky, because I must add <CreateFolder>:
<Directory Id="MYINSTALLDIR" Name="MySoftware">
<!-- my files... -->
<Component Id="ABC" Guid="PUT-GUID-HERE">
<CreateFolder/> <!-- have to add this -->
<Shortcut Id="UninstallProduct" Name="Uninstall MySoftware" Description="Uninstalls MySoftware" Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]"/>
</Component>
</Directory>
<Feature Id="DefaultFeature" Title="Main Feature" Level="1">
<!-- some references... -->
<ComponentRef Id="ABC" />
</Feature>
I also tried replacing <CreateFolder/> with <RemoveFolder Id="MYINSTALLDIR" On="uninstall" />, same results.
Another try:
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="StartMenuShortcuts" Guid="*">
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" />
<Shortcut Id="UninstallProduct1" Name="Uninstall MySoftware" Description="Uninstalls MySoftware" Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]"/>
<Shortcut Id="UninstallProduct2" Name="Uninstall MySoftware" Description="Uninstalls MySoftware" Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]" Directory="MYINSTALLDIR" />
</Component>
</DirectoryRef>
Here, besides having the same results, I get a warning when building: file.wxs(31) : warning LGHT1076 : ICE57: Component 'StartMenuShortcuts' has both per-user and per-machine data with an HKCU Registry KeyPath..
How do I create a shortcut that can be used without affecting the uninstall behavior? I don't know if it makes a difference, but I need this to work without Admin privileges (I'm using <Package ... InstallScope="perUser" InstallPrivileges="limited">).
I know I could just create a .lnk file and add it to the project, but I prefer not to, because then I'd have to worry about updating its GUID on every project.
The problem occurs because you didn't set the working directory for the msiexec and then it will use the current directory, raising error 2911 (Could not remove the folder).
Add the reference to WindowsFolder:
<Directory Id="MYINSTALLDIR" Name="MySoftware">
...
<Directory Id="WindowsFolder" Name="WindowsFolder" />
</Directory>
And then modify your shortcut adding the attribute WorkingDirectory="WindowsFolder":
<Shortcut Id="UninstallProduct" Name="Uninstall MySoftware"
Description="Uninstalls MySoftware" Target="[System64Folder]msiexec.exe"
Arguments="/x [ProductCode]" WorkingDirectory="WindowsFolder" />
Related
I am using Wix 3.11 and have tried a number of different ways and methods and can't seem to be able to figure out why Wix isn't removing my ApplicationDataFolder folder. During install I create the folder in the ApplicationDataFolder location for the user.
My application uses logging and stores it along with a few other things in the directory. During uninstall everything in the application folder is removed but the appdata folder with the logs and other files are left untouched.
I can't figure out why or what I am missing.
WXS Template
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" UpgradeCode="9e578e3d-0119-425c-8633-f54ffaaa4929" Name="#product.name#" Version="#product.version#" Manufacturer="#product.company#" Language="1033">
<Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" Comments="#product.version#" Description="#product.description#"/>
<Media Id="1" Cabinet="SomeApp.cab" EmbedCab="yes" />
<!-- Installer Properties -->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<PropertyRef Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED"/>
<!-- Installer Resources -->
<Icon Id="ApplicationIcon" SourceFile="SomeApp 4\SomeApp 4_vista.ico"/>
<Property Id="ARPPRODUCTICON" Value="ApplicationIcon" />
<Property Id="INSTALLDIR">
<RegistrySearch Key="SOFTWARE\Acme\SomeApp"
Root="HKCU" Type="raw"
Id="APPLICATIONFOLDER_REGSEARCH" Name="installation-path" />
</Property>
<WixVariable Id="WixUILicenseRtf" Value="SomeApp 4\license.rtf" />
<WixVariable Id="WixUIBannerBmp" Value="WixUIBannerBmp.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="WixUIDialogBmp.bmp" />
<!-- Check Existing Install -->
<Upgrade Id="9e578e3d-0119-425c-8633-f54ffaaa4929">
<UpgradeVersion Minimum="#product.version#" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="0.0.0" Maximum="#product.version#" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED"/>
</Upgrade>
<Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>
<!-- Prerequisites -->
<Condition Message="This application requires .NET Framework 4.6 or newer. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED]]>
</Condition>
<Condition Message="This application requires at least Windows 7 or Windows Server 2008 R2. Please upgrade your computer to a supported operating system and run this installer again.">
<![CDATA[Installed OR (VersionNT >= 601)]]>
</Condition>
<!-- Define the directory structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="ProgramFiles">
<Directory Id="INSTALLDIR" Name="#product.company#">
#product.applicationfiles#
#product.servicefiles#
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="#product.name#"/>
<Directory Id="ServiceProgramsFolder" Name="#product.name#"/>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
<Directory Id="LocalAppDataFolder">
<Directory Id="ApplicationDataFolder" Name="Acme" />
</Directory>
</Directory>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="1e578e4d-0229-425c-8633-f54ffaaa4901">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="SomeApp 4.6"
Description="#product.company# #product.name# #product.version#"
Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
WorkingDirectory="INSTALLDIR"
Icon ="ApplicationIcon"/>
<Shortcut Id="ApplicationStartMenuShortcut2"
Name="SomeApp 4.6 (Multiple Instances)"
Description="#product.company# #product.name# #product.version#"
Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
Arguments="MultipleInstance=True"
WorkingDirectory="INSTALLDIR"
Icon ="ApplicationIcon"/>
<Shortcut Id="ApplicationStartMenuShortcut3"
Name="SomeApp 4.6 (Notifications)"
Description="#product.company# #product.name# #product.version#"
Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
Arguments="Notifications=True"
WorkingDirectory="INSTALLDIR"
Icon ="ApplicationIcon"/>
<Shortcut Id="HelpStartMenuShortcut"
Name="SomeApp 4.6 Help"
Target="[INSTALLDIR]SomeApp 4\Documentation\SomeApp.chm"
WorkingDirectory="INSTALLDIR"/>
<Shortcut Id="UninstallProduct"
Name="Uninstall SomeApp 4.6"
Target="[SystemFolder]msiexec.exe"
Arguments="/x [ProductCode]"
Description="Uninstall #product" />
<Shortcut Id="desktopshortcut"
Directory="DesktopFolder"
Name="SomeApp 4.6"
WorkingDirectory="INSTALLDIR"
Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe" />
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<util:RemoveFolderEx On="uninstall" Property="ApplicationDataFolder" />
</Component>
</DirectoryRef>
<DirectoryRef Id="ServiceProgramsFolder">
<Component Id="ServiceShortcut" Guid="9e578e3d-0229-425c-8633-f54ffaaa4901">
<Shortcut Id="ServiceStartMenuShortcut"
Name="#product.name# Reporting Service"
Description="#product.name# Reporting Service"
Target="[INSTALLDIR]Reporting\SomeApp.ReportingService.exe"
WorkingDirectory="INSTALLDIR"
Icon ="ApplicationIcon"/>
<RemoveFolder Id="ServiceProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\Acme\SomeApp" Name="service-installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="INSTALLDIR">
<Component Id="CleanupMainApplicationFolder" Guid="*">
<RegistryValue Root="HKCU" Key="SOFTWARE\Acme\SomeApp" Name="installation-path" Type="string" Value="[INSTALLDIR]" KeyPath="yes" />
<util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />
<util:RemoveFolderEx On="uninstall" Property="ApplicationDataFolder" />
</Component>
</DirectoryRef>
<!-- Feature: SomeApp Application -->
<Feature Id="Feature.Application"
Title="SomeApp 4 - Application"
Description="SomeApp is an asset management and maintenance application designed to optimize asset value and improve manufacturing productivity."
ConfigurableDirectory="INSTALLDIR"
Level="1"
AllowAdvertise="no">
#product.applicationcomponents#
<ComponentRef Id="ApplicationShortcut" />
<ComponentRef Id="CleanupMainApplicationFolder" />
</Feature>
<!-- Feature: Reporting Service -->
<Feature Id="Feature.Service"
Title="SomeApp 4 - Reporting Service"
Description="This service generates and delivers reports that have been scheduled in the SomeApp Maintenance Management System."
ConfigurableDirectory="INSTALLDIR"
Level="3"
AllowAdvertise="no">
#product.servicecomponents#
<ComponentRef Id="ServiceShortcut" />
<Component Id="ReportingServiceInstaller" Guid="B72CAA3F-F2DB-48D2-90DD-061209AB2CE5" Directory="INSTALLDIR">
<CreateFolder />
<File Id="ReportingService.exe" Name="ReportingService.exe" KeyPath="yes" Source="#product.sourcedir#\Reporting\SomeApp.ReportingService.exe"/>
<ServiceInstall Id="ReportingServiceInstaller"
Type="ownProcess"
Vital="yes"
Name="SomeApp Reporting Service"
DisplayName="SomeApp - Reporting Service"
Description="This service generates and delivers reports that have been scheduled in the SomeApp Maintenance Management System."
Start="auto"
Account="NT AUTHORITY\LocalService"
ErrorControl="ignore"
Interactive="no" />
</Component>
</Feature>
<CustomAction Id="Cleanup_logfile" Directory="INSTALLDIR"
ExeCommand="cmd /C "rmdir %LOCALAPPDATA%\Acme /s /q""
Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="Cleanup_logfile" After="RemoveFiles" >
REMOVE="ALL"
</Custom>
</InstallExecuteSequence>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate"/>
</InstallExecuteSequence>
<UIRef Id="WixUI_FeatureTree" />
<UI>
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<!-- Add the GUI logic for installation -->
</UI>
</Product>
</Wix>
I have one project that uses util:RemoveFolderEx where it is working properly. The only difference I can see is that I explicitly set a property at runtime to the value of the install directory. My guess is that "INSTALLDIR" and "ApplicationDataFolder" are not actually properties since they are stored in the Directory table of your msi and not the property table. (Checked using ORCA)
Try doing
<SetProperty Id='AcmeAppDataFolderToRemove' Value='[ApplicationDataFolder]' After='AppSearch'/>
and then change your util:RemoveFolderEx to
<util:RemoveFolderEx On="uninstall" Property="AcmeAppDataFolderToRemove" />
and see if that works. (You might need to use Value='ApplicationDataFolder' without the []'s not sure.)
In response to your edit I went and looked at the RemoveFolderEx page and this looks important
The custom action that implements RemoveFolderEx does so by writing temporary rows to the RemoveFile table for each subfolder of the root folder you specify. 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.
I figured setting it to the directory would work but apparently these directories don't have values yet when RemoveFolderEx action actually executes. So, when this tries to resolve the properties or set the properties they are actually just empty.
A difference in what I said my installer does and what it actually does is that I get the value I set the property to through a RegistrySearch.
<Property Id="INSTALLDIR">
<RegistrySearch
Id='InstallDirRegistrySearch'
Type='raw'
Root='HKLM'
Key='SOFTWARE\$(var.OEMRegistryRootKeyName)'
Name='SDKPath' />
</Property>
<SetProperty Id='SDKFolderToRemove' Value='[INSTALLDIR]\$(var.OEMProduct) SDK' After='AppSearch'/>
So I would try writing the appdata dir to a registry key and getting the value into a property via registry search then using that property in your removefolderex, you probably don't need the setproperty, I just used it because I needed a folder under INSTALLDIR but in your case you can just have the registry key be the right folder.
I have been struggling with Wix for the last couple of days, probably read 15 guides around the web so far trying to make it working on my real application, but no luck.
I used a small and simple other project to practice and make sure I understand and do every thing right.
Following this guide I managed to got it to work, the next stage was trying to add the content of the directory to the installation since it holds many files that I dont want to add by hand.
So following this guide I used heat.exe to harvest the content of the folder, I got the heat to create the .wxs that I needed but next is trying to add its content to my Product.wxs file.
Problem is that it says I should add this:
<!-- Add ComponentGroupRef to existing Feature, or create new one -->
<!-- Notice the IDs & what we used in heat -->
<Feature Id="ProductFeature" Title="Main product" Level="1">
<ComponentGroupRef Id="ConfigurationUtilityComponents"/>
</Feature>
<Fragment>
<Directory Id="INSTALLDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ConfigurationUtilityDir" Name="ConfigurationUtility" />
</Directory>
</Directory>
</Fragment>
to my Product.wxs file , but I cant seem to figure out how to do it.
Can any one please help?
Here is my Product.wxs file:
<Product Id="8748CF04-E8D3-4A2B-B3F5-22E50B3A8E49"
Name="MyApp" Language="1033" Version="1.0.0.0" Manufacturer="My System Pvt Ltd"
UpgradeCode="8748CF04-E8D3-4A2B-B3F5-22E50B3A8E49">
<Package Id="*" InstallerVersion="200" Compressed="yes" InstallScope="perMachine"
InstallPrivileges="elevated" ReadOnly="yes"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<!--Add Cab1.cab File inside the Package-->
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" />
<!--Here We Install Our Main App-->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="MY System Pvt Ltd"/>
</Directory>
<!-- Step 1: For the Program Menu -->
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="My System Pvt Ltd"/>
</Directory>
<!--Step 2:For Desktop Folder-->
<Directory Id="DesktopFolder"/>
<!--Step 3:For StartUp Folder-->
<Directory Id="StartupFolder"/>
</Directory>
<!--Step 4 :Add Main App exe-->
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="myapplication.exe" Guid="84C5B9E8-FD90-4EA8-A502-B08AC9B38D39">
<File Source="$(var.WpfApplication2.TargetPath)" Name="MYApp.exe"
Id="MyAppEXE" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!-- Step 1.1: Add the shortcut to your installer package Program Menu or Start Menu-->
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="1A437020-D5C9-450C-9B3D-33957994780A">
<!--Add Shortcut of the Application in start Menu-->
<Shortcut Id="ApplicationStartMenuShortcut" Name="MyApp" Description="My Application Description"
Target="[INSTALLFOLDER]MyApp.exe" WorkingDirectory="INSTALLFOLDER">
<!--Add Icon to the ShortCut-->
<Icon Id="MYPMenuIcon" SourceFile=".\Desktop.ico" />
</Shortcut>
<!--Remove the Folder At time of Uninstall-->
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key='Software\[Manufacturer]\[ProductName]'
Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!-- Step 2.1: Add the shortcut to your installer package For DeskTop-->
<DirectoryRef Id="DesktopFolder">
<Component Id="ApplicationDeskShortcutComp" Guid="40127963-856D-460D-9E1B-4C10EB65835B">
<Shortcut Id="ApplicationDeskShortcut" Name="MYAppDesk"
Description="My Application Description" Target="[INSTALLFOLDER]MyApp.exe"
WorkingDirectory="INSTALLFOLDER">
<Icon Id="MYDeskIcon" SourceFile=".\Desktop.ico" />
</Shortcut>
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key='Software\[Manufacturer]\[ProductName]'
Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!--Step 3.1: add Shortcut to StartUp Folder to run application when you login-->
<DirectoryRef Id="StartupFolder">
<Component Id="ApplicationStartUpShortcutComp" Guid="843B6A2E-AB61-40C7-BE49-FBCD7F81E35D">
<Shortcut Id="ApplicationStartUpDeskShortcut" Name="MYAppDesk" Description="My Application Description"
Target="[INSTALLFOLDER]MyApp.exe" WorkingDirectory="INSTALLFOLDER">
<Icon Id="MyIconStartUp" SourceFile=".\Desktop.ico" />
</Shortcut>
<RemoveFolder Id="StartupFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key='Software\[Manufacturer]\[ProductName]'
Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!--Add Component-->
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentRef Id="myapplication.exe" />
<!--Step 1.2:Add Start menu or program Shortcut-->
<ComponentRef Id="ApplicationShortcut" />
<!--step 2.2Add DeskTop Shortcut-->
<ComponentRef Id="ApplicationDeskShortcutComp" />
<!--step 3.2Add DeskTop Shortcut-->
<ComponentRef Id="ApplicationStartUpShortcutComp"/>
<ComponentRef Id="dotNetClass.Output" />
<!--<ComponentRef Id="AU" />-->
</Feature>
</Product>
I kind of get where your coming from, I tried to link my Heat produced code to the product .wxs file.. What I did is, add the heat source code (.wxs) file to your project..
on the first Component group, Note down the name e.g
<ComponentGroup Id="SampleGroup">
Then in this section
<Feature Id="ProductFeature" Title="Random Desktop" Level="1">
<ComponentGroupRef Id="SampleGroup" />
</Feature>
</Product>
Make sure both names match, where it says "SampleGroup"
With Wix, I've figured out how to register file associations with ProgId but in Explorer, when you click on "Open with..." or "Choose Program...", I just see my apps EXE filename.
How do I change it to show my apps name without the EXE file extensions?
Also, I noticed other registered apps have info such as the company name in grey under their app's name (such as Microsoft or Document Foundation as shown in pics below). How is that added?
Here are some pics:
And here is my full wix.xml:
<Icon Id="icon.ico" SourceFile="jedit.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.ico"/>
<!-- Step 1: Define the directory structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="jedit"/>
</Directory>
<Directory Id="ProgramMenuFolder">
</Directory>
</Directory>
<!-- Step 2: Add files to your installer package -->
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="appfiles" Guid="{E73254A5-EFE2-4265-A231-B907FEF4B4C4}">
<File Id="jedit.jar" Source="jedit.jar"/>
<File Id="javaforce.jar" Source="javaforce.jar"/>
<File Id="jedit32.exe" Source="jedit32.exe" KeyPath="yes"/>
<File Id="jedit64.exe" Source="jedit64.exe"/>
<ProgId Id="jfEdit.txt" Description="Text Document" Advertise="yes" Icon="icon.ico">
<Extension Id="txt" ContentType="text/plain">
<Verb Id="open" Command="Open" Argument=""%1"" />
</Extension>
</ProgId>
<ProgId Id="jfEdit.ini" Description="Configuration Settings" Advertise="yes" Icon="icon.ico">
<Extension Id="ini" ContentType="text/plain">
<Verb Id="open" Command="Open" Argument=""%1"" />
</Extension>
</ProgId>
<ProgId Id="jfEdit.properties" Description="Properties" Advertise="yes" Icon="icon.ico">
<Extension Id="properties" ContentType="text/plain">
<Verb Id="open" Command="Open" Argument=""%1"" />
</Extension>
</ProgId>
</Component>
</DirectoryRef>
<!-- Step 2b: Add the shortcut to your installer package -->
<DirectoryRef Id="ProgramMenuFolder">
<Component Id="ApplicationShortcut" Guid="{A986E325-13AB-4FD1-AB3B-4637DF9BC1D9}">
<Shortcut Id="ApplicationStartMenuShortcut" Name="jfEdit" Description="Java Text Editor" Target="[APPLICATIONROOTDIRECTORY]jedit32.exe"
WorkingDirectory="APPLICATIONROOTDIRECTORY"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\jfEdit" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!-- Step 3: Tell WiX to install the files -->
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentRef Id="appfiles" />
<ComponentRef Id="ApplicationShortcut" />
</Feature>
Take a look at this response from #saschabeaumont that should contain quite all registry keys involved. The name displayed in the Open with...-dialog be the registry key with the name FriendlyAppName. The one displayed in the Open with... context menu entry of a file is in the registry key
HKLM\SOFTWARE\Classes\<YourProgId>\shell\open\FriendlyAppName
I've found those two to be different, however just hacked my registry. It could be that if you use the whole example of the linked answer that it will work perfectly.
The second line is AFAIK the Manufacturer-property in Windows Installer. As soon as the application is registered properly it should also be shown in the Open with... dialog.
I have an app that is being installed with WiX 3 - most of the install works fine by now, but trying to get the desktop shortcut to work seems to cost me my mind...
I have my app being installed and I already have a shortcut on the Start Menu folder - works just fine. But how do I get the desktop shortcut up and running?
<Product Id="*" Name="....." UpgradeCode="MY-GUID">
<Package Id="*" InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="foobar.cab" EmbedCab="yes" />
<Property Id="ALLUSERS">1</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="FooBar"/>
</Directory>
<Directory Id="DesktopFolder" SourceName="Desktop"/>
<Directory Id="ProgramFilesFolder">
<Directory Id="FoobarDir" Name="FOOBAR">
<Directory Id="INSTALLLOCATION" Name="FooApp">
<Component Id="MainFiles" Guid=".....">
<File Id="FooMainApp" Source="FooMainApp.exe" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
....
<!-- this shortcut here works just fine ... -->
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="AppShortcut" Guid="...">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="FooBarApp" Description="..."
Target="[INSTALLLOCATION]FooMainApp.exe"
WorkingDirectory="INSTALLLOCATION"/>
</Component>
</DirectoryRef>
<!-- but this shortcut here never seems to work .. ... -->
<DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcut" Guid="....." >
<Shortcut Id="DesktopAppShortcut"
Advertise="no"
Name="FooBarApp" Description="...."
Target="[INSTALLLOCATION]FooMainApp.exe"
WorkingDirectory="INSTALLLOCATION"/>
</Component>
</DirectoryRef>
The errors I keep getting are:
ICE18: KeyPath for Component:
'DesktopShortcut' is Directory:
'DesktopFolder'. The
Directory/Component pair must be
listed in the CreateFolders table.
ICE38: Component DesktopShortcut
installs to user profile. It must use
a registry key under HKCU as its
KeyPath, not a file.
ICE43: Component
DesktopShortcut has non-advertised
shortcuts. It should use a registry
key under HKCU as its KeyPath, not a
file.
I do not understand what on earth WiX 3 / Windows Installer is trying to tell me here.... anyone??
Both components, AppShortcut and DesktopShortcut, are in fact part of the "main" feature - I don't see any issue there. I can't figure out what on earth could be wrong here....
Update: ok, so I added some registry key stuff to my desktop shortcut
<Component Id="DesktopShortcut" Guid="BF3587B4-F52E-411E-8814-CFCBF8201C0D">
<RegistryKey Root="HKCU" Key="Software\Foo Inc\FooBarApp\Installed"
Action="createAndRemoveOnUninstall">
<RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes"/>
</RegistryKey>
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder"
Name="FooBar" WorkingDirectory="INSTALLLOCATION"
Icon="foobar.ico"
Target="[INSTALLOCATION]FooMainApp.exe"/>
</Component>
now the ICE messages are gone, but when I try to install the app, I get Error 1909 - the target folder doesn't exist, or you do not have permission to write to it (or something like that)
Update 2: the above sample code provided does work on Win XP, but it keeps failing on Win Server 2003 :-( Any further ideas??
Here's a working example from our live production code...
<Fragment>
<Component Id="DesktopShortcut" Directory="APPLICATIONFOLDER" Guid="*">
<RegistryValue Id="RegShortcutDesktop" Root="HKCU"
Key="SOFTWARE\ACME\settings" Name="DesktopSC" Value="1"
Type="integer" KeyPath="yes" />
<Shortcut Id="desktopSC" Target="[APPLICATIONFOLDER]MyApp.exe"
Directory="DesktopFolder" Name="My Application"
Icon="$(var.product).ico" IconIndex="0"
WorkingDirectory="APPLICATIONFOLDER" Advertise="no"/>
</Component>
</Fragment>
This is based on #saschabeaumont's answer, but hopefully with some extra helpful hints for us WiX beginners (is it a nightmare for everybody to learn???).
First, create a fragment that contains the shortcut details itself:
<Fragment>
<Component Id="DesktopShortcut" Directory="INSTALLFOLDER" Guid="*">
<RegistryValue Id="RegShortcutDesktop"
Root="HKCU"
Key="Software\Company\ApplicationName"
Name="DesktopSC"
Value="1"
Type="integer"
KeyPath="yes" />
<Shortcut Id="desktopSC"
Target="[INSTALLFOLDER]ApplicationName.exe"
WorkingDirectory="INSTALLFOLDER"
Icon="icon.ico"
Directory="DesktopFolder"
Name="ApplicationName"
Advertise="no"/>
</Component>
</Fragment>
Next, note that this fragment will need including in the Product element, like this:
<Feature Id="ProductFeature" Title="Your Application Title" Level="1">
...
<ComponentRef Id="DesktopShortcut" />
</Feature>
The ProductFeature will likely contain other fragments, such as files, and the program menu shortcut fragment.
Also, the DesktopFolder will need a reference in the TARGETDIR directory element (which will very likely contain other folders, such as ProgramMenuFolder as you require), like this:
<Directory Id="TARGETDIR" Name="SourceDir">
...
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>
Each of these ICE messages is basically complaining about the same thing: a component installing a shortcut should have a registry entry as its keypath. To fix this, add something like this to the component:
<RegistryValue Root="HKCU" Key="Software\MyCompany\MyApplicationName"
Name="desktopShortcut" Type="integer" Value="1" KeyPath="yes"/>
The same goes for the component installing the start menu shortcut. Take a look at the related wix documentation sample about creating a shortcut.
My purpose is to create an internet shortcut link and put to desktop. Here is the code that works for me:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="09F1B63D-FB03-43FD-A326-FD49F93D00C8" Name="TestProduct" Language="1033" Version="0.0.0.1" Manufacturer="WixEdit" UpgradeCode="6B2F9AB4-73A6-45CB-9EC4-590D1AAA6779">
<Package Description="Test file in a Product" Comments="Simple test" InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="simple.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Name="AAAA" Id="AAABBB">
<Component Id="AAAA">
<File Id="AAAA.EXE" Name="AAAA.exe" Source="U:\web\bin\x86\Release\AAAA.exe" />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder">
<Component Id="StartMenuShortcuts" Guid="E8EDD7BC-9762-4C3D-8341-FAEC983D318A">
<RemoveFolder Id="ProgramMenuDir" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" />
<util:InternetShortcut Id="WebsiteShortcut" Name="AAAA Website" Target="http://www.AAAA.com" />
</Component>
</Directory>
</Directory>
<Feature Id="DefaultFeature" Title="Main Feature" Level="1">
<ComponentRef Id="StartMenuShortcuts" />
<ComponentRef Id="AAAA" />
</Feature>
<UI />
</Product>
</Wix>
NOTE: you need to add the following to your candle and light command lines: -ext WiXUtilExtension
Not sure if this was available back in 2010, but this is how I do it in WiX 3.7:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="DesktopFolder" SourceName="Desktop" />
<Directory Id="MergeRedirectFolder">
<Component Id="MyExeComponent" Guid="{PUT-GUID-HERE}">
<File Id="MyExeFile" Source="$(var.ExeSourcePath)" KeyPath="yes">
<Shortcut
Id="DesktopShortcut"
Directory="DesktopFolder"
Name="$(var.ShortcutName)"
WorkingDirectory="MergeRedirectFolder" />
</File>
</Component>
</Directory>
</Directory>
In WIX, how do you create a non advertised shortcut in the allusers profile? So far I've only been able to accomplish this with advertised shortcuts. I prefer non-advertised shortcuts because you can go to the shortcut's properties and use "find target".
In the tutorials I've seen use a registry value for the keypath of a shortcut. The problem is they use HKCU as the root. When HKCU is used, and another user uninstalls the program (since it's installed for all users) the registry key is left behind. When I use HKMU as the root I get an ICE57 error, but the key is removed when another user uninstalls the program. I seem to be pushed towards using HKCU though HKMU seems to behave correctly (per-user vs all-users).
When I try to create the non advertised shortcut I get various ICE error such as ICE38, ICE43, or ICE 57. Most articles I've seen recommend "just ignore the ice errors". There must be a way to create the non advertised shortcuts, without creating ICE errors.
Please post sample code for a working example.
Sorry if it's bad etiquette to answer my own question.
Recently I stumbled upon the information on DISABLEADVTSHORTCUTS property. I created an install with advertised shortcuts and set the DISABLEADVTSHORTCUTS property to 1 which produced non-advertised shortcuts. This bypasses ICE43 errors because an advertised shortcut can use a file as a keypath. Because DISABLEADVTSHORTCUTS has been set Windows Installer will replace these advertised shortcuts with regular shortcuts.
I set the Package Element's InstallScope attribute to "perMachine". This sets the ALLUSERS property to 1. The values of ProgramMenuFolder and DesktopFolder will then resolve to the All Users profile.
For folders created under ProgramMenuFolder there is a RemoveFolder and RegistryValue element. The examples I've seen (ex1, ex2) use HKCU as the root for the RegistryValue. I changed this root to HKMU which resolves to HKCU or HKLM depending on the value of ALLUSERS.
In short, with DISABLEADVTSHORTCUTS set to 1 your advertised shortcuts will not produce ICE errors, but will be converted to non-advertised shortcuts when installed. A RegistryValue with root HKMU is fine for a KeyPath as long as it's not keypath for a non-advertised shortcut.
<?xml version="1.0" encoding="utf-8"?>
<!-- This example is based on SampleFirst by Gábor DEÁK JAHN, Tramontána:
http://www.tramontana.co.hu/wix/lesson1.php#1.3
Original SampleFirst:
http://www.tramontana.co.hu/wix/download.php?file=samples/samplefirst.zip&type=application/zip -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Name="Foobar 1.0" Id="YOURGUID-21F1-4026-ABD2-7CC7F8CE4D18" UpgradeCode="YOURGUID-AFA4-46C6-94AA-EEE3D104F903" Language="1033" Codepage="1252" Version="1.0.0" Manufacturer="Acme Ltd.">
<Package Id="*" Keywords="Installer" Description="Acme's Foobar 1.0 Installer" Comments="Foobar is a registered trademark of Acme Ltd." Manufacturer="Acme Ltd." InstallerVersion="100" Languages="1033" Compressed="yes" SummaryCodepage="1252" InstallScope="perMachine" />
<Media Id="1" Cabinet="Sample.cab" EmbedCab="yes" DiskPrompt="CD-ROM #1" />
<Property Id="DiskPrompt" Value="Acme's Foobar 1.0 Installation [1]" />
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="Acme" Name="Acme">
<Directory Id="INSTALLDIR" Name="Foobar 1.0">
<Component Id="MainExecutable" Guid="YOURGUID-3E4F-47A2-86F1-F3162E9C4798">
<File Id="FoobarEXE" Name="FoobarAppl10.exe" DiskId="1" Source="FoobarAppl10.exe" KeyPath="yes">
<Shortcut Id="startmenuFoobar10" Directory="ProgramMenuDir" Name="Foobar 1.0" WorkingDirectory="INSTALLDIR" Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
<Shortcut Id="desktopFoobar10" Directory="DesktopFolder" Name="Foobar 1.0" WorkingDirectory="INSTALLDIR" Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
</File>
</Component>
<Component Id="HelperLibrary" Guid="YOURGUID-C7DA-4C02-A2F0-A6E089FC0CF3">
<File Id="HelperDLL" Name="Helper.dll" DiskId="1" Source="Helper.dll" KeyPath="yes" />
</Component>
<Component Id="Manual" Guid="YOURGUID-FF92-4BF4-A322-819A3B2265A0">
<File Id="Manual" Name="Manual.pdf" DiskId="1" Source="Manual.pdf" KeyPath="yes">
<Shortcut Id="startmenuManual" Directory="ProgramMenuDir" Name="Instruction Manual" Advertise="yes" />
</File>
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="Foobar 1.0">
<Component Id="ProgramMenuDir" Guid="YOURGUID-D1C2-4D76-BA46-C6FA79862E77">
<RemoveFolder Id="ProgramMenuDir" On="uninstall" />
<RegistryValue Root="HKMU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes" />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
<Feature Id="Complete" Level="1">
<ComponentRef Id="MainExecutable" />
<ComponentRef Id="HelperLibrary" />
<ComponentRef Id="Manual" />
<ComponentRef Id="ProgramMenuDir" />
</Feature>
<Icon Id="Foobar10.exe" SourceFile="FoobarAppl10.exe" />
</Product>
</Wix>
Although this post is rather old it contains quite useful info and looks still active. I want to point out that in general you do NOT need a dummy registry key for your shortcut! AFAIK this is WiX tutorial thingy and is not MSI or certification requirement. Here is an example with no reg key:
<Fragment Id="Folders">
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="MyApp">
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="MyAppStartMenuDir" Name="MyApp"/>
</Directory>
</Directory>
</Fragment>
<Fragment Id="Components">
<Component Id="MyAppComp" Directory="INSTALLFOLDER" ...>
<!--The advertise flag below is to bypass ICE errors in WiX, the actual shortcut will not be advertises if those are disabled globally with DISABLEADVTSHORTCUTS-->
<File ..." KeyPath="yes">
<Shortcut Id="MyAppStartMenuLink" Directory="MyAppStartMenuDir" Advertise="yes" ... />
</File>
<RemoveFolder Id="StartMenuDirRemoved" Directory="MyAppStartMenuDir" On="uninstall" />
</Component>
</Fragment>
Note that this will put your shortcut together with the executable in one component. If this bothers you then use dummy registry key (as in the very well explained accepted self answer).
Take a look at From MSI to WiX, Part 10 - Shortcuts by Alex Shevchuk.
Or Rob Menching's blog post How to create an uninstall shortcut (and pass all the ICE validation).
Basically ICE57 is rather annoying... but here's the (seems to be working) code I'm using for Desktop shortcuts :)
<Component Id="DesktopShortcut" Directory="APPLICATIONFOLDER" Guid="*">
<RegistryValue Id="RegShortcutDesktop" Root="HKCU" Key="SOFTWARE\My App\1.0\settings" Name="DesktopSC" Value="1" Type="integer" KeyPath="yes" />
<Shortcut Id="desktopSc" Target="[APPLICATIONFOLDER]MyApp.exe" Directory="DesktopFolder" Name="My Applications" Icon="myapp.ico" IconIndex="0" WorkingDirectory="APPLICATIONFOLDER" Advertise="no"/>
<RemoveFolder Id="RemoveShortcutFolder" On="uninstall" />
<Condition>DT_SHORTCUT=1</Condition>
</Component>