Cloning a registry branch
RegCloneBranch()
is a function that copies all values and all sub-keys
below a given key to a new key. It copies a complete branch from the Microsoft
Windows registry, hence. RegCloneBranch()
should perhaps be called
RegCloneKey()
—which is the name I chose initially, but I found that
this name looks too much like the Win32 API function RegCloseKey()
.
Why?
I implemented this function because I needed it (of course) and because
a search on the Internet for such a function turned up empty. Three applications
that I have for RegCloneBranch()
are:
-
Setup programs that need to duplicate (or move) sections from the registry
below a new key.
These actions occur, for example, when updating an application or ActiveX control where the registry key name changed between the versions and you want to keep the user settings —meaning that you have to copy them from the old registry key to the new registry key.
-
Quick switching between multiple configurations.
For system administration, we often plug in a notebook computer into the customer's network. This allows use to use the "power tools" installed on the notebook to indentify and fix problems on the customer's network and client machines more easily and more quickly. For many clients, reconfiguring the notebook's network settings to adhere to the customer's network configuration (protocols, IP addresses, WINS and DHCP settings, gateways, DNS servers, etc.) is a recurring task. So when we have a configuration that works for a particular network, we can copy the sections of the registry that hold the network configuration to a "backup key". Any next time that we need to plug in the notebook in that foreign network, all we need to do is to restore the "backup key" section, by another copy.
-
Deploy applications that use the LeadTOOLS MultiMedia
library and ActiveMovie filters.
To use an ActiveMovie "video filter" control with he LeadTOOLS MultiMedia library, this filter has to be marked as "compatible" with that library. Registering the filter itself is not sufficient. LeadTOOLS provides the "LeadTOOLS Multimedia Filter Manager" to mark an ActiveMovie filter as "compatible" with its library, but...
- the filter manager is an interactive program (not good for an installation program where you want to ask the user the least amount of questions);
- the filter manager is not redistributable.
It turns out, however, that "marking a filter as compatible" involves nothing more than copying the appropriate setting for the ActiveMovie filter out of the registry section for the "ActiveMovie Filter Class Manager" below the registry key for the "LTMM Video Processors".
See the sidebar at the bottom of this article for details on the registry settings for LeadTOOLS filters.
Usage
The definition of RegCloneBranch()
is:
long RegCloneBranch(HKEY hkeyDestRoot, HKEY hkeySrcRoot);
Call RegCloneBranch()
with the source and the destination keys (HKEY
types). Both of these keys must already exist. If the destination key already
contains data, RegCloneBranch()
overwrites it if the source key contains
the same value settings. However, values that exist in the destination key and
that do not exist in the source key are not deleted.
Implementation
I implemented RegCloneBranch()
in straight C. No C++ features are used
and there are no dependencies on anything other than the Win32 API.
When you have used the registry functions earlier, the implementation is
probably straightforward (though lengthy).
#if !defined ASSERT #define ASSERT assert #endif long RegCloneBranch(HKEY hkeyDestRoot, HKEY hkeySrcRoot) { long result=ERROR_SUCCESS; DWORD index; DWORD subkeys,maxkeyname,values,maxvaluename,maxdata,type; LPSTR lpName=NULL, lpData=NULL; /* get information, so that we know how much memory to allocate */ result=RegQueryInfoKey(hkeySrcRoot,NULL,NULL,NULL,&subkeys,&maxkeyname, NULL,&values,&maxvaluename,&maxdata,NULL,NULL); if (result!=ERROR_SUCCESS) return result; /* in Windows NT/2000/XP, the name lengths do not include the '\0' terminator */ maxkeyname++; maxvaluename++; /* allocate buffers, one for data and one for value & class names */ if (maxvaluename>maxkeyname) maxkeyname=maxvaluename; ASSERT(maxkeyname>0); lpName=malloc(maxkeyname); if (lpName==NULL) { result=ERROR_NOT_ENOUGH_MEMORY; goto error_exit; } /* if */ if (maxdata>0) { lpData=malloc(maxdata); if (lpData==NULL) { result=ERROR_NOT_ENOUGH_MEMORY; goto error_exit; } /* if */ } else { lpData=NULL; } /* if */ /* first walk through the values */ for (index=0; index<values; index++) { DWORD namesize=maxkeyname; DWORD datasize=maxdata; ASSERT(lpData!=NULL); result=RegEnumValue(hkeySrcRoot,index,lpName,&namesize,NULL,&type,lpData,&datasize); ASSERT(result!=ERROR_MORE_DATA); if (result!=ERROR_SUCCESS) goto error_exit; result=RegSetValueEx(hkeyDestRoot,lpName,0L,type,lpData,datasize); if (result!=ERROR_SUCCESS) goto error_exit; } /* for */ /* no longer need the data block */ if (lpData!=NULL) { free(lpData); lpData=NULL; } /* if */ /* no walk through all subkeys, and recursively call this function to copy the tree */ for (index=0; index<subkeys; index++) { DWORD namesize=maxkeyname; HKEY hkeySrc; HKEY hkeyDest; RegEnumKeyEx(hkeySrcRoot,index,lpName,&namesize,NULL,NULL,NULL,NULL); result=RegOpenKeyEx(hkeySrcRoot,lpName,0L,KEY_READ,&hkeySrc); if (result!=ERROR_SUCCESS) goto error_exit; result=RegCreateKeyEx(hkeyDestRoot,lpName,0L,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL,&hkeyDest,NULL); if (result!=ERROR_SUCCESS) goto error_exit; RegCloneBranch(hkeyDest,hkeySrc); RegCloseKey(hkeySrc); RegCloseKey(hkeyDest); } /* for */ ASSERT(lpName!=NULL); free(lpName); lpName=NULL; return ERROR_SUCCESS; error_exit: if (lpName!=NULL) free(lpName); if (lpData!=NULL) free(lpData); return result; }
The function RegQueryInfoKey()
is very convenient, because it returns
the number of values and sub-keys below a key, as well as the maximum sizes (or lengths)
of names and data. This allows you to allocate precisely the right amount of memory
(that you need to read each item) before seeing every item.
RegCloneBranch()
has two loops. The first loop walks through all "values"
of the source key and copies each into the destination key. The second loop
walks through all sub-keys in the source key, creates those sub-keys below the
destination key and calls itself recursively.
For good measure, I have sprinkled a few assert()
macros through the
source. Please don't choke over the goto
statements, if you look carefully,
you will see that I have used them in a way that a C++ programmer would use
exception handling. It is an idiom that I use from time to time and that has never
caused me any trouble.
Download
The file regclone.c contains the code snippet presented above.
LeadTOOLS Filter Drivers
I built a DirectShow filter driver, which I registered with:
This creates, in my case, the following registry settings:
This installs the MyFilter driver and marks it as a DirectShow transform filter. LeadTOOLS, however, does not work with just any DirectShow transform filter, it only considers those that have been marked as "compatible". Do this with the LeadTOOLS Filter Manager (filename "LTMMFMgr.exe"). I have marked the four bottom lines in yellow to make a point a bit later on. The LeadTOOLS Filter Manager adds the following settings to the registry for the filter:
Observe how the settings of the last four lines (marked in yellow) in the registry settings table are an exact copy of the lines that the filter driver marks itself with to the ActiveMovie Filter Class Manager. That is, the LeadTOOLS Filter Manager does two things:
The |