I've hacked the TreeView message parts of commctrl.h into a vb module, but I'm struggling to make it work. Single argument calls are ok, but once we get into references to UDTs etc. I'm getting lost in byval and byref.
So:
a) I need some help making the SendMessage calls actually work (maybe necessary to do some VarPtr's an CopyMemory's)
b) once a). is sorted I want to make the module easy to use(i.e. hide all the nasty API and pointer and references etc. and call things by passing object refs. (for example))
Anyone wanna help me out?
Dan
Outside of a dog, a book is a man's best friend.
Inside of a dog, it's too dark to read.
OK...no one's interested, so what's wrong with this...
Module stuff
Code:
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Long, _
Source As Long, ByVal Length As Long)
Public Const TV_FIRST = &H1100
Public Const TVM_GETNEXTITEM = (TV_FIRST + 10)
Public Enum TVGN
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
TVGN_LASTVISIBLE = &HA
End Enum
Public Enum TVIF
TVIF_TEXT = &H1
TVIF_IMAGE = &H2
TVIF_PARAM = &H4
TVIF_STATE = &H8
TVIF_HANDLE = &H10
TVIF_SELECTEDIMAGE = &H20
TVIF_CHILDREN = &H40
TVIF_INTEGRAL = &H8
End Enum
Public Type TVITEMEX ' Only used for Get and Set messages.
mask As TVIF
hItem As Long
state As Integer
stateMask As Integer
pszText As Long ' Pointer to null terminated string
cchTextMax As Integer
iImage As Integer
iSelectedImage As Integer
cChildren As Integer
lParam As Long
iIntegral As Integer
End Type
Public Function TreeView_GetSelection(ByVal hwnd As Long) As Long
TreeView_GetSelection = TreeView_GetNextItem(hwnd, 0, TVGN_CARET)
End Function
Public Function TreeView_GetNextItem(ByVal hwnd As Long, ByVal hItem As Long, code As TVGN) As Long
TreeView_GetNextItem = SendMessage(hwnd, TVM_GETNEXTITEM, code, hItem)
End Function
Form stuff
Code:
Private Sub Command1_Click()
Dim hWndProject As Long
Dim hWndIDE As Long
Dim hWndTree As Long
Dim myItemEx As TVITEMEX
Dim lpItem As Long
Dim lpMyItemEx As Long
Dim i As Integer
hWndIDE = FindWindowEx(0, 0, "wndclass_desked_gsk", vbNullString)
hWndProject = FindWindowEx(hWndIDE, 0, "PROJECT", vbNullString)
hWndTree = FindWindowEx(hWndProject, 0, "SysTreeView32", vbNullString)
'i = TreeView_GetCount(hWndTree)
'i = TreeView_GetItemHeight(hWndTree)
'i = TreeView_GetIndent(hWndTree)
lpMyItemEx = VarPtr(myItemEx)
lpItem = TreeView_GetSelection(hWndTree)
CopyMemory lpMyItemEx, lpItem, LenB(myItemEx)
End Sub
I'm not getting any info back on the selected item...?
What am I doing wrong?
[Edited by Judd on 06-21-2000 at 09:46 AM]
Dan
Outside of a dog, a book is a man's best friend.
Inside of a dog, it's too dark to read.
Option Explicit
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function Findwindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SendMessageByNum Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Declare Function SendMessageByString Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Const WM_CLOSE = &H10
Sub p_Close_Dialog()
Dim lng_Dialog As Long
Dim lng_Button As Long
'PURPOSE: Get the handle of an application by the classname
lng_Dialog = Findwindow("#32770", vbNullString)
'lng_Dialog = Findwindow("XLMAIN", vbNullString)
'PURPOSE: Get extra information of that application
lng_Button = FindWindowEx(lng_Dialog, 0&, "Button", vbNullString)
'PURPOSE: Press the Buttons - Method #1
Call SendMessageByNum(lng_Button, WM_LBUTTONDOWN, 0, 0&
Call SendMessageByNum(lng_Button, WM_LBUTTONUP, 0, 0&
'PURPOSE: Press the Buttons - Method #2
Call SendMessage(lng_Button, WM_LBUTTONDOWN, 0, 0&
Call SendMessage(lng_Button, WM_LBUTTONUP, 0, 0&
'PURPOSE: Close the button
Call SendMessageByString(lng_Button, WM_CLOSE, 0, 0&
'PURPOSE: Close the message box
Call SendMessageByString(lng_Dialog, WM_CLOSE, 0, 0&
End Sub
The method above doesn't work because its just generally the wrong way to go about it. This is what ought to be done:
Form code
Code:
Option Explicit
Private Sub Command1_Click()
Dim hWndProject As Long
Dim hWndIDE As Long
Dim hWndTree As Long
Dim myItem As TVITEM
Dim lpItem As Long
Dim lpMyItem As Long
Dim szText As String
Dim bRes As Boolean
hWndIDE = FindWindowEx(0, 0, "wndclass_desked_gsk", vbNullString)
hWndProject = FindWindowEx(hWndIDE, 0, "PROJECT", vbNullString)
hWndTree = FindWindowEx(hWndProject, 0, "SysTreeView32", vbNullString)
szText = String(64, vbNullChar)
lpItem = TreeView_GetSelection(hWndTree)
myItem.hItem = lpItem
myItem.mask = TVIF_TEXT
myItem.pszText = StrPtr(szText)
myItem.cchTextMax = 64
lpMyItem = VarPtr(myItem)
bRes = TreeView_GetItem(hWndTree, lpMyItem)
szText = StrConv(szText, vbUnicode)
Text1.Text = left$(szText, InStr(1, szText, vbNullChar) - 1)
End Sub
Module code
Code:
Option Explicit
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, wParam As Any, lParam As Any) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Const TV_FIRST = &H1100
Public Const TVM_GETNEXTITEM = (TV_FIRST + 10)
Public Const TVM_GETITEM = (TV_FIRST + 12)
Public Enum TVGN
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
TVGN_LASTVISIBLE = &HA
End Enum
Public Enum TVIF
TVIF_TEXT = &H1
TVIF_IMAGE = &H2
TVIF_PARAM = &H4
TVIF_STATE = &H8
TVIF_HANDLE = &H10
TVIF_SELECTEDIMAGE = &H20
TVIF_CHILDREN = &H40
TVIF_INTEGRAL = &H80
End Enum
Public Type TVITEM
mask As TVIF
hItem As Long
state As Long
stateMask As Long
pszText As Long
cchTextMax As Long
iImage As Long
iSelectedImage As Long
cChildren As Long
lParam As Long
End Type
Public Function TreeView_GetSelection(hwnd As Long) As Long
TreeView_GetSelection = TreeView_GetNextItem(hwnd, 0, TVGN_CARET)
End Function
Public Function TreeView_GetNextItem(hwnd As Long, hItem As Long, code As TVGN) As Long
TreeView_GetNextItem = SendMessage(hwnd, TVM_GETNEXTITEM, ByVal code, hItem)
End Function
Public Function TreeView_GetItem(hwnd As Long, pitem As Long) As Boolean
TreeView_GetItem = SendMessage(hwnd, TVM_GETITEM, 0, ByVal pitem)
End Function
Thanks for all contributions!
[Edited by Judd on 06-22-2000 at 08:25 AM]
Dan
Outside of a dog, a book is a man's best friend.
Inside of a dog, it's too dark to read.
Public TREEVIEW_HOOK As Long
Public Const WH_CALLWNDPROC = &H4
Private Type CWPSTRUCT
lParam As Long
wParam As Long
message As Long
hwnd As Long
End Type
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, _
lpdwProcessId As Long) As Long
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
(ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public Function HookWindow(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim tCWP As CWPSTRUCT
Dim tNMTV As NMHDR
Dim sClass As String
Dim myItem As TVITEM
Dim lpItem As Long
Dim lpMyItem As Long
Dim szText As String
Dim bRes As Boolean
Static i As Integer
Const WM_NOTIFY = &H4E
'This is where you need to Hook the TreeView
CopyMemory tCWP, ByVal lParam, Len(tCWP)
i = i + 1
If tCWP.message = WM_NOTIFY Then
Form1.Label1.Caption = "WM_NOTIFY " & i
CopyMemory tNMTV, ByVal tCWP.lParam, Len(tNMTV)
If tNMTV.code = TVN_SELCHANGED Then
szText = String(64, vbNullChar)
lpItem = TreeView_GetSelection(tNMTV.hwndFrom)
myItem.hItem = lpItem
myItem.mask = TVIF_TEXT
myItem.pszText = StrPtr(szText)
myItem.cchTextMax = 64
lpMyItem = VarPtr(myItem)
bRes = TreeView_GetItem(tNMTV.hwndFrom, lpMyItem)
szText = StrConv(szText, vbUnicode)
Form1.Text1.Text = left$(szText, InStr(1, szText, vbNullChar) - 1)
End If
End If
HookWindow = CallNextHookEx(TREEVIEW_HOOK, nCode, wParam, ByVal lParam)
If i = 10000 Then i = 1
End Function
Additional form code (form has one text box, one label and two buttons)
Code:
Option Explicit
Public hWndProject As Long
Public hWndIDE As Long
Public hWndTree As Long
'Place these in the General Declarations section of your Form.
Private Const HWND_TOPMOST As Long = -1
Private Const HWND_NOTOPMOST As Long = -2
Private Const SWP_NOSIZE As Long = &H1
Private Const SWP_NOMOVE As Long = &H2
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Sub Form_Load()
'This API call makes your App to be the top-most Window.
Call SetWindowPos(Form1.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE)
End Sub
Private Sub Command2_Click()
Dim GetProcId As Long
Dim TreeViewThreadID As Long
hWndIDE = FindWindowEx(0, 0, "wndclass_desked_gsk", vbNullString)
hWndProject = FindWindowEx(hWndIDE, 0, "PROJECT", vbNullString)
hWndTree = FindWindowEx(hWndProject, 0, "SysTreeView32", vbNullString)
TreeViewThreadID = GetWindowThreadProcessId(hWndTree, GetProcId)
'Monitor All Messages to this Thread.
TREEVIEW_HOOK = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf HookWindow, App.hInstance, TreeViewThreadID)
End Sub
Private Sub Form_Unload(Cancel As Integer)
'Remove the Hook
If TREEVIEW_HOOK Then
Call UnhookWindowsHookEx(TREEVIEW_HOOK)
End If
End Sub
My very first hook (ahhhhhhh!)
[Edited by Judd on 06-23-2000 at 09:11 AM]
Dan
Outside of a dog, a book is a man's best friend.
Inside of a dog, it's too dark to read.
Ok so this is the only place i could find people talking about api used to get info out of a systree. My idea is all i want to do is simply read out all the nodes in a systree. the systreeview32 is part of the Kazaa program. I want to beable to do a search and the read out the results. As I have come to find out the results are displayed in a systreeview32. i have looked all over the net, and on msdn, it seems so simple, only if it were a listbox, but no it had to be a systree. if anyone can help please do.
here is the code so far:
Dim kazaaProcess As Long
Dim ListItemHold As Long
Dim song As String
Dim ListkazaaHold As Long
Dim ReadBytes As Long
'On Error Resume Next
kazaaframe& = FindWindow("KaZaA", vbNullString)
mdiclient& = FindWindowEx(kazaaframe&, 0&, "MDIClient", vbNullString)
kazaasearch& = FindWindowEx(mdiclient&, 0&, "AfxFrameOrView42s", vbNullString)
kazaasearch1& = FindWindowEx(kazaasearch&, 0&, "AfxMDIFrame42s", vbNullString)
For i = 1 To 2
kazaadialog& = FindWindowEx(kazaasearch1&, kazaadialog&, vbNullString, "") '"#32770 (Dialog)",
Next i
kazaastatic& = FindWindowEx(kazaadialog&, 0&, "Static", vbNullString)
kazaahandle = FindWindowEx(kazaastatic&, 0&, "SysTreeView32", vbNullString)
kazaaThread = GetWindowThreadProcessId(kazaahandle, kazaaProcess)
kazaaProcessThread = OpenProcess(PROCESS_VM_READ Or STANDARD_RIGHTS_REQUIRED, False, kazaaProcess)
If kazaaProcessThread Then
For Index = 0 To SendMessage(kazaahandle, TVM_GETCOUNT, 0, 0) - 1
song$ = String$(4, vbNullChar)
ListItemHold = SendMessage(kazaahandle, TVM_GETITEM, ByVal CLng(Index), ByVal 0&)
ListItemHold = ListItemHold + 24
Call ReadProcessMemory(kazaaProcessThread, ListItemHold, song$, 4, ReadBytes)
Call RtlMoveMemory(ListsongHold, ByVal song$, 4)
ListsongHold = ListsongHold + 6
song$ = String$(16, vbNullChar)
Call ReadProcessMemory(kazaaProcessThread, ListsongHold, song$, Len(song$), ReadBytes)
song$ = Left$(song$, InStr(song$, vbNullChar) - 1)
List1.AddItem song$
Next Index
Call CloseHandle(kazaaProcessThread)
End If
End Sub
This set of functions lets you find whether a Treeview node exists, as you can see you usually have to loop through all the nodes and check each one until you find what you're looking for.
Code:
Public Function FindChildNode(pTreeView As TreeView, pParentIndex As Integer, pTextToFind) As Node
Dim i As Integer
Dim iIndex As Integer
With pTreeView
iIndex = .Nodes(pParentIndex).Child.FirstSibling.Index
Do Until iIndex > .Nodes(pParentIndex).Child.LastSibling.Index
If UCase(.Nodes(iIndex).Text) = UCase(pTextToFind) Then
Set FindChildNode = .Nodes(iIndex)
Exit Function
End If
If iIndex <> .Nodes(pParentIndex).Child.LastSibling.Index Then
iIndex = .Nodes(iIndex).Next.Index
Else
iIndex = iIndex + 1
End If
Loop
End With
End Function
Public Function IsChildExist(pTree As TreeView, pParentIndex As Integer) As Boolean
If pTree.Nodes(pParentIndex).Children Then IsChildExist = True
End Function
Public Function SplitPathComponents(ByVal pPath As String, ByVal pSeparator As String) As Variant
Dim arrTemp() As String
Dim strTemp As String
Dim i As Integer
Do Until pPath = ""
If InStr(pPath, pSeparator) > 0 Then
strTemp = Left(pPath, InStr(pPath, pSeparator) - 1)
pPath = Mid(pPath, InStr(pPath, pSeparator) + 1)
ElseIf pPath <> "" Then
strTemp = pPath
pPath = ""
End If
ReDim Preserve arrTemp(i)
arrTemp(i) = Trim(strTemp)
i = i + 1
Loop
SplitPathComponents = arrTemp
End Function
Public Sub FindSpecificNode(pTree As TreeView, pPathToFind As String, pDelimeter As String)
Dim arrComp As Variant
Dim i As Integer
Dim iNode As Integer
Dim xNode As Node
Dim iRootParent As Integer
Dim bLast As Boolean
arrComp = SplitPathComponents(pPathToFind, pDelimeter) 'You can specify any delimeter (separator)
With TreeView1
For iNode = 1 To .Nodes.Count
If UCase(.Nodes(iNode).Text) = UCase(arrComp(0)) And .Nodes(iNode).Parent Is Nothing Then
iRootParent = iNode
.Nodes(iNode).EnsureVisible
.SetFocus
.Nodes(iNode).Selected = True
Exit For
End If
Next
If UBound(arrComp) = 0 Then Exit Sub
'If the root node found
If iRootParent > 0 Then
'Reset the counter
i = 0
bLast = False
Do
If .Nodes(iRootParent).Children Then
i = i + 1
Set xNode = FindChildNode(TreeView1, iRootParent, arrComp(i))
If xNode Is Nothing Then
MsgBox "Path not found"
Exit Sub
Else
iRootParent = xNode.Index
xNode.EnsureVisible
.SetFocus
xNode.Selected = True
If i = UBound(arrComp) Then bLast = True
End If
End If
Loop Until bLast
End If
End With
End Sub
Dan
Outside of a dog, a book is a man's best friend.
Inside of a dog, it's too dark to read.
yeah, i know that how you read thru a treeview, but wha tim looking for is the API to read out every thing in the systreeview32 child of the Kazaa program. unfortunatly i don't have acess to the source code, so i need to use api, i think its a similar idea to Judd
tom