RobMen's Recommendation: Do not advertise COM information in MSI.

This is a topic that I planned to cover a long time ago.  Later I realized that it takes quite a bit of explanation and code to demonstrate why advertising COM information is such a bad idea.  Recently, I've had a number of people all ask about this topic again, so I thought I'd sit down for a few hours and put the example together.

To be very specific, what I'm talking about is avoiding the use of the Class, ProgId, and MIME tables and to a lesser extent the Extension and Verb tables.  Using WiX toolset parlance, I'm talking about not specifying "yes" for the Advertise attribute on the elements with the same name as the tables above.

A lot of people think that my recommendation to avoid advertising COM information means they should avoid using the Class, ProgId or MIME WiX elements.  I am not.  Those elements can greatly simplify your setup code; just don't set the Advertise attribute to "yes" (the default is "no").  The WiX toolset will take care of generating the correct Registry rows for you using stable identifiers.

So why do I recommend not advertising COM information?  There are two reasons.  First, COM advertisement can cause unexpected repair behavior.  In particular, the Windows Installer will repair other products that share the advertised COM information.  Second, these repair situations can require the user to provide the source for the advertised product which may not be the product the user is actually using.  The user will experience this undesirable repair behavior until they fulfill the source requirement.  This second issue is the real reason I discourage people from using COM advertisement.

Historically, I've had some people argue (quite vehemently) with me that the repair behavior cannot actually happen.  I'm going to go write some code now to demonstrate the problem.  Be back later...

Okay, it is a day later (had to actually do real work today <smile/>) and I now have two example packages up on my web server so you can play along from home (link in step 0 below).  These are modifications to my "Fruit Server" demo.

For those of you that have never seen it, the "Fruit Server" is silly piece of code that you can call and it will randomly return you the name of some fruit.  The Fruit Server is implemented as both a DCOM Windows Service (native code, with a command-line client) and a Web Service (web browser is a client).  I use these programs to demonstrate how to do setup for "Windows things" and "Web things" in one place.  In this particular demo, I only needed the DCOM Service so I left out the Web Service.

Finally, to demonstrate the problem I provide "fs.msi" which is the normal "Fruit Server" that doesn't advertise anything and "fs2.msi" which is "The Other Fruit Server" that can advertise its DCOM proxy stub.  Those two installs will create directories in the ProgramFilesFolder with their respective names, so you can easily tell when they are fully installed.  Now, let's get on with the show.

0.  Download the Fs2Advertise.zip and unzip it to C:\demo

1.  Open up a command prompt:  Start -> Run -> cmd.exe

2.  Open up explorer window to ProgramFilesFolder: start "" "%ProgramFiles%"

3.  Scroll to the bottom of your ProgramFilesFolder explorer to see where new directories will be created.

4.  Install "Fruit Server": msiexec /i C:\demo\fs.msi

5.  Notice that "%ProgramFiles%\Fruit Server" is created in explorer.

6.  Run the Fruit Server client to get a fruit: "%ProgramFiles%\Fruit Server\FsClient.exe"

7.  Advertise "The Other Fruit Server": msiexec /jm C:\demo\fs2.msi

8.  Notice that "%ProgramFiles%\The Other Fruit Server" is not created.  That's because only the advertised entry points are registered.  In this case, only the DCOM proxy stub.

9.  Run the Fruit Server client to get another fruit: "%ProgramFiles%\Fruit Server\FsClient.exe"

10.  Notice that it takes a second for the Fruit Server client to return a fruit.  Then notice that the "%ProgramFiles%\The Other Fruit Server" folder was created!

These 11 steps demonstrate the first behavior I was talking about.  The execution of one program is suddenly affected by the installation of a second program.  To be specific, the entire feature in the second program that was advertised gets faulted in.  If that second program has hundreds of megabytes in an advertised feature (not a great design to begin with) the DCOM activation must wait for the install to complete.

Okay, that behavior isn't so great but let's look at the second issue.  This one is a the real kicker in my mind.

0.  Uninstall both of the installed programs. msiexec /x C:\demo\fs.msi & msiexec /x C:\demo\fs2.msi

1.  Advertise "The Other Fruit Server": msiexec /jm C:\demo\fs2.msi

2.  Rename "The Other Fruit Server" package to simulate the CD being ejected: move C:\demo\fs2.msi C:\demo\fs2x.msi

3.  Install "Fruit Server": msiexec /i C:\demo\fs.msi

4.  Launch the Fruit Server client to get a fruit:  "%ProgramFiles%\Fruit Server\FsClient.exe"

5.  Notice the source resolution prompt from the Windows Installer!  Notice even more closely that the prompt is asking for the path to the fs2.msi! 

6.  Hit cancel (maybe three or four times) to get your fruit.  Repeat step 4 and notice you always get prompted.

7.  Rename "The Other Fruit Server" package to allow you to remove it: move C:\demo\fs2x.msi C:\demo\fs2.msi

I hope you agree that this is pretty "wonky" behavior.  Even more users absolutely hate source resolution prompts, so if you did the work to ensure you avoid source resolution prompts another program could totally screw you up.  Finally, even if users did like the prompts you have to admit it is very strange that your program is asking for the source media for a completely different program.

Now some people will argue that you should use COM advertisement to improve the reliability of your program.  Personally, I don't see how one can argue that the side effects that COM advertisement exposes a program to can be considered reliability improvements.  If someone really wants to build reliability around their COM activation then I would highly recommend not advertising COM information, handle the error codes returned from ::CoCreateInstance() (and friends), and then repair the application using the MSI APIs.  Using this method, you have far more control over the Windows Install repair behavior.

Finally, I considered titling this blog entry, "Why you can and should ignore ICE33" but that title wouldn't be quite accurate.  For example, ICE33 also catches Extension and Verb registry keys.  IMHO, advertised Extension and Verb elements, like shortcuts, provide very logical user entry points to cause your application to get installed or repaired.  A user that double clicked on a file then saw an application begin to install is far less likely to question a source prompt (if the application can actually open that file extension) than if a program internally kicked off a repair and prompted for some other programs original media.

Oh, and before I wrap this blog entry up, anytime someone suggests you should ignore an ICE warning, you really should do your homework to understand why.  Hopefully this blog entry finally clears up all the complex behavior that explains why I don't recommend you advertise COM information and acknowledge but ultimately ignore the ICE33 warnings.

 

12 Comments

Comment by Darwin Sanoy at DesktopEngineer. on Thursday, March 15, 2007 7:53 AM

Rob,
Excellent work! It would be awesome if you enhanced your demo to show one more commonly encountered problem in enterprise environments.

One point of clarification - your example is actually showing install on demand behavior, which - if I'm not mistaken - works by feature install states, not component keypaths. I think your demo is the most relevant of the two scenarios because:
*) It is the most confusing to end users
*) It can happen even if users are completely locked down and actual self-healing risk is quite low.

As a best practice corporate environments should explicitly turn off advertising for all features that are setup to advertise by default and when deploying via group policy, always do a full install when targeting users (Windows 2003 and later). The only *straight forward* way that I know to do this is a response transform - but I'm working on a more generic solution as well.

D.

Comment by Darwin Sanoy at DesktopEngineer on Thursday, March 15, 2007 8:34 AM

Rob,
I did a lot of hammering on this and I think I have a simple command line solution for corporate admins that could dramatically reduce the instances of this issue.

I have blogged it here (and linked back this entry): http://desktopengineer.com/home/all_articles/windows_installer_com_advertising_and_cross-product_interaction

Comment by Jacob Idicula on Friday, March 16, 2007 8:35 AM

Hi Rob,

I have been communicating with you through Mat Williams, he has asked me to respond to you directly on this bolg.

I had a question about the practicality of your suggestion.

1. When populating the extension table would you populate the ProgId_ field.

2. Currently we are using WISE to repackage application setups and it doesn't provide the facility to selectively use advertsing information. Would have any sugesstions on how to go about doing it.

Best Regards
Jacob Idicula

Comment by Dan Lee on Tuesday, March 27, 2007 8:42 AM

I ran into this issue with the Microsoft Speech Recognition Engine distribution recently. If a users has Microsoft Visio installed and then installs our application, our application will install Speech Recognition engine 5.1. After install, the user opens our mapping application and accesses the voice controls. Once they do this, the repair scenario runs for Visio. Fortunately it only runs once. Unfortunately I have not found a way to prevent this behavior other than not distribute the speech recognition engine - which is not an option.

Comment by Rob Mensching on Tuesday, March 27, 2007 9:13 AM

Dan, that's really funny. Back in the old Office days (XP, I think), I told the Speech Team (who was delivering to Office) not to advertise their stuff. They were the way that I uncovered this behavior. You are now hitting *exactly* the same problem. Congratulations and I'm sorry I wasn't able to be more persuasive back then.

Comment by Pelle on Tuesday, April 3, 2007 5:50 AM

We've been trying to avoid time-consuming resilience checks based on the InProcServer32 magic cookies + msi-hooked calls to CoCreateInstance but have failed so far. Does anyone know if there's a workaround (our users don't appreciate random 5s hangs while windows installers checks that some files that existed half a minute ago still exist)?

Comment by Pelle on Saturday, May 19, 2007 2:33 PM

Oh, and it doesn't help that Installshield can extract COM info but cannot be coerced into installing it as "pure" registry values…
What we're going for now is a custom action that removes all Darwin descriptors after everything else has been written. Results indicate that performance of CoCreateInstance is an order of a magnitude better.
No love for Installshield of Windows Installer right now.... (it's a bit wonky that it looks as if only files in the GAC are checked - indicates a possible serious bug in the .NET additions to Windows Installer)

Comment by Paul on Wednesday, May 23, 2007 2:49 AM

Just a question Rob, I have re-authored your fs.msi to remove all ICE errors and now have no problems with the displayed behaviour. To be perfectly honest I would expect to get the problems your seeing when you sit a correctly authored MSI on an MSI that isnt, how is this a problem for MSI and a reason to leave ICE 33 warnings in a package????

When we package up any application, including Microsoft ones, we re-author them using transforms to remove ICE errors, leaving them in can causes problems like this, remove them and voila they go away!

Now I dont pretend to be the be all and end all in packaging but if i am able to reauthor your badly packaged MSI (fs.msi) and remove the behavior your seeing with advertising on fs2.msi) then I must be better than I thought.

Paul

Comment by Paul on Wednesday, May 23, 2007 3:15 AM

I withraw what I said, incorrectly authored the msi through the ommition of the appid information.

Paul

Comment by Steve on Friday, December 14, 2007 12:25 AM

The problem that caused me stop using advertised COM information was down to what I believe is a fundamental design flaw in the Class table. I’ll explain. The Class table has a foreign key to the Feature table, thus tying a particular COM class to a single feature. This is the feature that Windows Installer will try to repair. Imagine you have an msi that has two top level features FeatureOne and FeatureTwo, both of which contain the same component with the COM class. The Class table references FeatureOne in the Feature_ column. Now, if you install the product but only install FeatureTwo you will find that the COM component executable has been installed as extrected, the type library from the TypeLib Table has been registered, and NEARLY all the CLSID information had been registered. You will find that the InprocServer32 key is empty.

If you have published an msi that uses advertised COM, and then want to issue an upgrade that does not use advertised COM, you will need to have the new msi explicitly remove the InprocServer32 registry values that contain the “Darwin Descriptors”. Otherwise you will continue to get the undesirable behaviour, even after the upgrade.

Comment by Vadim Rapp on Saturday, April 12, 2008 2:43 AM

I'd think, these considerations are valid only in the case of publicly available software, that comes on CD, downloaded, etc. Yes, it's pretty obvious that advertising what's not available is bad idea. Compare this to a retail store giving you a raincheck, however, without any intention to have the item in stock in the future - would be deceptive.

But in case of network distribution by group policy, I don't see anything wrong in advertising. It's similar to using server-based applications, only in this case "delayed", so to speak. If I have COM object serving particular function, it's quite straightforward and logical to advertise it by assigning to all users without actual installation. Whoever needs the object, will have the package installed just when they need it. Whoever does not, will not have to install it. Also, if the user already have the package version 1, adversiting COM information is the easiest upgrade - next time the user is using the object, the package is upgraded. Without this, you have to create a WMI filter to find all users who have version 1 installed, and push version 2 to them - obviously less elegant.

Finally, if you know you have an object that might interfere (undesirably) with other applications, maybe it would be good idea to isolate it.

Comment by Bernd Brings on Thursday, April 18, 2013 6:18 AM

Hi, really great article. For further investigation i need Fs2Advertise.zip but it is not available any more. Is there a way to get it anywhere else ?

Leave a comment
optional