I love the way WiX gives you control over a Windows Installer project, and that it integrates with a variety of building styles (at work, I use it in conjunction with Cygwin make and Perl), but sometimes, sometimes, the documentation leaves a bit to be desired. Most of the time, I'm interested in element syntax and semantics, so I can search for WiX foo element, but it's harder to search for the finer details, like the various forms of property reference syntax beyond simple constructs like [INSTALLDIR].
In a recent effort, I was trying to construct a registry entry inside an merge module (MSM) — in this case, so that a Visual Studio .NET Add Reference dialog would recognize an assembly. The way this works is that you construct a registry key under Software\Microsoft\.NETFramework\AssemblyFolders (under the appropriate root, like HKEY_CURRENT_USER) whose default key value is a string with the path to a directory that should be scanned for assemblies.
Now, I suppose you could use [TARGETDIR] and then duplicate the directory part of the path that contains your assemblies, but [TARGETDIR] inside merge modules is a tempermental beast that oftens ends up being set to the eminently useless value of C:\. So it's better to tie the directory path to something that is more under your control, like an actual file or component that the MSM is delivering. Ideally, you should be able to change the location of the directory, and the registry element won't have to change. And that registry XML and the component XML probably will be close together, so it should be easier for future maintainers to see what's going on.
I knew about the [#file] syntax for getting the effective installed path of the file, but in this case I needed a directory path, not a file path. So I Googled and Googled and finally found this tantalizing discussion, and I was almost there. The problem was: where could I find the authoritative description of what It is better to use [$component]
actually referred to? It turns out that trying to search for a literal [$ in Google or Bing brings up a lot of junk. I also tried search for bracket and dollar hoping that some piece of documentation would spell out the punctuation. No such luck (although, hey, now I've done it!).
Now, I think part of the reason for the state of WiX documentation, such as it is, has to do with the fact that's largely a civilized but largely translucent front end to the MSI runtime, which is pretty well documented in MSDN and various SDK help files. Still, developers working in WiX aren't really interested in a lot of MSI detail, except when they surface in WiX directly. So, eventually, I found this documentation on how MSI resolves property names, keys, and other strings. While I don't expect the WiX documentation to clone or rewrite this kind of documentation, and we all know that links can change (especially, ugh, on the MSDN site), the usability of WiX depends a lot on how developers can figure out how to get the MSI machinery to work for them. In particular, this level of detail is needed to make clear that, for example, in [$componentid], the string really is naming a component with its ID, not a file.
And of course, showing a useful fragment says a lot, too, so I humbly submit this:
<Component Id="ACME_DotNET_Client_AssemblyFolder" Guid='F78BCC5-41AD-4026-AEDB-060F27783697'>
<RegistryKey Root="HKLM"
Key="Software\Microsoft\.NETFramework\AssemblyFolders\ACME_DotNET"
Action="createAndRemoveOnUninstall" >
<RegistryValue Type="string" Value="[$Client_Files]"/> <!-- Directory reference -->
</RegistryKey>
</Component>
<Directory Id='BinDirectory' Name='bin'>
<Component Id='Client_Files' Guid='936AA0E-7D75-461E-8532-D0DF7829E2F9'>
<File Id='acmeclient.dll' Name='acmeclient.dll' Source="$(sys.SOURCEFILEDIR)client\Win32\VC8\Release\acmeclient.dll" KeyPath='yes' />
</Component>
<Component Id='Extendo_Files' Guid='43FA5CF4-5A4D-4988-918D-34D8AA228ECC'>
<File Id='acmeextendo.dll' Name='acmeextendo.dll' Source="$(sys.SOURCEFILEDIR)extendo\Win32\VC8\Release\acmeextendo.dll" KeyPath='yes' />
</Component>
</Directory>
These elements would typically be nested under a Directory element. Notice how we only refer to one of the components, Client_Files, that owns an assembly file in the directory. And, of course, that the registry value is [$Client_File], and not, say [$acmeclient.dll] or maybe even [#BinDirectory].
Hope this helps (and is findable by other souls in need).
No comments:
Post a Comment