This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.

MSDN Magazine

Windows 2000 Registry: Latest Features and APIs Provide the Power to Customize and Extend Your Apps

Dino Esposito
This article assumes you�re familiar with Win32 and the Windows registry
Level of Difficulty     1   2   3 
Download the code for this article: Esposito1100.exe (37KB)
Browse the code for this article at Code Center: HTML Generator
SUMMARYThe Windows registry as it is recognized today first appeared in Windows 95. Its introduction simplified the storage of initialization information and made that data more secure. This article covers the history of the registry, the form it took in the early days, and its current incarnation in Windows 2000. Practical tips for managing data in the registry are outlined, along with descriptions of special keys, functions, and file types. Manipulation of the registry to customize both application behavior and certain features in Windows is discussed. Also covered are future directions of the registry, including the use of XML to store registry information in a hierarchical fashion.
T he registry contains a wealth of information for programmers and power users. An understanding of the registry can help developers better integrate their applications with the system software. By editing the registry, power users can customize the behavior of applications in ways that are not possible with preference dialogs and snap-ins alone. In this article I'll discuss the keys and registry features found in Windows® 2000, along with some new powerful API functions for accessing registry data.

Background

      The original goal of the registryâ€"the systemwide data repositoryâ€"was to replace INI files that were used in the early days of Windows to store user and application configuration data.
      There were several good reasons to replace INI files. First of all, they are text-based and easily edited in a text editor. As such, they are subject to unauthorized access and easy tampering. Additionally, information that needed to be stored in a structured, hierarchical way was saved as flat text in an INI file. XML would have been a good way to combine the usability of INI files with a rather complex data description, but XML had not been developed five years ago. Third, INI files force a decentralization of information. Without clear and fixed rules for organizing documents and folders, there is a risk that valuable information will get lost, duplicated, corrupted, or simply become more difficult to retrieve.
      Furthermore, INI files impose size restrictions; you cannot store more than 64KB of data in a single entry. This limitation is not due to the INI file itself, but to the API functions that read and return the values from the file. Unless you want to write your own version of functions like GetPrivateProfileString, bear in mind that these functions can't address buffers larger than 64KB.
      In contrast to all this, the registry is subject to security policies and can be manipulated only through special tools (like the Registry Editor) and API functions. Such a programming interface shields developers from having to change their code should Microsoft modify the internal registry structure.

Figure 1 Registry Size Information
Figure 1Registry Size Information

      Size restrictions are not a problem in the Windows registry, even though its size isn't unlimited. Figure 1 shows the system dialog that allows you to see the current size of the registry and change the maximum amount of space it can use. This dialog box appears when you right-click on My Computer, select Properties, select the Advanced Tab, open the Performance Options dialog, and then click the Change button to change the current settings. This option is only available in Windows NT® and Windows 2000, and only if you log in with administrator privileges. I'll say more about registry size later in this article.

Structure

      The Windows 9x registry is completely different from the Windows 2000 version, but the Windows 2000 registry underwent only minor changes from Windows NT 4.0. In Windows 9x, the registry consists of two files, system.dat and user.dat, in the Windows folder. System.dat contains information about the local machine and the software installed there; user.dat contains user-specific information for both applications and the machine.

      Upon installation, the operating system also creates a system.1st file in the root directory of the C drive. This file is a snapshot of the registry taken at the moment that Windows is correctly installed, but before you start using the system. You can rely on that file to be an early backup copy of the registry. In case of serious registry damage, the existing system.dat file can be replaced with system.1st, and all applications can be reinstalled. The Knowledge Base article Q131431 describes troubleshooting the registry in more detail. Actually, system.1st is not necessary for the proper operation of Windows, so you could delete it. However, this file should be saved as a backup of the registry. In Windows 2000, all these files disappeared, but the programming interface for the registry is still the same.

Backup and Restore

      Windows 98 automatically backs up the registry during startup. A utility called scanregw.exe checks the registry status, and if all is working properly, performs a backup. However, you can run the utility at any time in order to make your own backup.
      The windows\sysbckup folder contains up to five RBxxx.cab files; these are the five most recent backups. xxx represents the ordinal number of the backup. The cabinet file contains four files: system.dat, user.dat, win.ini, and system.ini.
      While the CAB format can save disk space, it is not a file format you can use to restore the registry directly. In fact, to replace the registry files you need to start Windows in safe command prompt only mode (essentially, MS-DOS® mode). When you start Windows in safe command prompt mode, the registry files aren't in use, so you can replace the registry with the contents of these CAB files. However, you might not be able to extract the contents of a CAB file because you need a special tool to process CAB files in MS-DOS mode. So, before you attempt to restore a backup copy, make sure you extract the files from the CAB file while Windows is running and put them into a different folder. Then reenter safe command prompt only mode and replace the registry files with MS-DOS commands.
      In Windows 2000 there is no automatic backup feature. However, you can implement backups in another way. The registry backup is built into the Windows 2000 Backup utility, which you can find in Programs | Accessories | System Tools. From the main page of the Backup utility, click on the Emergency Repair Disk (ERD) button and make sure to check the proper option for backing up registry files, as shown in Figure 2.

Figure 2 Registry Backup in Windows 2000
Figure 2Registry Backup in Windows 2000

      The procedure doesn't even attempt to copy the current registry to a floppyâ€"an impossible operation since the average size of the registry on many machines is close to 20MB. Instead, the backup procedure makes a copy of the registry files in the system repair folder: c:\winnt\repair. All the information stored in this folder is necessary to repair a damaged Windows 2000 installation and shouldn't be deleted or modified. In particular, the latest registry backup is saved in the RegBack subfolder.
      To restore correct registry information, you should run the Restore Wizard from the Backup utility and follow its instructions. Use the previously created ERD if you cannot start and log on to Windows. Through the Backup utility, you can also schedule the registry backup at predetermined intervals.
      For the Windows 2000 Backup tool, the system state includes at least the registry, the COM+ Class Registration database, and the system boot files. It also includes the Certificate Services database if the server is operating as a certificate server. If it is acting as a domain controller, then the directory services database is automatically part of the backup. For more information about the system state backup and restore under Windows NT 4.0 and earlier, refer to the Knowledge Base articles Q129037 and Q126464.
      The standard backup procedures copy all the registry files. To back up small portions of the registry, such as a node or a subtree, you can use the Export Registry File menu command of the Registry Editor (regedit). It allows you to select the branch to save and creates a text file with a REG extension. A REG file can also be used to enter registry settings later. The Import/Export Registry Editor feature is another option for backing up small branches of the registry before you test potentially harmful code.

Figure 3 Regedit
Figure 3Regedit


Viewing Registry Data

      The programmer's window into the system registry, the Registry Editor, is shown in Figure 3. It is a collection of root nodes containing different types of information. Each node expands into a number of subnodes or keys. All nodes can have any number of named entries and exactly one unnamed entryâ€"often referred to as the default entry. An entry is a name-value pair. Each entry can have a type chosen from a collection of possible types.
      The most important types are those listed in Figure 4. Notice that a REG_MULTI_SZ entry can be created only through the API functions, while a REG_EXPAND_SZ entry can also be created through the Windows Script Host object model. Only binary, text, and numeric entries can be created through visual tools such as the Registry Editor. You access a specific key or entry through a path name that identifies a logical path from one root node to the actual leaf.
      Both the Registry Editor and the Win32® Registry API provide a sort of virtualization of the registry content. The root nodes, keys, and entries you see represented don't correspond exactly to the actual files that make up the Windows 2000 registry. The structure of these component files is significantly different from the tree you usually see in visual editors and API functions. For example, neither the HKEY_CLASSES_ROOT (HKCR) nor the HKEY_CURRENT_USER (HKCU) nodes have a physical counterpart in any of the registry files. The information they show through the API virtualization is mirrored from a subtree of the HKEY_LOCAL_MACHINE (HKLM) and the HKEY_USERS (HKU) node respectively. In other words, HKCR and HKCU are aliases for HKEY_LOCAL_MACHINE\SOFTWARE\Classes and HKEY_USERS\.default.
      This also explains why in Windows 9x there are only two files: system.dat and user.dat. Their content corresponds to HKLM and HKU, which covers all the information accessible by the API and the Registry Editor.
      The virtual view provided by the Win32 API makes it possible for developers to work with different registries using the same tools even though the Windows 9x and Windows 2000 registries are structurally different.

Figure 5 File-type Variety
Figure 5File-type Variety

      All the files that form the Windows 2000 registry are stored in the \system32\config directory. If you look at the actual contents of the folder (see Figure 5), you can see several files with different extensions. Files without extensions contain the actual data for a root node. The content of the various registry root nodes are also known as hives (see Figure 6).
      Files with a .sav extension contain a copy of the specific registry node data that exists at the end of the text-mode setup stage. During the Windows 2000 startup you can distinguish two distinct stages: the text-mode stage and the graphics stage. When the system is about to leave the text-mode procedure, it saves the hives to the respective .sav files. If problems occur during the next graphic-mode step, the system restarts, but it doesn't repeat the whole setup procedure. It skips the text-mode step and reads the content of the registry hives from the respective .sav files.
      Files with the .log extension contain a transaction log of all the changes to the keys and value entries in the hive. Despite the extension that might make you think this is a text file, the content of the .log files is binary.
      The registry folder also contains one file with an extension of .alt. This .alt file is a backup copy of the most critical data in the HKLM hive. Windows 2000 utilizes only one ALT file, system.alt, which is a safety backup copy of the HKLM\System node.
      Figure 7 shows how the hives that are visible from the Registry Editor map to physical files.

      In the registry folder (\system32\config) you won't find a file that appears to contain user information. The content of HKCU and the content of the hives for other users are stored in different folders. In particular, you'll find files called ntuser.dat and ntuser.log.dat in user-specific folders under C:\Documents and Settings. For example, the HKCU settings for the Administrator can be found under C:\Documents and Settings\Administrator.

Size Limitations

      As mentioned earlier, there's an upper limit for the registry size because Windows NT and Windows 2000 stores the registry data in the paged poolâ€"a memory area available to all system components. Given this, greedy or buggy applications can fill up the registry and significantly reduce the amount of memory available to all processes. The paged pool memory has a predefined maximum size that can be manually read from and written to the PagedPoolSize entry under:
HKLM
  \System
    \CurrentControlSet
      \Control
         \Session Manager
            \Memory Management
By default the value is set to 0; the system dynamically calculates and sets the optimal value based on the total amount of physical memory. In this case the registry size is set to one-third of the paged pool size.
      The registry size limit, if not automatically determined by the operating system, is read from the RegistrySizeLimit entry under:
HKLM
  \System
    \CurrentControlSet
      \Control
This entry is not defined by default.
      In no case can the registry size limit be less than 4MB or greater than 80 percent of the paged pool size. It's worth noting that when the paged pool size changes, however, the registry size limit is not automatically updated. Furthermore, the maximum amount of registry space is only an upper limit; it does not cause space allocation, nor does it ensure that the space will be made available on demand.

      The Knowledge Base articles Q94993 and Q124594 describe in detail how to get and set the registry size limit programmatically. Don't forget, however, that you need to restart the machine for the changes to take effect.

Windows 2000 Registry Data

      The Windows 2000 Application Specification document (https://msdn.microsoft.com/library/specs/w2kserve.htm) states that the use of the registry must be limited to storing configuration and initialization data. In addition, all the information for the registry should be divided into computer-specific and user-specific data. This distinction allows applications to easily support multiple users and promotes location-independence for user profile data. In other words, once you've separated user-specific information from the rest of the application's data, and once you've made such information available over a network, you've provided full support for roaming usersâ€"users who connect to a distributed application from different locations and machines across the same organization.
      The registry has not always been the perfect repository for all application data as depicted in the Windows 95 Logo Program. For example, unless you take specific measures, it's difficult to move or access user configuration data from different machines, and it's potentially harmful to save or restore particular program settings. In the old days, if your users had problems with some program settings, you could suggest that they locate and delete a certain INI file. Usually the result would be the restoration of the standard settings. Deleting the wrong file was rather unlikely. But you can't suggest deleting a registry subtree, unless you're advising a power user. Even for experts, deleting a registry subtree is potentially dangerous because there's no undelete feature for the registry.
      For all these reasons, and to improve the overall efficiency, the Windows 2000 Application Specification reduces the circumstances in which you need to use the registry. The specification suggests that you use files instead of entries when the amount of data is larger than 2KB. To allow user roaming, you should create these files under a hierarchy of folders like this:
C:\Documents and Settings
  \User Name
    \Application Data
      \Company Name
        \Product Name
      You should use those filesâ€"whether they are INI, XML, or binariesâ€"as appendices of the registry and insert an entry that points to them.
      The registry can take up a large amount of space, and a very large registry can slow the overall system performance. So to save space, you should minimize the number of keys because a key consumes more space than a simpler entry. If you need to store a logically related group of data, you should figure out a way to describe them in as flat a structure as possible and use as many entries as possible. Once again, XML is the perfect tool to describe your data in a way that is both flat and structured. XML data is flat because it remains simple text, but it's structured because you can parse it into a powerful object model.

Special Keys and Entries

      Registry data is grouped into root nodes roughly following the schema depicted in Figure 8. In most cases, the same information can be set and read through API functions without directly accessing the registry. However, this is not necessarily true of all the information you might want to access. Knowing where to search for useful information can save you time and allow you to better integrate with the rest of the system.
      All the available information about registered file types and system objects is stored in the HKCR hive. This is also the hive to explore if you need to verify whether a certain COM object exists and is correctly installed. HKCR contains a node with all CLSIDs and ProgIDs. In the remainder of the article, I'll examine a few stumbling blocks and provide tips to accomplish tasks that would be impossible without modifying the registry. In doing so, I'll discuss little-known keys and entries. I'll talk about access to file classes, current settings for system objects, infotips, and regedit's lastkey behavior. Let's start with the * key.
      As I just mentioned, HKCR contains information about file types. You can refer to the article "Fusing Your App to the System Through the Windows 95 Shell" by Jeffrey Richter in the April 1996 issue of MSJ for basic information on file types and their registration. This has not changed since Windows 95.
      Due to limitations inherent in the file system architecture, the only way to group files into classes is by the file extension. All the files with a given extension belong to a certain class, regardless of their actual content. A Windows file type is identified by a HKCR node whose name matches the file's extension. For example, HKCR\.bmp identifies the node for bitmap files.
      Not all the class information for bitmaps is stored under the .bmp node, however. For a more flexible programming interface, an extension node points to another node that gathers all the information about the file class. The name of the file class for a certain file extension is stored in the unnamed default entry for the file type. For example, the file class for bitmap files is usually Paint.Picture. This is where you should search for information about bitmap images such as the icon, description, context menu, and shell extensions. The decoupling of extension and class allows different programs to register as the default handler for those files by changing a single entry and without overriding other programs' settings.
      Along with file classes and COM objects, the HKCR hive also contains the current settings for a number of system objects such as folders, directories, drives, and printers. You can update the standard configuration of any of these objects individually, but you can also apply the same changes to groups of objects. The * key is a pseudo system object that groups together all files of all possible classes. The Folder key includes both folders and file system directories. The Directory key refers only to file system directories. Windows 2000 introduces a new system object called AllFileSystemObjects, under which you can enter configuration information for both files and directories.
      You've probably noticed that infotips abound in the Windows 2000 Explorer, and not only for those file classes for which an infotip shell extension has been registered. Explorer, in fact, provides standard infotips for any file that appears in the shell view. The text displayed doesn't come from a systemwide infotip extension; it's read from various locations within the registry. Figure 9 shows the standard infotip for a VBScript file (.vbs). For more details and source code about infotip shell extensions, please refer to my article "Enhance Your User's Experience with New Infotip and Icon Overlay Shell Extensions" in the March 2000 issue.

Figure 9 Standard Infotip for VBScript Files
Figure 9Standard Infotip for VBScript Files

      Once the Windows 2000 shell detects the file type, it attempts to locate and load an infotip shell extension for that class. If it fails, it then searches for an Infotip entry under the file class node. For example, the default file class for ASP files is aspfile. An Infotip entry under HKCR\aspfile (see Figure 10) results in the behavior shown in Figure 11. If it fails again, the standard infotip is used.

Figure 10 ASP Infotip Settings
Figure 10ASP Infotip Settings


Figure 11 Simple Infotip
Figure 11Simple Infotip

      Interestingly, the standard infotip is customizable. It is defined by the Infotip entry of the HKCR\* node. Its text looks like this:

prop:Type;Author;Title;Subject;Comment;Size
      The prop: prefix tells Explorer that the following text must be interpreted. The final infotip is up to six lines long and shows the type of the document, the author, the title, and so forth. If any of this information is not available for the file, it is simply omitted. For most files, in fact, only type and size are known, as you saw in Figure 9. Author, title, and subject are usually available for Office documents and for all compound files that expose a SummaryInformation block. With Windows 2000, if you have an NTFS partition, you can associate author, title, subject, and comment information with any file type, including text files. In that case infotips change accordingly (see Figure 12).

Figure 12 Extended Infotip
Figure 12Extended Infotip

      On an NTFS volume, extra fields such as Author and Subject are stored through multiple data streams for any type of file that doesn't contain a SummaryInformation block in its own body. More information on this can be found in my article, "A Programmer's Perspective of NTFS 2000: Streams and Hard Links" in the March/April 2000 issue of MSDN® News.
      The structure of the HKCR\* Infotip entry is customizable and can be adapted to your own needs. In particular, you can alter the order in which the information is rendered and you can add new fields as well. For example,

prop:Size;Type;Modified;Author;Attributes
creates a tooltip like the one shown in Figure 13. The fields you can display within an infotip are those listed in the View | Choose Columns dialog box in Windows Explorer. Notice that the dialog may also include custom columns created through a column handler shell extension. Custom columns aren't supported in infotips, presumably because it would be rather complex for the shell to associate the column name with a CLSID.

Figure 13 New Custom Infotip
Figure 13New Custom Infotip

      If you use the Registry Editor on a daily basis there's another feature that you might find annoying over time: the automatic selection of the last accessed key. The name of the last key is stored in the LastKey entry under the Regedit node. Deleting this key is of no help since the key is overwritten or created upon exit. A partial solution is using regedt32.exe to change the permissions on the Regedit key. In particular, you can deny write access to the key to any users or groups you want, as shown in Figure 14. Make sure you apply the restriction to the Regedit key only, not to all of its subkeys. If you restrict the subkeys, you'll be unable to add and delete items to and from the favorites list.

Figure 14 Regedit Permissions
Figure 14Regedit Permissions

      At this point, you've successfully stopped the Registry Editor from selecting the last accessed key, but you also introduced a couple of predictable side effects. Since write permissions to the registry can be granted or denied only at the key level, there's no way to lock individual registry entries. Blocking the Regedit node also prevents the application from using the other two entries defined at the same level of LastKey: FindFlags and, more importantly, View. FindFlags maintains the state of the Find dialog, whereas View remembers the size and position of the program's window. This information will become unavailable once you deny writing permissions to the Regedit node. Henceforth, the program can't reopen where you closed it, nor can it remember the last find settings. You'll have to decide if these settings are important for you to maintain.

Working with File Types

      In this section I'll explain how to selectively set the visibility of file extensions (show or hide), set default behavior for double-clicking, control the Open With menu behavior, and manage connected HTML files, which I'll define later.
      As you know, there are folder properties to hide or show the extension for known file types. There might be circumstances, however, in which you don't want the same setting to apply to all file classes. For example, suppose you want to hide the extension for the majority of files, but not for a couple of classes, say, .xyz and .abc. By defining an AlwaysShowExt entry in the class node, you force the shell to override the current setting and always show the extension for those files. There's no need to assign a value to the entry, but you must create it as type REG_SZ. Conversely, if you always want to show the file extension except in a few instances, create a NeverShowExt entry in the appropriate class node.
      For a practical demonstration of this feature, consider shortcut files. By design, Explorer never shows the .lnk extension regardless of the shell-wide setting for known (registered) file types. If you look in the registry under HKCR\lnkfile, you'll find a NeverShowExt REG_SZ entry. In Figure 15 you can see that if you remove the entry, the .lnk extension is displayed on the Start menu. Note that for NeverShowExt/AlwaysShowExt changes to take effect, you need to reboot or at least log off.

Figure 15 Start Menu
Figure 15Start Menu

      Another way to use registry entries to set behavior is to define the action of a double mouse click. The Windows 2000 Application Specification documentation recommends that you always associate an action for double clicking on a file. This usually means defining an Open command for the file. If you don't want users to open files of a given type, you should designate those files as NoOpen. When someone attempts to open a NoOpen file, a message box like Figure 16 will appear.

Figure 16 NoOpen Message
Figure 16NoOpen Message

      To enable this feature, locate the class file in the registry and add a NoOpen REG_SZ entry with the custom text you want to be displayed in the caution message box. The NoOpen clause will be in effect only if there are no other shell commands defined for the file class. Furthermore, the NoOpen entry is ignored as soon as you define the first shell command.
      Another interesting feature in Windows 2000 is the Open With popup menu that allows you to choose which program should handle a certain document type. Once again, you can programmatically control those lists through the registry. The subtree is:

HKEY_CURRENT_USER
  \Software
    \Microsoft
      \Windows
        \CurrentVersion
          \Explorer
            \FileExts
      To define a new OpenWith list for a file type, you first must make sure that the file type is properly registered. Suppose you want to change the OpenWith list for .xyz files. Create a .xyz\OpenWithList subtree under the FileExts node. Any entry in the menu must be qualified by a progressive letter: a, b, c, and so forth. The order in which the items appear in the menu is set through an additional MRUList entry. It contains the sequence of the letters that define the order of the items, for example, "abc". Figure 17 presents two simple VBScript scripts to create and destroy a minimal OpenWith list for XYZ files. Figure 18 shows the menu in action.

Figure 18 Open With Menu
Figure 18Open With Menu

      To add an item to an existing list, you should determine the first letter available, then modify the MRUList entry. Notice that deleting registry nodes is different under Windows 9x, Windows NT, and Windows 2000. Deletion is automatically recursive under Windows 9x and deletes the entire subtree. Under Windows 2000, however, you can delete a registry node only if it doesn't contain child nodes. Entries don't affect node deletion.
      You can also change the behavior of connected files (which I'll define in a minute) through the registry. You've probably already run into a rather intriguing feature using HTML files in Windows 2000. Open an HTML page with Microsoft Internet Explorer 5.0 and then save it locally using the Save As menu command. Internet Explorer 5.0 saves only the main HTML page in the folder you specified, and creates a subdirectory where it stores all other files such as images, scripts, Cascading Style Sheets, and so on. It also automatically provides for redirecting internal tags to the newly created subfolder. The child folder has the name of the default page followed by _files. Interestingly, if you delete the default page or the subfolder, both disappear from the disk. The HTML page and its child folder are connected; the Windows 2000 shell is aware of this and acts accordingly. This feature is enabled only for HTML files, and only if you make your deletion through the shell or programmatically through the SHFileOperation function. It doesn't work if you delete either the page or the folder via the DeleteFile API function or the MS-DOS DEL command.
      This HTML auto-delete feature is controlled by a new flag supported by the Windows 2000 version of SHFileOperation. While calling the function, you can now employ the FOF_NO_CONNECTED_ELEMENTS flag. The effect is that the function doesn't move or delete connected files as an individual file; it only moves or deletes the specified files. Windows 2000 designates HTML pages as connected files since they often have a number of associated files that you need to copy, move, or delete as a whole to avoid breaking links. Such a feature is enabled by default and can be disabled as needed by setting the FOF_NO_CONNECTED_ELEMENTS flag before calling SHFileOperation. If you want to turn it off altogether, then go to

HKEY_CURRENT_USER
  \Software
    \Microsoft
      \Windows
        \CurrentVersion
          \Explorer
and make sure that a REG_DWORD entry called NoFileFolderConnection exists and set it to 1. Deleting the entry or setting its value to 0 turns the special HTML support back on.
      At the moment, only files with an extension of .htm or .html can be connected files. Their associated files are those contained in a child folder with a particular name. (The _files suffix is subject to localization.) Unfortunately, there is not a documented way to create custom connections and relationships between other groups of files.

Advanced Application Customization

      You can use the registry to customize application behavior. For example, through the registry you can get Windows 2000 and Windows 98 to use the same Outlook® Express e-mail folders and rename Favorites links. In this section, I'll show you how.
      The registry is the recommended place to store configuration data for both the system and applications. In general, an application should provide users with a public interface (such as an MMC snap-in or a Customize dialog box) to set all possible preferences. This approach often turns out to be a bit impractical, however, because of the large number of settings, time constraints, or because developers don't want certain parameters to be easily configured by users. Nevertheless, understanding an application's registry data can help you implement features that would otherwise be impossible to implement. I'll provide two examples of how tweaking the registry can help to enhance the user's experience of Windows 2000.
      One of my clients had multi-boot computers and wanted to use the same e-mail archives from both Windows 2000 and Windows 98. By default, on a multi-boot machine you'll have two completely separate installations of Outlook Express using separate folders. Outlook Express utilizes the registry to persist all sorts of parameters, including the store root directoryâ€"the path of the folder where all messages are kept. To solve both problems, I had to figure out the physical path for Outlook Express archives and devise a way to redirect it. On my machine Outlook Express stored lots of configuration information under:

HKEY_CURRENT_USER
  \Identities
    \{ACCC8CB2-2152-4378-A1A2-9F0C11D7CF76}
      \Software
        \Microsoft
          \Outlook Express
            \5.0
Here the CLSID is simply the ID of one of the possible identities you're using to send and receive messages through Outlook Express. The REG_SZ entry named StoreRoot contains the path name where all the archives are kept. You can change this entry to share Outlook Express archives among multiple installations.
      Another example of how registry tweaking can make your life easier makes use of the Windows 2000 Registry Editor. I like the Favorites menu that allows you to define shortcuts to frequently visited subtrees. However, I soon realized that it doesn't allow you to rename an existing link. You can rename a link, however, with the Registry Editor. To get to the Favorites subtree I just added another favorite link to:
HKEY_CURRENT_USER
  \Software
    \Microsoft
      \Windows
        \CurrentVersion
          \Applets
            \Regedit
              \Favorites

      Now I can go there with a click and rename items through the Registry Editor's user interface.

The Windows 2000 Open File Dialog

      With Windows 2000, the common Open File dialog changed its look and now shows a vertical toolbar (also known as a places bar) from which you can switch directly to frequently visited folders. Wouldn't it be great if you could programmatically specify which folders to display in the places bar and the number of folders to display? To date, the Windows 2000 SDK doesn't provide much of an opportunity for full customization. The only thing you can do on a per-program basis is hide the places bar by properly setting the new (Windows 2000) FlagsEx member of the OPENFILENAME structure:
OPENFILENAME ofn;
ofn.FlagsEx = OFN_EX_NOPLACESBAR;
      You could also turn the places bar off for all applications by setting a particular policy for common dialogs. Go to
HKEY_CURRENT_USER
  \Software
    \Microsoft
      \Windows
        \CurrentVersion
          \Policies
            \ComDlg32
and make sure there is a NoPlacesBar REG_SZ entry set to 1. For this change to take effect you don't need to reboot or shut down any applications. The relevant registry settings, in fact, are never cached and are always reread before displaying the dialog.
      The registry also specifies the icons for the commonly used folders that populate the places bar. The folders that appear there by default are History, Desktop, My Documents, My Computer, and My Network Places.
      To insert your own list of favorite folders, go to the same ComDlg32 node and create a new key called PlacesBar. You can specify up to five folders. Each folder is identified by an entry called Place0, Place1, and so forth, up to Place4. The value of these entries can be either a fully qualified path name or a CSIDL value that identifies a special folder independent of the particular machine. CSIDLs are numeric values that shell functions such as SHGetFolderLocation use to identify system-dependent or virtual folders such as My Documents, My Computer, Windows, My Network Places, and to find folders that reside in different locations on different machines.

Figure 19 Custom Places Bar
Figure 19Custom Places Bar

      If you want to specify an absolute file system path, create a REG_SZ or REG_EXPAND_SZ entry. If you plan to use a CSIDL, then a REG_DWORD entry is mandatory. CSIDL values are defined in shlobj.h. Make sure you get the one that ships with the latest Platform SDK if you want the new IDs specific to Windows 2000. The PlacesBar key does not exist by default. In this case GetOpenFileName displays the usual five folders. Figure 19 shows a new places bar that displays the folders I have chosen (Articles, WINNT, My Documents, Favorites, My Computer).

Registry API Flavors and New Functions

      There are basically three ways to program the registry: the Win32 API functions (advapi32.dll), the more recent Shell Lightweight API (shlwapi.dll), and various object models accessible mostly from Visual Basic® and Windows Script Host. If Visual Basic is your favorite development tool, I recommend taking a look at the RegObj library available from https://msdn.microsoft.com/vbasic/downloads. It is an object model that emulates the full Win32 API for working with the registry.
      The original set of registry functions provides you with the greatest flexibility. It requires you to open a key, to read or write to it, and then close it; the three basic operations for reading or writing an individual entry.
      The Shell Lightweight libraryâ€"also available with Windows 98, Windows 95, and Windows NT 4.0 plus Internet Explorer 5.0 or higherâ€"comes with some new functions that internally open and close the specified key when asked to read or write values. You just call SHGetValue or SHSetValue and let the function deal with the registry. In addition, the new API provides a SHDeleteKey function that recursively deletes non-empty keys. As explained earlier, this is the standard behavior in Windows 9x, but not in Windows NT or Windows 2000.
      The Windows 2000 SDK introduces three new functions that work with the registry: RegOpenUserClassesRoot, RegOpenCurrentUser, and RegDisablePredefinedCache. RegOpenUserClassesRoot returns a handle to HKCR for the specified user. You identify the user through an access token. The token can be returned by functions like LogonUser, and allows you to log onto the system as if you were another user.
      RegOpenCurrentUser retrieves a handle to HKCU. Notice that by default all the values stored in HKCU are cached for all threads in a process. To disable this practice and force the API to read and write from disk, remember to call RegDisablePredefinedCache.
      IQueryAssociations is another tool for working with the registry. It simplifies the information retrieval from HKCR and HKCU. You obtain a reference to the interface through IShellFolder's GetUIObjectOf or a new API function called AssocCreate. The IQueryAssociations methods allow you to set the root key and query for data, as shown in the following code:
IQueryAssociations *pQA=NULL;
AssocCreate(CLSID_QueryAssociations,
IID_IQueryAssociations, &pQA);
pQA->Init(NULL, _T(".txt"), NULL, NULL);
      You can force the interface to work on the portion of the HKCR that contains information about the specified file class. Alternatively, you could specify a ProgID or specify the HKEY handle to be the root. All the subsequent calls to IQueryAssociations methods (GetData, GetString) will use this root as the starting point for searching information.
      Other functions, such as AssocQueryKey and AssocQueryString, retrieve file information in a single shot and can be considered a more compact and direct replacement for repeated calls to RegOpenKeyEx, RegQueryValueEx, or SHGetValue.

Overriding Predefined Keys

      To improve setup programs and, more importantly, their interaction with the rest of the system, Microsoft introduced a new API called RegOverridePredefKey. Its purpose is to temporarily remap one of the registry's root nodes to a user-defined subtree. In this way, a setup program can checkâ€"and possibly denyâ€"all the registry settings that an installing component might want to create. Remapping HKCU or HKLM to a temporary key doesn't change anything for the component; it doesn't even realize it is writing to a different key. For all purposes, the remapped key evaluates to the original one. Once the component finishes updating the registry, the setup program can controlâ€"and possibly fixâ€"the entries before restoring the original root node and copying the entries from the temporary key to the right place.
      While the MSDN documentation emphasizes its use mostly within installation programs, I think that RegOverridePredefKey could be just as effectively used to accomplish less noble, but necessary tasks such as subclassing, discovery of program internals, and customization of existing programsâ€"all the dirty tasks that your users often ask for, but which aren't well documented. I'll explain how this works.
      The prototype of the function is rather straightforward:

LONG RegOverridePredefKey(
  HKEY hKey,     
  HKEY hNewHKey  
);
The hKey parameter is the handle to any of the predefined root nodes such as HKCR, HKCU, and HKLM. The hNewHKey argument is the handle to the key to the hive where all access will be automatically redirected. By remapping a node you can sometimes force existing programs to read the settings you want, instead of those they were supposed to read. Different settings may result in a different behavior (subclassing).
      This code remaps HKCU to HKCU\Dino:
RegOpenKeyEx(HKEY_CURRENT_USER, "Dino", 0, KEY_ALL_ACCESS, &hkMyCU);
RegOverridePredefKey(HKEY_CURRENT_USER, hkMyCU);
From now on, any attempt to read or write under HKCU transparently occurs under HKCU\Dino. To restore the original mapping, do the following:
RegOverridePredefKey(HKEY_CURRENT_USER, NULL);
      Once you called RegOverridePredefKey, you can safely close your handle to the mapping keyâ€"in this case, hkMyCU.
      The mapping is not a global setting; it takes place only within the context of the process that calls RegOverridePredefKey. So if you plan to use this feature to customize the behavior of existing programs, remember that you cannot spawn them from your own program. Instead, you should be able to "invade" the address space of the target app and call RegOverridePredefKey from there.
      Earlier, you may recall, I mentioned regedit.exe and the LastKey entry. Well, once you've successfully hooked up the Registry Editor process, you just call:
 RegOpenKeyEx(HKEY_CURRENT_USER, 
 "YourTempKey", 0, KEY_ALL_ACCESS, &hkTemp);
 RegOverridePredefKey(HKEY_CURRENT_USER, 
 hkTemp);
Then Regedit will try to access a subtree like this under what it thinks is HKCU:
  \Software
    \Microsoft
      \Windows
        \CurrentVersion
          \Applets
            \Regedit
      This time, though, the internal pointer is not placed on the real HKCU. It is placed, instead, on your temporary key, where such a subtree doesn't exist. Consequently, LastKey cannot be read, and the registry has all the root nodes collapsed. When you decide to override a predefined key, it's important that you restore things as soon as possible.
      This is even more important when you're working in another process's address space. In this case, you may not be informed of all the possible interaction between the registry and the program, so the risk of inadvertently breaking the application is high. In the previous example, you might restore the original mapping when the first WM_SHOWWINDOW message is fired.

      I described this example only for educational purposes and to help you understand the overall role of this official documented API function. Interprocess subclassing and hooking are not a recommended practice in Win32 and should be employed only when strictly necessary. For more information on this topic, refer to the book Advanced Windows by Jeffrey Richter (Microsoft Press, 1997).

Customizing the Shell's New Menu

      Every seasoned user of Windows knows about the New menu, available by right-clicking on any folder outside the area reserved for folder items. You can customize this menu to make it easy to create new files of your own file types from the shell. You can also add files to that menu that are not specific to your application or that you use regularly (such as HTML or XML files), but are not listed in the default menu content.
      Making a file type appear in the New menu is a two-step process. Assuming that a file type, such as .xml, is already properly registered, you start by creating a ShellNew key under the HKCR\.xml.
      The second step associates a creation procedure with the file type. The content of the new file can be determined in four ways. It could be an empty file, provided that it makes sense to you and the applications that will handle it. To create a null file, create an empty NullFile REG_SZ entry under ShellNew. The newly created file will have zero length. The name of the file is determined by concatenating the word New with the file type description (New XML Document.xml.)
      You could also initialize the file with a chunk of binary data read directly from the registry or from a disk file. In the former case, create a REG_BINARY Data entry and fill it with the binary stream of data. If you want to use a disk file template, then the entry you should create is FileName. It points to a file name that will be duplicated in the current folder. The template's path defaults to c:\winnt\shellnew. Notice that you get an error if FileName is empty, but not if it points to a file that does not exist.
      In all these cases, there's no way for you to interact with the shell during the file creation process. You can change the file name, but you can't dynamically determine the content based on runtime conditions. If you want more interaction, choose the fourth option and specify the name of an executable. This program can receive on the command line the default name of the new file, but it is totally responsible for the file's actual creation and content.

Figure 20 Creating XML and HTML Files
Figure 20Creating XML and HTML Files

      In Figure 20 you can see a program that helps create new HTML and XML files. Let's see how to register this program to handle the creation of new documents. Suppose you want it to generate XML files. Go to HKCR\.xml\ShellNew, create a REG_SZ Command entry, and make it point to the executable's name. Use the %1 symbol so it receives the suggested name for the new file on the command line.

Conclusion

      The registry is the focal point for many programming activities and the repository of configuration data. It is also a crucial element in Windows operating systems. The structure of the Windows NT and Windows 2000 registry makes them more accessible and robust than the registry in Windows 9x. Beyond using it to store your own data, the registry lets you do basically two things: read internal information that other programs have written, and modify existing system information to make Windows work the way you want it.
      Tweaking the registry is not for everyone. Only power users and expert programmers should write to the registry. And remember, if you do tweak the registry, make sure you keep a fresh backup copy of the registry on every machine.
For related articles see:
https://support.microsoft.com/support/kb/articles/Q132/3/32.asp
For background information see:
Windows 2000 Registry by Paul Sanna (Prentice Hall, 2000)
Dino Esposito is a trainer and consultant based in Rome. Author of several books for Wrox Press, he now spends most of his time teaching classes on ASP(+) and ADO(+). Get in touch with Dino at desposito@vb2themax.com.

From the November 2000 issue of MSDN Magazine.