Creating an installer for a Single File Generator - Part 2

8 June 2009 · 3 minute read · Visual Studio · LINQ to Umbraco

This post will be looking at another problem I had to overcome with creating the SFG for LINQ to Umbraco, this time I'll look at how to do an installer while using wild-card version numbering.

I'm a big fan of wild-card versioning of assembliies, and if you're not familiar with what I'm taking about I'm referring to when you make the assembly version number end in a * within the AssemblyInfo.cs file, eg:

[assembly: AssemblyVersion("0.0.1.*")]

So what's the point of this? Well I find it useful when you're doing development and releases to know exactly where you're at. There's nothing worse than going to update an environment, but then you find out that the same version is already there. Was it because the developer hadn't incremented the version number, or did I miss the deployment?

By using wild-card versioning the numbers for the * are generated by the compiler on the fly. I'm not 100% sure how it can it is generated, I got a little bit of information from a developer on the VS core team stating:

When versioning as #.#.x.y x is generated as the number of days since some time in 2000 (which you can work out fairly easily) and y is the number of seconds since midnight on the date divided by 2.

Pretty sweet but it means that knowing the version number before compile time is next to impossible. This makes a real problem when doing the CLSID registry key which I talked about in Part 1 of this series.

So how do we get around this? Well the obvious way is to make a fixed version number, but as I stated I don't like doing that, particularly when I'm doing the development, I'm really wanting to know what version of the generator is running vs what version I last compiled.
Well, how do we get around it?

Introducing System.Configuration.Install.Installer (System.Configuration.Install)

We need to make a class which inherits from the Installer class. This will allow us to run custom .NET code during the installer which we can do what we want, like say, edit the registry.

There are two methods which should be overriden, Install and Uninstall. If we're modifying the registry we need to write our own custom code to undo those changes. No one likes it when software doesn't clean up after itself.

Because we're going to need to know the version of the assembly the best place to add this is within the same assembly as the SFG itself.

Registry editing 101

There's lots of good tutorials on editing the registry with .NET so I'll just cover the basics. First off you need to create the generator key within the CLSID key:

RegistryKey genKey = Registry.LocalMachine.CreateSubKey(@"Software\Microsoft\VisualStudio\9.0\CLSID\{52B316AA-1997-4c81-9969-95404C09EEB4}");

 Next we need to create the values for the registry key via genKey.SetValue(name, data). So it will look like this:

genKey.SetValue("Assembly", Assembly.GetExecutingAssembly().FullName);
genKey.SetValue("Class", "Umbraco.Linq.DTMetal.CodeBuilder.LINQtoUmbracoGenerator");
genKey.SetValue("InprocServer32", Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), @"system32\mscoree.dll"));
genKey.SetValue("ThreadingModel", "Both");
genKey.Close();

Since we need to get the full name of the assembly, including version number (which we don't know!) we can just use reflection against the current assembly. And also we don't have the Installer environment variables so we need to map the path ourselves. And once done close off the registry.

Wrapping It Up

To finish it up we need to add an attribute to our custom installer class:

[RunInstaller(true)]

And then edit the Custom Actions section of the Windows Installer project and specify that the output of the SFG assembly will be used in both the Install and Uninstall steps.

Conclusion

So this is how you go about doing a SFG with wild-card assembly versioning and setting the registry up correctly.


Published: 2017-10-23 09:53:42 +1100 +1100, Version: 4113ab4