1) It isn't on most of the Smithsonian maps, making the task of finding it somewhat irritating.
2) It charges $18 at the door.
I don't mind 1 that much, but 2 was really obnoxious.
Building the SlimDX Installer
Developing the SlimDX installer turned out to be a massive headache. I believe there is good installer creation technology out there; however, it would appear that I do not actually have access to it. When it comes to the world of install technology on Windows, there are basically two groups:
- Installers that create Microsoft Installer (MSI) files. This includes the Setup Project in Visual Studio, and stuff created by InstallShield, Wise, WiX, and so on.
- Installers that do their own thing. In this group are NullSoft, InnoSetup, and some others.
The SlimDX installation had three basic requirements. First, it had to install the basic native prerequisites that SlimDX apps always require. For the June release, that meant the Visual C++ 2008 (version 9) runtime, and the DirectX redistribable files for June 2008. Second, it had to register SlimDX in the Global Assembly Cache (GAC). Lastly, it had to do an installation to a normal Program Files directory, which is necessary for VS to find the XML and PDB files, and for people to distribute SlimDX as a private assembly.
The first sticking point came when I was looking into registering SlimDX in the GAC. One would expect that this is fairly simple. Not so much. See, the usual method developers are shown for registering their stuff in the GAC is to use the gacutil.exe utility to do it. It turns out that this is only for developers. Normal users don't have gacutil, and you aren't allowed to redistribute it as part of the installer. So how do you register in the GAC? MSI can do it; if you're not MSI, you can go to hell. (There's a class in the .NET Framework that can do it, so if your installer can handle plugins written in .NET, then you can pull it off.) At this point, NSIS and InnoSetup dropped out of the running. No GAC registration was a non starter, and I didn't want to use a hack for something so simple and fundamental.
Okay, so now I was down to VS, which I didn't think was a bad thing. It generated these hideous, amateurish looking installers, but I found out that if you know where to look, you can reconfigure that stuff so that it actually looks like a decent bit of software. I mean it's VS, right? Stuff might be a little weird, but it's basically good at what it does? Not exactly. Visual Studio is a terrible installer authoring system. There doesn't seem to be any specific reason for it, either. It's just all around shoddy, and omits stupid things that should be simple. For example, there is an interface for working with special folders like the Windows directory without having to give them explicit paths. That's great...except there's no support for getting the temporary directory. There's no reason not to, because the MSI format supports it, and if you know the property name, you can write it explicitly in VS. You just can't get it automatically, so you have to check the documentation for what the properties are.
After tweaking the project for a while, I got back around to GAC registration. It turns out that Visual Studio doesn't look at the GAC when adding references. It actually reads a set of registry keys (HKLM or HKCU, SOFTWARE\Microsoft\.NETFramework\AssemblyFolders) and uses their default values to get a list of search directories, and then it loads assemblies that it finds out of those directories. So to install a managed assembly, you put it somewhere on the file system apart, then register it with the GAC and also add the assembly folders entry. VS even has a Registry view that allows you to do this sort of thing...except it doesn't let you edit the default value of a key. Again, this is something that is trivially supported by MSI, VS just doesn't do it. Unfortunately, there's no hack-around in VS itself. You have to install a tool called Orca to modify the MSI after VS finishes building it, and write in the registry value yourself. Orca does support automation, but I have yet to figure out exactly how.
Oh, and on Windows XP 64 or Vista 64, VS reads from HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432node\Microsoft\.NETFramework\AssemblyFolders instead, because it's a 32 bit app and it gets redirected. That took a little figuring out, because the installer runs as 64 bit and doesn't write under WOW6432node. What I haven't figured out, however, is why Windows/msiexec completely ignored me when I tried to write the key under WOW6432node. That's why 64 bit users need to browse to the SlimDX directory manually.
Installing the VC9 redist turns out to be rather easy, but the results are clunky. VS allows you to ask it to create a bootstrap EXE that installs requirements like the CRT and .NET -- but not DX for some reason -- automatically as necessary before launching your installer. All you have to do is check the boxes. Problem is, it doesn't package the MSI or the CRT redist into the EXE, like you'd want. It just leaves them hanging there, loose. I couldn't find any useful information on changing this behavior, or really doing much of anything about it. I ended up writing a simple EXE file that embeds the EXE, the MSI, and the VC9 redist folder inside itself. That's the published SlimDX installer; when you run it, it will stage those files to the temporary folder (typically Documents And Settings\USER\Local Settings\Temp), and invoke setup.exe there. The sad part is, despite being a total hack, this is probably far easier than more maintainable than any other way out there for packing things together, self extracting ZIPs included. (Although for this June release, the DX team finally got around to making their installer not a POS zip-inside-a-self-extracting-zip.)
There was also the question of installing the DirectX redistributable. There's a web installer...but that's not redistributable and so it's worthless to us. The normal redistributable package is about 70 MB, and includes every redist package since the D3DX library was made dynamic. That was in 2005. Somehow, I didn't really feel that SlimDX users needed DirectX from October 2005. It's just a waste of space and bandwidth. Luckily, the DX setup program is flexible, and allows you to reconfigure it and simply delete old components. I cut it down to a minimal set that doesn't include DX 9.0c core install files (which are huge), and that subset was fairly compact -- about 8 MB. Not bad. Now I just had to actually run that minima installation as part of the SlimDX installer, and everything would be good. It shouldn't be a surprise that there was precisely zero built in support for doing this.
After some research, it was clear that the only way to really do this was to write a "custom action" for the install. That doesn't sound so bad...except custom actions are either JScript/VBScript (highly unrecommended), or DLLs. (Managed DLLs can be used, and are handled via a native proxy DLL. Blech.) I decided to just follow this guide (which is poorly written, frankly) and build a C++ DLL called DXSetupAction to handle this for me. That way I'd even get to use the MS DirectSetup API, which can be used to easily and transparently install the DX redist. (Although the 1.5 MB dxsetup.exe file is required to be redistributed even if you do use DirectSetup. What the hell.) It was here that I realized that there was no clear way to access any of the DX redist files if they were embedded in the MSI. It sounded possible, but I couldn't really see how. (Later, I realized that the custom actions only run AFTER your application installation, so I could have simply installed the files as part of normal installation, even if that is rather contorted.) I decided to simply embed all of the redist files inside my DLL, just like I did with the main EXE, stage them to the temporary directory, and call DirectSetup from there.
I would love to say that worked, but it didn't. When testing on my machine, everything seemed fine. It was only when I moved to clean VM tests that I noticed that DirectSetup wasn't doing a goddamn thing. It would load out of the DLL. It would find the function. It would run the function, and it'd get a success code back. But it didn't actually accomplish anything. I decided to simply CreateProcess on dxsetup.exe with the /silent flag instead, which did work as expected. Maybe that's why you're required to redistribute the executable -- it saves you time once you notice their API is broken. On the bright side, I now have a single DLL which you can easily add to anything that can load it, MSI or otherwise, and it will quietly and neatly install DirectX for you. (The version's pretty easily configured, and it can do either x86 or x64.)
In any case, I finally had it working. Let's look at the layout: all of the DX files are embedded in DXSetupAction.dll. DXSetupAction.dll, and SlimDX.dll/.pdb/.xml are all embeddded in SlimDXSetup.msi. SlimDXRedist32.msi, setup.exe, and a vcredist_x86 folder are all embedded in SlimDXSetup.exe. I personally find this whole thing to be fairly ridiculous...but it works. This was a fairly simple install, too. I can't imagine what kind of horrors I'd have to endure if I was doing something more complex, like Visual Studio or Office. As I said before with the docs, I can't help but think that they must have something better than what the non-paying public has been given access to.
I thought you didn't want to put SlimDX in the GAC? Or at least I thought I saw you mention that at some point?