When accessing the HKEY_CURRENT_USER or HKEY_CLASSES_ROOT registry hives from code, people usually are unaware that they are actually accessing a registry symbolic link. This is probably mostly due to the fact, that MS deliberately chose to under-document the techniques to create and use symbolic registry links. So it was not until Paula Tomlinson wrote two articles in the 2001 February and August Windows Developer Journal issues, that the great unwashed masses, including me, took notice of the possibility of the Windows NT registry symbolic links to be leveraged from their user mode code. At first, I considered registry symbolic links as a mere abstract concept, because I had no idea where to use registry symbolic links at all in my code. Well, until recently...
The company that I am currently working for, changed its name last year. For the sake of simplicity, let's assume that the company's old name was oldname and that its new name is now newname. Our product's registry configuration data is traditionally in a subkey under HKEY_LOCAL_MACHINE\Software\oldname, but now the suits in our company want it to be in the subkey HKEY_LOCAL_MACHINE\Software\newname. How do you do that if you want to keep older binaries running alongside with newer binaries and all of them have to share identical configuration data that might get changed by older binaries that expect their configuration data to be at HKEY_LOCAL_MACHINE\Software\oldname as well as by newer binaries that expect their configuration data at HKEY_LOCAL_MACHINE\Software\newname? Have a synchronization service running permanently?
Another problem that we are currently facing is related to the x64 versions of Windows XP and Windows 2003 Server. We will probably have to ship the next product suite as a mixture of native x86 binaries and native x64 binaries, with all of them having to access the same configuration data under HKEY_LOCAL_MACHINE\Software\newname. But here is the catch: x86 binaries on x64 systems, when accessing HKEY_LOCAL_MACHINE\SOFTWARE, actually access the redirected path to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node in the x64 registry. Now we would have to create two keys, one at HKEY_LOCAL_MACHINE\SOFTWARE\newname for the x64 binaries, and another key at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\newname for the old x86 binaries, and always keep them in sync dutifully.
Both these problems can efficiently be solved by using registry symbolic links. I have attached two samples (unzip with directory preservation) to this article to be used for that purpose. The first one, x64SoftwareKeyLink, is a command line app that only works on x64 editions of Windows and it expects a string as a command line parameter that should denote a key name under HKEY_LOCAL_MACHINE\SOFTWARE. It then creates a registry symbolic link from the x64 registry path under HKEY_LOCAL_MACHINE\SOFTWARE to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node. In the above mentioned case, when used like so:
it creates a key under HKEY_LOCAL_MACHINE\Software\newname as a registry symbolic link to the key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\newname. If you now create HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\newname from a native x64 binary or HKEY_LOCAL_MACHINE\SOFTWARE\newname from a native x86 binary, both will share their configuration data.
The other app that is enclosed in the Zip file attached to this article, is an ugly MFC dialog based app (see the screenshot above) that allows you to play around with registry symbolic links, both on x86 and x64 OS versions. It is best used in parallel with regedit, so you can immediately see what happens after pressing one of the buttons.
When playing around with this sample, you should proceed as follows:
- Fire up the sample named linkcreat.
- Fire up regedit and navigate to HKEY_LOCAL_MACHINE\SOFTWARE.
- Just as in the screenshot above, select HKEY_LOCAL_MACHINE in the combo box and type Software\a in the edit box labeled "Link Name" and Software\b in the edit box labeled "Real Key".
- Now press the button labeled "Create Link", switch over to your regedit instance, and refresh by hitting F5.
- You will notice that the new key HKEY_LOCAL_MACHINE\Software\a has been created, but you will get an error if you select this key with the mouse or keyboard. This is because this symbolic link does not yet point to any existing key.
- Now switch back to linkcreat and press the button labeled "Create Real Key". Notice that back in regedit, after refreshing, a new key at HKEY_LOCAL_MACHINE\Software\b has been created. If you select HKEY_LOCAL_MACHINE\Software\a, you will still get the error message box in regedit.
- Now switch back to linkcreat and press the button labeled "Link to Real Key". Now switch back to regedit and select HKEY_LOCAL_MACHINE\Software\a again. The error message won't appear again. Try to create subkeys and values under either HKEY_LOCAL_MACHINE\Software\a or HKEY_LOCAL_MACHINE\Software\b and notice how they will be reflected in the other key, respectively, after doing a refresh.
If you reboot the machine, the keys will still be there because the symbolic link has been created permanently. You could create symbolic links as volatile links also which I will discuss later in this article. Now if you have played around enough with it, you can press the button labeled "Delete Link" in linkcreat. This will delete HKEY_LOCAL_MACHINE\Software\a which is the key with the symbolic link. Notice that after doing this, in regedit, you will see that HKEY_LOCAL_MACHINE\Software\a is gone now and that HKEY_LOCAL_MACHINE\Software\b still exists. HKEY_LOCAL_MACHINE\Software\b has been created in a plain vanilla fashion by linkcreat using the
RegCreateKeyEx API. So you can simply delete HKEY_LOCAL_MACHINE\Software\b in regedit, or if you don't have any subkeys created under it, you can use the button labeled "Delete Real Key" in linkcreat.
Both samples can be compiled for native x86 and native x64 targets as ANSI and UNICODE variants. The project files for the samples are VC6 project files, but I am sure that they can be automatically converted to project files for later versions of Visual Studio. At least, it worked for me with the beta 2 of Visual Studio 2005. In order to build native x64 binaries successfully, you should first download and install the Windows 2003 Server SP1 Platform SDK. You should then start your development environment (msdev.exe or devenv.exe) with the /useenv command line parameter from one of the x64 build consoles of this Platform SDK. Make sure you don't have the x86 targets selected when building for x64 and vice versa, otherwise you will get gazillions of compiler and linker errors.
Using the code
The code that deals with registry symbolic links can be found in the files rgsymlnk.c and rgsymlnk.h. All function declarations that are relevant for registry symbolic links can be found in the header file rgsymlnk.h and exist as a Unicode version that ends with a "W", an ANSI version that ends with an "A" and a mapping via macros for portable code. It doesn't matter whether you define UNICODE or MBCS for a project of yours where you want to use these files, you will always get both the wide character variants of the functions, the ANSI variants and the mapping macros.
What is left open to be documented are the flags that you can pass to the functions:
CSL_VOLATILE_LINK: Use this flag for the
DWORD parameter of
CreateSymLinkKey to create a volatile link.
CSL_WOW64_64KEY: Use this flag for the
DWORD parameter of
CreateSymLinkKey in x86 binaries in order to create the registry symbolic link in the x64 registry hive without the otherwise automatic redirection enabled. When used for native x64 binaries, this flag will be ignored by virtue of the Win64 macro that you have to define for x64 builds if you use rgsymlnk.c and rgsymlnk.h.
SSL_IGNORE_WOW6432NODE_HANDLING: Use this flag for the
DWORD parameter of
SetSymLink in order to advise this function not to use the otherwise automatic redirection when translating internally from the registry path passed via the string parameter to the kernel mode registry syntax. Again, when used for native x64 binaries, this flag will be ignored by virtue of the Win64 macro that you have to define for x64 builds if you use rgsymlnk.c and rgsymlnk.h.
I think, a creative programmer who is proficient enough to use a debugger, will be able to figure out quite easily how the rest of the code actually works.
Important: When using these files in your own code and for native x64 binaries, you *have* to define the Win64 macro, otherwise you will get funny results.
Points of Interest
A lot of the code in rgsymlnk.c and rgsymlnk.h is very similar to the code you can find for the articles that Paula Tomlinson wrote for the Windows Developer Journal. Unfortunately, Paula's code for x86 doesn't work anymore for old x86 binaries when executing on x64 platforms, because back then it was not perceivable that Microsoft would do this Registry-Redirection-Thingamajic with the Wow6432Node subkeys for x86 binaries on x64 editions of Windows. However, what I particularly disliked in her code is her ignorance regarding const strings, so for my variant, I chose const strings as parameters. Her code also uses the portable string data types whereas I wanted to have both an ANSI and a UNICODE version of all functions for maximum flexibility in my projects. Another thing I changed is the
CreateSymLinkKey function, where her code always creates a volatile symbolic link. In my variant, creation of volatile symbolic links is done via an optional flag. Her variant of this function also expects the path to the symbolic link to be passed via two strings, one for a path that gets created as a non-volatile key, and the other as a subkey name for the volatile symbolic link under the first key. I see no real reason for making this differentiation, therefore my variant expects the complete path to the symbolic link to be passed.
A final warning
Using the code in this article, you can easily mess up your machine. So please use it responsibly. In no way can I be made responsible, accountable or liable for any damages and stupid things that you can do with this code. Debug it, try to understand it, get a copy of Paula's articles, and use your brain, when using my code.
- First version - 10/16/2005.
- Bug fix - 10/18/2005: Removed the unwanted dependency from bufferoverflowu.lib from newer Platform SDKs in the x86 builds of x64SoftwareKeyLink.dsp.
- Documentation fix - 10/18/2005: Replaced the term "link target" with "link name" and "source key" with "real key" to avoid unnecessary confusion.