Walking The Registry Tree
In this installment, we'll take a detailed look at the recursive function we use to walk the Registry, WalkRegTree(), initializing the tree control to depict the structure of the Registry. The parameters, in the order shown, are the handle to an open Registry key and the handle to a tree item.
BOOL CWalkReg::WalkRegTree(HKEY hKey, HTREEITEM htiParent)
{
DWORD dwNSize;
DWORD dwCSize;
WCHAR wszName[MAX_PATH];
CHAR szMBCSName[MAX_PATH];
WCHAR wszClass[256];
FILETIME ft;
TVITEM tviTreeViewItem;
DWORD dwNumChildren = 0;
DWORD dwNumGrandChildren = 0;
LONG rc;
HTREEITEM htiChild;
HKEY hSubKey;
Using the handle to the key passed into the function, we query to find out whether the key has any children. We do this with the CeRegQueryInfoKey() function, passing NULLs for all parameters except dwNumChildren. This instructs the function to return only a count of the child keys of this key.
// query for count of children
rc = CeRegQueryInfoKey (hKey, NULL, NULL, 0,
&dwNumChildren, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
Here's the declaration for CeRegQueryInfoKey(), which shows the other items of information you can retrieve about the key:
LONG RegQueryInfoKey ( HKEY hKey, //Handle to open reg key
LPWSTR lpClass, //Unicode key class name
LPDWORD lpcbClass, //Unicode buffer size for
//class name
LPDWORD lpReserved //unused
LPDWORDlpcSubKeys, //count of child keys
LPDWORD lpcbMaxSubKeyLen, //size of longest child key name
LPDWORD lpcbMaxClassLen //longest child key class name
LPDWORD lpcValues, //count of key values
LPDWORD lpcbMaxValueNameLen, //longest value name
LPDWORD lpcbMaxValueLen, //unused
PDWORD lpcbSecurityDescriptor, //unused
PFILETIME lpftLastWriteTime //unused
);
Passing valid addresses in any of the parameters causes the corresponding data to be returned. To get the class name for a key, you must initialize both the lpClass and lpcbClass parameters.
Now we use the returned count of child keys, dwNumChildren, to enumerate the child keys of the key passed to the function.
//Iterate child keys
for( int iChildKeyEnumIndex = 0;
iChildKeyEnumIndex < dwNumChildren; iChildKeyEnumIndex++ )
{
//get child key name
dwNSize = dim(wszName);
dwCSize = dim(wszClass);
rc = CeRegEnumKeyEx (hKey, iChildKeyEnumIndex,
wszName, &dwNSize, NULL,
wszClass, &dwCSize, &ft);
if(rc != ERROR_SUCCESS)
{ return FALSE; }
When we find a child key, we open it by using the name returned by CeRegEnumKeyEx() and capture the child key's handle in hSubKey.
//open child key by name, capture HKEY
rc = CeRegOpenKeyEx(hKey, wszName, 0,
KEY_ALL_ACCESS, &hSubKey );
if( rc != ERROR_SUCCESS )
{ return FALSE; }
Now we find out whether the child key has children by passing its handle to CeRegQueryInfoKey().
// query for count of grand children
rc = CeRegQueryInfoKey (hSubKey, NULL, NULL, 0,
&dwNumGrandChildren, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
Every time we find hSubKey exists, we insert a new item in the tree control. First, we translate the key's Unicode name to multibyte format to make a caption for the tree item, and then we call our CWalkReg class member InsertTreeItem() to create and position the new tree item.
//convert the name string from WCS to MBCS
wcstombs( szMBCSName, wszName, sizeof(szMBCSName) );
// Add key to tree view.
htiChild = InsertTreeItem (htiParent, szMBCSName, 0,
dwNumGrandChildren, hSubKey);
If we know that the item has no children, we tell it so by passing a 0 (FALSE) flag in the children member of the TVITEM structure and setting this new item data with the CTreeCtrl member SetItem().
if(dwNumChildren == 0)
{
tviTreeViewItem.hItem = htiChild;
tviTreeViewItem.mask = TVIF_CHILDREN | TVIF_HANDLE;
tviTreeViewItem.cChildren = 0;
m_RegTree.SetItem( &tviTreeViewItem );
}
If the subkey has children, we need to recurse to continue walking out the Registry tree.
//if !children, return TRUE
if( dwNumChildren != 0 )
{
//recurse walk tree
WalkRegTree( hSubKey, htiChild );
m_RegTree.Expand(htiChild, TVE_COLLAPSE );
}//end if(dwNumChildren)
} //end for(iterate children )
return TRUE;
}
