Whew, I’ve had a great couple of weeks working away on the book and am really starting to make some progress. The installation says I’m installing 10MB of code and binaries so it’s starting to get there. The folks I’ve shown the code to are very excited and are especially impressed with the new SuperAssert.NET. Let’s just say it has some serious magic going on in it. You’re going to love it.

I finally got the installation moved over to the very interesting Windows Installer XML (WiX) Toolkit. The other product I was using would have been fine if I was near the end of development and knew all of the files I was going to be installing. However, best practices have you develop the install right along with the code. With the old product, I was spending forever baby sitting, tweaking, and fiddling, with the install to keep it building. The old product would have been great if I was near the end of development. However, it wasn’t very well suited for continuous use.

WiX doesn’t have the best documentation in the world, the bigger problem is the Windows Setup system itself. After reading through their documentation, I really wonder if the designers came from another planet. Maybe I’m missing something, but the whole thing seems massively more complicated than it really needs to be. Some of my pain is probably because I haven’t done too many installs, but everyone I’ve talked to has expressed the same sentiments.

After I somewhat figured out what I wanted my WiX install to do, I spent lots of quality time with the fine online tutorial by Gábor DEÁK JAHN. However, I was still missing something because I couldn’t see how to break up my installation. I wanted a .WXS file for each major binary for independence. My idea was that in that binary’s .WXS file would be all the source code, tests, and everything related to that binary. (When I’m saying binary here, I mean the entire directory tree that contains all the source code, tests, and extra files that make up that binary.)

I didn’t want one gigantic .WXS file for the five thousand or more files I expect to have in the end. While I could see how to use fragments, the only examples I saw showed that I was going to have to have a <ComponentRef> for each component. For some of the binary .WXS files are going to have fifteen to twenty components in them. The last thing I wanted to do was to be manually maintaining a list of components a thousand lines long. As I’m in the midst of the coding battles, I may be adding and removing components and files on a regular basis.

What I really wanted was a way to refer to all the components as a group so I could isolate the changes to the individual binary’s .WXS file and not have to maintain the component list in two separate files. Out of desperation, I started reading the WiX schema file reference and stumbled across <ComponentGroup> and <ComponentGroupRef>. Aha! That’s what I was missing. The <ComponentGroup> lets me lump all the components in a .WXS fragment in a logical place, the .WXS fragment itself. With <ComponentGroupRef>, I can add the reference to the binary in the appropriate <Feature> tag and rest assured that all the changes I’m making to the individual .WXS fragment are picked up by the main installation.

Once I got the Zen of component grouping, I just had to build my individual .WXS fragments for each binary. Using Tallow that comes with WiX, you can build the initial fragments. While Tallow’s helpful, the output will need a bunch of munging to make it useable. Here are the steps I follow on each initial .WXS:

  1. Delete all extraneous directories, *.SCC and all hidden files.
  2. Create an empty .WXS file matching the top level directory name.
  3. Run tallow.EXE across the directory: tallow -nologo -d ..Foo > Foo.wxs
  4. Change the initial DirectoryRef Id to INSTALLDIR
  5. Change each of the Directory and Component Ids to include the directory name. Keep the names to less than 72 characters.
  6. Add KeyPath=”yes” to each component.
  7. Change all src attributes to use relative paths.
  8. Change all the “file##” values to “file_<DIR NAME>_##. For example, file0 would become file_FOO_0.
  9. Under the Fragment element, create a ComponentGroup and add all the components in the file.
  10. Change all the PUT-GUID-HERE to a real GUID. Make sure to uppercase the GUID string itself.
  11. Add the group reference to the appropriate master install Feature element.
  12. Add the new .WXS to version control!

Below is an example of one of my WXS fragments so you can see how they are set up. Yes, I did the right thing and removed the GUID just so you wouldn’t accidentally reuse it.

<Wix xmlns=http://schemas.microsoft.com/wix/2003/01/wi>
  <
Fragment>
      <
ComponentGroup Id=groupFxCop>
          <
ComponentRef Id=componentFxCop/>
      </
ComponentGroup>
    <
DirectoryRef Id=INSTALLDIR>
      <
Directory Id=directoryFxCop Name=FxCop>
        <
Component Id=componentFxCop
                  
KeyPath=yes DiskId=1
                  
Guid=PUT_GUID_HERE>
          <
File Id=file_FXCOP_0
               
Name=CUSTOM_1.XML
               
LongName=CustomDictionary.xml
               
src=….FxCopCustomDictionary.xml />
          <
File Id=file_FXCOP_1
               
Name=DTT-DE_1.FXC
               
LongName=DTT-Debug.FxCop
               
src=….FxCopDTT-Debug.FxCop />
          <
File Id=file_FXCOP_2
               
Name=FxCop.wxs
               
src=….FxCopFxCop.wxs />
        </
Component>
      </
Directory>
    </
DirectoryRef>
  </
Fragment>
</
Wix>

After I have a .WXS fragment together, it’s just a matter of editing to add additional files and directories. Now I have my install code directly as part of the coding process so there’s much less time messing with installations, but I get all the benefit!

All I have left on the install is some UI work to offer the option to start the ReadMe.CHM and to connect to the book’s web site to look for updates. That’s all the easy stuff compared to getting the installation organized and building every build.