Two standard actions and one table are required to successfully install/uninstall shortcuts.
There are four additional columns (with matching names for attributes) which are used on Windows Vista or above in Multilingual User Interface:
I will not discuss them in this post.
For this blog I am using the following console application as an installable software:
Advertised shortcut sample
Here is the source for the advertised shortcut sample:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<?define APPPATH = "..\Project\ConsoleApp\bin\Debug"?>
<Product Id="{0B97B94B-5387-45B0-A34C-EFFAD7F6E509}"
Name="Advertised Shortcut Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{FC888F32-A21B-4AFB-81E9-EDBFB91E507B}">
<Package Id="{86EC5FC3-F006-4BFB-9EDA-8E8E72AC7325}"
Description="Advertised Shortcut Sample"
Comments="This installer database contains the logic and data required to install Advertised Shortcut Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Media Id="1" Cabinet="Advertised.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Advertis" LongName="Advertised Shortcut">
<Component Id="Component1"
Guid="{7A274A33-CEFE-4A0E-9E47-EFC8169EA480}"
DiskId="1">
<File Id="ConsoleApp.exe"
Name="ConsApp.exe"
LongName="ConsoleApp.exe"
Vital="yes"
KeyPath="yes"
Source="$(var.APPPATH)\ConsoleApp.exe">
<Shortcut Id="startmenuAdv"
Directory="ProgramMenuDir"
Advertise="yes"
Name="Advertis"
LongName="Advertised Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
</File>
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
<Directory Id="ProgramMenuDir" Name="Advertis" LongName="Advertised Shortcut" />
</Directory>
</Directory>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
AllowAdvertise="yes"
TypicalDefault="advertise"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
Initial installation state for the feature Feature1 is Advertise (TypicalDefault="advertise"). In this sample, advertised shortcut will be installed in the Start/All Programs menu. Create an installer database by using these two commands:
candle.exe Advertised.wxs
light.exe -out Advertised.msi Advertised.wixobj
Install the application, make sure that folder "Advertised Shortcut" is not present in the Program Files folder. Click on Start/All Programs/Advertised Shortcut/Advertised Shortcut Sample. You will notice that application is being installed and after installation is completed, console window will pop up with the message "Hello World!". Press Enter to close the window.
Open "Program Files/Advertised Shortcut" folder. Delete the ConsoleApp.exe file. Start the application again clicking on the shortcut in the Start/All Programs/Advertised Shortcut/Advertised Shortcut Sample. You will notice that application is being installed again and console window will pop up after installation is done. That was the Self-Repair feature of advertised shortcuts.
Fixing ICE error
If you will run validation on the Advertised.msi you will get error ICE64 with the error message "The directory ProgramMenuDir is in the user profile but not listed in the RemoveFile table". ICE64 is telling you that in the roaming scenario folder for a shortcut won't be removed from the user profile. To fix this error we need to add RemoveFolder element to a component which installs the shortcut:
<Component Id="Component1"
Guid="{7A274A33-CEFE-4A0E-9E47-EFC8169EA480}"
DiskId="1">
<File Id="ConsoleApp.exe"
Name="ConsApp.exe"
LongName="ConsoleApp.exe"
Vital="yes"
KeyPath="yes"
Source="$(var.APPPATH)\ConsoleApp.exe">
<Shortcut Id="startmenuAdv"
Directory="ProgramMenuDir"
Advertise="yes"
Name="Advertis"
LongName="Advertised Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
</File>
<RemoveFolder Id="DeleteShortcutFolder"
Directory="ProgramMenuDir"
On="uninstall" />
</Component>
Non-advertised shortcut sample
Here is the source for non-advertised shortcut sample:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<?define APPPATH = "..\Project\ConsoleApp\bin\Debug"?>
<Product Id="{1F39DCE0-2260-4864-9BA0-485E6A71DF53}"
Name="Nonadvertised Shortcut Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{6E802644-B952-4F69-AC5C-6F7F85F5B2D8}">
<Package Id="{EC78A9CE-C9AD-4C83-8ADB-AABDB21133A8}"
Description="Nonadvertised Shortcut Sample"
Comments="This installer database contains the logic and data required to install Nonadvertised Shortcut Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Media Id="1" Cabinet="Nonadver.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Nonadver" LongName="Nonadvertised Shortcut">
<Component Id="Component1"
Guid="{213F41E8-8AD5-4BEA-AFC5-652A02F6596F}"
DiskId="1">
<File Id="ConsoleApp.exe"
Name="ConsApp.exe"
LongName="ConsoleApp.exe"
Vital="yes"
KeyPath="yes"
Source="$(var.APPPATH)\ConsoleApp.exe" />
<Shortcut Id="startmenuNonadv"
Directory="ProgramMenuDir"
Advertise="no"
Name="Nonadver"
LongName="Nonadvertised Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe"
Target="[!ConsoleApp.exe]">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
<RemoveFolder Id="DeleteShortcutFolder"
Directory="ProgramMenuDir"
On="uninstall" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
<Directory Id="ProgramMenuDir" Name="Nonadver" LongName="Nonadvertised Shortcut" />
</Directory>
</Directory>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
Special case - Internet shortcut
Even though it is not supported directly by MSI and WiX, you still can create an Internet shortcut.
Create a file Microsoft.txt:
[InternetShortcut]
URL=http://www.microsoft.com
Here is the source for installing advertised Internet shortcut:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<?define APPPATH = "D:\MyLearning\WiX\Shortcuts\Project\ConsoleApp\bin\Debug"?>
<Product Id="{D0A6D167-690D-465C-806D-0FE6C17EB9B7}"
Name="Internet Shortcut Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{2E8AA511-1970-4085-942B-42293A21B827}">
<Package Id="{1A7EA7DE-2B0C-4DC6-ACF1-5F2808B806B3}"
Description="Internet Shortcut Sample"
Comments="This installer database contains the logic and data required to install Internet Shortcut Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Media Id="1" Cabinet="Advertised.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Advertis" LongName="Advertised Shortcut">
<Component Id="Component1"
Guid="{7A274A33-CEFE-4A0E-9E47-EFC8169EA480}"
DiskId="1">
<File Id="Microsoft.txt"
Name="MS.url"
LongName="Microsoft.url"
Vital="yes"
KeyPath="yes"
Source="Microsoft.txt">
<Shortcut Id="startmenuInternet"
Directory="ProgramMenuDir"
Advertise="yes"
Name="Intern"
LongName="Internet Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
</File>
<RemoveFolder Id="DeleteShortcutFolder"
Directory="ProgramMenuDir"
On="uninstall" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
<Directory Id="ProgramMenuDir" Name="Intern" LongName="Internet Shortcut" />
</Directory>
</Directory>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
AllowAdvertise="yes"
TypicalDefault="advertise"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
Special case - Starting application in the command window
We want to start our application in the command window. Command window must stay after our application will exit.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<?define APPPATH = "D:\MyLearning\WiX\Shortcuts\Project\ConsoleApp\bin\Debug"?>
<Product Id="{7DDD5785-FDDC-43A9-857F-75A3499B44B8}"
Name="Comspec Shortcut Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{69CCD9BE-D753-4300-B3CA-2D645C795C2D}">
<Package Id="{58D0EF68-8DED-4F08-A6CD-C9487E5B4B5E}"
Description="Comspec Shortcut Sample"
Comments="This installer database contains the logic and data required to install Comspec Shortcut Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Media Id="1" Cabinet="Comspec.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Comspec" LongName="Comspec Shortcut">
<Component Id="Component1"
Guid="{FC5A459A-74E6-4DF1-8A9A-EE9897414CFA}"
DiskId="1">
<File Id="ConsoleApp.exe"
Name="ConsApp.exe"
LongName="ConsoleApp.exe"
Vital="yes"
KeyPath="yes"
Source="$(var.APPPATH)\ConsoleApp.exe" />
<Shortcut Id="startmenuComspec"
Directory="ProgramMenuDir"
Advertise="no"
Name="Comspec"
LongName="Comspec Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe"
Target="[%ComSpec]"
Arguments='/k "[!ConsoleApp.exe]"'
Show="normal">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
<Directory Id="ProgramMenuDir" Name="Comspec" LongName="Comspec Shortcut" />
</Directory>
</Directory>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
Uninstall shortcut
For more details on why we need HKCU registry key as a keypath for uninstall shortcut component, read Rob Mensching's blog post How to create an uninstall shortcut (and pass all the ICE validation).
Here is the V3 code for uninstall shortcut sample which is almost identical to Rob's sample.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define APPPATH = "..\..\Project\ConsoleApp\bin\Debug"?>
<Product Id="{2E8A39F5-0699-4812-8863-8EB8C8D0DA39}"
Name="UninstallShortcut"
Language="1033"
Version="1.0.0.0"
Manufacturer="UninstallShortcut"
UpgradeCode="{A87BD175-7754-454A-B71E-13094FCB40C1}">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<Media Id="1" Cabinet="UninstallShortcut.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="UninstallShortcut">
<Component Id="Component1"
Guid="{1ED0183B-198D-4612-ABEE-1BDE42F3CF54}"
DiskId="1">
<RegistryKey Root="HKCU"
Key="Software\Uninstall Shortcut Sample\Uninstall">
<RegistryValue Value="KeyPathValue"
Type="string"
KeyPath="yes" />
</RegistryKey>
<Shortcut Id="startmenuNonadv"
Directory="ProgramMenuDir"
Advertise="no"
Name="Uninstall Shortcut Sample"
WorkingDirectory="INSTALLDIR"
Icon="Icon.exe"
Target="[SystemFolder]msiexec.exe"
Arguments="/x [ProductCode]">
<Icon Id="Icon.exe" SourceFile="$(var.APPPATH)\ConsoleApp.exe" />
</Shortcut>
<RemoveFolder Id="DeleteShortcutFolder"
Directory="ProgramMenuDir"
On="uninstall" />
</Component>
<Component Id="Component2"
Guid="{5178004E-6F08-4A77-8178-80CB0DF55E15}"
DiskId="1">
<File Id="ConsoleApp.exe"
Name="ConsoleApp.exe"
Vital="yes"
KeyPath="yes"
Source="$(var.APPPATH)\ConsoleApp.exe" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="Uninstall Shortcut sample" />
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="UninstallShortcut" Level="1">
<ComponentRef Id="Component1" />
<ComponentRef Id="Component2" />
</Feature>
</Product>
</Wix>
Attached is zip file containing all samples.