Virtual Developer Workshop: Containerized Development with Docker
When searching for strings in Combo boxes, the search is always case-insensitive. I have a need for a case-sensitive combo box in an application, so I have put together this class to implement that.
How to use it
Using the CComboBoxCS class is very straightforward. Follow the steps below to add one to an existing project.
- After putting the source files (ComboBoxCS.cpp and ComboBoxCS.h) into the directory you wish to use them from, add the files to your Visual Studio project.
- In the resource editor, add a combo where you wish.
- In Class Wizard add a member variable for your combo control, selecting "Control" from the "Category" list, and selecting "CComboBoxCS" from the "Variable Type" list. (If CComboBoxCS does not appear in the list, you may need to delete your class wizard file (.clw) and regenerate it). I will assume your control variable name is m_combo.
- In order to make the combo case-sensitive, add a handler for WM_INITDIALOG
in your dialog class if you don't already have one, and add the following code
That's all you need to do.
If you use many Combo boxes which you wish to make them all case-sensitive, you can set the default for all instances by adding:
or alternatively, if you always want this behaviour, you can change the default value in the source code: /*static*/ BOOL CListBoxCS::ms_bCaseSensitiveSearchDefault = TRUE;
How it works
The list box part of CComboBoxCS is subclassed to a CListBoxCS, which provides the case-sensitivity. (Note that the CListBoxCS class can be used in place of a CListBox should you require a case-sensitive list box). In order to subclass the list box, there are one or two methods available. One method ('the messy method') is to handle the WM_CTLCOLOR message. This is a standard (and well-documented) method. The other method ('the clean method') is to use the API function GetComboBoxInfo to ask the combobox for its list control. The drawback with the clean method is that it is only available on Win98, or WinNT 4.0 SP6, or later. The code uses LoadLibrary/GetProcAddress to determine whether the function is available. If it is it uses it, else it falls back to the messy method.
One problem with the messy method, is that the list box doesn't get subclassed until the user drops the list portion of the combo down. This is not good enough here, as we need the list to have been subclassed at the time we do a FindString or FindStringExact. So, we have to cheat.
On receipt of a FindString, FindStringExact, or SelectString message, we look to see whether we need to subclass the list. We need to if we are case-sensitive, and the list has not yet been subclassed. If we don't need to, then we simply pass the message on to the standard combobox Windows procedure.
Assuming we do need to subclass, we then call the function to drop the list portion of the combo. This forces the list to be (re)painted, which causes the required WM_CTLCOLOR to be sent to the combobox.
A problem with this is that we get the list box flicking up, and then closing again. To stop the list flickering, we can't just turn off redraw for the combo, as that doesn't affect the list, nor can we turn if off for the list, as we don't have it yet. The code I have used shrinks the combo so its list box is zero pixels high, and then drops it down. It is then resized to where it came from. This can all be done while the combo has redrawing turned off.
Using the clean method we don't have any of these problems, and can simply ask the combobox for a handle to the list box, which we then subclass. This is done at the earliest time it can be, which will be either as the user types in the edit control, as the list is dropped, or when the combobox receives a FindString/FindStringExact/SelectString message.
Version 2 - 10 Jun 2002
- new (clean) method of subclassing - uses API function GetComboBoxInfo() if available, else falls back to 'messy' method
- added handling of CB_SELECTSTRING message
- minor changes to the searching code