3 * 1. The following extended styles need to be implemented, use will
5 * CBES_EX_NOEDITIMAGEINDENT
6 * CBES_EX_PATHWORDBREAKPROC
8 * CBES_EX_CASESENSITIVE
9 * 2. None of the following callback items are implemented. Therefor
10 * no CBEN_GETDISPINFO notifies are issued. Use in either CBEM_INSERTITEM
11 * or CBEM_SETITEM will result in a FIXME:
15 * 3. No use is made of the iOverlay image.
16 * 4. Notify CBEN_DRAGBEGIN is not implemented.
21 * ComboBoxEx control v2 (mod6)
23 * Copyright 1998, 1999 Eric Kohl
26 * This is just a dummy control. An author is needed! Any volunteers?
27 * I will only improve this control once in a while.
28 * Eric <ekohl@abo.rhein-zeitung.de>
31 * Changes Guy Albertelli <galberte@neo.lrun.com>
32 * v1 Implemented messages: CB_SETITEMHEIGHT, WM_WINDOWPOSCHANGING,
33 * WM_DRAWITEM, and WM_MEASUREITEM. Fixed WM_CREATE. Fixed height
34 * of window rect reported fixing rebar control.
36 * 1. Rewrite of WM_Create for own created EDIT control. Also try to
37 * generate message sequence similar to native DLL.
38 * 2. Handle case where CBEM_SETITEM is called to display data in EDIT
40 * 3. Add override for WNDPROC for the EDIT control (reqed for VK_RETURN).
41 * 4. Dump input data for things using COMBOBOXEXITEM{A|W}.
42 * 5. Handle positioning EDIT control based on whether icon present.
43 * 6. Make InsertItemA use InsertItemW, and store all data in ..W form.
44 * 7. Implement CBEM_DELETEITEM, CBEM_GETITEM{A|W}, CB_SETCURSEL,
45 * CBEM_{GET|SET}UNICODEFORMAT.
46 * 8. Add override for WNDPROC for the COMBO control.
47 * 9. Support extended style CBES_EX_NOEDITIMAGE and warn others are not
49 * 10. Implement CB_FINDSTRINGEXACT in both the Combo and ComboEx window
50 * procs to match the items. This eliminates dup entries in the listbox.
53 * 1. Implemented CBN_SELCHANGE, CBN_KILLFOCUS, and CBN_SELENDOK.
54 * 2. Fix putting text in CBEN_ENDEDIT notifys for CBN_DROPDOWN case.
55 * 3. Lock image selected status to focus state of edit control if
56 * edit control exists. Mimics native actions.
57 * 4. Implemented WM_SETFOCUS in EditWndProc to track status of
59 * 5. The LBN_SELCHANGE is just for documentation purposes.
62 * 1. Add support for CB_GETITEMDATA to a Comboex. Returns the LPARAM
63 * passed during insert of item.
64 * 2. Remember selected item and don't issue CB_SETCURSEL unless needed.
65 * 3. Add initial support for WM_NCCREATE to remove unwanted window styles
66 * (Currently just WS_VSCROLL and WS_HSCROLL, but probably should be
68 * 4. Improve some traces.
69 * 5. Add support for CB_SETITEMDATA sets LPARAM value from item.
72 * 1. Add support for WM_NOTIFYFORMAT (both incoming and outgoing) and do
73 * WM_NOTIFY correctly based on results.
74 * 2. Fix memory leaks of text strings in COMBOEX_WM_DELETEITEM.
75 * 3. Add routines to handle special cases of NMCBEENDEDIT and NMCOMBOXEX
76 * so translation to ANSI is done correctly.
77 * 4. Fix some issues with COMBOEX_DrawItem.
79 * Test vehicals were the ControlSpy modules (rebar.exe and comboboxex.exe),
87 #include "debugtools.h"
88 #include "wine/unicode.h"
90 DEFAULT_DEBUG_CHANNEL(comboex);
92 * The following is necessary for the test done in COMBOEX_DrawItem
93 * to determine whether to dump out the DRAWITEM structure or not.
95 DECLARE_DEBUG_CHANNEL(message);
111 /* ComboBoxEx structure */
115 HWND hwndSelf; /* my own hwnd */
118 WNDPROC prevEditWndProc; /* previous Edit WNDPROC value */
119 WNDPROC prevComboWndProc; /* previous Combo WNDPROC value */
121 INT selected; /* index of selected item */
122 DWORD flags; /* WINE internal flags */
124 INT nb_items; /* Number of items */
125 BOOL bUnicode; /* TRUE if this window is Unicode */
126 BOOL NtfUnicode; /* TRUE if parent wants notify in Unicode */
127 CBE_ITEMDATA *edit; /* item data for edit item */
128 CBE_ITEMDATA *items; /* Array of items */
131 /* internal flags in the COMBOEX_INFO structure */
132 #define WCBE_ACTEDIT 0x00000001 /* Edit active i.e.
133 * CBEN_BEGINEDIT issued
134 * but CBEN_ENDEDIT{A|W}
136 #define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */
137 #define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */
140 #define ID_CB_EDIT 1001
144 * Special flag set in DRAWITEMSTRUCT itemState field. It is set by
145 * the ComboEx version of the Combo Window Proc so that when the
146 * WM_DRAWITEM message is then passed to ComboEx, we know that this
147 * particular WM_DRAWITEM message is for listbox only items. Any messasges
148 * without this flag is then for the Edit control field.
150 * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that
151 * only version 4.0 applications will have ODS_COMBOBOXEDIT set.
153 #define ODS_COMBOEXLBOX 0x4000
157 /* Height in pixels of control over the amount of the selected font */
160 /* Indent amount per MS documentation */
161 #define CBE_INDENT 10
163 /* Offset in pixels from left side for start of image or text */
164 #define CBE_STARTOFFSET 6
166 /* Offset between image and text */
169 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongA (hwnd, 0))
172 /* Things common to the entire DLL */
173 static ATOM ComboExInfo;
174 static LRESULT WINAPI
175 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
176 static LRESULT WINAPI
177 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
180 COMBOEX_DumpItem (CBE_ITEMDATA *item)
182 if (TRACE_ON(comboex)){
183 TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
184 item, item->mask, item->pszText, item->cchTextMax,
186 TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
187 item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam);
188 if ((item->mask & CBEIF_TEXT) && item->pszText)
189 TRACE("item %p - pszText=%s\n",
190 item, debugstr_w((const WCHAR *)item->pszText));
196 COMBOEX_DumpInput (COMBOBOXEXITEMA *input, BOOL true_for_w)
198 if (TRACE_ON(comboex)){
199 TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n",
200 input->mask, input->iItem, input->pszText, input->cchTextMax,
202 if ((input->mask & CBEIF_TEXT) && input->pszText) {
204 TRACE("input - pszText=<%s>\n",
205 debugstr_w((const WCHAR *)input->pszText));
207 TRACE("input - pszText=<%s>\n",
208 debugstr_a((const char *)input->pszText));
210 TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
211 input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam);
216 inline static LRESULT
217 COMBOEX_Forward (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
219 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
221 if (infoPtr->hwndCombo)
222 return SendMessageA (infoPtr->hwndCombo, uMsg, wParam, lParam);
229 COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr)
232 hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
233 hdr->hwndFrom = infoPtr->hwndSelf;
235 if (infoPtr->NtfUnicode)
236 return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
239 return SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
245 COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr)
248 /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
250 hdr->hdr.idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
251 hdr->hdr.hwndFrom = infoPtr->hwndSelf;
252 hdr->hdr.code = code;
253 if (infoPtr->NtfUnicode)
254 return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
257 LPWSTR str, ostr = NULL;
260 if (hdr->ceItem.mask & CBEIF_TEXT) {
261 ostr = hdr->ceItem.pszText;
263 if (!str) str = (LPWSTR)L"";
264 len = WideCharToMultiByte (CP_ACP, 0, str, -1, 0, 0, NULL, NULL);
266 hdr->ceItem.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(CHAR));
267 WideCharToMultiByte (CP_ACP, 0, str, -1, (LPSTR)hdr->ceItem.pszText,
272 ret = SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
274 if (hdr->ceItem.mask & CBEIF_TEXT) {
276 COMCTL32_Free (hdr->ceItem.pszText);
277 hdr->ceItem.pszText = ostr;
285 COMBOEX_NotifyEndEdit (COMBOEX_INFO *infoPtr, NMCBEENDEDITW *hdr, LPWSTR itemText)
288 /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
290 hdr->hdr.idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
291 hdr->hdr.hwndFrom = infoPtr->hwndSelf;
292 hdr->hdr.code = (infoPtr->NtfUnicode) ? CBEN_ENDEDITW : CBEN_ENDEDITA;
293 if (infoPtr->NtfUnicode)
294 return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
297 WideCharToMultiByte (CP_ACP, 0, itemText, -1,
298 (LPSTR)hdr->szText, CBEMAXSTRLEN, NULL, NULL);
299 return SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
306 COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size)
311 mydc = GetDC (0); /* why the entire screen???? */
312 nfont = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
313 ofont = (HFONT) SelectObject (mydc, nfont);
314 GetTextExtentPointA (mydc, "A", 1, size);
315 SelectObject (mydc, ofont);
317 TRACE("selected font hwnd=%08x, height=%ld\n", nfont, size->cy);
322 COMBOEX_CopyItem (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit)
324 if (cit->mask & CBEIF_TEXT) {
325 cit->pszText = item->pszText;
326 cit->cchTextMax = item->cchTextMax;
328 if (cit->mask & CBEIF_IMAGE)
329 cit->iImage = item->iImage;
330 if (cit->mask & CBEIF_SELECTEDIMAGE)
331 cit->iSelectedImage = item->iSelectedImage;
332 if (cit->mask & CBEIF_OVERLAY)
333 cit->iOverlay = item->iOverlay;
334 if (cit->mask & CBEIF_INDENT)
335 cit->iIndent = item->iIndent;
336 if (cit->mask & CBEIF_LPARAM)
337 cit->lParam = item->lParam;
343 COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr)
347 INT x, y, w, h, xoff = 0;
350 if (!infoPtr->hwndEdit) return;
351 iinfo.rcImage.left = iinfo.rcImage.right = 0;
353 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
354 xoff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
356 GetClientRect (infoPtr->hwndCombo, &rect);
357 InflateRect (&rect, -2, -2);
358 InvalidateRect (infoPtr->hwndCombo, &rect, TRUE);
360 /* reposition the Edit control based on whether icon exists */
361 COMBOEX_GetComboFontSize (infoPtr, &mysize);
362 TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy);
363 x = xoff + CBE_STARTOFFSET + 1;
365 w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1;
368 TRACE("Combo client (%d,%d)-(%d,%d), setting Edit to (%d,%d)-(%d,%d)\n",
369 rect.left, rect.top, rect.right, rect.bottom,
371 SetWindowPos(infoPtr->hwndEdit, HWND_TOP,
374 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
379 COMBOEX_ReSize (HWND hwnd, COMBOEX_INFO *infoPtr)
385 COMBOEX_GetComboFontSize (infoPtr, &mysize);
386 cy = mysize.cy + CBE_EXTRA;
388 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
389 cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy);
390 TRACE("upgraded height due to image: height=%d\n", cy);
392 SendMessageW (hwnd, CB_SETITEMHEIGHT, (WPARAM) -1, (LPARAM) cy);
393 if (infoPtr->hwndCombo)
394 SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
395 (WPARAM) 0, (LPARAM) cy);
400 COMBOEX_SetEditText (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
402 if (!infoPtr->hwndEdit) return;
403 /* native issues the following messages to the {Edit} control */
404 /* WM_SETTEXT (0,addr) */
405 /* EM_SETSEL32 (0,0) */
406 /* EM_SETSEL32 (0,-1) */
407 if (item->mask & CBEIF_TEXT) {
408 SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)item->pszText);
409 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
410 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
415 static CBE_ITEMDATA *
416 COMBOEX_FindItem(COMBOEX_INFO *infoPtr, INT index)
421 if ((index > infoPtr->nb_items) || (index < -1))
424 return infoPtr->edit;
425 item = infoPtr->items;
426 i = infoPtr->nb_items - 1;
428 /* find the item in the list */
429 while (item && (i > index)) {
430 item = (CBE_ITEMDATA *)item->next;
433 if (!item || (i != index)) {
434 FIXME("COMBOBOXEX item structures broken. Please report!\n");
442 COMBOEX_WarnCallBack (CBE_ITEMDATA *item)
444 if (item->pszText == LPSTR_TEXTCALLBACKW)
445 FIXME("Callback not implemented yet for pszText\n");
446 if (item->iImage == I_IMAGECALLBACK)
447 FIXME("Callback not implemented yet for iImage\n");
448 if (item->iSelectedImage == I_IMAGECALLBACK)
449 FIXME("Callback not implemented yet for iSelectedImage\n");
450 if (item->iOverlay == I_IMAGECALLBACK)
451 FIXME("Callback not implemented yet for iOverlay\n");
452 if (item->iIndent == I_INDENTCALLBACK)
453 FIXME("Callback not implemented yet for iIndent\n");
457 /* *** CBEM_xxx message support *** */
461 COMBOEX_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
463 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
464 INT index = (INT) wParam;
467 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
469 /* if item number requested does not exist then return failure */
470 if ((index > infoPtr->nb_items) || (index < 0)) {
471 ERR("attempt to delete item that does not exist\n");
475 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
476 ERR("attempt to delete item that was not found!\n");
480 /* doing this will result in WM_DELETEITEM being issued */
481 SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0);
483 return infoPtr->nb_items;
487 inline static LRESULT
488 COMBOEX_GetComboControl (HWND hwnd, WPARAM wParam, LPARAM lParam)
490 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
494 return (LRESULT)infoPtr->hwndCombo;
498 inline static LRESULT
499 COMBOEX_GetEditControl (HWND hwnd, WPARAM wParam, LPARAM lParam)
501 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
503 if ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN)
506 TRACE("-- 0x%x\n", infoPtr->hwndEdit);
508 return (LRESULT)infoPtr->hwndEdit;
512 inline static LRESULT
513 COMBOEX_GetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
515 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
517 TRACE("-- 0x%08lx\n", infoPtr->dwExtStyle);
519 return (LRESULT)infoPtr->dwExtStyle;
523 inline static LRESULT
524 COMBOEX_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
526 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
528 TRACE("-- 0x%p\n", infoPtr->himl);
530 return (LRESULT)infoPtr->himl;
535 COMBOEX_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
537 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
538 COMBOBOXEXITEMW *cit = (COMBOBOXEXITEMW *) lParam;
542 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
544 /* get real index of item to insert */
547 /* if item number requested does not exist then return failure */
548 if ((index > infoPtr->nb_items) || (index < -1)) {
549 ERR("attempt to get item that does not exist\n");
553 /* if the item is the edit control and there is no edit control, skip */
555 ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN))
558 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
559 ERR("attempt to get item that was not found!\n");
563 COMBOEX_CopyItem (infoPtr, item, cit);
569 inline static LRESULT
570 COMBOEX_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
572 COMBOBOXEXITEMA *cit = (COMBOBOXEXITEMA *) lParam;
573 COMBOBOXEXITEMW tmpcit;
576 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
578 tmpcit.mask = cit->mask;
579 tmpcit.iItem = cit->iItem;
580 COMBOEX_GetItemW (hwnd, wParam, (LPARAM) &tmpcit);
582 len = WideCharToMultiByte (CP_ACP, 0, tmpcit.pszText, -1, 0, 0, NULL, NULL);
584 WideCharToMultiByte (CP_ACP, 0, tmpcit.pszText, -1,
585 cit->pszText, cit->cchTextMax, NULL, NULL);
587 cit->iImage = tmpcit.iImage;
588 cit->iSelectedImage = tmpcit.iSelectedImage;
589 cit->iOverlay = tmpcit.iOverlay;
590 cit->iIndent = tmpcit.iIndent;
591 cit->lParam = tmpcit.lParam;
597 inline static LRESULT
598 COMBOEX_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
600 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
602 TRACE("%s hwnd=0x%x\n",
603 infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd);
605 return infoPtr->bUnicode;
609 inline static LRESULT
610 COMBOEX_HasEditChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
612 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
614 if ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN)
616 if ((infoPtr->flags & (WCBE_ACTEDIT | WCBE_EDITCHG)) ==
617 (WCBE_ACTEDIT | WCBE_EDITCHG))
624 COMBOEX_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
626 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
627 COMBOBOXEXITEMW *cit = (COMBOBOXEXITEMW *) lParam;
634 COMBOEX_DumpInput ((COMBOBOXEXITEMA *) cit, TRUE);
636 /* get real index of item to insert */
638 if (index == -1) index = infoPtr->nb_items;
639 if (index > infoPtr->nb_items) index = infoPtr->nb_items;
641 /* get space and chain it in */
642 item = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA));
644 item->pszText = NULL;
646 /* locate position to insert new item in */
647 if (index == infoPtr->nb_items) {
648 /* fast path for iItem = -1 */
649 item->next = infoPtr->items;
650 infoPtr->items = item;
653 INT i = infoPtr->nb_items-1;
654 CBE_ITEMDATA *moving = infoPtr->items;
656 while ((i > index) && moving) {
657 moving = (CBE_ITEMDATA *)moving->next;
661 FIXME("COMBOBOXEX item structures broken. Please report!\n");
665 item->next = moving->next;
669 /* fill in our hidden item structure */
670 item->mask = cit->mask;
671 if (item->mask & CBEIF_TEXT) {
676 if (!str) str = (LPWSTR) L"";
679 item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
680 strcpyW (item->pszText, str);
683 item->pszText = NULL;
684 item->cchTextMax = cit->cchTextMax;
686 if (item->mask & CBEIF_IMAGE)
687 item->iImage = cit->iImage;
688 if (item->mask & CBEIF_SELECTEDIMAGE)
689 item->iSelectedImage = cit->iSelectedImage;
690 if (item->mask & CBEIF_OVERLAY)
691 item->iOverlay = cit->iOverlay;
692 if (item->mask & CBEIF_INDENT)
693 item->iIndent = cit->iIndent;
694 if (item->mask & CBEIF_LPARAM)
695 item->lParam = cit->lParam;
698 COMBOEX_WarnCallBack (item);
700 COMBOEX_DumpItem (item);
702 SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING,
703 (WPARAM)cit->iItem, (LPARAM)item);
705 COMBOEX_CopyItem (infoPtr, item, &nmcit.ceItem);
706 COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit);
714 COMBOEX_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
716 COMBOBOXEXITEMA *cit = (COMBOBOXEXITEMA *) lParam;
717 COMBOBOXEXITEMW citW;
720 memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
721 if (cit->mask & CBEIF_TEXT) {
727 len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
729 citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
730 MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
733 ret = COMBOEX_InsertItemW(hwnd,wParam,(LPARAM)&citW);;
735 if (cit->mask & CBEIF_TEXT)
736 COMCTL32_Free(citW.pszText);
742 COMBOEX_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
744 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
747 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
749 dwTemp = infoPtr->dwExtStyle;
751 if (lParam & (CBES_EX_NOEDITIMAGEINDENT |
752 CBES_EX_PATHWORDBREAKPROC |
753 CBES_EX_NOSIZELIMIT |
754 CBES_EX_CASESENSITIVE))
755 FIXME("Extended style not implemented %08lx\n", lParam);
758 infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~(DWORD)wParam) | (DWORD)lParam;
761 infoPtr->dwExtStyle = (DWORD)lParam;
764 * native does this for CBES_EX_NOEDITIMAGE state change
766 if ((infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE) ^
767 (dwTemp & CBES_EX_NOEDITIMAGE)) {
768 /* if state of EX_NOEDITIMAGE changes, invalidate all */
769 TRACE("EX_NOEDITIMAGE state changed to %ld\n",
770 infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE);
771 InvalidateRect (hwnd, NULL, TRUE);
772 COMBOEX_AdjustEditPos (infoPtr);
773 if (infoPtr->hwndEdit)
774 InvalidateRect (infoPtr->hwndEdit, NULL, TRUE);
777 return (LRESULT)dwTemp;
781 inline static LRESULT
782 COMBOEX_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
784 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
787 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
789 himlTemp = infoPtr->himl;
790 infoPtr->himl = (HIMAGELIST)lParam;
792 COMBOEX_ReSize (hwnd, infoPtr);
793 InvalidateRect (infoPtr->hwndCombo, NULL, TRUE);
795 /* reposition the Edit control based on whether icon exists */
796 COMBOEX_AdjustEditPos (infoPtr);
797 return (LRESULT)himlTemp;
801 COMBOEX_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
803 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
804 COMBOBOXEXITEMW *cit = (COMBOBOXEXITEMW *) lParam;
808 COMBOEX_DumpInput ((COMBOBOXEXITEMA *) cit, TRUE);
810 /* get real index of item to insert */
813 /* if item number requested does not exist then return failure */
814 if ((index > infoPtr->nb_items) || (index < -1)) {
815 ERR("attempt to set item that does not exist yet!\n");
819 /* if the item is the edit control and there is no edit control, skip */
821 ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN))
824 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
825 ERR("attempt to set item that was not found!\n");
829 /* add/change stuff to the internal item structure */
830 item->mask |= cit->mask;
831 if (cit->mask & CBEIF_TEXT) {
834 WCHAR emptystr[1] = {0};
837 if (!str) str=emptystr;
840 item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
841 strcpyW(item->pszText,str);
843 item->cchTextMax = cit->cchTextMax;
845 if (cit->mask & CBEIF_IMAGE)
846 item->iImage = cit->iImage;
847 if (cit->mask & CBEIF_SELECTEDIMAGE)
848 item->iSelectedImage = cit->iSelectedImage;
849 if (cit->mask & CBEIF_OVERLAY)
850 item->iOverlay = cit->iOverlay;
851 if (cit->mask & CBEIF_INDENT)
852 item->iIndent = cit->iIndent;
853 if (cit->mask & CBEIF_LPARAM)
854 cit->lParam = cit->lParam;
856 COMBOEX_WarnCallBack (item);
858 COMBOEX_DumpItem (item);
860 /* if original request was to update edit control, do some fast foot work */
861 if (cit->iItem == -1) {
862 COMBOEX_SetEditText (infoPtr, item);
863 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE);
869 COMBOEX_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
871 COMBOBOXEXITEMA *cit = (COMBOBOXEXITEMA *) lParam;
872 COMBOBOXEXITEMW citW;
875 memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
876 if (cit->mask & CBEIF_TEXT) {
882 len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
884 citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
885 MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
888 ret = COMBOEX_SetItemW(hwnd,wParam,(LPARAM)&citW);;
890 if (cit->mask & CBEIF_TEXT)
891 COMCTL32_Free(citW.pszText);
896 inline static LRESULT
897 COMBOEX_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
899 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
900 BOOL bTemp = infoPtr->bUnicode;
902 TRACE("to %s hwnd=0x%04x, was %s\n",
903 ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd,
904 (bTemp) ? "TRUE" : "FALSE");
906 infoPtr->bUnicode = (BOOL)wParam;
913 /* *** CB_xxx message support *** */
917 COMBOEX_FindStringExact (COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
921 LPWSTR desired = NULL;
922 INT start = (INT) wParam;
924 i = MultiByteToWideChar (CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0);
926 desired = (LPWSTR)COMCTL32_Alloc ((i + 1)*sizeof(WCHAR));
927 MultiByteToWideChar (CP_ACP, 0, (LPSTR)lParam, -1, desired, i);
930 count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0 , 0);
932 /* now search from after starting loc and wrapping back to start */
933 for(i=start+1; i<count; i++) {
934 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
935 CB_GETITEMDATA, (WPARAM)i, 0);
936 TRACE("desired=%s, item=%s\n",
937 debugstr_w(desired), debugstr_w(item->pszText));
938 if (lstrcmpiW(item->pszText, desired) == 0) {
939 COMCTL32_Free (desired);
943 for(i=0; i<=start; i++) {
944 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
945 CB_GETITEMDATA, (WPARAM)i, 0);
946 TRACE("desired=%s, item=%s\n",
947 debugstr_w(desired), debugstr_w(item->pszText));
948 if (lstrcmpiW(item->pszText, desired) == 0) {
949 COMCTL32_Free (desired);
953 COMCTL32_Free(desired);
959 COMBOEX_GetItemData (HWND hwnd, WPARAM wParam, LPARAM lParam)
962 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
963 CBE_ITEMDATA *item1, *item2;
966 item1 = (CBE_ITEMDATA *)COMBOEX_Forward (hwnd, CB_GETITEMDATA,
968 if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
969 item2 = COMBOEX_FindItem (infoPtr, index);
970 if (item2 != item1) {
971 ERR("data structures damaged!\n");
974 if (item1->mask & CBEIF_LPARAM)
975 lret = (LRESULT) item1->lParam;
976 TRACE("returning 0x%08lx\n", lret);
979 lret = (LRESULT)item1;
980 TRACE("non-valid result from combo, returning 0x%08lx\n", lret);
986 COMBOEX_SetCursel (HWND hwnd, WPARAM wParam, LPARAM lParam)
989 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
993 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
994 /* FIXME: need to clear selection */
998 TRACE("selecting item %d text=%s\n", index, (item->pszText) ?
999 debugstr_w(item->pszText) : "<null>");
1000 infoPtr->selected = index;
1002 lret = SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, wParam, lParam);
1003 COMBOEX_SetEditText (infoPtr, item);
1009 COMBOEX_SetItemData (HWND hwnd, WPARAM wParam, LPARAM lParam)
1012 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1013 CBE_ITEMDATA *item1, *item2;
1015 item1 = (CBE_ITEMDATA *)COMBOEX_Forward (hwnd, CB_GETITEMDATA,
1017 if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
1018 item2 = COMBOEX_FindItem (infoPtr, index);
1019 if (item2 != item1) {
1020 ERR("data structures damaged!\n");
1023 item1->mask |= CBEIF_LPARAM;
1024 item1->lParam = lParam;
1025 TRACE("setting lparam to 0x%08lx\n", lParam);
1028 TRACE("non-valid result from combo 0x%08lx\n", (DWORD)item1);
1029 return (LRESULT)item1;
1034 COMBOEX_SetItemHeight (HWND hwnd, WPARAM wParam, LPARAM lParam)
1036 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1037 RECT cb_wrect, cbx_wrect, cbx_crect;
1041 /* First, lets forward the message to the normal combo control
1042 just like Windows. */
1043 if (infoPtr->hwndCombo)
1044 SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, wParam, lParam);
1046 GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1047 GetWindowRect (hwnd, &cbx_wrect);
1048 GetClientRect (hwnd, &cbx_crect);
1049 /* the height of comboex as height of the combo + comboex border */
1050 height = cb_wrect.bottom-cb_wrect.top
1051 + cbx_wrect.bottom-cbx_wrect.top
1052 - (cbx_crect.bottom-cbx_crect.top);
1053 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
1054 cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
1055 cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
1056 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
1057 cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
1058 cbx_wrect.right-cbx_wrect.left, height);
1059 SetWindowPos (hwnd, HWND_TOP, 0, 0,
1060 cbx_wrect.right-cbx_wrect.left,
1062 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1068 /* *** WM_xxx message support *** */
1072 COMBOEX_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1074 LPCREATESTRUCTA cs = (LPCREATESTRUCTA) lParam;
1075 COMBOEX_INFO *infoPtr;
1079 RECT wnrc1, clrc1, cmbwrc;
1083 /* allocate memory for info structure */
1084 infoPtr = (COMBOEX_INFO *)COMCTL32_Alloc (sizeof(COMBOEX_INFO));
1085 if (infoPtr == NULL) {
1086 ERR("could not allocate info memory!\n");
1090 /* initialize info structure */
1092 infoPtr->items = NULL;
1093 infoPtr->nb_items = 0;
1094 infoPtr->hwndSelf = hwnd;
1095 infoPtr->selected = -1;
1097 infoPtr->bUnicode = IsWindowUnicode (hwnd);
1099 i = SendMessageA(GetParent (hwnd),
1100 WM_NOTIFYFORMAT, hwnd, NF_QUERY);
1101 if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
1102 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n",
1106 infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
1108 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1110 /* create combo box */
1111 dwComboStyle = GetWindowLongA (hwnd, GWL_STYLE) &
1112 (CBS_SIMPLE|CBS_DROPDOWN|CBS_DROPDOWNLIST|WS_CHILD);
1114 GetWindowRect(hwnd, &wnrc1);
1115 GetClientRect(hwnd, &clrc1);
1116 TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d)\n",
1117 wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
1118 clrc1.left, clrc1.top, clrc1.right, clrc1.bottom);
1119 TRACE("combo style=%08lx, adding style=%08lx\n", dwComboStyle,
1120 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
1121 CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
1122 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED);
1124 /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
1125 /* specified. It then creates it's own version of the EDIT control */
1126 /* and makes the ComboBox the parent. This is because a normal */
1127 /* DROPDOWNLIST does not have a EDIT control, but we need one. */
1128 /* We also need to place the edit control at the proper location */
1129 /* (allow space for the icons). */
1131 infoPtr->hwndCombo = CreateWindowA ("ComboBox", "",
1132 /* following line added to match native */
1133 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
1134 CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
1135 /* was base and is necessary */
1136 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | dwComboStyle,
1137 cs->y, cs->x, cs->cx, cs->cy, hwnd,
1138 (HMENU) GetWindowLongA (hwnd, GWL_ID),
1139 GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
1142 * native does the following at this point according to trace:
1143 * GetWindowThreadProcessId(hwndCombo,0)
1144 * GetCurrentThreadId()
1145 * GetWindowThreadProcessId(hwndCombo, &???)
1146 * GetCurrentProcessId()
1150 * Setup a property to hold the pointer to the COMBOBOXEX
1153 test = GetPropA(infoPtr->hwndCombo, (LPCSTR)(LONG)ComboExInfo);
1154 if (!test || ((COMBOEX_INFO *)test != infoPtr)) {
1155 SetPropA(infoPtr->hwndCombo, "CC32SubclassInfo", (LONG)infoPtr);
1157 infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongA(infoPtr->hwndCombo,
1158 GWL_WNDPROC, (LONG)COMBOEX_ComboWndProc);
1159 infoPtr->font = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
1163 * Now create our own EDIT control so we can position it.
1164 * It is created only for CBS_DROPDOWN style
1166 if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
1167 infoPtr->hwndEdit = CreateWindowExA (0, "EDIT", "",
1168 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
1169 0, 0, 0, 0, /* will set later */
1171 (HMENU) GetWindowLongA (hwnd, GWL_ID),
1172 GetWindowLongA (hwnd, GWL_HINSTANCE),
1175 /* native does the following at this point according to trace:
1176 * GetWindowThreadProcessId(hwndEdit,0)
1177 * GetCurrentThreadId()
1178 * GetWindowThreadProcessId(hwndEdit, &???)
1179 * GetCurrentProcessId()
1183 * Setup a property to hold the pointer to the COMBOBOXEX
1186 test = GetPropA(infoPtr->hwndEdit, (LPCSTR)(LONG)ComboExInfo);
1187 if (!test || ((COMBOEX_INFO *)test != infoPtr)) {
1188 SetPropA(infoPtr->hwndEdit, "CC32SubclassInfo", (LONG)infoPtr);
1190 infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongA(infoPtr->hwndEdit,
1191 GWL_WNDPROC, (LONG)COMBOEX_EditWndProc);
1192 infoPtr->font = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
1195 infoPtr->hwndEdit = 0;
1200 * Locate the default font if necessary and then set it in
1201 * all associated controls
1203 if (!infoPtr->font) {
1204 SystemParametersInfoA (SPI_GETICONTITLELOGFONT, sizeof(mylogfont),
1206 infoPtr->font = CreateFontIndirectA (&mylogfont);
1208 SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
1209 if (infoPtr->hwndEdit) {
1210 SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
1211 SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
1214 COMBOEX_ReSize (hwnd, infoPtr);
1216 /* Above is fairly certain, below is much less certain. */
1218 GetWindowRect(hwnd, &wnrc1);
1219 GetClientRect(hwnd, &clrc1);
1220 GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
1221 TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d) CB wnd=(%d,%d)-(%d,%d)\n",
1222 wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
1223 clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
1224 cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
1225 SetWindowPos(infoPtr->hwndCombo, HWND_TOP,
1226 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
1227 SWP_NOACTIVATE | SWP_NOREDRAW);
1229 GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
1230 TRACE("CB window=(%d,%d)-(%d,%d)\n",
1231 cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
1232 SetWindowPos(hwnd, HWND_TOP,
1233 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
1234 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1236 COMBOEX_AdjustEditPos (infoPtr);
1239 * Create an item structure to represent the data in the
1242 item = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA));
1244 item->pszText = NULL;
1246 infoPtr->edit = item;
1252 inline static LRESULT
1253 COMBOEX_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1256 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1257 INT command = HIWORD(wParam);
1258 CBE_ITEMDATA *item = 0;
1260 INT cursel, n, oldItem;
1261 NMCBEENDEDITW cbeend;
1264 TRACE("for command %d\n", command);
1269 SendMessageW (GetParent (hwnd), WM_COMMAND, wParam,
1272 * from native trace of first dropdown after typing in URL in IE4
1273 * CB_GETCURSEL(Combo)
1274 * GetWindowText(Edit)
1275 * CB_GETCURSEL(Combo)
1276 * CB_GETCOUNT(Combo)
1277 * CB_GETITEMDATA(Combo, n)
1278 * WM_NOTIFY(parent, CBEN_ENDEDITA|W)
1279 * CB_GETCURSEL(Combo)
1280 * CB_SETCURSEL(COMBOEX, n)
1282 * the rest is supposition
1284 cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1286 /* find match from edit against those in Combobox */
1287 GetWindowTextW (infoPtr->hwndEdit, wintext, 520);
1288 n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
1289 for (cursel = 0; cursel < n; cursel++){
1290 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
1293 if ((INT)item == CB_ERR) break;
1294 if (lstrcmpiW(item->pszText, wintext) == 0) break;
1296 if ((cursel == n) || ((INT)item == CB_ERR)) {
1297 TRACE("failed to find match??? item=%p cursel=%d\n",
1299 if (infoPtr->hwndEdit)
1300 SetFocus(infoPtr->hwndEdit);
1305 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
1308 if ((INT)item == CB_ERR) {
1309 TRACE("failed to find match??? item=%p cursel=%d\n",
1311 if (infoPtr->hwndEdit)
1312 SetFocus(infoPtr->hwndEdit);
1317 /* Save flags for testing and reset them */
1318 oldflags = infoPtr->flags;
1319 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1321 if (oldflags & WCBE_ACTEDIT) {
1322 cbeend.fChanged = (oldflags & WCBE_EDITCHG);
1323 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1324 CB_GETCURSEL, 0, 0);
1325 cbeend.iWhy = CBENF_DROPDOWN;
1327 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, item->pszText)) {
1328 /* abort the change */
1329 TRACE("Notify requested abort of change\n");
1334 /* if selection has changed the set the new current selection */
1335 cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1336 if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) {
1337 infoPtr->selected = cursel;
1338 SendMessageW (hwnd, CB_SETCURSEL, cursel, 0);
1339 SetFocus(infoPtr->hwndCombo);
1345 * CB_GETCURSEL(Combo)
1346 * CB_GETITEMDATA(Combo) < simulated by COMBOEX_FindItem
1349 * WM_GETTEXTLENGTH(Edit)
1351 * EM_SETSEL(Edit, 0,0)
1352 * WM_GETTEXTLENGTH(Edit)
1354 * EM_SETSEL(Edit, 0,len)
1355 * return WM_COMMAND to parent
1357 oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1358 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
1359 ERR("item %d not found. Problem!\n", oldItem);
1362 infoPtr->selected = oldItem;
1363 COMBOEX_SetEditText (infoPtr, item);
1364 return SendMessageW (GetParent (hwnd), WM_COMMAND, wParam,
1369 * We have to change the handle since we are the control
1370 * issuing the message. IE4 depends on this.
1372 return SendMessageW (GetParent (hwnd), WM_COMMAND, wParam,
1377 * from native trace:
1380 * WM_GETTEXT(Edit, 104)
1381 * CB_GETCURSEL(Combo) rets -1
1382 * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
1383 * CB_GETCURSEL(Combo)
1384 * InvalidateRect(Combo, 0, 0)
1387 SendMessageW (GetParent (hwnd), WM_COMMAND, wParam,
1389 if (infoPtr->flags & WCBE_ACTEDIT) {
1390 GetWindowTextW (infoPtr->hwndEdit, wintext, 260);
1391 cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
1392 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1393 CB_GETCURSEL, 0, 0);
1394 cbeend.iWhy = CBENF_KILLFOCUS;
1396 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1397 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) {
1398 /* abort the change */
1399 TRACE("Notify requested abort of change\n");
1403 /* possible CB_GETCURSEL */
1404 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1410 * We have to change the handle since we are the control
1411 * issuing the message. IE4 depends on this.
1412 * We also need to set the focus back to the Edit control
1413 * after passing the command to the parent of the ComboEx.
1415 lret = SendMessageW (GetParent (hwnd), WM_COMMAND, wParam,
1417 if (infoPtr->hwndEdit)
1418 SetFocus(infoPtr->hwndEdit);
1425 inline static LRESULT
1426 COMBOEX_WM_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1428 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1429 DELETEITEMSTRUCT *dis = (DELETEITEMSTRUCT *)lParam;
1430 CBE_ITEMDATA *item, *olditem;
1432 NMCOMBOBOXEXW nmcit;
1434 TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%x, data=%08lx\n",
1435 dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData);
1437 if ((dis->itemID >= infoPtr->nb_items) || (dis->itemID < 0)) return FALSE;
1439 olditem = infoPtr->items;
1440 i = infoPtr->nb_items - 1;
1442 if (i == dis->itemID) {
1443 infoPtr->items = infoPtr->items->next;
1449 /* find the prior item in the list */
1450 while (item->next && (i > dis->itemID)) {
1451 item = (CBE_ITEMDATA *)item->next;
1454 if (!item->next || (i != dis->itemID)) {
1455 FIXME("COMBOBOXEX item structures broken. Please report!\n");
1458 olditem = item->next;
1459 item->next = (CBE_ITEMDATA *)((CBE_ITEMDATA *)item->next)->next;
1461 infoPtr->nb_items--;
1463 COMBOEX_CopyItem (infoPtr, olditem, &nmcit.ceItem);
1464 COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit);
1466 if (olditem->pszText)
1467 COMCTL32_Free(olditem->pszText);
1468 COMCTL32_Free(olditem);
1475 inline static LRESULT
1476 COMBOEX_DrawItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1478 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1479 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
1480 CBE_ITEMDATA *item = 0;
1484 int drawimage, drawstate;
1486 UINT xioff = 0; /* size and spacer of image if any */
1489 COLORREF nbkc, ntxc;
1491 if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0;
1493 /* dump the DRAWITEMSTRUCT if tracing "comboex" but not "message" */
1494 if (!TRACE_ON(message)) {
1495 TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
1496 dis->CtlType, dis->CtlID);
1497 TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n",
1498 dis->itemID, dis->itemAction, dis->itemState);
1499 TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n",
1500 dis->hwndItem, dis->hDC, dis->rcItem.left,
1501 dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom,
1506 /* "itemID - Specifies the menu item identifier for a menu */
1507 /* item or the index of the item in a list box or combo box. */
1508 /* For an empty list box or combo box, this member can be -1. */
1509 /* This allows the application to draw only the focus */
1510 /* rectangle at the coordinates specified by the rcItem */
1511 /* member even though there are no items in the control. */
1512 /* This indicates to the user whether the list box or combo */
1513 /* box has the focus. How the bits are set in the itemAction */
1514 /* member determines whether the rectangle is to be drawn as */
1515 /* though the list box or combo box has the focus. */
1516 if (dis->itemID == 0xffffffff) {
1517 if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) ||
1518 ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) {
1520 TRACE("drawing item -1 special focus, rect=(%d,%d)-(%d,%d)\n",
1521 dis->rcItem.left, dis->rcItem.top,
1522 dis->rcItem.right, dis->rcItem.bottom);
1524 else if ((dis->CtlType == ODT_COMBOBOX) &&
1525 (dis->itemAction == ODA_DRAWENTIRE)) {
1526 /* draw of edit control data */
1530 RECT exrc, cbrc, edrc;
1531 GetWindowRect (hwnd, &exrc);
1532 GetWindowRect (infoPtr->hwndCombo, &cbrc);
1533 edrc.left=edrc.top=edrc.right=edrc.bottom=-1;
1534 if (infoPtr->hwndEdit)
1535 GetWindowRect (infoPtr->hwndEdit, &edrc);
1536 TRACE("window rects ex=(%d,%d)-(%d,%d), cb=(%d,%d)-(%d,%d), ed=(%d,%d)-(%d,%d)\n",
1537 exrc.left, exrc.top, exrc.right, exrc.bottom,
1538 cbrc.left, cbrc.top, cbrc.right, cbrc.bottom,
1539 edrc.left, edrc.top, edrc.right, edrc.bottom);
1543 ERR("NOT drawing item -1 special focus, rect=(%d,%d)-(%d,%d), action=%08x, state=%08x\n",
1544 dis->rcItem.left, dis->rcItem.top,
1545 dis->rcItem.right, dis->rcItem.bottom,
1546 dis->itemAction, dis->itemState);
1551 /* If draw item is -1 (edit control) setup the item pointer */
1552 if (dis->itemID == 0xffffffff) {
1556 item = infoPtr->edit;
1558 if (infoPtr->hwndEdit) {
1560 /* free previous text of edit item */
1561 if (item->pszText) {
1562 COMCTL32_Free(item->pszText);
1564 item->mask &= ~CBEIF_TEXT;
1566 alen = SendMessageA (infoPtr->hwndEdit, WM_GETTEXT, 260, (LPARAM)&str);
1567 TRACE("edit control hwndEdit=%0x, text len=%d str=<%s>\n",
1568 infoPtr->hwndEdit, alen, str);
1570 item->mask |= CBEIF_TEXT;
1571 wlen = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
1573 item->pszText = (LPWSTR)COMCTL32_Alloc ((wlen + 1)*sizeof(WCHAR));
1574 MultiByteToWideChar (CP_ACP, 0, str, -1, item->pszText, wlen);
1580 /* if the item pointer is not set, then get the data and locate it */
1582 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
1583 CB_GETITEMDATA, (WPARAM)dis->itemID, 0);
1584 if (item == (CBE_ITEMDATA *)CB_ERR)
1586 FIXME("invalid item for id %d \n",dis->itemID);
1591 COMBOEX_DumpItem (item);
1593 xbase = CBE_STARTOFFSET;
1594 if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX))
1595 xbase += (item->iIndent * CBE_INDENT);
1596 if (item->mask & CBEIF_IMAGE) {
1597 ImageList_GetImageInfo(infoPtr->himl, item->iImage, &iinfo);
1598 xioff = (iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP);
1601 switch (dis->itemAction) {
1603 if (dis->itemState & ODS_SELECTED /*1*/) {
1604 if ((item->mask & CBEIF_TEXT) && item->pszText) {
1607 len = strlenW (item->pszText);
1608 GetTextExtentPointW (dis->hDC, item->pszText, len, &txtsize);
1609 rect.left = xbase + xioff - 1;
1610 rect.right = rect.left + txtsize.cx + 2;
1611 rect.top = dis->rcItem.top;
1612 rect.bottom = dis->rcItem.bottom;
1613 GetClipBox (dis->hDC, &rect2);
1614 TRACE("drawing item %d focus, rect=(%d,%d)-(%d,%d)\n",
1615 dis->itemID, rect.left, rect.top,
1616 rect.right, rect.bottom);
1617 TRACE(" clip=(%d,%d)-(%d,%d)\n",
1618 rect2.left, rect2.top,
1619 rect2.right, rect2.bottom);
1621 DrawFocusRect(dis->hDC, &rect);
1624 FIXME("ODA_FOCUS and ODS_SELECTED but no text\n");
1628 FIXME("ODA_FOCUS but not ODS_SELECTED\n");
1632 case ODA_DRAWENTIRE:
1634 drawstate = ILD_NORMAL;
1635 if (!(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE)) {
1636 if (item->mask & CBEIF_IMAGE)
1637 drawimage = item->iImage;
1638 if (dis->itemState & ODS_COMBOEXLBOX) {
1639 /* drawing listbox entry */
1640 if (dis->itemState & ODS_SELECTED) {
1641 if (item->mask & CBEIF_SELECTEDIMAGE)
1642 drawimage = item->iSelectedImage;
1643 drawstate = ILD_SELECTED;
1647 /* drawing combo/edit entry */
1648 if (infoPtr->hwndEdit) {
1649 /* if we have an edit control, the slave the
1650 * selection state to the Edit focus state
1652 if (infoPtr->flags & WCBE_EDITFOCUSED) {
1653 if (item->mask & CBEIF_SELECTEDIMAGE)
1654 drawimage = item->iSelectedImage;
1655 drawstate = ILD_SELECTED;
1659 /* if we don't have an edit control, use
1660 * the requested state.
1662 if (dis->itemState & ODS_SELECTED) {
1663 if (item->mask & CBEIF_SELECTEDIMAGE)
1664 drawimage = item->iSelectedImage;
1665 drawstate = ILD_SELECTED;
1670 if (drawimage != -1) {
1671 TRACE("drawing image state=%d\n", dis->itemState & ODS_SELECTED);
1672 ImageList_Draw (infoPtr->himl, drawimage, dis->hDC,
1673 xbase, dis->rcItem.top, drawstate);
1676 /* setup pointer to text to be drawn */
1677 if ((item->mask & CBEIF_TEXT) && item->pszText)
1678 str = item->pszText;
1682 /* now draw the text */
1683 len = lstrlenW (str);
1684 GetTextExtentPointW (dis->hDC, str, len, &txtsize);
1685 nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1686 COLOR_HIGHLIGHT : COLOR_WINDOW);
1687 SetBkColor (dis->hDC, nbkc);
1688 ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1689 COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT);
1690 SetTextColor (dis->hDC, ntxc);
1692 y = dis->rcItem.top +
1693 (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2;
1695 rect.right = x + txtsize.cx;
1696 rect.top = dis->rcItem.top + 1;
1697 rect.bottom = dis->rcItem.bottom - 1;
1698 TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n",
1699 dis->itemID, rect.left, rect.top, rect.right, rect.bottom);
1700 ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED,
1701 &rect, str, len, 0);
1702 if (dis->itemState & ODS_FOCUS) {
1707 TRACE("drawing item %d focus after text, rect=(%d,%d)-(%d,%d)\n",
1708 dis->itemID, rect.left, rect.top, rect.right, rect.bottom);
1709 DrawFocusRect (dis->hDC, &rect);
1713 FIXME("unknown action hwnd=%08x, wparam=%08x, lparam=%08lx, action=%d\n",
1714 hwnd, wParam, lParam, dis->itemAction);
1722 COMBOEX_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1724 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1726 if (infoPtr->hwndCombo)
1727 DestroyWindow (infoPtr->hwndCombo);
1729 if (infoPtr->edit) {
1730 COMCTL32_Free (infoPtr->edit);
1734 if (infoPtr->items) {
1735 CBE_ITEMDATA *this, *next;
1737 this = infoPtr->items;
1739 next = (CBE_ITEMDATA *)this->next;
1740 if ((this->mask & CBEIF_TEXT) && this->pszText)
1741 COMCTL32_Free (this->pszText);
1742 COMCTL32_Free (this);
1747 DeleteObject (infoPtr->font);
1749 /* free comboex info data */
1750 COMCTL32_Free (infoPtr);
1751 SetWindowLongA (hwnd, 0, 0);
1757 COMBOEX_MeasureItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1759 /*COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);*/
1760 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam;
1765 GetTextExtentPointA (hdc, "W", 1, &mysize);
1767 mis->itemHeight = mysize.cy + CBE_EXTRA;
1769 TRACE("adjusted height hwnd=%08x, height=%d\n",
1770 hwnd, mis->itemHeight);
1777 COMBOEX_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
1779 /* WARNING: The COMBOEX_INFO structure is not yet created */
1780 DWORD oldstyle, newstyle;
1782 oldstyle = (DWORD)GetWindowLongA (hwnd, GWL_STYLE);
1783 newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL);
1784 if (newstyle != oldstyle) {
1785 TRACE("req style %08lx, reseting style %08lx\n",
1786 oldstyle, newstyle);
1787 SetWindowLongA (hwnd, GWL_STYLE, newstyle);
1794 COMBOEX_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
1796 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1799 if (lParam == NF_REQUERY) {
1800 i = SendMessageA(GetParent (hwnd),
1801 WM_NOTIFYFORMAT, infoPtr->hwndSelf, NF_QUERY);
1802 if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
1803 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n",
1807 infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
1810 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
1815 COMBOEX_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1817 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1820 GetWindowRect (hwnd, &rect);
1821 TRACE("my rect (%d,%d)-(%d,%d)\n",
1822 rect.left, rect.top, rect.right, rect.bottom);
1824 MoveWindow (infoPtr->hwndCombo, 0, 0, rect.right -rect.left,
1825 rect.bottom - rect.top, TRUE);
1827 COMBOEX_AdjustEditPos (infoPtr);
1834 COMBOEX_WindowPosChanging (HWND hwnd, WPARAM wParam, LPARAM lParam)
1836 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1837 RECT cbx_wrect, cbx_crect, cb_wrect;
1839 WINDOWPOS *wp = (WINDOWPOS *)lParam;
1841 GetWindowRect (hwnd, &cbx_wrect);
1842 GetClientRect (hwnd, &cbx_crect);
1843 GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1845 /* width is winpos value + border width of comboex */
1847 + (cbx_wrect.right-cbx_wrect.left)
1848 - (cbx_crect.right-cbx_crect.left);
1850 TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n",
1851 wp->x, wp->y, wp->cx, wp->cy, wp->flags);
1852 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
1853 cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
1854 cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
1855 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
1856 cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
1857 width, cb_wrect.bottom-cb_wrect.top);
1859 if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0,
1861 cb_wrect.bottom-cb_wrect.top,
1864 GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1866 /* height is combo window height plus border width of comboex */
1867 height = (cb_wrect.bottom-cb_wrect.top)
1868 + (cbx_wrect.bottom-cbx_wrect.top)
1869 - (cbx_crect.bottom-cbx_crect.top);
1870 if (wp->cy < height) wp->cy = height;
1871 if (infoPtr->hwndEdit) {
1872 COMBOEX_AdjustEditPos (infoPtr);
1873 InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
1880 static LRESULT WINAPI
1881 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1883 COMBOEX_INFO *infoPtr = (COMBOEX_INFO *)GetPropA (hwnd, (LPCSTR)(LONG) ComboExInfo);
1884 NMCBEENDEDITW cbeend;
1885 WCHAR edit_text[260];
1886 COLORREF nbkc, obkc;
1891 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
1892 hwnd, uMsg, wParam, lParam, infoPtr);
1894 if (!infoPtr) return 0;
1900 /* handle (ignore) the return character */
1901 if (wParam == VK_RETURN) return 0;
1902 /* all other characters pass into the real Edit */
1903 return CallWindowProcA (infoPtr->prevEditWndProc,
1904 hwnd, uMsg, wParam, lParam);
1908 * The following was determined by traces of the native
1911 nbkc = GetSysColor (COLOR_WINDOW);
1912 obkc = SetBkColor (hDC, nbkc);
1913 GetClientRect (hwnd, &rect);
1914 TRACE("erasing (%d,%d)-(%d,%d)\n",
1915 rect.left, rect.top, rect.right, rect.bottom);
1916 ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
1917 SetBkColor (hDC, obkc);
1918 return CallWindowProcA (infoPtr->prevEditWndProc,
1919 hwnd, uMsg, wParam, lParam);
1922 INT oldItem, selected;
1925 switch ((INT)wParam)
1928 /* native version seems to do following for COMBOEX */
1930 * GetWindowTextA(Edit,&?, 0x104) x
1931 * CB_GETCURSEL to Combo rets -1 x
1932 * WM_NOTIFY to COMBOEX parent (rebar) x
1933 * (CBEN_ENDEDIT{A|W}
1934 * fChanged = FALSE x
1935 * inewSelection = -1 x
1938 * CB_GETCURSEL to Combo rets -1 x
1939 * InvalidateRect(Combo, 0) x
1940 * WM_SETTEXT to Edit x
1941 * EM_SETSEL to Edit (0,0) x
1942 * EM_SETSEL to Edit (0,-1) x
1943 * RedrawWindow(Combo, 0, 0, 5) x
1945 TRACE("special code for VK_ESCAPE\n");
1947 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1949 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1950 cbeend.fChanged = FALSE;
1951 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1952 CB_GETCURSEL, 0, 0);
1953 cbeend.iWhy = CBENF_ESCAPE;
1955 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
1956 /* abort the change */
1957 TRACE("Notify requested abort of change\n");
1960 oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
1961 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1962 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
1963 ERR("item %d not found. Problem!\n", oldItem);
1966 infoPtr->selected = oldItem;
1967 COMBOEX_SetEditText (infoPtr, item);
1968 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
1973 /* native version seems to do following for COMBOEX */
1975 * GetWindowTextA(Edit,&?, 0x104) x
1976 * CB_GETCURSEL to Combo rets -1 x
1977 * CB_GETCOUNT to Combo rets 0
1979 * CB_GETITEMDATA to match
1980 * *** above 3 lines simulated by FindItem x
1981 * WM_NOTIFY to COMBOEX parent (rebar) x
1982 * (CBEN_ENDEDIT{A|W} x
1983 * fChanged = TRUE (-1) x
1984 * iNewSelection = -1 or selected x
1986 * iWhy = 2 (CBENF_RETURN) x
1987 * CB_GETCURSEL to Combo rets -1 x
1988 * if -1 send CB_SETCURSEL to Combo -1 x
1989 * InvalidateRect(Combo, 0, 0) x
1991 * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
1994 TRACE("special code for VK_RETURN\n");
1996 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1998 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1999 selected = SendMessageW (infoPtr->hwndCombo,
2000 CB_GETCURSEL, 0, 0);
2002 if (selected != -1) {
2003 item = COMBOEX_FindItem (infoPtr, selected);
2004 TRACE("handling VK_RETURN, selected = %d, selected_text=%s\n",
2005 selected, debugstr_w(item->pszText));
2006 TRACE("handling VK_RETURN, edittext=%s\n",
2007 debugstr_w(edit_text));
2008 if (lstrcmpiW (item->pszText, edit_text)) {
2009 /* strings not equal -- indicate edit has changed */
2014 cbeend.iNewSelection = selected;
2015 cbeend.fChanged = TRUE;
2016 cbeend.iWhy = CBENF_RETURN;
2017 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
2018 /* abort the change, restore previous */
2019 TRACE("Notify requested abort of change\n");
2020 COMBOEX_SetEditText (infoPtr, infoPtr->edit);
2021 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
2025 oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
2026 if (oldItem != -1) {
2027 /* if something is selected, then deselect it */
2028 SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL,
2031 InvalidateRect (infoPtr->hwndCombo, 0, 0);
2032 SetFocus(infoPtr->hwndEdit);
2036 return CallWindowProcA (infoPtr->prevEditWndProc,
2037 hwnd, uMsg, wParam, lParam);
2043 /* remember the focus to set state of icon */
2044 lret = CallWindowProcA (infoPtr->prevEditWndProc,
2045 hwnd, uMsg, wParam, lParam);
2046 infoPtr->flags |= WCBE_EDITFOCUSED;
2051 * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
2053 infoPtr->flags &= ~WCBE_EDITFOCUSED;
2054 if (infoPtr->flags & WCBE_ACTEDIT) {
2055 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
2057 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
2058 cbeend.fChanged = FALSE;
2059 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
2060 CB_GETCURSEL, 0, 0);
2061 cbeend.iWhy = CBENF_KILLFOCUS;
2063 COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text);
2068 return CallWindowProcA (infoPtr->prevEditWndProc,
2069 hwnd, uMsg, wParam, lParam);
2075 static LRESULT WINAPI
2076 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2078 COMBOEX_INFO *infoPtr = (COMBOEX_INFO *)GetPropA (hwnd, (LPCSTR)(LONG) ComboExInfo);
2079 NMCBEENDEDITW cbeend;
2081 COLORREF nbkc, obkc;
2085 WCHAR edit_text[260];
2087 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
2088 hwnd, uMsg, wParam, lParam, infoPtr);
2090 if (!infoPtr) return 0;
2095 case CB_FINDSTRINGEXACT:
2096 return COMBOEX_FindStringExact (infoPtr, wParam, lParam);
2100 * The only way this message should come is from the
2101 * child Listbox issuing the message. Flag this so
2102 * that ComboEx knows this is listbox.
2104 ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
2105 return CallWindowProcA (infoPtr->prevComboWndProc,
2106 hwnd, uMsg, wParam, lParam);
2110 * The following was determined by traces of the native
2113 nbkc = GetSysColor (COLOR_WINDOW);
2114 obkc = SetBkColor (hDC, nbkc);
2115 GetClientRect (hwnd, &rect);
2116 TRACE("erasing (%d,%d)-(%d,%d)\n",
2117 rect.left, rect.top, rect.right, rect.bottom);
2118 ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
2119 SetBkColor (hDC, obkc);
2120 return CallWindowProcA (infoPtr->prevComboWndProc,
2121 hwnd, uMsg, wParam, lParam);
2125 * WM_NOTIFY to comboex parent (rebar)
2126 * with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001
2127 * CallWindowProc (previous)
2129 nmmse.dwItemSpec = 0;
2130 nmmse.dwItemData = 0;
2133 nmmse.dwHitInfo = lParam;
2134 COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
2135 return CallWindowProcA (infoPtr->prevComboWndProc,
2136 hwnd, uMsg, wParam, lParam);
2139 switch (HIWORD(wParam)) {
2142 /* traces show that COMBOEX does not issue CBN_EDITUPDATE
2151 * GetFocus() retns AA
2152 * GetWindowTextA(Edit)
2153 * CB_GETCURSEL(Combo) (got -1)
2154 * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
2155 * CB_GETCURSEL(Combo) (got -1)
2156 * InvalidateRect(Combo, 0, 0)
2157 * WM_KILLFOCUS(Combo, AA)
2160 focusedhwnd = GetFocus();
2161 if (infoPtr->flags & WCBE_ACTEDIT) {
2162 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
2163 cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
2164 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
2165 CB_GETCURSEL, 0, 0);
2166 cbeend.iWhy = CBENF_KILLFOCUS;
2168 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
2169 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
2170 /* abort the change */
2171 TRACE("Notify requested abort of change\n");
2175 /* possible CB_GETCURSEL */
2176 InvalidateRect (infoPtr->hwndCombo, 0, 0);
2178 SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS,
2179 (WPARAM)focusedhwnd, 0);
2184 * For EN_SETFOCUS this issues the same calls and messages
2185 * as the native seems to do.
2187 * for some cases however native does the following:
2188 * (noticed after SetFocus during LBUTTONDOWN on
2189 * on dropdown arrow)
2190 * WM_GETTEXTLENGTH (Edit);
2191 * WM_GETTEXT (Edit, len+1, str);
2192 * EM_SETSEL (Edit, 0, 0);
2193 * WM_GETTEXTLENGTH (Edit);
2194 * WM_GETTEXT (Edit, len+1, str);
2195 * EM_SETSEL (Edit, 0, len);
2196 * WM_NOTIFY (parent, CBEN_BEGINEDIT)
2200 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
2201 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
2202 COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr);
2203 infoPtr->flags |= WCBE_ACTEDIT;
2204 infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */
2210 * For EN_CHANGE this issues the same calls and messages
2211 * as the native seems to do.
2213 WCHAR edit_text[260];
2218 selected = SendMessageW (infoPtr->hwndCombo,
2219 CB_GETCURSEL, 0, 0);
2221 /* lstrlenA( lastworkingURL ) */
2223 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
2224 if (selected == -1) {
2225 lastwrk = infoPtr->edit->pszText;
2226 cnt = lstrlenW (lastwrk);
2227 if (cnt >= 259) cnt = 259;
2230 item = COMBOEX_FindItem (infoPtr, selected);
2231 cnt = lstrlenW (item->pszText);
2232 lastwrk = item->pszText;
2233 if (cnt >= 259) cnt = 259;
2236 TRACE("handling EN_CHANGE, selected = %d, selected_text=%s\n",
2237 selected, debugstr_w(lastwrk));
2238 TRACE("handling EN_CHANGE, edittext=%s\n",
2239 debugstr_w(edit_text));
2241 /* lstrcmpiW is between lastworkingURL and GetWindowText */
2243 if (lstrcmpiW (lastwrk, edit_text)) {
2244 /* strings not equal -- indicate edit has changed */
2245 infoPtr->flags |= WCBE_EDITCHG;
2247 SendMessageW ( GetParent(infoPtr->hwndSelf), WM_COMMAND,
2248 MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf),
2256 * Therefore from traces there is no additional code here
2260 * Using native COMCTL32 gets the following:
2261 * 1 == SHDOCVW.DLL issues call/message
2262 * 2 == COMCTL32.DLL issues call/message
2263 * 3 == WINE issues call/message
2266 * for LBN_SELCHANGE:
2267 * 1 CB_GETCURSEL(ComboEx)
2268 * 1 CB_GETDROPPEDSTATE(ComboEx)
2269 * 1 CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE)
2270 * 2 CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE)
2271 ** call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE)
2272 * 3 WM_COMMAND(ComboEx, CBN_SELENDOK)
2273 * WM_USER+49(ComboLB, 1,0) <=============!!!!!!!!!!!
2274 * 3 ShowWindow(ComboLB, SW_HIDE)
2275 * 3 RedrawWindow(Combo, RDW_UPDATENOW)
2276 * 3 WM_COMMAND(ComboEX, CBN_CLOSEUP)
2278 * 3 WM_COMMAND(ComboEx, CBN_SELCHANGE) (echo to parent)
2279 * ? LB_GETCURSEL <==|
2281 * ? LB_GETTEXT | Needs to be added to
2282 * ? WM_CTLCOLOREDIT(ComboEx) | Combo processing
2283 * ? LB_GETITEMDATA |
2284 * ? WM_DRAWITEM(ComboEx) <==|
2290 return CallWindowProcA (infoPtr->prevComboWndProc,
2291 hwnd, uMsg, wParam, lParam);
2297 static LRESULT WINAPI
2298 COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2300 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
2302 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2304 if (!COMBOEX_GetInfoPtr (hwnd)) {
2305 if (uMsg == WM_CREATE)
2306 return COMBOEX_Create (hwnd, wParam, lParam);
2307 if (uMsg == WM_NCCREATE)
2308 COMBOEX_NCCreate (hwnd, wParam, lParam);
2309 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2314 case CBEM_DELETEITEM: /* maps to CB_DELETESTRING */
2315 return COMBOEX_DeleteItem (hwnd, wParam, lParam);
2317 case CBEM_GETCOMBOCONTROL:
2318 return COMBOEX_GetComboControl (hwnd, wParam, lParam);
2320 case CBEM_GETEDITCONTROL:
2321 return COMBOEX_GetEditControl (hwnd, wParam, lParam);
2323 case CBEM_GETEXTENDEDSTYLE:
2324 return COMBOEX_GetExtendedStyle (hwnd, wParam, lParam);
2326 case CBEM_GETIMAGELIST:
2327 return COMBOEX_GetImageList (hwnd, wParam, lParam);
2330 return COMBOEX_GetItemA (hwnd, wParam, lParam);
2333 return COMBOEX_GetItemW (hwnd, wParam, lParam);
2335 case CBEM_GETUNICODEFORMAT:
2336 return COMBOEX_GetUnicodeFormat (hwnd, wParam, lParam);
2338 case CBEM_HASEDITCHANGED:
2339 return COMBOEX_HasEditChanged (hwnd, wParam, lParam);
2341 case CBEM_INSERTITEMA:
2342 return COMBOEX_InsertItemA (hwnd, wParam, lParam);
2344 case CBEM_INSERTITEMW:
2345 return COMBOEX_InsertItemW (hwnd, wParam, lParam);
2347 case CBEM_SETEXSTYLE: /* FIXME: obsoleted, should be the same as: */
2348 case CBEM_SETEXTENDEDSTYLE:
2349 return COMBOEX_SetExtendedStyle (hwnd, wParam, lParam);
2351 case CBEM_SETIMAGELIST:
2352 return COMBOEX_SetImageList (hwnd, wParam, lParam);
2355 return COMBOEX_SetItemA (hwnd, wParam, lParam);
2358 return COMBOEX_SetItemW (hwnd, wParam, lParam);
2360 case CBEM_SETUNICODEFORMAT:
2361 return COMBOEX_SetUnicodeFormat (hwnd, wParam, lParam);
2364 /* Combo messages we are not sure if we need to process or just forward */
2365 case CB_GETDROPPEDCONTROLRECT:
2366 case CB_GETITEMHEIGHT:
2368 case CB_GETLBTEXTLEN:
2369 case CB_GETEXTENDEDUI:
2371 case CB_RESETCONTENT:
2372 case CB_SELECTSTRING:
2375 FIXME("(0x%x 0x%x 0x%lx): possibly missing function\n",
2376 uMsg, wParam, lParam);
2377 return COMBOEX_Forward (hwnd, uMsg, wParam, lParam);
2379 /* Combo messages OK to just forward to the regular COMBO */
2382 case CB_GETDROPPEDSTATE:
2383 case CB_SETDROPPEDWIDTH:
2384 case CB_SETEXTENDEDUI:
2385 case CB_SHOWDROPDOWN:
2386 return COMBOEX_Forward (hwnd, uMsg, wParam, lParam);
2388 /* Combo messages we need to process specially */
2389 case CB_FINDSTRINGEXACT:
2390 return COMBOEX_FindStringExact (COMBOEX_GetInfoPtr (hwnd),
2393 case CB_GETITEMDATA:
2394 return COMBOEX_GetItemData (hwnd, wParam, lParam);
2397 return COMBOEX_SetCursel (hwnd, wParam, lParam);
2399 case CB_SETITEMDATA:
2400 return COMBOEX_SetItemData (hwnd, wParam, lParam);
2402 case CB_SETITEMHEIGHT:
2403 return COMBOEX_SetItemHeight (hwnd, wParam, lParam);
2407 /* Window messages passed to parent */
2409 return COMBOEX_Command (hwnd, wParam, lParam);
2412 if (infoPtr->NtfUnicode)
2413 return SendMessageW (GetParent (hwnd),
2414 uMsg, wParam, lParam);
2416 return SendMessageA (GetParent (hwnd),
2417 uMsg, wParam, lParam);
2420 /* Window messages we need to process */
2422 return COMBOEX_WM_DeleteItem (hwnd, wParam, lParam);
2425 return COMBOEX_DrawItem (hwnd, wParam, lParam);
2428 return COMBOEX_Destroy (hwnd, wParam, lParam);
2430 case WM_MEASUREITEM:
2431 return COMBOEX_MeasureItem (hwnd, wParam, lParam);
2433 case WM_NOTIFYFORMAT:
2434 return COMBOEX_NotifyFormat (hwnd, wParam, lParam);
2437 return COMBOEX_Size (hwnd, wParam, lParam);
2439 case WM_WINDOWPOSCHANGING:
2440 return COMBOEX_WindowPosChanging (hwnd, wParam, lParam);
2443 if (uMsg >= WM_USER)
2444 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
2445 uMsg, wParam, lParam);
2446 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2453 COMBOEX_Register (void)
2457 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
2458 wndClass.style = CS_GLOBALCLASS;
2459 wndClass.lpfnWndProc = (WNDPROC)COMBOEX_WindowProc;
2460 wndClass.cbClsExtra = 0;
2461 wndClass.cbWndExtra = sizeof(COMBOEX_INFO *);
2462 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
2463 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2464 wndClass.lpszClassName = WC_COMBOBOXEXA;
2466 RegisterClassA (&wndClass);
2468 ComboExInfo = GlobalAddAtomA("CC32SubclassInfo");
2473 COMBOEX_Unregister (void)
2475 UnregisterClassA (WC_COMBOBOXEXA, (HINSTANCE)NULL);