【问题标题】:Double click in selected item in treeview win32 api双击treeview win32 api中的选定项目
【发布时间】:2018-04-06 14:09:46
【问题描述】:

我想用 winapi 向其他应用程序的树视图中的选定项目发送有关鼠标双击的消息。

  • 如何在其他应用程序中获取treeview中选中项的句柄?

附注在 spy++ 中,我只获得树视图的句柄。

谢谢!

【问题讨论】:

  • 停止伪造输入。开始习惯UI Automation。到达那里后,您将看到可以访问树视图控件中的各个项目(假设目标控件实现了 UI 自动化接口)。
  • 你在说什么歇斯底里???如果您不知道,如何在树视图中处理选定的项目,然后通过。谢谢你的时间。
  • Treeview 项目没有与之关联的窗口句柄。
  • 感谢您的回答。老实说,我第一次听说 UI 自动化。
  • @IInspectable 一个标准的 Win32 TreeView 实现了对 UI 自动化的支持

标签: c# winapi treeview selecteditem selected


【解决方案1】:

最好使用UI Automation 处理此问题,它使用 COM 接口公开对 UI 元素的访问,例如 TreeView controls 和 TreeView items:

  • 通过CoCreateInstance() 创建CUIAutomation COM 对象的实例并获取其IUIAutomation 接口。

  • 调用其ElementFromHandle() 方法来检索TreeView 窗口的IUIAutomationElement 接口。

  • 调用它的FindFirst()方法找到第一个被选中的项目,得到它的IUIAutomationElement接口。

  • 调用其GetCurrentPattern() 方法来获取Invoke 控制模式的IUnknown 接口。

  • 查询IUIAutomationInvokePattern接口,然后调用其Invoke()方法

但是,如果您只想坚持使用窗口消息,则可以执行以下操作:

  • 使用TVM_GETNEXTITEM 消息获取所选项目,为wParam 指定TVGN_CARET。

  • 使用TVM_GETITEMRECT 消息在TreeView 的客户区内获取项目文本的矩形,并为其wParam 指定TRUE。

    但是,这需要跨进程边界手动封送 RECT,因为 RECT 必须存在于拥有 TreeView 的同一进程中。

    • 使用GetWindowThreadProcessId()获取拥有TreeView的进程ID

    • 使用OpenProcess() 获取进程ID 的HANDLE,请求PROCESS_VM_OPERATION 和PROCESS_VM_READ 访问

    • 在进程中使用VirtualAllocEx()分配一个RECT

    • 在TVM_GETITEMRECT 的lParam 中传递分配的指针

    • 使用ReadProcessMemory()读取RECT数据

    • 使用VirtualFreeEx()释放内存

    • 用CloseHandle()关闭进程句柄。

  • 向 TreeView 窗口发送 WM_LBUTTONDBLCLK 消息,指定项目文本矩形内的 X、Y 坐标。

【讨论】:

  • 阅读了 UI 自动化,但我不明白如何使用它。也许你有关于它的样本或文章。那会很好。谢谢。
  • UI 自动化是不合适的,因为窗口应该是可见的并且鼠标光标会跳动(如果你按下按钮),当光标消失并且必须搜索时这不是很愉快。我需要防止最终用户看到它。但第二种选择更合适。我会尽力。感谢您的建议!
  • 附注与 TestStackWhite 合作,链接:teststackwhite.readthedocs.io/en/latest
  • @IichiKohuro:UI 自动化确实不要求目标应用程序可见,也不实际移动鼠标。
  • @IInspectable 我已经测试了 teststack.white,我认为这是基于 UI 自动化。那么,有没有人有 C# 示例。在互联网上,我没有找到可以理解的示例。
【解决方案2】:

我知道这是旧的,但我尝试了很多方法让它在 VB.net 中工作。我需要为 RECT 创建 2 个不同的结构,因为它使用 Long 参数为 RECT 位置返回错误的值。 这是示例,您可以轻松转换为 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-24
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多