Retain desktop shortcut position on major upgrade in WiX - wix

My WiX installer optionally creates a desktop shortcut upon installation and removes it when it is uninstalled, a CREATEDESKTOPSHORTCUT property handles that, so nothing special so far.
When a major upgrade is performed, the shortcut is removed and recreated, resetting its position on the desktop to the first free spot. This is the default major upgrade behaviour, but how can I retain its position?
An obvious first approach involves using the WIX_UPGRADE_DETECTED property which is only present if a major upgrade is running (I only use major upgrades). The desired behaviour is
Create a shortcut on the initial installation if the product is not yet installed and CREATEDESKTOPSHORTCUT is true
Don't touch the shortcut on a major upgrade (e.g. if WIX_UPGRADE_DETECTED is present), regardless if it had been created on the initial installation or not
Remove the shortcut when the product is uninstalled and if it had been created on the initial installation
Is there a way to achieve that? I guess it might boil down to a Condition element inside the shortcut's Component or Feature, but I don't get it up and running.
Edit:
One possible approach is to make the shortcut creating component permanent and introduce an additional component that is only triggered when the product is removed (and not major upgraded) and explicitly removes the link file from the desktop:
<DirectoryRef Id="DesktopFolder">
<Component Id="CreateDesktopLink" Guid="My-GUID-1" Permanent="yes">
<RegistryValue ... />
<Shortcut Id="CmdShortcut" Name="My Desktop Link" Target="[SystemFolder]cmd.exe" />
</Component>
<Component Id="RemoveDesktopLink" Guid="My-GUID-2">
<RegistryValue ... />
<RemoveFile Id="RemoveDesktopLinkFile" Name="My Desktop Link.lnk" On="uninstall" />
<Condition>REMOVE=ALL AND NOT WIX_UPGRADE_DETECTED</Condition>
</Component>
</DirectoryRef>
although that would leave an orphaned component behind on uninstall. Optionally, I could move the shortcut creation into a custom action, eliminating the permanent component.
Any input is appreciated.

You can't preserve the shortcut - at least not in the default case of advertised shortcuts. These shortcuts contain a reference to the product, component and feature, and sometimes an icon that may be in the binary table of the cached MSI. At least two of these will change over an upgrade.
That leaves you with non-advertised shortcuts or ones you create yourself, for which attempting to preserve the location might work.
Perhaps you could enumerate the desktop icons (a search has code examples) so you can put the icon back where it was before, because that would work for all flavors of shortcut and you wouldn't need to change your upgrade logic. Just find out where it currently is, then find it again after it's installed and move it the original location.

How about sequencing your "RemoveExistingProducts" standard action after InstallFinalize?
Doing so would mean that the newer product is installed followed by an uninstall of the older product. When the newer product is installed, the reference count of the component creating the shortcut will get incremented to 2 and hence when the older product is uninstalled, the component creating the shortcut would be untouched.
I am just thinking that this is one other possible solution.
However, re-sequencing "RemoveExistingProducts" is something which you will have to think through deeply.

Related

WIX removes folder from WOW6432Node

I want to delete folder "TestCom" from HKLM\Software:
<RemoveRegistryKey Root="HKLM" Key="SOFTWARE\TestCom" Action="removeOnUninstall" />
But when I unistall application, it deletes TestCom folder from SOFTWARE\WOW6432Node\TestCom.
How can I remove SOFTWARE\TestCom folder ?
With just what is shown in the question, it's reasonable to assume this is either a 32-bit package, or at least a RemoveRegistryKey tied to a 32-bit component. In either of those cases, it will use a 32-bit view of the system.
My favorite way to visualize this is to launch c:\windows\syswow64\regedit.exe and view the registry through this 32-bit application. In that view, you will see that HKLM\SOFTWARE\TestCom is what has been modified.

WiX: returning a value from exepackage

I have been asked to add a function to an existing WiX package.
Specifically, I need to run a small c# application and return a single int back to WiX to conditionally control further actions.
I can see from ExePackage help that there is an ExitCode, but this is an enumeration of success, error, scheduleReboot or forceReboot.
I have googled quite a bit and I am wondering if I am missing the point. I can probably implement the C# process internally within WiX to get the user to provide the information I need, but the existing package already has custom ExePackages written in C# with a particular style, so I'd like to stay with that if I can. (The existing packages don't return any needed values)
Can I do this, or do I need to try and operate entirely within WiX?
For reference, one of the existing packages looks like this:
<ExePackage
SourceFile="..."
DisplayName="License Key"
InstallSize="0"
Permanent="yes"
InstallCommand="/ignoreIfLicensed"
RepairCommand="/ignore"
UninstallCommand="/ignore"
/>
The reference to <ExePackage ...> implies you want the condition to operate in a WIX bundle. In this scenario I think your options are limited and you can only map the return value of an ExePackage to global behaviour like forceReboot.
Do you have any <MsiPackage...> references? If you have, you could move the conditional behaviour inside each <MsiPackage...> using a Custom Action to call the exe and set a property. The property can then be used as a condition in each <component...> you want to conditionally install. See Using a WiX custom action to set a property's value for more information on custom actions setting properties.

What are the binary references in WIX?

I've used the dark.exe to create a WXS file from my 'old' Visual Studio 2010 msi file.
When I open the created WXS file, It has binary references on the top of the file that I can't explain. Can somebody tell me about it? And where can I find some documentation about it?
<Binary Id="InstallUtil" SourceFile="C:\Temp\Binary\InstallUtil" />
<Binary Id="MSVBDPCADLL" SourceFile="C:\Temp\Binary\MSVBDPCADLL" />
<Binary Id="VSDNETCFG" SourceFile="C:\Temp\Binary\VSDNETCFG" />
<Binary Id="DefBannerBitmap" SourceFile="C:\Temp\Binary\DefBannerBitmap" />
<Binary Id="UpFldrBtn" SourceFile="C:\Temp\Binary\UpFldrBtn" />
<Binary Id="NewFldrBtn" SourceFile="C:\Temp\Binary\NewFldrBtn" />
The top three are giving me the most questions because I don't where there for and what they do.
Short answer - these files are used in ui dialogs, custom actions, all places where some files are applicable to the functionality of the setup itself, but the product it installs.
In your case, the first three are DLLs used by Visual Studio Setup Projects to perform custom actions - MSI extensibility blocks. The last three are the icons used in UI dialogs later in code.
To get the files themselves, you should use export binaries parameter for Dark.exe.
Now, your options here depend on what you want to achieve. If your task is just upgrade your setup to VS2012, quick and dirty, then use the exported files as they were, it should work.
If, however, you want to do it clean and nice, or you should update your setup with new features, then you will have to rewrite these.
For UI: if your project does not contain custom UI, I suggest switching to WIX UI library - nice and built-in. If you have custom UI, you may extend it, but it is a lot more work. There are visual UI editors for WIX.
For custom actions: custom action is something you use when MSI/WIX abilities do not give you enough. To upgrade these, you should look where these first three binaries are used, and how they are called. Usually, the meaning of custom action may be devised from its name. Then, you have to replace these custom actions with your own (or ready-made by others or WIX team) that do the same. Then you may remove the unused binaries.

Unable to delete deployed file during installation with WIX installer

In our WIX installer project, we need to generate a new file, let's call it FileB, based on a deployed file, called FileA in a managed custom action function. In another word, in the component declaration, I declare the FileA. While in a custom action (which happens at commit phase), I need to generate FileB based on FileA. After that, since FileA is no use anymore, I want to delete it in the same custom action.
And here comes the problem: with the default installation folder, which is Program Files, the normal user is not allowed to add file (generate FileB) into this folder in the custom action (I am not 100% sure I am right, but it is the case in my test. And if I install it in another folder, there is no problem at all). So I think I need to give permission of creating file. In order to do that, I add a CreateFolder element to the component which includs FileA. The whole component declaration is something like this:
<Component Id='COMPONENT_NAME' Guid='MY_GUID'>
<!--OTHER FILES IN THE COMPONENT-->
...
<CreateFolder Directory='INSTALLDIR'>
<Permission CreateFile='yes' User='Everyone' GenericAll='yes' Delete='yes'/>
</CreateFolder>
<File Id='MyFileA' Name='FileA' Source='PATH_TO_FILEA' KeyPath='no' >
<Permission GenericAll='yes' User='Everyone' Delete='yes'/>
</File>
</Component>
The component actually belongs to a component group, which resides in INSTALLDIR. The reason there is other files in the same component element is because I want another File to be the keypath, so that deleting FileA would not cause a problem of that. And now the generation of FileB is working fine. But later in the same custom action, I am experiencing the problem when deleting FileA. It just says that ": Access to the path 'DEPLOYMENT_PATH_TO_FILEA' is denied." I thought the problem lies in the FileA declaration, that's why I added the Delete='yes' in the Permission element under File, hoping to make it OK to delete it (although I am not sure whether this means in the installation it is possible to delete). But still I get this error. Can anyone tell me what I did wrong?
Another question is, I really don't know what is the purpose of those CreatFolder elements. For one thing: if the aim is to create the directory structure, I think the (nested)Directory elements already do that. And why to have such element under Component element when most of the time you probably want the directory structure to be separated with component structure(the components just use directory reference to refer to correct directory). Secondly, the default Directory property of CreateFolder is the parent Directory where the component resides in. But it is common that more than one components reside in the same directory, like what I have here: multiple components are in the same component group, whose directory element references to INSTALLDIR. So only one of these components has the CreateFolder element, whose Directory property in my case is the parent directory of all those components. It is really hard to understand this structure. I guess I have some misunderstanding of the CreateFolder element. Can someone enlighten me to usage of CreateFolder? Thanks!
Thanks!
A number of issues to address here. First, you should know that Commit phase custom actions don't execute if rollback is disabled. You should really have an deferred and rollback custom action.
Second, you can't tell MSI to install a file and then go delete it. That's counterproductive and just causes servicing issues down the road. A better solution ( I'm assuming you are using a WiX DTF managed custom action ) is to include FileA as a content item in the custom action project. This will cause the file to exist in the current (temp) directory of the custom action while it execute. You can then generate fileb. For rollback, you can delete fileb.
You'll also need to author a RemoveFile element to teach MSI to delete the file on uninstall. Otherwise it won't since MSI doesn't know anything about fileb created by your out of process custom action.
Otherwise it'd be useful to know what the contents of fileb are. It would be easier to implement if this was an xml file that could be installed as fileb and then transformed using the xml wix extension.

Overriding banner image in Wix 3.5 Wixlib doesn't work in actual MSI

I am using several articles and other questions in order to override the banner bitmap images for a binary wixlib that I am using in 20+ other installers. This library provides our own custom UI, some custom dialogs, common resources, binaries, custom actions, etc.
Here is the code I am using in the wixlib to override the images:
<Binary Id="WixUI_Bmp_Banner" SourceFile="Bitmaps\bnnrbmp.bmp/>
<Binary Id="WixUI_Bmp_Dialog" SourceFile="Bitmaps\dlgbmp.bmp/>
But when I reference my wixlib in my actual MSI project, everything works except for the UI banner image overrides (my custom dialogs fire, process works, common binaries get installed, etc.). Is there something special I need to do in my binary wixlib project to override the UIExtension.wixlib default images in my own binary wixlib?
I saw this question here: Can WixUiBannerBmp be set in a wixlib?, however the answer to that question didn't answer the question, it was directly related to an icon and I'm not sure this guy was using a binary wixlib (re-distributable). My add/remove programs icon embedded in the wixlib already works just fine.
Images are specified via bind-time variables, not Binary elements. Your .wixlib can contain the variable values. The approach used in Can WixUiBannerBmp be set in a wixlib? doesn't use a .wixlib, but otherwise is the same. (A .wixlib is just a collection of .wixobj files.)
The WiX help file documents the variables in "Customizing Built-in WixUI Dialog Sets":
Replacing the default bitmaps
The WixUI dialog library includes default bitmaps for the background of the welcome and completion dialogs and the top banner of the other dialogs. You can replace those bitmaps with your own for product branding purposes. To replace default bitmaps, specify WiX variable values with the file names of your bitmaps, just like when replacing the default license text.
Example:
<WixVariable Id="WixUIBannerBmp" Value="banner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="dialog.bmp" />