Getting the hWnd of the edit component within a ComboBox control
I'm currently in the process of dusting off the bugs from a tool
written back in 2011. One of the bugs involves an editable
ComboBox
control paired with a separate Button
control. When
the button is clicked a popup menu is shown, and when an item in
this menu is clicked, the text of the ComboBox
is updated.
The problem with this scenario is by default, as soon as the
ComboBox
loses focus, the SelectionStart
, SelectionLength
and SelectedText
properties are reset, thus preventing my
little menu from replacing the selected text. While this article
doesn't solve this problem (I'll save that for the next
article!), it does describe how you can get the hWnd
, or
window handle (in .NET terms the Handle
) of the edit
component, thus opening the door for a little Win32 API fun.
There are various approaches to doing this - you could use
FindWindow
and search for a child window with a class of
edit
, or use SendMessage
with the CB_GETCOMBOBOXINFO
message. Or, easiest of all, we can use the GetComboBoxInfo
function.
Interop Declarations
Using this API is very simple, as there's one method and two simple structs.
[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO
{
public int cbSize;
public RECT rcItem;
public RECT rcButton;
public int stateButton;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
Calling the API
There is one (well, many, but lets start simple!) caveat which
you may fall foul of if you are new to Win32 API programming -
often the contents of structs need to be initialized with their
size first. But how to you know how big a structure is? Lucky
for you, you don't need to calculate it manually - the
Marshal.SizeOf
function will handle this for you.
If you forget to set the size, then the structure simply won't be populated.
NativeMethods.COMBOBOXINFO info;
info = new NativeMethods.COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
if (NativeMethods.GetComboBoxInfo(control.Handle, ref info))
{
// the info structure is now populated, go wild!
}
Getting the edit control handle
With the above in place, then getting the handle of the edit component is very straightforward.
private IntPtr GetEditHandle(ComboBox control)
{
NativeMethods.COMBOBOXINFO info;
info = new NativeMethods.COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
return NativeMethods.GetComboBoxInfo(control.Handle, ref info) ? info.hwndEdit : IntPtr.Zero;
}
Bear in mind that the edit
control is a Win32 control - not a
managed .NET control. In order to do anything with this
therefore, you need to use additional Win32 API methods, or
perhaps bind it to a NativeWindow
class for easy subclassing.
I'll briefly cover some of this in a future article.
Other goodies
The COMBOBOXINFO
structure has other information, such as the
handle of the list
control, which you see if you set the
DropDownStyle
property of the ComboBox
to Simple
and the
state of the dropdown button. You can view the MSDN
Documentation to learn more about the structure.
Update History
- 2013-09-29 - First published
- 2020-11-21 - Updated formatting
Downloads
Filename | Description | Version | Release Date | |
---|---|---|---|---|
GetComboBoxInfoDemo.zip
|
Sample project for the getting the hWnd of the edit component within a ComboBox control blog post. |
1.0.0.0 | 29/09/2013 | Download |
Leave a Comment
While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?