Responding to Tree Control Notification Messages

In our last article, we initialized and handled the Walk Registry Tree Page. Once you’ve added all of the items, the tree control manages most of the visual work of collapsing and expanding the tree control. However, there are some parts of the tree control’s behavior over which we want to exert control. First, we need to change the appearance of the icon next to the tree item when its selection state changes. We also must add a newly selected key’s values (or a message saying it has no values) to the list box control.

In order to do this, we need to:

  • Detect and handle tree control notification when the selected item changes.
  • Detect and handle tree control notification when the tree item is expanding.
  • Retrieve the handle to the opened registry key from the item’s lParam value.
  • Enumerate the key values.
  • Interpret and display the key values in the list control.

Here’s our plan of attack:

We created message handlers in CWalkReg to process the notification message from the tree control. Each of these functions was added to CWalkReg using the ClassWizard, which generated the message map entry shown below:

// Implementation
protected:
   // Generated message map functions
   //{{AFX_MSG(CWalkReg)
   afx_msg void OnItemexpandingRegTree(NMHDR* pNMHDR,
                                       LRESULT* pResult);
   afx_msg void OnSelchangedRegTree(NMHDR* pNMHDR,
                                    LRESULT* pResult);
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()

};

We’ll get the handle to the Registry keys for which we want to enumerate values from the lParam of the selected item’s TVITEM structure. (Recall that we stored the corresponding opened key’s handle in each item when we initialized the tree control.)

We’ll retrieve the keys’ values by looping through them with the RAPI function CeRegEnumValue().

Finally, we’ll display the values in the list control, using the CWalkReg member InterpretKeyValue (). This member detects the Registry-defined data type of the value, writes it to a properly formatted string, and inserts it in the list control.

Handling Item Expansion

Let’s start with a look at our simplest tree control notification handler, OnItemexpandingRegTree(). You’ll notice that like ordinary Windows messages handling functions, notification handlers have a standard form. Here are the first two lines of our TVN_ITEMEXPANDING notification handler:

void CWalkReg::OnItemexpandingRegTree(NMHDR* pNMHDR,
                                      LRESULT* pResult)
{

   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

The parameters, in the order shown, are a pointer to a notification message header structure, and a pointer to a variable through which this function can return a result. Notifications extend the windows messaging architecture by allowing controls to send more information than could be encapsulated in a Windows message, and by providing a standard from of communication that is consistent across various control types. To better understand this, let’s look more closely at the structures used to communicate the notification.

The NMHDR typedef looks like this:

typedef struct tagNMHDR {
HWND hwndFrom;    // handle of control sending message
UINT idFrom;      // identifier of control sending message
UINT code;        // control specific notification code
} NMHDR;

Examining the definition shown above, it is apparent that the NMHDR structure explicitly provides the handler function with both the window handle and the ID of the control sending the notification. Note this subtlety: The code member may be used to deliver either a code or a pointer to additional data.

In our example, we handle the TVN_ITEMEXPANDING notification because it is sent after the user has opened an item in the tree control. When this happens, we need to toggle the icon image. If it was the “selected” icon, we’ll set the “unselected” icon, and vice versa.

To change the icon, we need a pointer to the tree view control object. We get this pointer by casting the NMHDR structure pointer to an NM_TREEVIEW* and assigning the pointer to pNMTreeView.

void CTreeWalker::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

Here’s where the notification message magic comes in. At the least, all NOTIFY messages have a populated NMHDR structure, but many control notifications are actually a larger more complex structure that includes NMHDR as the first member of the control specific notification message. Here’s the typedef of the NM_TREEVIEW notification structure:

typedef struct tagNMTREEVIEW {
        NMHDR     hdr;         //the NMHDR structure for this
                               //notification
        UINT      action;      //code for action taken
        TVITEM    itemOld;     //item losing selection
        TVITEM    itemNew;     //item receiving selection
        POINT     ptDrag;      //point where user started dragging
                               //item
     } NM_TREEVIEW, FAR *LP_NMTREEVIEW;

For the purposes at hand, what is important about the NM_TREEVIEW structure is that it contains a fully populated TVITEM structure for the item receiving selection. To manipulate the item icon, we get the item’s handle from itemNew:

// get key handle from tree item
TVITEM tvitem = (TVITEM)pNMTreeView->itemNew;

We set the new image with the CTreeCtrl member SetItemImage(). The parameters to SetItemImage(), in the order shown, are the handle to the tree control item, the zero based image list index for the new icon, and the index of the item’s image when the item is selected.

   if(tvitem.iImage == 0 )
   {
       m_RegTree.SetItemImage( tvitem.hItem, 1, 0 );
   }
   else
   {
       m_RegTree.SetItemImage( tvitem.hItem, 0, 0 );
   }


   *pResult = 0;
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read