I primarily come from a .NET background, but there is one small task that I have to accomplish for a Windows Control, specifically a ComboBox.
I understand that the CBS_SORT message is needed for the ComboBox to sort items alphabetically. This works just fine for me when I add strings to the combobox using the CB_ADDSTRING flag.
I'm trying to make the ComboBox use a reverse (or other custom) sorting order.
If I use CreateWindow
to make my combobox, is there a way I can take the HWND it returns and hook up a custom method that processes the WM_COMPAREITEM message?
This is the article from Microsoft that talked about processing the WM_COMPAREITEM message. https://msdn.microsoft.com/en-us/library/windows/desktop/bb775791(v=vs.85).aspx
Edit: I suppose one workaround is to use the CB_INSERTSTRING flag for custom sorting, but I'd really prefer to implement something similar to a CompareTo in other languages if I can.
Edit: It's worth mentioning that class which calls CreateWindow (w/o using the CBS_HASSTRINGS flag) has a message handler for the WM_COMMAND message. It switches in the HIWORD to handle notifications like CBN_SELCHANGE.
I looked at the documentation for Combo box and noticed a slight difference between CBN_SELCHANGE and WM_COMPAREITEM.
The CBN_SELCHANGE notification code is 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 in the form of a WM_COMMAND message with CBN_SELCHANGE in the high-order word of the wParam parameter.
And here's what it says about WM_COMPAREITEM
The system sends the WM_COMPAREITEM message to determine the relative position of a new item in the sorted list of an owner-drawn combo box or list box. Whenever the application adds a new item, the system sends this message to the owner of a combo box or list box created with the CBS_SORT or LBS_SORT style.
As far as I can tell, the DWORD Style that is passed into the CreateWindow method is WS_VISIBLE | WS_CHILD | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | CBS_SORT
Perhaps the problem is that the combobox that is created is not an "owner-drawn" combobox? If that is the case, I would need to find a way to do that, but only handle the WM_COMPAREITEM case and not any other custom painting code.
Update I've created the ComboBox without the CBS_HASSTRINGS and with the CB_OWNERDRAWFIXED (Which then lets me process the WM_COMPAREITEM message).
Here's the message handling code
LRESULT MyComboBoxParent::OnCompareItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
//umsg is always wm_compareitem
COMPAREITEMSTRUCT* pCompareItemStruct = (COMPAREITEMSTRUCT*)lParam;
ATLASSERT(pCompareItemStruct->CtlType == ODT_COMBOBOX); //this assert works
int iItemId1 = pCompareItemStruct->itemID1;
int iItemId2 = pCompareItemStruct->itemID2;
LPCTSTR item1 = (LPCTSTR)pCompareItemStruct ->itemData1;
ATLASSERT(item1 != NULL);
LPCTSTR item2 = (LPCTSTR)pCompareItemStruct->itemData2;
ATLASSERT(item2 != NULL);
int iStringCompareResult = _tcscmp(item1, item2);
//should reverse the sorting order
int iReturn = -1 * iStringCompareResult;
return iReturn;
}
//and the existing code snippet that adds the values to the combobox
::SendMessage(m_hwndCombo,CB_ADDSTRING,0,(LPARAM) ((wchar_t*)bstr_tDisplayedValue))
The data coming in from the COMPAREITEMSTRUCT is really strange. I add the following values to the combo box in order.
- aaaa
- bbbb
- this triggers wm_compareitem
- iItemId1 is 0
- iItemId2 is -1
- item1 is 0x00000000 (null ptr)
- item2 is L"bbbb"
- (this causes the string compare to fail, so I just force return of -1)
- cccc
- iItemId1 is 0
- iItemId2 is -1
- item1 is 0x00000000 (null ptr)
- item2 is L"cccc"
- zzzz
- yyyy
- xxxx
z,y and x all follow the same pattern. I may have found one other guy on the internet with the same problem here. But hard to say for sure.