using System; using System.Runtime.InteropServices; using static Vanara.PInvoke.User32_Gdi; // ReSharper disable InconsistentNaming ReSharper disable FieldCanBeMadeReadOnly.Global namespace Vanara.PInvoke { public static partial class ComCtl32 { public const int CBEN_FIRST = -800; public const int CBM_FIRST = 0x1700; public const string WC_COMBOBOXEX = "ComboBoxEx32"; /// A value that specifies the action that generated the CBEN_ENDEDIT notification code. [PInvokeData("Commctrl.h", MSDNShortId = "bb775750")] public enum CBEN_ENDEDIT_FLAG { /// The edit box lost the keyboard focus. CBENF_KILLFOCUS = 1, /// The user completed the edit operation by pressing ENTER. CBENF_RETURN = 2, /// The user pressed ESC. CBENF_ESCAPE = 3, /// The user activated the drop-down list. CBENF_DROPDOWN = 4, } /// /// A set of bit flags that specify attributes of COMBOBOXEXITEM or of an operation that is using this structure. The flags specify members that are /// valid or must be filled in. /// [PInvokeData("Commctrl.h", MSDNShortId = "bb775746")] [Flags] public enum ComboBoxExItemMask { /// The pszText member is valid or must be filled in. CBEIF_TEXT = 0x00000001, /// The iImage member is valid or must be filled in. CBEIF_IMAGE = 0x00000002, /// The iSelectedImage member is valid or must be filled in. CBEIF_SELECTEDIMAGE = 0x00000004, /// The iOverlay member is valid or must be filled in. CBEIF_OVERLAY = 0x00000008, /// The iIndent member is valid or must be filled in. CBEIF_INDENT = 0x00000010, /// The lParam member is valid or must be filled in. CBEIF_LPARAM = 0x00000020, /// /// Set this flag when processing CBEN_GETDISPINFO; the ComboBoxEx control will retain the supplied information and will not request it again. /// CBEIF_DI_SETITEM = 0x10000000, } /// Support the extended styles that are listed in this section as well as most standard combo box control styles. [PInvokeData("Commctrl.h", MSDNShortId = "bb775742")] public enum ComboBoxExStyle { /// The edit box and the dropdown list will not display item images. CBES_EX_NOEDITIMAGE = 0x00000001, /// The edit box and the dropdown list will not display item images. CBES_EX_NOEDITIMAGEINDENT = 0x00000002, /// /// Windows NT only. The edit box will use the slash (/), backslash (\), and period (.) characters as word delimiters. This makes keyboard shortcuts /// for word-by-word cursor movement effective in path names and URLs. /// CBES_EX_PATHWORDBREAKPROC = 0x00000004, /// /// Allows the ComboBoxEx control to be vertically sized smaller than its contained combo box control. If the ComboBoxEx is sized smaller than the /// combo box, the combo box will be clipped. /// CBES_EX_NOSIZELIMIT = 0x00000008, /// /// BSTR searches in the list will be case sensitive. This includes searches as a result of text being typed in the edit box and the /// CB_FINDSTRINGEXACT message. /// CBES_EX_CASESENSITIVE = 0x00000010, /// /// Windows Vista and later. Causes items in the drop-down list and the edit box (when the edit box is read only) to be truncated with an ellipsis /// ("...") rather than just clipped by the edge of the control. This is useful when the control needs to be set to a fixed width, yet the entries in /// the list may be long. /// CBES_EX_TEXTENDELLIPSIS = 0x00000020, } /// Contains combo box status information. [PInvokeData("Winuser.h", MSDNShortId = "bb775798")] [Flags] public enum ComboBoxInfoState { /// The button exists and is not pressed. None = 0, /// There is no button. STATE_SYSTEM_INVISIBLE = 0x00008000, /// The button is pressed. STATE_SYSTEM_PRESSED = 0x00000008 } public enum ComboBoxMessage { CB_GETEDITSEL = 0x0140, CB_LIMITTEXT = 0x0141, CB_SETEDITSEL = 0x0142, CB_ADDSTRING = 0x0143, CB_DELETESTRING = 0x0144, CB_DIR = 0x0145, CB_GETCOUNT = 0x0146, CB_GETCURSEL = 0x0147, CB_GETLBTEXT = 0x0148, CB_GETLBTEXTLEN = 0x0149, CB_INSERTSTRING = 0x014A, CB_RESETCONTENT = 0x014B, CB_FINDSTRING = 0x014C, CB_SELECTSTRING = 0x014D, CB_SETCURSEL = 0x014E, CB_SHOWDROPDOWN = 0x014F, CB_GETITEMDATA = 0x0150, CB_SETITEMDATA = 0x0151, CB_GETDROPPEDCONTROLRECT = 0x0152, CB_SETITEMHEIGHT = 0x0153, CB_GETITEMHEIGHT = 0x0154, CB_SETEXTENDEDUI = 0x0155, CB_GETEXTENDEDUI = 0x0156, CB_GETDROPPEDSTATE = 0x0157, CB_FINDSTRINGEXACT = 0x0158, CB_SETLOCALE = 0x0159, CB_GETLOCALE = 0x015A, CB_GETTOPINDEX = 0x015b, CB_SETTOPINDEX = 0x015c, CB_GETHORIZONTALEXTENT = 0x015d, CB_SETHORIZONTALEXTENT = 0x015e, CB_GETDROPPEDWIDTH = 0x015f, CB_SETDROPPEDWIDTH = 0x0160, CB_INITSTORAGE = 0x0161, CB_MULTIPLEADDSTRING = 0x0163, CB_GETCOMBOBOXINFO = 0x0164, CB_SETMINVISIBLE = CBM_FIRST + 1, CB_GETMINVISIBLE = CBM_FIRST + 2, CB_SETCUEBANNER = CBM_FIRST + 3, CB_GETCUEBANNER = CBM_FIRST + 4, CBEM_SETIMAGELIST = WindowMessage.WM_USER + 2, CBEM_GETIMAGELIST = WindowMessage.WM_USER + 3, CBEM_DELETEITEM = ComboBoxMessage.CB_DELETESTRING, CBEM_GETCOMBOCONTROL = WindowMessage.WM_USER + 6, CBEM_GETEDITCONTROL = WindowMessage.WM_USER + 7, CBEM_SETEXSTYLE = WindowMessage.WM_USER + 8, // use SETEXTENDEDSTYLE instead CBEM_SETEXTENDEDSTYLE = WindowMessage.WM_USER + 14, // lparam == new style, wParam (optional) == mask CBEM_GETEXSTYLE = WindowMessage.WM_USER + 9, // use GETEXTENDEDSTYLE instead CBEM_GETEXTENDEDSTYLE = WindowMessage.WM_USER + 9, CBEM_SETUNICODEFORMAT = CommonControlMessage.CCM_SETUNICODEFORMAT, CBEM_GETUNICODEFORMAT = CommonControlMessage.CCM_GETUNICODEFORMAT, CBEM_HASEDITCHANGED = WindowMessage.WM_USER + 10, CBEM_INSERTITEM = WindowMessage.WM_USER + 11, CBEM_SETITEM = WindowMessage.WM_USER + 12, CBEM_GETITEM = WindowMessage.WM_USER + 13, CBEM_SETWINDOWTHEME = CommonControlMessage.CCM_SETWINDOWTHEME, } /// Combo Box Notification Codes [PInvokeData("Winuser.h", MSDNShortId = "ff485902")] public enum ComboBoxNotification { /// /// Sent when a combo box cannot allocate enough memory to meet a specific request. The parent window of the combo box receives this notification /// code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_ERRSPACE = (-1), /// /// Sent when the user changes the current selection in the list box of a combo box. The user can change the selection by clicking in the list box or /// by using the arrow keys. The parent window of the combo box receives this notification code in the form of a WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_SELCHANGE = 1, /// /// Sent when the user double-clicks a string in the list box of a combo box. The parent window of the combo box receives this notification code /// through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_DBLCLK = 2, /// /// Sent when a combo box receives the keyboard focus. The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_SETFOCUS = 3, /// /// Sent when a combo box loses the keyboard focus. The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_KILLFOCUS = 4, /// /// Sent after the user has taken an action that may have altered the text in the edit control portion of a combo box. Unlike the CBN_EDITUPDATE /// notification code, this notification code is sent after the system updates the screen. The parent window of the combo box receives this /// notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_EDITCHANGE = 5, /// /// Sent when the edit control portion of a combo box is about to display altered text. This notification code is sent after the control has /// formatted the text, but before it displays the text. The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_EDITUPDATE = 6, /// /// Sent when the list box of a combo box is about to be made visible. The parent window of the combo box receives this notification code through the /// WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_DROPDOWN = 7, /// /// Sent when the list box of a combo box has been closed. The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_CLOSEUP = 8, /// /// Sent when the user selects a list item, or selects an item and then closes the list. It indicates that the user's selection is to be processed. /// The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_SELENDOK = 9, /// /// Sent when the user selects an item, but then selects another control or closes the dialog box. It indicates the user's initial selection is to be /// ignored. The parent window of the combo box receives this notification code through the WM_COMMAND message. /// /// /// wParam /// The LOWORD contains the control identifier of the combo box. The HIWORD specifies the notification code. /// /// /// lParam /// Handle to the combo box. /// /// /// CBN_SELENDCANCEL = 10, /// /// Sent when a new item has been inserted in the control. This notification code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// /// A pointer to an structure containing information about the notification code and the item that was inserted. /// /// /// /// CBEN_INSERTITEM = CBEN_FIRST - 1, /// /// Sent when an item has been deleted. This notification code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// /// A pointer to an structure that contains information about the notification code and the deleted item. /// /// /// /// CBEN_DELETEITEM = CBEN_FIRST - 2, /// /// Sent when the user activates the drop-down list or clicks in the control's edit box. This notification code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// A pointer to an structure that contains information about the notification code. /// /// /// CBEN_BEGINEDIT = CBEN_FIRST - 4, /// /// Sent when the user has concluded an operation within the edit box or has selected an item from the control's drop-down list. This notification /// code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// A pointer to an structure that contains information about how the user concluded the edit operation. /// /// /// CBEN_ENDEDITA = CBEN_FIRST - 5, /// /// Sent when the user has concluded an operation within the edit box or has selected an item from the control's drop-down list. This notification /// code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// A pointer to an structure that contains information about how the user concluded the edit operation. /// /// /// CBEN_ENDEDITW = CBEN_FIRST - 6, /// /// Sent to retrieve display information about a callback item. This notification code is sent in the form of a WM_NOTIFY message. /// /// /// lParam /// A pointer to an structure that contains information about the notification code. /// /// /// CBEN_GETDISPINFO = CBEN_FIRST - 7, /// /// Sent when the user begins dragging the image of the item displayed in the edit portion of the control. This notification code is sent in the form /// of a WM_NOTIFY message. /// /// /// lParam /// A pointer to a structure that contains information about the notification code. /// /// /// CBEN_DRAGBEGIN = CBEN_FIRST - 9, } /// /// To create a combo box using the CreateWindow or CreateWindowEx function, specify the COMBOBOX class, appropriate window style constants, and a /// combination of the following combo box styles. /// [PInvokeData("CommCtrl.h", MSDNShortId = "bb775796")] public enum ComboBoxStyle { /// Displays the list box at all times. The current selection in the list box is displayed in the edit control. CBS_SIMPLE = 0x0001, /// Similar to CBS_SIMPLE, except that the list box is not displayed unless the user selects an icon next to the edit control. CBS_DROPDOWN = 0x0002, /// /// Similar to CBS_DROPDOWN, except that the edit control is replaced by a static text item that displays the current selection in the list box. /// CBS_DROPDOWNLIST = 0x0003, /// /// Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are all the same height. The /// owner window receives a WM_MEASUREITEM message when the combo box is created and a WM_DRAWITEM message when a visual aspect of the combo box has changed. /// CBS_OWNERDRAWFIXED = 0x0010, /// /// Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height. The /// owner window receives a WM_MEASUREITEM message for each item in the combo box when you create the combo box and a WM_DRAWITEM message when a /// visual aspect of the combo box has changed. /// CBS_OWNERDRAWVARIABLE = 0x0020, /// /// Automatically scrolls the text in an edit control to the right when the user types a character at the end of the line. If this style is not set, /// only text that fits within the rectangular boundary is allowed. /// CBS_AUTOHSCROLL = 0x0040, /// /// Converts text entered in the combo box edit control from the Windows character set to the OEM character set and then back to the Windows /// character set. This ensures proper character conversion when the application calls the CharToOem function to convert a Windows string in the /// combo box to OEM characters. This style is most useful for combo boxes that contain file names and applies only to combo boxes created with the /// CBS_SIMPLE or CBS_DROPDOWN style. /// CBS_OEMCONVERT = 0x0080, /// Automatically sorts strings added to the list box. CBS_SORT = 0x0100, /// /// Specifies that an owner-drawn combo box contains items consisting of strings. The combo box maintains the memory and address for the strings so /// the application can use the CB_GETLBTEXT message to retrieve the text for a particular item. /// CBS_HASSTRINGS = 0x0200, /// /// Specifies that the size of the combo box is exactly the size specified by the application when it created the combo box. Normally, the system /// sizes a combo box so that it does not display partial items. /// CBS_NOINTEGRALHEIGHT = 0x0400, /// /// Shows a disabled vertical scroll bar in the list box when the box does not contain enough items to scroll. Without this style, the scroll bar is /// hidden when the list box does not contain enough items. /// CBS_DISABLENOSCROLL = 0x0800, /// Converts to uppercase all text in both the selection field and the list. CBS_UPPERCASE = 0x2000, /// Converts to lowercase all text in both the selection field and the list. CBS_LOWERCASE = 0x4000, } /// /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return /// until the window procedure has processed the message. /// /// /// A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to /// all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not /// sent to child windows. /// /// The message to be sent. /// Additional message-specific information. /// Additional message-specific information. /// The return value specifies the result of the message processing; it depends on the message sent. public static IntPtr SendMessage(HandleRef hWnd, ComboBoxMessage Msg, int wParam, ref COMBOBOXINFO item) => User32_Gdi.SendMessage(hWnd, Msg, wParam, ref item); /// Contains combo box status information. [PInvokeData("Winuser.h", MSDNShortId = "bb775798")] [StructLayout(LayoutKind.Sequential)] public struct COMBOBOXINFO { /// The size, in bytes, of the structure. The calling application must set this to sizeof(COMBOBOXINFO). public int cbSize; /// A RECT structure that specifies the coordinates of the edit box. public RECT rcItem; /// A RECT structure that specifies the coordinates of the button that contains the drop-down arrow. public RECT rcButton; /// The combo box button state. public ComboBoxInfoState buttonState; /// A handle to the combo box. public IntPtr hwndCombo; /// A handle to the edit box. public IntPtr hwndEdit; /// A handle to the drop-down list. public IntPtr hwndList; /// Creates an instance of the structure from a handle and retrieves its values. /// The handle to a ComboBox. /// A structure with values from the supplied handle. [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static COMBOBOXINFO FromHandle(HandleRef hComboBox) { if (hComboBox.Handle == IntPtr.Zero) throw new ArgumentException("ComboBox handle cannot be NULL.", nameof(hComboBox)); var cbi = new COMBOBOXINFO() { cbSize = Marshal.SizeOf(typeof(COMBOBOXINFO)) }; SendMessage(hComboBox, ComboBoxMessage.CB_GETCOMBOBOXINFO, 0, ref cbi); return cbi; } /// Gets a value indicating whether this is invisible. /// true if invisible; otherwise, false. public bool Invisible => (buttonState & ComboBoxInfoState.STATE_SYSTEM_INVISIBLE) == ComboBoxInfoState.STATE_SYSTEM_INVISIBLE; /// Gets a value indicating whether this is pressed. /// true if pressed; otherwise, false. public bool Pressed => (buttonState & ComboBoxInfoState.STATE_SYSTEM_PRESSED) == ComboBoxInfoState.STATE_SYSTEM_PRESSED; /// Gets the item rectangle. /// The item rectangle. public System.Drawing.Rectangle ItemRectangle => rcItem; /// Gets the button rectangle. /// The button rectangle. public System.Drawing.Rectangle ButtonRectangle => rcButton; } /// Contains information used with the CBEN_DRAGBEGIN notification code. [PInvokeData("Commctrl.h", MSDNShortId = "bb775748")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct NMCBEDRAGBEGIN { /// The NMHDR structure that contains information about the notification code. public NMHDR hdr; /// /// The zero-based index of the item being dragged. This value will always be -1, indicating that the item being dragged is the item displayed in the /// edit portion of the control. /// public int iItemId; /// The character buffer that contains the text of the item being dragged. public string szText; } /// /// Contains information about the conclusion of an edit operation within a ComboBoxEx control. This structure is used with the CBEN_ENDEDIT notification code. /// [PInvokeData("Commctrl.h", MSDNShortId = "bb775750")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct NMCBEENDEDIT { /// The NMHDR structure that contains information about the notification code. public NMHDR hdr; /// /// A value indicating whether the contents of the control's edit box have changed. This value is nonzero if the contents have been modified, or zero otherwise. /// [MarshalAs(UnmanagedType.Bool)] public bool fChanged; /// /// The zero-based index of the item that will be selected after completing the edit operation. This value can be CB_ERR if no item will be selected. /// public int iNewSelection; /// A zero-terminated string that contains the text from within the control's edit box. public string szText; /// A value that specifies the action that generated the CBEN_ENDEDIT notification code. public CBEN_ENDEDIT_FLAG iWhy; } /// Contains information specific to ComboBoxEx items for use with notification codes. [PInvokeData("Commctrl.h", MSDNShortId = "bb775752")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct NMCOMBOBOXEX { /// The NMHDR structure that contains information about the notification code. public NMHDR hdr; /// /// The COMBOBOXEXITEM structure that holds item information specific to the current notification. Upon receiving a notification code, the /// COMBOBOXEXITEM structure holds information required for the owner to respond. The members of this structure are often used as fields for the /// owner to return values in response to the notification. /// public COMBOBOXEXITEM ceItem; } /// Contains information about an item in a ComboBoxEx control. /// [PInvokeData("Commctrl.h", MSDNShortId = "bb775746")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public sealed class COMBOBOXEXITEM : IDisposable { /// /// A set of bit flags that specify attributes of this structure or of an operation that is using this structure. The flags specify members that are /// valid or must be filled in. /// public ComboBoxExItemMask mask; /// The zero-based index of the item. [MarshalAs(UnmanagedType.SysInt)] public int iItem; /// /// A pointer to a character buffer that contains or receives the item's text. If text information is being retrieved, this member must be set to the /// address of a character buffer that will receive the text. The size of this buffer must also be indicated in cchTextMax. If this member is set to /// LPSTR_TEXTCALLBACK, the control will request the information by using the CBEN_GETDISPINFO notification codes. /// public IntPtr pszText; /// The length of pszText, in TCHARs. If text information is being set, this member is ignored. public int cchTextMax; /// /// The zero-based index of an image within the image list. The specified image will be displayed for the item when it is not selected. If this /// member is set to I_IMAGECALLBACK, the control will request the information by using CBEN_GETDISPINFO notification codes. /// public int iImage; /// /// The zero-based index of an image within the image list. The specified image will be displayed for the item when it is selected. If this member is /// set to I_IMAGECALLBACK, the control will request the information by using CBEN_GETDISPINFO notification codes. /// public int iSelectedImage; /// /// The one-based index of an overlay image within the image list. If this member is set to I_IMAGECALLBACK, the control will request the information /// by using CBEN_GETDISPINFO notification codes. /// public int iOverlay; /// /// The number of indent spaces to display for the item. Each indentation equals 10 pixels. If this member is set to I_INDENTCALLBACK, the control /// will request the information by using CBEN_GETDISPINFO notification codes. /// public int iIndent; /// A value specific to the item. public IntPtr lParam; /// Initializes a new instance of the class. /// Size of the text buffer. If this value is 0, no buffer is created. public COMBOBOXEXITEM(int textBufferSize = 0) : this(textBufferSize == 0 ? null : new string('\0', textBufferSize)) { } /// Initializes a new instance of the class. /// The text. public COMBOBOXEXITEM(string text) { Text = text; } /// Gets or sets the item's text. /// The text value. public string Text { get => pszText == LPSTR_TEXTCALLBACK ? null : Marshal.PtrToStringAuto(pszText); set { ((IDisposable)this).Dispose(); if (value == null) return; pszText = Marshal.StringToCoTaskMemAuto(value); cchTextMax = value.Length; mask |= ComboBoxExItemMask.CBEIF_TEXT; } } /// Gets or sets a value indicating whether to use a text callback method. /// true if using text callback method; otherwise, false. public bool UseTextCallback { get => pszText == LPSTR_TEXTCALLBACK; set { if (value) { ((IDisposable)this).Dispose(); pszText = LPSTR_TEXTCALLBACK; } mask |= ComboBoxExItemMask.CBEIF_TEXT; } } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. void IDisposable.Dispose() { if (pszText != IntPtr.Zero && pszText != LPSTR_TEXTCALLBACK) { Marshal.FreeCoTaskMem(pszText); pszText = IntPtr.Zero; cchTextMax = 0; } } } } }