ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

comboex.c
Go to the documentation of this file.
00001 /*
00002  * ComboBoxEx control
00003  *
00004  * Copyright 1998, 1999 Eric Kohl
00005  * Copyright 2000, 2001, 2002 Guy Albertelli <galberte@neo.lrun.com>
00006  * Copyright 2002 Dimitrie O. Paun
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  *
00022  * NOTE
00023  * 
00024  * This code was audited for completeness against the documented features
00025  * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
00026  * 
00027  * Unless otherwise noted, we believe this code to be complete, as per
00028  * the specification mentioned above.
00029  * If you discover missing features, or bugs, please note them below.
00030  * 
00031  */
00032 
00033 #include <stdarg.h>
00034 #include <string.h>
00035 #include "windef.h"
00036 #include "winbase.h"
00037 #include "wingdi.h"
00038 #include "winuser.h"
00039 #include "winnls.h"
00040 #include "commctrl.h"
00041 #include "comctl32.h"
00042 #include "wine/debug.h"
00043 #include "wine/unicode.h"
00044 
00045 WINE_DEFAULT_DEBUG_CHANNEL(comboex);
00046 
00047 /* Item structure */
00048 typedef struct _CBE_ITEMDATA
00049 {
00050     struct _CBE_ITEMDATA *next;
00051     UINT         mask;
00052     LPWSTR       pszText;
00053     LPWSTR       pszTemp;
00054     int          cchTextMax;
00055     int          iImage;
00056     int          iSelectedImage;
00057     int          iOverlay;
00058     int          iIndent;
00059     LPARAM       lParam;
00060 } CBE_ITEMDATA;
00061 
00062 /* ComboBoxEx structure */
00063 typedef struct
00064 {
00065     HIMAGELIST   himl;
00066     HWND         hwndSelf;         /* my own hwnd */
00067     HWND         hwndNotify;       /* my parent hwnd */
00068     HWND         hwndCombo;
00069     HWND         hwndEdit;
00070     DWORD        dwExtStyle;
00071     INT          selected;         /* index of selected item */
00072     DWORD        flags;            /* WINE internal flags */
00073     HFONT        defaultFont;
00074     HFONT        font;
00075     INT          nb_items;         /* Number of items */
00076     BOOL         unicode;          /* TRUE if this window is Unicode   */
00077     BOOL         NtfUnicode;       /* TRUE if parent wants notify in Unicode */
00078     CBE_ITEMDATA *edit;            /* item data for edit item */
00079     CBE_ITEMDATA *items;           /* Array of items */
00080 } COMBOEX_INFO;
00081 
00082 /* internal flags in the COMBOEX_INFO structure */
00083 #define  WCBE_ACTEDIT       0x00000001  /* Edit active i.e.
00084                                              * CBEN_BEGINEDIT issued
00085                                              * but CBEN_ENDEDIT{A|W}
00086                                              * not yet issued. */
00087 #define  WCBE_EDITCHG       0x00000002  /* Edit issued EN_CHANGE */
00088 #define  WCBE_EDITHASCHANGED    (WCBE_ACTEDIT | WCBE_EDITCHG)
00089 #define  WCBE_EDITFOCUSED   0x00000004  /* Edit control has focus */
00090 #define  WCBE_MOUSECAPTURED 0x00000008  /* Combo has captured mouse */
00091 #define  WCBE_MOUSEDRAGGED      0x00000010  /* User has dragged in combo */
00092 
00093 #define ID_CB_EDIT      1001
00094 
00095 
00096 /*
00097  * Special flag set in DRAWITEMSTRUCT itemState field. It is set by
00098  * the ComboEx version of the Combo Window Proc so that when the
00099  * WM_DRAWITEM message is then passed to ComboEx, we know that this
00100  * particular WM_DRAWITEM message is for listbox only items. Any message
00101  * without this flag is then for the Edit control field.
00102  *
00103  * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that
00104  * only version 4.0 applications will have ODS_COMBOBOXEDIT set.
00105  */
00106 #define ODS_COMBOEXLBOX     0x4000
00107 
00108 
00109 
00110 /* Height in pixels of control over the amount of the selected font */
00111 #define CBE_EXTRA       3
00112 
00113 /* Indent amount per MS documentation */
00114 #define CBE_INDENT      10
00115 
00116 /* Offset in pixels from left side for start of image or text */
00117 #define CBE_STARTOFFSET     6
00118 
00119 /* Offset between image and text */
00120 #define CBE_SEP         4
00121 
00122 #define COMBO_SUBCLASSID  1
00123 #define EDIT_SUBCLASSID   2
00124 
00125 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0))
00126 
00127 static LRESULT CALLBACK COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
00128                                              UINT_PTR uId, DWORD_PTR ref_data);
00129 static LRESULT CALLBACK COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
00130                                               UINT_PTR uId, DWORD_PTR ref_data);
00131 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr);
00132 typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR);
00133 
00134 static inline BOOL is_textW(LPCWSTR str)
00135 {
00136     return str && str != LPSTR_TEXTCALLBACKW;
00137 }
00138 
00139 static inline BOOL is_textA(LPCSTR str)
00140 {
00141     return str && str != LPSTR_TEXTCALLBACKA;
00142 }
00143 
00144 static inline LPCSTR debugstr_txt(LPCWSTR str)
00145 {
00146     if (str == LPSTR_TEXTCALLBACKW) return "(callback)";
00147     return debugstr_w(str);
00148 }
00149 
00150 static void COMBOEX_DumpItem (CBE_ITEMDATA const *item)
00151 {
00152     TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
00153           item, item->mask, item->pszText, item->cchTextMax, item->iImage);
00154     TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
00155           item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam);
00156     if (item->mask & CBEIF_TEXT)
00157         TRACE("item %p - pszText=%s\n", item, debugstr_txt(item->pszText));
00158 }
00159 
00160 
00161 static void COMBOEX_DumpInput (COMBOBOXEXITEMW const *input)
00162 {
00163     TRACE("input - mask=%08x, iItem=%ld, pszText=%p, cchTM=%d, iImage=%d\n",
00164           input->mask, input->iItem, input->pszText, input->cchTextMax,
00165           input->iImage);
00166     if (input->mask & CBEIF_TEXT)
00167         TRACE("input - pszText=<%s>\n", debugstr_txt(input->pszText));
00168     TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
00169           input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam);
00170 }
00171 
00172 
00173 static inline CBE_ITEMDATA *get_item_data(const COMBOEX_INFO *infoPtr, INT index)
00174 {
00175     return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA,
00176                                          index, 0);
00177 }
00178 
00179 static inline cmp_func_t get_cmp_func(COMBOEX_INFO const *infoPtr)
00180 {
00181     return infoPtr->dwExtStyle & CBES_EX_CASESENSITIVE ? lstrcmpW : lstrcmpiW;
00182 }
00183 
00184 static INT COMBOEX_Notify (const COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr)
00185 {
00186     hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
00187     hdr->hwndFrom = infoPtr->hwndSelf;
00188     hdr->code = code;
00189     if (infoPtr->NtfUnicode)
00190     return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr);
00191     else
00192     return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr);
00193 }
00194 
00195 
00196 static INT
00197 COMBOEX_NotifyItem (const COMBOEX_INFO *infoPtr, UINT code, NMCOMBOBOXEXW *hdr)
00198 {
00199     /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
00200     if (infoPtr->NtfUnicode)
00201     return COMBOEX_Notify (infoPtr, code, &hdr->hdr);
00202     else {
00203     LPWSTR wstr = hdr->ceItem.pszText;
00204     LPSTR astr = 0;
00205     INT ret, len = 0;
00206 
00207     if ((hdr->ceItem.mask & CBEIF_TEXT) && is_textW(wstr)) {
00208         len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL);
00209         if (len > 0) {
00210                 astr = Alloc ((len + 1)*sizeof(CHAR));
00211         if (!astr) return 0;
00212         WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0);
00213         hdr->ceItem.pszText = (LPWSTR)astr;
00214         }
00215     }
00216 
00217     if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA;
00218     else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA;
00219     else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA;
00220 
00221     ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr);
00222 
00223     if (astr && hdr->ceItem.pszText == (LPWSTR)astr)
00224         hdr->ceItem.pszText = wstr;
00225 
00226     Free(astr);
00227 
00228     return ret;
00229     }
00230 }
00231 
00232 
00233 static INT COMBOEX_NotifyEndEdit (const COMBOEX_INFO *infoPtr, NMCBEENDEDITW *neew, LPCWSTR wstr)
00234 {
00235     /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
00236     if (infoPtr->NtfUnicode) {
00237     lstrcpynW(neew->szText, wstr, CBEMAXSTRLEN);
00238     return COMBOEX_Notify (infoPtr, CBEN_ENDEDITW, &neew->hdr);
00239     } else {
00240     NMCBEENDEDITA neea;
00241 
00242         neea.hdr = neew->hdr;
00243         neea.fChanged = neew->fChanged;
00244         neea.iNewSelection = neew->iNewSelection;
00245         WideCharToMultiByte (CP_ACP, 0, wstr, -1, neea.szText, CBEMAXSTRLEN, 0, 0);
00246         neea.iWhy = neew->iWhy;
00247 
00248         return COMBOEX_Notify (infoPtr, CBEN_ENDEDITA, &neea.hdr);
00249     }
00250 }
00251 
00252 
00253 static void COMBOEX_NotifyDragBegin(const COMBOEX_INFO *infoPtr, LPCWSTR wstr)
00254 {
00255     /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
00256     if (infoPtr->NtfUnicode) {
00257         NMCBEDRAGBEGINW ndbw;
00258 
00259     ndbw.iItemid = -1;
00260     lstrcpynW(ndbw.szText, wstr, CBEMAXSTRLEN);
00261     COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINW, &ndbw.hdr);
00262     } else {
00263     NMCBEDRAGBEGINA ndba;
00264 
00265     ndba.iItemid = -1;
00266     WideCharToMultiByte (CP_ACP, 0, wstr, -1, ndba.szText, CBEMAXSTRLEN, 0, 0);
00267 
00268     COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINA, &ndba.hdr);
00269     }
00270 }
00271 
00272 
00273 static void COMBOEX_FreeText (CBE_ITEMDATA *item)
00274 {
00275     if (is_textW(item->pszText)) Free(item->pszText);
00276     item->pszText = 0;
00277     Free(item->pszTemp);
00278     item->pszTemp = 0;
00279 }
00280 
00281 
00282 static INT COMBOEX_GetIndex(COMBOEX_INFO const *infoPtr, CBE_ITEMDATA const *item)
00283 {
00284     CBE_ITEMDATA const *moving;
00285     INT index;
00286 
00287     moving = infoPtr->items;
00288     index = infoPtr->nb_items - 1;
00289 
00290     while (moving && (moving != item)) {
00291         moving = moving->next;
00292         index--;
00293     }
00294     if (!moving || (index < 0)) {
00295         ERR("COMBOBOXEX item structures broken. Please report!\n");
00296         return -1;
00297     }
00298     return index;
00299 }
00300 
00301 
00302 static LPCWSTR COMBOEX_GetText(const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
00303 {
00304     NMCOMBOBOXEXW nmce;
00305     LPWSTR text, buf;
00306     INT len;
00307 
00308     if (item->pszText != LPSTR_TEXTCALLBACKW)
00309     return item->pszText;
00310 
00311     ZeroMemory(&nmce, sizeof(nmce));
00312     nmce.ceItem.mask = CBEIF_TEXT;
00313     nmce.ceItem.lParam = item->lParam;
00314     nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item);
00315     COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce);
00316 
00317     if (is_textW(nmce.ceItem.pszText)) {
00318     len = MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, NULL, 0);
00319         buf = Alloc ((len + 1)*sizeof(WCHAR));
00320     if (buf)
00321         MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, buf, len);
00322     if (nmce.ceItem.mask & CBEIF_DI_SETITEM) {
00323         COMBOEX_FreeText(item);
00324         item->pszText = buf;
00325     } else {
00326         Free(item->pszTemp);
00327         item->pszTemp = buf;
00328     }
00329     text = buf;
00330     } else
00331     text = nmce.ceItem.pszText;
00332 
00333     if (nmce.ceItem.mask & CBEIF_DI_SETITEM)
00334     item->pszText = text;
00335     return text;
00336 }
00337 
00338 
00339 static void COMBOEX_GetComboFontSize (const COMBOEX_INFO *infoPtr, SIZE *size)
00340 {
00341     static const WCHAR strA[] = { 'A', 0 };
00342     HFONT nfont, ofont;
00343     HDC mydc;
00344 
00345     mydc = GetDC (0); /* why the entire screen???? */
00346     nfont = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
00347     ofont = SelectObject (mydc, nfont);
00348     GetTextExtentPointW (mydc, strA, 1, size);
00349     SelectObject (mydc, ofont);
00350     ReleaseDC (0, mydc);
00351     TRACE("selected font hwnd=%p, height=%d\n", nfont, size->cy);
00352 }
00353 
00354 
00355 static void COMBOEX_CopyItem (const CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit)
00356 {
00357     if (cit->mask & CBEIF_TEXT) {
00358         /*
00359          * when given a text buffer actually use that buffer
00360          */
00361         if (cit->pszText) {
00362         if (is_textW(item->pszText))
00363                 lstrcpynW(cit->pszText, item->pszText, cit->cchTextMax);
00364         else
00365         cit->pszText[0] = 0;
00366         } else {
00367             cit->pszText        = item->pszText;
00368             cit->cchTextMax     = item->cchTextMax;
00369         }
00370     }
00371     if (cit->mask & CBEIF_IMAGE)
00372     cit->iImage         = item->iImage;
00373     if (cit->mask & CBEIF_SELECTEDIMAGE)
00374     cit->iSelectedImage = item->iSelectedImage;
00375     if (cit->mask & CBEIF_OVERLAY)
00376     cit->iOverlay       = item->iOverlay;
00377     if (cit->mask & CBEIF_INDENT)
00378     cit->iIndent        = item->iIndent;
00379     if (cit->mask & CBEIF_LPARAM)
00380     cit->lParam         = item->lParam;
00381 }
00382 
00383 
00384 static void COMBOEX_AdjustEditPos (const COMBOEX_INFO *infoPtr)
00385 {
00386     SIZE mysize;
00387     INT x, y, w, h, xioff;
00388     RECT rect;
00389 
00390     if (!infoPtr->hwndEdit) return;
00391 
00392     if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) {
00393         IMAGEINFO iinfo;
00394         iinfo.rcImage.left = iinfo.rcImage.right = 0;
00395     ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
00396     xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
00397     }  else xioff = 0;
00398 
00399     GetClientRect (infoPtr->hwndCombo, &rect);
00400     InflateRect (&rect, -2, -2);
00401     InvalidateRect (infoPtr->hwndCombo, &rect, TRUE);
00402 
00403     /* reposition the Edit control based on whether icon exists */
00404     COMBOEX_GetComboFontSize (infoPtr, &mysize);
00405     TRACE("Combo font x=%d, y=%d\n", mysize.cx, mysize.cy);
00406     x = xioff + CBE_STARTOFFSET + 1;
00407     w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1;
00408     h = mysize.cy + 1;
00409     y = rect.bottom - h - 1;
00410 
00411     TRACE("Combo client (%s), setting Edit to (%d,%d)-(%d,%d)\n",
00412           wine_dbgstr_rect(&rect), x, y, x + w, y + h);
00413     SetWindowPos(infoPtr->hwndEdit, HWND_TOP, x, y, w, h,
00414          SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
00415 }
00416 
00417 
00418 static void COMBOEX_ReSize (const COMBOEX_INFO *infoPtr)
00419 {
00420     SIZE mysize;
00421     LONG cy;
00422     IMAGEINFO iinfo;
00423 
00424     COMBOEX_GetComboFontSize (infoPtr, &mysize);
00425     cy = mysize.cy + CBE_EXTRA;
00426     if (infoPtr->himl && ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo)) {
00427     cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy);
00428     TRACE("upgraded height due to image:  height=%d\n", cy);
00429     }
00430     SendMessageW (infoPtr->hwndSelf, CB_SETITEMHEIGHT, -1, cy);
00431     if (infoPtr->hwndCombo) {
00432         SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, 0, cy);
00433     if ( !(infoPtr->flags & CBES_EX_NOSIZELIMIT)) {
00434         RECT comboRect, ourRect;
00435         GetWindowRect(infoPtr->hwndCombo, &comboRect);
00436             GetWindowRect(infoPtr->hwndSelf, &ourRect);
00437             if (comboRect.bottom > ourRect.bottom)
00438                 SetWindowPos( infoPtr->hwndSelf, 0, 0, 0, ourRect.right - ourRect.left,
00439                               comboRect.bottom - comboRect.top,
00440                               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
00441     }
00442     }
00443 }
00444 
00445 
00446 static void COMBOEX_SetEditText (const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
00447 {
00448     if (!infoPtr->hwndEdit) return;
00449 
00450     if (item->mask & CBEIF_TEXT) {
00451     SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item));
00452     SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
00453     SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
00454     }
00455 }
00456 
00457 
00458 static CBE_ITEMDATA * COMBOEX_FindItem(const COMBOEX_INFO *infoPtr, INT_PTR index)
00459 {
00460     CBE_ITEMDATA *item;
00461     INT i;
00462 
00463     if ((index >= infoPtr->nb_items) || (index < -1))
00464     return 0;
00465     if (index == -1)
00466     return infoPtr->edit;
00467     item = infoPtr->items;
00468     i = infoPtr->nb_items - 1;
00469 
00470     /* find the item in the list */
00471     while (item && (i > index)) {
00472     item = item->next;
00473     i--;
00474     }
00475     if (!item || (i != index)) {
00476     ERR("COMBOBOXEX item structures broken. Please report!\n");
00477     return 0;
00478     }
00479     return item;
00480 }
00481 
00482 /* ***  CBEM_xxx message support  *** */
00483 
00484 static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWSTR buf)
00485 {
00486     CBE_ITEMDATA *item;
00487     LPCWSTR str;
00488 
00489     item = COMBOEX_FindItem(infoPtr, n);
00490     if (!item)
00491         return 0;
00492 
00493     str = COMBOEX_GetText(infoPtr, item);
00494     if (!str)
00495     {
00496         if (buf)
00497         {
00498             if (infoPtr->unicode)
00499                 buf[0] = 0;
00500             else
00501                 *((LPSTR)buf) = 0;
00502         }
00503         return 0;
00504     }
00505 
00506     if (infoPtr->unicode)
00507     {
00508         if (buf)
00509             lstrcpyW(buf, str);
00510         return lstrlenW(str);
00511     }
00512     else
00513     {
00514         UINT r;
00515         r = WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)buf, 0x40000000, NULL, NULL);
00516         if (r) r--;
00517         return r;
00518     }
00519 }
00520 
00521 
00522 static INT COMBOEX_DeleteItem (const COMBOEX_INFO *infoPtr, INT_PTR index)
00523 {
00524     TRACE("(index=%ld)\n", index);
00525 
00526     /* if item number requested does not exist then return failure */
00527     if ((index >= infoPtr->nb_items) || (index < 0)) return CB_ERR;
00528     if (!COMBOEX_FindItem(infoPtr, index)) return CB_ERR;
00529 
00530     /* doing this will result in WM_DELETEITEM being issued */
00531     SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, index, 0);
00532 
00533     return infoPtr->nb_items;
00534 }
00535 
00536 
00537 static BOOL COMBOEX_GetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
00538 {
00539     INT_PTR index = cit->iItem;
00540     CBE_ITEMDATA *item;
00541 
00542     TRACE("\n");
00543 
00544     /* if item number requested does not exist then return failure */
00545     if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
00546 
00547     /* if the item is the edit control and there is no edit control, skip */
00548     if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
00549 
00550     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
00551 
00552     COMBOEX_CopyItem (item, cit);
00553 
00554     return TRUE;
00555 }
00556 
00557 
00558 static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
00559 {
00560     COMBOBOXEXITEMW tmpcit;
00561 
00562     TRACE("\n");
00563 
00564     tmpcit.mask = cit->mask;
00565     tmpcit.iItem = cit->iItem;
00566     tmpcit.pszText = 0;
00567     if(!COMBOEX_GetItemW (infoPtr, &tmpcit)) return FALSE;
00568 
00569     if (cit->mask & CBEIF_TEXT)
00570     {
00571         if (is_textW(tmpcit.pszText) && cit->pszText)
00572             WideCharToMultiByte(CP_ACP, 0, tmpcit.pszText, -1,
00573                                 cit->pszText, cit->cchTextMax, NULL, NULL);
00574         else if (cit->pszText) cit->pszText[0] = 0;
00575         else cit->pszText = (LPSTR)tmpcit.pszText;
00576     }
00577 
00578     if (cit->mask & CBEIF_IMAGE)
00579         cit->iImage = tmpcit.iImage;
00580     if (cit->mask & CBEIF_SELECTEDIMAGE)
00581         cit->iSelectedImage = tmpcit.iSelectedImage;
00582     if (cit->mask & CBEIF_OVERLAY)
00583         cit->iOverlay = tmpcit.iOverlay;
00584     if (cit->mask & CBEIF_INDENT)
00585         cit->iIndent = tmpcit.iIndent;
00586     if (cit->mask & CBEIF_LPARAM)
00587         cit->lParam = tmpcit.lParam;
00588 
00589     return TRUE;
00590 }
00591 
00592 
00593 static inline BOOL COMBOEX_HasEditChanged (COMBOEX_INFO const *infoPtr)
00594 {
00595     return infoPtr->hwndEdit && (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
00596 }
00597 
00598 
00599 static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW const *cit)
00600 {
00601     INT_PTR index;
00602     CBE_ITEMDATA *item;
00603     NMCOMBOBOXEXW nmcit;
00604 
00605     TRACE("\n");
00606 
00607     if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit);
00608 
00609     /* get real index of item to insert */
00610     index = cit->iItem;
00611     if (index == -1) index = infoPtr->nb_items;
00612     if (index > infoPtr->nb_items) return -1;
00613 
00614     /* get zero-filled space and chain it in */
00615     if(!(item = Alloc (sizeof(*item)))) return -1;
00616 
00617     /* locate position to insert new item in */
00618     if (index == infoPtr->nb_items) {
00619         /* fast path for iItem = -1 */
00620         item->next = infoPtr->items;
00621     infoPtr->items = item;
00622     }
00623     else {
00624         INT i = infoPtr->nb_items-1;
00625     CBE_ITEMDATA *moving = infoPtr->items;
00626 
00627     while ((i > index) && moving) {
00628         moving = moving->next;
00629         i--;
00630     }
00631     if (!moving) {
00632         ERR("COMBOBOXEX item structures broken. Please report!\n");
00633         Free(item);
00634         return -1;
00635     }
00636     item->next = moving->next;
00637     moving->next = item;
00638     }
00639 
00640     /* fill in our hidden item structure */
00641     item->mask = cit->mask;
00642     if (item->mask & CBEIF_TEXT) {
00643     INT len = 0;
00644 
00645         if (is_textW(cit->pszText)) len = strlenW (cit->pszText);
00646     if (len > 0) {
00647             item->pszText = Alloc ((len + 1)*sizeof(WCHAR));
00648         if (!item->pszText) {
00649         Free(item);
00650         return -1;
00651         }
00652         strcpyW (item->pszText, cit->pszText);
00653     }
00654     else if (cit->pszText == LPSTR_TEXTCALLBACKW)
00655         item->pszText = LPSTR_TEXTCALLBACKW;
00656         item->cchTextMax = cit->cchTextMax;
00657     }
00658     if (item->mask & CBEIF_IMAGE)
00659         item->iImage = cit->iImage;
00660     if (item->mask & CBEIF_SELECTEDIMAGE)
00661         item->iSelectedImage = cit->iSelectedImage;
00662     if (item->mask & CBEIF_OVERLAY)
00663         item->iOverlay = cit->iOverlay;
00664     if (item->mask & CBEIF_INDENT)
00665         item->iIndent = cit->iIndent;
00666     if (item->mask & CBEIF_LPARAM)
00667         item->lParam = cit->lParam;
00668     infoPtr->nb_items++;
00669 
00670     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
00671 
00672     SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, cit->iItem, (LPARAM)item);
00673 
00674     memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
00675     nmcit.ceItem.mask=~0;
00676     COMBOEX_CopyItem (item, &nmcit.ceItem);
00677     COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit);
00678 
00679     return index;
00680 
00681 }
00682 
00683 
00684 static INT COMBOEX_InsertItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA const *cit)
00685 {
00686     COMBOBOXEXITEMW citW;
00687     LPWSTR wstr = NULL;
00688     INT ret;
00689 
00690     memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
00691     if (cit->mask & CBEIF_TEXT && is_textA(cit->pszText)) {
00692     INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0);
00693         wstr = Alloc ((len + 1)*sizeof(WCHAR));
00694     if (!wstr) return -1;
00695     MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len);
00696     citW.pszText = wstr;
00697     }
00698     ret = COMBOEX_InsertItemW(infoPtr, &citW);
00699 
00700     Free(wstr);
00701 
00702     return ret;
00703 }
00704 
00705 
00706 static DWORD
00707 COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style)
00708 {
00709     DWORD dwTemp;
00710 
00711     TRACE("(mask=x%08x, style=0x%08x)\n", mask, style);
00712 
00713     dwTemp = infoPtr->dwExtStyle;
00714 
00715     if (mask)
00716     infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~mask) | style;
00717     else
00718     infoPtr->dwExtStyle = style;
00719 
00720     /* see if we need to change the word break proc on the edit */
00721     if ((infoPtr->dwExtStyle ^ dwTemp) & CBES_EX_PATHWORDBREAKPROC)
00722         SetPathWordBreakProc(infoPtr->hwndEdit, 
00723             (infoPtr->dwExtStyle & CBES_EX_PATHWORDBREAKPROC) ? TRUE : FALSE);
00724 
00725     /* test if the control's appearance has changed */
00726     mask = CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT;
00727     if ((infoPtr->dwExtStyle & mask) != (dwTemp & mask)) {
00728     /* if state of EX_NOEDITIMAGE changes, invalidate all */
00729     TRACE("EX_NOEDITIMAGE state changed to %d\n",
00730           infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE);
00731     InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
00732     COMBOEX_AdjustEditPos (infoPtr);
00733     if (infoPtr->hwndEdit)
00734         InvalidateRect (infoPtr->hwndEdit, NULL, TRUE);
00735     }
00736 
00737     return dwTemp;
00738 }
00739 
00740 
00741 static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl)
00742 {
00743     HIMAGELIST himlTemp = infoPtr->himl;
00744 
00745     TRACE("\n");
00746 
00747     infoPtr->himl = himl;
00748 
00749     COMBOEX_ReSize (infoPtr);
00750     InvalidateRect (infoPtr->hwndCombo, NULL, TRUE);
00751 
00752     /* reposition the Edit control based on whether icon exists */
00753     COMBOEX_AdjustEditPos (infoPtr);
00754     return himlTemp;
00755 }
00756 
00757 static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, const COMBOBOXEXITEMW *cit)
00758 {
00759     INT_PTR index = cit->iItem;
00760     CBE_ITEMDATA *item;
00761 
00762     if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit);
00763 
00764     /* if item number requested does not exist then return failure */
00765     if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
00766 
00767     /* if the item is the edit control and there is no edit control, skip */
00768     if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
00769 
00770     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
00771 
00772     /* add/change stuff to the internal item structure */
00773     item->mask |= cit->mask;
00774     if (cit->mask & CBEIF_TEXT) {
00775     INT len = 0;
00776 
00777     COMBOEX_FreeText(item);
00778         if (is_textW(cit->pszText)) len = strlenW(cit->pszText);
00779     if (len > 0) {
00780             item->pszText = Alloc ((len + 1)*sizeof(WCHAR));
00781         if (!item->pszText) return FALSE;
00782         strcpyW(item->pszText, cit->pszText);
00783     } else if (cit->pszText == LPSTR_TEXTCALLBACKW)
00784         item->pszText = LPSTR_TEXTCALLBACKW;
00785         item->cchTextMax = cit->cchTextMax;
00786     }
00787     if (cit->mask & CBEIF_IMAGE)
00788         item->iImage = cit->iImage;
00789     if (cit->mask & CBEIF_SELECTEDIMAGE)
00790         item->iSelectedImage = cit->iSelectedImage;
00791     if (cit->mask & CBEIF_OVERLAY)
00792         item->iOverlay = cit->iOverlay;
00793     if (cit->mask & CBEIF_INDENT)
00794         item->iIndent = cit->iIndent;
00795     if (cit->mask & CBEIF_LPARAM)
00796         item->lParam = cit->lParam;
00797 
00798     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
00799 
00800     /* if original request was to update edit control, do some fast foot work */
00801     if (cit->iItem == -1 && cit->mask & CBEIF_TEXT) {
00802     COMBOEX_SetEditText (infoPtr, item);
00803     RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE);
00804     }
00805     return TRUE;
00806 }
00807 
00808 static BOOL COMBOEX_SetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA const *cit)
00809 {
00810     COMBOBOXEXITEMW citW;
00811     LPWSTR wstr = NULL;
00812     BOOL ret;
00813 
00814     memcpy(&citW, cit, sizeof(COMBOBOXEXITEMA));
00815     if ((cit->mask & CBEIF_TEXT) && is_textA(cit->pszText)) {
00816     INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0);
00817         wstr = Alloc ((len + 1)*sizeof(WCHAR));
00818     if (!wstr) return FALSE;
00819     MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len);
00820     citW.pszText = wstr;
00821     }
00822     ret = COMBOEX_SetItemW(infoPtr, &citW);
00823 
00824     Free(wstr);
00825 
00826     return ret;
00827 }
00828 
00829 
00830 static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value)
00831 {
00832     BOOL bTemp = infoPtr->unicode;
00833 
00834     TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE");
00835 
00836     infoPtr->unicode = value;
00837 
00838     return bTemp;
00839 }
00840 
00841 
00842 /* ***  CB_xxx message support  *** */
00843 
00844 static INT
00845 COMBOEX_FindStringExact (const COMBOEX_INFO *infoPtr, INT start, LPCWSTR str)
00846 {
00847     INT i;
00848     cmp_func_t cmptext = get_cmp_func(infoPtr);
00849     INT count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
00850 
00851     /* now search from after starting loc and wrapping back to start */
00852     for(i=start+1; i<count; i++) {
00853     CBE_ITEMDATA *item = get_item_data(infoPtr, i);
00854     if ((LRESULT)item == CB_ERR) continue;
00855     if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i;
00856     }
00857     for(i=0; i<=start; i++) {
00858     CBE_ITEMDATA *item = get_item_data(infoPtr, i);
00859     if ((LRESULT)item == CB_ERR) continue;
00860     if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i;
00861     }
00862     return CB_ERR;
00863 }
00864 
00865 
00866 static DWORD_PTR COMBOEX_GetItemData (const COMBOEX_INFO *infoPtr, INT_PTR index)
00867 {
00868     CBE_ITEMDATA const *item1;
00869     CBE_ITEMDATA const *item2;
00870     DWORD_PTR ret = 0;
00871 
00872     item1 = get_item_data(infoPtr, index);
00873     if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
00874     item2 = COMBOEX_FindItem (infoPtr, index);
00875     if (item2 != item1) {
00876         ERR("data structures damaged!\n");
00877         return CB_ERR;
00878     }
00879     if (item1->mask & CBEIF_LPARAM) ret = item1->lParam;
00880     TRACE("returning 0x%08lx\n", ret);
00881     } else {
00882         ret = (DWORD_PTR)item1;
00883         TRACE("non-valid result from combo, returning 0x%08lx\n", ret);
00884     }
00885     return ret;
00886 }
00887 
00888 
00889 static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT_PTR index)
00890 {
00891     CBE_ITEMDATA *item;
00892     INT sel;
00893 
00894     if (!(item = COMBOEX_FindItem(infoPtr, index)))
00895     return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);
00896 
00897     TRACE("selecting item %ld text=%s\n", index, debugstr_txt(item->pszText));
00898     infoPtr->selected = index;
00899 
00900     sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);
00901     COMBOEX_SetEditText (infoPtr, item);
00902     return sel;
00903 }
00904 
00905 
00906 static DWORD_PTR COMBOEX_SetItemData (const COMBOEX_INFO *infoPtr, INT_PTR index, DWORD_PTR data)
00907 {
00908     CBE_ITEMDATA *item1;
00909     CBE_ITEMDATA const *item2;
00910 
00911     item1 = get_item_data(infoPtr, index);
00912     if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
00913     item2 = COMBOEX_FindItem (infoPtr, index);
00914     if (item2 != item1) {
00915         ERR("data structures damaged!\n");
00916         return CB_ERR;
00917     }
00918     item1->mask |= CBEIF_LPARAM;
00919     item1->lParam = data;
00920     TRACE("setting lparam to 0x%08lx\n", data);
00921     return 0;
00922     }
00923     TRACE("non-valid result from combo %p\n", item1);
00924     return (DWORD_PTR)item1;
00925 }
00926 
00927 
00928 static INT COMBOEX_SetItemHeight (COMBOEX_INFO const *infoPtr, INT index, UINT height)
00929 {
00930     RECT cb_wrect, cbx_wrect, cbx_crect;
00931 
00932     /* First, lets forward the message to the normal combo control
00933        just like Windows.     */
00934     if (infoPtr->hwndCombo)
00935        if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
00936              index, height) == CB_ERR) return CB_ERR;
00937 
00938     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
00939     GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
00940     GetClientRect (infoPtr->hwndSelf, &cbx_crect);
00941     /* the height of comboex as height of the combo + comboex border */
00942     height = cb_wrect.bottom-cb_wrect.top
00943              + cbx_wrect.bottom-cbx_wrect.top
00944              - (cbx_crect.bottom-cbx_crect.top);
00945     TRACE("EX window=(%s), client=(%s)\n",
00946           wine_dbgstr_rect(&cbx_wrect), wine_dbgstr_rect(&cbx_crect));
00947     TRACE("CB window=(%s), EX setting=(0,0)-(%d,%d)\n",
00948           wine_dbgstr_rect(&cbx_wrect), cbx_wrect.right-cbx_wrect.left, height);
00949     SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0,
00950           cbx_wrect.right-cbx_wrect.left, height,
00951           SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
00952 
00953     return 0;
00954 }
00955 
00956 
00957 /* ***  WM_xxx message support  *** */
00958 
00959 
00960 static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
00961 {
00962     static const WCHAR NIL[] = { 0 };
00963     COMBOEX_INFO *infoPtr;
00964     LOGFONTW mylogfont;
00965     RECT win_rect;
00966     INT i;
00967 
00968     /* allocate memory for info structure */
00969     infoPtr = Alloc (sizeof(COMBOEX_INFO));
00970     if (!infoPtr) return -1;
00971 
00972     /* initialize info structure */
00973     /* note that infoPtr is allocated zero-filled */
00974 
00975     infoPtr->hwndSelf = hwnd;
00976     infoPtr->selected = -1;
00977 
00978     infoPtr->unicode = IsWindowUnicode (hwnd);
00979     infoPtr->hwndNotify = cs->hwndParent;
00980 
00981     i = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
00982     if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
00983     WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
00984     i = NFR_ANSI;
00985     }
00986     infoPtr->NtfUnicode = (i == NFR_UNICODE);
00987 
00988     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
00989 
00990     if (TRACE_ON(comboex)) {
00991     RECT client, rect;
00992     GetWindowRect(hwnd, &rect);
00993     GetClientRect(hwnd, &client);
00994     TRACE("EX window=(%s), client=(%s)\n",
00995         wine_dbgstr_rect(&rect), wine_dbgstr_rect(&client));
00996     }
00997 
00998     /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
00999     /* specified. It then creates it's own version of the EDIT control  */
01000     /* and makes the ComboBox the parent. This is because a normal      */
01001     /* DROPDOWNLIST does not have an EDIT control, but we need one.     */
01002     /* We also need to place the edit control at the proper location    */
01003     /* (allow space for the icons).                                     */
01004 
01005     infoPtr->hwndCombo = CreateWindowW (WC_COMBOBOXW, NIL,
01006              /* following line added to match native */
01007                          WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
01008                          CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
01009              /* was base and is necessary */
01010              WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED |
01011              GetWindowLongW (hwnd, GWL_STYLE),
01012              cs->y, cs->x, cs->cx, cs->cy, hwnd,
01013              (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID),
01014              (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL);
01015 
01016     /*
01017      * native does the following at this point according to trace:
01018      *  GetWindowThreadProcessId(hwndCombo,0)
01019      *  GetCurrentThreadId()
01020      *  GetWindowThreadProcessId(hwndCombo, &???)
01021      *  GetCurrentProcessId()
01022      */
01023 
01024     SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID,
01025                       (DWORD_PTR)hwnd);
01026     infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
01027 
01028     /*
01029      * Now create our own EDIT control so we can position it.
01030      * It is created only for CBS_DROPDOWN style
01031      */
01032     if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
01033     infoPtr->hwndEdit = CreateWindowExW (0, WC_EDITW, NIL,
01034             WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
01035             0, 0, 0, 0,  /* will set later */
01036             infoPtr->hwndCombo,
01037             (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID),
01038             (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL);
01039 
01040     /* native does the following at this point according to trace:
01041      *  GetWindowThreadProcessId(hwndEdit,0)
01042      *  GetCurrentThreadId()
01043      *  GetWindowThreadProcessId(hwndEdit, &???)
01044      *  GetCurrentProcessId()
01045      */
01046     SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID,
01047                       (DWORD_PTR)hwnd);
01048 
01049     infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0);
01050     }
01051 
01052     /*
01053      * Locate the default font if necessary and then set it in
01054      * all associated controls
01055      */
01056     if (!infoPtr->font) {
01057     SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont),
01058                    &mylogfont, 0);
01059     infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont);
01060     }
01061     SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
01062     if (infoPtr->hwndEdit) {
01063     SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
01064        SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, EC_USEFONTINFO, 0);
01065     }
01066 
01067     COMBOEX_ReSize (infoPtr);
01068 
01069     /* Above is fairly certain, below is much less certain. */
01070 
01071     GetWindowRect(hwnd, &win_rect);
01072 
01073     if (TRACE_ON(comboex)) {
01074     RECT client, rect;
01075     GetClientRect(hwnd, &client);
01076     GetWindowRect(infoPtr->hwndCombo, &rect);
01077     TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n",
01078         wine_dbgstr_rect(&win_rect), wine_dbgstr_rect(&client),
01079         wine_dbgstr_rect(&rect));
01080     }
01081     SetWindowPos(infoPtr->hwndCombo, HWND_TOP, 0, 0,
01082          win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
01083          SWP_NOACTIVATE | SWP_NOREDRAW);
01084 
01085     GetWindowRect(infoPtr->hwndCombo, &win_rect);
01086     TRACE("CB window=(%s)\n", wine_dbgstr_rect(&win_rect));
01087     SetWindowPos(hwnd, HWND_TOP, 0, 0,
01088          win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
01089          SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
01090 
01091     COMBOEX_AdjustEditPos (infoPtr);
01092 
01093     /*
01094      * Create an item structure to represent the data in the
01095      * EDIT control. It is allocated zero-filled.
01096      */
01097     infoPtr->edit = Alloc (sizeof (CBE_ITEMDATA));
01098     if (!infoPtr->edit) {
01099     COMBOEX_Destroy(infoPtr);
01100     return -1;
01101     }
01102 
01103     return 0;
01104 }
01105 
01106 
01107 static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
01108 {
01109     LRESULT lret;
01110     INT command = HIWORD(wParam);
01111     CBE_ITEMDATA *item = 0;
01112     WCHAR wintext[520];
01113     INT cursel, n;
01114     INT_PTR oldItem;
01115     NMCBEENDEDITW cbeend;
01116     DWORD oldflags;
01117     HWND parent = infoPtr->hwndNotify;
01118 
01119     TRACE("for command %d\n", command);
01120 
01121     switch (command)
01122     {
01123     case CBN_DROPDOWN:
01124         SetFocus (infoPtr->hwndCombo);
01125         ShowWindow (infoPtr->hwndEdit, SW_HIDE);
01126         infoPtr->flags |= WCBE_ACTEDIT;
01127         return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01128     case CBN_CLOSEUP:
01129     SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01130     /*
01131      * from native trace of first dropdown after typing in URL in IE4
01132      *  CB_GETCURSEL(Combo)
01133      *  GetWindowText(Edit)
01134      *  CB_GETCURSEL(Combo)
01135      *  CB_GETCOUNT(Combo)
01136      *  CB_GETITEMDATA(Combo, n)
01137      *  WM_NOTIFY(parent, CBEN_ENDEDITA|W)
01138      *  CB_GETCURSEL(Combo)
01139      *  CB_SETCURSEL(COMBOEX, n)
01140      *  SetFocus(Combo)
01141      * the rest is supposition
01142      */
01143     ShowWindow (infoPtr->hwndEdit, SW_SHOW);
01144     InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
01145     if (infoPtr->hwndEdit) InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
01146     cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
01147     if (cursel == -1) {
01148             cmp_func_t cmptext = get_cmp_func(infoPtr);
01149         /* find match from edit against those in Combobox */
01150         GetWindowTextW (infoPtr->hwndEdit, wintext, 520);
01151         n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
01152         for (cursel = 0; cursel < n; cursel++){
01153                 item = get_item_data(infoPtr, cursel);
01154         if ((INT_PTR)item == CB_ERR) break;
01155         if (!cmptext(COMBOEX_GetText(infoPtr, item), wintext)) break;
01156         }
01157         if ((cursel == n) || ((INT_PTR)item == CB_ERR)) {
01158         TRACE("failed to find match??? item=%p cursel=%d\n",
01159               item, cursel);
01160         if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
01161         return 0;
01162         }
01163     }
01164     else {
01165             item = get_item_data(infoPtr, cursel);
01166         if ((INT_PTR)item == CB_ERR) {
01167         TRACE("failed to find match??? item=%p cursel=%d\n",
01168               item, cursel);
01169         if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
01170         return 0;
01171         }
01172     }
01173 
01174     /* Save flags for testing and reset them */
01175     oldflags = infoPtr->flags;
01176     infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
01177 
01178     if (oldflags & WCBE_ACTEDIT) {
01179         cbeend.fChanged = (oldflags & WCBE_EDITCHG);
01180         cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
01181                          CB_GETCURSEL, 0, 0);
01182         cbeend.iWhy = CBENF_DROPDOWN;
01183 
01184         if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, COMBOEX_GetText(infoPtr, item))) return 0;
01185     }
01186 
01187     /* if selection has changed the set the new current selection */
01188     cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
01189     if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) {
01190         infoPtr->selected = cursel;
01191         SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0);
01192         SetFocus(infoPtr->hwndCombo);
01193     }
01194     return 0;
01195 
01196     case CBN_SELCHANGE:
01197     /*
01198      * CB_GETCURSEL(Combo)
01199      * CB_GETITEMDATA(Combo)   < simulated by COMBOEX_FindItem
01200      * lstrlenA
01201      * WM_SETTEXT(Edit)
01202      * WM_GETTEXTLENGTH(Edit)
01203      * WM_GETTEXT(Edit)
01204      * EM_SETSEL(Edit, 0,0)
01205      * WM_GETTEXTLENGTH(Edit)
01206      * WM_GETTEXT(Edit)
01207      * EM_SETSEL(Edit, 0,len)
01208      * return WM_COMMAND to parent
01209      */
01210     oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
01211     if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
01212         ERR("item %ld not found. Problem!\n", oldItem);
01213         break;
01214     }
01215     infoPtr->selected = oldItem;
01216     COMBOEX_SetEditText (infoPtr, item);
01217     return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01218 
01219     case CBN_SELENDOK:
01220     case CBN_SELENDCANCEL:
01221     /*
01222      * We have to change the handle since we are the control
01223      * issuing the message. IE4 depends on this.
01224      */
01225     return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01226 
01227     case CBN_KILLFOCUS:
01228     /*
01229      * from native trace:
01230      *
01231      *  pass to parent
01232      *  WM_GETTEXT(Edit, 104)
01233      *  CB_GETCURSEL(Combo) rets -1
01234      *  WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
01235      *  CB_GETCURSEL(Combo)
01236      *  InvalidateRect(Combo, 0, 0)
01237      *  return 0
01238      */
01239     SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01240     if (infoPtr->flags & WCBE_ACTEDIT) {
01241         GetWindowTextW (infoPtr->hwndEdit, wintext, 260);
01242         cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
01243         cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
01244                          CB_GETCURSEL, 0, 0);
01245         cbeend.iWhy = CBENF_KILLFOCUS;
01246 
01247         infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
01248         if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) return 0;
01249     }
01250     /* possible CB_GETCURSEL */
01251     InvalidateRect (infoPtr->hwndCombo, 0, 0);
01252     return 0;
01253 
01254     case CBN_SETFOCUS:
01255         return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01256 
01257     default:
01258     /*
01259      * We have to change the handle since we are the control
01260      * issuing the message. IE4 depends on this.
01261      * We also need to set the focus back to the Edit control
01262      * after passing the command to the parent of the ComboEx.
01263      */
01264     lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
01265     if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
01266     return lret;
01267     }
01268     return 0;
01269 }
01270 
01271 
01272 static BOOL COMBOEX_WM_DeleteItem (COMBOEX_INFO *infoPtr, DELETEITEMSTRUCT const *dis)
01273 {
01274     CBE_ITEMDATA *item, *olditem;
01275     NMCOMBOBOXEXW nmcit;
01276     UINT i;
01277 
01278     TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%p, data=%08lx\n",
01279       dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData);
01280 
01281     if (dis->itemID >= infoPtr->nb_items) return FALSE;
01282 
01283     olditem = infoPtr->items;
01284     i = infoPtr->nb_items - 1;
01285 
01286     if (i == dis->itemID) {
01287     infoPtr->items = infoPtr->items->next;
01288     }
01289     else {
01290     item = olditem;
01291     i--;
01292 
01293     /* find the prior item in the list */
01294     while (item->next && (i > dis->itemID)) {
01295         item = item->next;
01296         i--;
01297     }
01298     if (!item->next || (i != dis->itemID)) {
01299         ERR("COMBOBOXEX item structures broken. Please report!\n");
01300         return FALSE;
01301     }
01302     olditem = item->next;
01303     item->next = item->next->next;
01304     }
01305     infoPtr->nb_items--;
01306 
01307     memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
01308     nmcit.ceItem.mask=~0;
01309     COMBOEX_CopyItem (olditem, &nmcit.ceItem);
01310     COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit);
01311 
01312     COMBOEX_FreeText(olditem);
01313     Free(olditem);
01314 
01315     return TRUE;
01316 }
01317 
01318 
01319 static LRESULT COMBOEX_DrawItem (const COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT const *dis)
01320 {
01321     static const WCHAR nil[] = { 0 };
01322     CBE_ITEMDATA *item = 0;
01323     SIZE txtsize;
01324     RECT rect;
01325     LPCWSTR str = nil;
01326     UINT xbase, x, y;
01327     INT len;
01328     COLORREF nbkc, ntxc, bkc, txc;
01329     int drawimage, drawstate, xioff;
01330 
01331     TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
01332       dis->CtlType, dis->CtlID);
01333     TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n",
01334       dis->itemID, dis->itemAction, dis->itemState);
01335     TRACE("hWnd=%p hDC=%p (%s) itemData=0x%08lx\n",
01336           dis->hwndItem, dis->hDC, wine_dbgstr_rect(&dis->rcItem), dis->itemData);
01337 
01338     /* MSDN says:                                                       */
01339     /*     "itemID - Specifies the menu item identifier for a menu      */
01340     /*      item or the index of the item in a list box or combo box.   */
01341     /*      For an empty list box or combo box, this member can be -1.  */
01342     /*      This allows the application to draw only the focus          */
01343     /*      rectangle at the coordinates specified by the rcItem        */
01344     /*      member even though there are no items in the control.       */
01345     /*      This indicates to the user whether the list box or combo    */
01346     /*      box has the focus. How the bits are set in the itemAction   */
01347     /*      member determines whether the rectangle is to be drawn as   */
01348     /*      though the list box or combo box has the focus.             */
01349     if (dis->itemID == 0xffffffff) {
01350     if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) ||
01351          ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) {
01352 
01353             TRACE("drawing item -1 special focus, rect=(%s)\n",
01354                   wine_dbgstr_rect(&dis->rcItem));
01355     }
01356     else if ((dis->CtlType == ODT_COMBOBOX) &&
01357          (dis->itemAction == ODA_DRAWENTIRE)) {
01358         /* draw of edit control data */
01359 
01360         if (TRACE_ON(comboex)) {
01361         RECT exrc, cbrc, edrc;
01362         GetWindowRect (infoPtr->hwndSelf, &exrc);
01363         GetWindowRect (infoPtr->hwndCombo, &cbrc);
01364         edrc.left = edrc.top = edrc.right = edrc.bottom = -1;
01365         if (infoPtr->hwndEdit) GetWindowRect (infoPtr->hwndEdit, &edrc);
01366                 TRACE("window rects ex=(%s), cb=(%s), ed=(%s)\n",
01367                       wine_dbgstr_rect(&exrc), wine_dbgstr_rect(&cbrc),
01368                       wine_dbgstr_rect(&edrc));
01369         }
01370     }
01371     else {
01372             ERR("NOT drawing item  -1 special focus, rect=(%s), action=%08x, state=%08x\n",
01373                 wine_dbgstr_rect(&dis->rcItem),
01374                 dis->itemAction, dis->itemState);
01375         return 0;
01376     }
01377     }
01378 
01379     /* If draw item is -1 (edit control) setup the item pointer */
01380     if (dis->itemID == 0xffffffff) {
01381     item = infoPtr->edit;
01382 
01383     if (infoPtr->hwndEdit) {
01384         INT len;
01385 
01386         /* free previous text of edit item */
01387         COMBOEX_FreeText(item);
01388         item->mask &= ~CBEIF_TEXT;
01389         if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) {
01390         item->mask |= CBEIF_TEXT;
01391                 item->pszText = Alloc ((len + 1)*sizeof(WCHAR));
01392         if (item->pszText)
01393             GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1);
01394 
01395            TRACE("edit control hwndEdit=%p, text len=%d str=%s\n",
01396              infoPtr->hwndEdit, len, debugstr_txt(item->pszText));
01397         }
01398     }
01399     }
01400 
01401 
01402     /* if the item pointer is not set, then get the data and locate it */
01403     if (!item) {
01404         item = get_item_data(infoPtr, dis->itemID);
01405     if (item == (CBE_ITEMDATA *)CB_ERR) {
01406         ERR("invalid item for id %d\n", dis->itemID);
01407         return 0;
01408     }
01409     }
01410 
01411     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
01412 
01413     xbase = CBE_STARTOFFSET;
01414     if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) {
01415     INT indent = item->iIndent;
01416     if (indent == I_INDENTCALLBACK) {
01417         NMCOMBOBOXEXW nmce;
01418         ZeroMemory(&nmce, sizeof(nmce));
01419         nmce.ceItem.mask = CBEIF_INDENT;
01420         nmce.ceItem.lParam = item->lParam;
01421         nmce.ceItem.iItem = dis->itemID;
01422         COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce);
01423         if (nmce.ceItem.mask & CBEIF_DI_SETITEM)
01424         item->iIndent = nmce.ceItem.iIndent;
01425         indent = nmce.ceItem.iIndent;
01426     }
01427         xbase += (indent * CBE_INDENT);
01428     }
01429 
01430     drawimage = -2;
01431     drawstate = ILD_NORMAL;
01432     if (item->mask & CBEIF_IMAGE)
01433     drawimage = item->iImage;
01434     if (dis->itemState & ODS_COMBOEXLBOX) {
01435     /* drawing listbox entry */
01436     if (dis->itemState & ODS_SELECTED) {
01437         if (item->mask & CBEIF_SELECTEDIMAGE)
01438             drawimage = item->iSelectedImage;
01439         drawstate = ILD_SELECTED;
01440     }
01441     } else {
01442     /* drawing combo/edit entry */
01443     if (IsWindowVisible(infoPtr->hwndEdit)) {
01444         /* if we have an edit control, the slave the
01445              * selection state to the Edit focus state
01446          */
01447         if (infoPtr->flags & WCBE_EDITFOCUSED) {
01448             if (item->mask & CBEIF_SELECTEDIMAGE)
01449             drawimage = item->iSelectedImage;
01450         drawstate = ILD_SELECTED;
01451         }
01452     } else {
01453         /* if we don't have an edit control, use
01454          * the requested state.
01455          */
01456         if (dis->itemState & ODS_SELECTED) {
01457         if (item->mask & CBEIF_SELECTEDIMAGE)
01458             drawimage = item->iSelectedImage;
01459         drawstate = ILD_SELECTED;
01460         }
01461     }
01462     }
01463 
01464     if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) {
01465         IMAGEINFO iinfo;
01466         iinfo.rcImage.left = iinfo.rcImage.right = 0;
01467     ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
01468     xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
01469     }  else xioff = 0;
01470 
01471     /* setup pointer to text to be drawn */
01472     str = COMBOEX_GetText(infoPtr, item);
01473     if (!str) str = nil;
01474 
01475     len = strlenW (str);
01476     GetTextExtentPoint32W (dis->hDC, str, len, &txtsize);
01477 
01478     if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) {
01479     int overlay = item->iOverlay;
01480 
01481         if (drawimage == I_IMAGECALLBACK) {
01482         NMCOMBOBOXEXW nmce;
01483         ZeroMemory(&nmce, sizeof(nmce));
01484         nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE;
01485         nmce.ceItem.lParam = item->lParam;
01486         nmce.ceItem.iItem = dis->itemID;
01487         COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce);
01488         if (drawstate == ILD_NORMAL) {
01489             if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage;
01490             drawimage = nmce.ceItem.iImage;
01491         } else if (drawstate == ILD_SELECTED) {
01492             if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iSelectedImage = nmce.ceItem.iSelectedImage;
01493             drawimage =  nmce.ceItem.iSelectedImage;
01494         } else ERR("Bad draw state = %d\n", drawstate);
01495         }
01496 
01497     if (overlay == I_IMAGECALLBACK) {
01498         NMCOMBOBOXEXW nmce;
01499         ZeroMemory(&nmce, sizeof(nmce));
01500         nmce.ceItem.mask = CBEIF_OVERLAY;
01501         nmce.ceItem.lParam = item->lParam;
01502         nmce.ceItem.iItem = dis->itemID;
01503         COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce);
01504         if (nmce.ceItem.mask & CBEIF_DI_SETITEM)
01505         item->iOverlay = nmce.ceItem.iOverlay;
01506         overlay = nmce.ceItem.iOverlay;
01507     }
01508 
01509     if (drawimage >= 0 &&
01510         !(infoPtr->dwExtStyle & (CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT))) {
01511         if (overlay > 0) ImageList_SetOverlayImage (infoPtr->himl, overlay, 1);
01512         ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, xbase, dis->rcItem.top,
01513                 drawstate | (overlay > 0 ? INDEXTOOVERLAYMASK(1) : 0));
01514     }
01515 
01516     /* now draw the text */
01517     if (!IsWindowVisible (infoPtr->hwndEdit)) {
01518         nbkc = (dis->itemState & ODS_SELECTED) ?
01519                 comctl32_color.clrHighlight : comctl32_color.clrWindow;
01520         bkc = SetBkColor (dis->hDC, nbkc);
01521         ntxc = (dis->itemState & ODS_SELECTED) ?
01522                 comctl32_color.clrHighlightText : comctl32_color.clrWindowText;
01523         txc = SetTextColor (dis->hDC, ntxc);
01524         x = xbase + xioff;
01525         y = dis->rcItem.top +
01526             (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2;
01527         rect.left = x;
01528         rect.right = x + txtsize.cx;
01529         rect.top = dis->rcItem.top + 1;
01530         rect.bottom = dis->rcItem.bottom - 1;
01531             TRACE("drawing item %d text, rect=(%s)\n",
01532                   dis->itemID, wine_dbgstr_rect(&rect));
01533         ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED,
01534                  &rect, str, len, 0);
01535         SetBkColor (dis->hDC, bkc);
01536         SetTextColor (dis->hDC, txc);
01537     }
01538     }
01539 
01540     if (dis->itemAction & ODA_FOCUS) {
01541     rect.left = xbase + xioff - 1;
01542     rect.right = rect.left + txtsize.cx + 2;
01543     rect.top = dis->rcItem.top;
01544     rect.bottom = dis->rcItem.bottom;
01545     DrawFocusRect(dis->hDC, &rect);
01546     }
01547 
01548     return 0;
01549 }
01550 
01551 
01552 static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr)
01553 {
01554     if (infoPtr->items)
01555     {
01556         CBE_ITEMDATA *item, *next;
01557 
01558         item = infoPtr->items;
01559         while (item) {
01560             next = item->next;
01561             COMBOEX_FreeText (item);
01562             Free (item);
01563             item = next;
01564         }
01565         infoPtr->items = 0;
01566     }
01567 
01568     infoPtr->selected = -1;
01569     infoPtr->nb_items = 0;
01570 }
01571 
01572 
01573 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
01574 {
01575     if (infoPtr->hwndCombo)
01576         RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
01577 
01578     if (infoPtr->hwndEdit)
01579         RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
01580 
01581     COMBOEX_FreeText (infoPtr->edit);
01582     Free (infoPtr->edit);
01583     infoPtr->edit = 0;
01584 
01585     COMBOEX_ResetContent (infoPtr);
01586 
01587     if (infoPtr->defaultFont)
01588     DeleteObject (infoPtr->defaultFont);
01589 
01590     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
01591 
01592     /* free comboex info data */
01593     Free (infoPtr);
01594 
01595     return 0;
01596 }
01597 
01598 
01599 static LRESULT COMBOEX_Enable (COMBOEX_INFO *infoPtr, BOOL enable)
01600 {
01601     TRACE("hwnd=%p, enable=%s\n", infoPtr->hwndSelf, enable ? "TRUE":"FALSE");
01602 
01603     if (infoPtr->hwndEdit)
01604        EnableWindow(infoPtr->hwndEdit, enable);
01605 
01606     EnableWindow(infoPtr->hwndCombo, enable);
01607 
01608     /* Force the control to repaint when the enabled state changes. */
01609     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
01610 
01611     return 1;
01612 }
01613 
01614 
01615 static LRESULT COMBOEX_MeasureItem (COMBOEX_INFO const *infoPtr, MEASUREITEMSTRUCT *mis)
01616 {
01617     static const WCHAR strW[] = { 'W', 0 };
01618     SIZE mysize;
01619     HDC hdc;
01620 
01621     hdc = GetDC (0);
01622     GetTextExtentPointW (hdc, strW, 1, &mysize);
01623     ReleaseDC (0, hdc);
01624     mis->itemHeight = mysize.cy + CBE_EXTRA;
01625 
01626     TRACE("adjusted height hwnd=%p, height=%d\n",
01627       infoPtr->hwndSelf, mis->itemHeight);
01628 
01629     return 0;
01630 }
01631 
01632 
01633 static LRESULT COMBOEX_NCCreate (HWND hwnd)
01634 {
01635     /* WARNING: The COMBOEX_INFO structure is not yet created */
01636     DWORD oldstyle, newstyle;
01637 
01638     oldstyle = (DWORD)GetWindowLongW (hwnd, GWL_STYLE);
01639     newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL | WS_BORDER);
01640     if (newstyle != oldstyle) {
01641     TRACE("req style %08x, resetting style %08x\n",
01642           oldstyle, newstyle);
01643     SetWindowLongW (hwnd, GWL_STYLE, newstyle);
01644     }
01645     return 1;
01646 }
01647 
01648 
01649 static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam)
01650 {
01651     if (lParam == NF_REQUERY) {
01652     INT i = SendMessageW(infoPtr->hwndNotify,
01653              WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
01654     infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
01655     }
01656     return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI;
01657 }
01658 
01659 
01660 static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height)
01661 {
01662     TRACE("(width=%d, height=%d)\n", width, height);
01663 
01664     MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE);
01665 
01666     COMBOEX_AdjustEditPos (infoPtr);
01667 
01668     return 0;
01669 }
01670 
01671 
01672 static LRESULT COMBOEX_SetRedraw(const COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
01673 {
01674     LRESULT ret = DefWindowProcW( infoPtr->hwndSelf, WM_SETREDRAW, wParam, lParam );
01675     if (wParam) RedrawWindow( infoPtr->hwndSelf, NULL, 0, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN );
01676     return ret;
01677 }
01678 
01679 
01680 static LRESULT COMBOEX_WindowPosChanging (const COMBOEX_INFO *infoPtr, WINDOWPOS *wp)
01681 {
01682     RECT cbx_wrect, cbx_crect, cb_wrect;
01683     INT width, height;
01684 
01685     GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
01686     GetClientRect (infoPtr->hwndSelf, &cbx_crect);
01687     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
01688 
01689     /* width is winpos value + border width of comboex */
01690     width = wp->cx
01691         + (cbx_wrect.right-cbx_wrect.left)
01692             - (cbx_crect.right-cbx_crect.left);
01693 
01694     TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n",
01695       wp->x, wp->y, wp->cx, wp->cy, wp->flags);
01696     TRACE("EX window=(%s), client=(%s)\n",
01697           wine_dbgstr_rect(&cbx_wrect), wine_dbgstr_rect(&cbx_crect));
01698     TRACE("CB window=(%s), EX setting=(0,0)-(%d,%d)\n",
01699           wine_dbgstr_rect(&cbx_wrect), width, cb_wrect.bottom-cb_wrect.top);
01700 
01701     if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0,
01702                  width,
01703                  cb_wrect.bottom-cb_wrect.top,
01704                  SWP_NOACTIVATE);
01705 
01706     GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
01707 
01708     /* height is combo window height plus border width of comboex */
01709     height =   (cb_wrect.bottom-cb_wrect.top)
01710          + (cbx_wrect.bottom-cbx_wrect.top)
01711              - (cbx_crect.bottom-cbx_crect.top);
01712     wp->cy = height;
01713     if (infoPtr->hwndEdit) {
01714     COMBOEX_AdjustEditPos (infoPtr);
01715     InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
01716     }
01717 
01718     return 0;
01719 }
01720 
01721 static LRESULT CALLBACK
01722 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
01723                      UINT_PTR uId, DWORD_PTR ref_data)
01724 {
01725     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
01726     NMCBEENDEDITW cbeend;
01727     WCHAR edit_text[260];
01728     COLORREF obkc;
01729     HDC hDC;
01730     RECT rect;
01731     LRESULT lret;
01732 
01733     TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n",
01734       hwnd, uMsg, wParam, lParam, infoPtr);
01735 
01736     if (!infoPtr) return 0;
01737 
01738     switch (uMsg)
01739     {
01740 
01741     case WM_CHAR:
01742         /* handle (ignore) the return character */
01743         if (wParam == VK_RETURN) return 0;
01744         /* all other characters pass into the real Edit */
01745         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01746 
01747     case WM_ERASEBKGND:
01748         /*
01749          * The following was determined by traces of the native
01750          */
01751             hDC = (HDC) wParam;
01752         obkc = SetBkColor (hDC, comctl32_color.clrWindow);
01753             GetClientRect (hwnd, &rect);
01754             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
01755         ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
01756             SetBkColor (hDC, obkc);
01757         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01758 
01759     case WM_KEYDOWN: {
01760         INT_PTR oldItem, selected;
01761         CBE_ITEMDATA *item;
01762 
01763         switch ((INT)wParam)
01764         {
01765         case VK_ESCAPE:
01766         /* native version seems to do following for COMBOEX */
01767         /*
01768          *   GetWindowTextW(Edit,&?, 0x104)             x
01769          *   CB_GETCURSEL to Combo rets -1              x
01770          *   WM_NOTIFY to COMBOEX parent (rebar)        x
01771          *     (CBEN_ENDEDIT{A|W}
01772          *      fChanged = FALSE                        x
01773          *      inewSelection = -1                      x
01774          *      txt="www.hoho"                          x
01775          *      iWhy = 3                                x
01776          *   CB_GETCURSEL to Combo rets -1              x
01777          *   InvalidateRect(Combo, 0)                   x
01778          *   WM_SETTEXT to Edit                         x
01779          *   EM_SETSEL to Edit (0,0)                    x
01780          *   EM_SETSEL to Edit (0,-1)                   x
01781          *   RedrawWindow(Combo, 0, 0, 5)               x
01782          */
01783         TRACE("special code for VK_ESCAPE\n");
01784 
01785         GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
01786 
01787         infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
01788         cbeend.fChanged = FALSE;
01789         cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
01790                              CB_GETCURSEL, 0, 0);
01791         cbeend.iWhy = CBENF_ESCAPE;
01792 
01793         if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0;
01794         oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
01795         InvalidateRect (infoPtr->hwndCombo, 0, 0);
01796         if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
01797             ERR("item %ld not found. Problem!\n", oldItem);
01798             break;
01799         }
01800         infoPtr->selected = oldItem;
01801         COMBOEX_SetEditText (infoPtr, item);
01802         RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
01803                   RDW_INVALIDATE);
01804         break;
01805 
01806         case VK_RETURN:
01807         /* native version seems to do following for COMBOEX */
01808         /*
01809          *   GetWindowTextW(Edit,&?, 0x104)             x
01810          *   CB_GETCURSEL to Combo  rets -1             x
01811          *   CB_GETCOUNT to Combo  rets 0
01812          *   if >0 loop
01813          *       CB_GETITEMDATA to match
01814          * *** above 3 lines simulated by FindItem      x
01815          *   WM_NOTIFY to COMBOEX parent (rebar)        x
01816          *     (CBEN_ENDEDIT{A|W}                       x
01817          *        fChanged = TRUE (-1)                  x
01818          *        iNewSelection = -1 or selected        x
01819          *        txt=                                  x
01820          *        iWhy = 2 (CBENF_RETURN)               x
01821          *   CB_GETCURSEL to Combo  rets -1             x
01822          *   if -1 send CB_SETCURSEL to Combo -1        x
01823          *   InvalidateRect(Combo, 0, 0)                x
01824          *   SetFocus(Edit)                             x
01825          *   CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
01826          */
01827 
01828         TRACE("special code for VK_RETURN\n");
01829 
01830         GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
01831 
01832         infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
01833         selected = SendMessageW (infoPtr->hwndCombo,
01834                      CB_GETCURSEL, 0, 0);
01835 
01836         if (selected != -1) {
01837                     cmp_func_t cmptext = get_cmp_func(infoPtr);
01838             item = COMBOEX_FindItem (infoPtr, selected);
01839             TRACE("handling VK_RETURN, selected = %ld, selected_text=%s\n",
01840               selected, debugstr_txt(item->pszText));
01841             TRACE("handling VK_RETURN, edittext=%s\n",
01842               debugstr_w(edit_text));
01843             if (cmptext (COMBOEX_GetText(infoPtr, item), edit_text)) {
01844             /* strings not equal -- indicate edit has changed */
01845             selected = -1;
01846             }
01847         }
01848 
01849         cbeend.iNewSelection = selected;
01850         cbeend.fChanged = TRUE;
01851         cbeend.iWhy = CBENF_RETURN;
01852         if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
01853             /* abort the change, restore previous */
01854             TRACE("Notify requested abort of change\n");
01855             COMBOEX_SetEditText (infoPtr, infoPtr->edit);
01856             RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
01857                   RDW_INVALIDATE);
01858             return 0;
01859         }
01860         oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
01861         if (oldItem != -1) {
01862             /* if something is selected, then deselect it */
01863                     SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, -1, 0);
01864         }
01865         InvalidateRect (infoPtr->hwndCombo, 0, 0);
01866         SetFocus(infoPtr->hwndEdit);
01867         break;
01868 
01869         case VK_UP:
01870         case VK_DOWN:
01871         {
01872         INT step = wParam == VK_DOWN ? 1 : -1;
01873 
01874         oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0);
01875         if (oldItem >= 0 && oldItem + step >= 0)
01876             SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
01877             return 0;
01878         }
01879         default:
01880         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01881         }
01882         return 0;
01883             }
01884 
01885     case WM_SETFOCUS:
01886         /* remember the focus to set state of icon */
01887         lret = DefSubclassProc(hwnd, uMsg, wParam, lParam);
01888         infoPtr->flags |= WCBE_EDITFOCUSED;
01889         return lret;
01890 
01891     case WM_KILLFOCUS:
01892         /*
01893          * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
01894          */
01895         infoPtr->flags &= ~WCBE_EDITFOCUSED;
01896         if (infoPtr->flags & WCBE_ACTEDIT) {
01897         infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
01898 
01899         GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
01900         cbeend.fChanged = FALSE;
01901         cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
01902                              CB_GETCURSEL, 0, 0);
01903         cbeend.iWhy = CBENF_KILLFOCUS;
01904 
01905         COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text);
01906         }
01907         /* fall through */
01908 
01909     default:
01910         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01911     }
01912 }
01913 
01914 
01915 static LRESULT CALLBACK
01916 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
01917                       UINT_PTR uId, DWORD_PTR ref_data)
01918 {
01919     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
01920     NMCBEENDEDITW cbeend;
01921     NMMOUSE nmmse;
01922     COLORREF obkc;
01923     HDC hDC;
01924     HWND focusedhwnd;
01925     RECT rect;
01926     POINT pt;
01927     WCHAR edit_text[260];
01928 
01929     TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n",
01930       hwnd, uMsg, wParam, lParam, infoPtr);
01931 
01932     if (!infoPtr) return 0;
01933 
01934     switch (uMsg)
01935     {
01936 
01937     case WM_DRAWITEM:
01938         /*
01939          * The only way this message should come is from the
01940          * child Listbox issuing the message. Flag this so
01941          * that ComboEx knows this is listbox.
01942          */
01943         ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
01944         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01945 
01946     case WM_ERASEBKGND:
01947         /*
01948          * The following was determined by traces of the native
01949          */
01950             hDC = (HDC) wParam;
01951         obkc = SetBkColor (hDC, comctl32_color.clrWindow);
01952             GetClientRect (hwnd, &rect);
01953             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
01954         ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
01955             SetBkColor (hDC, obkc);
01956         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01957 
01958     case WM_SETCURSOR:
01959         /*
01960          *  WM_NOTIFY to comboex parent (rebar)
01961          *   with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001
01962          *  CallWindowProc (previous)
01963          */
01964         nmmse.dwItemSpec = 0;
01965         nmmse.dwItemData = 0;
01966         nmmse.pt.x = 0;
01967         nmmse.pt.y = 0;
01968         nmmse.dwHitInfo = lParam;
01969         COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
01970         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01971 
01972     case WM_LBUTTONDOWN:
01973         GetClientRect (hwnd, &rect);
01974         rect.bottom = rect.top + SendMessageW(infoPtr->hwndSelf,
01975                                       CB_GETITEMHEIGHT, -1, 0);
01976         rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL);
01977         pt.x = (short)LOWORD(lParam);
01978         pt.y = (short)HIWORD(lParam);
01979         if (PtInRect(&rect, pt))
01980         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01981 
01982         infoPtr->flags |= WCBE_MOUSECAPTURED;
01983         SetCapture(hwnd);
01984         break;
01985 
01986     case WM_LBUTTONUP:
01987         if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
01988         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01989 
01990         ReleaseCapture();
01991         infoPtr->flags &= ~WCBE_MOUSECAPTURED;
01992         if (infoPtr->flags & WCBE_MOUSEDRAGGED) {
01993         infoPtr->flags &= ~WCBE_MOUSEDRAGGED;
01994         } else {
01995         SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0);
01996         }
01997         break;
01998 
01999     case WM_MOUSEMOVE:
02000         if ( (infoPtr->flags & WCBE_MOUSECAPTURED) &&
02001         !(infoPtr->flags & WCBE_MOUSEDRAGGED)) {
02002         GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
02003         COMBOEX_NotifyDragBegin(infoPtr, edit_text);
02004         infoPtr->flags |= WCBE_MOUSEDRAGGED;
02005         }
02006         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
02007 
02008     case WM_COMMAND:
02009         switch (HIWORD(wParam)) {
02010 
02011         case EN_UPDATE:
02012         /* traces show that COMBOEX does not issue CBN_EDITUPDATE
02013          * on the EN_UPDATE
02014          */
02015         return 0;
02016 
02017         case EN_KILLFOCUS:
02018         /*
02019          * Native does:
02020          *
02021          *  GetFocus() retns AA
02022          *  GetWindowTextW(Edit)
02023          *  CB_GETCURSEL(Combo) (got -1)
02024          *  WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
02025          *  CB_GETCURSEL(Combo) (got -1)
02026          *  InvalidateRect(Combo, 0, 0)
02027          *  WM_KILLFOCUS(Combo, AA)
02028          *  return 0;
02029          */
02030         focusedhwnd = GetFocus();
02031         if (infoPtr->flags & WCBE_ACTEDIT) {
02032             GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
02033             cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
02034             cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
02035                              CB_GETCURSEL, 0, 0);
02036             cbeend.iWhy = CBENF_KILLFOCUS;
02037 
02038             infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
02039             if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0;
02040         }
02041         /* possible CB_GETCURSEL */
02042         InvalidateRect (infoPtr->hwndCombo, 0, 0);
02043         if (focusedhwnd)
02044             SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS,
02045                   (WPARAM)focusedhwnd, 0);
02046         return 0;
02047 
02048         case EN_SETFOCUS: {
02049         /*
02050          * For EN_SETFOCUS this issues the same calls and messages
02051          *  as the native seems to do.
02052          *
02053          * for some cases however native does the following:
02054          *   (noticed after SetFocus during LBUTTONDOWN on
02055          *    on dropdown arrow)
02056          *  WM_GETTEXTLENGTH (Edit);
02057          *  WM_GETTEXT (Edit, len+1, str);
02058          *  EM_SETSEL (Edit, 0, 0);
02059          *  WM_GETTEXTLENGTH (Edit);
02060          *  WM_GETTEXT (Edit, len+1, str);
02061          *  EM_SETSEL (Edit, 0, len);
02062          *  WM_NOTIFY (parent, CBEN_BEGINEDIT)
02063          */
02064         NMHDR hdr;
02065 
02066         SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
02067         SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
02068         COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr);
02069         infoPtr->flags |= WCBE_ACTEDIT;
02070         infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */
02071         return 0;
02072             }
02073 
02074         case EN_CHANGE: {
02075         /*
02076          * For EN_CHANGE this issues the same calls and messages
02077          *  as the native seems to do.
02078          */
02079         WCHAR edit_text[260];
02080         LPCWSTR lastwrk;
02081                 cmp_func_t cmptext = get_cmp_func(infoPtr);
02082 
02083         INT_PTR selected = SendMessageW (infoPtr->hwndCombo,
02084                                                  CB_GETCURSEL, 0, 0);
02085 
02086         /* lstrlenW( lastworkingURL ) */
02087 
02088         GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
02089         if (selected == -1) {
02090             lastwrk = infoPtr->edit->pszText;
02091         }
02092         else {
02093             CBE_ITEMDATA *item = COMBOEX_FindItem (infoPtr, selected);
02094             lastwrk = COMBOEX_GetText(infoPtr, item);
02095         }
02096 
02097         TRACE("handling EN_CHANGE, selected = %ld, selected_text=%s\n",
02098               selected, debugstr_w(lastwrk));
02099         TRACE("handling EN_CHANGE, edittext=%s\n",
02100               debugstr_w(edit_text));
02101 
02102         /* cmptext is between lastworkingURL and GetWindowText */
02103         if (cmptext (lastwrk, edit_text)) {
02104             /* strings not equal -- indicate edit has changed */
02105             infoPtr->flags |= WCBE_EDITCHG;
02106         }
02107         SendMessageW ( infoPtr->hwndNotify, WM_COMMAND,
02108                    MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf),
02109                       CBN_EDITCHANGE),
02110                    (LPARAM)infoPtr->hwndSelf);
02111         return 0;
02112             }
02113 
02114         case LBN_SELCHANGE:
02115         /*
02116          * Therefore from traces there is no additional code here
02117          */
02118 
02119         /*
02120          * Using native COMCTL32 gets the following:
02121          *  1 == SHDOCVW.DLL  issues call/message
02122          *  2 == COMCTL32.DLL  issues call/message
02123          *  3 == WINE  issues call/message
02124          *
02125          *
02126          * for LBN_SELCHANGE:
02127          *    1  CB_GETCURSEL(ComboEx)
02128          *    1  CB_GETDROPPEDSTATE(ComboEx)
02129          *    1  CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE)
02130          *    2  CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE)
02131          **   call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE)
02132          *    3  WM_COMMAND(ComboEx, CBN_SELENDOK)
02133          *      WM_USER+49(ComboLB, 1,0)  <=============!!!!!!!!!!!
02134          *    3  ShowWindow(ComboLB, SW_HIDE)
02135          *    3  RedrawWindow(Combo,  RDW_UPDATENOW)
02136          *    3  WM_COMMAND(ComboEX, CBN_CLOSEUP)
02137          **   end of CBRollUp
02138          *    3  WM_COMMAND(ComboEx, CBN_SELCHANGE)  (echo to parent)
02139          *    ?  LB_GETCURSEL              <==|
02140          *    ?  LB_GETTEXTLEN                |
02141          *    ?  LB_GETTEXT                   | Needs to be added to
02142          *    ?  WM_CTLCOLOREDIT(ComboEx)     | Combo processing
02143          *    ?  LB_GETITEMDATA               |
02144          *    ?  WM_DRAWITEM(ComboEx)      <==|
02145          */
02146         default:
02147         break;
02148         }/* fall through */
02149     default:
02150         return DefSubclassProc(hwnd, uMsg, wParam, lParam);
02151     }
02152     return 0;
02153 }
02154 
02155 
02156 static LRESULT WINAPI
02157 COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
02158 {
02159     COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
02160 
02161     TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
02162 
02163     if (!infoPtr) {
02164     if (uMsg == WM_CREATE)
02165         return COMBOEX_Create (hwnd, (LPCREATESTRUCTA)lParam);
02166     if (uMsg == WM_NCCREATE)
02167         COMBOEX_NCCreate (hwnd);
02168         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
02169     }
02170 
02171     switch (uMsg)
02172     {
02173         case CBEM_DELETEITEM:
02174         return COMBOEX_DeleteItem (infoPtr, wParam);
02175 
02176     case CBEM_GETCOMBOCONTROL:
02177         return (LRESULT)infoPtr->hwndCombo;
02178 
02179     case CBEM_GETEDITCONTROL:
02180         return (LRESULT)infoPtr->hwndEdit;
02181 
02182     case CBEM_GETEXTENDEDSTYLE:
02183         return infoPtr->dwExtStyle;
02184 
02185     case CBEM_GETIMAGELIST:
02186         return (LRESULT)infoPtr->himl;
02187 
02188     case CBEM_GETITEMA:
02189         return (LRESULT)COMBOEX_GetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
02190 
02191     case CBEM_GETITEMW:
02192         return (LRESULT)COMBOEX_GetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
02193 
02194     case CBEM_GETUNICODEFORMAT:
02195         return infoPtr->unicode;
02196 
02197     case CBEM_HASEDITCHANGED:
02198         return COMBOEX_HasEditChanged (infoPtr);
02199 
02200     case CBEM_INSERTITEMA:
02201         return COMBOEX_InsertItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
02202 
02203     case CBEM_INSERTITEMW:
02204         return COMBOEX_InsertItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
02205 
02206     case CBEM_SETEXSTYLE:
02207     case CBEM_SETEXTENDEDSTYLE:
02208         return COMBOEX_SetExtendedStyle (infoPtr, (DWORD)wParam, (DWORD)lParam);
02209 
02210     case CBEM_SETIMAGELIST:
02211         return (LRESULT)COMBOEX_SetImageList (infoPtr, (HIMAGELIST)lParam);
02212 
02213     case CBEM_SETITEMA:
02214         return COMBOEX_SetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam);
02215 
02216     case CBEM_SETITEMW:
02217         return COMBOEX_SetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam);
02218 
02219     case CBEM_SETUNICODEFORMAT:
02220         return COMBOEX_SetUnicodeFormat (infoPtr, wParam);
02221 
02222     /*case CBEM_SETWINDOWTHEME:
02223         FIXME("CBEM_SETWINDOWTHEME: stub\n");*/
02224 
02225     case WM_SETTEXT:
02226     case WM_GETTEXT:
02227     case WM_GETTEXTLENGTH:
02228             return SendMessageW(infoPtr->hwndEdit, uMsg, wParam, lParam);
02229 
02230     case CB_GETLBTEXT:
02231             return COMBOEX_GetListboxText(infoPtr, wParam, (LPWSTR)lParam);
02232 
02233     case CB_GETLBTEXTLEN:
02234             return COMBOEX_GetListboxText(infoPtr, wParam, NULL);
02235 
02236     case CB_RESETCONTENT:
02237             COMBOEX_ResetContent(infoPtr);
02238             /* fall through */
02239 
02240 /*   Combo messages we are not sure if we need to process or just forward */
02241     case CB_GETDROPPEDCONTROLRECT:
02242     case CB_GETITEMHEIGHT:
02243     case CB_GETEXTENDEDUI:
02244     case CB_LIMITTEXT:
02245     case CB_SELECTSTRING:
02246 
02247 /*   Combo messages OK to just forward to the regular COMBO */
02248     case CB_GETCOUNT:
02249     case CB_GETCURSEL:
02250     case CB_GETDROPPEDSTATE:
02251         case CB_SETDROPPEDWIDTH:
02252         case CB_SETEXTENDEDUI:
02253         case CB_SHOWDROPDOWN:
02254         return SendMessageW (infoPtr->hwndCombo, uMsg, wParam, lParam);
02255 
02256 /*   Combo messages we need to process specially */
02257         case CB_FINDSTRINGEXACT:
02258         return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCWSTR)lParam);
02259 
02260     case CB_GETITEMDATA:
02261         return COMBOEX_GetItemData (infoPtr, (INT)wParam);
02262 
02263     case CB_SETCURSEL:
02264         return COMBOEX_SetCursel (infoPtr, (INT)wParam);
02265 
02266     case CB_SETITEMDATA:
02267         return COMBOEX_SetItemData (infoPtr, (INT)wParam, (DWORD_PTR)lParam);
02268 
02269     case CB_SETITEMHEIGHT:
02270         return COMBOEX_SetItemHeight (infoPtr, (INT)wParam, (UINT)lParam);
02271 
02272 
02273 
02274 /*   Window messages passed to parent */
02275     case WM_COMMAND:
02276         return COMBOEX_Command (infoPtr, wParam);
02277 
02278     case WM_NOTIFY:
02279         if (infoPtr->NtfUnicode)
02280         return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
02281         else
02282         return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam);
02283 
02284 
02285 /*   Window messages we need to process */
02286         case WM_DELETEITEM:
02287         return COMBOEX_WM_DeleteItem (infoPtr, (DELETEITEMSTRUCT *)lParam);
02288 
02289         case WM_DRAWITEM:
02290             return COMBOEX_DrawItem (infoPtr, (DRAWITEMSTRUCT *)lParam);
02291 
02292     case WM_DESTROY:
02293         return COMBOEX_Destroy (infoPtr);
02294 
02295     case WM_ENABLE:
02296         return COMBOEX_Enable (infoPtr, (BOOL)wParam);
02297 
02298         case WM_MEASUREITEM:
02299             return COMBOEX_MeasureItem (infoPtr, (MEASUREITEMSTRUCT *)lParam);
02300 
02301         case WM_NOTIFYFORMAT:
02302         return COMBOEX_NotifyFormat (infoPtr, lParam);
02303 
02304     case WM_SIZE:
02305         return COMBOEX_Size (infoPtr, LOWORD(lParam), HIWORD(lParam));
02306 
02307         case WM_SETREDRAW:
02308             return COMBOEX_SetRedraw(infoPtr, wParam, lParam);
02309 
02310         case WM_WINDOWPOSCHANGING:
02311         return COMBOEX_WindowPosChanging (infoPtr, (WINDOWPOS *)lParam);
02312 
02313         case WM_SETFOCUS:
02314             SetFocus(infoPtr->hwndCombo);
02315             return 0;
02316 
02317         case WM_SYSCOLORCHANGE:
02318             COMCTL32_RefreshSysColors();
02319             return 0;
02320 
02321     default:
02322         if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
02323         ERR("unknown msg %04x wp=%08lx lp=%08lx\n",uMsg,wParam,lParam);
02324         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
02325     }
02326 }
02327 
02328 
02329 void COMBOEX_Register (void)
02330 {
02331     WNDCLASSW wndClass;
02332 
02333     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
02334     wndClass.style         = CS_GLOBALCLASS;
02335     wndClass.lpfnWndProc   = COMBOEX_WindowProc;
02336     wndClass.cbClsExtra    = 0;
02337     wndClass.cbWndExtra    = sizeof(COMBOEX_INFO *);
02338     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
02339     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
02340     wndClass.lpszClassName = WC_COMBOBOXEXW;
02341 
02342     RegisterClassW (&wndClass);
02343 }
02344 
02345 
02346 void COMBOEX_Unregister (void)
02347 {
02348     UnregisterClassW (WC_COMBOBOXEXW, NULL);
02349 }

Generated on Sun May 27 2012 04:22:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.