RobMensching.com /Blog
when setup isn't just xcopy

Posted by
Rob Mensching
Friday, April 27, 2007 3:08 AM

How to create an uninstall shortcut (and pass all the ICE validation).

A while ago, I saw this blog post about creating an uninstall shortcut using the WiX toolset.  My first reaction was, "Uhh, I thought the Logo says you're not supposed to create uninstall shortcuts."  But as the blog author noted clients are clients (especially if they are paying the bills).  My second reaction to the blog entry was, "Jeez, those CustomActions don't seem like they should be necessary." 

Well, it turned out that I've been doing a lot of demos recently.  When creating the demo code, I found that having an uninstall shortcut installed turned out to be really handy.  I routinely forget to uninstall the application package during my demos (which often messes up later demos) and the shortcut serves as a very handy reminder to clean up after myself.  Saves me from click over to Add/Remove Programs (ARP) as well.

Anyway, since I blogged a bunch of random personal goo tonight, I thought I'd wrap up by sharing my solution for creating an uninstall shortcut without using any CustomActions.

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="PUT-GUID-HERE"
             UpgradeCode="PUT-GUID-HERE"
             Name="TestUinstallShortcut"
             Language="1033"
             Version="1.0.0"
             Manufacturer="Microsoft Corporation">

        <Package InstallerVersion="200"
                 Compressed="yes" />

        <Media Id="1" />

        <Directory Id="TARGETDIR"
                   Name="SourceDir">
            <Directory Id="ProgramMenuFolder">
                <Directory Id="ShortcutFolder"
                           Name="My Application">
                    <Component Id="UninstallShortcutComponent"
                               Guid="PUT-GUID-HERE">
                        <RegistryKey Root="HKCU"
                                     Key="Software\My Application\Uninstall">
                            <RegistryValue Value="RobMen Was Here."
                                           Type="string"
                                           KeyPath="yes" />
                        </RegistryKey>

                        <Shortcut Id="UninstallProduct"
                                  Name="Uninstall My Application"
                                  Target="[System64Folder]msiexec.exe"
                                  Arguments="/x [ProductCode]"
                                  Directory="ShortcutFolder"
                                  Description="Uninstalls My Application" />

                        <RemoveFolder Id="RemoveShorcutFolder"
                                      On="uninstall" />
                    </Component>
                </Directory>
            </Directory>
        </Directory>

        <Feature Id="TestUninstallShortcut"
                 Title="Test Uninstall Shortcut Feature"
                 Level="1">
            <ComponentRef Id="UninstallShortcutComponent" />
        </Feature>
    </Product>
</Wix>

The only interesting part in this example is inside the Component element.  In there are actually a few interesting things to notice:

1.  As noted on the other blog entry, the registry key is created to make ICE18, ICE38 and ICE48 happy.  I know the registry key is recommended to make things work correctly for roaming user profiles (how many people use that? I don't know) but I don't understand why the ICEs aren't comfortable with me using the ShortcutFolder as the keypath (it is in the user's profile and should be just as good as the registry key as the key path).  I believe it has something to some minutia in the way that Group Policy and the Windows Installer interact.

2.  The Shortcut/@Target uses the System64Folder standard directory as the root for msiexec.exe.  I use System64Folder because that always resolves to the native "system32" directory on the operating system (SystemFolder resolves to the "SysWow64" directory on 64-bit operating systems).  Now, I'm not a 64-bit guru and I don't have access to a 64-bit OS right now so I could be wrong about System64Folder but my instincts say this is the right thing.  It works on 32-bit XP, I tested.  <smile?>

Note: I use the "[PropertyFolder]executable.exe" syntax here because I did not install the msiexec.exe (obviously, since that's the Windows Installer itself).  If the shortcut pointed at a file I installed then I would have used the "[#FileId]" syntax instead.

3.  The Shortcut/@Arguments passes the "uninstall command" (/x) plus the standard property for the product code of the package.  This is much simpler solution that proposed in the other blog entry.

4.  The Remove folder element exists to make ICE64 happy.  Like the registry key listed above, this cleans up things in a roaming user scenario.  I wish these quirky behaviors weren't exposed to package developers and that the Windows Installer would just "do the right thing".  There must be some crazy scenarios where the Windows Installer can't figure out things for itself.

Anyway, that's about the simplest .wxs file that I can think of to create an MSI that installs an shortcut to uninstall itself.

Silly?  Yes. 

Helpful?  Hopefully.  You should be able to use this information as a starting place to install shortcuts that point at more useful things (like your own application).

More complicated than it should be?  Definitely.  The ICEs add a registry key and remove folder entry that I don't want/need.  I'm considering adding some syntactic sugar to the WiX schema to simplify the authoring in this case but I'm concerned about creating a registry key unexpectedly.  Or maybe we can just convince the Windows Installer team to change the requirements that make these ICEs necessary.

In the mean time, keep coding, you know I am.

 


Posted by
Rob Mensching
Friday, April 27, 2007 1:53 AM

There is no "I" in "team" but there is "me".

The last couple days have been just draining.  Actually, the last few weeks have been draining.  Lots of communicating but not lots of action.  Lack of action means lack of progress.  Lack of progress despite lots of energy expenditure means draining.

Tonight was Thursday so it was also the night that a bunch of us get together to work on the WiX toolset.  Joe, Peter and Aaron were already there when I sat down heavily.  Joe immediately noted that I just looked tired.  I was.  Riding ghost was surprisingly taxing.

Then Peter pushed over the sandwich from Jersey Mike's.  "I got you your usual since I figured you were busy," he said.  I had been.  I missed the 6 PM deadline for sandwich orders tonight.  But Peter was awesome enough to anticipate the need anyway.

That immediately brightened up my evening.

I love working with all these guys (no women at the moment) on the WiX toolset because I feel like we're really part of a cohesive team.  We write code.  We joke around.  We catch up on current events.  We pull together even though there are no managerial or contractual ties to bind us.  Work gets done and we have fun doing it.

All of the above is why I look forward to Thursday nights.

 


Posted by
Rob Mensching
Friday, April 27, 2007 1:08 AM

It's like riding ghost.

I love William Gibson's novels.  I was introduced to cyberpunk when I was in high school and being the geek I am I just sucked it all in.  In Neuromancer there is a point where Case is able to watch Molly infiltrate Straylight via cyberspace.  Somewhere I picked up the term "ghosting" (probably from some other book) for being able to see through someone else's eyes without being there.  For you Halo fans, it's kinda' like Cortana hanging out in the Master Chief's head.

Well, today I rode ghost for our Systems Engineer (aka Operations people) as she went through the motions to deploy Windows Marketplace to our Staging environment.  To do this, Ops sets up a Live Meeting session and I get to watch the whole deployment go down.  Unfortunately, ghosting today was more like Case and Molly than Cortana and Master Chief since the only way to communicate was through Windows Messenger.  It is amazing how slow things get when you have to type your words.

The whole thing reminded me of a quote on a poster I used to have hanging in my bedroom when I was still in high school.  It went something like, "In cyberspace, no one can hear you scream." 

No, it wasn't that bad but the quote is fun.

 


Posted by
Rob Mensching
Thursday, April 19, 2007 12:49 AM

Managed Code CustomActions, no support on the way and here's why.

I was recently pinged by a triumvirate of individuals asking me about using managed code to write CustomActions.  This is a hot topic that comes up about every other month on the wix-users mailing list at SourceForge.  Those of you that hang out on that mailing list know that I've repeatedly stated that the WiX toolset does not support managed code CustomActions because the Windows Installer team does not support managed code CustomActions.

However, since I was asked by three people (all of them knowledgeable and respectable) at the same time I thought I would again ask the Windows Installer team about supporting managed code CustomActions.  I got the same answer I got last time, "The Windows Installer does not support CustomActions written in managed code."  However, this time we had time to have a deeper conversation about why the managed code is not supported for CustomActions.  There are essentially two reasons managed code is not supported: one technical, one strategic.

Technical

The technical issue that managed code CustomActions have is due to the fact that the .NET Framework is "sticky" (Carolyn, MSI Dev Lead, used the phrase "tattoos your process").  Once you load a version of the .NET Framework into a process, the .NET Framework is not unloaded.  More importantly, if you attempt to load a different version of the .NET Framework into your process later you will get the previously loaded version.

I have to admit this technical issue with using managed code in CustomActions surprised me.  I had heard of the problem before (of course, Carolyn had mentioned it a few times) but I didn't truly understand the ramifications until I wrote the code tonight then stepped through it in the debugger.  It is kinda' cool to see the .NET Framework v1.1 get loaded by one CustomAction then later have a second CustomAction try to load the .NET Framework v2.0, get the v1.1 Framework handed to it, then fail when trying to create an app domain later.  Well, it's only cool because I anticipated the failure.

What this mean is that if you end up in a scenario where you have a CustomAction written for one version of the .NET Framework and a second CustomAction written for a different version of the .NET Framework that your second CustomAction will fail before it can even get started.  Well, you could mark your .NET Framework 1.1 CustomAction to say that it will run in the .NET Framework 2.0 and then try to ensure that the .NET Framework 2.0 is loaded everywhere.  That might work until there is another .NET Framework version (4.0?).

There is additional complication on Windows Server 2003.  On that OS, the Windows Installer will attempt to load the .NET Framework 1.1 into the deferred CustomAction server (for a reason that Carolyn mentioned but I've forgotten now, should have taken better notes).  If you have already loaded the .NET Framework 2.0 (say, for a CustomAction) then the Windows Installer can fail to add files to the Global Assembly Cache.

All of these complications when managed code CustomActions are introduced reduce the chances that an installation package will successfully install and uninstall (let alone upgrade or be patchable).  When you approach the problem from a platform point of view (as the Windows Installer team must), I hope you agree that there are way too many common failure cases to support managed code CustomActions.

Now the intrepid developer might suggest that managed code CustomActions could be hosted in a separate process from the Windows Installer's CustomAction server.  That way the separate process would disappear and take the .NET Framework with it each time the CustomAction exited.  Make no mistake, this solution takes a lot of work and is most likely something along the lines of what the Windows Installer team would need to do to support managed code CustomActions.

However, they are focusing on other features because of their strategic position on CustomActions.

Strategic

Inside Windows there is a fair bit of discussion going on right now about how to improve application deployment on the operating system.  Knowing about the discussions, I invited a couple of the Windows architects to my conversation with the Windows Installer team about managed code CustomActions.  My hope was to provide the architects with a couple real world examples of problems facing setup developers today and maybe get some insight from them along the way.  What I got was validation of something I've seen coming for a long while.

Strategically the goal is to reduce the number of CustomActions shipping in installation packages.  It is generally accepted that a great majority of the installation failures out there today are failures inside CustomActions.  CustomActions in installation packages also surface as major problem for application compatibility between operating systems.   The data collected thus far suggests that application deployment would be improved by reducing the number CustomActions in installation packages.

Making it easier to create more CustomActions (which a managed code for CustomAction would certainly do) does not align with the strategic goal.

Now, having written something like 75% of the CustomActions in the WiX toolset let me assure you that I'm one of the first to point out that CustomActions are quite often a necessity today.  However, I also know that the code in the Windows Installer has had far more scrutiny and testing than the WiX CustomActions to date.  Thus, I can agree that it would be better if there were fewer CustomActions shipping in installation packages today and that the installation functionality was instead built into the Windows Installer or the operating system in general.

For example, imagine that to configure a web site in IIS that you didn't need a CustomAction from the WiX toolset (or some other vendor).  Instead, you just declare that you want your web site (much like you do in the WiX toolset today) and code that was installed with IIS would be activated by the Windows Installer to do the work.  That means that you and I would not be responsible for reverse engineering the IIS store (i.e. the metabase) then writing the CustomAction to ship in our installation package.  That would move us all a great many steps away from CustomActions and hopefully towards a more stable operating system.

Now, I know there are a good number of other things that people use CustomActions for today.  I also know that it would be very convenient to be able to write CustomActions in managed code.  However, today the Windows Installer does not support managed code CustomActions and the general direction appears to be to try to reduce the need for CustomActions overall.

 


Before