Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Understanding NT


February 2001/Understanding NT


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 doesn’t 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.

I’m 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 I’d 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. It’s also extremely important to include REG_OPTION_VOLATILE in the dwOptions parameter. The trickiest thing about symbolic links is that you can’t easily tell the difference between the link and the target key after you create the link. (After all, that’s 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 I’ve 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, it’s a symbolic link that doesn’t 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.” Here’s 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. There’s 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 you’ve written Windows NT/2000 device drivers, you’ve 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”. Don’t 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 it’s 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. It’s 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 you’ve 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 I’ve 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). I’ve now lost the handle to the actual symbolic link key, so I can no longer change what key it’s 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].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.