My Wix Journey - Day 21 @ 6:39pm EDT
This is more of a Windows Installer complaint, but since WiX and Windows Installer are so closely linked, I feel justified making these comments.
The mechanism that Windows Installer uses to call custom actions is convoluted, at best. A DLL embedded into an MSI is extracted at runtime to the %TEMP% directory, and dyamically renamed to a named format, "MSI???.tmp", where the string '???' is psuedo-randomly generated (There may be a pattern, but I haven't spent the time to figure it out.)
Why do I care? Well, I attempted to write an embedded DLL that used Managed Code. Specifically, I used C++ for the Windows Installer entry points, and then generated a c# module. This worked perfectly for my nUnit test suite, but my instalation kept failing when I tried this from Windows Installer. After quite some time debugging, I finally examined the fusion assembly binding logs. I discovered that even though the module is embedded in the same PE file as the original calling assembly, the .NET framework first looks for a '.module' file external to the existing assembly. If it fails to find that '.module', it then examines itself to find the referenced .net module. However, a small 'feature' is that it does this by looking for it's own original assembly name. The problem I experienced is that Windows Installer has renamed my assembly to the MSI???.tmp name, so I would get assembly/module load issues.
So, that went down the drain. As I am relatively C++ averse (especially Managed C++, though C++/CLI is supposed to rescue me from the ugliness that is MC++), I really preferred to write my CAs in C#.
My solution was to write an external assembly that I install into the GAC. Now, my c++ "interop" layer can always find the C# custom actions, as they are globally installed. That does leave me with a chicken and egg problem, though. How do I get my c# custom actions into the GAC before I call them? After all, I must have them available during my UI sequence, and I can't wait until intallation time for my CA's to be present.
I followed the same solution that InstallShield uses for there "InstallSheild Engine", idriver.exe. I wrote a mini-install to place my c# assembly into the GAC, and perform this installation at the beginning of my 'main' installer.
This is a lot of effort to get around the fact that the Windows Installer team hasn't really considered managed custom actions, although the user groups are teaming with such requests. Even though all future versions of the operating system will guarantee a managed framework, the WI team still insists on C++ as the custom code 'story' for windows installations. (Please don't tell me that Windows Installer supports vbscript. We all know this. We also should know that vbscript is very, very bad in installation situations).
So, a long story short - managed CAs are possible, but not easy. I'll post more on my Managed CA adventure soon.