views:

247

answers:

4
INT GetTree (HWND hWnd, HTREEITEM hItem, HKEY *pRoot, TCHAR *pszKey, 
             INT nMax) {
    TV_ITEM tvi;
    TCHAR szName[256];
    HTREEITEM hParent;
    HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);

    memset (&tvi, 0, sizeof (tvi));

    hParent = TreeView_GetParent (hwndTV, hItem);
    if (hParent) { 
        // Get the parent of the parent of the...
        GetTree (hWnd, hParent, pRoot, pszKey, nMax);

        // Get the name of the item.
        tvi.mask = TVIF_TEXT;
        tvi.hItem = hItem;
        tvi.pszText = szName;
        tvi.cchTextMax = dim(szName);
        TreeView_GetItem (hwndTV, &tvi);  //send the TVM_GETITEM message?

        lstrcat (pszKey, TEXT ("\\"));
        lstrcat (pszKey, szName);
    } else {
        *pszKey = TEXT ('\0');
        szName[0] = TEXT ('\0');
        // Get the name of the item.
        tvi.mask = TVIF_TEXT | TVIF_PARAM;
        tvi.hItem = hItem;
        tvi.pszText = szName;
        tvi.cchTextMax = dim(szName);
        if (TreeView_GetItem (hwndTV, &tvi))
            //*pRoot = (HTREEITEM)tvi.lParam;  //original
      hItem = (HTREEITEM)tvi.lParam;
        else {
            INT rc = GetLastError();
        }
    }
    return 0;
}

The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved? If you already had the values there would be no need to retrieve them.

Secondly near the comment "original" is the original line of code which will compile with a warning under embedded visual c++ 4.0, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code, and am trying to learn, is it possible the original author made a mistake on this line? The *pRoot should point to HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?

+1  A: 

Many times, API calls take in information in a structure, and also return information in the same structure. If you look at the documentation for TreeView_GetItem, it will clearly show how it operates.

As for the second question, are you compiling as C++? What is the error?

Yann Ramin
You answered the cause of the warning vs error question, it was compiling under c++, after changing it to c it now acts the same in both IDE's.
xaler7
+1  A: 

The LPTVITEM parameter to the TreeView_GetItem macro is used bi-directionally.

TreeView_GetItem does indeed send the TVM_GETITEM message to the treeview. What's going on here is that the caller fills in a little bit of the struct to say "here's what I have and what I want" and then the treeview will fill in the requested bits.

From the TreeView_GetItem documentation

When the TVM_GETITEM message is sent, the hItem member of the TVITEM or TVITEMEX structure identifies the item to retrieve information about, and the mask member specifies the attributes to retrieve.

For the second part, I think it looks like it was a mistake, based on the names of the variables etc., but you should probably check how the function is used in the rest of the code to make sure.

Neil Williams
When I looked at the documentation I was wondering which parameters are in or out parameters, I appreciate though how you pointed out that my frame of reference is off, since I never considered using a single structure to both send and receive at the same time. All the other programming languages I've used the direction was one way (at least on the surface), so when I read getitem I am thinking the transfer is one way. Its something I will have to get used to that functions have return types yet the parameters can act like return types also. Thanks for your answer.
xaler7
+2  A: 
The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved, because if you already had the values there would be no need to retrieve them.

After that comment, the first line is to specify to TreeView_GetItem (which, by the way, is actually a SendMessage in disguise) that we want to retrieve the text of the item and the associated lParam. The next line specifies the handle to the item about which we want information.

The following line specifies where the retrieved text must be saved, i.e. in the szName buffer, which has been allocated at the beginning of the function; the last line before the function call specifies the size of such buffer, so to avoid buffer overflows.

I suggest you to have a look at the documentation of TreeView_GetItem and of TVITEM to understand better what's going on.

Secondly near the comment "original" is the original line of code which will compile with a varning under embedded visual c++, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code and am trying to learn is it possible the original author made a mistake on this line, since the *pRoot should point to and HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?

It's not clear what the code is trying to do there; at first glance I'd say that in the lParam associated to each item in the root node of the treeview is stored a handle to a registry key, and the procedure retrieves it in that way. Still, if it was like that, the (HTREEITEM) cast wouldn't make sense at all; probably it was a mistake, forgiven by the compiler because it treated all handles as plain void *; if my hypothesis is correct you should keep the original line, just replacing (HTREEITEM) with (HKEY).

Matteo Italia
I'll try casting to an HKEY and see what happens.
xaler7
Just to be sure: the tree control about which we are talking is there to show the keys of the registry, right?
Matteo Italia
Yes, that's correct.
xaler7
+1  A: 

The first question is pretty simple: you're filling in a few of the items in the structure to tell what data you want, then calling TreeView_GetItem to actually retrieve the specified data. In this case, you're specifying TVIF_TEXT, which says you want the text for the particular item. You also give it a buffer where it's going to put the text (szName), and tell it how long that buffer is (so it won't write past the end of the buffer). When you call TreeView_GetIem, it copies the text for that item into your buffer.

As to your second question: it looks like all that code (both old and new) is somewhat problematic. The general intent seems to be to retrieve the path to the item that was originally passed in, but it seems to do that rather poorly. It starts by recursively walking up the tree to the root. Then it retrieves the text for the root item, but only into the local variable szName -- which it then ignores (does not copy into szKey). It does store the handle to the root item into hItem (this is where it originally wrote to pRoot).

Then, as it returns (walking back "down" the tree), it retrieves the text for each item, and appends those names to szKey (separated by '\'), to form (most of) the path to the item originally passed in. Unfortunately, as it does this, it ignores the nMax that was passed in, so it can (apparently) write past the end of the szKey buffer.

Jerry Coffin
Your explanation of how recursion works is helpful as I wondered how recursion unwinds. I'm used to automatic bounds checking (from other langauges) so its good you made me see how nMax is not used to keep the size of szKey in sync with its buffer size.
xaler7