| Demonstrates some serious goofing around with treeview item data... For both the Mscomctl and Comctl32 TreeView and ListView controls, the Node and ListItem's ObjPtr values reside at the 3rd DWORD (@ byte offset 8) in the Node and ListItem's lParam, i.e.: MoveMemory pNode, ByVal tvi.lParam + 8, 4 ' ...these aren't yet fully tested ' ' MoveMemory hItem, ByVal ObjPtr(Node) + 68, 4 ' Node's hItem is @ byte offset 68 ' MoveMemory tvi.lParam, ObjPtr(Node) + 84, 4 ' Node's tvi.lParam is @ byte offset 84 ' MoveMemory pNode, hItem + 4, 4 ' hItem's ObjPtr(Node) is @ byte offset 4 In the module: Option Explicit ' Brad Martinez, http://www.mvps.org/ccrp/ ' User-defined as the maximum treeview item text length. ' If an items text exceeds this value when calling GetTVItemText, there will be problems... Public Const MAX_ITEM = 256 Public Const EM_SETTABSTOPS = &HCB Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long) Declare Function LocalSize Lib "kernel32" (ByVal hMem As Long) As Long Declare Function lstrcpyA Lib "kernel32" (lpString1 As Any, lpString2 As Any) As Long Declare Function lstrlenA Lib "kernel32" (lpString As Any) As Long Declare Function lstrcpyW Lib "kernel32" (lpString1 As Any, lpString2 As Any) As Long Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hWnd As Long, ByVal wMsg As Long, wParam As Any, _ lParam As Any) As Long ' <--- Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation _ As OSVERSIONINFO) As Long Public Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 ' Maintenance string for PSS usage End Type Public Enum GVE_PlatformId VER_PLATFORM_WIN32s = 0 VER_PLATFORM_WIN32_WINDOWS = 1 VER_PLATFORM_WIN32_NT = 2 End Enum ' what's in treeview hItems... i.e MoveMemory ti, ByVal hItem, Len(ti) ' very undocumented, but has been tested and is consistant in the following: ' Platform Win version IE verson Comctl32.dll version TREEITEM bytes ' Win95 4.00.950a 3.02 (4.70.1215) 4.00.950 32 bytes ' Win95 4.00.950a 3.02 (4.70.1215) 4.70 32 bytes ' NT4 SP3 4.00.1381 3.02 (4.70.1300) 4.70 32 bytes ' Win95 4.00.950a 4.01 (4.72.3118.8 SP1) 4.72.3110.1 36 bytes ' Win98 4,10.1998 4.72.3612.1713 (SP2) 4.72.3612.1702 36 bytes ' NT5 b2 5.00.1877 5.00.0708.700 5.00.0707.3000 36 bytes #Const WIN32_IE = &H400 Public Type TREEITEM ' ti hitemParent As Long ' handle of the item's parent, can be 0 (root's parent is a dummy ' item, whose only valid member is the hitemChild, the root itself) hitemNextSibling As Long ' handle of the item's next sibling, can be 0 hitemChild As Long ' handle of the item's first child, can be 0 lpszText As Long ' pointer to the item's text, allocated in DWORD chunks, can be ' LPSTR_TEXTCALLBACK, is Unicode on NT wState As Integer ' item's state flags, 1st byte is state, low nibble of 2nd byte is ' overlay image index, high nibble of 2nd byte is state image index wImage As Integer ' normal icon imagelist index, can be I_IMAGECALLBACK (&HFFFF) wSelectedImage As Integer ' selected icon imagelist index, can be I_IMAGECALLBACK (&HFFFF) wID As Integer ' appears to be some sort of item ID (?) wIndex As Integer ' item's 0-based physical position in the tree, can change bLevel As Byte ' item's 0-based hierarchical level in the tree bChildren As Byte ' TVITEM.cChildren, can't be I_CHILDRENCALLBACK (?) lParam As Long ' TVITEM.lParam, usually points to something internally allocated ' / 32 bytes #If (WIN32_IE >= &H400) Then dwIDBit As Long ' always 1 #End If End Type ' treeview definitions defined in Commctrl.h ' Callback constants ' T/LVITEM.pszText Public Const LPSTR_TEXTCALLBACK = (-1) ' TVITEM.iImage/iSelectedImage, LVITEM.iImage Public Const I_IMAGECALLBACK = (-1) ' TVITEM.cChildren Public Const I_CHILDRENCALLBACK = (-1&) Public Type TVITEM ' was TV_ITEM mask As TVITEM_mask hItem As Long state As TVITEM_state stateMask As TVITEM_state pszText As Long ' pointer cchTextMax As Long iImage As Long iSelectedImage As Long cChildren As Long lParam As Long End Type Public Enum TVITEM_mask TVIF_TEXT = &H1 TVIF_IMAGE = &H2 TVIF_PARAM = &H4 TVIF_STATE = &H8 TVIF_HANDLE = &H10 TVIF_SELECTEDIMAGE = &H20 TVIF_CHILDREN = &H40 #If (WIN32_IE >= &H400) Then TVIF_INTEGRAL = &H80 #End If TVIF_DI_SETITEM = &H1000 ' Notification End Enum Public Enum TVITEM_state TVIS_FOCUSED = &H1 ' no more than one item TVIS_SELECTED = &H2 ' highlight, more than one?! TVIS_CUT = &H4 TVIS_DROPHILITED = &H8 TVIS_BOLD = &H10 TVIS_EXPANDED = &H20 TVIS_EXPANDEDONCE = &H40 #If (WIN32_IE >= &H300) Then TVIS_EXPANDPARTIAL = &H80 #End If TVIS_OVERLAYMASK = &HF00 TVIS_STATEIMAGEMASK = &HF000 TVIS_USERMASK = &HF000 End Enum ' messages Public Const TV_FIRST = &H1100 Public Const TVM_GETNEXTITEM = (TV_FIRST + 10) Public Const TVM_GETITEM = (TV_FIRST + 12) Public Const TVM_SETITEM = (TV_FIRST + 13) Public Enum TVM_GETNEXTITEM_wParam TVGN_ROOT = &H0 TVGN_NEXT = &H1 TVGN_PREVIOUS = &H2 TVGN_PARENT = &H3 TVGN_CHILD = &H4 TVGN_FIRSTVISIBLE = &H5 TVGN_NEXTVISIBLE = &H6 TVGN_PREVIOUSVISIBLE = &H7 TVGN_DROPHILITE = &H8 TVGN_CARET = &H9 #If (WIN32_IE >= &H400) Then TVGN_LASTVISIBLE = &HA #End If End Enum ' Returns an ANSII string from a pointer to an ANSII string. Public Function GetStrFromPtrA(lpszA As Long) As String Dim sRtn As String sRtn = String$(lstrlenA(ByVal lpszA), 0) If Len(sRtn) Then Call lstrcpyA(ByVal sRtn, ByVal lpszA) GetStrFromPtrA = sRtn End If End Function ' Returns an ANSII string from a pointer to a Unicode string. Public Function GetStrFromPtrW(lpszW As Long) As String Dim sRtn As String sRtn = String$(lstrlenW(ByVal lpszW) * 2, 0) ' 2 bytes/char If Len(sRtn) Then Call lstrcpyW(ByVal sRtn, ByVal lpszW) GetStrFromPtrW = StrConv(sRtn, vbFromUnicode) End If End Function ' Returns the string before first null char encountered (if any) from an ANSII string. Public Function GetStrFromBufferA(sz As String) As String If InStr(sz, vbNullChar) Then GetStrFromBufferA = Left$(sz, InStr(sz, vbNullChar) - 1) Else ' If sz had no null char, the Left$ function above would return a zero length string (""). GetStrFromBufferA = sz End If End Function ' Returns True if the current operating system is WinNT Public Function IsWinNT() As Boolean Dim osvi As OSVERSIONINFO osvi.dwOSVersionInfoSize = Len(osvi) GetVersionEx osvi IsWinNT = (osvi.dwPlatformId = VER_PLATFORM_WIN32_NT) End Function ' treeview calls ' Returns the lParam of the specified treeview item. Public Function GetTVItemlParam(hwndTV As Long, hItem As Long) As Long Dim tvi As TVITEM tvi.mask = TVIF_PARAM tvi.hItem = hItem If TreeView_GetItem(hwndTV, tvi) Then GetTVItemlParam = tvi.lParam End If End Function ' Returns the text of the specified treeview item if successful, returns an empty string otherwise. ' hwndTV - treeview's window handle ' hItem - item's handle whose text is to be to returned ' cbItem - length of the specified item's text. Public Function GetTVItemText(hwndTV As Long, hItem As Long, _ Optional cbItem As Long = MAX_ITEM) As String Dim tvi As TVITEM ' Initialize the struct to retrieve the item's text. tvi.mask = TVIF_TEXT tvi.hItem = hItem tvi.pszText = StrPtr(String$(cbItem, 0)) tvi.cchTextMax = cbItem If TreeView_GetItem(hwndTV, tvi) Then GetTVItemText = GetStrFromPtrA(tvi.pszText) End If End Function ' Returns the specified treeview item's TVITEM.cChildren value ' hwndTV - treeview's window handle ' hItem - handle of the item to evaluate Public Function GetTVItemChildren(hwndTV As Long, hItem As Long) As Long Dim tvi As TVITEM tvi.mask = TVIF_CHILDREN tvi.hItem = hItem Call TreeView_GetItem(hwndTV, tvi) GetTVItemChildren = tvi.cChildren End Function ' Treeview macros defined in Commctrl.h ' Retrieves some or all of a tree-view item's attributes. ' Returns TRUE if successful or FALSE otherwise. Public Function TreeView_GetItem(hWnd As Long, pitem As TVITEM) As Boolean TreeView_GetItem = SendMessage(hWnd, TVM_GETITEM, 0, pitem) End Function ' Sets some or all of a tree-view item's attributes. ' Old docs say returns zero if successful or - 1 otherwise. ' New docs say returns TRUE if successful, or FALSE otherwise Public Function TreeView_SetItem(hWnd As Long, pitem As TVITEM) As Boolean TreeView_SetItem = SendMessage(hWnd, TVM_SETITEM, 0, pitem) End Function ' TreeView_GetNextItem ' Retrieves the tree-view item that bears the specified relationship to a specified item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetNextItem(hWnd As Long, hItem As Long, flag As Long) As Long TreeView_GetNextItem = SendMessage(hWnd, TVM_GETNEXTITEM, ByVal flag, ByVal hItem) End Function ' Retrieves the first child item. The hitem parameter must be NULL. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetChild(hWnd As Long, hItem As Long) As Long TreeView_GetChild = TreeView_GetNextItem(hWnd, hItem, TVGN_CHILD) End Function ' Retrieves the next sibling item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetNextSibling(hWnd As Long, hItem As Long) As Long TreeView_GetNextSibling = TreeView_GetNextItem(hWnd, hItem, TVGN_NEXT) End Function ' Retrieves the previous sibling item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetPrevSibling(hWnd As Long, hItem As Long) As Long TreeView_GetPrevSibling = TreeView_GetNextItem(hWnd, hItem, TVGN_PREVIOUS) End Function ' Retrieves the parent of the specified item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetParent(hWnd As Long, hItem As Long) As Long TreeView_GetParent = TreeView_GetNextItem(hWnd, hItem, TVGN_PARENT) End Function ' Retrieves the first visible item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetFirstVisible(hWnd As Long) As Long TreeView_GetFirstVisible = TreeView_GetNextItem(hWnd, 0, TVGN_FIRSTVISIBLE) End Function ' Retrieves the next visible item that follows the specified item. The specified item must be visible. ' Use the TVM_GETITEMRECT message to determine whether an item is visible. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetNextVisible(hWnd As Long, hItem As Long) As Long TreeView_GetNextVisible = TreeView_GetNextItem(hWnd, hItem, TVGN_NEXTVISIBLE) End Function ' Retrieves the first visible item that precedes the specified item. The specified item must be visible. ' Use the TVM_GETITEMRECT message to determine whether an item is visible. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetPrevVisible(hWnd As Long, hItem As Long) As Long TreeView_GetPrevVisible = TreeView_GetNextItem(hWnd, hItem, TVGN_PREVIOUSVISIBLE) End Function ' Retrieves the currently selected item. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetSelection(hWnd As Long) As Long TreeView_GetSelection = TreeView_GetNextItem(hWnd, 0, TVGN_CARET) End Function ' Retrieves the item that is the target of a drag-and-drop operation. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetDropHilight(hWnd As Long) As Long TreeView_GetDropHilight = TreeView_GetNextItem(hWnd, 0, TVGN_DROPHILITE) End Function ' Retrieves the topmost or very first item of the tree-view control. ' Returns the handle to the item if successful or 0 otherwise. Public Function TreeView_GetRoot(hWnd As Long) As Long TreeView_GetRoot = TreeView_GetNextItem(hWnd, 0, TVGN_ROOT) End Function 'Code in Form1.frm Option Explicit Private m_hwndTV As Long Private Sub Form_Load() Dim Node1 As Node Dim Node2 As Node Dim Node3 As Node Dim i As Integer Dim j As Integer Dim k As Integer ' number of Nodes at each respective hierarchical level Const nNodes1 = 2 Const nNodes2 = 3 Const nNodes3 = 3 Call SendMessage(Text1.hWnd, EM_SETTABSTOPS, ByVal 1, 60) With TreeView1 ' Initialize the TreeView .HideSelection = False .Indentation = 19 * Screen.TwipsPerPixelX .LabelEdit = tvwManual .LineStyle = tvwRootLines m_hwndTV = .hWnd ' Fill up the treeview... For i = 1 To nNodes1 Set Node1 = .Nodes.Add(, , , "Root" & i, 1, 1) For j = 1 To nNodes2 Set Node2 = .Nodes.Add(Node1.Index, tvwChild, , "Root" & i & "Child" & j, 2, 2) For k = 1 To nNodes3 Set Node3 = .Nodes.Add(Node2.Index, tvwChild, , _ "GrandChild" & (nNodes2 * nNodes3 * (i - 1)) + (nNodes3 * (j - 1)) + k, 3, 3) Next Next Node1.Expanded = True Next .Nodes(1).Selected = True Call TreeView1_NodeClick(.Nodes(1)) End With End Sub Private Sub TreeView1_NodeClick(ByVal Node As ComctlLib.Node) Dim hItem As Long Dim ti As TREEITEM Dim sOut As String hItem = TreeView_GetSelection(m_hwndTV) If hItem Then MoveMemory ti, ByVal hItem, Len(ti) With ti ' The root's parent hItem points to a dummy hItem, whose ' only valid TREEITEM member is hitemChild, the root itself. sOut = GetTVItemText(m_hwndTV, .hitemParent) If Len(sOut) Then sOut = "hitemParent:" & vbTab & sOut & vbCrLf Else sOut = "hitemParent:" & vbTab & " End If If .hitemNextSibling Then sOut = sOut & "hitemNextSibling:" & vbTab & GetTVItemText(m_hwndTV, _ .hitemNextSibling) & vbCrLf Else sOut = sOut & "hitemNextSibling:" & vbTab & " End If If .hitemChild Then sOut = sOut & "hitemChild:" & vbTab & GetTVItemText(m_hwndTV, _ .hitemChild) & vbCrLf Else sOut = sOut & "hitemChild:" & vbTab & " End If If (.lpszText = LPSTR_TEXTCALLBACK) Then sOut = sOut & "lpszText:" & vbTab & "LPSTR_TEXTCALLBACK" & vbCrLf Else If IsWinNT Then sOut = sOut & "lpszText:" & vbTab & GetStrFromPtrW(.lpszText) & vbCrLf Else sOut = sOut & "lpszText:" & vbTab & GetStrFromPtrA(.lpszText) & vbCrLf End If End If sOut = sOut & "wState" & vbTab & "&H" & Hex(.wState) & vbCrLf If (.lpszText = I_IMAGECALLBACK) Then sOut = sOut & "wImage:" & vbTab & "I_IMAGECALLBACK" & vbCrLf Else sOut = sOut & "wImage:" & vbTab & .wImage & vbCrLf End If If (.lpszText = I_IMAGECALLBACK) Then sOut = sOut & "wSelectedImage:" & vbTab & "I_IMAGECALLBACK" & vbCrLf Else sOut = sOut & "wSelectedImage:" & vbTab & .wSelectedImage & vbCrLf End If sOut = sOut & "wID:" & vbTab & .wID & vbCrLf sOut = sOut & "wIndex:" & vbTab & .wIndex & vbCrLf sOut = sOut & "bLevel:" & vbTab & .bLevel & vbCrLf sOut = sOut & "bChildren:" & vbTab & .bChildren & vbCrLf sOut = sOut & "lParam size:" & vbTab & LocalSize(.lParam) & vbCrLf #If (WIN32_IE >= &H400) Then ' valid only for Comctl32.dll >= v4.71 sOut = sOut & "dwIDBit:" & vbTab & "&H" & Hex(.dwIDBit) & " bytes" #End If End With ' ti Text1 = sOut End If ' hItem End Sub Private Sub Command1_Click() Static fRemoveCallbacks As Boolean fRemoveCallbacks = Not fRemoveCallbacks Call SetNodeCallbacks(TreeView_GetRoot(m_hwndTV), fRemoveCallbacks) Call TreeView1_NodeClick(TreeView1.SelectedItem) End Sub ' Recursively walks the whole tree, toggling the callback attributes (text, images, button) for all Nodes in the VB TreeView's real treeview, as specified by the fRemove flag.. The TreeView normally does callback for these items, but can be explicitly set and overridden (and the VB TreeView has no idea what's happening). ' On first call, pass TreeView_GetRoot for hitemSib Private Sub SetNodeCallbacks(hitemSib As Long, fRemove As Boolean) Dim tvi As TVITEM Dim nod As Node tvi.mask = TVIF_TEXT Or TVIF_IMAGE Or TVIF_SELECTEDIMAGE ' Or TVIF_CHILDREN Do While hitemSib ' test code, uncomment for the Immediate and Locals window 'Debug.Print GetTVItemChildren(m_hwndTV, hitemSib) 'Call InvestigateTVItemData(m_hwndTV, hitemSib) tvi.hItem = hitemSib If fRemove Then ' Get the Node from the hItem, and remove the item's ' callback attributes by explicitly setting them. Set nod = GetNodeFromhItem(hitemSib) If ((nod Is Nothing) = False) Then ' Store the Node's Text in an allocated pointer' tvi.pszText = StrPtr(String$(MAX_ITEM, 0)) Call lstrcpyA(ByVal tvi.pszText, ByVal nod.Text) ' real imagelist indices are zero-based tvi.iImage = nod.Image - 1 tvi.iSelectedImage = CLng(nod.SelectedImage) - 1 ' see below... ' tvi.cChildren = Abs(CBool(TreeView_GetChild(m_hwndTV, hitemSib))) End If Else ' Restore the callbacks tvi.pszText = LPSTR_TEXTCALLBACK tvi.iImage = I_IMAGECALLBACK tvi.iSelectedImage = I_IMAGECALLBACK ' this causes problems, something's weird here that has yet to be understood... ' tvi.cChildren = I_CHILDRENCALLBACK End If Call TreeView_SetItem(m_hwndTV, tvi) ' Recursively call this proc using the current sibling's first child (if any), and get the next sibling Call SetNodeCallbacks(TreeView_GetChild(m_hwndTV, hitemSib), fRemove) hitemSib = TreeView_GetNextSibling(m_hwndTV, hitemSib) Loop End Sub Private Function GetNodeFromhItem(hItem As Long) As Node Dim lParam As Long Dim pNode As Long lParam = GetTVItemlParam(m_hwndTV, hItem) If lParam Then MoveMemory pNode, ByVal lParam + 8, 4 Set GetNodeFromhItem = GetNodeFromPtr(pNode) End If ' lParam End Function Private Function GetNodeFromPtr(pNode As Long) As Node Dim nod As Node MoveMemory nod, pNode, 4 Set GetNodeFromPtr = nod MoveMemory nod, 0&, 4 End Function Public Function InvestigateTVItemData(hwndTV As Long, hItem As Long) As Boolean Dim nod As Node Dim lParam As Long Dim adw0(24) As Long Dim adw1(24) As Long Dim adw2(24) As Long Dim adw3(24) As Long Dim adw4(24) As Long Set nod = GetNodeFromhItem(hItem) lParam = GetTVItemlParam(m_hwndTV, hItem) MoveMemory adw0(0), ByVal ObjPtr(nod), 100 ' Node's hItem is in adw0(17) (@ byte offset 68) MoveMemory adw1(0), ObjPtr(nod), 100 ' Node's tvi.lParam is in adw1(21) (@ byte offset 84) MoveMemory adw2(0), ByVal lParam, 100 ' tvi.lParam's pNode is in adw2(2) (@ byte offset 8) MoveMemory adw3(0), ByVal hItem, 100 ' hItem's tvi.lParam's is in adw3(7) (@ byte offset 28) MoveMemory adw4(0), hItem, 100 ' hItem's ObjPtr(Node) is in adw4(1) (@ byte offset 4) Stop End Function ' Determines if the given treeview item handle is valid and exists in the specified treeview. ' The hItem is valid if it equals the child (@ byte offset 8), or child's sibling ' (@ byte offset 4), of the hItem's parent (@ byte offset 0) Public Function IsTVItemValid(hwndTV As Long, hItem As Long) As Boolean Dim hitemParent As Long Dim hitemChild As Long Dim fValid As Boolean If (LocalSize(hItem) >= 32) Then ' Get the item's parent (the root has a dummy parent hItem) MoveMemory hitemParent, ByVal hItem, 4 ' Get the parent's first child MoveMemory hitemChild, ByVal hitemParent + 8, 4 Do While hitemChild And (fValid = False) fValid = (hItem = hitemChild) ' Get the current sibling's next sibling MoveMemory hitemChild, ByVal hitemChild + 4, 4 Loop End If ' LocalSize IsTVItemValid = fValid End Function |
TreeView Item Data |
Freelance ASP PHP web development | Web developer India Web development India| Prayagasoft - web designer India, Ecommerce developer india, Ecommerce design