Silencing the Windows Installer Restart Manager

This is the story of the day I discovered that there’s something simple about Windows Installer.

When it comes to creating installer packages, the thought of using the Windows Installer service fills the average developer with dread. Calling Windows Installer unapproachable and unintuitive is an understatement. It is only thanks to Rob Mensching and the gang working on the Windows Installer XML (WiX) toolkit that it is even approachable. Unfortunately the progress on WiX is slow, although admittedly not quite as slow as Window Clippings. As John Robbins said to me the other day, don’t get me started on how no one at Microsoft cares about install and just leaves poor Rob out there on his own. 🙂

I have tried to streamline the Window Clippings installer such that all you see is a simple progress window (and possibly a security prompt) which takes just a few seconds to complete.

install

That’s it. No wizard with ten pages of meaningless junk you have to get through. It just gets on with it so that you can get on with using Window Clippings.

To streamline the update process I made sure that Window Clippings supports the Restart Manager (RM) so that it can be automatically restarted via the RM API that the Windows Installer service uses. For some reason the Window Installer service doesn’t trust the Restart Manager to do the right thing and wants the user to take some responsibility, so it throws this window at the user:

prompt

Of course I’ve already made sure that Window Clippings can be safely restarted so I really didn’t want this ugly prompt to stop the update process in its tracks.

I had read the page in the Windows Installer SDK about using Windows Installer with the Restart Manager and figured I could use the MsiSetExternalUI function to suppress the prompt. But then I read the fineprint:

MsiSetExternalUI should only be called from a Bootstrapping application. You cannot call MsiSetExternalUI from a custom action.

It’s at this point that I realized that WiX can’t help me with this problem and I was filled with trepidation. I asked John and he mentioned the work on Burn. That sounded complicated. After a while I collected myself and turned back to the Windows Installer SDK and realized something: not everything about Windows Installer is complicated! I know, it’s hard to believe but it’s true. Writing a bootstrapping application for Windows Installer can, at least for my simple needs, be accomplished with very little code. The MsiInstallProduct function takes the place of msiexec.exe to install the package. All that’s left is to call MsiSetExternalUI with a simple callback that always returns IDOK and the Restart Manager prompt goes away. Here is the entire bootstrap application:

#include <windows.h>
#include <Msi.h>
#pragma comment(lib, "msi.lib")
 
static int CALLBACK ExternalCallback(void * /*context*/,
                                     UINT /*type*/,
                                     LPCWSTR /*message*/)
{
    return IDOK;
}
 
int WINAPI wWinMain(HINSTANCE /*instance*/,
                    HINSTANCE,
                    PWSTR /*commandLine*/,
                    int /*show*/)
{
    MsiSetExternalUI(ExternalCallback,
                     INSTALLLOGMODE_RMFILESINUSE,
                     nullptr); // context
 
    return MsiInstallProduct(L"path or URL to .msi file",
                             nullptr); // command line
}

And that’s it. I now have a streamlined install and update process without any unnecessary prompts. In future I can even use the bootstrap application to easily skin the progress window but this will do for now.

As an aside, I then compiled a release build and was disappointed that this simple application took a staggering 38KB so I checked with Steve Miller and he showed me how simple it is to get rid of the C Runtime for simple applications that don’t rely on the runtime’s initialization code. You just need to manually set your entry point to wWinMain and the linker will throw away it’s stub code. You can find this in your project’s advanced linker settings. That got me down to under 10KB (including the VeriSign digital signature and common controls manifest).

I hope this story saves you some unnecessary anxiety. And as Rob always says, keep coding… you know I am!

2 thoughts on “Silencing the Windows Installer Restart Manager

  1. Levy

    All nice and clean, but if you use this method of installing a .msi file programatically (using MsiInstallProduct while you set a callback with MsiSetExternalUI) you will have the following problem: if you build a new version of the .msi file that you want to use to upgrade an already installed (older) version of the same .msi fille, the upgrade will not happen. Instead, the new build will be installed side by side the old one, in the add/remove programs control panel applet. If I do not install the callback using MsiInstallProduct, the new build uninstalls the old one (correct behaviour). Any ideas? Help!

    Reply
    1. Kenny Kerr Post author

      No idea. The way I did it actually worked correctly. There was only ever one entry in the Add/Remove table regardless of how many versions I went through. I am however no MSI expert. Sorry I cannot help more.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s