Search code examples
.netvb.netwinformswinapicombobox

Retrieve a ComboBox counts and items by using SendMessage API


I want to get a count and list of ComboBox control which is not mine so that I cannot modify the code.

For example, controlling the target app can be done by using SendMessage API.

But, how can I retrieve a whole list of the target control by hooking?


Solution

  • You can find a list of ComboBox control messages here:

    To get items count you need to use CB_GETCOUNT message and to get text of an item you can use CB_GETLBTEXT message.

    Example

    Here I created a ComboBoxHelper class which you can create its instance by passing Handle of the ComboBox and use its properties:

    • SelectedIndex as Integer: Returns selected index, returns -1 if no item is selected.
    • Selectedtext as String: Returns text of selected item, returns String.Empty if no item is selected.
    • ItemsCount as Integer: returns count of items.
    • Items(index) as String: returns text of specified item (the item at specified index)
    • Items as List(of String): returns the list of items of combo box. If there is no items, it returns an empty list.
    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
    

    Here is an example of usage of the 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))