Last month, I described how the Windows NT/2000 registry is organized in terms of hive files and predefined root keys. Another interesting feature of the Windows NT/2000 registry is support for symbolic links. Symbolic links are not supported on Windows 9x, and they might as well not be supported on Windows NT/2000 as far as the average developer is concerned, since Microsoft doesnt completely document how to use them. Ironically, because symbolic links are semi-documented, some developers assume they are available for their own use and waste lots of development time trying to make them work.
Im not sure why Microsoft chose to partially document registry symbolic links. Why tease us by mentioning KEY_CREATE_LINK and REG_LINK in the registry documentation without actually giving us enough information to use them? In all fairness, symbolic links can be a little dangerous. In preparing the sample code for this article, I accidentally created a circular symbolic link that allowed me to hang my machine, just by starting either regedit.exe or regedt32.exe. Still, symbolic links are a powerful feature, and Id prefer that developers be given the choice whether to use them (responsibly, of course).
Registry Symbolic Links
A registry symbolic link is just a special registry key that is linked to another registry key. Any time you access the symbolic link key, you are actually accessing the underlying key that the symbolic link key is pointing at (linked to). You can see several examples of symbolic links that the operating system uses, including some of the predefined registry keys. (HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet are examples of symbolic links used by the operating system.) The concept of symbolic links makes it convenient for one program (or one part of a program) to link an abstract registry key to a specific registry key based on some set of circumstances. Then, other parts of the application can access the abstract key, knowing it points to the right thing. Programmers take advantage of this feature all the time by saving settings under HKEY_CURRENT_USER and not worrying about who the current user.
To create a symbolic link, you need to create a registry key specifying KEY_CREATE_LINK in the samDesired parameter. Its also extremely important to include REG_OPTION_VOLATILE in the dwOptions parameter. The trickiest thing about symbolic links is that you cant easily tell the difference between the link and the target key after you create the link. (After all, thats kind of the definition of a symbolic link.) The other purpose of a symbolic link is to be able to programmatically change what the link points to, and it can be difficult to do this if your program goes away (more on this later). Creating the link as a volatile registry key lets you recreate the link on the next boot.
So far, everything Ive described is documented by Microsoft. If you create a key with the KEY_CREATE_LINK value, it will show up in regedt32.exe and regedit.exe as a grayed out unavailable key (see Figure 1). After all, its a symbolic link that doesnt point to anything yet. To link this key to another key, you might have guessed that it involves the REG_LINK registry data type. The MSDN (Microsfoft Developer Network) online documentation describes REG_LINK as: A Unicode symbolic link. Used internally; applications should not use this type. Heres the part that is not documented: you have to set a special value called SymbolicLinkValue of type REG_LINK in the symbolic link key. The data associated with this special value is the target registry key to link to. Theres one more catch: the target registry key needs to be in kernel-mode registry syntax, and it absolutely must be written as a Unicode string.
If youve written Windows NT/2000 device drivers, youve noticed that the base registry keys are referenced a little differently. Since drivers run in the LocalSystem context, they can only access a limited set of the registry (HKEY_LOCAL_MACHINE and HKEY_USERS). In kernel-mode, HKEY_LOCAL_MACHINE is referred to as \Registry\MACHINE and HKEY_USERS is referred to as \Registry\USER. So, to point my symbolic link key to HKEY_LOCAL_MACHINE\SOFTWARE\foo, I would use RegSetValueEx() to set a value named SymbolicLinkValue of type REG_LINK to the Unicode string \Registry\MACHINE\SOFTWARE\foo. Dont forget the extra set of backslashes needed when entering these strings in C or C++ constants.
Sample Code
The previous description seems easy enough, but its surprisingly easy to mess it up (another good reason for symbolic links to always be volatile registry keys). To demonstrate the process, I wrote the two simple routines in symlink.c (Listing 1). The prototypes for these routines are in symlink.h (Listing 2). CreateSymLinkKey() creates a volatile symbolic link key under the specified root key and subkey. I first create (or open if it already exists) the specified subkey and then create the symbolic link under that open key. Its important that only the last part of the key is created as volatile and with the KEY_CREATE_LINK attribute. CreateSymLinkKey() returns the registry handle of the newly created symbolic link key.
This registry handle is then passed to SetSymLink() to actually establish the symbolic link to the specified registry root key and subkey. As long as you have the original handle to the symbolic link key that was created in CreateSymLinkKey(), you can change the target of the symbolic link as often as you like by calling SetSymLink(). Therein lies the catch. Once youve lost that original registry key handle, you can no longer distinguish the symbolic link from the registry key it is linked to, and thus you can no longer change what key it links to.
To demonstrate using these routines, I wrote a simple Win32 application in main.c (Listing 3). This program has a very simple dialog-box user interface that is implemented in main.rc (Listing 4) and main.h (Listing 5). WinMain() first creates some dummy registry keys to test symbolic links with. Under HKEY_LOCAL_MACHINE\SOFTWARE, it creates a paulat key with three subkeys; A, B, and C. Under each of these subkeys, it creates two values with distinguishing data (the key A, will have a REG_SZ value of AAA and a DWORD value of 1, the key B will have a REG_SZ value of BBB and a DWORD value of 2, etc.). Then WinMain() creates a dialog box that is handled by MainDlgProc().
During WM_INITDIALOG processing, I call CreateSymLinkKey() to create a symbolic link key called Current under
HKEY_LOCAL_MACHINE \SOFTWARE \PaulaT
The most likely reason for this routine to fail is if Ive run the program before and closed it before running it again. In this case, the Current key will already be created and may or may not be a symbolic link to a target key. In either case, I no longer have the handle to the newly created symbolic link key, and thus I can no longer alter what the key is linked to. So, I gray out the buttons on the user interface and call Refresh() (more on both of these later).
The dialog box in Figure 2 has three buttons labeled Current -> A, Current -> B, and Current -> C. In response to any of these buttons being pressed, I call SetSymLink() to link the symbolic link key Current to the appropriate subkey (A, B, or C). Then, just to demonstrate that it works, I call Refresh(), which opens
HKEY_LOCAL_MACHINE \SOFTWARE \PaulaT \Current
and displays the contents of the Val1 and Val2 registry values in static fields on the dialog box. The data in the Val1 and Val2 keys will be dependent on which key Current is linked to (see Figure 3).
Conclusion
Just to reiterate, if I close symlink.exe and reopen it, my attempt to create the symbolic link key Current will fail with an error code of ERROR_ALREADY_EXISTS (183). Ive now lost the handle to the actual symbolic link key, so I can no longer change what key its linked to. I can still access the Current key, but I will be accessing the previously assigned key that Current is linked to. This is one of the things that makes registry symbolic links particularly useful for services and drivers and a bit less useful for applications. (Services and drivers tend to load early and stay running until the machine is rebooted.)
Also note that deleting a symbolic link registry key will delete the target registry key, which effectively deletes both keys. In the example above, deleting Current will also delete the key it is linked to (A, B, or C). If there are any other symbolic links to that key, they will be deleted, as well.
Symbolic links are a powerful and useful concept, but they can also be dangerous, so please use this information responsibly.
Paula Tomlinson has been developing Windows, Windows CE, and Windows NT based applications and device drivers for 13 years. In her spare time, Paula enjoys flying N422HJ, a 1951 Ryan Navion. The opinions expressed here are hers alone. Paula can be reached at [email protected].