27 September, 2006

Windows Installer Woes

Launching a windows application after install completes in Windows Installer


I was tasked at work to become the "install czar" so to speak. For this, I needed to learn some things about the Windows Installer. While there is a pretty good guide for the Windows Installer at Microsoft's MSDN site, much of the information was elusive. For instance, I needed information about custom actions. For one installation I created a windows forms application which would copy a boat-load of images from the install DVD to the client machine. The images were about 3Gb in total size, so I didn't want to package them in the install. The install contained a small sampling of the images, and it was bulging at 300+Mb - this takes such a long time to process, checkout, build etc.

MS has a pretty good CustomAction Reference page, but it didn't cover everything I was looking at. I went into the setup project I had created in VS 2003, added the .EXE I had created and added it to the "Install" custom action. It seems to me, this should have worked, but it didn't. It appeared the EXE was never called. So I downloaded the Windows Platform SDK which comes with an ultra-cool tool called Orca which allows editing of the MSI tables. Looking at the tables, the EXE being called had a type of 1024. However, there was not 1024 type in the reference page.

Long story short, I found this blog from some guy calling himself Boneman, which is an excellent tutorial for Custom Actions in the Windows Installer.

I tried everything I could think of to get this stupid application to launch at the end of the install - nothing seemed to work. Then I went and revisited the Custom Actions section in the VS IDE. What I found was a property settings named "InstallerClass". I set that to "False" and voila! It worked!

But my application was flawed. I didn't know exactly what the working directory would be, I thought it would be the directory from which the install was launched. I was wrong, it was the directory in which the application file was placed. Now I needed to find the correct DVD drive in order to get the images off of it. To accomplish this goal, I imported the kernel32.dll to access the GetDriveType and GetVolumeInformation methods. These two methods return to me the type of drive, and all of the drive information you think you might ever want. Well, actually, the GetDriveType returns a System.Long value, and you have to know what each value represents. Here is how I figured drive type:


[DllImport("kernel32.dll")]
public static extern long GetDriveType(string driveLetter);

private int
DriveType(string asDrive)
{
if ((GetDriveType(asDrive) & 5) == 5)
return 5;
if ((GetDriveType(asDrive) & 3) == 3)
return 3;
if ((GetDriveType(asDrive) & 2) == 2)
return 2;
if ((GetDriveType(asDrive) & 4) == 4)
return 4;
if ((GetDriveType(asDrive) & 6) == 6)
return 6;

return 0;
}


Now, figuring out that 5 is the CD drive took quite a bit of searching, but having the Platform SDK mentioned above sure helps. At any rate, I got the CD drive, then looked for the volume name that I named the DVD during creation. If it locates that and the proper directory is on that disc, then it copies the files. If not, I pop up a folder browse window to allow the user to determine where the image files are.

No comments: