I want to send message about mouse double click to selected item in treeview in other application with winapi.
ps In spy++ i get handle only for treeview.
Thank you!
This is best handled using UI Automation , which exposes access to UI elements, like TreeView controls and TreeView items , using COM interfaces:
create an instance of the CUIAutomation
COM object via CoCreateInstance()
and get its IUIAutomation
interface.
call its ElementFromHandle()
method to retrieve an IUIAutomationElement
interface for the TreeView window.
call its FindFirst()
method to find the first selected item and get its IUIAutomationElement
interface.
call its GetCurrentPattern()
method to get an IUnknown
interface for the Invoke
control pattern.
query it for the IUIAutomationInvokePattern
interface, and then call its Invoke()
method
But, if you want to stick with just window messages, you can do the following:
get the selected item using the TVM_GETNEXTITEM
message, specifying TVGN_CARET
for the wParam
.
get the rectangle of the item's text within the TreeView's client area using the TVM_GETITEMRECT
message, specifying TRUE for its wParam
.
However, this requires manually marshaling a RECT
across process boundaries, as the RECT
must exist in the same process that owns the TreeView.
use GetWindowThreadProcessId()
to get the ID of the process that owns the TreeView
use OpenProcess()
to get a HANDLE
to the process ID, requesting PROCESS_VM_OPERATION
and PROCESS_VM_READ
access
use VirtualAllocEx()
to allocate a RECT
in the process
pass that allocated pointer in the lParam
of TVM_GETITEMRECT
use ReadProcessMemory()
to read the RECT
data
free the memory with VirtualFreeEx()
close the process handle with CloseHandle()
.
send a WM_LBUTTONDBLCLK
message to the TreeView window, specifying X,Y coordinates that are within the item text's rectangle.
I Know this is old, but I tried many ways to make it work in VB.net. I need to create 2 different structures for RECT because it was returning wrong values for the RECT position with Long parameters. Here is the example, you can easily convert to C#
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim SelNodeRectangle As RECT = GetTreeViewSelectedNodeRECT(TreeViewPtr)
End Sub
Private Const TV_FIRST As Integer = &H1100
Private Const TVGN_CARET As Integer = &H9
Private Const TVM_GETNEXTITEM As Integer = (TV_FIRST + 10)
Private Const TVM_GETITEMRECT As Integer = (TV_FIRST + 4)
Private Const PROCESS_VM_OPERATION As Integer = &H8
Private Const PROCESS_VM_READ As Integer = &H10
Private Const PROCESS_VM_WRITE = (&H20)
Private Const PAGE_READWRITE As Long = &H4
Private Const MEM_COMMIT As Long = &H1000&
Private Const MEM_RELEASE As Long = &H8000&
Private Structure RECTPointer
Public Left As IntPtr
End Structure
Private Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
<Flags>
Public Enum AllocationType
Commit = &H1000
Reserve = &H2000
Decommit = &H4000
Release = &H8000
Reset = &H80000
Physical = &H400000
TopDown = &H100000
WriteWatch = &H200000
LargePages = &H20000000
End Enum
Private Declare Function SendMessageA Lib "user32" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Long) As IntPtr
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByRef buffer As RECTPointer, ByVal dwSize As Integer, ByVal lpNumberOfBytesWritten As IntPtr) As Boolean
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As IntPtr, ByRef lpdwProcessID As Integer) As Integer
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Boolean, ByVal dwProcessId As UInteger) As IntPtr
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UInteger, ByVal flAllocationType As UInteger, ByVal flProtect As UInteger) As IntPtr
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Long, ByVal lpBuffer As Long, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As IntPtr,
ByVal lpAddress As IntPtr,
ByVal dwSize As Integer,
ByVal dwFreeType As AllocationType) As Boolean
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As IntPtr) As <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> Boolean
Private Function GetTreeViewSelectedNodeRECT(TreeViewPTR As IntPtr) As RECT
Const dwBufferSize As Integer = 1024
Dim dwProcessID As Integer
Dim processHandle As IntPtr = IntPtr.Zero
Dim remotePointerBuffer As IntPtr = IntPtr.Zero
Dim localPointerBuffer As IntPtr = IntPtr.Zero
Dim threadId As IntPtr = IntPtr.Zero
localPointerBuffer = Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize)
threadId = GetWindowThreadProcessId(TreeViewPTR, dwProcessID)
processHandle = OpenProcess(PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, dwProcessID)
remotePointerBuffer = VirtualAllocEx(processHandle, IntPtr.Zero, dwBufferSize, MEM_COMMIT, PAGE_READWRITE)
Dim bSuccess As Boolean
Dim tvItem As New RECTPointer()
Dim SelectedNodePTR As IntPtr = SendMessageA(TreeViewPTR, TVM_GETNEXTITEM, TVGN_CARET, 0)
tvItem.Left = SelectedNodePTR
bSuccess = WriteProcessMemory(processHandle, remotePointerBuffer, tvItem, Runtime.InteropServices.Marshal.SizeOf(GetType(RECTPointer)), IntPtr.Zero)
If Not bSuccess Then
Throw New SystemException("Fail writing to process memory!")
End If
SendMessageA(TreeViewPTR, TVM_GETITEMRECT, 0, remotePointerBuffer)
bSuccess = ReadProcessMemory(processHandle, remotePointerBuffer, localPointerBuffer, dwBufferSize, IntPtr.Zero)
If Not bSuccess Then
Throw New SystemException("Fail reading from process memory!")
End If
Dim returnRECT As RECT = Runtime.InteropServices.Marshal.PtrToStructure(localPointerBuffer, GetType(RECT))
If localPointerBuffer <> IntPtr.Zero Then
Runtime.InteropServices.Marshal.FreeHGlobal(localPointerBuffer)
End If
If remotePointerBuffer <> IntPtr.Zero Then
VirtualFreeEx(processHandle, remotePointerBuffer, 0, MEM_RELEASE)
End If
If processHandle <> IntPtr.Zero Then
CloseHandle(processHandle)
End If
Return returnRECT
End Function
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.