ISWIX, LLC View Christopher Painter's profile on LinkedIn profile for Christopher Painter at Stack Overflow, Q&A for professional and enthusiast programmers

Tuesday, December 12, 2006

OMG: InstallShield killed Kennedy

[EDIT: Portions of this post are seriously useless because of a flawed assumption. Please be sure to read the comments to understand why. ]

Sorry, I havn't had a rant in awhile and I really need to get this one of my chest. I want to let everyone in on a secret:

Setup Development IS Software Development

Setup is point and click for the user, NOT the developer

Since everyone else in the blogosphere is currently getting worked up over InstallAware, I'm going to pick one of my other favorite topics: Developers who blame their tools for all their problems.

I recently saw a thread on InstallShield community from Weevie who was asserting:

Since it would appear that IS does not support .net installer classes competently (they work fine in the VS2005 setup and deployment project :rolleyes how do people suggest I install a certificate.

Later someone offered:

Presumably you would write a set of wrappers around the CAPICOM.dll and then use these wrappers within a custom action. Obviously the CAPICOM.dll would need to be deployed onto the target machine before hand.

and the orginal poster added:

p.s. I should have mentioned we do not want to use Instalshield's proprietary stuff...only Microsoft's!

Wow, I really don't know where to start. I'll start with I know that InstallShield properly consumes Installer class custom actions because I was stuck in my own special hell working with hundreds of VDPROJ merge modules and hundreds of .NET Installer class custom actions. While I can't say the custom actions always worked properly, they were always fired by InstallShield. The fact that they blew up in mysterious ways was not InstallShield fault, it was the product of very bad design choice of using Installer class custom actions. When the CLR throws an exception InstallUtil doesn't help you awhole lot in handling it or knowing why. But hey, somehow Microsoft proprietary stuff MUST be better the InstallScript proprietary stuff.

The truth is InstallShields CoCreateObjectDotNet() pattern is so much more powerful then IntallUtil. Take this example of CAPICOM.dll. I don't have the assembly so I havn't seen the metadata, but I'll take a guess an easy solution would go something like this:

Insert CAPICOM.dll into the SUPPORT FILES folder. InstallShield will make this file available at runtime and you can find it's location by serializing the SUPPORTDIR property into the CustomActionData property because since your changing the system configuration I'm sure we'll want to schedule this as a deferred custom action with no impersonation.

Next we'll write a C# class and declarate it with [ComVisible(true)]. Instead of adding CAPICOM.dll as a reference, were going to use reflection to dynamically get the type of the server component, instantiate it and invoke the method that will instlal our certificates. Now drop this assembly in SUPPORT FILES also.

Finally we will write an InstallScript deferred custom action that reads the CustomActionData property and deserializes all of the properties we need. Then we will use CoCreateObjectDotNet to create an instance of our wrapper class that's stored in SUPPORTDIR. Finally we'll invoke the wrapper method. We'll also use a try.catch block to handle errors and if we find any we'll exit the InstallScript CA ( Type 1 MSI ) and trigger a rollback.

If for some reason we decide we just really, really don't want to use InstallScript then we can replace it with out own Type1 CA that does the same thing.

Absolutely everything that I just described has been discussed ( with detailed code examples ) here on my blog. It all really does work so. Sure there are alot of different moving parts to understand but it's up to you as a developer to master them. Remember that before running off and blaming InstallShield for yet another alleged infraction.

1 comment:

  1. When I originally wrote this article, I had never looked at capicom.dll and didn't know anything about it. I wrote the post on the assumption that the original poster had a valid reason for calling an Installer class.

    In hine site, there was no valid reason. capicom.dll is an unmanaged automation object ( COM ) and in order to consume it in .NET you don't add it as a refernce, you generate a runtime callable wrapper using tlbimp and add the interop as a reference.

    But InstallShield is unmanaged code so there is no reason to go to .NET in the first place. Just call the COM automation directory with CoCreateObject(). It also seems that CAPICOM.dll is built into windows these days so there is no reason to deploy it either.

    So just google for CAPICOM SDK and download/install the MSI package. You'll find a samples directory including VBS which will give you everything you need to know to port this code over to InstallScript.