[RFC 2/2] Share user32 combo with comctl32 combo

Fabian Maurer dark.shadow4 at web.de
Sat Nov 10 11:05:22 CST 2018


Currently combobox (and other controls) are duplicated in
user32 and comctl32.
Since most of the code is the same,
it would make sense to deduplicate it, and have one common
implementation to for both versions of the control.

This is a POC implementation on how I imagine it could be done,
is this something we could implement?
---
 dlls/comctl32/combo.c         | 2104 +----------------------------
 dlls/user32/combo.c           | 2163 +-----------------------------
 include/wine/controls/combo.c | 2358 +++++++++++++++++++++++++++++++++
 3 files changed, 2365 insertions(+), 4260 deletions(-)
 create mode 100644 include/wine/controls/combo.c

diff --git a/dlls/comctl32/combo.c b/dlls/comctl32/combo.c
index 12ea7bbff6..6124884482 100644
--- a/dlls/comctl32/combo.c
+++ b/dlls/comctl32/combo.c
@@ -38,2113 +38,15 @@
 
 #include "comctl32.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(combo);
+#define CONTROL_VERSION 2
+#include "wine/controls/combo.c"
 
-  /* bits in the dwKeyData */
-#define KEYDATA_ALT             0x2000
-#define KEYDATA_PREVSTATE       0x4000
-
-/*
- * Additional combo box definitions
- */
-
-#define CB_NOTIFY( lphc, code ) \
-    (SendMessageW((lphc)->owner, WM_COMMAND, \
-                  MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)), (LPARAM)(lphc)->self))
-
-#define CB_DISABLED( lphc )   (!IsWindowEnabled((lphc)->self))
-#define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
-#define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
-#define CB_HWND( lphc )       ((lphc)->self)
-#define CB_GETTYPE( lphc )    ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
-
-#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
-
-/*
- * Drawing globals
- */
-static HBITMAP 	hComboBmp = 0;
-static UINT	CBitHeight, CBitWidth;
-
-/*
- * Look and feel dependent "constants"
- */
-
-#define COMBO_YBORDERGAP         5
-#define COMBO_XBORDERSIZE()      2
-#define COMBO_YBORDERSIZE()      2
-#define COMBO_EDITBUTTONSPACE()  0
-#define EDIT_CONTROL_PADDING()   1
-
-#define ID_CB_LISTBOX           1000
-#define ID_CB_EDIT              1001
-
-/***********************************************************************
- *           COMBO_Init
- *
- * Load combo button bitmap.
- */
-static BOOL COMBO_Init(void)
-{
-  HDC		hDC;
-
-  if( hComboBmp ) return TRUE;
-  if( (hDC = CreateCompatibleDC(0)) )
-  {
-    BOOL	bRet = FALSE;
-    if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
-    {
-      BITMAP      bm;
-      HBITMAP     hPrevB;
-      RECT        r;
-
-      GetObjectW( hComboBmp, sizeof(bm), &bm );
-      CBitHeight = bm.bmHeight;
-      CBitWidth  = bm.bmWidth;
-
-      TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
-
-      hPrevB = SelectObject( hDC, hComboBmp);
-      SetRect( &r, 0, 0, CBitWidth, CBitHeight );
-      InvertRect( hDC, &r );
-      SelectObject( hDC, hPrevB );
-      bRet = TRUE;
-    }
-    DeleteDC( hDC );
-    return bRet;
-  }
-  return FALSE;
-}
-
-/***********************************************************************
- *           COMBO_NCCreate
- */
-static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
-{
-    HEADCOMBO *lphc;
-
-    if (COMBO_Init() && (lphc = heap_alloc_zero(sizeof(*lphc))))
-    {
-        lphc->self = hwnd;
-        SetWindowLongPtrW( hwnd, 0, (LONG_PTR)lphc );
-
-       /* some braindead apps do try to use scrollbar/border flags */
-
-	lphc->dwStyle = style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
-        SetWindowLongW( hwnd, GWL_STYLE, style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL) );
-
-	/*
-	 * We also have to remove the client edge style to make sure
-	 * we don't end-up with a non client area.
-	 */
-        SetWindowLongW( hwnd, GWL_EXSTYLE,
-                        GetWindowLongW( hwnd, GWL_EXSTYLE ) & ~WS_EX_CLIENTEDGE );
-
-	if( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
-              lphc->dwStyle |= CBS_HASSTRINGS;
-	if( !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
-	      lphc->wState |= CBF_NOTIFY;
-
-        TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/***********************************************************************
- *           COMBO_NCDestroy
- */
-static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
-{
-    if (lphc)
-    {
-        TRACE("[%p]: freeing storage\n", lphc->self);
-
-        if ( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
-            DestroyWindow( lphc->hWndLBox );
-
-        SetWindowLongPtrW( lphc->self, 0, 0 );
-        heap_free( lphc );
-    }
-
-    return 0;
-}
-
-/***********************************************************************
- *           CBGetTextAreaHeight
- *
- * This method will calculate the height of the text area of the
- * combobox.
- * The height of the text area is set in two ways.
- * It can be set explicitly through a combobox message or through a
- * WM_MEASUREITEM callback.
- * If this is not the case, the height is set to font height + 4px
- * This height was determined through experimentation.
- * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
- */
-static INT CBGetTextAreaHeight(
-  HWND        hwnd,
-  LPHEADCOMBO lphc)
-{
-  INT iTextItemHeight;
-
-  if( lphc->editHeight ) /* explicitly set height */
-  {
-    iTextItemHeight = lphc->editHeight;
-  }
-  else
-  {
-    TEXTMETRICW tm;
-    HDC         hDC       = GetDC(hwnd);
-    HFONT       hPrevFont = 0;
-    INT         baseUnitY;
-
-    if (lphc->hFont)
-      hPrevFont = SelectObject( hDC, lphc->hFont );
-
-    GetTextMetricsW(hDC, &tm);
-
-    baseUnitY = tm.tmHeight;
-
-    if( hPrevFont )
-      SelectObject( hDC, hPrevFont );
-
-    ReleaseDC(hwnd, hDC);
-
-    iTextItemHeight = baseUnitY + 4;
-  }
-
-  /*
-   * Check the ownerdraw case if we haven't asked the parent the size
-   * of the item yet.
-   */
-  if ( CB_OWNERDRAWN(lphc) &&
-       (lphc->wState & CBF_MEASUREITEM) )
-  {
-    MEASUREITEMSTRUCT measureItem;
-    RECT              clientRect;
-    INT               originalItemHeight = iTextItemHeight;
-    UINT id = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
-
-    /*
-     * We use the client rect for the width of the item.
-     */
-    GetClientRect(hwnd, &clientRect);
-
-    lphc->wState &= ~CBF_MEASUREITEM;
-
-    /*
-     * Send a first one to measure the size of the text area
-     */
-    measureItem.CtlType    = ODT_COMBOBOX;
-    measureItem.CtlID      = id;
-    measureItem.itemID     = -1;
-    measureItem.itemWidth  = clientRect.right;
-    measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
-    measureItem.itemData   = 0;
-    SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
-    iTextItemHeight = 6 + measureItem.itemHeight;
-
-    /*
-     * Send a second one in the case of a fixed ownerdraw list to calculate the
-     * size of the list items. (we basically do this on behalf of the listbox)
-     */
-    if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
-    {
-      measureItem.CtlType    = ODT_COMBOBOX;
-      measureItem.CtlID      = id;
-      measureItem.itemID     = 0;
-      measureItem.itemWidth  = clientRect.right;
-      measureItem.itemHeight = originalItemHeight;
-      measureItem.itemData   = 0;
-      SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
-      lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
-    }
-
-    /*
-     * Keep the size for the next time
-     */
-    lphc->editHeight = iTextItemHeight;
-  }
-
-  return iTextItemHeight;
-}
-
-/***********************************************************************
- *           CBForceDummyResize
- *
- * The dummy resize is used for listboxes that have a popup to trigger
- * a re-arranging of the contents of the combobox and the recalculation
- * of the size of the "real" control window.
- */
-static void CBForceDummyResize(
-  LPHEADCOMBO lphc)
-{
-  RECT windowRect;
-  int newComboHeight;
-
-  newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
-
-  GetWindowRect(lphc->self, &windowRect);
-
-  /*
-   * We have to be careful, resizing a combobox also has the meaning that the
-   * dropped rect will be resized. In this case, we want to trigger a resize
-   * to recalculate layout but we don't want to change the dropped rectangle
-   * So, we pass the height of text area of control as the height.
-   * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
-   * message.
-   */
-  SetWindowPos( lphc->self,
-		NULL,
-		0, 0,
-		windowRect.right  - windowRect.left,
-		newComboHeight,
-		SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
-}
-
-/***********************************************************************
- *           CBCalcPlacement
- *
- * Set up component coordinates given valid lphc->RectCombo.
- */
-static void CBCalcPlacement(
-  HWND        hwnd,
-  LPHEADCOMBO lphc,
-  LPRECT      lprEdit,
-  LPRECT      lprButton,
-  LPRECT      lprLB)
-{
-  /*
-   * Again, start with the client rectangle.
-   */
-  GetClientRect(hwnd, lprEdit);
-
-  /*
-   * Remove the borders
-   */
-  InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
-
-  /*
-   * Chop off the bottom part to fit with the height of the text area.
-   */
-  lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
-
-  /*
-   * The button starts the same vertical position as the text area.
-   */
-  CopyRect(lprButton, lprEdit);
-
-  /*
-   * If the combobox is "simple" there is no button.
-   */
-  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
-    lprButton->left = lprButton->right = lprButton->bottom = 0;
-  else
-  {
-    /*
-     * Let's assume the combobox button is the same width as the
-     * scrollbar button.
-     * size the button horizontally and cut-off the text area.
-     */
-    lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
-    lprEdit->right  = lprButton->left;
-  }
-
-  /*
-   * In the case of a dropdown, there is an additional spacing between the
-   * text area and the button.
-   */
-  if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-  {
-    lprEdit->right -= COMBO_EDITBUTTONSPACE();
-  }
-
-  /*
-   * If we have an edit control, we space it away from the borders slightly.
-   */
-  if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
-  {
-    InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
-  }
-
-  /*
-   * Adjust the size of the listbox popup.
-   */
-  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
-  {
-    /*
-     * Use the client rectangle to initialize the listbox rectangle
-     */
-    GetClientRect(hwnd, lprLB);
-
-    /*
-     * Then, chop-off the top part.
-     */
-    lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
-  }
-  else
-  {
-    /*
-     * Make sure the dropped width is as large as the combobox itself.
-     */
-    if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
-    {
-      lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
-
-      /*
-       * In the case of a dropdown, the popup listbox is offset to the right.
-       * so, we want to make sure it's flush with the right side of the
-       * combobox
-       */
-      if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	lprLB->right -= COMBO_EDITBUTTONSPACE();
-    }
-    else
-       lprLB->right = lprLB->left + lphc->droppedWidth;
-  }
-
-  /* don't allow negative window width */
-  if (lprEdit->right < lprEdit->left)
-    lprEdit->right = lprEdit->left;
-
-  TRACE("\ttext\t= (%s)\n", wine_dbgstr_rect(lprEdit));
-
-  TRACE("\tbutton\t= (%s)\n", wine_dbgstr_rect(lprButton));
-
-  TRACE("\tlbox\t= (%s)\n", wine_dbgstr_rect(lprLB));
-}
-
-/***********************************************************************
- *           CBGetDroppedControlRect
- */
-static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
-{
-    /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
-     of the combo box and the lower right corner of the listbox */
-
-    GetWindowRect(lphc->self, lpRect);
-
-    lpRect->right =  lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
-    lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
-
-}
-
-/***********************************************************************
- *           COMBO_Create
- */
-static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style )
-{
-  static const WCHAR clbName[] = {'C','o','m','b','o','L','B','o','x',0};
-  static const WCHAR editName[] = {'E','d','i','t',0};
-
-  OpenThemeData( hwnd, WC_COMBOBOXW );
-  if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
-  if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
-
-  lphc->owner = hwndParent;
-
-  /*
-   * The item height and dropped width are not set when the control
-   * is created.
-   */
-  lphc->droppedWidth = lphc->editHeight = 0;
-
-  /*
-   * The first time we go through, we want to measure the ownerdraw item
-   */
-  lphc->wState |= CBF_MEASUREITEM;
-
-  /*
-   * Per default the comctl32 version of combo shows up to 30 items
-   */
-  lphc->visibleItems = 30;
-
-  /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
-
-  if( lphc->owner || !(style & WS_VISIBLE) )
-  {
-      UINT lbeStyle   = 0;
-      UINT lbeExStyle = 0;
-
-      /*
-       * Initialize the dropped rect to the size of the client area of the
-       * control and then, force all the areas of the combobox to be
-       * recalculated.
-       */
-      GetClientRect( hwnd, &lphc->droppedRect );
-      CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
-
-      /*
-       * Adjust the position of the popup listbox if it's necessary
-       */
-      if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
-      {
-	lphc->droppedRect.top   = lphc->textRect.bottom + COMBO_YBORDERSIZE();
-
-	/*
-	 * If it's a dropdown, the listbox is offset
-	 */
-	if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	  lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
-
-        if (lphc->droppedRect.bottom < lphc->droppedRect.top)
-            lphc->droppedRect.bottom = lphc->droppedRect.top;
-        if (lphc->droppedRect.right < lphc->droppedRect.left)
-            lphc->droppedRect.right = lphc->droppedRect.left;
-        MapWindowPoints( hwnd, 0, (LPPOINT)&lphc->droppedRect, 2 );
-      }
-
-      /* create listbox popup */
-
-      lbeStyle = (LBS_NOTIFY | LBS_COMBOBOX | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
-                 (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
-
-      if( lphc->dwStyle & CBS_SORT )
-	lbeStyle |= LBS_SORT;
-      if( lphc->dwStyle & CBS_HASSTRINGS )
-	lbeStyle |= LBS_HASSTRINGS;
-      if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
-	lbeStyle |= LBS_NOINTEGRALHEIGHT;
-      if( lphc->dwStyle & CBS_DISABLENOSCROLL )
-	lbeStyle |= LBS_DISABLENOSCROLL;
-
-      if( CB_GETTYPE(lphc) == CBS_SIMPLE ) 	/* child listbox */
-      {
-	lbeStyle |= WS_VISIBLE;
-
-	/*
-	 * In win 95 look n feel, the listbox in the simple combobox has
-	 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
-	 */
-	lbeStyle   &= ~WS_BORDER;
-	lbeExStyle |= WS_EX_CLIENTEDGE;
-      }
-      else
-      {
-        lbeExStyle |= (WS_EX_TOPMOST | WS_EX_TOOLWINDOW);
-      }
-
-      lphc->hWndLBox = CreateWindowExW(lbeExStyle, clbName, NULL, lbeStyle,
-              lphc->droppedRect.left, lphc->droppedRect.top, lphc->droppedRect.right - lphc->droppedRect.left,
-              lphc->droppedRect.bottom - lphc->droppedRect.top, hwnd, (HMENU)ID_CB_LISTBOX,
-              (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
-      if( lphc->hWndLBox )
-      {
-	  BOOL	bEdit = TRUE;
-	  lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
-
-	  if( lphc->wState & CBF_EDIT )
-	  {
-	      if( lphc->dwStyle & CBS_OEMCONVERT )
-		  lbeStyle |= ES_OEMCONVERT;
-	      if( lphc->dwStyle & CBS_AUTOHSCROLL )
-		  lbeStyle |= ES_AUTOHSCROLL;
-	      if( lphc->dwStyle & CBS_LOWERCASE )
-		  lbeStyle |= ES_LOWERCASE;
-	      else if( lphc->dwStyle & CBS_UPPERCASE )
-		  lbeStyle |= ES_UPPERCASE;
-
-              if (!IsWindowEnabled(hwnd)) lbeStyle |= WS_DISABLED;
-
-              lphc->hWndEdit = CreateWindowExW(0, editName, NULL, lbeStyle,
-                                               lphc->textRect.left, lphc->textRect.top,
-                                               lphc->textRect.right - lphc->textRect.left,
-                                               lphc->textRect.bottom - lphc->textRect.top,
-                                               hwnd, (HMENU)ID_CB_EDIT,
-                                               (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), NULL );
-	      if( !lphc->hWndEdit )
-		bEdit = FALSE;
-	  }
-
-          if( bEdit )
-	  {
-	    if( CB_GETTYPE(lphc) != CBS_SIMPLE )
-	    {
-              /* Now do the trick with parent */
-	      SetParent(lphc->hWndLBox, HWND_DESKTOP);
-              /*
-               * If the combo is a dropdown, we must resize the control
-	       * to fit only the text area and button. To do this,
-	       * we send a dummy resize and the WM_WINDOWPOSCHANGING message
-	       * will take care of setting the height for us.
-               */
-	      CBForceDummyResize(lphc);
-	    }
-
-	    TRACE("init done\n");
-	    return 0;
-	  }
-	  ERR("edit control failure.\n");
-      } else ERR("listbox failure.\n");
-  } else ERR("no owner for visible combo.\n");
-
-  /* CreateWindow() will send WM_NCDESTROY to cleanup */
-
-  return -1;
-}
-
-/***********************************************************************
- *           CBPaintButton
- *
- * Paint combo button (normal, pressed, and disabled states).
- */
-static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
-{
-    UINT buttonState = DFCS_SCROLLCOMBOBOX;
-
-    if( lphc->wState & CBF_NOREDRAW )
-      return;
-
-
-    if (lphc->wState & CBF_BUTTONDOWN)
-	buttonState |= DFCS_PUSHED;
-
-    if (CB_DISABLED(lphc))
-	buttonState |= DFCS_INACTIVE;
-
-    DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
-}
-
-/***********************************************************************
- *           COMBO_PrepareColors
- *
- * This method will sent the appropriate WM_CTLCOLOR message to
- * prepare and setup the colors for the combo's DC.
- *
- * It also returns the brush to use for the background.
- */
-static HBRUSH COMBO_PrepareColors(
-        LPHEADCOMBO lphc,
-        HDC         hDC)
-{
-    HBRUSH  hBkgBrush;
-
-    /*
-     * Get the background brush for this control.
-     */
-    if (CB_DISABLED(lphc))
-    {
-        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLORSTATIC,
-                (WPARAM)hDC, (LPARAM)lphc->self );
-
-        /*
-         * We have to change the text color since WM_CTLCOLORSTATIC will
-         * set it to the "enabled" color. This is the same behavior as the
-         * edit control
-         */
-        SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
-    }
-    else
-    {
-        /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
-        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLOREDIT,
-                (WPARAM)hDC, (LPARAM)lphc->self );
-    }
-
-    /*
-     * Catch errors.
-     */
-    if( !hBkgBrush )
-        hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
-
-    return hBkgBrush;
-}
-
-/***********************************************************************
- *           CBPaintText
- *
- * Paint CBS_DROPDOWNLIST text field / update edit control contents.
- */
-static void CBPaintText(HEADCOMBO *lphc, HDC hdc_paint)
-{
-   RECT rectEdit = lphc->textRect;
-   INT	id, size = 0;
-   LPWSTR pText = NULL;
-
-   TRACE("\n");
-
-   /* follow Windows combobox that sends a bunch of text
-    * inquiries to its listbox while processing WM_PAINT. */
-
-   if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
-   {
-        size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
-	if (size == LB_ERR)
-	  FIXME("LB_ERR probably not handled yet\n");
-        if ((pText = heap_alloc((size + 1) * sizeof(WCHAR))))
-	{
-            /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
-           size=SendMessageW(lphc->hWndLBox, LB_GETTEXT, id, (LPARAM)pText);
-	    pText[size] = '\0';	/* just in case */
-	} else return;
-   }
-
-   if( lphc->wState & CBF_EDIT )
-   {
-        static const WCHAR empty_stringW[] = { 0 };
-	if( CB_HASSTRINGS(lphc) ) SetWindowTextW( lphc->hWndEdit, pText ? pText : empty_stringW );
-	if( lphc->wState & CBF_FOCUSED )
-           SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, MAXLONG);
-   }
-   else if(!(lphc->wState & CBF_NOREDRAW) && IsWindowVisible( lphc->self ))
-   {
-     /* paint text field ourselves */
-     HDC hdc = hdc_paint ? hdc_paint : GetDC(lphc->self);
-     UINT itemState = ODS_COMBOBOXEDIT;
-     HFONT hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
-     HBRUSH hPrevBrush, hBkgBrush;
-
-     /*
-      * Give ourselves some space.
-      */
-     InflateRect( &rectEdit, -1, -1 );
-
-     hBkgBrush = COMBO_PrepareColors( lphc, hdc );
-     hPrevBrush = SelectObject( hdc, hBkgBrush );
-     FillRect( hdc, &rectEdit, hBkgBrush );
-
-     if( CB_OWNERDRAWN(lphc) )
-     {
-       DRAWITEMSTRUCT dis;
-       HRGN           clipRegion;
-       UINT ctlid = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
-
-       /* setup state for DRAWITEM message. Owner will highlight */
-       if ( (lphc->wState & CBF_FOCUSED) &&
-	    !(lphc->wState & CBF_DROPPED) )
-	   itemState |= ODS_SELECTED | ODS_FOCUS;
-
-       if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED;
-
-       dis.CtlType	= ODT_COMBOBOX;
-       dis.CtlID	= ctlid;
-       dis.hwndItem	= lphc->self;
-       dis.itemAction	= ODA_DRAWENTIRE;
-       dis.itemID	= id;
-       dis.itemState	= itemState;
-       dis.hDC		= hdc;
-       dis.rcItem	= rectEdit;
-       dis.itemData     = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0);
-
-       /*
-	* Clip the DC and have the parent draw the item.
-	*/
-       clipRegion = set_control_clipping( hdc, &rectEdit );
-
-       SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
-
-       SelectClipRgn( hdc, clipRegion );
-       if (clipRegion) DeleteObject( clipRegion );
-     }
-     else
-     {
-       static const WCHAR empty_stringW[] = { 0 };
-
-       if ( (lphc->wState & CBF_FOCUSED) &&
-	    !(lphc->wState & CBF_DROPPED) ) {
-
-	   /* highlight */
-	   FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
-	   SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
-	   SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
-       }
-
-       ExtTextOutW( hdc,
-		    rectEdit.left + 1,
-		    rectEdit.top + 1,
-		    ETO_OPAQUE | ETO_CLIPPED,
-		    &rectEdit,
-		    pText ? pText : empty_stringW , size, NULL );
-
-       if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
-	 DrawFocusRect( hdc, &rectEdit );
-     }
-
-     if( hPrevFont )
-       SelectObject(hdc, hPrevFont );
-
-    if( hPrevBrush )
-        SelectObject( hdc, hPrevBrush );
-
-     if( !hdc_paint )
-       ReleaseDC( lphc->self, hdc );
-   }
-
-    heap_free(pText);
-}
-
-/***********************************************************************
- *           CBPaintBorder
- */
-static void CBPaintBorder(
-  HWND            hwnd,
-  const HEADCOMBO *lphc,
-  HDC             hdc)
-{
-  RECT clientRect;
-
-  if (CB_GETTYPE(lphc) != CBS_SIMPLE)
-  {
-    GetClientRect(hwnd, &clientRect);
-  }
-  else
-  {
-    clientRect = lphc->textRect;
-
-    InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
-    InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
-  }
-
-  DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
-}
-
-static LRESULT COMBO_ThemedPaint(HTHEME theme, HEADCOMBO *lphc, HDC hdc)
-{
-    int button_state;
-    RECT frame;
-
-    /* paint border */
-    if (CB_GETTYPE(lphc) != CBS_SIMPLE)
-        GetClientRect(lphc->self, &frame);
-    else
-    {
-        frame = lphc->textRect;
-        InflateRect(&frame, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
-        InflateRect(&frame, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
-    }
-
-    DrawThemeBackground(theme, hdc, 0, IsWindowEnabled(lphc->self) ? CBXS_NORMAL : CBXS_DISABLED, &frame, NULL);
-
-    /* Paint button */
-    if (!IsRectEmpty(&lphc->buttonRect))
-    {
-        if (!IsWindowEnabled(lphc->self))
-            button_state = CBXS_DISABLED;
-        else if (lphc->wState & CBF_BUTTONDOWN)
-            button_state = CBXS_PRESSED;
-        else if (lphc->wState & CBF_HOT)
-            button_state = CBXS_HOT;
-        else
-            button_state = CBXS_NORMAL;
-        DrawThemeBackground(theme, hdc, CP_DROPDOWNBUTTON, button_state, &lphc->buttonRect, NULL);
-    }
-
-    if ((lphc->dwStyle & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
-        CBPaintText(lphc, hdc);
-
-    return 0;
-}
-
-/***********************************************************************
- *           COMBO_Paint
- */
-static LRESULT COMBO_Paint(HEADCOMBO *lphc, HDC hdc)
-{
-    HBRUSH hPrevBrush, hBkgBrush;
-
-    TRACE("hdc=%p\n", hdc);
-
-    /*
-     * Retrieve the background brush and select it in the
-     * DC.
-     */
-    hBkgBrush = COMBO_PrepareColors(lphc, hdc);
-    hPrevBrush = SelectObject(hdc, hBkgBrush);
-    if (!(lphc->wState & CBF_EDIT))
-        FillRect(hdc, &lphc->textRect, hBkgBrush);
-
-    /*
-     * In non 3.1 look, there is a sunken border on the combobox
-     */
-    CBPaintBorder(lphc->self, lphc, hdc);
-
-    if (!IsRectEmpty(&lphc->buttonRect))
-        CBPaintButton(lphc, hdc, lphc->buttonRect);
-
-    /* paint the edit control padding area */
-    if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
-    {
-        RECT rPadEdit = lphc->textRect;
-
-        InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
-
-        FrameRect(hdc, &rPadEdit, GetSysColorBrush(COLOR_WINDOW));
-    }
-
-    if (!(lphc->wState & CBF_EDIT))
-        CBPaintText( lphc, hdc );
-
-    if (hPrevBrush)
-        SelectObject( hdc, hPrevBrush );
-
-    return 0;
-}
-
-/***********************************************************************
- *           CBUpdateLBox
- *
- * Select listbox entry according to the contents of the edit control.
- */
-static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
-{
-   INT	length, idx;
-   LPWSTR pText = NULL;
-
-   idx = LB_ERR;
-   length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
-
-    if (length > 0)
-        pText = heap_alloc((length + 1) * sizeof(WCHAR));
-
-   TRACE("\t edit text length %i\n", length );
-
-   if( pText )
-   {
-       GetWindowTextW( lphc->hWndEdit, pText, length + 1);
-       idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING, -1, (LPARAM)pText);
-       heap_free( pText );
-   }
-
-   SendMessageW(lphc->hWndLBox, LB_SETCURSEL, bSelect ? idx : -1, 0);
-
-   /* probably superfluous but Windows sends this too */
-   SendMessageW(lphc->hWndLBox, LB_SETCARETINDEX, idx < 0 ? 0 : idx, 0);
-   SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, idx < 0 ? 0 : idx, 0);
-
-   return idx;
-}
-
-/***********************************************************************
- *           CBUpdateEdit
- *
- * Copy a listbox entry to the edit control.
- */
-static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
-{
-   INT	length;
-   LPWSTR pText = NULL;
-   static const WCHAR empty_stringW[] = { 0 };
-
-   TRACE("\t %i\n", index );
-
-   if( index >= 0 ) /* got an entry */
-   {
-       length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, index, 0);
-       if( length != LB_ERR)
-       {
-           if ((pText = heap_alloc((length + 1) * sizeof(WCHAR))))
-               SendMessageW(lphc->hWndLBox, LB_GETTEXT, index, (LPARAM)pText);
-       }
-   }
-
-   if( CB_HASSTRINGS(lphc) )
-   {
-      lphc->wState |= (CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
-      SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText : (LPARAM)empty_stringW);
-      lphc->wState &= ~(CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
-   }
-
-   if( lphc->wState & CBF_FOCUSED )
-      SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
-
-    heap_free( pText );
-}
-
-/***********************************************************************
- *           CBDropDown
- *
- * Show listbox popup.
- */
-static void CBDropDown( LPHEADCOMBO lphc )
-{
-    HMONITOR monitor;
-    MONITORINFO mon_info;
-   RECT rect,r;
-   int nItems;
-   int nDroppedHeight;
-
-   TRACE("[%p]: drop down\n", lphc->self);
-
-   CB_NOTIFY( lphc, CBN_DROPDOWN );
-
-   /* set selection */
-
-   lphc->wState |= CBF_DROPPED;
-   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-   {
-       lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
-
-       /* Update edit only if item is in the list */
-       if( !(lphc->wState & CBF_CAPTURE) && lphc->droppedIndex >= 0)
-	 CBUpdateEdit( lphc, lphc->droppedIndex );
-   }
-   else
-   {
-       lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-
-       SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
-                    lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex, 0);
-       SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
-   }
-
-   /* now set popup position */
-   GetWindowRect( lphc->self, &rect );
-
-   /*
-    * If it's a dropdown, the listbox is offset
-    */
-   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-     rect.left += COMBO_EDITBUTTONSPACE();
-
-  /* if the dropped height is greater than the total height of the dropped
-     items list, then force the drop down list height to be the total height
-     of the items in the dropped list */
-
-  /* And Remove any extra space (Best Fit) */
-   nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
-  /* if listbox length has been set directly by its handle */
-   GetWindowRect(lphc->hWndLBox, &r);
-   if (nDroppedHeight < r.bottom - r.top)
-       nDroppedHeight = r.bottom - r.top;
-   nItems = (int)SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
-
-   if (nItems > 0)
-   {
-        int nIHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
-
-        if (lphc->dwStyle & CBS_NOINTEGRALHEIGHT)
-        {
-            nDroppedHeight -= 1;
-        }
-        else
-        {
-            if (nItems > lphc->visibleItems)
-            nItems = lphc->visibleItems;
-            nDroppedHeight = nItems * nIHeight + COMBO_YBORDERSIZE();
-        }
-   }
-
-   r.left = rect.left;
-   r.top = rect.bottom;
-   r.right = r.left + lphc->droppedRect.right - lphc->droppedRect.left;
-   r.bottom = r.top + nDroppedHeight;
-
-   /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
-   monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
-   mon_info.cbSize = sizeof(mon_info);
-   GetMonitorInfoW( monitor, &mon_info );
-
-   if (r.bottom > mon_info.rcWork.bottom)
-   {
-       r.top = max( rect.top - nDroppedHeight, mon_info.rcWork.top );
-       r.bottom = min( r.top + nDroppedHeight, mon_info.rcWork.bottom );
-   }
-
-   SetWindowPos( lphc->hWndLBox, HWND_TOPMOST, r.left, r.top, r.right - r.left, r.bottom - r.top,
-                 SWP_NOACTIVATE | SWP_SHOWWINDOW );
-
-
-   if( !(lphc->wState & CBF_NOREDRAW) )
-     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
-			   RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
-
-   EnableWindow( lphc->hWndLBox, TRUE );
-   if (GetCapture() != lphc->self)
-      SetCapture(lphc->hWndLBox);
-}
-
-/***********************************************************************
- *           CBRollUp
- *
- * Hide listbox popup.
- */
-static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
-{
-   HWND	hWnd = lphc->self;
-
-   TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
-	 lphc->self, ok, (INT)(lphc->wState & CBF_DROPPED));
-
-   CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
-
-   if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
-   {
-
-       if( lphc->wState & CBF_DROPPED )
-       {
-	   RECT	rect;
-
-	   lphc->wState &= ~CBF_DROPPED;
-	   ShowWindow( lphc->hWndLBox, SW_HIDE );
-
-           if(GetCapture() == lphc->hWndLBox)
-           {
-               ReleaseCapture();
-           }
-
-	   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	   {
-	       rect = lphc->buttonRect;
-	   }
-	   else
-           {
-	       if( bButton )
-	       {
-		 UnionRect( &rect,
-			    &lphc->buttonRect,
-			    &lphc->textRect);
-	       }
-	       else
-		 rect = lphc->textRect;
-
-	       bButton = TRUE;
-	   }
-
-	   if( bButton && !(lphc->wState & CBF_NOREDRAW) )
-	       RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
-			       RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
-	   CB_NOTIFY( lphc, CBN_CLOSEUP );
-       }
-   }
-}
-
-/***********************************************************************
- *           COMBO_FlipListbox
- *
- * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
- */
-BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
-{
-   if( lphc->wState & CBF_DROPPED )
-   {
-       CBRollUp( lphc, ok, bRedrawButton );
-       return FALSE;
-   }
-
-   CBDropDown( lphc );
-   return TRUE;
-}
-
-/***********************************************************************
- *           CBRepaintButton
- */
-static void CBRepaintButton( LPHEADCOMBO lphc )
-   {
-  InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
-  UpdateWindow(lphc->self);
-}
-
-/***********************************************************************
- *           COMBO_SetFocus
- */
-static void COMBO_SetFocus( LPHEADCOMBO lphc )
-{
-   if( !(lphc->wState & CBF_FOCUSED) )
-   {
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-           SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
-
-       /* This is wrong. Message sequences seem to indicate that this
-          is set *after* the notify. */
-       /* lphc->wState |= CBF_FOCUSED;  */
-
-       if( !(lphc->wState & CBF_EDIT) )
-	 InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-
-       CB_NOTIFY( lphc, CBN_SETFOCUS );
-       lphc->wState |= CBF_FOCUSED;
-   }
-}
-
-/***********************************************************************
- *           COMBO_KillFocus
- */
-static void COMBO_KillFocus( LPHEADCOMBO lphc )
-{
-   HWND	hWnd = lphc->self;
-
-   if( lphc->wState & CBF_FOCUSED )
-   {
-       CBRollUp( lphc, FALSE, TRUE );
-       if( IsWindow( hWnd ) )
-       {
-           if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-               SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
-
-	   lphc->wState &= ~CBF_FOCUSED;
-
-           /* redraw text */
-	   if( !(lphc->wState & CBF_EDIT) )
-	     InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-
-           CB_NOTIFY( lphc, CBN_KILLFOCUS );
-       }
-   }
-}
-
-/***********************************************************************
- *           COMBO_Command
- */
-static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
-{
-   if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
-   {
-       /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
-
-       switch( HIWORD(wParam) >> 8 )
-       {
-	   case (EN_SETFOCUS >> 8):
-
-               TRACE("[%p]: edit [%p] got focus\n", lphc->self, lphc->hWndEdit );
-
-		COMBO_SetFocus( lphc );
-	        break;
-
-	   case (EN_KILLFOCUS >> 8):
-
-               TRACE("[%p]: edit [%p] lost focus\n", lphc->self, lphc->hWndEdit );
-
-		/* NOTE: it seems that Windows' edit control sends an
-		 * undocumented message WM_USER + 0x1B instead of this
-		 * notification (only when it happens to be a part of
-		 * the combo). ?? - AK.
-		 */
-
-		COMBO_KillFocus( lphc );
-		break;
-
-
-	   case (EN_CHANGE >> 8):
-	       /*
-	        * In some circumstances (when the selection of the combobox
-		* is changed for example) we don't want the EN_CHANGE notification
-		* to be forwarded to the parent of the combobox. This code
-		* checks a flag that is set in these occasions and ignores the
-		* notification.
-	        */
-		if (lphc->wState & CBF_NOLBSELECT)
-		{
-		  lphc->wState &= ~CBF_NOLBSELECT;
-		}
-		else
-		{
-		  CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
-		}
-
-	        if (!(lphc->wState & CBF_NOEDITNOTIFY))
-		  CB_NOTIFY( lphc, CBN_EDITCHANGE );
-		break;
-
-	   case (EN_UPDATE >> 8):
-	        if (!(lphc->wState & CBF_NOEDITNOTIFY))
-		  CB_NOTIFY( lphc, CBN_EDITUPDATE );
-		break;
-
-	   case (EN_ERRSPACE >> 8):
-		CB_NOTIFY( lphc, CBN_ERRSPACE );
-       }
-   }
-   else if( lphc->hWndLBox == hWnd )
-   {
-       switch( (short)HIWORD(wParam) )
-       {
-	   case LBN_ERRSPACE:
-		CB_NOTIFY( lphc, CBN_ERRSPACE );
-		break;
-
-	   case LBN_DBLCLK:
-		CB_NOTIFY( lphc, CBN_DBLCLK );
-		break;
-
-	   case LBN_SELCHANGE:
-	   case LBN_SELCANCEL:
-
-                TRACE("[%p]: lbox selection change [%x]\n", lphc->self, lphc->wState );
-
-                /* do not roll up if selection is being tracked
-                 * by arrow keys in the dropdown listbox */
-                if (!(lphc->wState & CBF_NOROLLUP))
-                {
-                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
-                }
-                else lphc->wState &= ~CBF_NOROLLUP;
-
-		CB_NOTIFY( lphc, CBN_SELCHANGE );
-
-		if( HIWORD(wParam) == LBN_SELCHANGE)
-		{
-		   if( lphc->wState & CBF_EDIT )
-		       lphc->wState |= CBF_NOLBSELECT;
-		   CBPaintText( lphc, NULL );
-		}
-                break;
-
-	   case LBN_SETFOCUS:
-	   case LBN_KILLFOCUS:
-		/* nothing to do here since ComboLBox always resets the focus to its
-		 * combo/edit counterpart */
-		 break;
-       }
-   }
-   return 0;
-}
-
-/***********************************************************************
- *           COMBO_ItemOp
- *
- * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
- */
-static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
-{
-   HWND hWnd = lphc->self;
-   UINT id = (UINT)GetWindowLongPtrW( hWnd, GWLP_ID );
-
-   TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
-
-   switch( msg )
-   {
-   case WM_DELETEITEM:
-       {
-           DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_DRAWITEM:
-       {
-           DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_COMPAREITEM:
-       {
-           COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_MEASUREITEM:
-       {
-           MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           break;
-       }
-   }
-   return SendMessageW(lphc->owner, msg, id, lParam);
-}
-
-
-/***********************************************************************
- *           COMBO_GetTextW
- */
-static LRESULT COMBO_GetText( HEADCOMBO *lphc, INT count, LPWSTR buf )
-{
-    INT length;
-
-    if( lphc->wState & CBF_EDIT )
-        return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
-
-    /* get it from the listbox */
-
-    if (!count || !buf) return 0;
-    if( lphc->hWndLBox )
-    {
-        INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-        if (idx == LB_ERR) goto error;
-        length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
-        if (length == LB_ERR) goto error;
-
-        /* 'length' is without the terminating character */
-        if (length >= count)
-        {
-            WCHAR *lpBuffer = heap_alloc((length + 1) * sizeof(WCHAR));
-            if (!lpBuffer) goto error;
-            length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
-
-            /* truncate if buffer is too short */
-            if (length != LB_ERR)
-            {
-                lstrcpynW( buf, lpBuffer, count );
-                length = count;
-            }
-            heap_free( lpBuffer );
-        }
-        else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
-
-        if (length == LB_ERR) return 0;
-        return length;
-    }
-
- error:  /* error - truncate string, return zero */
-    buf[0] = 0;
-    return 0;
-}
-
-/***********************************************************************
- *           CBResetPos
- *
- * This function sets window positions according to the updated
- * component placement struct.
- */
-static void CBResetPos(
-  LPHEADCOMBO lphc,
-  const RECT  *rectEdit,
-  const RECT  *rectLB,
-  BOOL        bRedraw)
-{
-   BOOL	bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
-
-   /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
-    * sizing messages */
-
-   if( lphc->wState & CBF_EDIT )
-     SetWindowPos( lphc->hWndEdit, 0,
-		   rectEdit->left, rectEdit->top,
-		   rectEdit->right - rectEdit->left,
-		   rectEdit->bottom - rectEdit->top,
-                       SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
-
-   SetWindowPos( lphc->hWndLBox, 0,
-		 rectLB->left, rectLB->top,
-                 rectLB->right - rectLB->left,
-		 rectLB->bottom - rectLB->top,
-		   SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
-
-   if( bDrop )
-   {
-       if( lphc->wState & CBF_DROPPED )
-       {
-           lphc->wState &= ~CBF_DROPPED;
-           ShowWindow( lphc->hWndLBox, SW_HIDE );
-       }
-
-       if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
-           RedrawWindow( lphc->self, NULL, 0,
-                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
-   }
-}
-
-
-/***********************************************************************
- *           COMBO_Size
- */
-static void COMBO_Size( LPHEADCOMBO lphc )
-{
-  /*
-   * Those controls are always the same height. So we have to make sure
-   * they are not resized to another value.
-   */
-  if( CB_GETTYPE(lphc) != CBS_SIMPLE )
-  {
-    int newComboHeight, curComboHeight, curComboWidth;
-    RECT rc;
-
-    GetWindowRect(lphc->self, &rc);
-    curComboHeight = rc.bottom - rc.top;
-    curComboWidth = rc.right - rc.left;
-    newComboHeight = CBGetTextAreaHeight(lphc->self, lphc) + 2*COMBO_YBORDERSIZE();
-
-    /*
-     * Resizing a combobox has another side effect, it resizes the dropped
-     * rectangle as well. However, it does it only if the new height for the
-     * combobox is more than the height it should have. In other words,
-     * if the application resizing the combobox only had the intention to resize
-     * the actual control, for example, to do the layout of a dialog that is
-     * resized, the height of the dropdown is not changed.
-     */
-    if( curComboHeight > newComboHeight )
-    {
-      TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%d, oldDropTop=%d\n",
-            curComboHeight, newComboHeight, lphc->droppedRect.bottom,
-            lphc->droppedRect.top);
-      lphc->droppedRect.bottom = lphc->droppedRect.top + curComboHeight - newComboHeight;
-    }
-    /*
-     * Restore original height
-     */
-    if( curComboHeight != newComboHeight )
-      SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
-            SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW);
-  }
-
-  CBCalcPlacement(lphc->self,
-		  lphc,
-		  &lphc->textRect,
-		  &lphc->buttonRect,
-		  &lphc->droppedRect);
-
-  CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-}
-
-
-/***********************************************************************
- *           COMBO_Font
- */
-static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
-{
-  /*
-   * Set the font
-   */
-  lphc->hFont = hFont;
-
-  /*
-   * Propagate to owned windows.
-   */
-  if( lphc->wState & CBF_EDIT )
-      SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
-  SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
-
-  /*
-   * Redo the layout of the control.
-   */
-  if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
-  {
-    CBCalcPlacement(lphc->self,
-		    lphc,
-		    &lphc->textRect,
-		    &lphc->buttonRect,
-		    &lphc->droppedRect);
-
-    CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-  }
-  else
-  {
-    CBForceDummyResize(lphc);
-  }
-}
-
-
-/***********************************************************************
- *           COMBO_SetItemHeight
- */
-static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
-{
-   LRESULT	lRet = CB_ERR;
-
-   if( index == -1 ) /* set text field height */
-   {
-       if( height < 32768 )
-       {
-           lphc->editHeight = height + 2;  /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
-
-	 /*
-	  * Redo the layout of the control.
-	  */
-	 if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
-	 {
-	   CBCalcPlacement(lphc->self,
-			   lphc,
-			   &lphc->textRect,
-			   &lphc->buttonRect,
-			   &lphc->droppedRect);
-
-	   CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-	 }
-	 else
-	 {
-	   CBForceDummyResize(lphc);
-	 }
-
-	   lRet = height;
-       }
-   }
-   else if ( CB_OWNERDRAWN(lphc) )	/* set listbox item height */
-       lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT, index, height);
-   return lRet;
-}
-
-/***********************************************************************
- *           COMBO_SelectString
- */
-static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText)
-{
-   INT index = SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, start, pText);
-   if( index >= 0 )
-   {
-     if( lphc->wState & CBF_EDIT )
-       CBUpdateEdit( lphc, index );
-     else
-     {
-       InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-     }
-   }
-   return (LRESULT)index;
-}
-
-/***********************************************************************
- *           COMBO_LButtonDown
- */
-static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
-{
-   POINT     pt;
-   BOOL      bButton;
-   HWND      hWnd = lphc->self;
-
-   pt.x = (short)LOWORD(lParam);
-   pt.y = (short)HIWORD(lParam);
-   bButton = PtInRect(&lphc->buttonRect, pt);
-
-   if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
-       (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
-   {
-       lphc->wState |= CBF_BUTTONDOWN;
-       if( lphc->wState & CBF_DROPPED )
-       {
-	   /* got a click to cancel selection */
-
-           lphc->wState &= ~CBF_BUTTONDOWN;
-           CBRollUp( lphc, TRUE, FALSE );
-	   if( !IsWindow( hWnd ) ) return;
-
-           if( lphc->wState & CBF_CAPTURE )
-           {
-               lphc->wState &= ~CBF_CAPTURE;
-               ReleaseCapture();
-           }
-       }
-       else
-       {
-	   /* drop down the listbox and start tracking */
-
-           lphc->wState |= CBF_CAPTURE;
-           SetCapture( hWnd );
-           CBDropDown( lphc );
-       }
-       if( bButton ) CBRepaintButton( lphc );
-   }
-}
-
-/***********************************************************************
- *           COMBO_LButtonUp
- *
- * Release capture and stop tracking if needed.
- */
-static void COMBO_LButtonUp( LPHEADCOMBO lphc )
-{
-   if( lphc->wState & CBF_CAPTURE )
-   {
-       lphc->wState &= ~CBF_CAPTURE;
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-       {
-	   INT index = CBUpdateLBox( lphc, TRUE );
-	   /* Update edit only if item is in the list */
-	   if(index >= 0)
-	   {
-	       lphc->wState |= CBF_NOLBSELECT;
-	       CBUpdateEdit( lphc, index );
-	       lphc->wState &= ~CBF_NOLBSELECT;
-	   }
-       }
-       ReleaseCapture();
-       SetCapture(lphc->hWndLBox);
-   }
-
-   if( lphc->wState & CBF_BUTTONDOWN )
-   {
-       lphc->wState &= ~CBF_BUTTONDOWN;
-       CBRepaintButton( lphc );
-   }
-}
-
-/***********************************************************************
- *           COMBO_MouseMove
- *
- * Two things to do - track combo button and release capture when
- * pointer goes into the listbox.
- */
-static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
-{
-   POINT  pt;
-   RECT   lbRect;
-
-   pt.x = (short)LOWORD(lParam);
-   pt.y = (short)HIWORD(lParam);
-
-   if( lphc->wState & CBF_BUTTONDOWN )
-   {
-     BOOL bButton;
-
-     bButton = PtInRect(&lphc->buttonRect, pt);
-
-     if( !bButton )
-     {
-       lphc->wState &= ~CBF_BUTTONDOWN;
-       CBRepaintButton( lphc );
-     }
-   }
-
-   GetClientRect( lphc->hWndLBox, &lbRect );
-   MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
-   if( PtInRect(&lbRect, pt) )
-   {
-       lphc->wState &= ~CBF_CAPTURE;
-       ReleaseCapture();
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
-
-       /* hand over pointer tracking */
-       SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
-   }
-}
-
-static LRESULT COMBO_GetComboBoxInfo(const HEADCOMBO *lphc, COMBOBOXINFO *pcbi)
-{
-    if (!pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
-        return FALSE;
-
-    pcbi->rcItem = lphc->textRect;
-    pcbi->rcButton = lphc->buttonRect;
-    pcbi->stateButton = 0;
-    if (lphc->wState & CBF_BUTTONDOWN)
-        pcbi->stateButton |= STATE_SYSTEM_PRESSED;
-    if (IsRectEmpty(&lphc->buttonRect))
-        pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
-    pcbi->hwndCombo = lphc->self;
-    pcbi->hwndItem = lphc->hWndEdit;
-    pcbi->hwndList = lphc->hWndLBox;
-    return TRUE;
-}
 
 static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
 {
-    HEADCOMBO *lphc = (HEADCOMBO *)GetWindowLongPtrW( hwnd, 0 );
-    HTHEME theme;
-
     TRACE("[%p]: msg %#x wp %08lx lp %08lx\n", hwnd, message, wParam, lParam );
 
-    if (!IsWindow(hwnd)) return 0;
-
-    if (lphc || message == WM_NCCREATE)
-    switch(message)
-    {
-    case WM_NCCREATE:
-    {
-        LONG style = ((CREATESTRUCTW *)lParam)->style;
-        return COMBO_NCCreate(hwnd, style);
-    }
-
-    case WM_NCDESTROY:
-        COMBO_NCDestroy(lphc);
-        break;/* -> DefWindowProc */
-
-    case WM_CREATE:
-    {
-        HWND hwndParent;
-        LONG style;
-
-        hwndParent = ((CREATESTRUCTW *)lParam)->hwndParent;
-        style = ((CREATESTRUCTW *)lParam)->style;
-        return COMBO_Create(hwnd, lphc, hwndParent, style);
-    }
-
-    case WM_DESTROY:
-        theme = GetWindowTheme( hwnd );
-        CloseThemeData( theme );
-        break;
-
-    case WM_THEMECHANGED:
-        theme = GetWindowTheme( hwnd );
-        CloseThemeData( theme );
-        OpenThemeData( hwnd, WC_COMBOBOXW );
-        break;
-
-    case WM_PRINTCLIENT:
-    case WM_PAINT:
-    {
-        LRESULT ret = 0;
-        PAINTSTRUCT ps;
-        HDC hdc;
-
-        hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
-
-        if (hdc && !(lphc->wState & CBF_NOREDRAW))
-        {
-            HTHEME theme = GetWindowTheme(hwnd);
-
-            if (theme)
-                ret = COMBO_ThemedPaint(theme, lphc, hdc);
-            else
-                ret = COMBO_Paint(lphc, hdc);
-        }
-
-        if (!wParam)
-            EndPaint(hwnd, &ps);
-
-        return ret;
-    }
-    case WM_ERASEBKGND:
-        /* do all painting in WM_PAINT like Windows does */
-        return 1;
-
-    case WM_GETDLGCODE:
-    {
-        LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
-        if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
-        {
-            int vk = (int)((LPMSG)lParam)->wParam;
-
-            if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
-                result |= DLGC_WANTMESSAGE;
-        }
-        return  result;
-    }
-
-    case WM_SIZE:
-        if (lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
-            COMBO_Size( lphc );
-        return  TRUE;
-
-    case WM_SETFONT:
-        COMBO_Font( lphc, (HFONT)wParam, (BOOL)lParam );
-        return TRUE;
-
-    case WM_GETFONT:
-        return (LRESULT)lphc->hFont;
-
-    case WM_SETFOCUS:
-        if (lphc->wState & CBF_EDIT)
-        {
-            SetFocus( lphc->hWndEdit );
-            /* The first time focus is received, select all the text */
-            if (!(lphc->wState & CBF_BEENFOCUSED))
-            {
-                SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
-                lphc->wState |= CBF_BEENFOCUSED;
-            }
-        }
-        else
-            COMBO_SetFocus( lphc );
-        return  TRUE;
-
-    case WM_KILLFOCUS:
-    {
-        HWND hwndFocus = (HWND)wParam;
-        if (!hwndFocus || (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox))
-            COMBO_KillFocus( lphc );
-        return  TRUE;
-    }
-
-    case WM_COMMAND:
-        return COMBO_Command( lphc, wParam, (HWND)lParam );
-
-    case WM_GETTEXT:
-        return COMBO_GetText( lphc, wParam, (LPWSTR)lParam );
-
-    case WM_SETTEXT:
-    case WM_GETTEXTLENGTH:
-    case WM_CLEAR:
-        if ((message == WM_GETTEXTLENGTH) && !ISWIN31 && !(lphc->wState & CBF_EDIT))
-        {
-            int j = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-            if (j == -1) return 0;
-            return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
-        }
-        else if ( lphc->wState & CBF_EDIT )
-        {
-            LRESULT ret;
-            lphc->wState |= CBF_NOEDITNOTIFY;
-            ret = SendMessageW(lphc->hWndEdit, message, wParam, lParam);
-            lphc->wState &= ~CBF_NOEDITNOTIFY;
-            return ret;
-        }
-        else
-            return CB_ERR;
-
-    case WM_CUT:
-    case WM_PASTE:
-    case WM_COPY:
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, message, wParam, lParam);
-        else return  CB_ERR;
-
-    case WM_DRAWITEM:
-    case WM_DELETEITEM:
-    case WM_COMPAREITEM:
-    case WM_MEASUREITEM:
-        return COMBO_ItemOp(lphc, message, lParam);
-
-    case WM_ENABLE:
-        if (lphc->wState & CBF_EDIT)
-            EnableWindow( lphc->hWndEdit, (BOOL)wParam );
-        EnableWindow( lphc->hWndLBox, (BOOL)wParam );
-
-        /* Force the control to repaint when the enabled state changes. */
-        InvalidateRect(lphc->self, NULL, TRUE);
-        return  TRUE;
-
-    case WM_SETREDRAW:
-        if (wParam)
-            lphc->wState &= ~CBF_NOREDRAW;
-        else
-            lphc->wState |= CBF_NOREDRAW;
-
-        if ( lphc->wState & CBF_EDIT )
-            SendMessageW(lphc->hWndEdit, message, wParam, lParam);
-        SendMessageW(lphc->hWndLBox, message, wParam, lParam);
-        return  0;
-
-    case WM_SYSKEYDOWN:
-        if ( KEYDATA_ALT & HIWORD(lParam) )
-            if( wParam == VK_UP || wParam == VK_DOWN )
-                COMBO_FlipListbox( lphc, FALSE, FALSE );
-        return  0;
-
-    case WM_KEYDOWN:
-        if ((wParam == VK_RETURN || wParam == VK_ESCAPE) &&
-                (lphc->wState & CBF_DROPPED))
-        {
-            CBRollUp( lphc, wParam == VK_RETURN, FALSE );
-            return TRUE;
-        }
-        else if ((wParam == VK_F4) && !(lphc->wState & CBF_EUI))
-        {
-            COMBO_FlipListbox( lphc, FALSE, FALSE );
-            return TRUE;
-        }
-        /* fall through */
-    case WM_CHAR:
-    case WM_IME_CHAR:
-        {
-            HWND hwndTarget;
-
-            if ( lphc->wState & CBF_EDIT )
-                hwndTarget = lphc->hWndEdit;
-            else
-                hwndTarget = lphc->hWndLBox;
-
-           return SendMessageW(hwndTarget, message, wParam, lParam);
-        }
-
-    case WM_LBUTTONDOWN:
-        if ( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self );
-        if ( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
-        return  TRUE;
-
-    case WM_LBUTTONUP:
-        COMBO_LButtonUp( lphc );
-        return  TRUE;
-
-    case WM_MOUSEMOVE:
-        if (!IsRectEmpty(&lphc->buttonRect))
-        {
-            POINT pt;
-
-            pt.x = (short)LOWORD(lParam);
-            pt.y = (short)HIWORD(lParam);
-
-            if (PtInRect(&lphc->buttonRect, pt))
-            {
-                if (!(lphc->wState & CBF_HOT))
-                {
-                    lphc->wState |= CBF_HOT;
-                    RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE | RDW_UPDATENOW);
-                }
-            }
-            else if (lphc->wState & CBF_HOT)
-            {
-                lphc->wState &= ~CBF_HOT;
-                RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE | RDW_UPDATENOW);
-            }
-        }
-
-        if ( lphc->wState & CBF_CAPTURE )
-            COMBO_MouseMove( lphc, wParam, lParam );
-        return  TRUE;
-
-    case WM_MOUSEWHEEL:
-        if (wParam & (MK_SHIFT | MK_CONTROL))
-            return DefWindowProcW(hwnd, message, wParam, lParam);
-
-        if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_UP, 0);
-        if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_DOWN, 0);
-        return TRUE;
-
-    /* Combo messages */
-    case CB_ADDSTRING:
-        if (lphc->dwStyle & CBS_LOWERCASE)
-            CharLowerW((LPWSTR)lParam);
-        else if (lphc->dwStyle & CBS_UPPERCASE)
-            CharUpperW((LPWSTR)lParam);
-        return SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
-
-    case CB_INSERTSTRING:
-        if (lphc->dwStyle & CBS_LOWERCASE)
-            CharLowerW((LPWSTR)lParam);
-        else if (lphc->dwStyle & CBS_UPPERCASE)
-            CharUpperW((LPWSTR)lParam);
-        return SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
-
-    case CB_DELETESTRING:
-        return SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
-
-    case CB_SELECTSTRING:
-        return COMBO_SelectString(lphc, (INT)wParam, lParam);
-
-    case CB_FINDSTRING:
-        return SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
-
-    case CB_FINDSTRINGEXACT:
-        return SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
-
-    case CB_SETITEMHEIGHT:
-        return  COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
-
-    case CB_GETITEMHEIGHT:
-        if ((INT)wParam >= 0) /* listbox item */
-            return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
-        return  CBGetTextAreaHeight(hwnd, lphc);
-
-    case CB_RESETCONTENT:
-        SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
-
-        if ((lphc->wState & CBF_EDIT) && CB_HASSTRINGS(lphc))
-        {
-            static const WCHAR empty_stringW[] = { 0 };
-            SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)empty_stringW);
-        }
-        else
-            InvalidateRect(lphc->self, NULL, TRUE);
-        return  TRUE;
-
-    case CB_INITSTORAGE:
-        return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
-
-    case CB_GETHORIZONTALEXTENT:
-        return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
-
-    case CB_SETHORIZONTALEXTENT:
-        return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
-
-    case CB_GETTOPINDEX:
-        return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
-
-    case CB_GETLOCALE:
-        return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
-
-    case CB_SETLOCALE:
-        return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
-
-    case CB_SETDROPPEDWIDTH:
-        if ((CB_GETTYPE(lphc) == CBS_SIMPLE) || (INT)wParam >= 32768)
-            return CB_ERR;
-
-        /* new value must be higher than combobox width */
-        if ((INT)wParam >= lphc->droppedRect.right - lphc->droppedRect.left)
-            lphc->droppedWidth = wParam;
-        else if (wParam)
-            lphc->droppedWidth = 0;
-
-        /* recalculate the combobox area */
-        CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
-
-        /* fall through */
-    case CB_GETDROPPEDWIDTH:
-        if (lphc->droppedWidth)
-            return lphc->droppedWidth;
-        return  lphc->droppedRect.right - lphc->droppedRect.left;
-
-    case CB_GETDROPPEDCONTROLRECT:
-        if (lParam)
-            CBGetDroppedControlRect(lphc, (LPRECT)lParam );
-        return  CB_OKAY;
-
-    case CB_GETDROPPEDSTATE:
-        return (lphc->wState & CBF_DROPPED) != 0;
-
-    case CB_DIR:
-        return SendMessageW(lphc->hWndLBox, LB_DIR, wParam, lParam);
-
-    case CB_SHOWDROPDOWN:
-        if (CB_GETTYPE(lphc) != CBS_SIMPLE)
-        {
-            if (wParam)
-            {
-                if (!(lphc->wState & CBF_DROPPED))
-                    CBDropDown( lphc );
-            }
-            else if (lphc->wState & CBF_DROPPED)
-                CBRollUp( lphc, FALSE, TRUE );
-        }
-        return  TRUE;
-
-    case CB_GETCOUNT:
-        return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
-
-    case CB_GETCURSEL:
-        return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-
-    case CB_SETCURSEL:
-        lParam = SendMessageW(lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
-        if (lParam >= 0)
-            SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
-
-        /* no LBN_SELCHANGE in this case, update manually */
-        CBPaintText(lphc, NULL);
-        lphc->wState &= ~CBF_SELCHANGE;
-        return lParam;
-
-    case CB_GETLBTEXT:
-        return SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
-
-    case CB_GETLBTEXTLEN:
-        return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
-
-    case CB_GETITEMDATA:
-        return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
-
-    case CB_SETITEMDATA:
-        return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
-
-    case CB_GETEDITSEL:
-        /* Edit checks passed parameters itself */
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
-        return  CB_ERR;
-
-    case CB_SETEDITSEL:
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_SETSEL, (INT)(SHORT)LOWORD(lParam), (INT)(SHORT)HIWORD(lParam) );
-        return  CB_ERR;
-
-    case CB_SETEXTENDEDUI:
-        if (CB_GETTYPE(lphc) == CBS_SIMPLE )
-            return  CB_ERR;
-        if (wParam)
-            lphc->wState |= CBF_EUI;
-        else
-            lphc->wState &= ~CBF_EUI;
-        return  CB_OKAY;
-
-    case CB_GETEXTENDEDUI:
-        return (lphc->wState & CBF_EUI) != 0;
-
-    case CB_GETCOMBOBOXINFO:
-        return COMBO_GetComboBoxInfo(lphc, (COMBOBOXINFO *)lParam);
-
-    case CB_LIMITTEXT:
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
-        return  TRUE;
-
-    case CB_GETMINVISIBLE:
-        return lphc->visibleItems;
-
-    case CB_SETMINVISIBLE:
-        lphc->visibleItems = (INT)wParam;
-        return TRUE;
-
-    default:
-        if (message >= WM_USER)
-            WARN("unknown msg WM_USER+%04x wp=%04lx lp=%08lx\n", message - WM_USER, wParam, lParam );
-        break;
-    }
-
-    return DefWindowProcW(hwnd, message, wParam, lParam);
+    return control_proc_combo(hwnd, message, wParam, lParam, TRUE);
 }
 
 void COMBO_Register(void)
diff --git a/dlls/user32/combo.c b/dlls/user32/combo.c
index 8b7cd17909..6079788faa 100644
--- a/dlls/user32/combo.c
+++ b/dlls/user32/combo.c
@@ -37,43 +37,9 @@
 #include "winternl.h"
 #include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(combo);
+#define CONTROL_VERSION 1
+#include "wine/controls/combo.c"
 
-  /* bits in the dwKeyData */
-#define KEYDATA_ALT             0x2000
-#define KEYDATA_PREVSTATE       0x4000
-
-/*
- * Additional combo box definitions
- */
-
-#define CB_NOTIFY( lphc, code ) \
-    (SendMessageW((lphc)->owner, WM_COMMAND, \
-                  MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)), (LPARAM)(lphc)->self))
-
-#define CB_DISABLED( lphc )   (!IsWindowEnabled((lphc)->self))
-#define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
-#define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
-#define CB_HWND( lphc )       ((lphc)->self)
-#define CB_GETTYPE( lphc )    ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
-
-#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
-
-/*
- * Drawing globals
- */
-static HBITMAP 	hComboBmp = 0;
-static UINT	CBitHeight, CBitWidth;
-
-/*
- * Look and feel dependent "constants"
- */
-
-#define COMBO_YBORDERGAP         5
-#define COMBO_XBORDERSIZE()      2
-#define COMBO_YBORDERSIZE()      2
-#define COMBO_EDITBUTTONSPACE()  0
-#define EDIT_CONTROL_PADDING()   1
 
 /*********************************************************************
  * combo class descriptor
@@ -89,2140 +55,19 @@ const struct builtin_class_descr COMBO_builtin_class =
     0                     /* brush */
 };
 
-
-/***********************************************************************
- *           COMBO_Init
- *
- * Load combo button bitmap.
- */
-static BOOL COMBO_Init(void)
-{
-  HDC		hDC;
-
-  if( hComboBmp ) return TRUE;
-  if( (hDC = CreateCompatibleDC(0)) )
-  {
-    BOOL	bRet = FALSE;
-    if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
-    {
-      BITMAP      bm;
-      HBITMAP     hPrevB;
-      RECT        r;
-
-      GetObjectW( hComboBmp, sizeof(bm), &bm );
-      CBitHeight = bm.bmHeight;
-      CBitWidth  = bm.bmWidth;
-
-      TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
-
-      hPrevB = SelectObject( hDC, hComboBmp);
-      SetRect( &r, 0, 0, CBitWidth, CBitHeight );
-      InvertRect( hDC, &r );
-      SelectObject( hDC, hPrevB );
-      bRet = TRUE;
-    }
-    DeleteDC( hDC );
-    return bRet;
-  }
-  return FALSE;
-}
-
-/***********************************************************************
- *           COMBO_NCCreate
- */
-static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
-{
-    HEADCOMBO *lphc;
-
-    if (COMBO_Init() && (lphc = heap_alloc_zero(sizeof(*lphc))))
-    {
-        lphc->self = hwnd;
-        SetWindowLongPtrW( hwnd, 0, (LONG_PTR)lphc );
-
-       /* some braindead apps do try to use scrollbar/border flags */
-
-	lphc->dwStyle = style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
-        SetWindowLongW( hwnd, GWL_STYLE, style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL) );
-
-	/*
-	 * We also have to remove the client edge style to make sure
-	 * we don't end-up with a non client area.
-	 */
-        SetWindowLongW( hwnd, GWL_EXSTYLE,
-                        GetWindowLongW( hwnd, GWL_EXSTYLE ) & ~WS_EX_CLIENTEDGE );
-
-	if( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
-              lphc->dwStyle |= CBS_HASSTRINGS;
-	if( !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
-	      lphc->wState |= CBF_NOTIFY;
-
-        TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/***********************************************************************
- *           COMBO_NCDestroy
- */
-static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
-{
-    if (lphc)
-    {
-        TRACE("[%p]: freeing storage\n", lphc->self);
-
-        if ( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
-            DestroyWindow( lphc->hWndLBox );
-
-        SetWindowLongPtrW( lphc->self, 0, 0 );
-        heap_free( lphc );
-    }
-
-    return 0;
-}
-
-/***********************************************************************
- *           CBGetTextAreaHeight
- *
- * This method will calculate the height of the text area of the
- * combobox.
- * The height of the text area is set in two ways.
- * It can be set explicitly through a combobox message or through a
- * WM_MEASUREITEM callback.
- * If this is not the case, the height is set to font height + 4px
- * This height was determined through experimentation.
- * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
- */
-static INT CBGetTextAreaHeight(
-  HWND        hwnd,
-  LPHEADCOMBO lphc)
-{
-  INT iTextItemHeight;
-
-  if( lphc->editHeight ) /* explicitly set height */
-  {
-    iTextItemHeight = lphc->editHeight;
-  }
-  else
-  {
-    TEXTMETRICW tm;
-    HDC         hDC       = GetDC(hwnd);
-    HFONT       hPrevFont = 0;
-    INT         baseUnitY;
-
-    if (lphc->hFont)
-      hPrevFont = SelectObject( hDC, lphc->hFont );
-
-    GetTextMetricsW(hDC, &tm);
-
-    baseUnitY = tm.tmHeight;
-
-    if( hPrevFont )
-      SelectObject( hDC, hPrevFont );
-
-    ReleaseDC(hwnd, hDC);
-
-    iTextItemHeight = baseUnitY + 4;
-  }
-
-  /*
-   * Check the ownerdraw case if we haven't asked the parent the size
-   * of the item yet.
-   */
-  if ( CB_OWNERDRAWN(lphc) &&
-       (lphc->wState & CBF_MEASUREITEM) )
-  {
-    MEASUREITEMSTRUCT measureItem;
-    RECT              clientRect;
-    INT               originalItemHeight = iTextItemHeight;
-    UINT id = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
-
-    /*
-     * We use the client rect for the width of the item.
-     */
-    GetClientRect(hwnd, &clientRect);
-
-    lphc->wState &= ~CBF_MEASUREITEM;
-
-    /*
-     * Send a first one to measure the size of the text area
-     */
-    measureItem.CtlType    = ODT_COMBOBOX;
-    measureItem.CtlID      = id;
-    measureItem.itemID     = -1;
-    measureItem.itemWidth  = clientRect.right;
-    measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
-    measureItem.itemData   = 0;
-    SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
-    iTextItemHeight = 6 + measureItem.itemHeight;
-
-    /*
-     * Send a second one in the case of a fixed ownerdraw list to calculate the
-     * size of the list items. (we basically do this on behalf of the listbox)
-     */
-    if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
-    {
-      measureItem.CtlType    = ODT_COMBOBOX;
-      measureItem.CtlID      = id;
-      measureItem.itemID     = 0;
-      measureItem.itemWidth  = clientRect.right;
-      measureItem.itemHeight = originalItemHeight;
-      measureItem.itemData   = 0;
-      SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
-      lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
-    }
-
-    /*
-     * Keep the size for the next time
-     */
-    lphc->editHeight = iTextItemHeight;
-  }
-
-  return iTextItemHeight;
-}
-
-/***********************************************************************
- *           CBForceDummyResize
- *
- * The dummy resize is used for listboxes that have a popup to trigger
- * a re-arranging of the contents of the combobox and the recalculation
- * of the size of the "real" control window.
- */
-static void CBForceDummyResize(
-  LPHEADCOMBO lphc)
-{
-  RECT windowRect;
-  int newComboHeight;
-
-  newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
-
-  GetWindowRect(lphc->self, &windowRect);
-
-  /*
-   * We have to be careful, resizing a combobox also has the meaning that the
-   * dropped rect will be resized. In this case, we want to trigger a resize
-   * to recalculate layout but we don't want to change the dropped rectangle
-   * So, we pass the height of text area of control as the height.
-   * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
-   * message.
-   */
-  SetWindowPos( lphc->self,
-		NULL,
-		0, 0,
-		windowRect.right  - windowRect.left,
-		newComboHeight,
-		SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
-}
-
-/***********************************************************************
- *           CBCalcPlacement
- *
- * Set up component coordinates given valid lphc->RectCombo.
- */
-static void CBCalcPlacement(
-  HWND        hwnd,
-  LPHEADCOMBO lphc,
-  LPRECT      lprEdit,
-  LPRECT      lprButton,
-  LPRECT      lprLB)
-{
-  /*
-   * Again, start with the client rectangle.
-   */
-  GetClientRect(hwnd, lprEdit);
-
-  /*
-   * Remove the borders
-   */
-  InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
-
-  /*
-   * Chop off the bottom part to fit with the height of the text area.
-   */
-  lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
-
-  /*
-   * The button starts the same vertical position as the text area.
-   */
-  CopyRect(lprButton, lprEdit);
-
-  /*
-   * If the combobox is "simple" there is no button.
-   */
-  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
-    lprButton->left = lprButton->right = lprButton->bottom = 0;
-  else
-  {
-    /*
-     * Let's assume the combobox button is the same width as the
-     * scrollbar button.
-     * size the button horizontally and cut-off the text area.
-     */
-    lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
-    lprEdit->right  = lprButton->left;
-  }
-
-  /*
-   * In the case of a dropdown, there is an additional spacing between the
-   * text area and the button.
-   */
-  if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-  {
-    lprEdit->right -= COMBO_EDITBUTTONSPACE();
-  }
-
-  /*
-   * If we have an edit control, we space it away from the borders slightly.
-   */
-  if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
-  {
-    InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
-  }
-
-  /*
-   * Adjust the size of the listbox popup.
-   */
-  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
-  {
-    /*
-     * Use the client rectangle to initialize the listbox rectangle
-     */
-    GetClientRect(hwnd, lprLB);
-
-    /*
-     * Then, chop-off the top part.
-     */
-    lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
-  }
-  else
-  {
-    /*
-     * Make sure the dropped width is as large as the combobox itself.
-     */
-    if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
-    {
-      lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
-
-      /*
-       * In the case of a dropdown, the popup listbox is offset to the right.
-       * so, we want to make sure it's flush with the right side of the
-       * combobox
-       */
-      if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	lprLB->right -= COMBO_EDITBUTTONSPACE();
-    }
-    else
-       lprLB->right = lprLB->left + lphc->droppedWidth;
-  }
-
-  /* don't allow negative window width */
-  if (lprEdit->right < lprEdit->left)
-    lprEdit->right = lprEdit->left;
-
-  TRACE("\ttext\t= (%s)\n", wine_dbgstr_rect(lprEdit));
-
-  TRACE("\tbutton\t= (%s)\n", wine_dbgstr_rect(lprButton));
-
-  TRACE("\tlbox\t= (%s)\n", wine_dbgstr_rect(lprLB));
-}
-
-/***********************************************************************
- *           CBGetDroppedControlRect
- */
-static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
-{
-    /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
-     of the combo box and the lower right corner of the listbox */
-
-    GetWindowRect(lphc->self, lpRect);
-
-    lpRect->right =  lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
-    lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
-
-}
-
-/***********************************************************************
- *           COMBO_Create
- */
-static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style,
-                             BOOL unicode )
-{
-  static const WCHAR clbName[] = {'C','o','m','b','o','L','B','o','x',0};
-  static const WCHAR editName[] = {'E','d','i','t',0};
-
-  if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
-  if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
-
-  lphc->owner = hwndParent;
-
-  /*
-   * The item height and dropped width are not set when the control
-   * is created.
-   */
-  lphc->droppedWidth = lphc->editHeight = 0;
-
-  /*
-   * The first time we go through, we want to measure the ownerdraw item
-   */
-  lphc->wState |= CBF_MEASUREITEM;
-
-  /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
-
-  if( lphc->owner || !(style & WS_VISIBLE) )
-  {
-      UINT lbeStyle   = 0;
-      UINT lbeExStyle = 0;
-
-      /*
-       * Initialize the dropped rect to the size of the client area of the
-       * control and then, force all the areas of the combobox to be
-       * recalculated.
-       */
-      GetClientRect( hwnd, &lphc->droppedRect );
-      CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
-
-      /*
-       * Adjust the position of the popup listbox if it's necessary
-       */
-      if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
-      {
-	lphc->droppedRect.top   = lphc->textRect.bottom + COMBO_YBORDERSIZE();
-
-	/*
-	 * If it's a dropdown, the listbox is offset
-	 */
-	if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	  lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
-
-        if (lphc->droppedRect.bottom < lphc->droppedRect.top)
-            lphc->droppedRect.bottom = lphc->droppedRect.top;
-        if (lphc->droppedRect.right < lphc->droppedRect.left)
-            lphc->droppedRect.right = lphc->droppedRect.left;
-        MapWindowPoints( hwnd, 0, (LPPOINT)&lphc->droppedRect, 2 );
-      }
-
-      /* create listbox popup */
-
-      lbeStyle = (LBS_NOTIFY | LBS_COMBOBOX | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
-                 (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
-
-      if( lphc->dwStyle & CBS_SORT )
-	lbeStyle |= LBS_SORT;
-      if( lphc->dwStyle & CBS_HASSTRINGS )
-	lbeStyle |= LBS_HASSTRINGS;
-      if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
-	lbeStyle |= LBS_NOINTEGRALHEIGHT;
-      if( lphc->dwStyle & CBS_DISABLENOSCROLL )
-	lbeStyle |= LBS_DISABLENOSCROLL;
-
-      if( CB_GETTYPE(lphc) == CBS_SIMPLE ) 	/* child listbox */
-      {
-	lbeStyle |= WS_VISIBLE;
-
-	/*
-	 * In win 95 look n feel, the listbox in the simple combobox has
-	 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
-	 */
-	lbeStyle   &= ~WS_BORDER;
-	lbeExStyle |= WS_EX_CLIENTEDGE;
-      }
-      else
-      {
-        lbeExStyle |= (WS_EX_TOPMOST | WS_EX_TOOLWINDOW);
-      }
-
-      if (unicode)
-          lphc->hWndLBox = CreateWindowExW(lbeExStyle, clbName, NULL, lbeStyle,
-                                           lphc->droppedRect.left,
-                                           lphc->droppedRect.top,
-                                           lphc->droppedRect.right - lphc->droppedRect.left,
-                                           lphc->droppedRect.bottom - lphc->droppedRect.top,
-                                           hwnd, (HMENU)ID_CB_LISTBOX,
-                                           (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
-      else
-          lphc->hWndLBox = CreateWindowExA(lbeExStyle, "ComboLBox", NULL, lbeStyle,
-                                           lphc->droppedRect.left,
-                                           lphc->droppedRect.top,
-                                           lphc->droppedRect.right - lphc->droppedRect.left,
-                                           lphc->droppedRect.bottom - lphc->droppedRect.top,
-                                           hwnd, (HMENU)ID_CB_LISTBOX,
-                                           (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
-
-      if( lphc->hWndLBox )
-      {
-	  BOOL	bEdit = TRUE;
-	  lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
-
-	  if( lphc->wState & CBF_EDIT )
-	  {
-	      if( lphc->dwStyle & CBS_OEMCONVERT )
-		  lbeStyle |= ES_OEMCONVERT;
-	      if( lphc->dwStyle & CBS_AUTOHSCROLL )
-		  lbeStyle |= ES_AUTOHSCROLL;
-	      if( lphc->dwStyle & CBS_LOWERCASE )
-		  lbeStyle |= ES_LOWERCASE;
-	      else if( lphc->dwStyle & CBS_UPPERCASE )
-		  lbeStyle |= ES_UPPERCASE;
-
-              if (!IsWindowEnabled(hwnd)) lbeStyle |= WS_DISABLED;
-
-              if (unicode)
-                  lphc->hWndEdit = CreateWindowExW(0, editName, NULL, lbeStyle,
-                                                   lphc->textRect.left, lphc->textRect.top,
-                                                   lphc->textRect.right - lphc->textRect.left,
-                                                   lphc->textRect.bottom - lphc->textRect.top,
-                                                   hwnd, (HMENU)ID_CB_EDIT,
-                                                   (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), NULL );
-              else
-                  lphc->hWndEdit = CreateWindowExA(0, "Edit", NULL, lbeStyle,
-                                                   lphc->textRect.left, lphc->textRect.top,
-                                                   lphc->textRect.right - lphc->textRect.left,
-                                                   lphc->textRect.bottom - lphc->textRect.top,
-                                                   hwnd, (HMENU)ID_CB_EDIT,
-                                                   (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), NULL );
-
-	      if( !lphc->hWndEdit )
-		bEdit = FALSE;
-	  }
-
-          if( bEdit )
-	  {
-	    if( CB_GETTYPE(lphc) != CBS_SIMPLE )
-	    {
-              /* Now do the trick with parent */
-	      SetParent(lphc->hWndLBox, HWND_DESKTOP);
-              /*
-               * If the combo is a dropdown, we must resize the control
-	       * to fit only the text area and button. To do this,
-	       * we send a dummy resize and the WM_WINDOWPOSCHANGING message
-	       * will take care of setting the height for us.
-               */
-	      CBForceDummyResize(lphc);
-	    }
-
-	    TRACE("init done\n");
-	    return 0;
-	  }
-	  ERR("edit control failure.\n");
-      } else ERR("listbox failure.\n");
-  } else ERR("no owner for visible combo.\n");
-
-  /* CreateWindow() will send WM_NCDESTROY to cleanup */
-
-  return -1;
-}
-
-/***********************************************************************
- *           CBPaintButton
- *
- * Paint combo button (normal, pressed, and disabled states).
- */
-static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
-{
-    UINT buttonState = DFCS_SCROLLCOMBOBOX;
-
-    if( lphc->wState & CBF_NOREDRAW )
-      return;
-
-
-    if (lphc->wState & CBF_BUTTONDOWN)
-	buttonState |= DFCS_PUSHED;
-
-    if (CB_DISABLED(lphc))
-	buttonState |= DFCS_INACTIVE;
-
-    DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
-}
-
-/***********************************************************************
- *           COMBO_PrepareColors
- *
- * This method will sent the appropriate WM_CTLCOLOR message to
- * prepare and setup the colors for the combo's DC.
- *
- * It also returns the brush to use for the background.
- */
-static HBRUSH COMBO_PrepareColors(
-        LPHEADCOMBO lphc,
-        HDC         hDC)
-{
-    HBRUSH  hBkgBrush;
-
-    /*
-     * Get the background brush for this control.
-     */
-    if (CB_DISABLED(lphc))
-    {
-        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLORSTATIC,
-                (WPARAM)hDC, (LPARAM)lphc->self );
-
-        /*
-         * We have to change the text color since WM_CTLCOLORSTATIC will
-         * set it to the "enabled" color. This is the same behavior as the
-         * edit control
-         */
-        SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
-    }
-    else
-    {
-        /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
-        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLOREDIT,
-                (WPARAM)hDC, (LPARAM)lphc->self );
-    }
-
-    /*
-     * Catch errors.
-     */
-    if( !hBkgBrush )
-        hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
-
-    return hBkgBrush;
-}
-
-/***********************************************************************
- *           CBPaintText
- *
- * Paint CBS_DROPDOWNLIST text field / update edit control contents.
- */
-static void CBPaintText(HEADCOMBO *lphc, HDC hdc_paint)
-{
-   RECT rectEdit = lphc->textRect;
-   INT	id, size = 0;
-   LPWSTR pText = NULL;
-
-   TRACE("\n");
-
-   /* follow Windows combobox that sends a bunch of text
-    * inquiries to its listbox while processing WM_PAINT. */
-
-   if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
-   {
-        size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
-	if (size == LB_ERR)
-	  FIXME("LB_ERR probably not handled yet\n");
-        if ((pText = heap_alloc((size + 1) * sizeof(WCHAR))))
-	{
-            /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
-           size=SendMessageW(lphc->hWndLBox, LB_GETTEXT, id, (LPARAM)pText);
-	    pText[size] = '\0';	/* just in case */
-	} else return;
-   }
-
-   if( lphc->wState & CBF_EDIT )
-   {
-        static const WCHAR empty_stringW[] = { 0 };
-	if( CB_HASSTRINGS(lphc) ) SetWindowTextW( lphc->hWndEdit, pText ? pText : empty_stringW );
-	if( lphc->wState & CBF_FOCUSED )
-           SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, MAXLONG);
-   }
-   else if(!(lphc->wState & CBF_NOREDRAW) && IsWindowVisible( lphc->self ))
-   {
-     /* paint text field ourselves */
-     HDC hdc = hdc_paint ? hdc_paint : GetDC(lphc->self);
-     UINT itemState = ODS_COMBOBOXEDIT;
-     HFONT hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
-     HBRUSH hPrevBrush, hBkgBrush;
-
-     /*
-      * Give ourselves some space.
-      */
-     InflateRect( &rectEdit, -1, -1 );
-
-     hBkgBrush = COMBO_PrepareColors( lphc, hdc );
-     hPrevBrush = SelectObject( hdc, hBkgBrush );
-     FillRect( hdc, &rectEdit, hBkgBrush );
-
-     if( CB_OWNERDRAWN(lphc) )
-     {
-       DRAWITEMSTRUCT dis;
-       HRGN           clipRegion;
-       UINT ctlid = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
-
-       /* setup state for DRAWITEM message. Owner will highlight */
-       if ( (lphc->wState & CBF_FOCUSED) &&
-	    !(lphc->wState & CBF_DROPPED) )
-	   itemState |= ODS_SELECTED | ODS_FOCUS;
-
-       if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED;
-
-       dis.CtlType	= ODT_COMBOBOX;
-       dis.CtlID	= ctlid;
-       dis.hwndItem	= lphc->self;
-       dis.itemAction	= ODA_DRAWENTIRE;
-       dis.itemID	= id;
-       dis.itemState	= itemState;
-       dis.hDC		= hdc;
-       dis.rcItem	= rectEdit;
-       dis.itemData     = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0);
-
-       /*
-	* Clip the DC and have the parent draw the item.
-	*/
-       clipRegion = set_control_clipping( hdc, &rectEdit );
-
-       SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
-
-       SelectClipRgn( hdc, clipRegion );
-       if (clipRegion) DeleteObject( clipRegion );
-     }
-     else
-     {
-       static const WCHAR empty_stringW[] = { 0 };
-
-       if ( (lphc->wState & CBF_FOCUSED) &&
-	    !(lphc->wState & CBF_DROPPED) ) {
-
-	   /* highlight */
-	   FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
-	   SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
-	   SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
-       }
-
-       ExtTextOutW( hdc,
-		    rectEdit.left + 1,
-		    rectEdit.top + 1,
-		    ETO_OPAQUE | ETO_CLIPPED,
-		    &rectEdit,
-		    pText ? pText : empty_stringW , size, NULL );
-
-       if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
-	 DrawFocusRect( hdc, &rectEdit );
-     }
-
-     if( hPrevFont )
-       SelectObject(hdc, hPrevFont );
-
-    if( hPrevBrush )
-        SelectObject( hdc, hPrevBrush );
-
-     if( !hdc_paint )
-       ReleaseDC( lphc->self, hdc );
-   }
-
-    heap_free(pText);
-}
-
-/***********************************************************************
- *           CBPaintBorder
- */
-static void CBPaintBorder(
-  HWND            hwnd,
-  const HEADCOMBO *lphc,
-  HDC             hdc)
-{
-  RECT clientRect;
-
-  if (CB_GETTYPE(lphc) != CBS_SIMPLE)
-  {
-    GetClientRect(hwnd, &clientRect);
-  }
-  else
-  {
-    clientRect = lphc->textRect;
-
-    InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
-    InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
-  }
-
-  DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
-}
-
-/***********************************************************************
- *           COMBO_Paint
- */
-static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
-{
-  PAINTSTRUCT ps;
-  HDC 	hDC;
-
-  hDC = (hParamDC) ? hParamDC
-		   : BeginPaint( lphc->self, &ps);
-
-  TRACE("hdc=%p\n", hDC);
-
-  if( hDC && !(lphc->wState & CBF_NOREDRAW) )
-  {
-      HBRUSH	hPrevBrush, hBkgBrush;
-
-      /*
-       * Retrieve the background brush and select it in the
-       * DC.
-       */
-      hBkgBrush = COMBO_PrepareColors(lphc, hDC);
-
-      hPrevBrush = SelectObject( hDC, hBkgBrush );
-      if (!(lphc->wState & CBF_EDIT))
-        FillRect(hDC, &lphc->textRect, hBkgBrush);
-
-      /*
-       * In non 3.1 look, there is a sunken border on the combobox
-       */
-      CBPaintBorder(lphc->self, lphc, hDC);
-
-      if( !IsRectEmpty(&lphc->buttonRect) )
-      {
-	CBPaintButton(lphc, hDC, lphc->buttonRect);
-      }
-
-      /* paint the edit control padding area */
-      if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
-      {
-          RECT rPadEdit = lphc->textRect;
-
-          InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
-
-          FrameRect( hDC, &rPadEdit, GetSysColorBrush(COLOR_WINDOW) );
-      }
-
-      if( !(lphc->wState & CBF_EDIT) )
-	CBPaintText( lphc, hDC );
-
-      if( hPrevBrush )
-	SelectObject( hDC, hPrevBrush );
-  }
-
-  if( !hParamDC )
-    EndPaint(lphc->self, &ps);
-
-  return 0;
-}
-
-/***********************************************************************
- *           CBUpdateLBox
- *
- * Select listbox entry according to the contents of the edit control.
- */
-static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
-{
-   INT	length, idx;
-   LPWSTR pText = NULL;
-
-   idx = LB_ERR;
-   length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
-
-    if (length > 0)
-        pText = heap_alloc((length + 1) * sizeof(WCHAR));
-
-   TRACE("\t edit text length %i\n", length );
-
-   if( pText )
-   {
-       GetWindowTextW( lphc->hWndEdit, pText, length + 1);
-       idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING, -1, (LPARAM)pText);
-       heap_free( pText );
-   }
-
-   SendMessageW(lphc->hWndLBox, LB_SETCURSEL, bSelect ? idx : -1, 0);
-
-   /* probably superfluous but Windows sends this too */
-   SendMessageW(lphc->hWndLBox, LB_SETCARETINDEX, idx < 0 ? 0 : idx, 0);
-   SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, idx < 0 ? 0 : idx, 0);
-
-   return idx;
-}
-
-/***********************************************************************
- *           CBUpdateEdit
- *
- * Copy a listbox entry to the edit control.
- */
-static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
-{
-   INT	length;
-   LPWSTR pText = NULL;
-   static const WCHAR empty_stringW[] = { 0 };
-
-   TRACE("\t %i\n", index );
-
-   if( index >= 0 ) /* got an entry */
-   {
-       length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, index, 0);
-       if( length != LB_ERR)
-       {
-           if ((pText = heap_alloc((length + 1) * sizeof(WCHAR))))
-               SendMessageW(lphc->hWndLBox, LB_GETTEXT, index, (LPARAM)pText);
-       }
-   }
-
-   if( CB_HASSTRINGS(lphc) )
-   {
-      lphc->wState |= (CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
-      SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText : (LPARAM)empty_stringW);
-      lphc->wState &= ~(CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
-   }
-
-   if( lphc->wState & CBF_FOCUSED )
-      SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
-
-    heap_free( pText );
-}
-
-/***********************************************************************
- *           CBDropDown
- *
- * Show listbox popup.
- */
-static void CBDropDown( LPHEADCOMBO lphc )
-{
-    HMONITOR monitor;
-    MONITORINFO mon_info;
-   RECT rect,r;
-   int nItems;
-   int nDroppedHeight;
-
-   TRACE("[%p]: drop down\n", lphc->self);
-
-   CB_NOTIFY( lphc, CBN_DROPDOWN );
-
-   /* set selection */
-
-   lphc->wState |= CBF_DROPPED;
-   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-   {
-       lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
-
-       /* Update edit only if item is in the list */
-       if( !(lphc->wState & CBF_CAPTURE) && lphc->droppedIndex >= 0)
-	 CBUpdateEdit( lphc, lphc->droppedIndex );
-   }
-   else
-   {
-       lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-
-       SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
-                    lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex, 0);
-       SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
-   }
-
-   /* now set popup position */
-   GetWindowRect( lphc->self, &rect );
-
-   /*
-    * If it's a dropdown, the listbox is offset
-    */
-   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-     rect.left += COMBO_EDITBUTTONSPACE();
-
-  /* if the dropped height is greater than the total height of the dropped
-     items list, then force the drop down list height to be the total height
-     of the items in the dropped list */
-
-  /* And Remove any extra space (Best Fit) */
-   nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
-  /* if listbox length has been set directly by its handle */
-   GetWindowRect(lphc->hWndLBox, &r);
-   if (nDroppedHeight < r.bottom - r.top)
-       nDroppedHeight = r.bottom - r.top;
-   nItems = (int)SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
-
-   if (nItems > 0)
-   {
-      int nHeight;
-      int nIHeight;
-
-      nIHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
-
-      nHeight = nIHeight*nItems;
-
-      if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
-         nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
-   }
-
-   r.left = rect.left;
-   r.top = rect.bottom;
-   r.right = r.left + lphc->droppedRect.right - lphc->droppedRect.left;
-   r.bottom = r.top + nDroppedHeight;
-
-   /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
-   monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
-   mon_info.cbSize = sizeof(mon_info);
-   GetMonitorInfoW( monitor, &mon_info );
-
-   if (r.bottom > mon_info.rcWork.bottom)
-   {
-       r.top = max( rect.top - nDroppedHeight, mon_info.rcWork.top );
-       r.bottom = min( r.top + nDroppedHeight, mon_info.rcWork.bottom );
-   }
-
-   SetWindowPos( lphc->hWndLBox, HWND_TOPMOST, r.left, r.top, r.right - r.left, r.bottom - r.top,
-                 SWP_NOACTIVATE | SWP_SHOWWINDOW );
-
-
-   if( !(lphc->wState & CBF_NOREDRAW) )
-     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
-			   RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
-
-   EnableWindow( lphc->hWndLBox, TRUE );
-   if (GetCapture() != lphc->self)
-      SetCapture(lphc->hWndLBox);
-}
-
-/***********************************************************************
- *           CBRollUp
- *
- * Hide listbox popup.
- */
-static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
-{
-   HWND	hWnd = lphc->self;
-
-   TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
-	 lphc->self, ok, (INT)(lphc->wState & CBF_DROPPED));
-
-   CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
-
-   if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
-   {
-
-       if( lphc->wState & CBF_DROPPED )
-       {
-	   RECT	rect;
-
-	   lphc->wState &= ~CBF_DROPPED;
-	   ShowWindow( lphc->hWndLBox, SW_HIDE );
-
-           if(GetCapture() == lphc->hWndLBox)
-           {
-               ReleaseCapture();
-           }
-
-	   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-	   {
-	       rect = lphc->buttonRect;
-	   }
-	   else
-           {
-	       if( bButton )
-	       {
-		 UnionRect( &rect,
-			    &lphc->buttonRect,
-			    &lphc->textRect);
-	       }
-	       else
-		 rect = lphc->textRect;
-
-	       bButton = TRUE;
-	   }
-
-	   if( bButton && !(lphc->wState & CBF_NOREDRAW) )
-	       RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
-			       RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
-	   CB_NOTIFY( lphc, CBN_CLOSEUP );
-       }
-   }
-}
-
-/***********************************************************************
- *           COMBO_FlipListbox
- *
- * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
- */
-BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
-{
-   if( lphc->wState & CBF_DROPPED )
-   {
-       CBRollUp( lphc, ok, bRedrawButton );
-       return FALSE;
-   }
-
-   CBDropDown( lphc );
-   return TRUE;
-}
-
-/***********************************************************************
- *           CBRepaintButton
- */
-static void CBRepaintButton( LPHEADCOMBO lphc )
-   {
-  InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
-  UpdateWindow(lphc->self);
-}
-
-/***********************************************************************
- *           COMBO_SetFocus
- */
-static void COMBO_SetFocus( LPHEADCOMBO lphc )
-{
-   if( !(lphc->wState & CBF_FOCUSED) )
-   {
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-           SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
-
-       /* This is wrong. Message sequences seem to indicate that this
-          is set *after* the notify. */
-       /* lphc->wState |= CBF_FOCUSED;  */
-
-       if( !(lphc->wState & CBF_EDIT) )
-	 InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-
-       CB_NOTIFY( lphc, CBN_SETFOCUS );
-       lphc->wState |= CBF_FOCUSED;
-   }
-}
-
-/***********************************************************************
- *           COMBO_KillFocus
- */
-static void COMBO_KillFocus( LPHEADCOMBO lphc )
-{
-   HWND	hWnd = lphc->self;
-
-   if( lphc->wState & CBF_FOCUSED )
-   {
-       CBRollUp( lphc, FALSE, TRUE );
-       if( IsWindow( hWnd ) )
-       {
-           if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-               SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
-
-	   lphc->wState &= ~CBF_FOCUSED;
-
-           /* redraw text */
-	   if( !(lphc->wState & CBF_EDIT) )
-	     InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-
-           CB_NOTIFY( lphc, CBN_KILLFOCUS );
-       }
-   }
-}
-
-/***********************************************************************
- *           COMBO_Command
- */
-static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
-{
-   if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
-   {
-       /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
-
-       switch( HIWORD(wParam) >> 8 )
-       {
-	   case (EN_SETFOCUS >> 8):
-
-               TRACE("[%p]: edit [%p] got focus\n", lphc->self, lphc->hWndEdit );
-
-		COMBO_SetFocus( lphc );
-	        break;
-
-	   case (EN_KILLFOCUS >> 8):
-
-               TRACE("[%p]: edit [%p] lost focus\n", lphc->self, lphc->hWndEdit );
-
-		/* NOTE: it seems that Windows' edit control sends an
-		 * undocumented message WM_USER + 0x1B instead of this
-		 * notification (only when it happens to be a part of
-		 * the combo). ?? - AK.
-		 */
-
-		COMBO_KillFocus( lphc );
-		break;
-
-
-	   case (EN_CHANGE >> 8):
-	       /*
-	        * In some circumstances (when the selection of the combobox
-		* is changed for example) we don't want the EN_CHANGE notification
-		* to be forwarded to the parent of the combobox. This code
-		* checks a flag that is set in these occasions and ignores the
-		* notification.
-	        */
-		if (lphc->wState & CBF_NOLBSELECT)
-		{
-		  lphc->wState &= ~CBF_NOLBSELECT;
-		}
-		else
-		{
-		  CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
-		}
-
-	        if (!(lphc->wState & CBF_NOEDITNOTIFY))
-		  CB_NOTIFY( lphc, CBN_EDITCHANGE );
-		break;
-
-	   case (EN_UPDATE >> 8):
-	        if (!(lphc->wState & CBF_NOEDITNOTIFY))
-		  CB_NOTIFY( lphc, CBN_EDITUPDATE );
-		break;
-
-	   case (EN_ERRSPACE >> 8):
-		CB_NOTIFY( lphc, CBN_ERRSPACE );
-       }
-   }
-   else if( lphc->hWndLBox == hWnd )
-   {
-       switch( (short)HIWORD(wParam) )
-       {
-	   case LBN_ERRSPACE:
-		CB_NOTIFY( lphc, CBN_ERRSPACE );
-		break;
-
-	   case LBN_DBLCLK:
-		CB_NOTIFY( lphc, CBN_DBLCLK );
-		break;
-
-	   case LBN_SELCHANGE:
-	   case LBN_SELCANCEL:
-
-                TRACE("[%p]: lbox selection change [%x]\n", lphc->self, lphc->wState );
-
-                /* do not roll up if selection is being tracked
-                 * by arrow keys in the dropdown listbox */
-                if (!(lphc->wState & CBF_NOROLLUP))
-                {
-                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
-                }
-                else lphc->wState &= ~CBF_NOROLLUP;
-
-		CB_NOTIFY( lphc, CBN_SELCHANGE );
-
-		if( HIWORD(wParam) == LBN_SELCHANGE)
-		{
-		   if( lphc->wState & CBF_EDIT )
-		       lphc->wState |= CBF_NOLBSELECT;
-		   CBPaintText( lphc, NULL );
-		}
-                break;
-
-	   case LBN_SETFOCUS:
-	   case LBN_KILLFOCUS:
-		/* nothing to do here since ComboLBox always resets the focus to its
-		 * combo/edit counterpart */
-		 break;
-       }
-   }
-   return 0;
-}
-
-/***********************************************************************
- *           COMBO_ItemOp
- *
- * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
- */
-static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
-{
-   HWND hWnd = lphc->self;
-   UINT id = (UINT)GetWindowLongPtrW( hWnd, GWLP_ID );
-
-   TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
-
-   switch( msg )
-   {
-   case WM_DELETEITEM:
-       {
-           DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_DRAWITEM:
-       {
-           DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_COMPAREITEM:
-       {
-           COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           lpIS->hwndItem = hWnd;
-           break;
-       }
-   case WM_MEASUREITEM:
-       {
-           MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
-           lpIS->CtlType  = ODT_COMBOBOX;
-           lpIS->CtlID    = id;
-           break;
-       }
-   }
-   return SendMessageW(lphc->owner, msg, id, lParam);
-}
-
-
-/***********************************************************************
- *           COMBO_GetTextW
- */
-static LRESULT COMBO_GetTextW( HEADCOMBO *lphc, INT count, LPWSTR buf )
-{
-    INT length;
-
-    if( lphc->wState & CBF_EDIT )
-        return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
-
-    /* get it from the listbox */
-
-    if (!count || !buf) return 0;
-    if( lphc->hWndLBox )
-    {
-        INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-        if (idx == LB_ERR) goto error;
-        length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
-        if (length == LB_ERR) goto error;
-
-        /* 'length' is without the terminating character */
-        if (length >= count)
-        {
-            WCHAR *lpBuffer = heap_alloc((length + 1) * sizeof(WCHAR));
-            if (!lpBuffer) goto error;
-            length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
-
-            /* truncate if buffer is too short */
-            if (length != LB_ERR)
-            {
-                lstrcpynW( buf, lpBuffer, count );
-                length = count;
-            }
-            heap_free( lpBuffer );
-        }
-        else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
-
-        if (length == LB_ERR) return 0;
-        return length;
-    }
-
- error:  /* error - truncate string, return zero */
-    buf[0] = 0;
-    return 0;
-}
-
-
-/***********************************************************************
- *           COMBO_GetTextA
- *
- * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
- *       also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
- */
-static LRESULT COMBO_GetTextA( LPHEADCOMBO lphc, INT count, LPSTR buf )
-{
-    INT length;
-
-    if( lphc->wState & CBF_EDIT )
-        return SendMessageA( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
-
-    /* get it from the listbox */
-
-    if (!count || !buf) return 0;
-    if( lphc->hWndLBox )
-    {
-        INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-        if (idx == LB_ERR) goto error;
-        length = SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
-        if (length == LB_ERR) goto error;
-
-        /* 'length' is without the terminating character */
-        if (length >= count)
-        {
-            LPSTR lpBuffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) );
-            if (!lpBuffer) goto error;
-            length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
-
-            /* truncate if buffer is too short */
-            if (length != LB_ERR)
-            {
-                lstrcpynA( buf, lpBuffer, count );
-                length = count;
-            }
-            HeapFree( GetProcessHeap(), 0, lpBuffer );
-        }
-        else length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
-
-        if (length == LB_ERR) return 0;
-        return length;
-    }
-
- error:  /* error - truncate string, return zero */
-    buf[0] = 0;
-    return 0;
-}
-
-
-/***********************************************************************
- *           CBResetPos
- *
- * This function sets window positions according to the updated
- * component placement struct.
- */
-static void CBResetPos(
-  LPHEADCOMBO lphc,
-  const RECT  *rectEdit,
-  const RECT  *rectLB,
-  BOOL        bRedraw)
-{
-   BOOL	bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
-
-   /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
-    * sizing messages */
-
-   if( lphc->wState & CBF_EDIT )
-     SetWindowPos( lphc->hWndEdit, 0,
-		   rectEdit->left, rectEdit->top,
-		   rectEdit->right - rectEdit->left,
-		   rectEdit->bottom - rectEdit->top,
-                       SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
-
-   SetWindowPos( lphc->hWndLBox, 0,
-		 rectLB->left, rectLB->top,
-                 rectLB->right - rectLB->left,
-		 rectLB->bottom - rectLB->top,
-		   SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
-
-   if( bDrop )
-   {
-       if( lphc->wState & CBF_DROPPED )
-       {
-           lphc->wState &= ~CBF_DROPPED;
-           ShowWindow( lphc->hWndLBox, SW_HIDE );
-       }
-
-       if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
-           RedrawWindow( lphc->self, NULL, 0,
-                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
-   }
-}
-
-
-/***********************************************************************
- *           COMBO_Size
- */
-static void COMBO_Size( LPHEADCOMBO lphc )
-{
-  /*
-   * Those controls are always the same height. So we have to make sure
-   * they are not resized to another value.
-   */
-  if( CB_GETTYPE(lphc) != CBS_SIMPLE )
-  {
-    int newComboHeight, curComboHeight, curComboWidth;
-    RECT rc;
-
-    GetWindowRect(lphc->self, &rc);
-    curComboHeight = rc.bottom - rc.top;
-    curComboWidth = rc.right - rc.left;
-    newComboHeight = CBGetTextAreaHeight(lphc->self, lphc) + 2*COMBO_YBORDERSIZE();
-
-    /*
-     * Resizing a combobox has another side effect, it resizes the dropped
-     * rectangle as well. However, it does it only if the new height for the
-     * combobox is more than the height it should have. In other words,
-     * if the application resizing the combobox only had the intention to resize
-     * the actual control, for example, to do the layout of a dialog that is
-     * resized, the height of the dropdown is not changed.
-     */
-    if( curComboHeight > newComboHeight )
-    {
-      TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%d, oldDropTop=%d\n",
-            curComboHeight, newComboHeight, lphc->droppedRect.bottom,
-            lphc->droppedRect.top);
-      lphc->droppedRect.bottom = lphc->droppedRect.top + curComboHeight - newComboHeight;
-    }
-    /*
-     * Restore original height
-     */
-    if( curComboHeight != newComboHeight )
-      SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
-            SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW);
-  }
-
-  CBCalcPlacement(lphc->self,
-		  lphc,
-		  &lphc->textRect,
-		  &lphc->buttonRect,
-		  &lphc->droppedRect);
-
-  CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-}
-
-
-/***********************************************************************
- *           COMBO_Font
- */
-static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
-{
-  /*
-   * Set the font
-   */
-  lphc->hFont = hFont;
-
-  /*
-   * Propagate to owned windows.
-   */
-  if( lphc->wState & CBF_EDIT )
-      SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
-  SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
-
-  /*
-   * Redo the layout of the control.
-   */
-  if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
-  {
-    CBCalcPlacement(lphc->self,
-		    lphc,
-		    &lphc->textRect,
-		    &lphc->buttonRect,
-		    &lphc->droppedRect);
-
-    CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-  }
-  else
-  {
-    CBForceDummyResize(lphc);
-  }
-}
-
-
-/***********************************************************************
- *           COMBO_SetItemHeight
- */
-static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
-{
-   LRESULT	lRet = CB_ERR;
-
-   if( index == -1 ) /* set text field height */
-   {
-       if( height < 32768 )
-       {
-           lphc->editHeight = height + 2;  /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
-
-	 /*
-	  * Redo the layout of the control.
-	  */
-	 if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
-	 {
-	   CBCalcPlacement(lphc->self,
-			   lphc,
-			   &lphc->textRect,
-			   &lphc->buttonRect,
-			   &lphc->droppedRect);
-
-	   CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
-	 }
-	 else
-	 {
-	   CBForceDummyResize(lphc);
-	 }
-
-	   lRet = height;
-       }
-   }
-   else if ( CB_OWNERDRAWN(lphc) )	/* set listbox item height */
-       lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT, index, height);
-   return lRet;
-}
-
-/***********************************************************************
- *           COMBO_SelectString
- */
-static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText, BOOL unicode )
-{
-   INT index = unicode ? SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, start, pText) :
-                         SendMessageA(lphc->hWndLBox, LB_SELECTSTRING, start, pText);
-   if( index >= 0 )
-   {
-     if( lphc->wState & CBF_EDIT )
-       CBUpdateEdit( lphc, index );
-     else
-     {
-       InvalidateRect(lphc->self, &lphc->textRect, TRUE);
-     }
-   }
-   return (LRESULT)index;
-}
-
-/***********************************************************************
- *           COMBO_LButtonDown
- */
-static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
-{
-   POINT     pt;
-   BOOL      bButton;
-   HWND      hWnd = lphc->self;
-
-   pt.x = (short)LOWORD(lParam);
-   pt.y = (short)HIWORD(lParam);
-   bButton = PtInRect(&lphc->buttonRect, pt);
-
-   if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
-       (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
-   {
-       lphc->wState |= CBF_BUTTONDOWN;
-       if( lphc->wState & CBF_DROPPED )
-       {
-	   /* got a click to cancel selection */
-
-           lphc->wState &= ~CBF_BUTTONDOWN;
-           CBRollUp( lphc, TRUE, FALSE );
-	   if( !IsWindow( hWnd ) ) return;
-
-           if( lphc->wState & CBF_CAPTURE )
-           {
-               lphc->wState &= ~CBF_CAPTURE;
-               ReleaseCapture();
-           }
-       }
-       else
-       {
-	   /* drop down the listbox and start tracking */
-
-           lphc->wState |= CBF_CAPTURE;
-           SetCapture( hWnd );
-           CBDropDown( lphc );
-       }
-       if( bButton ) CBRepaintButton( lphc );
-   }
-}
-
-/***********************************************************************
- *           COMBO_LButtonUp
- *
- * Release capture and stop tracking if needed.
- */
-static void COMBO_LButtonUp( LPHEADCOMBO lphc )
-{
-   if( lphc->wState & CBF_CAPTURE )
-   {
-       lphc->wState &= ~CBF_CAPTURE;
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-       {
-	   INT index = CBUpdateLBox( lphc, TRUE );
-	   /* Update edit only if item is in the list */
-	   if(index >= 0)
-	   {
-	       lphc->wState |= CBF_NOLBSELECT;
-	       CBUpdateEdit( lphc, index );
-	       lphc->wState &= ~CBF_NOLBSELECT;
-	   }
-       }
-       ReleaseCapture();
-       SetCapture(lphc->hWndLBox);
-   }
-
-   if( lphc->wState & CBF_BUTTONDOWN )
-   {
-       lphc->wState &= ~CBF_BUTTONDOWN;
-       CBRepaintButton( lphc );
-   }
-}
-
-/***********************************************************************
- *           COMBO_MouseMove
- *
- * Two things to do - track combo button and release capture when
- * pointer goes into the listbox.
- */
-static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
-{
-   POINT  pt;
-   RECT   lbRect;
-
-   pt.x = (short)LOWORD(lParam);
-   pt.y = (short)HIWORD(lParam);
-
-   if( lphc->wState & CBF_BUTTONDOWN )
-   {
-     BOOL bButton;
-
-     bButton = PtInRect(&lphc->buttonRect, pt);
-
-     if( !bButton )
-     {
-       lphc->wState &= ~CBF_BUTTONDOWN;
-       CBRepaintButton( lphc );
-     }
-   }
-
-   GetClientRect( lphc->hWndLBox, &lbRect );
-   MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
-   if( PtInRect(&lbRect, pt) )
-   {
-       lphc->wState &= ~CBF_CAPTURE;
-       ReleaseCapture();
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
-
-       /* hand over pointer tracking */
-       SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
-   }
-}
-
-static LRESULT COMBO_GetComboBoxInfo(const HEADCOMBO *lphc, COMBOBOXINFO *pcbi)
-{
-    if (!pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
-        return FALSE;
-
-    pcbi->rcItem = lphc->textRect;
-    pcbi->rcButton = lphc->buttonRect;
-    pcbi->stateButton = 0;
-    if (lphc->wState & CBF_BUTTONDOWN)
-        pcbi->stateButton |= STATE_SYSTEM_PRESSED;
-    if (IsRectEmpty(&lphc->buttonRect))
-        pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
-    pcbi->hwndCombo = lphc->self;
-    pcbi->hwndItem = lphc->hWndEdit;
-    pcbi->hwndList = lphc->hWndLBox;
-    return TRUE;
-}
-
-static char *strdupA(LPCSTR str)
-{
-    char *ret;
-    DWORD len;
-
-    if(!str) return NULL;
-
-    len = strlen(str);
-    ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
-    memcpy(ret, str, len + 1);
-    return ret;
-}
-
-/***********************************************************************
- *           ComboWndProc_common
- */
 LRESULT ComboWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL unicode )
 {
-    HEADCOMBO *lphc = (HEADCOMBO *)GetWindowLongPtrW( hwnd, 0 );
-
     TRACE("[%p]: msg %s wp %08lx lp %08lx\n",
         hwnd, SPY_GetMsgName(message, hwnd), wParam, lParam );
 
-    if (!IsWindow(hwnd)) return 0;
-
-    if (lphc || message == WM_NCCREATE)
-    switch(message)
-    {
-
-    /* System messages */
-
-    case WM_NCCREATE:
-    {
-        LONG style = unicode ? ((LPCREATESTRUCTW)lParam)->style :
-                               ((LPCREATESTRUCTA)lParam)->style;
-        return COMBO_NCCreate(hwnd, style);
-    }
-    case WM_NCDESTROY:
-        COMBO_NCDestroy(lphc);
-        break;/* -> DefWindowProc */
-
-    case WM_CREATE:
-    {
-        HWND hwndParent;
-        LONG style;
-        if(unicode)
-        {
-            hwndParent = ((LPCREATESTRUCTW)lParam)->hwndParent;
-            style = ((LPCREATESTRUCTW)lParam)->style;
-        }
-        else
-        {
-            hwndParent = ((LPCREATESTRUCTA)lParam)->hwndParent;
-            style = ((LPCREATESTRUCTA)lParam)->style;
-        }
-        return COMBO_Create(hwnd, lphc, hwndParent, style, unicode);
-    }
-
-    case WM_PRINTCLIENT:
-    case WM_PAINT:
-        /* wParam may contain a valid HDC! */
-        return  COMBO_Paint(lphc, (HDC)wParam);
-
-    case WM_ERASEBKGND:
-        /* do all painting in WM_PAINT like Windows does */
-        return 1;
-
-    case WM_GETDLGCODE:
-    {
-        LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
-        if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
-        {
-            int vk = (int)((LPMSG)lParam)->wParam;
-
-            if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
-                result |= DLGC_WANTMESSAGE;
-        }
-        return  result;
-    }
-
-    case WM_SIZE:
-        if (lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
-            COMBO_Size( lphc );
-        return  TRUE;
-
-    case WM_SETFONT:
-        COMBO_Font( lphc, (HFONT)wParam, (BOOL)lParam );
-        return TRUE;
-
-    case WM_GETFONT:
-        return (LRESULT)lphc->hFont;
-
-    case WM_SETFOCUS:
-        if (lphc->wState & CBF_EDIT)
-        {
-            SetFocus( lphc->hWndEdit );
-            /* The first time focus is received, select all the text */
-            if (!(lphc->wState & CBF_BEENFOCUSED))
-            {
-                SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
-                lphc->wState |= CBF_BEENFOCUSED;
-            }
-        }
-        else
-            COMBO_SetFocus( lphc );
-        return  TRUE;
-
-    case WM_KILLFOCUS:
-    {
-        HWND hwndFocus = WIN_GetFullHandle( (HWND)wParam );
-        if (!hwndFocus || (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox))
-            COMBO_KillFocus( lphc );
-        return  TRUE;
-    }
-
-    case WM_COMMAND:
-        return COMBO_Command( lphc, wParam, WIN_GetFullHandle( (HWND)lParam ) );
-
-    case WM_GETTEXT:
-        return unicode ? COMBO_GetTextW( lphc, wParam, (LPWSTR)lParam )
-                       : COMBO_GetTextA( lphc, wParam, (LPSTR)lParam );
-
-    case WM_SETTEXT:
-    case WM_GETTEXTLENGTH:
-    case WM_CLEAR:
-        if ((message == WM_GETTEXTLENGTH) && !ISWIN31 && !(lphc->wState & CBF_EDIT))
-        {
-            int j = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-            if (j == -1) return 0;
-            return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, j, 0) :
-                             SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
-        }
-        else if ( lphc->wState & CBF_EDIT )
-        {
-            LRESULT ret;
-            lphc->wState |= CBF_NOEDITNOTIFY;
-            ret = unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
-                            SendMessageA(lphc->hWndEdit, message, wParam, lParam);
-            lphc->wState &= ~CBF_NOEDITNOTIFY;
-            return ret;
-        }
-        else
-            return CB_ERR;
-
-    case WM_CUT:
-    case WM_PASTE:
-    case WM_COPY:
-        if (lphc->wState & CBF_EDIT)
-        {
-            return unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
-                             SendMessageA(lphc->hWndEdit, message, wParam, lParam);
-        }
-        else return  CB_ERR;
-
-    case WM_DRAWITEM:
-    case WM_DELETEITEM:
-    case WM_COMPAREITEM:
-    case WM_MEASUREITEM:
-        return COMBO_ItemOp(lphc, message, lParam);
-
-    case WM_ENABLE:
-        if (lphc->wState & CBF_EDIT)
-            EnableWindow( lphc->hWndEdit, (BOOL)wParam );
-        EnableWindow( lphc->hWndLBox, (BOOL)wParam );
-
-        /* Force the control to repaint when the enabled state changes. */
-        InvalidateRect(lphc->self, NULL, TRUE);
-        return  TRUE;
-
-    case WM_SETREDRAW:
-        if (wParam)
-            lphc->wState &= ~CBF_NOREDRAW;
-        else
-            lphc->wState |= CBF_NOREDRAW;
-
-        if ( lphc->wState & CBF_EDIT )
-            SendMessageW(lphc->hWndEdit, message, wParam, lParam);
-        SendMessageW(lphc->hWndLBox, message, wParam, lParam);
-        return  0;
-
-    case WM_SYSKEYDOWN:
-        if ( KEYDATA_ALT & HIWORD(lParam) )
-            if( wParam == VK_UP || wParam == VK_DOWN )
-                COMBO_FlipListbox( lphc, FALSE, FALSE );
-        return  0;
-
-    case WM_KEYDOWN:
-        if ((wParam == VK_RETURN || wParam == VK_ESCAPE) &&
-                (lphc->wState & CBF_DROPPED))
-        {
-            CBRollUp( lphc, wParam == VK_RETURN, FALSE );
-            return TRUE;
-        }
-        else if ((wParam == VK_F4) && !(lphc->wState & CBF_EUI))
-        {
-            COMBO_FlipListbox( lphc, FALSE, FALSE );
-            return TRUE;
-        }
-        /* fall through */
-    case WM_CHAR:
-    case WM_IME_CHAR:
-        {
-            HWND hwndTarget;
-
-            if ( lphc->wState & CBF_EDIT )
-                hwndTarget = lphc->hWndEdit;
-            else
-                hwndTarget = lphc->hWndLBox;
-
-            return unicode ? SendMessageW(hwndTarget, message, wParam, lParam) :
-                             SendMessageA(hwndTarget, message, wParam, lParam);
-        }
-
-    case WM_LBUTTONDOWN:
-        if ( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self );
-        if ( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
-        return  TRUE;
-
-    case WM_LBUTTONUP:
-        COMBO_LButtonUp( lphc );
-        return  TRUE;
-
-    case WM_MOUSEMOVE:
-        if (lphc->wState & CBF_CAPTURE)
-            COMBO_MouseMove( lphc, wParam, lParam );
-        return  TRUE;
-
-    case WM_MOUSEWHEEL:
-        if (wParam & (MK_SHIFT | MK_CONTROL))
-            return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
-                             DefWindowProcA(hwnd, message, wParam, lParam);
-
-        if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_UP, 0);
-        if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_DOWN, 0);
-        return TRUE;
-
-    /* Combo messages */
-
-    case CB_ADDSTRING:
-        if( unicode )
-        {
-            if( lphc->dwStyle & CBS_LOWERCASE )
-                CharLowerW((LPWSTR)lParam);
-            else if( lphc->dwStyle & CBS_UPPERCASE )
-                CharUpperW((LPWSTR)lParam);
-            return SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
-        }
-        else /* unlike the unicode version, the ansi version does not overwrite
-                the string if converting case */
-        {
-            char *string = NULL;
-            LRESULT ret;
-            if( lphc->dwStyle & CBS_LOWERCASE )
-            {
-                string = strdupA((LPSTR)lParam);
-                CharLowerA(string);
-            }
-
-            else if( lphc->dwStyle & CBS_UPPERCASE )
-            {
-                string = strdupA((LPSTR)lParam);
-                CharUpperA(string);
-            }
-
-            ret = SendMessageA(lphc->hWndLBox, LB_ADDSTRING, 0, string ? (LPARAM)string : lParam);
-            HeapFree(GetProcessHeap(), 0, string);
-            return ret;
-        }
-    case CB_INSERTSTRING:
-        if( unicode )
-        {
-            if( lphc->dwStyle & CBS_LOWERCASE )
-                CharLowerW((LPWSTR)lParam);
-            else if( lphc->dwStyle & CBS_UPPERCASE )
-                CharUpperW((LPWSTR)lParam);
-            return SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
-        }
-        else
-        {
-            if( lphc->dwStyle & CBS_LOWERCASE )
-                CharLowerA((LPSTR)lParam);
-            else if( lphc->dwStyle & CBS_UPPERCASE )
-                CharUpperA((LPSTR)lParam);
-
-            return SendMessageA(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
-        }
-    case CB_DELETESTRING:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0) :
-                         SendMessageA(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
-
-    case CB_SELECTSTRING:
-        return COMBO_SelectString(lphc, (INT)wParam, lParam, unicode);
-
-    case CB_FINDSTRING:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam) :
-                         SendMessageA(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
-
-    case CB_FINDSTRINGEXACT:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam) :
-                         SendMessageA(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
-
-    case CB_SETITEMHEIGHT:
-        return  COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
-
-    case CB_GETITEMHEIGHT:
-        if ((INT)wParam >= 0) /* listbox item */
-            return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
-        return  CBGetTextAreaHeight(hwnd, lphc);
-
-    case CB_RESETCONTENT:
-        SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
-
-        if ((lphc->wState & CBF_EDIT) && CB_HASSTRINGS(lphc))
-        {
-            static const WCHAR empty_stringW[] = { 0 };
-            SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)empty_stringW);
-        }
-        else
-            InvalidateRect(lphc->self, NULL, TRUE);
-        return  TRUE;
-
-    case CB_INITSTORAGE:
-        return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
-
-    case CB_GETHORIZONTALEXTENT:
-        return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
-
-    case CB_SETHORIZONTALEXTENT:
-        return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
-
-    case CB_GETTOPINDEX:
-        return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
-
-    case CB_GETLOCALE:
-        return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
-
-    case CB_SETLOCALE:
-        return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
-
-    case CB_SETDROPPEDWIDTH:
-        if ((CB_GETTYPE(lphc) == CBS_SIMPLE) || (INT)wParam >= 32768)
-            return CB_ERR;
-
-        /* new value must be higher than combobox width */
-        if ((INT)wParam >= lphc->droppedRect.right - lphc->droppedRect.left)
-            lphc->droppedWidth = wParam;
-        else if (wParam)
-            lphc->droppedWidth = 0;
-
-        /* recalculate the combobox area */
-        CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
-
-        /* fall through */
-    case CB_GETDROPPEDWIDTH:
-        if (lphc->droppedWidth)
-            return lphc->droppedWidth;
-        return  lphc->droppedRect.right - lphc->droppedRect.left;
-
-    case CB_GETDROPPEDCONTROLRECT:
-        if (lParam)
-            CBGetDroppedControlRect(lphc, (LPRECT)lParam );
-        return  CB_OKAY;
-
-    case CB_GETDROPPEDSTATE:
-        return (lphc->wState & CBF_DROPPED) != 0;
-
-    case CB_DIR:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_DIR, wParam, lParam) :
-                         SendMessageA(lphc->hWndLBox, LB_DIR, wParam, lParam);
-
-    case CB_SHOWDROPDOWN:
-        if (CB_GETTYPE(lphc) != CBS_SIMPLE)
-        {
-            if (wParam)
-            {
-                if (!(lphc->wState & CBF_DROPPED))
-                    CBDropDown( lphc );
-            }
-            else if (lphc->wState & CBF_DROPPED)
-                CBRollUp( lphc, FALSE, TRUE );
-        }
-        return  TRUE;
-
-    case CB_GETCOUNT:
-        return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
-
-    case CB_GETCURSEL:
-        return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-
-    case CB_SETCURSEL:
-        lParam = SendMessageW(lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
-        if (lParam >= 0)
-            SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
-
-        /* no LBN_SELCHANGE in this case, update manually */
-        CBPaintText(lphc, NULL);
-        lphc->wState &= ~CBF_SELCHANGE;
-        return lParam;
-
-    case CB_GETLBTEXT:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam) :
-                         SendMessageA(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
-
-    case CB_GETLBTEXTLEN:
-        return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0) :
-                         SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
-
-    case CB_GETITEMDATA:
-        return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
-
-    case CB_SETITEMDATA:
-        return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
-
-    case CB_GETEDITSEL:
-        /* Edit checks passed parameters itself */
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
-        return  CB_ERR;
-
-    case CB_SETEDITSEL:
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_SETSEL, (INT)(SHORT)LOWORD(lParam), (INT)(SHORT)HIWORD(lParam) );
-        return  CB_ERR;
-
-    case CB_SETEXTENDEDUI:
-        if (CB_GETTYPE(lphc) == CBS_SIMPLE )
-            return  CB_ERR;
-        if (wParam)
-            lphc->wState |= CBF_EUI;
-        else
-            lphc->wState &= ~CBF_EUI;
-        return  CB_OKAY;
-
-    case CB_GETEXTENDEDUI:
-        return (lphc->wState & CBF_EUI) != 0;
-
-    case CB_GETCOMBOBOXINFO:
-        return COMBO_GetComboBoxInfo(lphc, (COMBOBOXINFO *)lParam);
-
-    case CB_LIMITTEXT:
-        if (lphc->wState & CBF_EDIT)
-            return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
-        return  TRUE;
-
-    default:
-        if (message >= WM_USER)
-            WARN("unknown msg WM_USER+%04x wp=%04lx lp=%08lx\n", message - WM_USER, wParam, lParam );
-        break;
-    }
-    return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
-                   DefWindowProcA(hwnd, message, wParam, lParam);
+    return control_proc_combo(hwnd, message, wParam, lParam, unicode);
 }
 
 /*************************************************************************
  *           GetComboBoxInfo   (USER32.@)
  */
 BOOL WINAPI GetComboBoxInfo(HWND hwndCombo,      /* [in] handle to combo box */
-			    PCOMBOBOXINFO pcbi   /* [in/out] combo box information */)
+                            PCOMBOBOXINFO pcbi   /* [in/out] combo box information */)
 {
     TRACE("(%p, %p)\n", hwndCombo, pcbi);
     return SendMessageW(hwndCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi);
diff --git a/include/wine/controls/combo.c b/include/wine/controls/combo.c
new file mode 100644
index 0000000000..c2a18c9c1f
--- /dev/null
+++ b/include/wine/controls/combo.c
@@ -0,0 +1,2358 @@
+WINE_DEFAULT_DEBUG_CHANNEL(combo);
+
+  /* bits in the dwKeyData */
+#define KEYDATA_ALT             0x2000
+#define KEYDATA_PREVSTATE       0x4000
+
+/*
+ * Additional combo box definitions
+ */
+
+#define CB_NOTIFY( lphc, code ) \
+    (SendMessageW((lphc)->owner, WM_COMMAND, \
+                  MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)), (LPARAM)(lphc)->self))
+
+#define CB_DISABLED( lphc )   (!IsWindowEnabled((lphc)->self))
+#define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
+#define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
+#define CB_HWND( lphc )       ((lphc)->self)
+#define CB_GETTYPE( lphc )    ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
+
+#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
+
+/*
+ * Drawing globals
+ */
+static HBITMAP  hComboBmp = 0;
+static UINT     CBitHeight, CBitWidth;
+
+/*
+ * Look and feel dependent "constants"
+ */
+
+#define COMBO_YBORDERGAP         5
+#define COMBO_XBORDERSIZE()      2
+#define COMBO_YBORDERSIZE()      2
+#define COMBO_EDITBUTTONSPACE()  0
+#define EDIT_CONTROL_PADDING()   1
+
+#ifndef ID_CB_LISTBOX
+#define ID_CB_LISTBOX           1000
+#endif
+
+#ifndef ID_CB_EDIT
+#define ID_CB_EDIT              1001
+#endif
+
+/***********************************************************************
+ *           COMBO_Init
+ *
+ * Load combo button bitmap.
+ */
+static BOOL COMBO_Init(void)
+{
+  HDC           hDC;
+
+  if( hComboBmp ) return TRUE;
+  if( (hDC = CreateCompatibleDC(0)) )
+  {
+    BOOL        bRet = FALSE;
+    if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
+    {
+      BITMAP      bm;
+      HBITMAP     hPrevB;
+      RECT        r;
+
+      GetObjectW( hComboBmp, sizeof(bm), &bm );
+      CBitHeight = bm.bmHeight;
+      CBitWidth  = bm.bmWidth;
+
+      TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
+
+      hPrevB = SelectObject( hDC, hComboBmp);
+      SetRect( &r, 0, 0, CBitWidth, CBitHeight );
+      InvertRect( hDC, &r );
+      SelectObject( hDC, hPrevB );
+      bRet = TRUE;
+    }
+    DeleteDC( hDC );
+    return bRet;
+  }
+  return FALSE;
+}
+
+/***********************************************************************
+ *           COMBO_NCCreate
+ */
+static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
+{
+    HEADCOMBO *lphc;
+
+    if (COMBO_Init() && (lphc = heap_alloc_zero(sizeof(*lphc))))
+    {
+        lphc->self = hwnd;
+        SetWindowLongPtrW( hwnd, 0, (LONG_PTR)lphc );
+
+       /* some braindead apps do try to use scrollbar/border flags */
+
+        lphc->dwStyle = style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
+        SetWindowLongW( hwnd, GWL_STYLE, style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL) );
+
+        /*
+         * We also have to remove the client edge style to make sure
+         * we don't end-up with a non client area.
+         */
+        SetWindowLongW( hwnd, GWL_EXSTYLE,
+                        GetWindowLongW( hwnd, GWL_EXSTYLE ) & ~WS_EX_CLIENTEDGE );
+
+        if( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
+              lphc->dwStyle |= CBS_HASSTRINGS;
+        if( !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
+              lphc->wState |= CBF_NOTIFY;
+
+        TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *           COMBO_NCDestroy
+ */
+static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
+{
+    if (lphc)
+    {
+        TRACE("[%p]: freeing storage\n", lphc->self);
+
+        if ( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
+            DestroyWindow( lphc->hWndLBox );
+
+        SetWindowLongPtrW( lphc->self, 0, 0 );
+        heap_free( lphc );
+    }
+
+    return 0;
+}
+
+/***********************************************************************
+ *           CBGetTextAreaHeight
+ *
+ * This method will calculate the height of the text area of the
+ * combobox.
+ * The height of the text area is set in two ways.
+ * It can be set explicitly through a combobox message or through a
+ * WM_MEASUREITEM callback.
+ * If this is not the case, the height is set to font height + 4px
+ * This height was determined through experimentation.
+ * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
+ */
+static INT CBGetTextAreaHeight(
+  HWND        hwnd,
+  LPHEADCOMBO lphc)
+{
+  INT iTextItemHeight;
+
+  if( lphc->editHeight ) /* explicitly set height */
+  {
+    iTextItemHeight = lphc->editHeight;
+  }
+  else
+  {
+    TEXTMETRICW tm;
+    HDC         hDC       = GetDC(hwnd);
+    HFONT       hPrevFont = 0;
+    INT         baseUnitY;
+
+    if (lphc->hFont)
+      hPrevFont = SelectObject( hDC, lphc->hFont );
+
+    GetTextMetricsW(hDC, &tm);
+
+    baseUnitY = tm.tmHeight;
+
+    if( hPrevFont )
+      SelectObject( hDC, hPrevFont );
+
+    ReleaseDC(hwnd, hDC);
+
+    iTextItemHeight = baseUnitY + 4;
+  }
+
+  /*
+   * Check the ownerdraw case if we haven't asked the parent the size
+   * of the item yet.
+   */
+  if ( CB_OWNERDRAWN(lphc) &&
+       (lphc->wState & CBF_MEASUREITEM) )
+  {
+    MEASUREITEMSTRUCT measureItem;
+    RECT              clientRect;
+    INT               originalItemHeight = iTextItemHeight;
+    UINT id = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
+
+    /*
+     * We use the client rect for the width of the item.
+     */
+    GetClientRect(hwnd, &clientRect);
+
+    lphc->wState &= ~CBF_MEASUREITEM;
+
+    /*
+     * Send a first one to measure the size of the text area
+     */
+    measureItem.CtlType    = ODT_COMBOBOX;
+    measureItem.CtlID      = id;
+    measureItem.itemID     = -1;
+    measureItem.itemWidth  = clientRect.right;
+    measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
+    measureItem.itemData   = 0;
+    SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
+    iTextItemHeight = 6 + measureItem.itemHeight;
+
+    /*
+     * Send a second one in the case of a fixed ownerdraw list to calculate the
+     * size of the list items. (we basically do this on behalf of the listbox)
+     */
+    if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
+    {
+      measureItem.CtlType    = ODT_COMBOBOX;
+      measureItem.CtlID      = id;
+      measureItem.itemID     = 0;
+      measureItem.itemWidth  = clientRect.right;
+      measureItem.itemHeight = originalItemHeight;
+      measureItem.itemData   = 0;
+      SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
+      lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
+    }
+
+    /*
+     * Keep the size for the next time
+     */
+    lphc->editHeight = iTextItemHeight;
+  }
+
+  return iTextItemHeight;
+}
+
+/***********************************************************************
+ *           CBForceDummyResize
+ *
+ * The dummy resize is used for listboxes that have a popup to trigger
+ * a re-arranging of the contents of the combobox and the recalculation
+ * of the size of the "real" control window.
+ */
+static void CBForceDummyResize(
+  LPHEADCOMBO lphc)
+{
+  RECT windowRect;
+  int newComboHeight;
+
+  newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
+
+  GetWindowRect(lphc->self, &windowRect);
+
+  /*
+   * We have to be careful, resizing a combobox also has the meaning that the
+   * dropped rect will be resized. In this case, we want to trigger a resize
+   * to recalculate layout but we don't want to change the dropped rectangle
+   * So, we pass the height of text area of control as the height.
+   * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
+   * message.
+   */
+  SetWindowPos( lphc->self,
+                NULL,
+                0, 0,
+                windowRect.right  - windowRect.left,
+                newComboHeight,
+                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+}
+
+/***********************************************************************
+ *           CBCalcPlacement
+ *
+ * Set up component coordinates given valid lphc->RectCombo.
+ */
+static void CBCalcPlacement(
+  HWND        hwnd,
+  LPHEADCOMBO lphc,
+  LPRECT      lprEdit,
+  LPRECT      lprButton,
+  LPRECT      lprLB)
+{
+  /*
+   * Again, start with the client rectangle.
+   */
+  GetClientRect(hwnd, lprEdit);
+
+  /*
+   * Remove the borders
+   */
+  InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
+
+  /*
+   * Chop off the bottom part to fit with the height of the text area.
+   */
+  lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
+
+  /*
+   * The button starts the same vertical position as the text area.
+   */
+  CopyRect(lprButton, lprEdit);
+
+  /*
+   * If the combobox is "simple" there is no button.
+   */
+  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+    lprButton->left = lprButton->right = lprButton->bottom = 0;
+  else
+  {
+    /*
+     * Let's assume the combobox button is the same width as the
+     * scrollbar button.
+     * size the button horizontally and cut-off the text area.
+     */
+    lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
+    lprEdit->right  = lprButton->left;
+  }
+
+  /*
+   * In the case of a dropdown, there is an additional spacing between the
+   * text area and the button.
+   */
+  if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+  {
+    lprEdit->right -= COMBO_EDITBUTTONSPACE();
+  }
+
+  /*
+   * If we have an edit control, we space it away from the borders slightly.
+   */
+  if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+  {
+    InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
+  }
+
+  /*
+   * Adjust the size of the listbox popup.
+   */
+  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+  {
+    /*
+     * Use the client rectangle to initialize the listbox rectangle
+     */
+    GetClientRect(hwnd, lprLB);
+
+    /*
+     * Then, chop-off the top part.
+     */
+    lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
+  }
+  else
+  {
+    /*
+     * Make sure the dropped width is as large as the combobox itself.
+     */
+    if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
+    {
+      lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
+
+      /*
+       * In the case of a dropdown, the popup listbox is offset to the right.
+       * so, we want to make sure it's flush with the right side of the
+       * combobox
+       */
+      if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+        lprLB->right -= COMBO_EDITBUTTONSPACE();
+    }
+    else
+       lprLB->right = lprLB->left + lphc->droppedWidth;
+  }
+
+  /* don't allow negative window width */
+  if (lprEdit->right < lprEdit->left)
+    lprEdit->right = lprEdit->left;
+
+  TRACE("\ttext\t= (%s)\n", wine_dbgstr_rect(lprEdit));
+
+  TRACE("\tbutton\t= (%s)\n", wine_dbgstr_rect(lprButton));
+
+  TRACE("\tlbox\t= (%s)\n", wine_dbgstr_rect(lprLB));
+}
+
+/***********************************************************************
+ *           CBGetDroppedControlRect
+ */
+static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
+{
+    /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
+     of the combo box and the lower right corner of the listbox */
+
+    GetWindowRect(lphc->self, lpRect);
+
+    lpRect->right =  lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
+    lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
+
+}
+
+/***********************************************************************
+ *           COMBO_Create
+ */
+static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style,
+                             BOOL unicode )
+{
+  static const WCHAR clbName[] = {'C','o','m','b','o','L','B','o','x',0};
+  static const WCHAR editName[] = {'E','d','i','t',0};
+
+#if CONTROL_VERSION==2
+  OpenThemeData( hwnd, WC_COMBOBOXW );
+
+  /*
+   * Per default the comctl32 version of combo shows up to 30 items
+   */
+  lphc->visibleItems = 30;
+#endif
+
+  if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
+  if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+
+  lphc->owner = hwndParent;
+
+  /*
+   * The item height and dropped width are not set when the control
+   * is created.
+   */
+  lphc->droppedWidth = lphc->editHeight = 0;
+
+  /*
+   * The first time we go through, we want to measure the ownerdraw item
+   */
+  lphc->wState |= CBF_MEASUREITEM;
+
+  /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
+
+  if( lphc->owner || !(style & WS_VISIBLE) )
+  {
+      UINT lbeStyle   = 0;
+      UINT lbeExStyle = 0;
+
+      /*
+       * Initialize the dropped rect to the size of the client area of the
+       * control and then, force all the areas of the combobox to be
+       * recalculated.
+       */
+      GetClientRect( hwnd, &lphc->droppedRect );
+      CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
+
+      /*
+       * Adjust the position of the popup listbox if it's necessary
+       */
+      if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
+      {
+        lphc->droppedRect.top   = lphc->textRect.bottom + COMBO_YBORDERSIZE();
+
+        /*
+         * If it's a dropdown, the listbox is offset
+         */
+        if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+          lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
+
+        if (lphc->droppedRect.bottom < lphc->droppedRect.top)
+            lphc->droppedRect.bottom = lphc->droppedRect.top;
+        if (lphc->droppedRect.right < lphc->droppedRect.left)
+            lphc->droppedRect.right = lphc->droppedRect.left;
+        MapWindowPoints( hwnd, 0, (LPPOINT)&lphc->droppedRect, 2 );
+      }
+
+      /* create listbox popup */
+
+      lbeStyle = (LBS_NOTIFY | LBS_COMBOBOX | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
+                 (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
+
+      if( lphc->dwStyle & CBS_SORT )
+        lbeStyle |= LBS_SORT;
+      if( lphc->dwStyle & CBS_HASSTRINGS )
+        lbeStyle |= LBS_HASSTRINGS;
+      if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
+        lbeStyle |= LBS_NOINTEGRALHEIGHT;
+      if( lphc->dwStyle & CBS_DISABLENOSCROLL )
+        lbeStyle |= LBS_DISABLENOSCROLL;
+
+      if( CB_GETTYPE(lphc) == CBS_SIMPLE )      /* child listbox */
+      {
+        lbeStyle |= WS_VISIBLE;
+
+        /*
+         * In win 95 look n feel, the listbox in the simple combobox has
+         * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
+         */
+        lbeStyle   &= ~WS_BORDER;
+        lbeExStyle |= WS_EX_CLIENTEDGE;
+      }
+      else
+      {
+        lbeExStyle |= (WS_EX_TOPMOST | WS_EX_TOOLWINDOW);
+      }
+
+      if (unicode)
+          lphc->hWndLBox = CreateWindowExW(lbeExStyle, clbName, NULL, lbeStyle,
+                                           lphc->droppedRect.left,
+                                           lphc->droppedRect.top,
+                                           lphc->droppedRect.right - lphc->droppedRect.left,
+                                           lphc->droppedRect.bottom - lphc->droppedRect.top,
+                                           hwnd, (HMENU)ID_CB_LISTBOX,
+                                           (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
+      else
+          lphc->hWndLBox = CreateWindowExA(lbeExStyle, "ComboLBox", NULL, lbeStyle,
+                                           lphc->droppedRect.left,
+                                           lphc->droppedRect.top,
+                                           lphc->droppedRect.right - lphc->droppedRect.left,
+                                           lphc->droppedRect.bottom - lphc->droppedRect.top,
+                                           hwnd, (HMENU)ID_CB_LISTBOX,
+                                           (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
+
+      if( lphc->hWndLBox )
+      {
+          BOOL  bEdit = TRUE;
+          lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
+
+          if( lphc->wState & CBF_EDIT )
+          {
+              if( lphc->dwStyle & CBS_OEMCONVERT )
+                  lbeStyle |= ES_OEMCONVERT;
+              if( lphc->dwStyle & CBS_AUTOHSCROLL )
+                  lbeStyle |= ES_AUTOHSCROLL;
+              if( lphc->dwStyle & CBS_LOWERCASE )
+                  lbeStyle |= ES_LOWERCASE;
+              else if( lphc->dwStyle & CBS_UPPERCASE )
+                  lbeStyle |= ES_UPPERCASE;
+
+              if (!IsWindowEnabled(hwnd)) lbeStyle |= WS_DISABLED;
+
+              if (unicode)
+                  lphc->hWndEdit = CreateWindowExW(0, editName, NULL, lbeStyle,
+                                                   lphc->textRect.left, lphc->textRect.top,
+                                                   lphc->textRect.right - lphc->textRect.left,
+                                                   lphc->textRect.bottom - lphc->textRect.top,
+                                                   hwnd, (HMENU)ID_CB_EDIT,
+                                                   (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), NULL );
+              else
+                  lphc->hWndEdit = CreateWindowExA(0, "Edit", NULL, lbeStyle,
+                                                   lphc->textRect.left, lphc->textRect.top,
+                                                   lphc->textRect.right - lphc->textRect.left,
+                                                   lphc->textRect.bottom - lphc->textRect.top,
+                                                   hwnd, (HMENU)ID_CB_EDIT,
+                                                   (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), NULL );
+
+              if( !lphc->hWndEdit )
+                bEdit = FALSE;
+          }
+
+          if( bEdit )
+          {
+            if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+            {
+              /* Now do the trick with parent */
+              SetParent(lphc->hWndLBox, HWND_DESKTOP);
+              /*
+               * If the combo is a dropdown, we must resize the control
+               * to fit only the text area and button. To do this,
+               * we send a dummy resize and the WM_WINDOWPOSCHANGING message
+               * will take care of setting the height for us.
+               */
+              CBForceDummyResize(lphc);
+            }
+
+            TRACE("init done\n");
+            return 0;
+          }
+          ERR("edit control failure.\n");
+      } else ERR("listbox failure.\n");
+  } else ERR("no owner for visible combo.\n");
+
+  /* CreateWindow() will send WM_NCDESTROY to cleanup */
+
+  return -1;
+}
+
+/***********************************************************************
+ *           CBPaintButton
+ *
+ * Paint combo button (normal, pressed, and disabled states).
+ */
+static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
+{
+    UINT buttonState = DFCS_SCROLLCOMBOBOX;
+
+    if( lphc->wState & CBF_NOREDRAW )
+      return;
+
+
+    if (lphc->wState & CBF_BUTTONDOWN)
+        buttonState |= DFCS_PUSHED;
+
+    if (CB_DISABLED(lphc))
+        buttonState |= DFCS_INACTIVE;
+
+    DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
+}
+
+/***********************************************************************
+ *           COMBO_PrepareColors
+ *
+ * This method will sent the appropriate WM_CTLCOLOR message to
+ * prepare and setup the colors for the combo's DC.
+ *
+ * It also returns the brush to use for the background.
+ */
+static HBRUSH COMBO_PrepareColors(
+        LPHEADCOMBO lphc,
+        HDC         hDC)
+{
+    HBRUSH  hBkgBrush;
+
+    /*
+     * Get the background brush for this control.
+     */
+    if (CB_DISABLED(lphc))
+    {
+        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLORSTATIC,
+                (WPARAM)hDC, (LPARAM)lphc->self );
+
+        /*
+         * We have to change the text color since WM_CTLCOLORSTATIC will
+         * set it to the "enabled" color. This is the same behavior as the
+         * edit control
+         */
+        SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
+    }
+    else
+    {
+        /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
+        hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLOREDIT,
+                (WPARAM)hDC, (LPARAM)lphc->self );
+    }
+
+    /*
+     * Catch errors.
+     */
+    if( !hBkgBrush )
+        hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
+
+    return hBkgBrush;
+}
+
+/***********************************************************************
+ *           CBPaintText
+ *
+ * Paint CBS_DROPDOWNLIST text field / update edit control contents.
+ */
+static void CBPaintText(HEADCOMBO *lphc, HDC hdc_paint)
+{
+   RECT rectEdit = lphc->textRect;
+   INT  id, size = 0;
+   LPWSTR pText = NULL;
+
+   TRACE("\n");
+
+   /* follow Windows combobox that sends a bunch of text
+    * inquiries to its listbox while processing WM_PAINT. */
+
+   if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
+   {
+        size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
+        if (size == LB_ERR)
+          FIXME("LB_ERR probably not handled yet\n");
+        if ((pText = heap_alloc((size + 1) * sizeof(WCHAR))))
+        {
+            /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
+           size=SendMessageW(lphc->hWndLBox, LB_GETTEXT, id, (LPARAM)pText);
+            pText[size] = '\0'; /* just in case */
+        } else return;
+   }
+
+   if( lphc->wState & CBF_EDIT )
+   {
+        static const WCHAR empty_stringW[] = { 0 };
+        if( CB_HASSTRINGS(lphc) ) SetWindowTextW( lphc->hWndEdit, pText ? pText : empty_stringW );
+        if( lphc->wState & CBF_FOCUSED )
+           SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, MAXLONG);
+   }
+   else if(!(lphc->wState & CBF_NOREDRAW) && IsWindowVisible( lphc->self ))
+   {
+     /* paint text field ourselves */
+     HDC hdc = hdc_paint ? hdc_paint : GetDC(lphc->self);
+     UINT itemState = ODS_COMBOBOXEDIT;
+     HFONT hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
+     HBRUSH hPrevBrush, hBkgBrush;
+
+     /*
+      * Give ourselves some space.
+      */
+     InflateRect( &rectEdit, -1, -1 );
+
+     hBkgBrush = COMBO_PrepareColors( lphc, hdc );
+     hPrevBrush = SelectObject( hdc, hBkgBrush );
+     FillRect( hdc, &rectEdit, hBkgBrush );
+
+     if( CB_OWNERDRAWN(lphc) )
+     {
+       DRAWITEMSTRUCT dis;
+       HRGN           clipRegion;
+       UINT ctlid = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
+
+       /* setup state for DRAWITEM message. Owner will highlight */
+       if ( (lphc->wState & CBF_FOCUSED) &&
+            !(lphc->wState & CBF_DROPPED) )
+           itemState |= ODS_SELECTED | ODS_FOCUS;
+
+       if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED;
+
+       dis.CtlType      = ODT_COMBOBOX;
+       dis.CtlID        = ctlid;
+       dis.hwndItem     = lphc->self;
+       dis.itemAction   = ODA_DRAWENTIRE;
+       dis.itemID       = id;
+       dis.itemState    = itemState;
+       dis.hDC          = hdc;
+       dis.rcItem       = rectEdit;
+       dis.itemData     = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0);
+
+       /*
+        * Clip the DC and have the parent draw the item.
+        */
+       clipRegion = set_control_clipping( hdc, &rectEdit );
+
+       SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
+
+       SelectClipRgn( hdc, clipRegion );
+       if (clipRegion) DeleteObject( clipRegion );
+     }
+     else
+     {
+       static const WCHAR empty_stringW[] = { 0 };
+
+       if ( (lphc->wState & CBF_FOCUSED) &&
+            !(lphc->wState & CBF_DROPPED) ) {
+
+           /* highlight */
+           FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
+           SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
+           SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
+       }
+
+       ExtTextOutW( hdc,
+                    rectEdit.left + 1,
+                    rectEdit.top + 1,
+                    ETO_OPAQUE | ETO_CLIPPED,
+                    &rectEdit,
+                    pText ? pText : empty_stringW , size, NULL );
+
+       if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
+         DrawFocusRect( hdc, &rectEdit );
+     }
+
+     if( hPrevFont )
+       SelectObject(hdc, hPrevFont );
+
+    if( hPrevBrush )
+        SelectObject( hdc, hPrevBrush );
+
+     if( !hdc_paint )
+       ReleaseDC( lphc->self, hdc );
+   }
+
+    heap_free(pText);
+}
+
+/***********************************************************************
+ *           CBPaintBorder
+ */
+static void CBPaintBorder(
+  HWND            hwnd,
+  const HEADCOMBO *lphc,
+  HDC             hdc)
+{
+  RECT clientRect;
+
+  if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+  {
+    GetClientRect(hwnd, &clientRect);
+  }
+  else
+  {
+    clientRect = lphc->textRect;
+
+    InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+    InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
+  }
+
+  DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
+}
+
+#if CONTROL_VERSION==2
+static LRESULT COMBO_ThemedPaint(HTHEME theme, HEADCOMBO *lphc, HDC hdc)
+{
+    int button_state;
+    RECT frame;
+
+    /* paint border */
+    if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+        GetClientRect(lphc->self, &frame);
+    else
+    {
+        frame = lphc->textRect;
+        InflateRect(&frame, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+        InflateRect(&frame, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
+    }
+
+    DrawThemeBackground(theme, hdc, 0, IsWindowEnabled(lphc->self) ? CBXS_NORMAL : CBXS_DISABLED, &frame, NULL);
+
+    /* Paint button */
+    if (!IsRectEmpty(&lphc->buttonRect))
+    {
+        if (!IsWindowEnabled(lphc->self))
+            button_state = CBXS_DISABLED;
+        else if (lphc->wState & CBF_BUTTONDOWN)
+            button_state = CBXS_PRESSED;
+        else if (lphc->wState & CBF_HOT)
+            button_state = CBXS_HOT;
+        else
+            button_state = CBXS_NORMAL;
+        DrawThemeBackground(theme, hdc, CP_DROPDOWNBUTTON, button_state, &lphc->buttonRect, NULL);
+    }
+
+    if ((lphc->dwStyle & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
+        CBPaintText(lphc, hdc);
+
+    return 0;
+}
+
+/***********************************************************************
+ *           COMBO_Paint
+ */
+static LRESULT COMBO_Paint(HEADCOMBO *lphc, HDC hdc)
+{
+    HBRUSH hPrevBrush, hBkgBrush;
+
+    TRACE("hdc=%p\n", hdc);
+
+    /*
+     * Retrieve the background brush and select it in the
+     * DC.
+     */
+    hBkgBrush = COMBO_PrepareColors(lphc, hdc);
+    hPrevBrush = SelectObject(hdc, hBkgBrush);
+    if (!(lphc->wState & CBF_EDIT))
+        FillRect(hdc, &lphc->textRect, hBkgBrush);
+
+    /*
+     * In non 3.1 look, there is a sunken border on the combobox
+     */
+    CBPaintBorder(lphc->self, lphc, hdc);
+
+    if (!IsRectEmpty(&lphc->buttonRect))
+        CBPaintButton(lphc, hdc, lphc->buttonRect);
+
+    /* paint the edit control padding area */
+    if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+    {
+        RECT rPadEdit = lphc->textRect;
+
+        InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+
+        FrameRect(hdc, &rPadEdit, GetSysColorBrush(COLOR_WINDOW));
+    }
+
+    if (!(lphc->wState & CBF_EDIT))
+        CBPaintText( lphc, hdc );
+
+    if (hPrevBrush)
+        SelectObject( hdc, hPrevBrush );
+
+    return 0;
+}
+#else
+static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
+{
+  PAINTSTRUCT ps;
+  HDC   hDC;
+
+  hDC = (hParamDC) ? hParamDC
+                   : BeginPaint( lphc->self, &ps);
+
+  TRACE("hdc=%p\n", hDC);
+
+  if( hDC && !(lphc->wState & CBF_NOREDRAW) )
+  {
+      HBRUSH    hPrevBrush, hBkgBrush;
+
+      /*
+       * Retrieve the background brush and select it in the
+       * DC.
+       */
+      hBkgBrush = COMBO_PrepareColors(lphc, hDC);
+
+      hPrevBrush = SelectObject( hDC, hBkgBrush );
+      if (!(lphc->wState & CBF_EDIT))
+        FillRect(hDC, &lphc->textRect, hBkgBrush);
+
+      /*
+       * In non 3.1 look, there is a sunken border on the combobox
+       */
+      CBPaintBorder(lphc->self, lphc, hDC);
+
+      if( !IsRectEmpty(&lphc->buttonRect) )
+      {
+        CBPaintButton(lphc, hDC, lphc->buttonRect);
+      }
+
+      /* paint the edit control padding area */
+      if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+      {
+          RECT rPadEdit = lphc->textRect;
+
+          InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+
+          FrameRect( hDC, &rPadEdit, GetSysColorBrush(COLOR_WINDOW) );
+      }
+
+      if( !(lphc->wState & CBF_EDIT) )
+        CBPaintText( lphc, hDC );
+
+      if( hPrevBrush )
+        SelectObject( hDC, hPrevBrush );
+  }
+
+  if( !hParamDC )
+    EndPaint(lphc->self, &ps);
+
+  return 0;
+}
+#endif
+
+/***********************************************************************
+ *           CBUpdateLBox
+ *
+ * Select listbox entry according to the contents of the edit control.
+ */
+static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
+{
+   INT  length, idx;
+   LPWSTR pText = NULL;
+
+   idx = LB_ERR;
+   length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
+
+    if (length > 0)
+        pText = heap_alloc((length + 1) * sizeof(WCHAR));
+
+   TRACE("\t edit text length %i\n", length );
+
+   if( pText )
+   {
+       GetWindowTextW( lphc->hWndEdit, pText, length + 1);
+       idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING, -1, (LPARAM)pText);
+       heap_free( pText );
+   }
+
+   SendMessageW(lphc->hWndLBox, LB_SETCURSEL, bSelect ? idx : -1, 0);
+
+   /* probably superfluous but Windows sends this too */
+   SendMessageW(lphc->hWndLBox, LB_SETCARETINDEX, idx < 0 ? 0 : idx, 0);
+   SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, idx < 0 ? 0 : idx, 0);
+
+   return idx;
+}
+
+/***********************************************************************
+ *           CBUpdateEdit
+ *
+ * Copy a listbox entry to the edit control.
+ */
+static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
+{
+   INT  length;
+   LPWSTR pText = NULL;
+   static const WCHAR empty_stringW[] = { 0 };
+
+   TRACE("\t %i\n", index );
+
+   if( index >= 0 ) /* got an entry */
+   {
+       length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, index, 0);
+       if( length != LB_ERR)
+       {
+           if ((pText = heap_alloc((length + 1) * sizeof(WCHAR))))
+               SendMessageW(lphc->hWndLBox, LB_GETTEXT, index, (LPARAM)pText);
+       }
+   }
+
+   if( CB_HASSTRINGS(lphc) )
+   {
+      lphc->wState |= (CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
+      SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText : (LPARAM)empty_stringW);
+      lphc->wState &= ~(CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
+   }
+
+   if( lphc->wState & CBF_FOCUSED )
+      SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
+
+    heap_free( pText );
+}
+
+/***********************************************************************
+ *           CBDropDown
+ *
+ * Show listbox popup.
+ */
+static void CBDropDown( LPHEADCOMBO lphc )
+{
+    HMONITOR monitor;
+    MONITORINFO mon_info;
+   RECT rect,r;
+   int nItems;
+   int nDroppedHeight;
+
+   TRACE("[%p]: drop down\n", lphc->self);
+
+   CB_NOTIFY( lphc, CBN_DROPDOWN );
+
+   /* set selection */
+
+   lphc->wState |= CBF_DROPPED;
+   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+   {
+       lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
+
+       /* Update edit only if item is in the list */
+       if( !(lphc->wState & CBF_CAPTURE) && lphc->droppedIndex >= 0)
+         CBUpdateEdit( lphc, lphc->droppedIndex );
+   }
+   else
+   {
+       lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+       SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
+                    lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex, 0);
+       SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
+   }
+
+   /* now set popup position */
+   GetWindowRect( lphc->self, &rect );
+
+   /*
+    * If it's a dropdown, the listbox is offset
+    */
+   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+     rect.left += COMBO_EDITBUTTONSPACE();
+
+  /* if the dropped height is greater than the total height of the dropped
+     items list, then force the drop down list height to be the total height
+     of the items in the dropped list */
+
+  /* And Remove any extra space (Best Fit) */
+   nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
+  /* if listbox length has been set directly by its handle */
+   GetWindowRect(lphc->hWndLBox, &r);
+   if (nDroppedHeight < r.bottom - r.top)
+       nDroppedHeight = r.bottom - r.top;
+   nItems = (int)SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+
+   if (nItems > 0)
+   {
+#if CONTROL_VERSION==2
+       int nIHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
+
+       if (lphc->dwStyle & CBS_NOINTEGRALHEIGHT)
+       {
+           nDroppedHeight -= 1;
+       }
+       else
+       {
+           if (nItems > lphc->visibleItems)
+           nItems = lphc->visibleItems;
+           nDroppedHeight = nItems * nIHeight + COMBO_YBORDERSIZE();
+       }
+#else
+      int nHeight;
+      int nIHeight;
+
+      nIHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
+
+      nHeight = nIHeight*nItems;
+
+      if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
+         nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
+#endif
+   }
+
+   r.left = rect.left;
+   r.top = rect.bottom;
+   r.right = r.left + lphc->droppedRect.right - lphc->droppedRect.left;
+   r.bottom = r.top + nDroppedHeight;
+
+   /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
+   monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
+   mon_info.cbSize = sizeof(mon_info);
+   GetMonitorInfoW( monitor, &mon_info );
+
+   if (r.bottom > mon_info.rcWork.bottom)
+   {
+       r.top = max( rect.top - nDroppedHeight, mon_info.rcWork.top );
+       r.bottom = min( r.top + nDroppedHeight, mon_info.rcWork.bottom );
+   }
+
+   SetWindowPos( lphc->hWndLBox, HWND_TOPMOST, r.left, r.top, r.right - r.left, r.bottom - r.top,
+                 SWP_NOACTIVATE | SWP_SHOWWINDOW );
+
+
+   if( !(lphc->wState & CBF_NOREDRAW) )
+     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
+                           RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+
+   EnableWindow( lphc->hWndLBox, TRUE );
+   if (GetCapture() != lphc->self)
+      SetCapture(lphc->hWndLBox);
+}
+
+/***********************************************************************
+ *           CBRollUp
+ *
+ * Hide listbox popup.
+ */
+static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
+{
+   HWND hWnd = lphc->self;
+
+   TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
+         lphc->self, ok, (INT)(lphc->wState & CBF_DROPPED));
+
+   CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
+
+   if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
+   {
+
+       if( lphc->wState & CBF_DROPPED )
+       {
+           RECT rect;
+
+           lphc->wState &= ~CBF_DROPPED;
+           ShowWindow( lphc->hWndLBox, SW_HIDE );
+
+           if(GetCapture() == lphc->hWndLBox)
+           {
+               ReleaseCapture();
+           }
+
+           if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+           {
+               rect = lphc->buttonRect;
+           }
+           else
+           {
+               if( bButton )
+               {
+                 UnionRect( &rect,
+                            &lphc->buttonRect,
+                            &lphc->textRect);
+               }
+               else
+                 rect = lphc->textRect;
+
+               bButton = TRUE;
+           }
+
+           if( bButton && !(lphc->wState & CBF_NOREDRAW) )
+               RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
+                               RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+           CB_NOTIFY( lphc, CBN_CLOSEUP );
+       }
+   }
+}
+
+/***********************************************************************
+ *           COMBO_FlipListbox
+ *
+ * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
+ */
+BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
+{
+   if( lphc->wState & CBF_DROPPED )
+   {
+       CBRollUp( lphc, ok, bRedrawButton );
+       return FALSE;
+   }
+
+   CBDropDown( lphc );
+   return TRUE;
+}
+
+/***********************************************************************
+ *           CBRepaintButton
+ */
+static void CBRepaintButton( LPHEADCOMBO lphc )
+   {
+  InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
+  UpdateWindow(lphc->self);
+}
+
+/***********************************************************************
+ *           COMBO_SetFocus
+ */
+static void COMBO_SetFocus( LPHEADCOMBO lphc )
+{
+   if( !(lphc->wState & CBF_FOCUSED) )
+   {
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+           SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
+
+       /* This is wrong. Message sequences seem to indicate that this
+          is set *after* the notify. */
+       /* lphc->wState |= CBF_FOCUSED;  */
+
+       if( !(lphc->wState & CBF_EDIT) )
+         InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+       CB_NOTIFY( lphc, CBN_SETFOCUS );
+       lphc->wState |= CBF_FOCUSED;
+   }
+}
+
+/***********************************************************************
+ *           COMBO_KillFocus
+ */
+static void COMBO_KillFocus( LPHEADCOMBO lphc )
+{
+   HWND hWnd = lphc->self;
+
+   if( lphc->wState & CBF_FOCUSED )
+   {
+       CBRollUp( lphc, FALSE, TRUE );
+       if( IsWindow( hWnd ) )
+       {
+           if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+               SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
+
+           lphc->wState &= ~CBF_FOCUSED;
+
+           /* redraw text */
+           if( !(lphc->wState & CBF_EDIT) )
+             InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+           CB_NOTIFY( lphc, CBN_KILLFOCUS );
+       }
+   }
+}
+
+/***********************************************************************
+ *           COMBO_Command
+ */
+static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
+{
+   if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
+   {
+       /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
+
+       switch( HIWORD(wParam) >> 8 )
+       {
+           case (EN_SETFOCUS >> 8):
+
+               TRACE("[%p]: edit [%p] got focus\n", lphc->self, lphc->hWndEdit );
+
+                COMBO_SetFocus( lphc );
+                break;
+
+           case (EN_KILLFOCUS >> 8):
+
+               TRACE("[%p]: edit [%p] lost focus\n", lphc->self, lphc->hWndEdit );
+
+                /* NOTE: it seems that Windows' edit control sends an
+                 * undocumented message WM_USER + 0x1B instead of this
+                 * notification (only when it happens to be a part of
+                 * the combo). ?? - AK.
+                 */
+
+                COMBO_KillFocus( lphc );
+                break;
+
+
+           case (EN_CHANGE >> 8):
+               /*
+                * In some circumstances (when the selection of the combobox
+                * is changed for example) we don't want the EN_CHANGE notification
+                * to be forwarded to the parent of the combobox. This code
+                * checks a flag that is set in these occasions and ignores the
+                * notification.
+                */
+                if (lphc->wState & CBF_NOLBSELECT)
+                {
+                  lphc->wState &= ~CBF_NOLBSELECT;
+                }
+                else
+                {
+                  CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
+                }
+
+                if (!(lphc->wState & CBF_NOEDITNOTIFY))
+                  CB_NOTIFY( lphc, CBN_EDITCHANGE );
+                break;
+
+           case (EN_UPDATE >> 8):
+                if (!(lphc->wState & CBF_NOEDITNOTIFY))
+                  CB_NOTIFY( lphc, CBN_EDITUPDATE );
+                break;
+
+           case (EN_ERRSPACE >> 8):
+                CB_NOTIFY( lphc, CBN_ERRSPACE );
+       }
+   }
+   else if( lphc->hWndLBox == hWnd )
+   {
+       switch( (short)HIWORD(wParam) )
+       {
+           case LBN_ERRSPACE:
+                CB_NOTIFY( lphc, CBN_ERRSPACE );
+                break;
+
+           case LBN_DBLCLK:
+                CB_NOTIFY( lphc, CBN_DBLCLK );
+                break;
+
+           case LBN_SELCHANGE:
+           case LBN_SELCANCEL:
+
+                TRACE("[%p]: lbox selection change [%x]\n", lphc->self, lphc->wState );
+
+                /* do not roll up if selection is being tracked
+                 * by arrow keys in the dropdown listbox */
+                if (!(lphc->wState & CBF_NOROLLUP))
+                {
+                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
+                }
+                else lphc->wState &= ~CBF_NOROLLUP;
+
+                CB_NOTIFY( lphc, CBN_SELCHANGE );
+
+                if( HIWORD(wParam) == LBN_SELCHANGE)
+                {
+                   if( lphc->wState & CBF_EDIT )
+                       lphc->wState |= CBF_NOLBSELECT;
+                   CBPaintText( lphc, NULL );
+                }
+                break;
+
+           case LBN_SETFOCUS:
+           case LBN_KILLFOCUS:
+                /* nothing to do here since ComboLBox always resets the focus to its
+                 * combo/edit counterpart */
+                 break;
+       }
+   }
+   return 0;
+}
+
+/***********************************************************************
+ *           COMBO_ItemOp
+ *
+ * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
+ */
+static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
+{
+   HWND hWnd = lphc->self;
+   UINT id = (UINT)GetWindowLongPtrW( hWnd, GWLP_ID );
+
+   TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
+
+   switch( msg )
+   {
+   case WM_DELETEITEM:
+       {
+           DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_DRAWITEM:
+       {
+           DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_COMPAREITEM:
+       {
+           COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_MEASUREITEM:
+       {
+           MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           break;
+       }
+   }
+   return SendMessageW(lphc->owner, msg, id, lParam);
+}
+
+
+/***********************************************************************
+ *           COMBO_GetTextW
+ */
+static LRESULT COMBO_GetTextW( HEADCOMBO *lphc, INT count, LPWSTR buf )
+{
+    INT length;
+
+    if( lphc->wState & CBF_EDIT )
+        return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
+
+    /* get it from the listbox */
+
+    if (!count || !buf) return 0;
+    if( lphc->hWndLBox )
+    {
+        INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+        if (idx == LB_ERR) goto error;
+        length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
+        if (length == LB_ERR) goto error;
+
+        /* 'length' is without the terminating character */
+        if (length >= count)
+        {
+            WCHAR *lpBuffer = heap_alloc((length + 1) * sizeof(WCHAR));
+            if (!lpBuffer) goto error;
+            length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
+
+            /* truncate if buffer is too short */
+            if (length != LB_ERR)
+            {
+                lstrcpynW( buf, lpBuffer, count );
+                length = count;
+            }
+            heap_free( lpBuffer );
+        }
+        else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
+
+        if (length == LB_ERR) return 0;
+        return length;
+    }
+
+ error:  /* error - truncate string, return zero */
+    buf[0] = 0;
+    return 0;
+}
+
+
+/***********************************************************************
+ *           COMBO_GetTextA
+ *
+ * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
+ *       also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
+ */
+static LRESULT COMBO_GetTextA( LPHEADCOMBO lphc, INT count, LPSTR buf )
+{
+    INT length;
+
+    if( lphc->wState & CBF_EDIT )
+        return SendMessageA( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
+
+    /* get it from the listbox */
+
+    if (!count || !buf) return 0;
+    if( lphc->hWndLBox )
+    {
+        INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+        if (idx == LB_ERR) goto error;
+        length = SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
+        if (length == LB_ERR) goto error;
+
+        /* 'length' is without the terminating character */
+        if (length >= count)
+        {
+            LPSTR lpBuffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) );
+            if (!lpBuffer) goto error;
+            length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
+
+            /* truncate if buffer is too short */
+            if (length != LB_ERR)
+            {
+                lstrcpynA( buf, lpBuffer, count );
+                length = count;
+            }
+            HeapFree( GetProcessHeap(), 0, lpBuffer );
+        }
+        else length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
+
+        if (length == LB_ERR) return 0;
+        return length;
+    }
+
+ error:  /* error - truncate string, return zero */
+    buf[0] = 0;
+    return 0;
+}
+
+
+/***********************************************************************
+ *           CBResetPos
+ *
+ * This function sets window positions according to the updated
+ * component placement struct.
+ */
+static void CBResetPos(
+  LPHEADCOMBO lphc,
+  const RECT  *rectEdit,
+  const RECT  *rectLB,
+  BOOL        bRedraw)
+{
+   BOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
+
+   /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
+    * sizing messages */
+
+   if( lphc->wState & CBF_EDIT )
+     SetWindowPos( lphc->hWndEdit, 0,
+                   rectEdit->left, rectEdit->top,
+                   rectEdit->right - rectEdit->left,
+                   rectEdit->bottom - rectEdit->top,
+                       SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   SetWindowPos( lphc->hWndLBox, 0,
+                 rectLB->left, rectLB->top,
+                 rectLB->right - rectLB->left,
+                 rectLB->bottom - rectLB->top,
+                   SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   if( bDrop )
+   {
+       if( lphc->wState & CBF_DROPPED )
+       {
+           lphc->wState &= ~CBF_DROPPED;
+           ShowWindow( lphc->hWndLBox, SW_HIDE );
+       }
+
+       if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
+           RedrawWindow( lphc->self, NULL, 0,
+                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
+   }
+}
+
+
+/***********************************************************************
+ *           COMBO_Size
+ */
+static void COMBO_Size( LPHEADCOMBO lphc )
+{
+  /*
+   * Those controls are always the same height. So we have to make sure
+   * they are not resized to another value.
+   */
+  if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+  {
+    int newComboHeight, curComboHeight, curComboWidth;
+    RECT rc;
+
+    GetWindowRect(lphc->self, &rc);
+    curComboHeight = rc.bottom - rc.top;
+    curComboWidth = rc.right - rc.left;
+    newComboHeight = CBGetTextAreaHeight(lphc->self, lphc) + 2*COMBO_YBORDERSIZE();
+
+    /*
+     * Resizing a combobox has another side effect, it resizes the dropped
+     * rectangle as well. However, it does it only if the new height for the
+     * combobox is more than the height it should have. In other words,
+     * if the application resizing the combobox only had the intention to resize
+     * the actual control, for example, to do the layout of a dialog that is
+     * resized, the height of the dropdown is not changed.
+     */
+    if( curComboHeight > newComboHeight )
+    {
+      TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%d, oldDropTop=%d\n",
+            curComboHeight, newComboHeight, lphc->droppedRect.bottom,
+            lphc->droppedRect.top);
+      lphc->droppedRect.bottom = lphc->droppedRect.top + curComboHeight - newComboHeight;
+    }
+    /*
+     * Restore original height
+     */
+    if( curComboHeight != newComboHeight )
+      SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
+            SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW);
+  }
+
+  CBCalcPlacement(lphc->self,
+                  lphc,
+                  &lphc->textRect,
+                  &lphc->buttonRect,
+                  &lphc->droppedRect);
+
+  CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+}
+
+
+/***********************************************************************
+ *           COMBO_Font
+ */
+static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
+{
+  /*
+   * Set the font
+   */
+  lphc->hFont = hFont;
+
+  /*
+   * Propagate to owned windows.
+   */
+  if( lphc->wState & CBF_EDIT )
+      SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
+  SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
+
+  /*
+   * Redo the layout of the control.
+   */
+  if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+  {
+    CBCalcPlacement(lphc->self,
+                    lphc,
+                    &lphc->textRect,
+                    &lphc->buttonRect,
+                    &lphc->droppedRect);
+
+    CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+  }
+  else
+  {
+    CBForceDummyResize(lphc);
+  }
+}
+
+
+/***********************************************************************
+ *           COMBO_SetItemHeight
+ */
+static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
+{
+   LRESULT      lRet = CB_ERR;
+
+   if( index == -1 ) /* set text field height */
+   {
+       if( height < 32768 )
+       {
+           lphc->editHeight = height + 2;  /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
+
+         /*
+          * Redo the layout of the control.
+          */
+         if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+         {
+           CBCalcPlacement(lphc->self,
+                           lphc,
+                           &lphc->textRect,
+                           &lphc->buttonRect,
+                           &lphc->droppedRect);
+
+           CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+         }
+         else
+         {
+           CBForceDummyResize(lphc);
+         }
+
+           lRet = height;
+       }
+   }
+   else if ( CB_OWNERDRAWN(lphc) )      /* set listbox item height */
+       lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT, index, height);
+   return lRet;
+}
+
+/***********************************************************************
+ *           COMBO_SelectString
+ */
+static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText, BOOL unicode )
+{
+   INT index = unicode ? SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, start, pText) :
+                         SendMessageA(lphc->hWndLBox, LB_SELECTSTRING, start, pText);
+   if( index >= 0 )
+   {
+     if( lphc->wState & CBF_EDIT )
+       CBUpdateEdit( lphc, index );
+     else
+     {
+       InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+     }
+   }
+   return (LRESULT)index;
+}
+
+/***********************************************************************
+ *           COMBO_LButtonDown
+ */
+static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
+{
+   POINT     pt;
+   BOOL      bButton;
+   HWND      hWnd = lphc->self;
+
+   pt.x = (short)LOWORD(lParam);
+   pt.y = (short)HIWORD(lParam);
+   bButton = PtInRect(&lphc->buttonRect, pt);
+
+   if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
+       (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
+   {
+       lphc->wState |= CBF_BUTTONDOWN;
+       if( lphc->wState & CBF_DROPPED )
+       {
+           /* got a click to cancel selection */
+
+           lphc->wState &= ~CBF_BUTTONDOWN;
+           CBRollUp( lphc, TRUE, FALSE );
+           if( !IsWindow( hWnd ) ) return;
+
+           if( lphc->wState & CBF_CAPTURE )
+           {
+               lphc->wState &= ~CBF_CAPTURE;
+               ReleaseCapture();
+           }
+       }
+       else
+       {
+           /* drop down the listbox and start tracking */
+
+           lphc->wState |= CBF_CAPTURE;
+           SetCapture( hWnd );
+           CBDropDown( lphc );
+       }
+       if( bButton ) CBRepaintButton( lphc );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_LButtonUp
+ *
+ * Release capture and stop tracking if needed.
+ */
+static void COMBO_LButtonUp( LPHEADCOMBO lphc )
+{
+   if( lphc->wState & CBF_CAPTURE )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+       {
+           INT index = CBUpdateLBox( lphc, TRUE );
+           /* Update edit only if item is in the list */
+           if(index >= 0)
+           {
+               lphc->wState |= CBF_NOLBSELECT;
+               CBUpdateEdit( lphc, index );
+               lphc->wState &= ~CBF_NOLBSELECT;
+           }
+       }
+       ReleaseCapture();
+       SetCapture(lphc->hWndLBox);
+   }
+
+   if( lphc->wState & CBF_BUTTONDOWN )
+   {
+       lphc->wState &= ~CBF_BUTTONDOWN;
+       CBRepaintButton( lphc );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_MouseMove
+ *
+ * Two things to do - track combo button and release capture when
+ * pointer goes into the listbox.
+ */
+static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
+{
+   POINT  pt;
+   RECT   lbRect;
+
+   pt.x = (short)LOWORD(lParam);
+   pt.y = (short)HIWORD(lParam);
+
+   if( lphc->wState & CBF_BUTTONDOWN )
+   {
+     BOOL bButton;
+
+     bButton = PtInRect(&lphc->buttonRect, pt);
+
+     if( !bButton )
+     {
+       lphc->wState &= ~CBF_BUTTONDOWN;
+       CBRepaintButton( lphc );
+     }
+   }
+
+   GetClientRect( lphc->hWndLBox, &lbRect );
+   MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
+   if( PtInRect(&lbRect, pt) )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       ReleaseCapture();
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
+
+       /* hand over pointer tracking */
+       SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
+   }
+}
+
+static LRESULT COMBO_GetComboBoxInfo(const HEADCOMBO *lphc, COMBOBOXINFO *pcbi)
+{
+    if (!pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
+        return FALSE;
+
+    pcbi->rcItem = lphc->textRect;
+    pcbi->rcButton = lphc->buttonRect;
+    pcbi->stateButton = 0;
+    if (lphc->wState & CBF_BUTTONDOWN)
+        pcbi->stateButton |= STATE_SYSTEM_PRESSED;
+    if (IsRectEmpty(&lphc->buttonRect))
+        pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
+    pcbi->hwndCombo = lphc->self;
+    pcbi->hwndItem = lphc->hWndEdit;
+    pcbi->hwndList = lphc->hWndLBox;
+    return TRUE;
+}
+
+static char *strdupA(LPCSTR str)
+{
+    char *ret;
+    DWORD len;
+
+    if(!str) return NULL;
+
+    len = strlen(str);
+    ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
+    memcpy(ret, str, len + 1);
+    return ret;
+}
+
+/***********************************************************************
+ *           ComboWndProc_common
+ */
+LRESULT control_proc_combo( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+    HEADCOMBO *lphc = (HEADCOMBO *)GetWindowLongPtrW( hwnd, 0 );
+
+    if (!IsWindow(hwnd)) return 0;
+
+    if (lphc || message == WM_NCCREATE)
+    switch(message)
+    {
+
+    /* System messages */
+
+    case WM_NCCREATE:
+    {
+        LONG style = unicode ? ((LPCREATESTRUCTW)lParam)->style :
+                               ((LPCREATESTRUCTA)lParam)->style;
+        return COMBO_NCCreate(hwnd, style);
+    }
+    case WM_NCDESTROY:
+        COMBO_NCDestroy(lphc);
+        break;/* -> DefWindowProc */
+
+    case WM_CREATE:
+    {
+        HWND hwndParent;
+        LONG style;
+        if(unicode)
+        {
+            hwndParent = ((LPCREATESTRUCTW)lParam)->hwndParent;
+            style = ((LPCREATESTRUCTW)lParam)->style;
+        }
+        else
+        {
+            hwndParent = ((LPCREATESTRUCTA)lParam)->hwndParent;
+            style = ((LPCREATESTRUCTA)lParam)->style;
+        }
+        return COMBO_Create(hwnd, lphc, hwndParent, style, unicode);
+    }
+
+    case WM_PRINTCLIENT:
+    case WM_PAINT:
+    {
+#if CONTROL_VERSION==2
+        LRESULT ret = 0;
+        PAINTSTRUCT ps;
+        HDC hdc;
+
+        hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
+
+        if (hdc && !(lphc->wState & CBF_NOREDRAW))
+        {
+            HTHEME theme = GetWindowTheme(hwnd);
+
+            if (theme)
+                ret = COMBO_ThemedPaint(theme, lphc, hdc);
+            else
+                ret = COMBO_Paint(lphc, hdc);
+        }
+
+        if (!wParam)
+            EndPaint(hwnd, &ps);
+
+        return ret;
+#else
+        /* wParam may contain a valid HDC! */
+        return  COMBO_Paint(lphc, (HDC)wParam);
+#endif
+    }
+
+    case WM_ERASEBKGND:
+        /* do all painting in WM_PAINT like Windows does */
+        return 1;
+
+    case WM_GETDLGCODE:
+    {
+        LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
+        if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
+        {
+            int vk = (int)((LPMSG)lParam)->wParam;
+
+            if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
+                result |= DLGC_WANTMESSAGE;
+        }
+        return  result;
+    }
+
+    case WM_SIZE:
+        if (lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
+            COMBO_Size( lphc );
+        return  TRUE;
+
+    case WM_SETFONT:
+        COMBO_Font( lphc, (HFONT)wParam, (BOOL)lParam );
+        return TRUE;
+
+    case WM_GETFONT:
+        return (LRESULT)lphc->hFont;
+
+    case WM_SETFOCUS:
+        if (lphc->wState & CBF_EDIT)
+        {
+            SetFocus( lphc->hWndEdit );
+            /* The first time focus is received, select all the text */
+            if (!(lphc->wState & CBF_BEENFOCUSED))
+            {
+                SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
+                lphc->wState |= CBF_BEENFOCUSED;
+            }
+        }
+        else
+            COMBO_SetFocus( lphc );
+        return  TRUE;
+
+    case WM_KILLFOCUS:
+    {
+#if CONTROL_VERSION==2
+        HWND hwndFocus = (HWND)wParam;
+#else
+        HWND hwndFocus = WIN_GetFullHandle( (HWND)wParam );
+#endif
+        if (!hwndFocus || (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox))
+            COMBO_KillFocus( lphc );
+        return  TRUE;
+    }
+
+    case WM_COMMAND:
+#if CONTROL_VERSION==2
+        return COMBO_Command( lphc, wParam, (HWND)lParam );
+#else
+        return COMBO_Command( lphc, wParam, WIN_GetFullHandle( (HWND)lParam ) );
+#endif
+
+    case WM_GETTEXT:
+        return unicode ? COMBO_GetTextW( lphc, wParam, (LPWSTR)lParam )
+                       : COMBO_GetTextA( lphc, wParam, (LPSTR)lParam );
+
+    case WM_SETTEXT:
+    case WM_GETTEXTLENGTH:
+    case WM_CLEAR:
+        if ((message == WM_GETTEXTLENGTH) && !ISWIN31 && !(lphc->wState & CBF_EDIT))
+        {
+            int j = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+            if (j == -1) return 0;
+            return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, j, 0) :
+                             SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
+        }
+        else if ( lphc->wState & CBF_EDIT )
+        {
+            LRESULT ret;
+            lphc->wState |= CBF_NOEDITNOTIFY;
+            ret = unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
+                            SendMessageA(lphc->hWndEdit, message, wParam, lParam);
+            lphc->wState &= ~CBF_NOEDITNOTIFY;
+            return ret;
+        }
+        else
+            return CB_ERR;
+
+    case WM_CUT:
+    case WM_PASTE:
+    case WM_COPY:
+        if (lphc->wState & CBF_EDIT)
+        {
+            return unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
+                             SendMessageA(lphc->hWndEdit, message, wParam, lParam);
+        }
+        else return  CB_ERR;
+
+    case WM_DRAWITEM:
+    case WM_DELETEITEM:
+    case WM_COMPAREITEM:
+    case WM_MEASUREITEM:
+        return COMBO_ItemOp(lphc, message, lParam);
+
+    case WM_ENABLE:
+        if (lphc->wState & CBF_EDIT)
+            EnableWindow( lphc->hWndEdit, (BOOL)wParam );
+        EnableWindow( lphc->hWndLBox, (BOOL)wParam );
+
+        /* Force the control to repaint when the enabled state changes. */
+        InvalidateRect(lphc->self, NULL, TRUE);
+        return  TRUE;
+
+    case WM_SETREDRAW:
+        if (wParam)
+            lphc->wState &= ~CBF_NOREDRAW;
+        else
+            lphc->wState |= CBF_NOREDRAW;
+
+        if ( lphc->wState & CBF_EDIT )
+            SendMessageW(lphc->hWndEdit, message, wParam, lParam);
+        SendMessageW(lphc->hWndLBox, message, wParam, lParam);
+        return  0;
+
+    case WM_SYSKEYDOWN:
+        if ( KEYDATA_ALT & HIWORD(lParam) )
+            if( wParam == VK_UP || wParam == VK_DOWN )
+                COMBO_FlipListbox( lphc, FALSE, FALSE );
+        return  0;
+
+    case WM_KEYDOWN:
+        if ((wParam == VK_RETURN || wParam == VK_ESCAPE) &&
+                (lphc->wState & CBF_DROPPED))
+        {
+            CBRollUp( lphc, wParam == VK_RETURN, FALSE );
+            return TRUE;
+        }
+        else if ((wParam == VK_F4) && !(lphc->wState & CBF_EUI))
+        {
+            COMBO_FlipListbox( lphc, FALSE, FALSE );
+            return TRUE;
+        }
+        /* fall through */
+    case WM_CHAR:
+    case WM_IME_CHAR:
+        {
+            HWND hwndTarget;
+
+            if ( lphc->wState & CBF_EDIT )
+                hwndTarget = lphc->hWndEdit;
+            else
+                hwndTarget = lphc->hWndLBox;
+
+            return unicode ? SendMessageW(hwndTarget, message, wParam, lParam) :
+                             SendMessageA(hwndTarget, message, wParam, lParam);
+        }
+
+    case WM_LBUTTONDOWN:
+        if ( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self );
+        if ( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
+        return  TRUE;
+
+    case WM_LBUTTONUP:
+        COMBO_LButtonUp( lphc );
+        return  TRUE;
+
+    case WM_MOUSEMOVE:
+    {
+#if CONTROL_VERSION==2
+        if (!IsRectEmpty(&lphc->buttonRect))
+        {
+            POINT pt;
+
+            pt.x = (short)LOWORD(lParam);
+            pt.y = (short)HIWORD(lParam);
+
+            if (PtInRect(&lphc->buttonRect, pt))
+            {
+                if (!(lphc->wState & CBF_HOT))
+                {
+                    lphc->wState |= CBF_HOT;
+                    RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE | RDW_UPDATENOW);
+                }
+            }
+            else if (lphc->wState & CBF_HOT)
+            {
+                lphc->wState &= ~CBF_HOT;
+                RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE | RDW_UPDATENOW);
+            }
+        }
+#endif
+        if (lphc->wState & CBF_CAPTURE)
+            COMBO_MouseMove( lphc, wParam, lParam );
+        return  TRUE;
+    }
+
+    case WM_MOUSEWHEEL:
+        if (wParam & (MK_SHIFT | MK_CONTROL))
+            return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
+                             DefWindowProcA(hwnd, message, wParam, lParam);
+
+        if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_UP, 0);
+        if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_DOWN, 0);
+        return TRUE;
+
+    /* Combo messages */
+
+    case CB_ADDSTRING:
+        if( unicode )
+        {
+            if( lphc->dwStyle & CBS_LOWERCASE )
+                CharLowerW((LPWSTR)lParam);
+            else if( lphc->dwStyle & CBS_UPPERCASE )
+                CharUpperW((LPWSTR)lParam);
+            return SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+        }
+        else /* unlike the unicode version, the ansi version does not overwrite
+                the string if converting case */
+        {
+            char *string = NULL;
+            LRESULT ret;
+            if( lphc->dwStyle & CBS_LOWERCASE )
+            {
+                string = strdupA((LPSTR)lParam);
+                CharLowerA(string);
+            }
+
+            else if( lphc->dwStyle & CBS_UPPERCASE )
+            {
+                string = strdupA((LPSTR)lParam);
+                CharUpperA(string);
+            }
+
+            ret = SendMessageA(lphc->hWndLBox, LB_ADDSTRING, 0, string ? (LPARAM)string : lParam);
+            HeapFree(GetProcessHeap(), 0, string);
+            return ret;
+        }
+    case CB_INSERTSTRING:
+        if( unicode )
+        {
+            if( lphc->dwStyle & CBS_LOWERCASE )
+                CharLowerW((LPWSTR)lParam);
+            else if( lphc->dwStyle & CBS_UPPERCASE )
+                CharUpperW((LPWSTR)lParam);
+            return SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+        }
+        else
+        {
+            if( lphc->dwStyle & CBS_LOWERCASE )
+                CharLowerA((LPSTR)lParam);
+            else if( lphc->dwStyle & CBS_UPPERCASE )
+                CharUpperA((LPSTR)lParam);
+
+            return SendMessageA(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+        }
+    case CB_DELETESTRING:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0) :
+                         SendMessageA(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
+
+    case CB_SELECTSTRING:
+        return COMBO_SelectString(lphc, (INT)wParam, lParam, unicode);
+
+    case CB_FINDSTRING:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam) :
+                         SendMessageA(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
+
+    case CB_FINDSTRINGEXACT:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam) :
+                         SendMessageA(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
+
+    case CB_SETITEMHEIGHT:
+        return  COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
+
+    case CB_GETITEMHEIGHT:
+        if ((INT)wParam >= 0) /* listbox item */
+            return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
+        return  CBGetTextAreaHeight(hwnd, lphc);
+
+    case CB_RESETCONTENT:
+        SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
+
+        if ((lphc->wState & CBF_EDIT) && CB_HASSTRINGS(lphc))
+        {
+            static const WCHAR empty_stringW[] = { 0 };
+            SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)empty_stringW);
+        }
+        else
+            InvalidateRect(lphc->self, NULL, TRUE);
+        return  TRUE;
+
+    case CB_INITSTORAGE:
+        return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
+
+    case CB_GETHORIZONTALEXTENT:
+        return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
+
+    case CB_SETHORIZONTALEXTENT:
+        return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
+
+    case CB_GETTOPINDEX:
+        return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
+
+    case CB_GETLOCALE:
+        return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
+
+    case CB_SETLOCALE:
+        return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
+
+    case CB_SETDROPPEDWIDTH:
+        if ((CB_GETTYPE(lphc) == CBS_SIMPLE) || (INT)wParam >= 32768)
+            return CB_ERR;
+
+        /* new value must be higher than combobox width */
+        if ((INT)wParam >= lphc->droppedRect.right - lphc->droppedRect.left)
+            lphc->droppedWidth = wParam;
+        else if (wParam)
+            lphc->droppedWidth = 0;
+
+        /* recalculate the combobox area */
+        CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
+
+        /* fall through */
+    case CB_GETDROPPEDWIDTH:
+        if (lphc->droppedWidth)
+            return lphc->droppedWidth;
+        return  lphc->droppedRect.right - lphc->droppedRect.left;
+
+    case CB_GETDROPPEDCONTROLRECT:
+        if (lParam)
+            CBGetDroppedControlRect(lphc, (LPRECT)lParam );
+        return  CB_OKAY;
+
+    case CB_GETDROPPEDSTATE:
+        return (lphc->wState & CBF_DROPPED) != 0;
+
+    case CB_DIR:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_DIR, wParam, lParam) :
+                         SendMessageA(lphc->hWndLBox, LB_DIR, wParam, lParam);
+
+    case CB_SHOWDROPDOWN:
+        if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+        {
+            if (wParam)
+            {
+                if (!(lphc->wState & CBF_DROPPED))
+                    CBDropDown( lphc );
+            }
+            else if (lphc->wState & CBF_DROPPED)
+                CBRollUp( lphc, FALSE, TRUE );
+        }
+        return  TRUE;
+
+    case CB_GETCOUNT:
+        return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+
+    case CB_GETCURSEL:
+        return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+    case CB_SETCURSEL:
+        lParam = SendMessageW(lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
+        if (lParam >= 0)
+            SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
+
+        /* no LBN_SELCHANGE in this case, update manually */
+        CBPaintText(lphc, NULL);
+        lphc->wState &= ~CBF_SELCHANGE;
+        return lParam;
+
+    case CB_GETLBTEXT:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam) :
+                         SendMessageA(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
+
+    case CB_GETLBTEXTLEN:
+        return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0) :
+                         SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
+
+    case CB_GETITEMDATA:
+        return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
+
+    case CB_SETITEMDATA:
+        return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
+
+    case CB_GETEDITSEL:
+        /* Edit checks passed parameters itself */
+        if (lphc->wState & CBF_EDIT)
+            return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
+        return  CB_ERR;
+
+    case CB_SETEDITSEL:
+        if (lphc->wState & CBF_EDIT)
+            return SendMessageW(lphc->hWndEdit, EM_SETSEL, (INT)(SHORT)LOWORD(lParam), (INT)(SHORT)HIWORD(lParam) );
+        return  CB_ERR;
+
+    case CB_SETEXTENDEDUI:
+        if (CB_GETTYPE(lphc) == CBS_SIMPLE )
+            return  CB_ERR;
+        if (wParam)
+            lphc->wState |= CBF_EUI;
+        else
+            lphc->wState &= ~CBF_EUI;
+        return  CB_OKAY;
+
+    case CB_GETEXTENDEDUI:
+        return (lphc->wState & CBF_EUI) != 0;
+
+    case CB_GETCOMBOBOXINFO:
+        return COMBO_GetComboBoxInfo(lphc, (COMBOBOXINFO *)lParam);
+
+    case CB_LIMITTEXT:
+        if (lphc->wState & CBF_EDIT)
+            return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
+        return  TRUE;
+
+#if CONTROL_VERSION==2
+    case WM_DESTROY:
+    {
+        HTHEME theme = GetWindowTheme( hwnd );
+        CloseThemeData( theme );
+        break;
+    }
+
+    case WM_THEMECHANGED:
+    {
+        HTHEME theme = GetWindowTheme( hwnd );
+        CloseThemeData( theme );
+        OpenThemeData( hwnd, WC_COMBOBOXW );
+        break;
+    }
+
+    case CB_GETMINVISIBLE:
+        return lphc->visibleItems;
+
+    case CB_SETMINVISIBLE:
+        lphc->visibleItems = (INT)wParam;
+        return TRUE;
+
+#endif
+
+    default:
+        if (message >= WM_USER)
+            WARN("unknown msg WM_USER+%04x wp=%04lx lp=%08lx\n", message - WM_USER, wParam, lParam );
+        break;
+    }
+    return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
+                   DefWindowProcA(hwnd, message, wParam, lParam);
+}
-- 
2.19.1




More information about the wine-devel mailing list