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 system wide 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
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
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
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
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 (http://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
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 11 Simple 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
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
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
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
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
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
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 .htm 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
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
http://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
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.
|