Rob Mensching has been promising to put an updated version of WiX with better written documentation on sourceforget.net for a while now. But at the time of writing the May 27th build is still the latest one. But do you know what? I’m beginning not to care. I’m actually getting to the point where I can do anything I want: though the gifts of dark and orca (for examining what’s going on in an msi) and virtual pc for an easy way to test roll outs.

<?xml:namespace prefix = o ns = “urn:schemas-microsoft-com:office:office” /> /o:p

After the epic that was finding out how to ngen stuff as part of an MSI I moved on to trying to automate other parts of our deployment process. This means running the installer classes inside the .NET assemblies. While could have used the same approach as ngen added a CustomAction that called InstallUtil with the correct parameters, I wanted to see if it was possible to call the install classes directly from the MSIs.

 /o:p

I started off with the assumption that if it was possible to call install classes directly from an MSI then this is what visual studio generated MSI would do. Anyway visual studio generated MSI do not call the install class directly, but they don’t make a call to installutil.exe either; so I thought I’d explain here what they do. I guess this doesn’t prove that it isn’t possible to call installer classes directly, so if any one has a way of doing this I’d be interested to here.

 /o:p

While anyone could of course use dark to reverse engineer a visual studio generated assembly for themselves, there are a few little pit falls that make it quite tricky. Also visual studio produced installers look pretty yucky when reverse engineered from dark because of the auto-generated ids. So I thought it might be worth a blog entry anyway.

 /o:p

When visual studio creates an msi with a custom action it embeds 3 binary streams into the binary table. You can use dark with the –x switch to get both the syntax for embedding these and the streams themselves. Below is shown the syntax for adding them to the binary table. These binaries provide a sort of installutil like functionality that can be embedded into the MSI. While only InstallUtil is directly involved in running the installer class, the other two are required as either libraries or to set up some temporary files required by the InstallUtil.

 /o:p

<Binary Id=“InstallUtil” src=“Binary\InstallUtil.ibd” />/o:p

<Binary Id=“MSVBDPCADLL” src=“Binary\MSVBDPCADLL.ibd” />/o:p

<Binary Id=“VSDNETCFG” src=“Binary\VSDNETCFG.ibd” />/o:p

 /o:p

Running the installer class requires two CustomActions tags. One CustomAction sets up a property which will form the parameter to the call to the InstallUtil then the second custom action class actually call the InstallUtil. The syntax is shown below, the most important bit is the Value attribute, get this wrong and the installUtil will throw an error, most likely a cryptic one.

 /o:p

<CustomAction Id=“TestInstaller.dllInstall.install.SetProperty” Property=“TestInstaller.dllInstall.install” Value=“/installtype=notransaction /action=install /LogFile= &quot;[#TestInstaller.dllFile]&quot; &quot;[VSDFxConfigFile]&quot;” />

 /o:p

The &quot;[#TestInstaller.dllFile]&quot; section of the value is arguably the most important bit. The “TestInstaller.dllFile” should be the id of the File tag that contains the installer class you whish to run.

 /o:p

I’ve tried removing the &quot;[VSDFxConfigFile]&quot; section as I couldn’t work out where this was coming from, an therefore thought it was wall dressing. But the InstallUtil will not work with out it. The properties value is actually set up by the custom action shown below.

 /o:p

<CustomAction Id=“SetPrereqs” BinaryKey=“MSVBDPCADLL” DllEntry=“CheckFX” />

 /o:p

The custom action that actually runs the InstallUtil is given below. The one thing that slightly unclear to me is why the parameter created in the TestInstaller.dllInstall.install.SetProperty is passed to the InstallUtil. I’m guessing that it’s because the CustomAction and the Property share the same name, but I’m not completely sure.

 /o:p

<CustomAction Id=“TestInstaller.dllInstall.install” BinaryKey=“InstallUtil” DllEntry=“ManagedInstall” Execute=“deferred” />

 

And that about it, the rest is stuff I’ve coved before. I’ve gone to town on the example, there is a c# source file included that creates a .dll with an installer class, so the wxs source file should compile, link and run no problem.

Feedback:

Feedback was imported from my only blog engine, it’s no longer possible to post feedback here.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Per Bergland

Since you’ve dived heavily into this, can you understand why, if the same binary installer class assembly is used as a custom action twice from two different locations (in my case in two different merge modules), installutil runs the "first" assembly twice, thereby causing me headache, overwriting the install state and also not allowing me to use the assembly’s codebase to figure out where I’m being installed.

The installer log seems A-OK in the SetProperty call, but the dll path that it sets isn’t used:
i.e. excerpts from the log file

Property(S): _0BE99E77_3C01_420F_A33F_846759DD7199.install = /installtype=notransaction /action=install /LogFile=webserviceinstall.log /Verbose /TARGETDIR=.. /DEFAULTDOC=SpaceService20.asmx /VDIR=XXSpaceWeb /DEFVDIR=SpaceWeb "C:\Program Files\Carmenta\SpaceWeb2\SpaceWeb Web Service\SpaceWeb Web Service\bin\Carmenta.VDirInstaller.dll" "C:\DOCUME~1\pebe_p\LOCALS~1\Temp\CFG4626.tmp"

Property(S): _8FF9ED89_DD8F_41A8_94B9_70FB394F142E.install = /installtype=notransaction /action=install /LogFile=demositeinstall.log /Verbose /TARGETDIR=.. /DEFAULTDOC=default.asp /VDIR=XXSpaceWebDemoSite /DEFVDIR=SpaceWebDemoSite "C:\Program Files\Carmenta\SpaceWeb2\Samples\SpaceWebDemoSite\bin\Carmenta.VDirInstaller.dll" "C:\DOCUME~1\pebe_p\LOCALS~1\Temp\CFG4626.tmp"

The dll path set last is used for the first install as well…

re: Running .NET installer classes – Reverse engineering what VS.NET does - Per Bergland

And I think I found the cause of the problem 5 minutes later:

***************
An entry from David Levine at http://blogs.msdn.com/astebner/archive/2004/06/06/149713.aspx:

2. Windows installer itself has bugs in how it invokes custom actions. It works great if you run the install or uninstall as completely separate operations, but if you try to use the automatic uninstall/install feature you are in for a nasty surprise. The current implementation creates a single appdomain (the default) out of which it runs all custom actions in managed code, and it never recycles the appdomain. That means that once you load an assembly it stays loaded. This means that if an old assembly runs an uninstall routine, then when the newer version of it is copied to the target, instead of running the install custom action in the new assembly you will actually run the install CA in the old assembly.

***************
I.e. I must have two different binaries (different names or different strongnames).
This truly and deeply sucks.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Robert Pickering

Glad you found an explaination, I was completely unware of that bug.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Mike Green

This is a great insight into running installer classes. Do you know anyway of generating the necessary .ibd files without using Visual Studio?

I’m trying to get installer classes running using WiX and only the .NET Framework SDK 1.1 with an app developed in Visual Basic.

Thanks in advance.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Robert Pickering

It appears that ibd streams can be encoded and decoded with the commandline tool "msidb.exe" [1] which is part of the installer platform SDK. However it doesn’t look to intuitive to use and I after a quick glance I can’t see a switch that you need to choose to convert a .dll to .ibd. Having said that I think .ibd I’m talking about were create specifically for visual studio so might not be able to get a copy of the orginal dlls with out visual studio.

What I did was once I’d used dark.exe (part of WiX) with -x to extract the .ibd files is place them in the our source repository so the build server had access to them. I guess theres arguments against putting binary files inside you’re souce control system, but I think it’s okay under some circumstances (and this is one of them).

Having said all that I’m now moving away form using this technique to run instaler classes. This is because I try to install a service and discovered that doing it this way didn’t allow me to specific a username and password switches. I now tend to run the installutil.exe in a very similar way to how I described running the ngen tool. You get annoying cmd shell window popping up in the middle of you’re install but I can live with that.

[1] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msidb_exe.asp

re: Running .NET installer classes – Reverse engineering what VS.NET does - Mike Green

Thanks for that. After further investigation, I’ve concluded that the .ibd files are probably simply the original binary files with different names. InstallUtil.ibd is InstallUtil.dll from the .NET Framework SDK. I’m guessing that the other two are native to Visual Studio 2003. Probably MSVBDPCADLL is MSVBDPCA.DLL and VSDNETCFG is VSDNET.CFG. I’ve picked up all three files from an available .msi using dark.exe -x to extract them. I’ve also discovered that InstallUtil.dll is different between the .NET Framework SDK 1.0 and 1.1 so care is needed to use the right one. Visual Studio 2002 installation packages only seem to use InstallUtil.ibd and not the other two.

I’ve suggested that WiX incorporate these aspects of Windows Installer packages in some form but only time will tell whether Rob Mensching decides to take this forward.

I haven’t tried installing a service with a specific username/password but surely you can do it with ServiceProcessInstaller.Account ServiceProcessInstaller.Username and ServiceProcessInstaller.Password can’t you?

re: Running .NET installer classes – Reverse engineering what VS.NET does - Robert Pickering

Thanks for the info about where the ibd files come from I had often wondered but never bothered to find out.

You can set the account an a service is installed under via ServiceProcessInstaller.Account ServiceProcessInstaller.Username, but the installer class for this project exposes them via /username and /password switch, which can be read ServiceProcessInstaller.Conext.Parameters, but using InstallUtil.dll doesn’t seem to populate the Parameters collection correctly. Then again it could have been something I was doing wrong as I didn’t spent too long trying to get it working, as I was already fairly fed up by this point.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Mike Green

I think I was slightly wrong about the original file names. I now think MSVBDPCADLL.ibd derives from DPCA.DLL and VSDNETCFG.ibd might be built on-the-fly as its a .config file that is editable with a text editor.

Rob Mensching has rejected my suggestion to build InstallUtil capability into WiX with a cryptic comment about avoiding using InstallUtil in Windows Installer packages. I’m hoping he will elaborate on why he thinks it isn’t a good idea to use InstallUtil in the next few days.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Adar Wesley

Great description of what happens. I have been investigating this for the passed few days, and this helped me fill in some gaps.

One point you left open in the original post is:
>>The one thing that slightly unclear to me
>>is why the parameter created in the
>>TestInstaller.dllInstall.install.SetProperty
>>is passed to the InstallUtil. I’m guessing
>>that it’s because the CustomAction and the
>>Property share the same name, but I’m not
>>completely sure.

Your assumpsion is correct!
In order to pass Installer Property values to a deferred CustomAction, you set a propety with the same name as the CustomAction in "Execute Immediate" mode.
When the deferred CustomAction is executed, the value is available to the CustomAction through the CustomActionData property.

I found the clearest explanation for this behavior in the "Wise For Windows Installer" Help file.

Search for: "Tips on Calling .DLLs"
Find the Section:
"Accessing Windows Installer Properties from a Custom Action"

Begin Quote:
————
For the Call Custom DLL actions, in the User Interface or Execute Immediate sequences, you can send Windows Installer properties to the .DLL function as parameters. The property’s current value is passed to the function and, if the function changes that value, the new value is put into the corresponding property.

In the Execute Deferred sequence, you are limited in the number of properties you can access. You can only access these properties from a custom action in deferred mode: UserSID, CustomActionData, and ProductCode. CustomActionData is filled with the property value of any Windows Installer property that shares the same name with the Custom Action. See the topic titled Obtaining Context Information for Deferred Execution Custom Actions in the Windows Installer SDK Help.
———-
End Quote:


re: Running .NET installer classes – Reverse engineering what VS.NET does - Oleg Zelenkov

The ManagedInstall() function is defined in the %FrameworkDir%\%FrameworkVersion%\InstallUtilLib.dll

While it is desirable to have an ability to invoke InstallUtil.exe from MSI, I would not want to find it amongst WiX custom actions. I’d rather expect this feature from the MSI team. I think a new action is to be introduced. That would save time and solve bugs once and for all.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Tim

Please help me and tell me how to get MSVBDPCADLL.dll file

Regards,
Timothy.asir@mindteck.com

re: Running .NET installer classes – Reverse engineering what VS.NET does - karl oyun

hi,

these CAs seem to be native to VS.NET and therefore are not suported. What this means is basically that VS needs them for managing virtual directories in its web projects and you are not suppose to use them on your own. But again, who cares what is allowed and whats not… take a look here http://nant.sourceforge.net/wiki/index.php...%20build%20file
That is a nice example of using all the WEBCA actions, their meaning is in their names i think…

As for the others, my guess is:

DIRCA_CheckFX - checks if .NET framework is installed on the target machine

VSDCA_VsdLaunchConditions - same as LaunchConditions, but checks for specific VS.NET components.

ERRCA_UIANDADVERTISED - checks if the product is advertised. if it is, it will prevent execution of the installation in full UI mode

ERRCA_CANCELNEWERVERSION - cancel installation if the newer version is detected (typically executed after FindRelatedProducts action).

There is no such thing as MSVBDPCADLL.DLL, instead you should be looking for MSVBDPCA.DLL (http://www.biacreations.com/MSVBDPCA.DLL) as MSVBDPCADLL is just a handle to the file.

re: Running .NET installer classes – Reverse engineering what VS.NET does - Reverse engineer

I like this a lot, l work in reverse engineering.