【问题标题】:Retrieve a ComboBox counts and items by using SendMessage API使用 SendMessage API 检索 ComboBox 计数和项目
【发布时间】:2017-07-07 19:11:20
【问题描述】:

我想获得不属于我的ComboBox 控件的计数和列表,因此我无法修改代码。

例如,可以使用SendMessage API 来控制目标应用程序。

但是,我怎样才能通过挂钩来检索目标控件的整个列表?

【问题讨论】:

  • 你可以使用 UI 自动化
  • GetComboBoxInfo 并使用来自COMBOBOXINFOhwndList ?
  • 您已将建议的解决方案交错到问题描述中。请询问您仅尝试解决的问题。这意味着删除所有对 "SendMessage""hooking" 的引用。

标签: .net vb.net winforms winapi combobox


【解决方案1】:

您可以在此处找到ComboBox 控制消息的列表:

要获取项目计数,您需要使用 CB_GETCOUNT 消息,要获取项目的文本,您可以使用 CB_GETLBTEXT 消息。

示例

在这里我创建了一个ComboBoxHelper 类,您可以通过传递ComboBoxHandle 并使用它的属性来创建它的实例:

  • SelectedIndex as Integer:返回选择的索引,如果没有选择项返回 -1。
  • Selectedtext as String:返回所选项目的文本,如果没有选择项目,则返回 String.Empty
  • ItemsCount as Integer:返回项目数。
  • Items(index) as String:返回指定项的文本(指定索引处的项)
  • Items as List(of String):返回组合框的项目列表。如果没有项目,则返回一个空列表。
Public Class ComboBoxHelper
    Private hWnd As IntPtr
    Const CB_GETCURSEL As Integer = &H147
    Const CB_SETCURSEL As Integer = &H14E
    Const CB_GETCOUNT As Integer = &H146
    Const CB_GETLBTEXT As Integer = &H148
    Const CB_GETLBTEXTLEN As Integer = &H149
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, _
        ByVal wParam As Integer, ByRef lParam As Integer) As IntPtr
    End Function
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, _
        ByVal wParam As Integer, ByVal lParam As System.Text.StringBuilder) As IntPtr
    End Function
    Public Sub New(handle As IntPtr)
        hWnd = handle
    End Sub
    Public Property SelectedIndex As Integer
        Get
            Return SendMessage(hWnd, CB_GETCURSEL, 0, 0).ToInt32()
        End Get
        Set(ByVal value As Integer)
            SendMessage(hWnd, CB_SETCURSEL, value, 0).ToInt32()
        End Set
    End Property
    Public ReadOnly Property ItemsCount As Integer
        Get
            Return SendMessage(hWnd, CB_GETCOUNT, 0, 0).ToInt32()
        End Get
    End Property
    Public ReadOnly Property SelectedText As String
        Get
            Dim index = Me.SelectedIndex
            If (Me.SelectedIndex = -1) Then
                Return String.Empty
            End If
            Return Me.Items(index)
        End Get
    End Property
    Public ReadOnly Property Items() As List(Of String)
        Get
            If (ItemsCount > 0) Then
                Return Enumerable.Range(0, ItemsCount) _
                                 .Select(Function(index) Items(index)).ToList()
            Else
                Return New List(Of String)
            End If
        End Get
    End Property
    Public ReadOnly Property Items(index As Integer) As String
        Get
            If (index < 0 OrElse index >= ItemsCount) Then
                Throw New ArgumentOutOfRangeException("index")
            End If
            Dim length = SendMessage(hWnd, CB_GETLBTEXTLEN, index, 0).ToInt32()
            Dim text As New System.Text.StringBuilder(length)
            SendMessage(hWnd, CB_GETLBTEXT, index, text)
            Return text.ToString()
        End Get
    End Property
End Class

以下是该类的使用示例:

Dim combo As New ComboBoxHelper(hWnd) 'You have hWnd
MessageBox.Show(combo.ItemsCount.ToString())
MessageBox.Show(combo.SelectedIndex.ToString())
MessageBox.Show(combo.SelectedText.ToString())
combo.Items.ForEach(Function(item) MessageBox.Show(item))

【讨论】:

  • 您不能跨进程边界发送CB_GETLBTEXT(或任何窗口类私人消息)。抱歉,不是解决方案。 -1.
  • @IInspectable 不要急于否决答案。首先测试它们。我使用两个不同的过程对其进行了测试,它可以正常工作:)
  • @IInspectable 您可以使用 2 个不同的应用程序简单地对其进行测试,一个包含组合框,另一个使用我的 ComboBoxHelper 获取项目文本和计数。测试后,如果您喜欢答案,请投赞成票。我将在答案中保存一个虚拟更改,以便您更改投票;)
  • 啊,原来如此。 CB_GETLBTEXT 确实是标准的 Windows 消息(不是 WM_USER 消息)。无论如何,仍然是一个糟糕的解决方案。改为使用 UI 自动化,以便能够读取不受本机窗口支持的组合框的内容。
  • @IInspectable 如果您有宝贵的知识可以分享,分享就足够了,您无需证明您知道什么或其他人不知道什么。无论如何,您的评论可能对未来的读者有用:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多