Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / comctl32 / comboex.c
1 /*
2  * ComboBoxEx control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  * Copyright 2000, 2001, 2002 Guy Albertelli <galberte@neo.lrun.com>
6  * Copyright 2002 Dimitrie O. Paun
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * TODO   <-------------
23  *  1. The following extended styles need to be implemented, use will
24  *     result in a FIXME:
25  *           CBES_EX_NOEDITIMAGEINDENT
26  *           CBES_EX_PATHWORDBREAKPROC
27  *           CBES_EX_NOSIZELIMIT
28  *           CBES_EX_CASESENSITIVE
29  *  2. None of the following callback items are implemented. Therefor
30  *     no CBEN_GETDISPINFO notifies are issued. Use in either CBEM_INSERTITEM
31  *     or CBEM_SETITEM will result in a FIXME:
32  *           LPSTR_TEXTCALLBACK
33  *           I_IMAGECALLBACK
34  *           I_INDENTCALLBACK
35  *  3. No use is made of the iOverlay image.
36  *  4. Notify CBEN_DRAGBEGIN is not implemented.
37  *
38  */
39
40 #include <string.h>
41 #include "winbase.h"
42 #include "commctrl.h"
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(comboex);
47 /*
48  * The following is necessary for the test done in COMBOEX_DrawItem
49  * to determine whether to dump out the DRAWITEM structure or not.
50  */
51 WINE_DECLARE_DEBUG_CHANNEL(message);
52
53 /* Item structure */
54 typedef struct
55 {
56     VOID         *next;
57     UINT         mask;
58     LPWSTR       pszText;
59     int          cchTextMax;
60     int          iImage;
61     int          iSelectedImage;
62     int          iOverlay;
63     int          iIndent;
64     LPARAM       lParam;
65 } CBE_ITEMDATA;
66
67 /* ComboBoxEx structure */
68 typedef struct
69 {
70     HIMAGELIST   himl;
71     HWND         hwndSelf;         /* my own hwnd */
72     HWND         hwndCombo;
73     HWND         hwndEdit;
74     WNDPROC      prevEditWndProc;  /* previous Edit WNDPROC value */
75     WNDPROC      prevComboWndProc; /* previous Combo WNDPROC value */
76     DWORD        dwExtStyle;
77     INT          selected;         /* index of selected item */
78     DWORD        flags;            /* WINE internal flags */
79     HFONT        defaultFont;
80     HFONT        font;
81     INT          nb_items;         /* Number of items */
82     BOOL         unicode;          /* TRUE if this window is Unicode   */
83     BOOL         NtfUnicode;       /* TRUE if parent wants notify in Unicode */
84     CBE_ITEMDATA *edit;            /* item data for edit item */
85     CBE_ITEMDATA *items;           /* Array of items */
86 } COMBOEX_INFO;
87
88 /* internal flags in the COMBOEX_INFO structure */
89 #define  WCBE_ACTEDIT        0x00000001     /* Edit active i.e.
90                                              * CBEN_BEGINEDIT issued
91                                              * but CBEN_ENDEDIT{A|W}
92                                              * not yet issued. */
93 #define  WCBE_EDITCHG        0x00000002     /* Edit issued EN_CHANGE */
94 #define  WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG)
95 #define  WCBE_EDITFOCUSED    0x00000004     /* Edit control has focus */
96
97
98 #define ID_CB_EDIT    1001
99
100
101 /*
102  * Special flag set in DRAWITEMSTRUCT itemState field. It is set by
103  * the ComboEx version of the Combo Window Proc so that when the 
104  * WM_DRAWITEM message is then passed to ComboEx, we know that this 
105  * particular WM_DRAWITEM message is for listbox only items. Any messasges
106  * without this flag is then for the Edit control field.
107  *
108  * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that 
109  * only version 4.0 applications will have ODS_COMBOBOXEDIT set.
110  */
111 #define ODS_COMBOEXLBOX  0x4000
112
113
114
115 /* Height in pixels of control over the amount of the selected font */
116 #define CBE_EXTRA     3
117
118 /* Indent amount per MS documentation */
119 #define CBE_INDENT    10
120
121 /* Offset in pixels from left side for start of image or text */
122 #define CBE_STARTOFFSET   6
123
124 /* Offset between image and text */
125 #define CBE_SEP   4
126
127 #define COMBOEX_SUBCLASS_PROP "CCComboEx32SubclassInfo"
128 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongW (hwnd, 0))
129
130
131 /* Things common to the entire DLL */
132 static LRESULT WINAPI
133 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
134 static LRESULT WINAPI
135 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
136
137 static void COMBOEX_DumpItem (CBE_ITEMDATA *item)
138 {
139     TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
140           item, item->mask, item->pszText, item->cchTextMax, item->iImage);
141     TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
142           item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam);
143     if ((item->mask & CBEIF_TEXT) && item->pszText)
144         TRACE("item %p - pszText=%s\n", item, debugstr_w(item->pszText));
145 }
146
147
148 static void COMBOEX_DumpInput (COMBOBOXEXITEMW *input)
149 {
150     TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n",
151           input->mask, input->iItem, input->pszText, input->cchTextMax,
152           input->iImage);
153     if ((input->mask & CBEIF_TEXT) && input->pszText)
154         TRACE("input - pszText=<%s>\n", debugstr_w(input->pszText));
155     TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
156           input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam);
157 }
158
159
160 inline static LRESULT
161 COMBOEX_Forward (COMBOEX_INFO *infoPtr, UINT uMsg, WPARAM wParam, LPARAM lParam)
162 {
163     if (infoPtr->hwndCombo)    
164         return SendMessageW (infoPtr->hwndCombo, uMsg, wParam, lParam);
165
166     return 0;
167 }
168
169
170 static INT COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr)
171 {
172     hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
173     hdr->hwndFrom = infoPtr->hwndSelf;
174     hdr->code = code;
175     if (infoPtr->NtfUnicode)
176         return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
177                              (LPARAM)hdr);
178     else
179         return SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
180                              (LPARAM)hdr);
181 }
182
183
184 static INT
185 COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr)
186 {
187
188     /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
189
190     hdr->hdr.idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
191     hdr->hdr.hwndFrom = infoPtr->hwndSelf;
192     hdr->hdr.code = code;
193     if (infoPtr->NtfUnicode)
194         return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
195                              (LPARAM)hdr);
196     else {
197         LPWSTR str, ostr = NULL;
198         INT ret, len = 0;
199
200         if (hdr->ceItem.mask & CBEIF_TEXT) {
201             ostr = hdr->ceItem.pszText;
202             str = ostr;
203             if (!str) str = (LPWSTR)L"";
204             len = WideCharToMultiByte (CP_ACP, 0, str, -1, 0, 0, NULL, NULL);
205             if (len > 0) {
206                 hdr->ceItem.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(CHAR));
207                 //FIXME: what if alloc failed?
208                 WideCharToMultiByte (CP_ACP, 0, str, -1, (LPSTR)hdr->ceItem.pszText,
209                                      len, NULL, NULL);
210             }
211         }
212
213         ret = SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
214                             (LPARAM)hdr);
215         if (hdr->ceItem.mask & CBEIF_TEXT) {
216             if (len > 0)
217                 COMCTL32_Free (hdr->ceItem.pszText);
218             hdr->ceItem.pszText = ostr;
219         }
220         return ret;
221     }
222 }
223
224
225 static INT
226 COMBOEX_NotifyEndEdit (COMBOEX_INFO *infoPtr, NMCBEENDEDITW *hdr, LPWSTR itemText)
227 {
228
229     /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
230
231     hdr->hdr.idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
232     hdr->hdr.hwndFrom = infoPtr->hwndSelf;
233     hdr->hdr.code = (infoPtr->NtfUnicode) ? CBEN_ENDEDITW : CBEN_ENDEDITA;
234     if (infoPtr->NtfUnicode)
235         return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
236                              (LPARAM)hdr);
237     else {
238         NMCBEENDEDITA ansi;
239
240         memcpy (&ansi.hdr, &hdr->hdr, sizeof(NMHDR));
241         ansi.fChanged = hdr->fChanged;
242         ansi.iNewSelection = hdr->iNewSelection;
243         WideCharToMultiByte (CP_ACP, 0, itemText, -1,
244                              (LPSTR)&ansi.szText, CBEMAXSTRLEN, NULL, NULL);
245         ansi.iWhy = hdr->iWhy;
246         return SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
247                              (LPARAM)&ansi);
248     }
249 }
250
251
252 static void COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size)
253 {
254     HFONT nfont, ofont;
255     HDC mydc;
256
257     mydc = GetDC (0); /* why the entire screen???? */
258     nfont = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
259     ofont = (HFONT) SelectObject (mydc, nfont);
260     GetTextExtentPointA (mydc, "A", 1, size);
261     SelectObject (mydc, ofont);
262     ReleaseDC (0, mydc);
263     TRACE("selected font hwnd=%08x, height=%ld\n", nfont, size->cy);
264 }
265
266
267 static void COMBOEX_CopyItem (CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit)
268 {
269     if (cit->mask & CBEIF_TEXT) {
270         /*
271          * when given a text buffer actually use that buffer
272          */
273         if (cit->pszText)
274         {
275             lstrcpynW(cit->pszText,item->pszText,cit->cchTextMax);
276         }
277         else
278         {
279             cit->pszText        = item->pszText;
280             cit->cchTextMax     = item->cchTextMax;
281         }
282     }
283     if (cit->mask & CBEIF_IMAGE)
284         cit->iImage         = item->iImage;
285     if (cit->mask & CBEIF_SELECTEDIMAGE)
286         cit->iSelectedImage = item->iSelectedImage;
287     if (cit->mask & CBEIF_OVERLAY)
288         cit->iOverlay       = item->iOverlay;
289     if (cit->mask & CBEIF_INDENT)
290         cit->iIndent        = item->iIndent;
291     if (cit->mask & CBEIF_LPARAM)
292         cit->lParam         = item->lParam;
293 }
294
295
296 static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr)
297 {
298     SIZE mysize;
299     IMAGEINFO iinfo;
300     INT x, y, w, h, xoff = 0;
301     RECT rect;
302
303     if (!infoPtr->hwndEdit) return;
304
305     iinfo.rcImage.left = iinfo.rcImage.right = 0;
306     if (infoPtr->himl) {
307         ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
308         xoff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
309     }
310     GetClientRect (infoPtr->hwndCombo, &rect);
311     InflateRect (&rect, -2, -2);
312     InvalidateRect (infoPtr->hwndCombo, &rect, TRUE);
313
314     /* reposition the Edit control based on whether icon exists */
315     COMBOEX_GetComboFontSize (infoPtr, &mysize);
316     TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy);
317     x = xoff + CBE_STARTOFFSET + 1;
318     w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1;
319     h = mysize.cy + 1;
320     y = rect.bottom - h - 1;
321
322     TRACE("Combo client (%d,%d)-(%d,%d), setting Edit to (%d,%d)-(%d,%d)\n",
323           rect.left, rect.top, rect.right, rect.bottom, x, y, x + w, y + h);
324     SetWindowPos(infoPtr->hwndEdit, HWND_TOP, x, y, w, h,
325                  SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
326 }
327
328
329 static void COMBOEX_ReSize (COMBOEX_INFO *infoPtr)
330 {
331     SIZE mysize;
332     UINT cy;
333     IMAGEINFO iinfo;
334
335     COMBOEX_GetComboFontSize (infoPtr, &mysize);
336     cy = mysize.cy + CBE_EXTRA;
337     if (infoPtr->himl) {
338         ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
339         cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy);
340         TRACE("upgraded height due to image:  height=%d\n", cy);
341     }
342     SendMessageW (infoPtr->hwndSelf, CB_SETITEMHEIGHT, (WPARAM)-1, (LPARAM)cy);
343     if (infoPtr->hwndCombo)
344         SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
345                       (WPARAM) 0, (LPARAM) cy);
346 }
347
348
349 static void COMBOEX_SetEditText (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
350 {
351     if (!infoPtr->hwndEdit) return;
352     /* native issues the following messages to the {Edit} control */
353     /*      WM_SETTEXT (0,addr)     */
354     /*      EM_SETSEL32 (0,0)       */
355     /*      EM_SETSEL32 (0,-1)      */
356     if (item->mask & CBEIF_TEXT) {
357         SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)item->pszText);
358         SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
359         SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
360     }
361 }
362
363  
364 static CBE_ITEMDATA * COMBOEX_FindItem(COMBOEX_INFO *infoPtr, INT index)
365 {
366     CBE_ITEMDATA *item;
367     INT i;
368
369     if ((index > infoPtr->nb_items) || (index < -1))
370         return 0;
371     if (index == -1)
372         return infoPtr->edit;
373     item = infoPtr->items;
374     i = infoPtr->nb_items - 1;
375
376     /* find the item in the list */
377     while (item && (i > index)) {
378         item = (CBE_ITEMDATA *)item->next;
379         i--;
380     }
381     if (!item || (i != index)) {
382         ERR("COMBOBOXEX item structures broken. Please report!\n");
383         return 0;
384     }
385     return item;
386 }
387
388
389 static inline BOOL COMBOEX_HasEdit(COMBOEX_INFO *infoPtr)
390 {
391     return infoPtr->hwndEdit;
392 }
393  
394
395 static void COMBOEX_WarnCallBack (CBE_ITEMDATA *item)
396 {
397     if (item->pszText == LPSTR_TEXTCALLBACKW)
398         FIXME("Callback not implemented yet for pszText\n");
399     if (item->iImage == I_IMAGECALLBACK)
400         FIXME("Callback not implemented yet for iImage\n");
401     if (item->iSelectedImage == I_IMAGECALLBACK)
402         FIXME("Callback not implemented yet for iSelectedImage\n");
403     if (item->iOverlay == I_IMAGECALLBACK)
404         FIXME("Callback not implemented yet for iOverlay\n");
405     if (item->iIndent == I_INDENTCALLBACK)
406         FIXME("Callback not implemented yet for iIndent\n");
407 }
408
409
410 /* ***  CBEM_xxx message support  *** */
411
412
413 static INT COMBOEX_DeleteItem (COMBOEX_INFO *infoPtr, INT index)
414 {
415     CBE_ITEMDATA *item;
416
417     TRACE("(index=%d)\n", index);
418
419     /* if item number requested does not exist then return failure */
420     if ((index > infoPtr->nb_items) || (index < 0)) return CB_ERR;
421     if (!(item = COMBOEX_FindItem(infoPtr, index))) return CB_ERR;
422
423     /* doing this will result in WM_DELETEITEM being issued */
424     SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0);
425
426     return infoPtr->nb_items;
427 }
428
429
430 static BOOL COMBOEX_GetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
431 {
432     INT index = cit->iItem;
433     CBE_ITEMDATA *item;
434
435     TRACE("(...)\n");
436
437     /* if item number requested does not exist then return failure */
438     if ((index > infoPtr->nb_items) || (index < -1)) return FALSE;
439
440     /* if the item is the edit control and there is no edit control, skip */
441     if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
442
443     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
444
445     COMBOEX_CopyItem (item, cit);
446
447     return TRUE;
448 }
449
450
451 static BOOL COMBOEX_GetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
452 {
453     COMBOBOXEXITEMW tmpcit;
454
455     TRACE("(...)\n");
456
457     tmpcit.mask = cit->mask;
458     tmpcit.iItem = cit->iItem;
459     tmpcit.pszText = 0;
460     if(!COMBOEX_GetItemW (infoPtr, &tmpcit)) return FALSE;
461
462     WideCharToMultiByte (CP_ACP, 0, tmpcit.pszText, -1, 
463                          cit->pszText, cit->cchTextMax, NULL, NULL);
464
465     cit->iImage = tmpcit.iImage;
466     cit->iSelectedImage = tmpcit.iSelectedImage;
467     cit->iOverlay = tmpcit.iOverlay;
468     cit->iIndent = tmpcit.iIndent;
469     cit->lParam = tmpcit.lParam;
470
471     return TRUE;
472 }
473
474
475 inline static BOOL COMBOEX_HasEditChanged (COMBOEX_INFO *infoPtr)
476 {
477     return COMBOEX_HasEdit(infoPtr) &&
478            (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
479 }
480
481
482 static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
483 {
484     INT index;
485     CBE_ITEMDATA *item;
486     NMCOMBOBOXEXW nmcit;
487
488     TRACE("\n");
489
490     if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit);
491
492     /* get real index of item to insert */
493     index = cit->iItem;
494     if (index == -1) index = infoPtr->nb_items;
495     if (index > infoPtr->nb_items) index = infoPtr->nb_items;
496
497     /* get space and chain it in */
498     if(!(item = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof(*item)))) return -1;
499     
500     item->next = NULL;
501     item->pszText = NULL;
502
503     /* locate position to insert new item in */
504     if (index == infoPtr->nb_items) {
505         /* fast path for iItem = -1 */
506         item->next = infoPtr->items;
507         infoPtr->items = item;
508     }
509     else {
510         INT i = infoPtr->nb_items-1;
511         CBE_ITEMDATA *moving = infoPtr->items;
512
513         while ((i > index) && moving) {
514             moving = (CBE_ITEMDATA *)moving->next;
515             i--;
516         }
517         if (!moving) {
518             ERR("COMBOBOXEX item structures broken. Please report!\n");
519             COMCTL32_Free(item);
520             return -1;
521         }
522         item->next = moving->next;
523         moving->next = item;
524     }
525
526     /* fill in our hidden item structure */
527     item->mask           = cit->mask;
528     if (item->mask & CBEIF_TEXT) {
529         LPWSTR str;
530         INT len;
531
532         str = cit->pszText;
533         if (!str) str = (LPWSTR) L"";
534         len = strlenW (str);
535         if (len > 0) {
536             item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
537             //FIXME: what if allocation fails?
538             strcpyW (item->pszText, str);
539         }
540         else
541             item->pszText = NULL;
542         item->cchTextMax   = cit->cchTextMax;
543     }
544     if (item->mask & CBEIF_IMAGE)
545         item->iImage         = cit->iImage;
546     if (item->mask & CBEIF_SELECTEDIMAGE)
547         item->iSelectedImage = cit->iSelectedImage;
548     if (item->mask & CBEIF_OVERLAY)
549         item->iOverlay       = cit->iOverlay;
550     if (item->mask & CBEIF_INDENT)
551         item->iIndent        = cit->iIndent;
552     if (item->mask & CBEIF_LPARAM)
553         item->lParam         = cit->lParam;
554     infoPtr->nb_items++;
555
556     COMBOEX_WarnCallBack (item);
557
558     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
559
560     SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, 
561                   (WPARAM)cit->iItem, (LPARAM)item);
562
563     memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
564     COMBOEX_CopyItem (item, &nmcit.ceItem);
565     COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit);
566
567     return index;
568
569 }
570
571
572 static INT COMBOEX_InsertItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
573 {
574     COMBOBOXEXITEMW citW;
575     INT ret;
576
577     memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
578     if (cit->mask & CBEIF_TEXT) {
579         LPSTR str = cit->pszText;
580         INT len = 0;
581
582         if (str) len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
583         if (len > 0) {
584             citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
585             if (!citW.pszText) return -1;
586             MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
587         }
588     }
589     ret = COMBOEX_InsertItemW(infoPtr, &citW);;
590     
591     if (citW.pszText) COMCTL32_Free(citW.pszText);
592     
593     return ret;
594 }
595
596
597 static DWORD 
598 COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style)
599 {
600     DWORD dwTemp;
601
602     TRACE("(mask=x%08lx, style=0x%08lx)\n", mask, style);
603
604     dwTemp = infoPtr->dwExtStyle;
605
606     if (style &  (CBES_EX_NOEDITIMAGEINDENT |
607                   CBES_EX_PATHWORDBREAKPROC |
608                   CBES_EX_NOSIZELIMIT |
609                   CBES_EX_CASESENSITIVE))
610         FIXME("Extended style not implemented %08lx\n", style);
611
612     if (mask)
613         infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~mask) | style;
614     else
615         infoPtr->dwExtStyle = style;
616
617     /*
618      * native does this for CBES_EX_NOEDITIMAGE state change
619      */
620     if ((infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE) ^
621         (dwTemp & CBES_EX_NOEDITIMAGE)) {
622         /* if state of EX_NOEDITIMAGE changes, invalidate all */
623         TRACE("EX_NOEDITIMAGE state changed to %ld\n",
624               infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE);
625         InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
626         COMBOEX_AdjustEditPos (infoPtr);
627         if (infoPtr->hwndEdit)
628             InvalidateRect (infoPtr->hwndEdit, NULL, TRUE);
629     }
630
631     return dwTemp;
632 }
633
634
635 static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl)
636 {
637     HIMAGELIST himlTemp = infoPtr->himl;
638
639     TRACE("(...)\n");
640
641     infoPtr->himl = himl;
642
643     COMBOEX_ReSize (infoPtr);
644     InvalidateRect (infoPtr->hwndCombo, NULL, TRUE);
645
646     /* reposition the Edit control based on whether icon exists */
647     COMBOEX_AdjustEditPos (infoPtr);
648     return himlTemp;
649 }
650
651 static BOOL COMBOEX_SetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
652 {
653     INT index = cit->iItem;
654     CBE_ITEMDATA *item;
655
656     if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit);
657
658     /* if item number requested does not exist then return failure */
659     if ((index > infoPtr->nb_items) || (index < -1)) return FALSE;
660
661     /* if the item is the edit control and there is no edit control, skip */
662     if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
663
664     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
665
666     /* add/change stuff to the internal item structure */ 
667     item->mask |= cit->mask;
668     if (cit->mask & CBEIF_TEXT) {
669         LPWSTR str = cit->pszText;
670         INT len = 0;
671
672         if (str) len = strlenW(str);
673         if (len > 0) {
674             item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
675             if (!item->pszText) return FALSE;
676             strcpyW(item->pszText, str);
677         }
678         item->cchTextMax   = cit->cchTextMax;
679     }
680     if (cit->mask & CBEIF_IMAGE)
681         item->iImage         = cit->iImage;
682     if (cit->mask & CBEIF_SELECTEDIMAGE)
683         item->iSelectedImage = cit->iSelectedImage;
684     if (cit->mask & CBEIF_OVERLAY)
685         item->iOverlay       = cit->iOverlay;
686     if (cit->mask & CBEIF_INDENT)
687         item->iIndent        = cit->iIndent;
688     if (cit->mask & CBEIF_LPARAM)
689         cit->lParam         = cit->lParam;
690
691     COMBOEX_WarnCallBack (item);
692
693     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
694
695     /* if original request was to update edit control, do some fast foot work */
696     if (cit->iItem == -1) {
697         COMBOEX_SetEditText (infoPtr, item);
698         RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE);
699     }
700     return TRUE;
701 }
702
703 static BOOL COMBOEX_SetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
704 {
705     COMBOBOXEXITEMW     citW;
706     BOOL                ret;
707
708     memcpy(&citW, cit, sizeof(COMBOBOXEXITEMA));
709     if (cit->mask & CBEIF_TEXT) {
710         LPSTR str = cit->pszText;
711         INT len = 0;
712
713         str = cit->pszText;
714         if (str) len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
715         if (len > 0) {
716             citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
717             if (!citW.pszText) return FALSE;
718             MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
719         }
720     }
721     ret = COMBOEX_SetItemW(infoPtr, &citW);;
722
723     if (citW.pszText) COMCTL32_Free(citW.pszText);
724
725     return ret;
726 }
727
728
729 static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value)
730 {
731     BOOL bTemp = infoPtr->unicode;
732
733     TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE");
734
735     infoPtr->unicode = value;
736
737     return bTemp;
738 }
739
740
741 /* ***  CB_xxx message support  *** */
742
743 static INT
744 COMBOEX_FindStringExact (COMBOEX_INFO *infoPtr, INT start, LPCSTR str)
745 {
746     INT i, count;
747     CBE_ITEMDATA *item;
748     LPWSTR desired = NULL;
749
750     i = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
751     if (i > 0) {
752         desired = (LPWSTR)COMCTL32_Alloc ((i + 1)*sizeof(WCHAR));
753         if (!desired) return CB_ERR;
754         MultiByteToWideChar (CP_ACP, 0, str, -1, desired, i);
755     }
756
757     count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
758
759     /* now search from after starting loc and wrapping back to start */
760     for(i=start+1; i<count; i++) {
761         item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, 
762                           CB_GETITEMDATA, (WPARAM)i, 0);
763         TRACE("desired=%s, item=%s\n", 
764               debugstr_w(desired), debugstr_w(item->pszText));
765         if (lstrcmpiW(item->pszText, desired) == 0) {
766             COMCTL32_Free (desired);
767             return i;
768         }
769     }
770     for(i=0; i<=start; i++) {
771         item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, 
772                           CB_GETITEMDATA, (WPARAM)i, 0);
773         TRACE("desired=%s, item=%s\n", 
774               debugstr_w(desired), debugstr_w(item->pszText));
775         if (lstrcmpiW(item->pszText, desired) == 0) {
776             COMCTL32_Free (desired);
777             return i;
778         }
779     }
780     COMCTL32_Free(desired);
781     return CB_ERR;
782 }
783
784
785 static DWORD COMBOEX_GetItemData (COMBOEX_INFO *infoPtr, INT index)
786 {
787     CBE_ITEMDATA *item1, *item2;
788     DWORD ret = 0;
789
790     item1 = (CBE_ITEMDATA *)COMBOEX_Forward (infoPtr, CB_GETITEMDATA, index, 0);
791     if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
792         item2 = COMBOEX_FindItem (infoPtr, index);
793         if (item2 != item1) {
794             ERR("data structures damaged!\n");
795             return CB_ERR;
796         }
797         if (item1->mask & CBEIF_LPARAM) ret = item1->lParam;
798         TRACE("returning 0x%08lx\n", ret);
799     } else {
800         ret = (DWORD)item1;
801         TRACE("non-valid result from combo, returning 0x%08lx\n", ret);
802     }
803     return ret;
804 }
805
806
807 static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT index)
808 {
809     CBE_ITEMDATA *item;
810     INT sel;
811
812     if (!(item = COMBOEX_FindItem(infoPtr, index)))
813         return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);
814
815     TRACE("selecting item %d text=%s\n", index, (item->pszText) ?
816           debugstr_w(item->pszText) : "<null>");
817     infoPtr->selected = index;
818
819     sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);
820     COMBOEX_SetEditText (infoPtr, item);
821     return sel;
822 }
823
824
825 static DWORD COMBOEX_SetItemData (COMBOEX_INFO *infoPtr, INT index, DWORD data)
826 {
827     CBE_ITEMDATA *item1, *item2;
828
829     item1 = (CBE_ITEMDATA *)COMBOEX_Forward (infoPtr,CB_GETITEMDATA,index,data);
830     
831     if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
832         item2 = COMBOEX_FindItem (infoPtr, index);
833         if (item2 != item1) {
834             ERR("data structures damaged!\n");
835             return CB_ERR;
836         }
837         item1->mask |= CBEIF_LPARAM;
838         item1->lParam = data;
839         TRACE("setting lparam to 0x%08lx\n", data);
840         return 0;
841     }
842     TRACE("non-valid result from combo 0x%08lx\n", (DWORD)item1);
843     return (LRESULT)item1;
844 }
845
846
847 static INT COMBOEX_SetItemHeight (COMBOEX_INFO *infoPtr, INT index, UINT height)
848 {
849     RECT cb_wrect, cbx_wrect, cbx_crect;
850
851     /* First, lets forward the message to the normal combo control
852        just like Windows.     */
853     if (infoPtr->hwndCombo)
854        if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
855                          index, height) == CB_ERR) return CB_ERR;
856
857     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
858     GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
859     GetClientRect (infoPtr->hwndSelf, &cbx_crect);
860     /* the height of comboex as height of the combo + comboex border */ 
861     height = cb_wrect.bottom-cb_wrect.top
862              + cbx_wrect.bottom-cbx_wrect.top
863              - (cbx_crect.bottom-cbx_crect.top);
864     TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
865           cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
866           cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
867     TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
868           cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
869           cbx_wrect.right-cbx_wrect.left, height);
870     SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0,
871                   cbx_wrect.right-cbx_wrect.left, height,
872                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
873
874     return 0;
875 }
876
877
878 /* ***  WM_xxx message support  *** */
879
880
881 static LRESULT COMBOEX_Create (HWND hwnd, LPCREATESTRUCTA cs)
882 {
883     WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 };
884     WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 };
885     WCHAR NIL[] = { 0 };
886     COMBOEX_INFO *infoPtr;
887     DWORD dwComboStyle;
888     LOGFONTW mylogfont;
889     RECT wnrc1, clrc1, cmbwrc;
890     INT i;
891
892     /* allocate memory for info structure */
893     infoPtr = (COMBOEX_INFO *)COMCTL32_Alloc (sizeof(COMBOEX_INFO));
894     if (!infoPtr) return -1;
895
896     /* initialize info structure */
897     /* note that infoPtr is allocated zero-filled */
898     
899     infoPtr->hwndSelf = hwnd;
900     infoPtr->selected = -1;
901
902     infoPtr->unicode = IsWindowUnicode (hwnd);
903
904     i = SendMessageW(GetParent (hwnd), WM_NOTIFYFORMAT, hwnd, NF_QUERY);
905     if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
906         WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
907         i = NFR_ANSI;
908     }
909     infoPtr->NtfUnicode = (i == NFR_UNICODE);
910
911     SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
912
913     /* create combo box */
914     dwComboStyle = GetWindowLongW (hwnd, GWL_STYLE) &
915                         (CBS_SIMPLE|CBS_DROPDOWN|CBS_DROPDOWNLIST|WS_CHILD);
916
917     GetWindowRect(hwnd, &wnrc1);
918     GetClientRect(hwnd, &clrc1);
919     TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d)\n",
920           wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
921           clrc1.left, clrc1.top, clrc1.right, clrc1.bottom);
922     TRACE("combo style=%08lx, adding style=%08lx\n", dwComboStyle,
923           WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
924           CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
925           WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED);
926
927     /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
928     /* specified. It then creates it's own version of the EDIT control  */
929     /* and makes the ComboBox the parent. This is because a normal      */
930     /* DROPDOWNLIST does not have a EDIT control, but we need one.      */
931     /* We also need to place the edit control at the proper location    */
932     /* (allow space for the icons).                                     */
933
934     infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL,
935                          /* following line added to match native */
936                          WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
937                          CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST | 
938                          /* was base and is necessary */
939                          WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | dwComboStyle,
940                          cs->y, cs->x, cs->cx, cs->cy, hwnd,
941                          (HMENU) GetWindowLongW (hwnd, GWL_ID),
942                          GetWindowLongW (hwnd, GWL_HINSTANCE), NULL);
943
944     /* 
945      * native does the following at this point according to trace:
946      *  GetWindowThreadProcessId(hwndCombo,0)
947      *  GetCurrentThreadId()
948      *  GetWindowThreadProcessId(hwndCombo, &???)
949      *  GetCurrentProcessId()
950      */
951
952     /*
953      * Setup a property to hold the pointer to the COMBOBOXEX 
954      * data structure.
955      */
956     SetPropA(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd);
957     infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongW(infoPtr->hwndCombo, 
958                                 GWL_WNDPROC, (LONG)COMBOEX_ComboWndProc);
959     infoPtr->font = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
960
961
962     /*
963      * Now create our own EDIT control so we can position it.
964      * It is created only for CBS_DROPDOWN style
965      */
966     if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
967         infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL,
968                     WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
969                     0, 0, 0, 0,  /* will set later */
970                     infoPtr->hwndCombo, 
971                     (HMENU) GetWindowLongW (hwnd, GWL_ID),
972                     GetWindowLongW (hwnd, GWL_HINSTANCE),
973                     NULL);
974
975         /* native does the following at this point according to trace:
976          *  GetWindowThreadProcessId(hwndEdit,0)
977          *  GetCurrentThreadId()
978          *  GetWindowThreadProcessId(hwndEdit, &???)
979          *  GetCurrentProcessId()
980          */
981
982         /*
983          * Setup a property to hold the pointer to the COMBOBOXEX 
984          * data structure.
985          */
986         SetPropA(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd);
987         infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongW(infoPtr->hwndEdit, 
988                                  GWL_WNDPROC, (LONG)COMBOEX_EditWndProc);
989         infoPtr->font = SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
990     }
991
992     /*
993      * Locate the default font if necessary and then set it in
994      * all associated controls
995      */
996     if (!infoPtr->font) {
997         SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont), 
998                                &mylogfont, 0);
999         infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont);
1000     }
1001     SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
1002     if (infoPtr->hwndEdit) {
1003         SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
1004         SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
1005     }
1006
1007     COMBOEX_ReSize (infoPtr);
1008
1009     /* Above is fairly certain, below is much less certain. */
1010
1011     GetWindowRect(hwnd, &wnrc1);
1012     GetClientRect(hwnd, &clrc1);
1013     GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
1014     TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d) CB wnd=(%d,%d)-(%d,%d)\n",
1015           wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
1016           clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
1017           cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
1018     SetWindowPos(infoPtr->hwndCombo, HWND_TOP, 
1019                  0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
1020                  SWP_NOACTIVATE | SWP_NOREDRAW);
1021
1022     GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
1023     TRACE("CB window=(%d,%d)-(%d,%d)\n",
1024           cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
1025     SetWindowPos(hwnd, HWND_TOP, 
1026                  0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
1027                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1028
1029     COMBOEX_AdjustEditPos (infoPtr);
1030
1031     /*
1032      * Create an item structure to represent the data in the 
1033      * EDIT control. It is allocated zero-filled.
1034      */
1035     infoPtr->edit = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA));
1036     //FIXME: what if allocation failed?
1037
1038     return 0;
1039 }
1040
1041
1042 static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1043 {
1044     LRESULT lret;
1045     INT command = HIWORD(wParam);
1046     CBE_ITEMDATA *item = 0;
1047     WCHAR wintext[520];
1048     INT cursel, n, oldItem;
1049     NMCBEENDEDITW cbeend;
1050     DWORD oldflags;
1051     HWND parent = GetParent (infoPtr->hwndSelf);
1052
1053     TRACE("for command %d\n", command);
1054
1055     switch (command)
1056     {
1057     case CBN_DROPDOWN:
1058         SetFocus (infoPtr->hwndCombo);
1059         ShowWindow (infoPtr->hwndEdit, SW_HIDE);
1060         return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1061         
1062     case CBN_CLOSEUP:
1063         SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1064         /*
1065          * from native trace of first dropdown after typing in URL in IE4 
1066          *  CB_GETCURSEL(Combo)
1067          *  GetWindowText(Edit)
1068          *  CB_GETCURSEL(Combo)
1069          *  CB_GETCOUNT(Combo)
1070          *  CB_GETITEMDATA(Combo, n)
1071          *  WM_NOTIFY(parent, CBEN_ENDEDITA|W)
1072          *  CB_GETCURSEL(Combo)
1073          *  CB_SETCURSEL(COMBOEX, n)
1074          *  SetFocus(Combo)
1075          * the rest is supposition  
1076          */
1077         ShowWindow (infoPtr->hwndEdit, SW_SHOW);
1078         InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
1079         InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
1080         cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1081         if (cursel == -1) {
1082             /* find match from edit against those in Combobox */
1083             GetWindowTextW (infoPtr->hwndEdit, wintext, 520);
1084             n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
1085             for (cursel = 0; cursel < n; cursel++){
1086                 item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, 
1087                                                      CB_GETITEMDATA, 
1088                                                      cursel, 0);
1089                 if ((INT)item == CB_ERR) break;
1090                 if (lstrcmpiW(item->pszText, wintext) == 0) break;
1091             }
1092             if ((cursel == n) || ((INT)item == CB_ERR)) {
1093                 TRACE("failed to find match??? item=%p cursel=%d\n",
1094                       item, cursel);
1095                 if (infoPtr->hwndEdit)
1096                     SetFocus(infoPtr->hwndEdit);
1097                 return 0;
1098             }
1099         }
1100         else {
1101             item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, 
1102                                                  CB_GETITEMDATA, 
1103                                                  cursel, 0);
1104             if ((INT)item == CB_ERR) {
1105                 TRACE("failed to find match??? item=%p cursel=%d\n",
1106                       item, cursel);
1107                 if (infoPtr->hwndEdit)
1108                     SetFocus(infoPtr->hwndEdit);
1109                 return 0;
1110             }
1111         }
1112
1113         /* Save flags for testing and reset them */
1114         oldflags = infoPtr->flags;
1115         infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1116
1117         if (oldflags & WCBE_ACTEDIT) {
1118             cbeend.fChanged = (oldflags & WCBE_EDITCHG);
1119             cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1120                                                  CB_GETCURSEL, 0, 0);
1121             cbeend.iWhy = CBENF_DROPDOWN;
1122
1123             if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, item->pszText)) {
1124                 /* abort the change */
1125                 TRACE("Notify requested abort of change\n");
1126                 return 0;
1127             }
1128         }
1129
1130         /* if selection has changed the set the new current selection */
1131         cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1132         if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) {
1133             infoPtr->selected = cursel;
1134             SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0);
1135             SetFocus(infoPtr->hwndCombo);
1136         }
1137         return 0;
1138
1139     case CBN_SELCHANGE:
1140         /*
1141          * CB_GETCURSEL(Combo)
1142          * CB_GETITEMDATA(Combo)   < simulated by COMBOEX_FindItem
1143          * lstrlenA
1144          * WM_SETTEXT(Edit)
1145          * WM_GETTEXTLENGTH(Edit)
1146          * WM_GETTEXT(Edit)
1147          * EM_SETSEL(Edit, 0,0)
1148          * WM_GETTEXTLENGTH(Edit)
1149          * WM_GETTEXT(Edit)
1150          * EM_SETSEL(Edit, 0,len)
1151          * return WM_COMMAND to parent
1152          */
1153         oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1154         if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
1155             ERR("item %d not found. Problem!\n", oldItem);
1156             break;
1157         }
1158         infoPtr->selected = oldItem;
1159         COMBOEX_SetEditText (infoPtr, item);
1160         return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1161
1162     case CBN_SELENDOK:
1163         /* 
1164          * We have to change the handle since we are the control
1165          * issuing the message. IE4 depends on this.
1166          */
1167         return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1168
1169     case CBN_KILLFOCUS:
1170         /*
1171          * from native trace:
1172          *
1173          *  pass to parent
1174          *  WM_GETTEXT(Edit, 104)
1175          *  CB_GETCURSEL(Combo) rets -1
1176          *  WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
1177          *  CB_GETCURSEL(Combo)
1178          *  InvalidateRect(Combo, 0, 0)
1179          *  return 0
1180          */
1181         SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1182         if (infoPtr->flags & WCBE_ACTEDIT) {
1183             GetWindowTextW (infoPtr->hwndEdit, wintext, 260);
1184             cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
1185             cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1186                                                  CB_GETCURSEL, 0, 0);
1187             cbeend.iWhy = CBENF_KILLFOCUS;
1188
1189             infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1190             if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) {
1191                 /* abort the change */
1192                 TRACE("Notify requested abort of change\n");
1193                 return 0;
1194             }
1195         }
1196         /* possible CB_GETCURSEL */
1197         InvalidateRect (infoPtr->hwndCombo, 0, 0);
1198         return 0;
1199
1200     default:
1201         /* 
1202          * We have to change the handle since we are the control
1203          * issuing the message. IE4 depends on this.
1204          * We also need to set the focus back to the Edit control
1205          * after passing the command to the parent of the ComboEx.
1206          */
1207         lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
1208         if (infoPtr->hwndEdit)
1209             SetFocus(infoPtr->hwndEdit);
1210         return lret;
1211     }
1212     return 0;
1213 }
1214
1215
1216 static BOOL COMBOEX_WM_DeleteItem (COMBOEX_INFO *infoPtr, DELETEITEMSTRUCT *dis)
1217 {
1218     CBE_ITEMDATA *item, *olditem;
1219     NMCOMBOBOXEXW nmcit;
1220     INT i;
1221
1222     TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%x, data=%08lx\n",
1223           dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData);
1224
1225     if (dis->itemID >= infoPtr->nb_items) return FALSE;
1226
1227     olditem = infoPtr->items;
1228     i = infoPtr->nb_items - 1;
1229
1230     if (i == dis->itemID) {
1231         infoPtr->items = infoPtr->items->next;
1232     }
1233     else {
1234         item = olditem;
1235         i--;
1236
1237         /* find the prior item in the list */
1238         while (item->next && (i > dis->itemID)) {
1239             item = (CBE_ITEMDATA *)item->next;
1240             i--;
1241         }
1242         if (!item->next || (i != dis->itemID)) {
1243             ERR("COMBOBOXEX item structures broken. Please report!\n");
1244             return FALSE;
1245         }
1246         olditem = item->next;
1247         item->next = (CBE_ITEMDATA *)((CBE_ITEMDATA *)item->next)->next;
1248     }
1249     infoPtr->nb_items--;
1250
1251     memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
1252     COMBOEX_CopyItem (olditem, &nmcit.ceItem);
1253     COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit);
1254
1255     if (olditem->pszText) COMCTL32_Free(olditem->pszText);
1256     COMCTL32_Free(olditem);
1257
1258     return TRUE;
1259 }
1260
1261
1262 static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis)
1263 {
1264     WCHAR nil[] = { 0 };
1265     CBE_ITEMDATA *item = 0;
1266     SIZE txtsize;
1267     RECT rect;
1268     LPCWSTR str = nil;
1269     int drawimage, drawstate;
1270     UINT xbase, x, y;
1271     UINT xioff = 0;               /* size and spacer of image if any */
1272     IMAGEINFO iinfo;
1273     INT len;
1274     COLORREF nbkc, ntxc, bkc, txc;
1275
1276     if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0;
1277
1278     /* dump the DRAWITEMSTRUCT if tracing "comboex" but not "message" */
1279     if (!TRACE_ON(message)) {
1280         TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", 
1281               dis->CtlType, dis->CtlID);
1282         TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", 
1283               dis->itemID, dis->itemAction, dis->itemState);
1284         TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n",
1285               dis->hwndItem, dis->hDC, dis->rcItem.left, 
1286               dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom, 
1287               dis->itemData);
1288     }
1289
1290     /* MSDN says:                                                       */
1291     /*     "itemID - Specifies the menu item identifier for a menu      */
1292     /*      item or the index of the item in a list box or combo box.   */
1293     /*      For an empty list box or combo box, this member can be -1.  */
1294     /*      This allows the application to draw only the focus          */
1295     /*      rectangle at the coordinates specified by the rcItem        */
1296     /*      member even though there are no items in the control.       */
1297     /*      This indicates to the user whether the list box or combo    */
1298     /*      box has the focus. How the bits are set in the itemAction   */
1299     /*      member determines whether the rectangle is to be drawn as   */
1300     /*      though the list box or combo box has the focus.             */
1301     if (dis->itemID == 0xffffffff) {
1302         if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) ||
1303              ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) { 
1304
1305             TRACE("drawing item -1 special focus, rect=(%d,%d)-(%d,%d)\n",
1306                   dis->rcItem.left, dis->rcItem.top,
1307                   dis->rcItem.right, dis->rcItem.bottom);
1308         }
1309         else if ((dis->CtlType == ODT_COMBOBOX) && 
1310                  (dis->itemAction == ODA_DRAWENTIRE)) {
1311             /* draw of edit control data */
1312
1313             /* testing */
1314             {
1315                 RECT exrc, cbrc, edrc;
1316                 GetWindowRect (infoPtr->hwndSelf, &exrc);
1317                 GetWindowRect (infoPtr->hwndCombo, &cbrc);
1318                 edrc.left=edrc.top=edrc.right=edrc.bottom=-1;
1319                 if (infoPtr->hwndEdit)
1320                     GetWindowRect (infoPtr->hwndEdit, &edrc);
1321                 TRACE("window rects ex=(%d,%d)-(%d,%d), cb=(%d,%d)-(%d,%d), ed=(%d,%d)-(%d,%d)\n",
1322                       exrc.left, exrc.top, exrc.right, exrc.bottom,
1323                       cbrc.left, cbrc.top, cbrc.right, cbrc.bottom,
1324                       edrc.left, edrc.top, edrc.right, edrc.bottom);
1325             }
1326         }
1327         else {
1328             ERR("NOT drawing item  -1 special focus, rect=(%d,%d)-(%d,%d), action=%08x, state=%08x\n",
1329                 dis->rcItem.left, dis->rcItem.top,
1330                 dis->rcItem.right, dis->rcItem.bottom,
1331                 dis->itemAction, dis->itemState);
1332             return 0;
1333         }
1334     }
1335
1336     /* If draw item is -1 (edit control) setup the item pointer */
1337     if (dis->itemID == 0xffffffff) {
1338         item = infoPtr->edit;
1339
1340         if (infoPtr->hwndEdit) {
1341             INT len;
1342
1343             /* free previous text of edit item */
1344             if (item->pszText) {
1345                 COMCTL32_Free(item->pszText);
1346                 item->pszText = 0;
1347                 item->mask &= ~CBEIF_TEXT;
1348             }
1349             if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) {
1350                 item->mask |= CBEIF_TEXT;
1351                 item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
1352                 //FIXME: what if alloc failed?
1353                 GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1);
1354             
1355                TRACE("edit control hwndEdit=%0x, text len=%d str=%s\n",
1356                      infoPtr->hwndEdit, len, debugstr_w(item->pszText));
1357             }
1358         }
1359     }
1360
1361
1362     /* if the item pointer is not set, then get the data and locate it */
1363     if (!item) {
1364         item = (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo,
1365                              CB_GETITEMDATA, (WPARAM)dis->itemID, 0);
1366         if (item == (CBE_ITEMDATA *)CB_ERR) {
1367             ERR("invalid item for id %d \n", dis->itemID);
1368             return 0;
1369         }
1370     }
1371
1372     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
1373
1374     xbase = CBE_STARTOFFSET;
1375     if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX))
1376         xbase += (item->iIndent * CBE_INDENT);
1377     if (item->mask & CBEIF_IMAGE) {
1378         ImageList_GetImageInfo(infoPtr->himl, item->iImage, &iinfo);
1379         xioff = (iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP);
1380     }
1381
1382     /* setup pointer to text to be drawn */
1383     if (item && (item->mask & CBEIF_TEXT) && item->pszText)
1384         str = item->pszText;
1385     else
1386         str = nil;
1387
1388     len = strlenW (str);
1389     GetTextExtentPoint32W (dis->hDC, str, len, &txtsize);
1390     
1391     if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) {
1392         drawimage = -1;
1393         drawstate = ILD_NORMAL;
1394         if (!(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE)) {
1395             if (item->mask & CBEIF_IMAGE) 
1396                 drawimage = item->iImage;
1397             if (dis->itemState & ODS_COMBOEXLBOX) {
1398                 /* drawing listbox entry */
1399                 if (dis->itemState & ODS_SELECTED) {
1400                     if (item->mask & CBEIF_SELECTEDIMAGE)
1401                         drawimage = item->iSelectedImage;
1402                     drawstate = ILD_SELECTED;
1403                 }
1404             }
1405             else {
1406                 /* drawing combo/edit entry */
1407                 if (IsWindowVisible(infoPtr->hwndEdit)) {
1408                     /* if we have an edit control, the slave the 
1409                      * selection state to the Edit focus state 
1410                      */
1411                     if (infoPtr->flags & WCBE_EDITFOCUSED) {
1412                         if (item->mask & CBEIF_SELECTEDIMAGE)
1413                             drawimage = item->iSelectedImage;
1414                         drawstate = ILD_SELECTED;
1415                     }
1416                 }
1417                 else {
1418                     /* if we don't have an edit control, use 
1419                      * the requested state.
1420                      */
1421                     if (dis->itemState & ODS_SELECTED) {
1422                         if (item->mask & CBEIF_SELECTEDIMAGE)
1423                             drawimage = item->iSelectedImage;
1424                         drawstate = ILD_SELECTED;
1425                     }
1426                 }
1427             }
1428         }
1429         if (drawimage != -1) {
1430             TRACE("drawing image state=%d\n", dis->itemState & ODS_SELECTED);
1431             ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, 
1432                             xbase, dis->rcItem.top, drawstate);
1433         }
1434
1435         /* now draw the text */
1436         if (!IsWindowVisible (infoPtr->hwndEdit)) {
1437         nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1438                             COLOR_HIGHLIGHT : COLOR_WINDOW);
1439         bkc = SetBkColor (dis->hDC, nbkc);
1440         ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1441                             COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT);
1442         txc = SetTextColor (dis->hDC, ntxc);
1443         x = xbase + xioff;
1444         y = dis->rcItem.top +
1445             (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2;
1446         rect.left = x;
1447         rect.right = x + txtsize.cx;
1448         rect.top = dis->rcItem.top + 1;
1449         rect.bottom = dis->rcItem.bottom - 1;
1450         TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n",
1451               dis->itemID, rect.left, rect.top, rect.right, rect.bottom);
1452         ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED,
1453                      &rect, str, len, 0);
1454         SetBkColor (dis->hDC, bkc);
1455         SetTextColor (dis->hDC, txc);
1456         }
1457     }
1458     
1459     if (dis->itemAction & ODA_FOCUS) {
1460         rect.left = xbase + xioff - 1;
1461         rect.right = rect.left + txtsize.cx + 2;
1462         rect.top = dis->rcItem.top;
1463         rect.bottom = dis->rcItem.bottom;
1464         DrawFocusRect(dis->hDC, &rect);
1465     }
1466
1467     return 0;
1468 }
1469
1470
1471 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
1472 {
1473     if (infoPtr->hwndCombo)
1474         DestroyWindow (infoPtr->hwndCombo);
1475
1476     if (infoPtr->edit) {
1477         COMCTL32_Free (infoPtr->edit);
1478         infoPtr->edit = 0;
1479     }
1480
1481     if (infoPtr->items) {
1482         CBE_ITEMDATA *this, *next;
1483
1484         this = infoPtr->items;
1485         while (this) {
1486             next = (CBE_ITEMDATA *)this->next;
1487             if ((this->mask & CBEIF_TEXT) && this->pszText)
1488                 COMCTL32_Free (this->pszText);
1489             COMCTL32_Free (this);
1490             this = next;
1491         }
1492         infoPtr->items = 0;
1493     }
1494
1495     if (infoPtr->defaultFont) 
1496         DeleteObject (infoPtr->defaultFont);
1497
1498     /* free comboex info data */
1499     COMCTL32_Free (infoPtr);
1500     SetWindowLongW (infoPtr->hwndSelf, 0, 0);
1501     return 0;
1502 }
1503
1504
1505 static LRESULT COMBOEX_MeasureItem (COMBOEX_INFO *infoPtr, MEASUREITEMSTRUCT *mis)
1506 {
1507     SIZE mysize;
1508     HDC hdc;
1509
1510     hdc = GetDC (0);
1511     GetTextExtentPointA (hdc, "W", 1, &mysize);
1512     ReleaseDC (0, hdc);
1513     mis->itemHeight = mysize.cy + CBE_EXTRA;
1514
1515     TRACE("adjusted height hwnd=%08x, height=%d\n",
1516           infoPtr->hwndSelf, mis->itemHeight);
1517
1518     return 0;
1519 }
1520
1521
1522 static LRESULT COMBOEX_NCCreate (HWND hwnd)
1523 {
1524     /* WARNING: The COMBOEX_INFO structure is not yet created */
1525     DWORD oldstyle, newstyle;
1526
1527     oldstyle = (DWORD)GetWindowLongW (hwnd, GWL_STYLE);
1528     newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL);
1529     if (newstyle != oldstyle) {
1530         TRACE("req style %08lx, reseting style %08lx\n",
1531               oldstyle, newstyle);
1532         SetWindowLongW (hwnd, GWL_STYLE, newstyle);
1533     }
1534     return 1;
1535 }
1536
1537
1538 static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam)
1539 {
1540     if (lParam == NF_REQUERY) {
1541         INT i = SendMessageW(GetParent (infoPtr->hwndSelf),
1542                          WM_NOTIFYFORMAT, infoPtr->hwndSelf, NF_QUERY);
1543         if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
1544             ERR("wrong response to WM_NOTIFYFORMAT (%d), set to ANSI\n", i);
1545             i = NFR_ANSI;
1546         }
1547         infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
1548         return (LRESULT)i;
1549     }
1550     return (LRESULT)(infoPtr->unicode ? NFR_UNICODE : NFR_ANSI);
1551 }
1552
1553
1554 static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height)
1555 {
1556     TRACE("(width=%d, height=%d)\n", width, height); 
1557
1558     MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE);
1559
1560     COMBOEX_AdjustEditPos (infoPtr);
1561
1562     return 0;
1563 }
1564
1565
1566 static LRESULT COMBOEX_WindowPosChanging (COMBOEX_INFO *infoPtr, WINDOWPOS *wp)
1567 {
1568     RECT cbx_wrect, cbx_crect, cb_wrect;
1569     UINT width, height;
1570
1571     GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
1572     GetClientRect (infoPtr->hwndSelf, &cbx_crect);
1573     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1574
1575     /* width is winpos value + border width of comboex */
1576     width = wp->cx
1577             + (cbx_wrect.right-cbx_wrect.left) 
1578             - (cbx_crect.right-cbx_crect.left); 
1579
1580     TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n",
1581           wp->x, wp->y, wp->cx, wp->cy, wp->flags);
1582     TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
1583           cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
1584           cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
1585     TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
1586           cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
1587           width, cb_wrect.bottom-cb_wrect.top);
1588
1589     if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0,
1590                              width,
1591                              cb_wrect.bottom-cb_wrect.top,
1592                              SWP_NOACTIVATE);
1593
1594     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1595
1596     /* height is combo window height plus border width of comboex */
1597     height =   (cb_wrect.bottom-cb_wrect.top)
1598              + (cbx_wrect.bottom-cbx_wrect.top)
1599              - (cbx_crect.bottom-cbx_crect.top);
1600     if (wp->cy < height) wp->cy = height;
1601     if (infoPtr->hwndEdit) {
1602         COMBOEX_AdjustEditPos (infoPtr);
1603         InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
1604     }
1605
1606     return 0;
1607 }
1608
1609
1610 static LRESULT WINAPI
1611 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1612 {
1613     HWND hwndComboex = (HWND)GetPropA(hwnd, COMBOEX_SUBCLASS_PROP);
1614     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
1615     NMCBEENDEDITW cbeend;
1616     WCHAR edit_text[260];
1617     COLORREF obkc;
1618     HDC hDC;
1619     RECT rect;
1620     LRESULT lret;
1621
1622     TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", 
1623           hwnd, uMsg, wParam, lParam, infoPtr);
1624
1625     if (!infoPtr) return 0;
1626
1627     switch (uMsg)
1628     {
1629
1630         case WM_CHAR:
1631             /* handle (ignore) the return character */
1632             if (wParam == VK_RETURN) return 0;
1633             /* all other characters pass into the real Edit */
1634             return CallWindowProcW (infoPtr->prevEditWndProc, 
1635                                    hwnd, uMsg, wParam, lParam);
1636
1637         case WM_ERASEBKGND:
1638             /*
1639              * The following was determined by traces of the native 
1640              */
1641             hDC = (HDC) wParam;
1642             obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW));
1643             GetClientRect (hwnd, &rect);
1644             TRACE("erasing (%d,%d)-(%d,%d)\n",
1645                   rect.left, rect.top, rect.right, rect.bottom);
1646             ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
1647             SetBkColor (hDC, obkc);
1648             return CallWindowProcW (infoPtr->prevEditWndProc, 
1649                                    hwnd, uMsg, wParam, lParam);
1650
1651         case WM_KEYDOWN: {
1652             INT oldItem, selected, step = 1;
1653             CBE_ITEMDATA *item;
1654
1655             switch ((INT)wParam)
1656             {
1657             case VK_ESCAPE:
1658                 /* native version seems to do following for COMBOEX */
1659                 /*
1660                  *   GetWindowTextA(Edit,&?, 0x104)             x
1661                  *   CB_GETCURSEL to Combo rets -1              x
1662                  *   WM_NOTIFY to COMBOEX parent (rebar)        x
1663                  *     (CBEN_ENDEDIT{A|W} 
1664                  *      fChanged = FALSE                        x
1665                  *      inewSelection = -1                      x
1666                  *      txt="www.hoho"                          x
1667                  *      iWhy = 3                                x
1668                  *   CB_GETCURSEL to Combo rets -1              x
1669                  *   InvalidateRect(Combo, 0)                   x
1670                  *   WM_SETTEXT to Edit                         x
1671                  *   EM_SETSEL to Edit (0,0)                    x
1672                  *   EM_SETSEL to Edit (0,-1)                   x
1673                  *   RedrawWindow(Combo, 0, 0, 5)               x
1674                  */
1675                 TRACE("special code for VK_ESCAPE\n");
1676
1677                 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1678
1679                 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1680                 cbeend.fChanged = FALSE;
1681                 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1682                                                      CB_GETCURSEL, 0, 0);
1683                 cbeend.iWhy = CBENF_ESCAPE;
1684
1685                 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
1686                     /* abort the change */
1687                     TRACE("Notify requested abort of change\n");
1688                     return 0;
1689                 }
1690                 oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
1691                 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1692                 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
1693                     ERR("item %d not found. Problem!\n", oldItem);
1694                     break;
1695                 }
1696                 infoPtr->selected = oldItem;              
1697                 COMBOEX_SetEditText (infoPtr, item);
1698                 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | 
1699                               RDW_INVALIDATE);
1700                 break;
1701
1702             case VK_RETURN:
1703                 /* native version seems to do following for COMBOEX */
1704                 /*
1705                  *   GetWindowTextA(Edit,&?, 0x104)             x
1706                  *   CB_GETCURSEL to Combo  rets -1             x
1707                  *   CB_GETCOUNT to Combo  rets 0
1708                  *   if >0 loop 
1709                  *       CB_GETITEMDATA to match
1710                  * *** above 3 lines simulated by FindItem      x  
1711                  *   WM_NOTIFY to COMBOEX parent (rebar)        x
1712                  *     (CBEN_ENDEDIT{A|W}                       x
1713                  *        fChanged = TRUE (-1)                  x
1714                  *        iNewSelection = -1 or selected        x
1715                  *        txt=                                  x
1716                  *        iWhy = 2 (CBENF_RETURN)               x
1717                  *   CB_GETCURSEL to Combo  rets -1             x
1718                  *   if -1 send CB_SETCURSEL to Combo -1        x
1719                  *   InvalidateRect(Combo, 0, 0)                x
1720                  *   SetFocus(Edit)                             x
1721                  *   CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
1722                  */
1723
1724                 TRACE("special code for VK_RETURN\n");
1725
1726                 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1727
1728                 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1729                 selected = SendMessageW (infoPtr->hwndCombo,
1730                                          CB_GETCURSEL, 0, 0);
1731
1732                 if (selected != -1) {
1733                     item = COMBOEX_FindItem (infoPtr, selected);
1734                     TRACE("handling VK_RETURN, selected = %d, selected_text=%s\n",
1735                           selected, debugstr_w(item->pszText));
1736                     TRACE("handling VK_RETURN, edittext=%s\n",
1737                           debugstr_w(edit_text));
1738                     if (lstrcmpiW (item->pszText, edit_text)) {
1739                         /* strings not equal -- indicate edit has changed */
1740                         selected = -1;
1741                     }
1742                 }
1743
1744                 cbeend.iNewSelection = selected;
1745                 cbeend.fChanged = TRUE; 
1746                 cbeend.iWhy = CBENF_RETURN;
1747                 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
1748                     /* abort the change, restore previous */
1749                     TRACE("Notify requested abort of change\n");
1750                     COMBOEX_SetEditText (infoPtr, infoPtr->edit);
1751                     RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | 
1752                                   RDW_INVALIDATE);
1753                     return 0;
1754                 }
1755                 oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
1756                 if (oldItem != -1) {
1757                     /* if something is selected, then deselect it */
1758                     SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, 
1759                                   (WPARAM)-1, 0);
1760                 }
1761                 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1762                 SetFocus(infoPtr->hwndEdit);
1763                 break;
1764
1765             case VK_UP:
1766                 step = -1;
1767             case VK_DOWN:
1768                 /* by default, step is 1 */
1769                 oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0);
1770                 if (oldItem >= 0 && oldItem + step >= 0)
1771                     SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
1772                 return 0;
1773             default:
1774                 return CallWindowProcW (infoPtr->prevEditWndProc,
1775                                        hwnd, uMsg, wParam, lParam);
1776             }
1777             return 0;
1778             }
1779
1780         case WM_SETFOCUS:
1781             /* remember the focus to set state of icon */
1782             lret = CallWindowProcW (infoPtr->prevEditWndProc, 
1783                                    hwnd, uMsg, wParam, lParam);
1784             infoPtr->flags |= WCBE_EDITFOCUSED;
1785             return lret;
1786
1787         case WM_KILLFOCUS:
1788             /* 
1789              * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
1790              */
1791             infoPtr->flags &= ~WCBE_EDITFOCUSED;
1792             if (infoPtr->flags & WCBE_ACTEDIT) {
1793                 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1794
1795                 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1796                 cbeend.fChanged = FALSE;
1797                 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1798                                                      CB_GETCURSEL, 0, 0);
1799                 cbeend.iWhy = CBENF_KILLFOCUS;
1800
1801                 COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text);
1802             }
1803             /* fall through */
1804
1805         default:
1806             return CallWindowProcW (infoPtr->prevEditWndProc, 
1807                                    hwnd, uMsg, wParam, lParam);
1808     }
1809     return 0;
1810 }
1811
1812
1813 static LRESULT WINAPI
1814 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1815 {
1816     HWND hwndComboex = (HWND)GetPropA(hwnd, COMBOEX_SUBCLASS_PROP);
1817     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
1818     NMCBEENDEDITW cbeend;
1819     NMMOUSE nmmse;
1820     COLORREF obkc;
1821     HDC hDC;
1822     HWND focusedhwnd;
1823     RECT rect;
1824     WCHAR edit_text[260];
1825
1826     TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", 
1827           hwnd, uMsg, wParam, lParam, infoPtr);
1828
1829     if (!infoPtr) return 0;
1830
1831     switch (uMsg)
1832     {
1833
1834     case CB_FINDSTRINGEXACT:
1835             return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCSTR)lParam);
1836
1837     case WM_DRAWITEM:
1838             /*
1839              * The only way this message should come is from the
1840              * child Listbox issuing the message. Flag this so
1841              * that ComboEx knows this is listbox.
1842              */
1843             ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
1844             return CallWindowProcW (infoPtr->prevComboWndProc, 
1845                                    hwnd, uMsg, wParam, lParam);
1846
1847     case WM_ERASEBKGND:
1848             /*
1849              * The following was determined by traces of the native 
1850              */
1851             hDC = (HDC) wParam;
1852             obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW));
1853             GetClientRect (hwnd, &rect);
1854             TRACE("erasing (%d,%d)-(%d,%d)\n",
1855                   rect.left, rect.top, rect.right, rect.bottom);
1856             ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
1857             SetBkColor (hDC, obkc);
1858             return CallWindowProcW (infoPtr->prevComboWndProc, 
1859                                    hwnd, uMsg, wParam, lParam);
1860
1861     case WM_SETCURSOR:
1862             /*
1863              *  WM_NOTIFY to comboex parent (rebar)
1864              *   with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001
1865              *  CallWindowProc (previous)
1866              */
1867             nmmse.dwItemSpec = 0;
1868             nmmse.dwItemData = 0;
1869             nmmse.pt.x = 0;
1870             nmmse.pt.y = 0;
1871             nmmse.dwHitInfo = lParam;
1872             COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
1873             return CallWindowProcW (infoPtr->prevComboWndProc, 
1874                                    hwnd, uMsg, wParam, lParam);
1875
1876     case WM_COMMAND:
1877             switch (HIWORD(wParam)) {
1878
1879             case EN_UPDATE:
1880                 /* traces show that COMBOEX does not issue CBN_EDITUPDATE
1881                  * on the EN_UPDATE
1882                  */
1883                 return 0;
1884
1885             case EN_KILLFOCUS:
1886                 /*
1887                  * Native does:
1888                  *
1889                  *  GetFocus() retns AA
1890                  *  GetWindowTextA(Edit)
1891                  *  CB_GETCURSEL(Combo) (got -1)
1892                  *  WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
1893                  *  CB_GETCURSEL(Combo) (got -1)
1894                  *  InvalidateRect(Combo, 0, 0)
1895                  *  WM_KILLFOCUS(Combo, AA)
1896                  *  return 0;
1897                  */
1898                 focusedhwnd = GetFocus();
1899                 if (infoPtr->flags & WCBE_ACTEDIT) {
1900                     GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1901                     cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
1902                     cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
1903                                                          CB_GETCURSEL, 0, 0);
1904                     cbeend.iWhy = CBENF_KILLFOCUS;
1905
1906                     infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
1907                     if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
1908                         /* abort the change */
1909                         TRACE("Notify requested abort of change\n");
1910                         return 0;
1911                     }
1912                 }
1913                 /* possible CB_GETCURSEL */
1914                 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1915                 if (focusedhwnd)
1916                     SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS,
1917                                   (WPARAM)focusedhwnd, 0); 
1918                 return 0;
1919
1920             case EN_SETFOCUS: {
1921                 /* 
1922                  * For EN_SETFOCUS this issues the same calls and messages
1923                  *  as the native seems to do.
1924                  *
1925                  * for some cases however native does the following:
1926                  *   (noticed after SetFocus during LBUTTONDOWN on
1927                  *    on dropdown arrow)
1928                  *  WM_GETTEXTLENGTH (Edit);
1929                  *  WM_GETTEXT (Edit, len+1, str);
1930                  *  EM_SETSEL (Edit, 0, 0);
1931                  *  WM_GETTEXTLENGTH (Edit);
1932                  *  WM_GETTEXT (Edit, len+1, str);
1933                  *  EM_SETSEL (Edit, 0, len);
1934                  *  WM_NOTIFY (parent, CBEN_BEGINEDIT)
1935                  */
1936                 NMHDR hdr;
1937
1938                 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
1939                 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
1940                 COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr);
1941                 infoPtr->flags |= WCBE_ACTEDIT;
1942                 infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */
1943                 return 0;
1944                 }
1945
1946             case EN_CHANGE: {
1947                 /* 
1948                  * For EN_CHANGE this issues the same calls and messages
1949                  *  as the native seems to do.
1950                  */
1951                 WCHAR edit_text[260];
1952                 WCHAR *lastwrk;
1953                 INT selected, cnt;
1954                 CBE_ITEMDATA *item;
1955
1956                 selected = SendMessageW (infoPtr->hwndCombo,
1957                                          CB_GETCURSEL, 0, 0);
1958
1959                 /* lstrlenA( lastworkingURL ) */
1960
1961                 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
1962                 if (selected == -1) {
1963                     lastwrk = infoPtr->edit->pszText;
1964                     cnt = lstrlenW (lastwrk);
1965                     if (cnt >= 259) cnt = 259;
1966                 }
1967                 else {
1968                     item = COMBOEX_FindItem (infoPtr, selected);
1969                     cnt = lstrlenW (item->pszText);
1970                     lastwrk = item->pszText;
1971                     if (cnt >= 259) cnt = 259;
1972                 }
1973
1974                 TRACE("handling EN_CHANGE, selected = %d, selected_text=%s\n",
1975                       selected, debugstr_w(lastwrk));
1976                 TRACE("handling EN_CHANGE, edittext=%s\n",
1977                       debugstr_w(edit_text));
1978
1979                 /* lstrcmpiW is between lastworkingURL and GetWindowText */
1980
1981                 if (lstrcmpiW (lastwrk, edit_text)) {
1982                     /* strings not equal -- indicate edit has changed */
1983                     infoPtr->flags |= WCBE_EDITCHG;
1984                 }
1985                 SendMessageW ( GetParent(infoPtr->hwndSelf), WM_COMMAND,
1986                                MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf),
1987                                           CBN_EDITCHANGE),
1988                                infoPtr->hwndSelf);
1989                 return 0;
1990                 }
1991
1992             case LBN_SELCHANGE:
1993                 /*
1994                  * Therefore from traces there is no additional code here
1995                  */
1996
1997                 /*
1998                  * Using native COMCTL32 gets the following:
1999                  *  1 == SHDOCVW.DLL  issues call/message
2000                  *  2 == COMCTL32.DLL  issues call/message
2001                  *  3 == WINE  issues call/message
2002                  *
2003                  *
2004                  * for LBN_SELCHANGE:
2005                  *    1  CB_GETCURSEL(ComboEx)
2006                  *    1  CB_GETDROPPEDSTATE(ComboEx)
2007                  *    1  CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE)
2008                  *    2  CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE)
2009                  **   call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE)
2010                  *    3  WM_COMMAND(ComboEx, CBN_SELENDOK)
2011                  *      WM_USER+49(ComboLB, 1,0)  <=============!!!!!!!!!!!
2012                  *    3  ShowWindow(ComboLB, SW_HIDE)
2013                  *    3  RedrawWindow(Combo,  RDW_UPDATENOW)
2014                  *    3  WM_COMMAND(ComboEX, CBN_CLOSEUP)
2015                  **   end of CBRollUp
2016                  *    3  WM_COMMAND(ComboEx, CBN_SELCHANGE)  (echo to parent)
2017                  *    ?  LB_GETCURSEL              <==|
2018                  *    ?  LB_GETTEXTLEN                |
2019                  *    ?  LB_GETTEXT                   | Needs to be added to
2020                  *    ?  WM_CTLCOLOREDIT(ComboEx)     | Combo processing
2021                  *    ?  LB_GETITEMDATA               |
2022                  *    ?  WM_DRAWITEM(ComboEx)      <==|
2023                  */
2024             default:
2025                 break;
2026             }/* fall through */
2027     default:
2028             return CallWindowProcW (infoPtr->prevComboWndProc, 
2029                                    hwnd, uMsg, wParam, lParam);
2030     }
2031     return 0;
2032 }
2033
2034
2035 static LRESULT WINAPI
2036 COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2037 {
2038     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
2039
2040     TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2041
2042     if (!infoPtr) {
2043         if (uMsg == WM_CREATE)
2044             return COMBOEX_Create (hwnd, (LPCREATESTRUCTA)lParam);
2045         if (uMsg == WM_NCCREATE)
2046             COMBOEX_NCCreate (hwnd);
2047         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2048     }
2049
2050     switch (uMsg)
2051     {
2052         case CBEM_DELETEITEM:
2053             return COMBOEX_DeleteItem (infoPtr, wParam);
2054
2055         case CBEM_GETCOMBOCONTROL:
2056             return infoPtr->hwndCombo;
2057
2058         case CBEM_GETEDITCONTROL:
2059             return infoPtr->hwndEdit;
2060
2061         case CBEM_GETEXTENDEDSTYLE:
2062             return infoPtr->dwExtStyle;
2063
2064         case CBEM_GETIMAGELIST:
2065             return (LRESULT)infoPtr->himl;
2066
2067         case CBEM_GETITEMA:
2068             return (LRESULT)COMBOEX_GetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
2069
2070         case CBEM_GETITEMW:
2071             return (LRESULT)COMBOEX_GetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
2072
2073         case CBEM_GETUNICODEFORMAT:
2074             return infoPtr->unicode;
2075
2076         case CBEM_HASEDITCHANGED:
2077             return COMBOEX_HasEditChanged (infoPtr);
2078
2079         case CBEM_INSERTITEMA:
2080             return COMBOEX_InsertItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
2081
2082         case CBEM_INSERTITEMW:
2083             return COMBOEX_InsertItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
2084
2085         case CBEM_SETEXSTYLE:
2086         case CBEM_SETEXTENDEDSTYLE:
2087             return COMBOEX_SetExtendedStyle (infoPtr, (DWORD)wParam, (DWORD)lParam);
2088
2089         case CBEM_SETIMAGELIST:
2090             return (LRESULT)COMBOEX_SetImageList (infoPtr, (HIMAGELIST)lParam);
2091
2092         case CBEM_SETITEMA:
2093             return COMBOEX_SetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
2094
2095         case CBEM_SETITEMW:
2096             return COMBOEX_SetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
2097
2098         case CBEM_SETUNICODEFORMAT:
2099             return COMBOEX_SetUnicodeFormat (infoPtr, wParam);
2100
2101         /* case CBEM_SETWINDOWTHEME: FIXME */
2102
2103 /*   Combo messages we are not sure if we need to process or just forward */
2104         case CB_GETDROPPEDCONTROLRECT:
2105         case CB_GETITEMHEIGHT:
2106         case CB_GETLBTEXT:
2107         case CB_GETLBTEXTLEN:
2108         case CB_GETEXTENDEDUI:
2109         case CB_LIMITTEXT:
2110         case CB_RESETCONTENT:
2111         case CB_SELECTSTRING:
2112         case WM_SETTEXT:
2113         case WM_GETTEXT:
2114             FIXME("(0x%x 0x%x 0x%lx): possibly missing function\n",
2115                   uMsg, wParam, lParam);
2116
2117 /*   Combo messages OK to just forward to the regular COMBO */
2118         case CB_GETCOUNT:        
2119         case CB_GETCURSEL:
2120         case CB_GETDROPPEDSTATE:
2121         case CB_SETDROPPEDWIDTH:
2122         case CB_SETEXTENDEDUI:
2123         case CB_SHOWDROPDOWN:
2124             return COMBOEX_Forward (infoPtr, uMsg, wParam, lParam);
2125
2126 /*   Combo messages we need to process specially */
2127         case CB_FINDSTRINGEXACT:
2128             return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCSTR)lParam);
2129
2130         case CB_GETITEMDATA:
2131             return COMBOEX_GetItemData (infoPtr, (INT)wParam);
2132
2133         case CB_SETCURSEL:
2134             return COMBOEX_SetCursel (infoPtr, (INT)wParam);
2135
2136         case CB_SETITEMDATA:
2137             return COMBOEX_SetItemData (infoPtr, (INT)wParam, (DWORD)lParam);
2138
2139         case CB_SETITEMHEIGHT:
2140             return COMBOEX_SetItemHeight (infoPtr, (INT)wParam, (UINT)lParam);
2141
2142
2143
2144 /*   Window messages passed to parent */
2145         case WM_COMMAND:
2146             return COMBOEX_Command (infoPtr, wParam, lParam);
2147
2148         case WM_NOTIFY:
2149             if (infoPtr->NtfUnicode)
2150                 return SendMessageW (GetParent (hwnd), uMsg, wParam, lParam);
2151             else
2152                 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
2153
2154
2155 /*   Window messages we need to process */
2156         case WM_DELETEITEM:
2157             return COMBOEX_WM_DeleteItem (infoPtr, (DELETEITEMSTRUCT *)lParam);
2158
2159         case WM_DRAWITEM:
2160             return COMBOEX_DrawItem (infoPtr, (DRAWITEMSTRUCT *)lParam);
2161
2162         case WM_DESTROY:
2163             return COMBOEX_Destroy (infoPtr);
2164
2165         case WM_MEASUREITEM:
2166             return COMBOEX_MeasureItem (infoPtr, (MEASUREITEMSTRUCT *)lParam);
2167
2168         case WM_NOTIFYFORMAT:
2169             return COMBOEX_NotifyFormat (infoPtr, lParam);
2170
2171         case WM_SIZE:
2172             return COMBOEX_Size (infoPtr, LOWORD(lParam), HIWORD(lParam));
2173
2174         case WM_WINDOWPOSCHANGING:
2175             return COMBOEX_WindowPosChanging (infoPtr, (WINDOWPOS *)lParam);
2176
2177         default:
2178             if (uMsg >= WM_USER)
2179                 ERR("unknown msg %04x wp=%08x lp=%08lx\n",uMsg,wParam,lParam);
2180             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2181     }
2182     return 0;
2183 }
2184
2185
2186 void COMBOEX_Register (void)
2187 {
2188     WNDCLASSW wndClass;
2189
2190     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2191     wndClass.style         = CS_GLOBALCLASS;
2192     wndClass.lpfnWndProc   = (WNDPROC)COMBOEX_WindowProc;
2193     wndClass.cbClsExtra    = 0;
2194     wndClass.cbWndExtra    = sizeof(COMBOEX_INFO *);
2195     wndClass.hCursor       = LoadCursorW (0, IDC_ARROWW);
2196     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2197     wndClass.lpszClassName = WC_COMBOBOXEXW;
2198  
2199     RegisterClassW (&wndClass);
2200 }
2201
2202
2203 void COMBOEX_Unregister (void)
2204 {
2205     UnregisterClassW (WC_COMBOBOXEXW, (HINSTANCE)NULL);
2206 }
2207