I had never before attempted to create a deployment project in Visual Studio. So, of course, the first time I was asked to do so, I also had to deploy the .Net Framework and MDAC as well! Why should my life be easy?
Everyone has used Windows Installer at one time or another; it is how almost all Windows-based programs are installed today. You have used it if you ever added or removed a program in the "Add/Remove Programs" section of Control Panel. If you double-click on a file with the extension of "msi", it will start up Windows Installer.
Here was my challenge: install and run a website on a computer that was not attached to the internet, and did not have IIS installed. Instead of IIS, we would use Microsoft's Cassini web server. The catch was, Cassini is written in C#, and therefore requires the .Net Framework. And because the website that we were going to run in Cassini was going to hit an Access database, we also had to install MDAC (2.6 or higher). The target computers were unlikely to have either the .Net Framework or MDAC of any vintage installed.
The first step was to open Visual Studio and create an application setup deployment project (New Project > Setup and Deployment Projects > Setup Project). Using the file editor, I added the website and the Windows Forms application (which runs the website under Cassini) to the Application Folder (since it wasn't running under IIS, it didn't need to be in wwwroot). I added the Cassini.dll to the Global Assembly Cache folder, and created a shortcut to the Forms application, putting it in the Users Desktop. When I built the solution, I had an MSI file to do the hard work of deployment.
Windows Installer was created to facilitate installation of high-level applications (like what I describe in the previous paragraph), not core infrastructure applications like the .Net Framework and MDAC. Originally I did try to do it that way, adding a Custom Action to install MDAC. But that just didn't work. Since the computers we needed to install on were not connected to our network, we needed a simple way for a non-technical person to run the install of everything required. Helpfully, Microsoft provides two C++ programs, one to install the Framework [#1], and another to install MDAC [#2], and explained how someone "skilled in C++" could combine the two. Which I am not.
It was therefore with great joy that I discovered that Kevin Moore posted a program on The Code Project [#3] written in C++ that would install everything necessary to run a .Net application, including Windows Installer itself, the Framework, MDAC, IE 6, and even, where needed, MSDE. A simple INI file provides a few necessary bits of information, one of which is the name of the MSI file that would load your .Net application subsequent to the other systems being installed.
How it works
One of the first things the setup program does is determine what already exists, and therefore does not need to be installed.
To determine if the .NET Framework exists, it does the following:
- get the FxInstallerPath variable from the settings.ini file and attempt to find the dotnexfx.exe file there (If the variable value is just a dot, that means look in the current folder.)
- if found, get the file version from the dotnetfx.exe file
- get the .NetVersion variable from the settings.ini file (example: v1.1)
- look for the HKLM\SOFTWARE\Microsoft\,NetFramework\Policy\v1.1 registry folder
- locate the registry key for the file version (example: 4322) matching the file version of the dotnetfx.exe file
- get the numeric LanguageDirectory variable from the settings.ini file (default: 1033, U.S. English)
- build a path using this information: c:\WINNT\Microsoft.Net\Framework\v1.1.4322\1033\. If the directory is found, no need to load the framework.
To determine if any level of MDAC exists on the machine, it looks in the registry at HKLM\SOFTWARE\Microsoft\DataAccess, looking for the FullInstallVer key. If MDAC 2.5 is installed, it will have a value like this: 2.53.6200.1. You set what is the minimum level acceptable (which, to work with the Framework must be at least 2.6), by setting the MDACVersion variable in the settings.ini file that comes with Moore's setup program. If the FullInstallVer is greater than or equal to the value in the settings file, no need to install MDAC.
Similarly, to see that the version of Internet Explorer is at least v5.1, it checks the HKLM\SOFTWARE\Microsoft\Internet Explorer folder and gets the value for the Version key.
The original version of Kevin Moore's program installed systems in this order: IE, MDAC, MSDE, MSI, and finally the .NET Framework. I suspect that I ran into a problem with MDAC loading before .Net. So, I changed the order to: MSI, .NET Framework, MDAC, IE, and I don't allow MSDE to load at all (since our particular project didn't need it). This seemed to work fine. And I could be wrong that loading MDAC before .Net was really the cause of an error. At any rate, the new ordering made more sense in my mind, and it worked.
Speaking of errors, if you should happen to be one of those people who doesn't get everything absolutely perfect the first time (can I see a show of hands?), Windows Installer puts error messages into the Application Event log. For more detail (lots more!!), use the following registry entry:
This will create a verbose log file in C:\Documents and Settings\[username]\Local Settings\Temp\, with the format MSIxxxxx.log, where 'xxxxx' is an apparently random collection of letters and numbers.
And Microsoft's Windows Installer FAQ page [#4] has a troubleshooting section with more information on logs, etc.
Once Moore's program installs all the missing infrastructure systems, it then executes my MSI file (the name of which must be set in the settings.ini file MSI variable) to install the .Net application I want to install.
My first deployment was tricky. Kevin Moore's version of the bootstrap program made it a great deal easier. And, I learned a lot about what works and what doesn't. May all your own deployment projects be easy and uneventful.
[#1] .NET Framework bootstrap sample -- www.microsoft.com/downloads/details.aspx?familyid=66350891-d15b-446b-bd69-f7f849224a00&displaylang=en
[#2] MDAC bootstrap sample -- support.microsoft.com/default.aspx?scid=kb;EN-US;q257604
[#3] Kevin Moore's excellent combined bootstrap -- www.codeproject.com/managedcpp/dotnetsetup.asp
[#4] Windows Installer FAQ -- www.microsoft.com/windows2000/community/centers/management/msi_faq.mspx