2 * ComboBoxEx control v2 (mod3)
4 * Copyright 1998, 1999 Eric Kohl
7 * This is just a dummy control. An author is needed! Any volunteers?
8 * I will only improve this control once in a while.
9 * Eric <ekohl@abo.rhein-zeitung.de>
13 * - All notifications.
16 * - should include "combo.h"
18 * Changes Guy Albertelli <galberte@neo.lrun.com>
19 * v1 Implemented messages: CB_SETITEMHEIGHT, WM_WINDOWPOSCHANGING,
20 * WM_DRAWITEM, and WM_MEASUREITEM. Fixed WM_CREATE. Fixed height
21 * of window rect reported fixing rebar control.
23 * 1. Rewrite of WM_Create for own created EDIT control. Also try to
24 * generate message sequence similar to native DLL.
25 * 2. Handle case where CBEM_SETITEM is called to display data in EDIT
27 * 3. Add override for WNDPROC for the EDIT control (reqed for VK_RETURN).
28 * 4. Dump input data for things using COMBOBOXEXITEM{A|W}.
29 * 5. Handle positioning EDIT control based on whether icon present.
30 * 6. Make InsertItemA use InsertItemW, and store all data in ..W form.
31 * 7. Implement CB_SETCURSEL.
32 * 8. Add override for WNDPROC for the COMBO control.
34 * Test vehicals were the ControlSpy modules (rebar.exe and comboboxex.exe),
42 #include "debugtools.h"
43 #include "wine/unicode.h"
45 DEFAULT_DEBUG_CHANNEL(comboex
);
47 * The following is necessary for the test done in COMBOEX_DrawItem
48 * to determine whether to dump out the DRAWITEM structure or not.
50 DECLARE_DEBUG_CHANNEL(message
);
66 /* ComboBoxEx structure */
70 HWND hwndSelf
; /* my own hwnd */
73 WNDPROC prevEditWndProc
; /* previous Edit WNDPROC value */
74 WNDPROC prevComboWndProc
; /* previous Combo WNDPROC value */
76 DWORD flags
; /* WINE internal flags */
78 INT nb_items
; /* Number of items */
79 CBE_ITEMDATA
*edit
; /* item data for edit item */
80 CBE_ITEMDATA
*items
; /* Array of items */
83 /* internal flags in the COMBOEX_INFO structure */
84 #define WCBE_ACTEDIT 0x00000001 /* Edit active i.e.
85 * CBEN_BEGINEDIT issued
86 * but CBEN_ENDEDIT{A|W}
91 #define ID_CB_EDIT 1001
93 /* Height in pixels of control over the amount of the selected font */
96 /* Indent amount per MS documentation */
99 /* Offset in pixels from left side for start of image or text */
100 #define CBE_STARTOFFSET 6
102 /* Offset between image and text */
105 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongA (hwnd, 0))
108 /* Things common to the entire DLL */
109 static ATOM ComboExInfo
;
110 static LRESULT WINAPI
111 COMBOEX_EditWndProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
112 static LRESULT WINAPI
113 COMBOEX_ComboWndProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
116 COMBOEX_DumpItem (CBE_ITEMDATA
*item
)
118 if (TRACE_ON(comboex
)){
119 TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
120 item
, item
->mask
, item
->pszText
, item
->cchTextMax
,
122 TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
123 item
, item
->iSelectedImage
, item
->iOverlay
, item
->iIndent
, item
->lParam
);
124 if ((item
->mask
& CBEIF_TEXT
) && item
->pszText
)
125 TRACE("item %p - pszText=%s\n",
126 item
, debugstr_w((const WCHAR
*)item
->pszText
));
132 COMBOEX_DumpInput (COMBOBOXEXITEMA
*input
, BOOL true_for_w
)
134 if (TRACE_ON(comboex
)){
135 TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n",
136 input
->mask
, input
->iItem
, input
->pszText
, input
->cchTextMax
,
138 if ((input
->mask
& CBEIF_TEXT
) && input
->pszText
) {
140 TRACE("input - pszText=<%s>\n",
141 debugstr_w((const WCHAR
*)input
->pszText
));
143 TRACE("input - pszText=<%s>\n",
144 debugstr_a((const char *)input
->pszText
));
146 TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
147 input
->iSelectedImage
, input
->iOverlay
, input
->iIndent
, input
->lParam
);
152 inline static LRESULT
153 COMBOEX_Forward (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
155 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
157 FIXME("(0x%x 0x%x 0x%lx): stub\n", uMsg
, wParam
, lParam
);
159 if (infoPtr
->hwndCombo
)
160 return SendMessageA (infoPtr
->hwndCombo
, uMsg
, wParam
, lParam
);
167 COMBOEX_Notify (COMBOEX_INFO
*infoPtr
, INT code
, NMHDR
*hdr
)
170 hdr
->idFrom
= GetDlgCtrlID (infoPtr
->hwndSelf
);
171 hdr
->hwndFrom
= infoPtr
->hwndSelf
;
173 return SendMessageA (GetParent(infoPtr
->hwndSelf
), WM_NOTIFY
, 0,
179 COMBOEX_GetComboFontSize (COMBOEX_INFO
*infoPtr
, SIZE
*size
)
184 mydc
= GetDC (0); /* why the entire screen???? */
185 nfont
= SendMessageA (infoPtr
->hwndCombo
, WM_GETFONT
, 0, 0);
186 ofont
= (HFONT
) SelectObject (mydc
, nfont
);
187 GetTextExtentPointA (mydc
, "A", 1, size
);
188 SelectObject (mydc
, ofont
);
190 TRACE("selected font hwnd=%08x, height=%ld\n", nfont
, size
->cy
);
195 COMBOEX_AdjustEditPos (COMBOEX_INFO
*infoPtr
)
199 INT x
, y
, w
, h
, xoff
= 0;
202 if (!infoPtr
->hwndEdit
) return;
203 iinfo
.rcImage
.left
= iinfo
.rcImage
.right
= 0;
205 ImageList_GetImageInfo(infoPtr
->himl
, 0, &iinfo
);
206 xoff
= iinfo
.rcImage
.right
- iinfo
.rcImage
.left
+ CBE_SEP
;
208 GetClientRect (infoPtr
->hwndCombo
, &rect
);
209 InflateRect (&rect
, -2, -2);
210 InvalidateRect (infoPtr
->hwndCombo
, &rect
, TRUE
);
212 /* reposition the Edit control based on whether icon exists */
213 COMBOEX_GetComboFontSize (infoPtr
, &mysize
);
214 TRACE("Combo font x=%ld, y=%ld\n", mysize
.cx
, mysize
.cy
);
215 x
= xoff
+ CBE_STARTOFFSET
;
217 w
= rect
.right
-rect
.left
- x
- GetSystemMetrics(SM_CXVSCROLL
) - 1;
220 TRACE("Combo client (%d,%d)-(%d,%d), setting Edit to (%d,%d)-(%d,%d)\n",
221 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
,
223 SetWindowPos(infoPtr
->hwndEdit
, HWND_TOP
,
226 SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
231 COMBOEX_ReSize (HWND hwnd
, COMBOEX_INFO
*infoPtr
)
237 COMBOEX_GetComboFontSize (infoPtr
, &mysize
);
238 cy
= mysize
.cy
+ CBE_EXTRA
;
240 ImageList_GetImageInfo(infoPtr
->himl
, 0, &iinfo
);
241 cy
= max (iinfo
.rcImage
.bottom
- iinfo
.rcImage
.top
, cy
);
242 TRACE("upgraded height due to image: height=%d\n", cy
);
244 SendMessageA (hwnd
, CB_SETITEMHEIGHT
, (WPARAM
) -1, (LPARAM
) cy
);
245 if (infoPtr
->hwndCombo
)
246 SendMessageA (infoPtr
->hwndCombo
, CB_SETITEMHEIGHT
,
247 (WPARAM
) 0, (LPARAM
) cy
);
252 COMBOEX_SetEditText (COMBOEX_INFO
*infoPtr
, CBE_ITEMDATA
*item
)
254 if (!infoPtr
->hwndEdit
) return;
255 /* native issues the following messages to the {Edit} control */
256 /* WM_SETTEXT (0,addr) */
257 /* EM_SETSEL32 (0,0) */
258 /* EM_SETSEL32 (0,-1) */
259 if (item
->mask
& CBEIF_TEXT
) {
260 SendMessageW (infoPtr
->hwndEdit
, WM_SETTEXT
, 0, (LPARAM
)item
->pszText
);
261 SendMessageA (infoPtr
->hwndEdit
, EM_SETSEL
, 0, 0);
262 SendMessageA (infoPtr
->hwndEdit
, EM_SETSEL
, 0, -1);
267 static CBE_ITEMDATA
*
268 COMBOEX_FindItem(COMBOEX_INFO
*infoPtr
, INT index
)
273 if ((index
> infoPtr
->nb_items
) || (index
< -1))
276 return infoPtr
->edit
;
277 item
= infoPtr
->items
;
278 i
= infoPtr
->nb_items
- 1;
280 /* find the item in the list */
281 while (item
&& (i
> index
)) {
282 item
= (CBE_ITEMDATA
*)item
->next
;
285 if (!item
|| (i
!= index
)) {
286 FIXME("COMBOBOXEX item structures broken. Please report!\n");
293 /* *** CBEM_xxx message support *** */
296 /* << COMBOEX_DeleteItem >> */
299 inline static LRESULT
300 COMBOEX_GetComboControl (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
302 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
306 return (LRESULT
)infoPtr
->hwndCombo
;
310 inline static LRESULT
311 COMBOEX_GetEditControl (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
313 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
315 if ((GetWindowLongA (hwnd
, GWL_STYLE
) & CBS_DROPDOWNLIST
) != CBS_DROPDOWN
)
318 TRACE("-- 0x%x\n", infoPtr
->hwndEdit
);
320 return (LRESULT
)infoPtr
->hwndEdit
;
324 inline static LRESULT
325 COMBOEX_GetExtendedStyle (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
327 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
329 return (LRESULT
)infoPtr
->dwExtStyle
;
333 inline static LRESULT
334 COMBOEX_GetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
336 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
338 TRACE("(0x%08x 0x%08lx)\n", wParam
, lParam
);
340 return (LRESULT
)infoPtr
->himl
;
344 /* << COMBOEX_GetItemA >> */
346 /* << COMBOEX_GetItemW >> */
348 /* << COMBOEX_GetUniCodeFormat >> */
352 COMBOEX_HasEditChanged (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
354 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
356 if ((GetWindowLongA (hwnd
, GWL_STYLE
) & CBS_DROPDOWNLIST
) != CBS_DROPDOWN
)
358 if (infoPtr
->flags
& WCBE_ACTEDIT
)
359 /* FIXME: need to also test edit control */
366 COMBOEX_InsertItemW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
368 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
369 COMBOBOXEXITEMW
*cit
= (COMBOBOXEXITEMW
*) lParam
;
373 COMBOEX_DumpInput ((COMBOBOXEXITEMA
*) cit
, TRUE
);
375 /* get real index of item to insert */
377 if (index
== -1) index
= infoPtr
->nb_items
;
378 if (index
> infoPtr
->nb_items
) index
= infoPtr
->nb_items
;
380 /* get space and chain it in */
381 item
= (CBE_ITEMDATA
*)COMCTL32_Alloc (sizeof (CBE_ITEMDATA
));
383 item
->pszText
= NULL
;
385 /* locate position to insert new item in */
386 if (index
== infoPtr
->nb_items
) {
387 /* fast path for iItem = -1 */
388 item
->next
= infoPtr
->items
;
389 infoPtr
->items
= item
;
392 INT i
= infoPtr
->nb_items
-1;
393 CBE_ITEMDATA
*moving
= infoPtr
->items
;
395 while ((i
> index
) && moving
) {
396 moving
= (CBE_ITEMDATA
*)moving
->next
;
400 FIXME("COMBOBOXEX item structures broken. Please report!\n");
404 item
->next
= moving
->next
;
408 /* fill in our hidden item structure */
409 item
->mask
= cit
->mask
;
410 if (item
->mask
& CBEIF_TEXT
) {
415 if (!str
) str
= (LPWSTR
) L
"";
418 item
->pszText
= (LPWSTR
)COMCTL32_Alloc ((len
+ 1)*sizeof(WCHAR
));
419 strcpyW (item
->pszText
, str
);
421 item
->cchTextMax
= cit
->cchTextMax
;
423 if (item
->mask
& CBEIF_IMAGE
)
424 item
->iImage
= cit
->iImage
;
425 if (item
->mask
& CBEIF_SELECTEDIMAGE
)
426 item
->iSelectedImage
= cit
->iSelectedImage
;
427 if (item
->mask
& CBEIF_OVERLAY
)
428 item
->iOverlay
= cit
->iOverlay
;
429 if (item
->mask
& CBEIF_INDENT
)
430 item
->iIndent
= cit
->iIndent
;
431 if (item
->mask
& CBEIF_LPARAM
)
432 item
->lParam
= cit
->lParam
;
435 COMBOEX_DumpItem (item
);
437 SendMessageA (infoPtr
->hwndCombo
, CB_INSERTSTRING
,
438 (WPARAM
)cit
->iItem
, (LPARAM
)item
);
446 COMBOEX_InsertItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
448 COMBOBOXEXITEMA
*cit
= (COMBOBOXEXITEMA
*) lParam
;
449 COMBOBOXEXITEMW citW
;
452 memcpy(&citW
,cit
,sizeof(COMBOBOXEXITEMA
));
453 if (cit
->mask
& CBEIF_TEXT
) {
459 len
= MultiByteToWideChar (CP_ACP
, 0, str
, -1, NULL
, 0);
461 citW
.pszText
= (LPWSTR
)COMCTL32_Alloc ((len
+ 1)*sizeof(WCHAR
));
462 MultiByteToWideChar (CP_ACP
, 0, str
, -1, citW
.pszText
, len
);
465 ret
= COMBOEX_InsertItemW(hwnd
,wParam
,(LPARAM
)&citW
);;
467 if (cit
->mask
& CBEIF_TEXT
)
468 COMCTL32_Free(citW
.pszText
);
474 COMBOEX_SetExtendedStyle (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
476 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
479 TRACE("(0x%08x 0x%08lx)\n", wParam
, lParam
);
481 dwTemp
= infoPtr
->dwExtStyle
;
484 infoPtr
->dwExtStyle
= (infoPtr
->dwExtStyle
& ~(DWORD
)wParam
) | (DWORD
)lParam
;
487 infoPtr
->dwExtStyle
= (DWORD
)lParam
;
489 /* FIXME: repaint?? */
491 return (LRESULT
)dwTemp
;
495 inline static LRESULT
496 COMBOEX_SetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
498 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
501 TRACE("(0x%08x 0x%08lx)\n", wParam
, lParam
);
503 himlTemp
= infoPtr
->himl
;
504 infoPtr
->himl
= (HIMAGELIST
)lParam
;
506 COMBOEX_ReSize (hwnd
, infoPtr
);
507 InvalidateRect (infoPtr
->hwndCombo
, NULL
, TRUE
);
509 /* reposition the Edit control based on whether icon exists */
510 COMBOEX_AdjustEditPos (infoPtr
);
511 return (LRESULT
)himlTemp
;
515 COMBOEX_SetItemW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
517 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
518 COMBOBOXEXITEMW
*cit
= (COMBOBOXEXITEMW
*) lParam
;
522 COMBOEX_DumpInput ((COMBOBOXEXITEMA
*) cit
, TRUE
);
524 /* get real index of item to insert */
527 /* if item number requested does not exist then return failure */
528 if ((index
> infoPtr
->nb_items
) || (index
< -1)) {
529 ERR("attempt to set item that does not exist yet!\n");
533 /* if the item is the edit control and there is no edit control, skip */
535 ((GetWindowLongA (hwnd
, GWL_STYLE
) & CBS_DROPDOWNLIST
) != CBS_DROPDOWN
))
538 if (!(item
= COMBOEX_FindItem(infoPtr
, index
))) {
539 ERR("attempt to set item that was not found!\n");
543 /* add/change stuff to the internal item structure */
544 item
->mask
|= cit
->mask
;
545 if (cit
->mask
& CBEIF_TEXT
) {
548 WCHAR emptystr
[1] = {0};
551 if (!str
) str
=emptystr
;
554 item
->pszText
= (LPWSTR
)COMCTL32_Alloc ((len
+ 1)*sizeof(WCHAR
));
555 strcpyW(item
->pszText
,str
);
557 item
->cchTextMax
= cit
->cchTextMax
;
559 if (cit
->mask
& CBEIF_IMAGE
)
560 item
->iImage
= cit
->iImage
;
561 if (cit
->mask
& CBEIF_SELECTEDIMAGE
)
562 item
->iSelectedImage
= cit
->iSelectedImage
;
563 if (cit
->mask
& CBEIF_OVERLAY
)
564 item
->iOverlay
= cit
->iOverlay
;
565 if (cit
->mask
& CBEIF_INDENT
)
566 item
->iIndent
= cit
->iIndent
;
567 if (cit
->mask
& CBEIF_LPARAM
)
568 cit
->lParam
= cit
->lParam
;
570 COMBOEX_DumpItem (item
);
572 /* if original request was to update edit control, do some fast foot work */
573 if (cit
->iItem
== -1) {
574 COMBOEX_SetEditText (infoPtr
, item
);
575 RedrawWindow (infoPtr
->hwndCombo
, 0, 0, RDW_ERASE
| RDW_INVALIDATE
);
581 COMBOEX_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
583 COMBOBOXEXITEMA
*cit
= (COMBOBOXEXITEMA
*) lParam
;
584 COMBOBOXEXITEMW citW
;
587 memcpy(&citW
,cit
,sizeof(COMBOBOXEXITEMA
));
588 if (cit
->mask
& CBEIF_TEXT
) {
594 len
= MultiByteToWideChar (CP_ACP
, 0, str
, -1, NULL
, 0);
596 citW
.pszText
= (LPWSTR
)COMCTL32_Alloc ((len
+ 1)*sizeof(WCHAR
));
597 MultiByteToWideChar (CP_ACP
, 0, str
, -1, citW
.pszText
, len
);
600 ret
= COMBOEX_SetItemW(hwnd
,wParam
,(LPARAM
)&citW
);;
602 if (cit
->mask
& CBEIF_TEXT
)
603 COMCTL32_Free(citW
.pszText
);
608 /* << COMBOEX_SetUniCodeFormat >> */
611 /* *** CB_xxx message support *** */
615 COMBOEX_SetCursel (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
618 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
621 if (!(item
= COMBOEX_FindItem(infoPtr
, index
))) {
622 /* FIXME: need to clear selection */
626 TRACE("selecting item %d\n", index
);
628 COMBOEX_SetEditText (infoPtr
, item
);
629 if (infoPtr
->hwndCombo
)
630 return SendMessageA (infoPtr
->hwndCombo
, CB_SETCURSEL
, wParam
, lParam
);
636 COMBOEX_SetItemHeight (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
638 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
639 RECT cb_wrect
, cbx_wrect
, cbx_crect
;
643 /* First, lets forward the message to the normal combo control
644 just like Windows. */
645 if (infoPtr
->hwndCombo
)
646 SendMessageA (infoPtr
->hwndCombo
, CB_SETITEMHEIGHT
, wParam
, lParam
);
648 GetWindowRect (infoPtr
->hwndCombo
, &cb_wrect
);
649 GetWindowRect (hwnd
, &cbx_wrect
);
650 GetClientRect (hwnd
, &cbx_crect
);
651 /* the height of comboex as height of the combo + comboex border */
652 height
= cb_wrect
.bottom
-cb_wrect
.top
653 + cbx_wrect
.bottom
-cbx_wrect
.top
654 - (cbx_crect
.bottom
-cbx_crect
.top
);
655 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
656 cbx_wrect
.left
, cbx_wrect
.top
, cbx_wrect
.right
, cbx_wrect
.bottom
,
657 cbx_crect
.left
, cbx_crect
.top
, cbx_crect
.right
, cbx_crect
.bottom
);
658 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
659 cb_wrect
.left
, cb_wrect
.top
, cb_wrect
.right
, cb_wrect
.bottom
,
660 cbx_wrect
.right
-cbx_wrect
.left
, height
);
661 SetWindowPos (hwnd
, HWND_TOP
, 0, 0,
662 cbx_wrect
.right
-cbx_wrect
.left
,
664 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOMOVE
);
670 /* *** WM_xxx message support *** */
674 COMBOEX_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
676 LPCREATESTRUCTA cs
= (LPCREATESTRUCTA
) lParam
;
677 COMBOEX_INFO
*infoPtr
;
681 RECT wnrc1
, clrc1
, cmbwrc
;
684 /* allocate memory for info structure */
685 infoPtr
= (COMBOEX_INFO
*)COMCTL32_Alloc (sizeof(COMBOEX_INFO
));
686 if (infoPtr
== NULL
) {
687 ERR("could not allocate info memory!\n");
691 /* initialize info structure */
693 infoPtr
->items
= NULL
;
694 infoPtr
->nb_items
= 0;
695 infoPtr
->hwndSelf
= hwnd
;
697 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
699 /* create combo box */
700 dwComboStyle
= GetWindowLongA (hwnd
, GWL_STYLE
) &
701 (CBS_SIMPLE
|CBS_DROPDOWN
|CBS_DROPDOWNLIST
|WS_CHILD
);
703 TRACE("combo style=%08lx, additional style=%08lx\n", dwComboStyle
,
704 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_VSCROLL
|
705 CBS_NOINTEGRALHEIGHT
| CBS_DROPDOWNLIST
|
706 WS_CHILD
| WS_VISIBLE
| CBS_OWNERDRAWFIXED
);
708 /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
709 /* specified. It then creates it's own version of the EDIT control */
710 /* and makes the ComboBox the parent. This is because a normal */
711 /* DROPDOWNLIST does not have a EDIT control, but we need one. */
712 /* We also need to place the edit control at the proper location */
713 /* (allow space for the icons). */
715 infoPtr
->hwndCombo
= CreateWindowA ("ComboBox", "",
716 /* following line added to match native */
717 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_VSCROLL
|
718 CBS_NOINTEGRALHEIGHT
| CBS_DROPDOWNLIST
|
719 /* was base and is necessary */
720 WS_CHILD
| WS_VISIBLE
| CBS_OWNERDRAWFIXED
| dwComboStyle
,
721 cs
->y
, cs
->x
, cs
->cx
, cs
->cy
, hwnd
,
722 /* (HMENU) GetWindowLongA (hwnd, GWL_ID), */
723 /* */ (HMENU
) 0, /* */
724 GetWindowLongA (hwnd
, GWL_HINSTANCE
), NULL
);
727 /* ***** not needed any more ***** */
731 * The following does not work (WIN98 or later) but we need
732 * the list box handle for later
733 * SendMessageA(infoPtr->hwndCombo, CB_GETCOMBOBOXINFO, 0,
734 * (LPARAM) &comboinfo);
735 * infoPtr->hwndLBox = comboinfo.hwndList;
737 * So we need to violate philosophical separation by the following
740 lphc
= (LPHEADCOMBO
) GetWindowLongA(infoPtr
->hwndCombo
, 0);
741 infoPtr
->hwndLBox
= lphc
->hWndLBox
;
742 if (!infoPtr
->hwndLBox
) {
743 ERR("error error listbox handle zero\n");
748 * native does the following at this point according to trace:
749 * GetWindowThreadProcessId(hwndCombo,0)
750 * GetCurrentThreadId()
751 * GetWindowThreadProcessId(hwndCombo, &???)
752 * GetCurrentProcessId()
756 * Setup a property to hold the pointer to the COMBOBOXEX
759 test
= GetPropA(infoPtr
->hwndCombo
, (LPCSTR
)(LONG
)ComboExInfo
);
760 if (!test
|| ((COMBOEX_INFO
*)test
!= infoPtr
)) {
761 SetPropA(infoPtr
->hwndCombo
, "CC32SubclassInfo", (LONG
)infoPtr
);
763 infoPtr
->prevComboWndProc
= (WNDPROC
)SetWindowLongA(infoPtr
->hwndCombo
,
764 GWL_WNDPROC
, (LONG
)COMBOEX_ComboWndProc
);
765 infoPtr
->font
= SendMessageA (infoPtr
->hwndCombo
, WM_GETFONT
, 0, 0);
769 * Now create our own EDIT control so we can position it.
770 * It is created only for CBS_DROPDOWN style
772 if ((cs
->style
& CBS_DROPDOWNLIST
) == CBS_DROPDOWN
) {
773 infoPtr
->hwndEdit
= CreateWindowExA (0, "EDIT", "",
774 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| ES_AUTOHSCROLL
,
775 0, 0, 0, 0, /* will set later */
777 (HMENU
) GetWindowLongA (hwnd
, GWL_ID
),
778 GetWindowLongA (hwnd
, GWL_HINSTANCE
),
781 /* native does the following at this point according to trace:
782 * GetWindowThreadProcessId(hwndEdit,0)
783 * GetCurrentThreadId()
784 * GetWindowThreadProcessId(hwndEdit, &???)
785 * GetCurrentProcessId()
789 * Setup a property to hold the pointer to the COMBOBOXEX
792 test
= GetPropA(infoPtr
->hwndEdit
, (LPCSTR
)(LONG
)ComboExInfo
);
793 if (!test
|| ((COMBOEX_INFO
*)test
!= infoPtr
)) {
794 SetPropA(infoPtr
->hwndEdit
, "CC32SubclassInfo", (LONG
)infoPtr
);
796 infoPtr
->prevEditWndProc
= (WNDPROC
)SetWindowLongA(infoPtr
->hwndEdit
,
797 GWL_WNDPROC
, (LONG
)COMBOEX_EditWndProc
);
798 infoPtr
->font
= SendMessageA (infoPtr
->hwndCombo
, WM_GETFONT
, 0, 0);
801 infoPtr
->hwndEdit
= 0;
806 * Locate the default font if necessary and then set it in
807 * all associated controls
809 if (!infoPtr
->font
) {
810 SystemParametersInfoA (SPI_GETICONTITLELOGFONT
, sizeof(mylogfont
),
812 infoPtr
->font
= CreateFontIndirectA (&mylogfont
);
814 SendMessageA (infoPtr
->hwndCombo
, WM_SETFONT
, (WPARAM
)infoPtr
->font
, 0);
815 if (infoPtr
->hwndEdit
) {
816 SendMessageA (infoPtr
->hwndEdit
, WM_SETFONT
, (WPARAM
)infoPtr
->font
, 0);
817 SendMessageA (infoPtr
->hwndEdit
, EM_SETMARGINS
, (WPARAM
)EC_USEFONTINFO
, 0);
820 COMBOEX_ReSize (hwnd
, infoPtr
);
822 /* Above is fairly certain, below is much less certain. */
824 GetWindowRect(hwnd
, &wnrc1
);
825 GetClientRect(hwnd
, &clrc1
);
826 GetWindowRect(infoPtr
->hwndCombo
, &cmbwrc
);
827 TRACE("Ex wnd=(%d,%d)-(%d,%d) Ex clt=(%d,%d)-(%d,%d) Cb wnd=(%d,%d)-(%d,%d)\n",
828 wnrc1
.left
, wnrc1
.top
, wnrc1
.right
, wnrc1
.bottom
,
829 clrc1
.left
, clrc1
.top
, clrc1
.right
, clrc1
.bottom
,
830 cmbwrc
.left
, cmbwrc
.top
, cmbwrc
.right
, cmbwrc
.bottom
);
831 SetWindowPos(infoPtr
->hwndCombo
, HWND_TOP
,
832 0, 0, wnrc1
.right
-wnrc1
.left
, wnrc1
.bottom
-wnrc1
.top
,
833 SWP_NOACTIVATE
| SWP_NOREDRAW
);
835 GetWindowRect(infoPtr
->hwndCombo
, &cmbwrc
);
836 TRACE("Ex wnd=(%d,%d)-(%d,%d)\n",
837 cmbwrc
.left
, cmbwrc
.top
, cmbwrc
.right
, cmbwrc
.bottom
);
838 SetWindowPos(hwnd
, HWND_TOP
,
839 0, 0, cmbwrc
.right
-cmbwrc
.left
, cmbwrc
.bottom
-cmbwrc
.top
,
840 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOMOVE
);
842 COMBOEX_AdjustEditPos (infoPtr
);
845 * Create an item structure to represent the data in the
848 item
= (CBE_ITEMDATA
*)COMCTL32_Alloc (sizeof (CBE_ITEMDATA
));
850 item
->pszText
= NULL
;
852 infoPtr
->edit
= item
;
858 inline static LRESULT
859 COMBOEX_DrawItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
861 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
862 DRAWITEMSTRUCT
*dis
= (DRAWITEMSTRUCT
*)lParam
;
863 CBE_ITEMDATA
*item
= 0;
868 UINT xioff
= 0; /* size and spacer of image if any */
872 if (!IsWindowEnabled(infoPtr
->hwndCombo
)) return 0;
875 /* "itemID - Specifies the menu item identifier for a menu */
876 /* item or the index of the item in a list box or combo box. */
877 /* For an empty list box or combo box, this member can be -1. */
878 /* This allows the application to draw only the focus */
879 /* rectangle at the coordinates specified by the rcItem */
880 /* member even though there are no items in the control. */
881 /* This indicates to the user whether the list box or combo */
882 /* box has the focus. How the bits are set in the itemAction */
883 /* member determines whether the rectangle is to be drawn as */
884 /* though the list box or combo box has the focus. */
885 if (dis
->itemID
== 0xffffffff) {
886 if ( ( (dis
->itemAction
& ODA_FOCUS
) && (dis
->itemState
& ODS_SELECTED
)) ||
887 ( (dis
->itemAction
& (ODA_SELECT
| ODA_DRAWENTIRE
)) && (dis
->itemState
& ODS_FOCUS
) ) ) {
888 TRACE("drawing item -1 special focus, rect=(%d,%d)-(%d,%d)\n",
889 dis
->rcItem
.left
, dis
->rcItem
.top
,
890 dis
->rcItem
.right
, dis
->rcItem
.bottom
);
891 DrawFocusRect(dis
->hDC
, &dis
->rcItem
);
894 else if ((dis
->CtlType
== ODT_COMBOBOX
) &&
895 (dis
->itemAction
== ODA_DRAWENTIRE
) &&
896 (dis
->itemState
== 0)) {
897 /* draw of edit control data */
901 TRACE("drawing edit control\n");
902 item
= infoPtr
->edit
;
905 COMCTL32_Free(item
->pszText
);
907 item
->mask
&= ~CBEIF_TEXT
;
909 if (infoPtr
->hwndEdit
) {
910 alen
= SendMessageA (infoPtr
->hwndEdit
, WM_GETTEXT
, 260, (LPARAM
)&str
);
911 TRACE("hwndEdit=%0x, text len=%d str=<%s>\n", infoPtr
->hwndEdit
, alen
, str
);
913 item
->mask
|= CBEIF_TEXT
;
914 wlen
= MultiByteToWideChar (CP_ACP
, 0, str
, -1, NULL
, 0);
916 item
->pszText
= (LPWSTR
)COMCTL32_Alloc ((wlen
+ 1)*sizeof(WCHAR
));
917 MultiByteToWideChar (CP_ACP
, 0, str
, -1, item
->pszText
, wlen
);
925 RECT exrc
, cbrc
, edrc
;
926 GetWindowRect (hwnd
, &exrc
);
927 GetWindowRect (infoPtr
->hwndCombo
, &cbrc
);
928 edrc
.left
=edrc
.top
=edrc
.right
=edrc
.bottom
=-1;
929 if (infoPtr
->hwndEdit
)
930 GetWindowRect (infoPtr
->hwndEdit
, &edrc
);
931 TRACE("window rects ex=(%d,%d)-(%d,%d), cb=(%d,%d)-(%d,%d), ed=(%d,%d)-(%d,%d)\n",
932 exrc
.left
, exrc
.top
, exrc
.right
, exrc
.bottom
,
933 cbrc
.left
, cbrc
.top
, cbrc
.right
, cbrc
.bottom
,
934 edrc
.left
, edrc
.top
, edrc
.right
, edrc
.bottom
);
938 ERR("NOT drawing item -1 special focus, rect=(%d,%d)-(%d,%d), action=%08x, state=%08x\n",
939 dis
->rcItem
.left
, dis
->rcItem
.top
,
940 dis
->rcItem
.right
, dis
->rcItem
.bottom
,
941 dis
->itemAction
, dis
->itemState
);
947 item
= (CBE_ITEMDATA
*)SendMessageA (infoPtr
->hwndCombo
,
948 CB_GETITEMDATA
, (WPARAM
)dis
->itemID
, 0);
949 if (item
== (CBE_ITEMDATA
*)CB_ERR
)
951 FIXME("invalid item for id %d \n",dis
->itemID
);
954 if (!TRACE_ON(message
)) {
955 TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
956 dis
->CtlType
, dis
->CtlID
);
957 TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n",
958 dis
->itemID
, dis
->itemAction
, dis
->itemState
);
959 TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n",
960 dis
->hwndItem
, dis
->hDC
, dis
->rcItem
.left
,
961 dis
->rcItem
.top
, dis
->rcItem
.right
, dis
->rcItem
.bottom
,
964 COMBOEX_DumpItem (item
);
966 xbase
= CBE_STARTOFFSET
;
967 if (item
->mask
& CBEIF_INDENT
)
968 xbase
+= (item
->iIndent
* CBE_INDENT
);
969 if (item
->mask
& CBEIF_IMAGE
) {
970 ImageList_GetImageInfo(infoPtr
->himl
, item
->iImage
, &iinfo
);
971 xioff
= (iinfo
.rcImage
.right
- iinfo
.rcImage
.left
+ CBE_SEP
);
974 switch (dis
->itemAction
) {
976 if (dis
->itemState
& ODS_SELECTED
/*1*/) {
977 if ((item
->mask
& CBEIF_TEXT
) && item
->pszText
) {
978 len
= strlenW (item
->pszText
);
979 GetTextExtentPointW (dis
->hDC
, item
->pszText
, len
, &txtsize
);
980 rect
.left
= xbase
+ xioff
- 1;
981 rect
.top
= dis
->rcItem
.top
- 1 +
982 (dis
->rcItem
.bottom
- dis
->rcItem
.top
- txtsize
.cy
) / 2;
983 rect
.right
= rect
.left
+ txtsize
.cx
+ 2;
984 rect
.bottom
= rect
.top
+ txtsize
.cy
+ 2;
985 TRACE("drawing item %d focus, rect=(%d,%d)-(%d,%d)\n",
986 dis
->itemID
, rect
.left
, rect
.top
,
987 rect
.right
, rect
.bottom
);
988 DrawFocusRect(dis
->hDC
, &rect
);
995 if (item
->mask
& CBEIF_IMAGE
) drawimage
= item
->iImage
;
996 if ((dis
->itemState
& ODS_SELECTED
) &&
997 (item
->mask
& CBEIF_SELECTEDIMAGE
))
998 drawimage
= item
->iSelectedImage
;
999 if (drawimage
!= -1) {
1000 ImageList_Draw (infoPtr
->himl
, drawimage
, dis
->hDC
,
1001 xbase
, dis
->rcItem
.top
,
1002 (dis
->itemState
& ODS_SELECTED
) ?
1003 ILD_SELECTED
: ILD_NORMAL
);
1005 if ((item
->mask
& CBEIF_TEXT
) && item
->pszText
) {
1007 COLORREF nbkc
, ntxc
;
1009 len
= strlenW (item
->pszText
);
1010 GetTextExtentPointW (dis
->hDC
, item
->pszText
, len
, &txtsize
);
1011 nbkc
= GetSysColor ((dis
->itemState
& ODS_SELECTED
) ?
1012 COLOR_HIGHLIGHT
: COLOR_WINDOW
);
1013 SetBkColor (dis
->hDC
, nbkc
);
1014 ntxc
= GetSysColor ((dis
->itemState
& ODS_SELECTED
) ?
1015 COLOR_HIGHLIGHTTEXT
: COLOR_WINDOWTEXT
);
1016 SetTextColor (dis
->hDC
, ntxc
);
1018 y
= dis
->rcItem
.top
+
1019 (dis
->rcItem
.bottom
- dis
->rcItem
.top
- txtsize
.cy
) / 2;
1021 rect
.right
= x
+ txtsize
.cx
;
1023 rect
.bottom
= y
+ txtsize
.cy
;
1024 TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n",
1025 dis
->itemID
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1026 ExtTextOutW (dis
->hDC
, x
, y
, ETO_OPAQUE
| ETO_CLIPPED
,
1027 &rect
, item
->pszText
, len
, 0);
1028 if (dis
->itemState
& ODS_FOCUS
) {
1033 TRACE("drawing item %d focus, rect=(%d,%d)-(%d,%d)\n",
1034 dis
->itemID
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1035 DrawFocusRect (dis
->hDC
, &rect
);
1040 FIXME("unknown action hwnd=%08x, wparam=%08x, lparam=%08lx, action=%d\n",
1041 hwnd
, wParam
, lParam
, dis
->itemAction
);
1049 COMBOEX_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1051 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
1053 if (infoPtr
->hwndCombo
)
1054 DestroyWindow (infoPtr
->hwndCombo
);
1056 if (infoPtr
->edit
) {
1057 COMCTL32_Free (infoPtr
->edit
);
1061 if (infoPtr
->items
) {
1062 CBE_ITEMDATA
*this, *next
;
1064 this = infoPtr
->items
;
1066 next
= (CBE_ITEMDATA
*)this->next
;
1067 if ((this->mask
& CBEIF_TEXT
) && this->pszText
)
1068 COMCTL32_Free (this->pszText
);
1069 COMCTL32_Free (this);
1074 DeleteObject (infoPtr
->font
);
1076 /* free comboex info data */
1077 COMCTL32_Free (infoPtr
);
1078 SetWindowLongA (hwnd
, 0, 0);
1084 COMBOEX_MeasureItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1086 /*COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);*/
1087 MEASUREITEMSTRUCT
*mis
= (MEASUREITEMSTRUCT
*) lParam
;
1092 GetTextExtentPointA (hdc
, "W", 1, &mysize
);
1094 mis
->itemHeight
= mysize
.cy
+ CBE_EXTRA
;
1096 TRACE("adjusted height hwnd=%08x, height=%d\n",
1097 hwnd
, mis
->itemHeight
);
1104 COMBOEX_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1106 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
1109 GetWindowRect (hwnd
, &rect
);
1110 TRACE("my rect (%d,%d)-(%d,%d)\n",
1111 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1113 MoveWindow (infoPtr
->hwndCombo
, 0, 0, rect
.right
-rect
.left
,
1114 rect
.bottom
- rect
.top
, TRUE
);
1116 COMBOEX_AdjustEditPos (infoPtr
);
1123 COMBOEX_WindowPosChanging (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1125 COMBOEX_INFO
*infoPtr
= COMBOEX_GetInfoPtr (hwnd
);
1127 RECT cbx_wrect
, cbx_crect
, cb_wrect
;
1129 WINDOWPOS
*wp
= (WINDOWPOS
*)lParam
;
1131 ret
= DefWindowProcA (hwnd
, WM_WINDOWPOSCHANGING
, wParam
, lParam
);
1132 GetWindowRect (hwnd
, &cbx_wrect
);
1133 GetClientRect (hwnd
, &cbx_crect
);
1134 GetWindowRect (infoPtr
->hwndCombo
, &cb_wrect
);
1136 /* width is winpos value + border width of comboex */
1138 + cbx_wrect
.right
-cbx_wrect
.left
1139 - (cbx_crect
.right
- cbx_crect
.left
);
1141 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
1142 cbx_wrect
.left
, cbx_wrect
.top
, cbx_wrect
.right
, cbx_wrect
.bottom
,
1143 cbx_crect
.left
, cbx_crect
.top
, cbx_crect
.right
, cbx_crect
.bottom
);
1144 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
1145 cb_wrect
.left
, cb_wrect
.top
, cb_wrect
.right
, cb_wrect
.bottom
,
1146 width
, cb_wrect
.bottom
-cb_wrect
.top
);
1148 SetWindowPos (infoPtr
->hwndCombo
, HWND_TOP
, 0, 0,
1150 cb_wrect
.bottom
-cb_wrect
.top
,
1153 /* ****** new # 3 ******* */
1154 COMBOEX_AdjustEditPos (infoPtr
);
1160 static LRESULT WINAPI
1161 COMBOEX_EditWndProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1163 COMBOEX_INFO
*infoPtr
= (COMBOEX_INFO
*)GetPropA (hwnd
, (LPCSTR
)(LONG
) ComboExInfo
);
1165 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
1166 hwnd
, uMsg
, wParam
, lParam
, infoPtr
);
1168 if (!infoPtr
) return 0;
1174 NMCBEENDEDITA cbeend
;
1178 switch ((INT
)wParam
)
1181 /* native version seems to do following for COMBOEX */
1183 * GetWindowTextA(Edit,&?, 0x104) x
1184 * CB_GETCURSEL to Combo rets -1 x
1185 * WM_NOTIFY to COMBOEX parent (rebar) x
1186 * (CBEN_ENDEDIT{A|W}
1187 * fChanged = FALSE x
1188 * inewSelection = -1 x
1191 * CB_GETCURSEL to Combo rets -1 x
1192 * InvalidateRect(Combo, 0) x
1193 * WM_SETTEXT to Edit x
1194 * EM_SETSEL to Edit (0,0) x
1195 * EM_SETSEL to Edit (0,-1) x
1196 * RedrawWindow(Combo, 0, 0, 5) x
1198 TRACE("special code for VK_ESCAPE\n");
1200 GetWindowTextA (infoPtr
->hwndEdit
, cbeend
.szText
, 260);
1202 infoPtr
->flags
&= ~WCBE_ACTEDIT
;
1203 cbeend
.fChanged
= FALSE
;
1204 cbeend
.iNewSelection
= SendMessageA (infoPtr
->hwndCombo
,
1205 CB_GETCURSEL
, 0, 0);
1206 cbeend
.iWhy
= CBENF_ESCAPE
;
1208 if (COMBOEX_Notify (infoPtr
, CBEN_ENDEDITA
,
1209 (NMHDR
*)&cbeend
)) {
1210 /* abort the change */
1213 oldItem
= SendMessageA (infoPtr
->hwndCombo
,CB_GETCURSEL
, 0, 0);
1214 InvalidateRect (infoPtr
->hwndCombo
, 0, 0);
1215 if (!(item
= COMBOEX_FindItem(infoPtr
, oldItem
))) {
1216 ERR("item %d not found. Problem!\n", oldItem
);
1220 COMBOEX_SetEditText (infoPtr
, item
);
1221 RedrawWindow (infoPtr
->hwndCombo
, 0, 0, RDW_ERASE
|
1226 /* native version seems to do following for COMBOEX */
1228 * GetWindowTextA(Edit,&?, 0x104) x
1229 * CB_GETCURSEL to Combo rets -1 x
1230 * CB_GETCOUNT to Combo rets 0
1231 * WM_NOTIFY to COMBOEX parent (rebar) x
1232 * (CBEN_ENDEDIT{A|W}
1233 * fChanged = TRUE (-1) x
1234 * iNewSelection = -1 x
1236 * iWhy = 2 (CBENF_RETURN) x
1237 * CB_GETCURSEL to Combo rets -1 x
1238 * InvalidateRect(Combo, 0, 0) x
1240 * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
1243 TRACE("special code for VK_RETURN\n");
1245 GetWindowTextA (infoPtr
->hwndEdit
, cbeend
.szText
, 260);
1247 infoPtr
->flags
&= ~WCBE_ACTEDIT
;
1248 cbeend
.iNewSelection
= SendMessageA (infoPtr
->hwndCombo
,
1249 CB_GETCURSEL
, 0, 0);
1250 cbeend
.fChanged
= TRUE
;
1251 cbeend
.iWhy
= CBENF_RETURN
;
1253 if (COMBOEX_Notify (infoPtr
, CBEN_ENDEDITA
,
1254 (NMHDR
*)&cbeend
)) {
1255 /* abort the change */
1258 oldItem
= SendMessageA (infoPtr
->hwndCombo
,CB_GETCURSEL
, 0, 0);
1259 InvalidateRect (infoPtr
->hwndCombo
, 0, 0);
1260 SetFocus(infoPtr
->hwndEdit
);
1264 return CallWindowProcA (infoPtr
->prevEditWndProc
,
1265 hwnd
, uMsg
, wParam
, lParam
);
1271 * should do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
1272 * ** fall through for now **
1274 infoPtr
->flags
&= ~WCBE_ACTEDIT
;
1278 /* The above messages need code - will be delivered later */
1280 return CallWindowProcA (infoPtr
->prevEditWndProc
,
1281 hwnd
, uMsg
, wParam
, lParam
);
1287 static LRESULT WINAPI
1288 COMBOEX_ComboWndProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1290 COMBOEX_INFO
*infoPtr
= (COMBOEX_INFO
*)GetPropA (hwnd
, (LPCSTR
)(LONG
) ComboExInfo
);
1292 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
1293 hwnd
, uMsg
, wParam
, lParam
, infoPtr
);
1295 if (!infoPtr
) return 0;
1300 /* traces show that COMBOEX does not issue CBN_EDITUPDATE
1303 if (HIWORD(wParam
) == EN_UPDATE
) return 0;
1305 if (HIWORD(wParam
) == EN_SETFOCUS
) {
1307 * For EN_SETFOCUS this issues the same calls and messages
1308 * as the native seems to do.
1312 SendMessageA (infoPtr
->hwndEdit
, EM_SETSEL
, 0, 0);
1313 SendMessageA (infoPtr
->hwndEdit
, EM_SETSEL
, 0, -1);
1314 COMBOEX_Notify (infoPtr
, CBEN_BEGINEDIT
, &hdr
);
1315 infoPtr
->flags
|= WCBE_ACTEDIT
;
1319 if (HIWORD(wParam
) == EN_CHANGE
) {
1321 * For EN_CHANGE this issues the same calls and messages
1322 * as the native seems to do.
1324 WCHAR selected_text
[260];
1328 selected
= SendMessageA (infoPtr
->hwndCombo
,
1329 CB_GETCURSEL
, 0, 0);
1331 /* lstrlenA( lastworkingURL ) */
1334 GetWindowTextW (infoPtr
->hwndEdit
, selected_text
, 260);
1336 item
= COMBOEX_FindItem (infoPtr
, selected
);
1337 cnt
= lstrlenW (item
->pszText
);
1338 if (cnt
>= 259) cnt
= 259;
1339 lstrcpynW (selected_text
, item
->pszText
, cnt
);
1340 selected_text
[cnt
+1] = 0;
1343 TRACE("handling EN_CHANGE, selected = %d, text=%s\n",
1344 selected
, debugstr_w(selected_text
));
1346 /* lstrcmpiW is between lastworkingURL and GetWindowText */
1348 if (lstrcmpiW (infoPtr
->edit
->pszText
, selected_text
)) {
1349 /* strings not equal -- what to do???? */
1350 ERR("strings do not match\n");
1352 SendMessageA ( GetParent(infoPtr
->hwndSelf
), WM_COMMAND
,
1353 MAKEWPARAM(GetDlgCtrlID (infoPtr
->hwndSelf
),
1363 /* The above messages need code - will be delivered later */
1365 return CallWindowProcA (infoPtr
->prevComboWndProc
,
1366 hwnd
, uMsg
, wParam
, lParam
);
1372 static LRESULT WINAPI
1373 COMBOEX_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1375 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd
, uMsg
, wParam
, lParam
);
1376 if (!COMBOEX_GetInfoPtr (hwnd
) && (uMsg
!= WM_CREATE
))
1377 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1381 /* case CBEM_DELETEITEM: */
1383 case CBEM_GETCOMBOCONTROL
:
1384 return COMBOEX_GetComboControl (hwnd
, wParam
, lParam
);
1386 case CBEM_GETEDITCONTROL
:
1387 return COMBOEX_GetEditControl (hwnd
, wParam
, lParam
);
1389 case CBEM_GETEXTENDEDSTYLE
:
1390 return COMBOEX_GetExtendedStyle (hwnd
, wParam
, lParam
);
1392 case CBEM_GETIMAGELIST
:
1393 return COMBOEX_GetImageList (hwnd
, wParam
, lParam
);
1395 /* case CBEM_GETITEMA:
1397 case CBEM_GETUNICODEFORMAT:
1400 case CBEM_HASEDITCHANGED
:
1401 return COMBOEX_HasEditChanged (hwnd
, wParam
, lParam
);
1403 case CBEM_INSERTITEMA
:
1404 return COMBOEX_InsertItemA (hwnd
, wParam
, lParam
);
1406 case CBEM_INSERTITEMW
:
1407 return COMBOEX_InsertItemW (hwnd
, wParam
, lParam
);
1409 case CBEM_SETEXSTYLE
: /* FIXME: obsoleted, should be the same as: */
1410 case CBEM_SETEXTENDEDSTYLE
:
1411 return COMBOEX_SetExtendedStyle (hwnd
, wParam
, lParam
);
1413 case CBEM_SETIMAGELIST
:
1414 return COMBOEX_SetImageList (hwnd
, wParam
, lParam
);
1417 return COMBOEX_SetItemA (hwnd
, wParam
, lParam
);
1420 return COMBOEX_SetItemW (hwnd
, wParam
, lParam
);
1422 /* case CBEM_SETUNICODEFORMAT:
1425 case CB_DELETESTRING
:
1426 case CB_FINDSTRINGEXACT
:
1429 case CB_GETDROPPEDCONTROLRECT
:
1430 case CB_GETDROPPEDSTATE
:
1431 case CB_GETITEMDATA
:
1432 case CB_GETITEMHEIGHT
:
1434 case CB_GETLBTEXTLEN
:
1435 case CB_GETEXTENDEDUI
:
1437 case CB_RESETCONTENT
:
1438 case CB_SELECTSTRING
:
1439 case CB_SETDROPPEDWIDTH
: /* used by IE 4 */
1440 case CB_SETEXTENDEDUI
: /* used by IE 4 */
1441 case CB_SETITEMDATA
:
1442 case CB_SHOWDROPDOWN
: /* used by IE 4 */
1445 return COMBOEX_Forward (hwnd
, uMsg
, wParam
, lParam
);
1448 return COMBOEX_SetCursel (hwnd
, wParam
, lParam
);
1450 case CB_SETITEMHEIGHT
:
1451 return COMBOEX_SetItemHeight (hwnd
, wParam
, lParam
);
1454 /* Messages passed to parent */
1457 return SendMessageA (GetParent (hwnd
), uMsg
, wParam
, lParam
);
1461 return COMBOEX_Create (hwnd
, wParam
, lParam
);
1464 return COMBOEX_DrawItem (hwnd
, wParam
, lParam
);
1467 return COMBOEX_Destroy (hwnd
, wParam
, lParam
);
1469 case WM_MEASUREITEM
:
1470 return COMBOEX_MeasureItem (hwnd
, wParam
, lParam
);
1473 return COMBOEX_Size (hwnd
, wParam
, lParam
);
1475 case WM_WINDOWPOSCHANGING
:
1476 return COMBOEX_WindowPosChanging (hwnd
, wParam
, lParam
);
1479 if (uMsg
>= WM_USER
)
1480 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1481 uMsg
, wParam
, lParam
);
1482 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1489 COMBOEX_Register (void)
1493 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1494 wndClass
.style
= CS_GLOBALCLASS
;
1495 wndClass
.lpfnWndProc
= (WNDPROC
)COMBOEX_WindowProc
;
1496 wndClass
.cbClsExtra
= 0;
1497 wndClass
.cbWndExtra
= sizeof(COMBOEX_INFO
*);
1498 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1499 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1500 wndClass
.lpszClassName
= WC_COMBOBOXEXA
;
1502 RegisterClassA (&wndClass
);
1504 ComboExInfo
= GlobalAddAtomA("CC32SubclassInfo");
1509 COMBOEX_Unregister (void)
1511 UnregisterClassA (WC_COMBOBOXEXA
, (HINSTANCE
)NULL
);