Iterating through the registry
You can iterate through the registry items and nodes the way you expect to iterate through any collection. Iterate through items by index like this:
For i = 0 To node.ItemCount - 1
With node.Items(i)
s = s & .Name & “(“ & i & “) = “ & VarToStr(.Value) & sCrLf
End With
Next
The VarToStr function in this loop is local to the test program. It converts numeric, integer, or binary data to a string in the following format:
(0) = Default
Bytes(1) = 54 00 68 00 65 00 20 00 ...
String(2) = A String
Number(3) = &H00000005 (5)
ExpandString(4) = A C:\temp string
Normally, it’s easier to iterate with For Each. The CRegItemWalker and CRegNodeWalker classes do the hard work (as explained in Chapter 4) so that you can iterate easily:
For Each nodesSub In node
s = s & nodesSub.Name & sCrLf
‘ Iterate items with For Each
For Each item In nodesSub.Items
s = s & item.Name & “ = “ & VarToStr(item.Value) & sCrLf
Next
Next
The outer loop walks through nodes, and the inner loop walks through the items of each node.
You can use these techniques to iterate yourself, but there’s an even easier way. CRegNode knows how to walk using the WalkNodes, WalkItems, and WalkAllNodes methods. Let’s look at WalkAllNodes, which walks recursively through all the nested nodes at and below the current node. WalkAllNodes keeps walking through nodes with For Each, calling itself on each node it finds until there are no nodes left to walk. There’s only one problem. How does WalkAllNodes know what to do with what it walks? It doesn’t. Only the client can say what needs to be done, and the way to ask the client is through an interface.
The IUseRegItems interface provides the template for registry operations on items or nodes:
Function UseNode(node As CRegNode, ByVal iLevel As Long) As Boolean
End Function
Function UseItem(item As CRegItem, ByVal iLevel As Long) As Boolean
End Function
The client of the CRegNode class implements the IUseRegItems interface and passes an IUseRegItems object to CRegNode. In the Test Registry program, the main form does the implementing. It provides IUseRegItems_UseItem and IUseRegItems_UseNode functions that append formatted text for each node or item to a module-level string, which is written to a textbox when the walk is finished. In real life, you’d probably want to do something more interesting—such as put the nodes in a TreeView and the items in a ListView.
The WalkAllNodes method calls back to the IUseRegItems object you pass it so that your code can handle the real work. The client code is easy:
node.WalkAllNodes Me, node, 0
The first parameter of WalkAllNodes is the IUseRegItems object that tells what to do with each node and item. Since the client form implements IUseRegItems, it can simply pass itself. The second parameter is the starting node. The third parameter is the indent level. Each nested call to WalkAllNodes increments the indent level, which is passed back to the client in the UseNode and UseItem procedures. The client can use the level to produce formatted output. For example, here’s how the Test Registry form implements the UseNode procedure:
Private Function IUseRegItems_UseNode(node As CRegNode, _
ByVal iLevel As Long) As Boolean
With node
sOut = sOut & Space$((iLevel) * 4) & .Name & “ : “ & sCrLf
.WalkItems Me, iLevel
DoEvents
End With
End Function
After writing the formatted node information, the code calls WalkItems to handle the item information. For each note item, WalkItems calls UseItem, which Test Registry implements like this:
Private Function IUseRegItems_UseItem(item As CRegItem, _
ByVal iLevel As Long) As Boolean
With item
sOut = sOut & Space$((iLevel - 1) * 4) & “ > “ & _
.Name & “ : “ & VarToStr(.Value) & sCrLf
End With
End Function
The last piece of this puzzle is the implementation of WalkAllNodes in the CRegNode class. First it calls the UseNode method of the IUseRegItems object to display the current node. Then it calls WalkAllNodes recursively to do the same thing again on each node in the current node.
Function WalkAllNodes(use As IUseRegItems, nodeStart As CRegNode, _
ByVal iLevel As Long) As CRegNode
If use.UseNode(nodeStart, iLevel) Then
Set WalkAllNodes = nodeStart
Exit Function
End If
Dim i As Long, nodeT As CRegNode
‘ Iterate by index for greater speed
For i = 0 To nodeStart.NodeCount - 1
Set WalkAllNodes = WalkAllNodes(use, nodeStart.Nodes(i), _
iLevel + 1)
Next
End Function
Notice that WalkAllNodes and UseNode are functions (as are WalkNodes, WalkItems, and UseItem). This enables you to write registry search procedures. Your implementation of UseNode could check for items that meet a certain condition and return True when it is found. WalkAllNodes would recognize the return as a signal to stop walking and return the current node up through the recursion chain. The Test Registry sample program doesn’t use this feature. It always returns False so that the walk continues until there are no more nodes.
Let me make one more point about node and item walking. Under Windows NT there are many things in the registry that your programs might not have the right to access. I’m not going to get into the security issues now. The point is that if you walk through a place you have no right to walk, you’ll encounter an access denied error (5). If you’re not careful, this will terminate your walk, leaving additional walkable objects unwalked. The CRegNode and CRegItem classes have to trap errors and skip unwalkable objects rather than failing on them. This requires some messy code, particularly in the More method of the CRegNodeWalker class.