WiX Proper Creation of Desktop Shortcut - wix

There are two answers on Create shortcut to desktop using WiX
Both these answers lack any real explanation of what is going on. What is the difference between these two methods of creating shortcuts? The first method falls in line with WiX - Create shortcut documentation.
The second method has a MergeRedirectFolder which I can't seem to find any documentation on, and I don't understand why the second example doesn't require the registry setting since according to WiX Documentation, a registry setting:
is required as a Shortcut cannot serve as the KeyPath for a component when installing non-advertised shortcuts for the current users.
Does this mean that the second method is an advertised shortcut? Or is it an answer that assumes the user is installing per machine? Or am I lost in the sauce? (Quite possible - second day trying to use WiX, since Microsoft forced me down this path.)
The first one:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="DesktopFolder" Name="Desktop">
<Component Id="ApplicationShortcutDesktop" Guid="*">
<Shortcut Id="ApplicationDesktopShortcut"
Name="Text under your icon"
Description="Comment field in your shortcut"
Target="[MYAPPDIRPROPERTY]MyApp.exe"
WorkingDirectory="MYAPPDIRPROPERTY"/>
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
<RegistryValue
Root="HKCU"
Key="Software/MyAppName"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</Directory>
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="MyCompany" Name="MyCompany">
<Directory Id="MYAPPDIRPROPERTY" Name="MyAppName">
</Directory>
</Directory>
</Directory>
The second one:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="DesktopFolder" SourceName="Desktop" />
<Directory Id="MergeRedirectFolder">
<Component Id="MyExeComponent" Guid="*">
<File Id="MyExeFile" Source="$(var.ExeSourcePath)" KeyPath="yes">
<Shortcut
Id="DesktopShortcut"
Directory="DesktopFolder"
Name="$(var.ShortcutName)"
WorkingDirectory="MergeRedirectFolder" />
</File>
</Component>
</Directory>
</Directory>

Caveat: Per Doc's comment, since neither example specified the Advertise attribute, neither should create an advertised shortcut. I don't remember what led me to write the answer below; it seems likely to be incorrect. I'll leave the answer in tact in case there is some subtle truth behind it.
The first example creates an advertised shortcut; the second creates a non-advertised shortcut. The rules for the two types of shortcuts are described with the Shortcut Table Target column.
A non-advertised shortcut is a standard Windows shortcut like you would create with Windows Explorer. An advertised shortcut enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated.

Related

WIX :Adding a shortcut to StartMenu folder Windows 10

I have an application that will install a shortcut to Start Menu folder. It is working perfectly in Win7. But shortcut is not coming when I install the application in Windows 10 machine. The shortcut entry in my WIX file is given below.
<Component Id="cmptest" Guid="*" KeyPath="yes">
<Shortcut Id="test.exe2" Directory="StartMenuFolder"
Name="test" Target="[#test.exe]" Hotkey="0" IconIndex="0" Show="normal" />
</Component>
Before getting into too much detail:
Are you sure the shortcut really isn't there? The Windows 10 start menu is so strange that I find I have to look twice very often to find shortcuts that are actually there. Just checking.
For that matter, are you sure the install actually completes in Windows 10? Perhaps it rolls back and you didn't notice?
The Directory StartMenuFolder does not compile for my test project, until I add it as a directory under TARGETDIR myself:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="StartMenuFolder" />
</Directory>
I assume you already have this folder added there to make your setup compile. You could also try ProgramMenuFolder for testing and see if the shortcut shows up.
Where is the rest of your WiX source? I can't see if you actually install the file you reference: #test.exe? Does the component that hosts that file actually get installed on Windows 10?
And for some extra strangeness: I haven't seen this much, but since the problem manifests itself on Windows 10, maybe have a read of this answer and see if it rings any bells: Wix Uninstall Shortcut not working
Essentially some shortcuts are hidden auto-magically in Windows 8 and probably upwards. I don't see any reason why your shortcut should be hidden though.
I have been able to get the shortcuts for to show up using the ProgramMenuFolder suggested by Stein Asmul for testing. Below is my setup which is working, with the exception being that my icons not showing up.
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Barcode Printer App" />
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="BarcodePrinterAppShortcuts" Name="Barcode Printer App" />
</Directory>
</Directory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="ProductComponent">
<File Id="BarcodeAppExe" Source="$(var.BarcodePrinterHelperApp.TargetPath)" >
<Shortcut Id="BarcodeAppShortcut"
Directory="BarcodePrinterAppShortcuts"
Name="Barcode Printer App"
WorkingDirectory="INSTALLFOLDER"
Advertise="yes"
Icon="icon.ico"
IconIndex="0"
>
</Shortcut>
</File>
<RemoveFolder Id="DeleteTheBarcodeAppShortcut"
Directory="BarcodePrinterAppShortcuts"
On="uninstall" />
</Component>
</ComponentGroup>
<Component Id="UninstallShortcut" Guid="*" Directory="BarcodePrinterAppShortcuts">
<Shortcut Id="UninstallThisProduct"
Name="Uninstall Barcode Printer App"
Description="Uninstalls Barcode Printer App"
Target="[System64Folder]msiexec.exe"
Arguments="/x [ProductCode]" />
<RegistryValue Root="HKCU" Key="Software\Powerserve\BarcodePrinterApp" Name="installed" Type="integer" Value="1" KeyPath="yes" />
</Component>
It could be permission issue. Try to run your installation As Administrator (or, open Command Prompt as Administrator) and run your installation from there. Also, you may want to check User Account Control settings and lower the slider if it's too restrictive.

How to define a directory structure (path) to use as the WorkingDirectory attribute

I already successfully created an MSI for PyCharm because the installer is not working properly in silent mode. So I had my first successful experience with WiX.
Now, I got a folder to install from our developers.
This program should go to "C:\ProgramFiles\Folder A\Folder B"
because later there will be another package that goes to "C:\ProgramFiles\Folder A\Folder C"
So, here's what I got (part of it):
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A"/>
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B"/>
</Directory>
</Directory>
I am trying now to create the shortcut
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[APPLICATIONSUBDIRECTORY]\Program B.exe" Icon="ProductIcon" WorkingDirectory="APPLICATIONSUBDIRECTORY"/>
So, my intention was that APPLICATIONSUBDIRECTORY = "C:\ProgramFiles\Folder A\Folder B" but it's going to be "C:\ProgramFiles\Folder B"
I found this:
Setting Wix shortcut with environment variable workingdirectory
But I would rather not use additional properties if there's already a directory structure.
Leaving away this:
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
and using APPLICATIONROOTDIRECTORY would work but I need a second layer of folders.
The Target attribute does not like this as well.
Using (a combination of variables)
Target="[APPLICATIONROOTDIRECTORY]\[APPLICATIONSUBDIRECTORY]\Program B.exe"
does not work but
Target="[APPLICATIONROOTDIRECTORY]\Folder B\Program B.exe"
does.
As I am new to WiX I am still struggling to define directories.
The first 2 Directory Ids are joined but the 3rd one doesn't.
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A"/>
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B"/>
</Directory>
This is my batch file:
#echo off
SET WIXPATH=C:\Program Files (x86)\WiX Toolset v3.11\bin
SET COMPONENTGROUP=MyCompGroup
SET FILEFOLDER=Files
SET FILELIST=FileList
SET MAINFILE=Main
SET MSINAME=Program B.msi
if exist FileList.wxs del FileList.wxs
if exist *.wixobj del *.wixobj
if exist *.wixpdb del *.wixpdb
if exist *.msi del *.msi
if exist *.cab del *.cab
pause
"%wixpath%\heat.exe" dir ".\%FILEFOLDER%" -cg %COMPONENTGROUP% -dr APPLICATIONROOTDIRECTORY -out %FILELIST%.wxs -gg -ke -srd -sfrag -template fragment
"%wixpath%\candle.exe" -arch x86 %MAINFILE%.wxs %FILELIST%.wxs
"%wixpath%\light.exe" -b %FILEFOLDER% -out "%MSINAME%" %MAINFILE%.wixobj %FILELIST%.wixobj
And that's the directory structure to "capture":
/--Files
/----Program B
/------File1
/------File2
etc.
Glitch in Directory Structure
It looks like there is an error in your Directory hierarchy. Maybe try to change it to look like this as a first step:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A">
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B" />
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B" />
</Directory>
</Directory>
Are you using Visual Studio? Try going Edit => Advanced => Format Document when you have your WiX source file open. See what the indentation looks like. Your sub-folders should be indented as shown above. If they don't indent, look at the /> entries. Only add these if you indicate that there are no further sub-folders.
Adding Your Shortcut
As to your shortcut. Here is how you should be able to add an advertised shortcut to a file you install:
<Shortcut Id="mysc" Advertise="yes" Directory="ApplicationProgramsFolder"
Name="My Shortcut" Description="My Shorcut Description" />
This Shortcut element should be added to the component that installs the file in question, for example like this:
<Component Id="NOTEPAD.EXE" Feature="ProductFeature">
<File Source="MyReleaseFiles\NOTEPAD.EXE" />
<Shortcut Id="mysc" Advertise="yes" Directory="ApplicationProgramsFolder"
Name="My Shortcut" Description="My Shorcut Description" />
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"
Directory="ApplicationProgramsFolder"/>
</Component>
Visual Studio
You can install the Visual Studio 2017 Community Edition for free - and I recommend this way to make WiX MSIs. You get some more help from the tool to avoid errors such as the issue with your Directory hierarchy.
I wrote a short answer on how to create a minimal "Hello World" style WiX MSI using Visual Studio:
WiX installer msi not installing the Winform app created with Visual Studio 2017.
You might want to reinstall the latest WiX version and the Visual Studio extensions (2017) if you install Visual Studio to ensure that the WiX project types and extensions are available.
Still learning how this forum works :-) To post markup I need to use "answer" instead of "comment", right?
This is how it works like #Stein Åsmul wrote:
I split every directory element into <Directory> and </Directory> instead of just <Directory />.
I know it's not necessary for the "last" one but just to make it clear for me next time I look at that code :-)
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Folder A">
<Directory Id="APPLICATIONSUBDIRECTORY" Name="Folder B">
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Program B">
</Directory>
</Directory>
</Directory>
The shortcut part works like this:
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="*PUT-IN-GUID*">
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[APPLICATIONSUBDIRECTORY]\Program B.exe" Icon="ProductIcon" WorkingDirectory="APPLICATIONSUBDIRECTORY"/>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[blabla]\Program B" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
It's not perfect but way better than copying the whole crap by batch file...
It would be even better if our developers would use WiX instead of giving me just binaries to deploy :-)
As another workaround I was able to create a new property yesterday using a custom action. It is not upper case on purpose.
<SetProperty Id="ApplicationFullDirectory" Value="[APPLICATIONROOTDIRECTORY]Folder B" After="CostInitialize" />
This allowed me to use the new variable/property "ApplicationFullDirectory" in the shortcut element.
<Shortcut Id="ApplicationStartMenuShortcut" Name="Program B" Target="[ApplicationFullDirectory]\Program B.exe" Icon="ProductIcon" WorkingDirectory="ApplicationFullDirectory"/>
But still learning :-)

WiX Ice64 error for shortcut parent directory

I am trying to create a start menu shortcut for an application using WiX, the problem is that I am receiving an Ice64 error stating that the parent directory of the shortcut directory is not in the RemoveFile table.
I do not want to remove this parent folder (organisation folder) on uninstall as other applications may have shortcuts in other children of it.
My code looks like
<Feature Id="ProductFeature" Title="MyApplication" Level="1">
<ComponentGroupRef Id="Components" />
<ComponentRef Id="ProfilesShortcut"/>
</Feature>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="OrgDir" Name="OrganisationName">
<Directory Id="AppDir" Name="MyApplication" />
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgFilesOrgDir" Name="OrganisationName">
<Directory Id="ProgFilesAppDir" Name="MyApplication" />
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<DirectoryRef Id="ProgFilesAppDir">
<Component Id="ProfilesShortcut" Guid="*">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="MyApplication"
Description="My Application"
Target="[#MyApplication.exe]"
WorkingDirectory="AppDir"/>
<RemoveFolder Id="ProgFilesAppDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Organisation\MyApplication" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
Feel free to add the remove file element to your shortcut component.
Remove an empty folder if the parent component is selected for installation or removal.
The RemoveFolder element will only remove empty folders so if your product is not the only part of that suite installed it will leave the parent folder alone since other products will have put files/folders there. Consider the scenario where your product is either the only one installed (should remove the folder) or is the last one to be uninstalled from the suite (should remove the folder). In these two cases the folder should get removed. The order of RemoveFolder elements get defined might matter so I would test putting the ProgramFilesOrgFolder remove element before and after ProgFilesAppDir remove element just to see if one of them fails.
Alternatively you can just suppress ICE64 but then you will leave a folder behind once all the products are uninstalled. Not a huge deal really but might be annoying to some users.

How to define installation folder from command line parameter in Wix installer

I install my application to a specific folder using the below wxs code:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="CompanyName">
<Directory Id="SUBDIR" Name="Application Launcher">
<Component Id="ApplicationFiles" Guid="*">
<File Name="app.exe" Id="AppFile1" Source="app.exe" Vital="yes" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
I want to specify the installation folder with a parameter to be given from the command line like below:
msiexec.exe /i setup.msi PATH=C:\MyCompany\Folder\ /qn
Thanks a lot.
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="CompanyFolder" Name="CompanyName">
<Directory Id="INSTALLLOCATION" Name="Application Launcher">
<Component Id="ApplicationFiles" Guid="*">
<File Name="app.exe" Id="AppFile1" Source="app.exe" Vital="yes" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
For your install:
msiexec /I setup.msi INSTALLLOCATION=C:\Somewhere /qn
I am adding as an answer to get proper links. You should check out Wix's auto-generate GUID feature: WIX Autogenerate GUID *?
This feature allows you to stop generating your own GUIDs and have Wix take care of them in an "automagic" way. I haven't tested it, but anything that makes your source file cleaner, shorter, and easier to maintain is worth trying. It also makes it easier to share Wix snippets without people reusing your generated GUID.
Maybe also check out:
How To: Generate a GUID
Change my component GUID in wix?
WIX Autogenerate GUID *
Rob Mensching (Wix author) states it is safe for normal use
And one more thing with regards to properties. In general all PUBLIC properties (uppercase) can be set on the command line. If you want to use these properties in deferred mode custom actions you need to check out the concept of restricted public properties and the SecureCustomProperties property. Some Installshield info too. And a nice old Wise article.

"ICE38: Component installs to user profile" error for a specific component

I am trying to write a Windows Installer script in WiX 3.6 with a per-machine and x64 architecture only setting. I have the following project structure (shortened):
<Directory Id="ProgramFiles64Folder" Name="PFiles">
<Directory Id="APPLICATIONFOLDER" Name="My Company">
<Directory Id="ProductFolder" Name="My Product">
<Component Id="MainComponent" Guid="" Win64="yes" KeyPath="yes">
...
</Component>
<Directory Id="DataFolder" Name="Data">
<Directory Id="Machine" Name="Machine" >
<Directory Id="MachinesFolder" Name="Machines">
<Component Id="Machine1" Guid="{74341536-72DF-48C3-95E8-2851D9FA8318}" Win64="yes" KeyPath="yes">
...
</Component>
</Directory>
<Directory Id="TemplateFolder" Name="Template">
<Component Id="TemplateFiles" Guid="{A0D0C225-D604-4B84-971D-41687A30EC36}" Win64="yes" KeyPath="yes">
<File Id="Template1.rsbak" Source="$(var.SolutionDir)bin\Release\File1.rsbak" />
...
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
The problem is that I receive the error ICE38: Component TemplateFiles installs to user profile. It must use a registry key under HKCU as its KeyPath, not a file for the TemplateFiles component when I compile. What confuses me is that I use a similar structure in another project (working), and have several components with the exact same setup in my project (not shown above). Why does this - and this only - component insist on installing to the user profile when all others get installed correctly, to Program Files?
Looks like there's significant difference for msi between Program Files and Users\UserName\Documents folders. The last is referenced in your example:
<Directory Id="DataFolder" Name="Data">
I came to the similar problem and found an answer in the blog post - https://robmensching.com/blog/posts/2007/4/27/how-to-create-an-uninstall-shortcut-and-pass-all-the/
In short you need to define RegistryKey on HKCU root as subelement to Component and add RemoveFolder element as subelement to Directory. See the link above for full example. In addition:
Remove KeyPath attribute from Component element
RemoveFolder possibly have to be defined for all folders. I used dummy component with no file inside for that