A Little Background History
One of the pernicious problems of working in a separate physical location from the rest of my team is the necessity of using a VPN. The VPN itself is a Godsend in many ways, and makes the whole venture practical - but a VPN across the Atlantic is a far cry from a local gigabit LAN. This means that certain things which are fine to do on the LAN are not fine for me to do across the VPN.
For instance, it is standard procedure to take all SDKs and libraries and place them on a master file server, and then compile against them over the network. So, for example, the all-important foo.lib file in the FooSDK might be stored on \\Master\Foo\lib\foo.lib. This is, by convention, mapped to a drive letter (F: in our case) to produce F:\Foo\lib\foo.lib. The Visual Studio project is then pointed to this path, and each time someone builds the project, the latest version of the .lib is fetched across the network.
This works beautifully when you're 10 metres from the master server and linked by gigabit hardware - it's virtually indistinguishable from compiling against the same .lib on a local hard drive. However, when you factor in the overhead of the VPN, the network-to-internet bandwidth cap on the VPN, and the latency created by the not-so-short sprint across a major ocean, the same operation is not so pleasant to do on the VPN. More accurately, it's virtually impossible - transfer speeds are abysmal and compiles grind to a halt.
When your development habits rely on compiling and running test code as often as every 5 minutes (as mine do), it is imperative that compiles be snappy. This means that compiling across the VPN is a no-go.
The solution is pretty painless: those of us working across the VPN copy the SDK files to a local drive, and compile against that. Since the shared files change very rarely, and the whole team is generally notified whenever they do change, this doesn't create many problems.
However, it does create a problem for me. I have my hard drive partitioned into two segments, forming C: and D: drives. This leaves my DVD burner as E:, and my USB thumb-drive as F:. I've also had other drives attached in various configurations - the bottom line is that the F: letter is not available. This means I can't use F: for my shared SDK files.
Again, this isn't a huge challenge to solve - I just modify the VS project to point at my preferred path (D:\Programming\SDKs\Foo\lib\foo.lib) and off I go.
Unfortunately, there's one final speed bump: when I want to change the project in any way (new build settings, adding/removing files, rearranging things, etc.) I can't simply slap my changes into source control and be done with it. My local project has to retain different paths to each library file from the paths used in the master project. This means that any time anyone updates the project in source control, I have to merge the changes to my local copy by hand.
The obvious answer, of course, is to move the paths out of the project and add them as global settings in the Visual Studio options. However, this is impractical, because we need different paths for different build configurations, and various other subtle annoyances.
The bottom line is that I wanted to create my own path wildcards. For instance, $(FrameworkDir) in VS2005 points to the installed location of the .Net framework. I wanted to be able to set up general variables of the form $(Foo) - not just paths, but any string that I might want to use in the project configuration to do Magical Configuration Hackery.
It took some rooting around on the interblag, but I came across an interesting tidbit: you can indeed create $(Foo) variables via the Windows mechanism of environment variables.
My first approach was to use a batch file to launch Visual Studio, and set up the environment variables before spawning the DevEnv.EXE process. This worked, but it's a bit of an ugly solution - for example, it means I have to launch VS and then open a solution rather than double-clicking the solution in Explorer; otherwise the variables don't get set and the project won't build right. As it turns out, though, this works great for doing automated builds, so it's worth keeping in mind.
The final step is observing that VS addins have a rather perverse amount of power over the IDE itself. Specifically, an addin can create an environment variable - and, happily, they will be recognized correctly when used as part of project build settings.
All you have to do is create the variable and set it. The ideal place to do this is the OnConnection handler of the addin's Connect class, so that whenever the addin is loaded, the variable is configured. If the addin loads with the IDE, then your $(Foo) variable will appear to magically be part of the intrinsic variables provided by the IDE. However, you can set the variables at any time, and any subsequent compiles will use the variable correctly.
The magical incantation couldn't be simpler:
Our project can now refer to $(FooSDKPath)\foo.lib. Each developer configures the correct location of $(FooSDKPath) for his local box; for most of them, this is the normal network master server (which, incidentally, is the default value I coded in, since defaults are vitally important). Now, all of us enjoy builds which Just Work(TM), and, as a bonus, those of us working via the VPN can now auto-merge our project changes into source control without having to manually work around our local path settings.
Beyond the Hack
This is of course just one possible way to exploit the ability. I'll leave it to your imagination what can be done once you can put arbitrary variables into your build settings and then configure them on the fly. I personally attached a little UI to the VS addin to aid in configuration; in theory this could trivially be extended to a general-purpose addin that lets you set any variables you want. (In fact, I believe there's already such a project floating around the net someplace, although its quality may be questionable.)
Frankly, at the moment I'm a little too sleep-deprived to really have any good ideas how this could be used. If someone comes up with some, let me know, and I'll reward you with a cookie after I get some rest.
So... go forth, and hack merrily.