updated listbox control from wine 0.9.2
[reactos.git] / reactos / lib / user32 / controls / combo.c
index 0eea751..54aa7ee 100644 (file)
@@ -1,20 +1,30 @@
 /*
  * Combo controls
- * 
+ *
  * Copyright 1997 Alex Korobka
- * 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
  * FIXME: roll up in Netscape 3.01.
  */
 
-#include <string.h>
-
-#include <windows.h>
-#include <user32/sysmetr.h>
-#include <user32/win.h>
+#include <user32.h>
+#define NDEBUG
+#include <debug.h>
 
-#include <user32/heapdup.h>
-#include <user32/combo.h>
-#include <user32/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(combo);
 
   /* bits in the dwKeyData */
 #define KEYDATA_ALT             0x2000
  * Additional combo box definitions
  */
 
-#define CB_GETPTR( wnd )      (*(LPHEADCOMBO*)((wnd)->wExtra))
 #define CB_NOTIFY( lphc, code ) \
-       (SendMessageA( (lphc)->owner, WM_COMMAND, \
-                        MAKEWPARAM((lphc)->self->wIDmenu, (code)), (LPARAM)(lphc)->self->hwndSelf))
-#define CB_GETEDITTEXTLENGTH( lphc ) \
-       (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
+    (SendMessageW((lphc)->owner, WM_COMMAND, \
+                  MAKEWPARAM(GetWindowLongA((lphc)->self,GWL_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 ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
 
+/*
+ * Drawing globals
+ */
 static HBITMAP         hComboBmp = 0;
-static UINT            CBitHeight, CBitWidth;
-static UINT            CBitOffset = 8;
+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
+
+static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+
+/*********************************************************************
+ * combo class descriptor
+ */
+const struct builtin_class_descr COMBO_builtin_class =
+{
+#ifdef __REACTOS__
+    L"ComboBox",           /* name */
+    CS_PARENTDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, /* style  */
+    (WNDPROC) ComboWndProcW,        /* procW */
+    (WNDPROC) ComboWndProcA,        /* procA */
+    sizeof(HEADCOMBO *),  /* extra */
+    (LPCWSTR) IDC_ARROW,            /* cursor */
+    0                     /* brush */
+#else
+    "ComboBox",           /* name */
+    CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, /* style  */
+    ComboWndProcA,        /* procA */
+    ComboWndProcW,        /* procW */
+    sizeof(HEADCOMBO *),  /* extra */
+    IDC_ARROW,            /* cursor */
+    0                     /* brush */
+#endif
+};
+
 
 /***********************************************************************
  *           COMBO_Init
  *
  * Load combo button bitmap.
  */
-WINBOOL COMBO_Init(void)
+static BOOL COMBO_Init()
 {
   HDC          hDC;
-  
+
   if( hComboBmp ) return TRUE;
   if( (hDC = CreateCompatibleDC(0)) )
   {
-    WINBOOL    bRet = FALSE;
-    if( (hComboBmp = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO))) )
+    BOOL       bRet = FALSE;
+    if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
     {
       BITMAP      bm;
       HBITMAP     hPrevB;
       RECT        r;
 
-      GetObjectA( hComboBmp, sizeof(bm), &bm );
+      GetObjectW( hComboBmp, sizeof(bm), &bm );
       CBitHeight = bm.bmHeight;
       CBitWidth  = bm.bmWidth;
 
-      DPRINT( "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
+      TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
 
       hPrevB = SelectObject( hDC, hComboBmp);
       SetRect( &r, 0, 0, CBitWidth, CBitHeight );
@@ -75,34 +129,36 @@ WINBOOL COMBO_Init(void)
 /***********************************************************************
  *           COMBO_NCCreate
  */
-static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
+static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
 {
-   LPHEADCOMBO                 lphc;
+    LPHEADCOMBO lphc;
 
-   if ( wnd && COMBO_Init() &&
-      (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
-   {
-       LPCREATESTRUCT     lpcs = (CREATESTRUCT*)lParam;
-       
-       memset( lphc, 0, sizeof(HEADCOMBO) );
-       *(LPHEADCOMBO*)wnd->wExtra = lphc;
+    if (COMBO_Init() && (lphc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEADCOMBO))) )
+    {
+        lphc->self = hwnd;
+        SetWindowLongA( hwnd, 0, (LONG)lphc );
 
        /* some braindead apps do try to use scrollbar/border flags */
 
-       lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
-       wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
+       lphc->dwStyle = style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
+        SetWindowLongA( 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.
+        */
+        SetWindowLongA( hwnd, GWL_EXSTYLE,
+                        GetWindowLongA( hwnd, GWL_EXSTYLE ) & ~WS_EX_CLIENTEDGE );
 
-       if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
+       if( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
               lphc->dwStyle |= CBS_HASSTRINGS;
-       if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
+       if( !(GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
              lphc->wState |= CBF_NOTIFY;
 
-       DPRINT( "[0x%08x], style = %08x\n", 
-                    (UINT)lphc, lphc->dwStyle );
-
-       return (LRESULT)(UINT)wnd->hwndSelf; 
+        TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
+        return TRUE;
     }
-    return (LRESULT)FALSE;
+    return FALSE;
 }
 
 /***********************************************************************
@@ -113,135 +169,265 @@ static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
 
    if( lphc )
    {
-       WND*            wnd = lphc->self;
-
-       DPRINT("[%04x]: freeing storage\n", CB_HWND(lphc));
+       TRACE("[%p]: freeing storage\n", lphc->self);
 
-       if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox ) 
+       if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
           DestroyWindow( lphc->hWndLBox );
 
+       SetWindowLongA( lphc->self, 0, 0 );
        HeapFree( GetProcessHeap(), 0, lphc );
-       wnd->wExtra[0] = 0;
    }
    return 0;
 }
 
 /***********************************************************************
- *           CBGetDefaultTextHeight
- */
-static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE lpSize )
-{
-   if( lphc->editHeight ) /* explicitly set height */
-       lpSize->cy = lphc->editHeight;
-   else
-   {
-       HDC    hDC = GetDC( lphc->self->hwndSelf );
-       HFONT  hPrevFont = 0;
-
-       if( lphc->hFont ) hPrevFont = SelectObject( hDC, lphc->hFont );
-
-       GetTextExtentPointA( hDC, "0", 1, lpSize);
-
-       lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER;
-
-       if( hPrevFont ) SelectObject( hDC, hPrevFont );
-       ReleaseDC( lphc->self->hwndSelf, hDC );
-   }
-   lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left;
-}
-
-
-/***********************************************************************
- *           CBCalcPlacement
+ *           CBGetTextAreaHeight
  *
- * Set up component coordinates given valid lphc->RectCombo.
+ * 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 13 dialog units.
+ * This height was determined through experimentation.
  */
-static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT lprEdit, 
-                            LPRECT lprButton, LPRECT lprLB )
+static INT CBGetTextAreaHeight(
+  HWND        hwnd,
+  LPHEADCOMBO lphc)
 {
-   RECT        rect = lphc->RectCombo;
-   SIZE        size;
+  INT iTextItemHeight;
 
-   /* get combo height and width */
+  if( lphc->editHeight ) /* explicitly set height */
+  {
+    iTextItemHeight = lphc->editHeight;
+  }
+  else
+  {
+    TEXTMETRICW tm;
+    HDC         hDC       = GetDC(hwnd);
+    HFONT       hPrevFont = 0;
+    INT         baseUnitY;
 
-   if( CB_OWNERDRAWN(lphc) )
-   {
-       UINT    u = lphc->RectEdit.bottom - lphc->RectEdit.top;
+    if (lphc->hFont)
+      hPrevFont = SelectObject( hDC, lphc->hFont );
 
-       if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
-       {
-          MEASUREITEMSTRUCT        mi;
+    GetTextMetricsW(hDC, &tm);
 
-          /* calculate defaults before sending WM_MEASUREITEM */
+    baseUnitY = tm.tmHeight;
 
-          CBGetDefaultTextHeight( lphc, &size );
+    if( hPrevFont )
+      SelectObject( hDC, hPrevFont );
 
-          lphc->wState &= ~CBF_MEASUREITEM;
+    ReleaseDC(hwnd, hDC);
 
-          mi.CtlType = ODT_COMBOBOX;
-          mi.CtlID   = lphc->self->wIDmenu;
-          mi.itemID  = -1;
-          mi.itemWidth  = size.cx;
-          mi.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
-          mi.itemData   = 0;
-          SendMessageA(lphc->owner, WM_MEASUREITEM, 
-                               (WPARAM)mi.CtlID, (LPARAM)&mi);
-          u = 6 + (UINT)mi.itemHeight;
-       }
-       else
-          size.cx = rect.right - rect.left;
-       size.cy = u;
-   }
-   else 
-       CBGetDefaultTextHeight( lphc, &size );
+    iTextItemHeight = ((13 * baseUnitY) / 8);
 
-   /* calculate text and button placement */
+    /*
+     * This "formula" calculates the height of the complete control.
+     * To calculate the height of the text area, we have to remove the
+     * borders.
+     */
+    iTextItemHeight -= 2*COMBO_YBORDERSIZE();
+  }
 
-   lprEdit->left = lprEdit->top = lprButton->top = 0;
-   if( CB_GETTYPE(lphc) == CBS_SIMPLE )        /* no button */
-       lprButton->left = lprButton->right = lprButton->bottom = 0;
-   else
-   {
-       INT     i = size.cx - CBitWidth - 10;   /* seems ok */
+  /*
+   * 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 = GetWindowLongA( lphc->self, GWL_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;
+    }
 
-       lprButton->right = size.cx;
-       lprButton->left = (INT)i;
-       lprButton->bottom = lprButton->top + size.cy;
+    /*
+     * Keep the size for the next time
+     */
+    lphc->editHeight = iTextItemHeight;
+  }
 
-       if( i < 0 ) size.cx = 0;
-       else size.cx = i;
-   }
+  return iTextItemHeight;
+}
 
-   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
-   {
-       size.cx -= CBitOffset;
-       if( size.cx < 0 ) size.cx = 0;
-   }
+/***********************************************************************
+ *           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 );
+}
 
-   lprEdit->right = size.cx; lprEdit->bottom = size.cy;
+/***********************************************************************
+ *           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;
+  }
 
-   /* listbox placement */
+  /*
+   * 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();
+  }
 
-   lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
-   lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
-   lprLB->right = rect.right - rect.left;
-   lprLB->bottom = rect.bottom - rect.top;
+  /*
+   * 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());
+  }
 
-   if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
+  /*
+   * 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;
+  }
 
-   DPRINT("[%04x]: (%i,%i-%i,%i) placement\n",
-               CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top, 
-               lphc->RectCombo.right, lphc->RectCombo.bottom);
-
-   DPRINT("\ttext\t= (%i,%i-%i,%i)\n",
-               lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
+  TRACE("\ttext\t= (%ld,%ld-%ld,%ld)\n",
+       lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
 
-   DPRINT("\tbutton\t= (%i,%i-%i,%i)\n",
-               lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
+  TRACE("\tbutton\t= (%ld,%ld-%ld,%ld)\n",
+       lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
 
-   DPRINT("\tlbox\t= (%i,%i-%i,%i)\n", 
-               lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
+  TRACE("\tlbox\t= (%ld,%ld-%ld,%ld)\n",
+       lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
 }
 
 /***********************************************************************
@@ -249,48 +435,121 @@ static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT lprEdit,
  */
 static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
 {
-   lpRect->left = lphc->RectCombo.left +
-                      (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
-   lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
-                                             SYSMETRICS_CYBORDER;
-   lpRect->right = lphc->RectCombo.right;
-   lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
+    /* 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_WindowPosChanging
+ */
+static LRESULT COMBO_WindowPosChanging(
+  HWND        hwnd,
+  LPHEADCOMBO lphc,
+  WINDOWPOS*  posChanging)
+{
+  /*
+   * We need to override the WM_WINDOWPOSCHANGING method to handle all
+   * the non-simple comboboxes. The problem is that those controls are
+   * always the same height. We have to make sure they are not resized
+   * to another value.
+   */
+  if ( ( CB_GETTYPE(lphc) != CBS_SIMPLE ) &&
+       ((posChanging->flags & SWP_NOSIZE) == 0) )
+  {
+    int newComboHeight;
+
+    newComboHeight = CBGetTextAreaHeight(hwnd,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 different from 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 (posChanging->cy != newComboHeight)
+    {
+       TRACE("posChanging->cy=%d, newComboHeight=%d, oldbot=%ld, oldtop=%ld\n",
+             posChanging->cy, newComboHeight, lphc->droppedRect.bottom,
+             lphc->droppedRect.top);
+      lphc->droppedRect.bottom = lphc->droppedRect.top + posChanging->cy - newComboHeight;
+
+      posChanging->cy = newComboHeight;
+    }
+  }
+
+  return 0;
 }
 
 /***********************************************************************
  *           COMBO_Create
  */
-LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
+static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style,
+                             BOOL unicode )
 {
-  static char clbName[] = "ComboLBox";
-  static char editName[] = "Edit";
+  static const WCHAR clbName[] = {'C','o','m','b','o','L','B','o','x',0};
+  static const WCHAR editName[] = {'E','d','i','t',0};
 
-  LPCREATESTRUCT  lpcs = (CREATESTRUCT*)lParam;
-  
   if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
-  else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+  if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+
+  lphc->owner = hwndParent;
 
-  lphc->self  = wnd;
-  lphc->owner = lpcs->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 || !(lpcs->style & WS_VISIBLE) )
+  if( lphc->owner || !(style & WS_VISIBLE) )
   {
-      UINT     lbeStyle;
-      RECT     editRect, btnRect, lbRect;
+      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();
 
-      GetWindowRect( wnd->hwndSelf, &lphc->RectCombo );
+       /*
+        * If it's a dropdown, the listbox is offset
+        */
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+         lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
 
-      lphc->wState |= CBF_MEASUREITEM;
-      CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
-      lphc->RectButton = btnRect;
-      lphc->droppedWidth = lphc->editHeight = 0;
+       ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect);
+       ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect.right);
+      }
 
       /* create listbox popup */
 
-      lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) | 
-                 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
+      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;
@@ -300,32 +559,46 @@ LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
        lbeStyle |= LBS_NOINTEGRALHEIGHT;
       if( lphc->dwStyle & CBS_DISABLENOSCROLL )
        lbeStyle |= LBS_DISABLENOSCROLL;
-  
+
       if( CB_GETTYPE(lphc) == CBS_SIMPLE )     /* child listbox */
-       lbeStyle |= WS_CHILD | WS_VISIBLE;
-      else                                     /* popup listbox */
       {
-       lbeStyle |= WS_POPUP;
-       OffsetRect( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
+       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);
       }
 
-     /* Dropdown ComboLBox is not a child window and we cannot pass 
-      * ID_CB_LISTBOX directly because it will be treated as a menu handle.
-      */
+      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)GetWindowLongA( hwnd, GWL_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)GetWindowLongA( hwnd, GWL_HINSTANCE ), lphc );
 
-      lphc->hWndLBox = CreateWindowExA( 0, clbName, NULL, lbeStyle, 
-                       lbRect.left + SYSMETRICS_CXBORDER, 
-                       lbRect.top + SYSMETRICS_CYBORDER, 
-                       lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER, 
-                       lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER, 
-                       lphc->self->hwndSelf, 
-                      (lphc->dwStyle & CBS_DROPDOWN)? (HMENU)0 : (HMENU)ID_CB_LISTBOX,
-                       lphc->self->hInstance, (LPVOID)lphc );
       if( lphc->hWndLBox )
       {
-         WINBOOL       bEdit = TRUE;
-         lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
-         if( lphc->wState & CBF_EDIT ) 
+         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;
@@ -335,31 +608,49 @@ LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
                  lbeStyle |= ES_LOWERCASE;
              else if( lphc->dwStyle & CBS_UPPERCASE )
                  lbeStyle |= ES_UPPERCASE;
-             lphc->hWndEdit = CreateWindowExA( 0, editName, NULL, lbeStyle,
-                       editRect.left, editRect.top, editRect.right - editRect.left,
-                       editRect.bottom - editRect.top, lphc->self->hwndSelf, 
-                       (HMENU)ID_CB_EDIT, lphc->self->hInstance, NULL );
-             if( !lphc->hWndEdit ) bEdit = FALSE;
-         } 
+
+              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)GetWindowLongA( hwnd, GWL_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)GetWindowLongA( hwnd, GWL_HINSTANCE ), NULL );
+
+             if( !lphc->hWndEdit )
+               bEdit = FALSE;
+         }
 
           if( bEdit )
          {
-             lphc->RectEdit = editRect;
-             if( CB_GETTYPE(lphc) != CBS_SIMPLE )
-             {
-               lphc->wState |= CBF_NORESIZE;
-               SetWindowPos( wnd->hwndSelf, 0, 0, 0, 
-                               lphc->RectCombo.right - lphc->RectCombo.left,
-                               lphc->RectEdit.bottom - lphc->RectEdit.top,
-                               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
-               lphc->wState &= ~CBF_NORESIZE;
-             }
-             DPRINT("init done\n");
-             return (LRESULT)wnd->hwndSelf;
+           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;
          }
-         DPRINT("edit control failure.\n");
-      } else DPRINT("listbox failure.\n");
-  } else DPRINT("no owner for visible combo.\n");
+         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 */
 
@@ -371,48 +662,21 @@ LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
  *
  * Paint combo button (normal, pressed, and disabled states).
  */
-static void CBPaintButton(LPHEADCOMBO lphc, HDC hdc)
+static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
 {
-    RECT       r;
-    UINT       x, y;
-    WINBOOL    bWINBOOL;
-    HDC       hMemDC;
-    HBRUSH    hPrevBrush;
-    COLORREF    oldTextColor, oldBkColor;
-
-    if( lphc->wState & CBF_NOREDRAW ) return;
+    UINT buttonState = DFCS_SCROLLCOMBOBOX;
 
-    hPrevBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
-    r = lphc->RectButton;
-
-    Rectangle(hdc, r.left, r.top, r.right, r.bottom );
-    if( (bWINBOOL = lphc->wState & CBF_BUTTONDOWN) )
-    {
-       DrawEdge( hdc, &r, EDGE_SUNKEN, BF_RECT );
-       OffsetRect( &r, 1, 1 );
-    } else {
-        r.top++, r.left++;
-       DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
-       r.top--, r.left--;
-    }
+    if( lphc->wState & CBF_NOREDRAW )
+      return;
 
-    InflateRect( &r, -1, -1 ); 
 
-    x = (r.left + r.right - CBitWidth) >> 1;
-    y = (r.top + r.bottom - CBitHeight) >> 1;
+    if (lphc->wState & CBF_BUTTONDOWN)
+       buttonState |= DFCS_PUSHED;
 
-    InflateRect( &r, -3, -3 );
+    if (CB_DISABLED(lphc))
+       buttonState |= DFCS_INACTIVE;
 
-    hMemDC = CreateCompatibleDC( hdc );
-    SelectObject( hMemDC, hComboBmp );
-    oldTextColor = SetTextColor( hdc, GetSysColor(COLOR_BTNFACE) );
-    oldBkColor = SetBkColor( hdc, CB_DISABLED(lphc) ? RGB(128,128,128) :
-                              RGB(0,0,0) );
-    BitBlt( hdc, x, y, 8, 8, hMemDC, 0, 0, SRCCOPY );
-    SetBkColor( hdc, oldBkColor );
-    SetTextColor( hdc, oldTextColor );
-    DeleteDC( hMemDC );
-    SelectObject( hdc, hPrevBrush );
+    DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
 }
 
 /***********************************************************************
@@ -420,111 +684,242 @@ static void CBPaintButton(LPHEADCOMBO lphc, HDC hdc)
  *
  * Paint CBS_DROPDOWNLIST text field / update edit control contents.
  */
-static void CBPaintText(LPHEADCOMBO lphc, HDC hdc)
+static void CBPaintText(
+  LPHEADCOMBO lphc,
+  HDC         hdc,
+  RECT        rectEdit)
 {
    INT id, size = 0;
-   LPSTR       pText = NULL;
+   LPWSTR pText = NULL;
 
    if( lphc->wState & CBF_NOREDRAW ) return;
 
-   /* follow Windows combobox that sends a bunch of text 
+   TRACE("\n");
+
+   /* follow Windows combobox that sends a bunch of text
     * inquiries to its listbox while processing WM_PAINT. */
 
-   if( (id = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
+   if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
    {
-        size = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
-        if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
+        size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
+       if (size == LB_ERR)
+         FIXME("LB_ERR probably not handled yet\n");
+        if( (pText = HeapAlloc( GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR))) )
        {
-           SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText );
+            /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
+           size=SendMessageW(lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText);
            pText[size] = '\0'; /* just in case */
        } else return;
    }
+   else
+       if( !CB_OWNERDRAWN(lphc) )
+          return;
 
    if( lphc->wState & CBF_EDIT )
    {
-       if( CB_HASSTRINGS(lphc) ) SetWindowTextA( lphc->hWndEdit, pText ? pText : "" );
-       if( lphc->wState & CBF_FOCUSED ) 
-           SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
+        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, (LPARAM)(-1));
    }
    else /* paint text field ourselves */
    {
-        HBRUSH hPrevBrush = 0;
-       HDC      hDC = hdc;
+     UINT      itemState = ODS_COMBOBOXEDIT;
+     HFONT     hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
 
-       if( !hDC ) 
-       {
-           if ((hDC = GetDC(lphc->self->hwndSelf)))
-            {
-                HBRUSH hBrush = (HBRUSH)SendMessageA( lphc->owner,
-                                                  WM_CTLCOLORLISTBOX, 
-                                                  (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf );
-                hPrevBrush = SelectObject( hDC, 
-                           (hBrush) ? hBrush : GetStockObject(WHITE_BRUSH) );
-            }
-       }
-       if( hDC )
-       {
-           RECT        rect;
-           UINT        itemState;
-           HFONT       hPrevFont = (lphc->hFont) ? SelectObject(hDC, lphc->hFont) : 0;
-
-           PatBlt( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
-                          (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
-                          (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
-                          (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
-           InflateRect( &rect, -1, -1 );
-
-           if( lphc->wState & CBF_FOCUSED && 
-               !(lphc->wState & CBF_DROPPED) )
-           {
-               /* highlight */
+     /*
+      * Give ourselves some space.
+      */
+     InflateRect( &rectEdit, -1, -1 );
+
+     if( CB_OWNERDRAWN(lphc) )
+     {
+       DRAWITEMSTRUCT dis;
+       HRGN           clipRegion;
+       UINT ctlid = GetWindowLongA( lphc->self, GWL_ID );
+
+       /* setup state for DRAWITEM message. Owner will highlight */
+       if ( (lphc->wState & CBF_FOCUSED) &&
+           !(lphc->wState & CBF_DROPPED) )
+          itemState |= ODS_SELECTED | ODS_FOCUS;
+
+       /*
+       * Save the current clip region.
+       * To retrieve the clip region, we need to create one "dummy"
+       * clip region.
+       */
+       clipRegion = CreateRectRgnIndirect(&rectEdit);
+
+       if (GetClipRgn(hdc, clipRegion)!=1)
+       {
+        DeleteObject(clipRegion);
+        clipRegion=NULL;
+       }
 
-               FillRect( hDC, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
-                SetBkColor( hDC, GetSysColor( COLOR_HIGHLIGHT ) );
-                SetTextColor( hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
-               itemState = ODS_SELECTED | ODS_FOCUS;
-           } else itemState = 0;
+       if (!IsWindowEnabled(lphc->self) & WS_DISABLED) 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,
+                                       (WPARAM)id, 0 );
+
+       /*
+       * Clip the DC and have the parent draw the item.
+       */
+       IntersectClipRect(hdc,
+                        rectEdit.left,  rectEdit.top,
+                        rectEdit.right, rectEdit.bottom);
+
+       SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
+
+       /*
+       * Reset the clipping region.
+       */
+       SelectClipRgn(hdc, 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 ) );
+       }
 
-           if( CB_OWNERDRAWN(lphc) )
-           {
-               DRAWITEMSTRUCT dis;
-
-               if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
-
-               dis.CtlType     = ODT_COMBOBOX;
-               dis.CtlID       = lphc->self->wIDmenu;
-               dis.hwndItem    = lphc->self->hwndSelf;
-               dis.itemAction  = ODA_DRAWENTIRE;
-               dis.itemID      = id;
-               dis.itemState   = itemState;
-               dis.hDC         = hDC;
-               dis.rcItem      = rect;
-               dis.itemData    = SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, 
-                                                                 (WPARAM)id, 0 );
-               SendMessageA( lphc->owner, WM_DRAWITEM, 
-                               lphc->self->wIDmenu, (LPARAM)&dis );
-           }
-           else
-           {
-               ExtTextOutA( hDC, rect.left + 1, rect.top + 1,
-                               ETO_OPAQUE | ETO_CLIPPED, &rect,
-                               pText ? pText : "" , size, NULL );
-               if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
-                   DrawFocusRect( hDC, &rect );
-           }
+       ExtTextOutW( hdc,
+                   rectEdit.left + 1,
+                   rectEdit.top + 1,
+                   ETO_OPAQUE | ETO_CLIPPED,
+                   &rectEdit,
+                   pText ? pText : empty_stringW , size, NULL );
 
-           if( hPrevFont ) SelectObject(hDC, hPrevFont );
-           if( !hdc ) 
-           {
-               if( hPrevBrush ) SelectObject( hDC, hPrevBrush );
-               ReleaseDC( lphc->self->hwndSelf, hDC );
-           }
-       }
+       if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
+        DrawFocusRect( hdc, &rectEdit );
+     }
+
+     if( hPrevFont )
+       SelectObject(hdc, hPrevFont );
    }
    if (pText)
        HeapFree( GetProcessHeap(), 0, pText );
 }
 
+/***********************************************************************
+ *           CBPaintBorder
+ */
+static void CBPaintBorder(
+  HWND        hwnd,
+  LPHEADCOMBO lphc,
+  HDC         hdc)
+{
+  RECT clientRect;
+
+  if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+  {
+    GetClientRect(hwnd, &clientRect);
+  }
+  else
+  {
+    CopyRect(&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_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
+  {
+    if (lphc->wState & CBF_EDIT)
+    {
+      hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLOREDIT,
+                                      (WPARAM)hDC, (LPARAM)lphc->self );
+    }
+    else
+    {
+      hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLORLISTBOX,
+                                      (WPARAM)hDC, (LPARAM)lphc->self );
+    }
+  }
+
+  /*
+   * Catch errors.
+   */
+  if( !hBkgBrush )
+    hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
+
+  return hBkgBrush;
+}
+
+/***********************************************************************
+ *           COMBO_EraseBackground
+ */
+static LRESULT COMBO_EraseBackground(
+  HWND        hwnd,
+  LPHEADCOMBO lphc,
+  HDC         hParamDC)
+{
+  HBRUSH  hBkgBrush;
+  HDC    hDC;
+
+  if(lphc->wState & CBF_EDIT)
+      return TRUE;
+
+  hDC = (hParamDC) ? hParamDC
+                  : GetDC(hwnd);
+  /*
+   * Retrieve the background brush
+   */
+  hBkgBrush = COMBO_PrepareColors(lphc, hDC);
+
+  FillRect(hDC, &lphc->textRect, hBkgBrush);
+
+  if (!hParamDC)
+    ReleaseDC(hwnd, hDC);
+
+  return TRUE;
+}
+
 /***********************************************************************
  *           COMBO_Paint
  */
@@ -532,43 +927,54 @@ static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
 {
   PAINTSTRUCT ps;
   HDC  hDC;
-  
+
   hDC = (hParamDC) ? hParamDC
-                  : BeginPaint( lphc->self->hwndSelf, &ps);
+                  : BeginPaint( lphc->self, &ps);
+
+  TRACE("hdc=%p\n", hDC);
+
   if( hDC && !(lphc->wState & CBF_NOREDRAW) )
   {
       HBRUSH   hPrevBrush, hBkgBrush;
 
-      hBkgBrush = (HBRUSH)SendMessageA( lphc->owner, WM_CTLCOLORLISTBOX,
-                                 (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf );
-      if( !hBkgBrush ) hBkgBrush = GetStockObject(WHITE_BRUSH);
+      /*
+       * Retrieve the background brush and select it in the
+       * DC.
+       */
+      hBkgBrush = COMBO_PrepareColors(lphc, hDC);
 
       hPrevBrush = SelectObject( hDC, hBkgBrush );
-      if( !IsRectEmpty(&lphc->RectButton) )
-      {
-         /* paint everything to the right of the text field */
 
-         PatBlt( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
-                        lphc->RectButton.right - lphc->RectEdit.right,
-                        lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
-          CBPaintButton( lphc, hDC );
+      /*
+       * 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);
       }
 
-      if( !(lphc->wState & CBF_EDIT) )
+      /* paint the edit control padding area */
+      if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
       {
-         /* paint text field */
-         
-         HPEN hPrevPen = SelectObject( hDC, GetSysColorPen(
-                                                         COLOR_WINDOWFRAME) );
-
-         Rectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
-                      lphc->RectEdit.right, lphc->RectButton.bottom );
-         SelectObject( hDC, hPrevPen );
-         CBPaintText( lphc, hDC );
+          RECT rPadEdit = lphc->textRect;
+
+          InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+
+          FrameRect( hDC, &rPadEdit, GetSysColorBrush(COLOR_WINDOW) );
       }
-      if( hPrevBrush ) SelectObject( hDC, hPrevBrush );
+
+      if( !(lphc->wState & CBF_EDIT) )
+       CBPaintText( lphc, hDC, lphc->textRect);
+
+      if( hPrevBrush )
+       SelectObject( hDC, hPrevBrush );
   }
-  if( !hParamDC ) EndPaint(lphc->self->hwndSelf, &ps);
+
+  if( !hParamDC )
+    EndPaint(lphc->self, &ps);
+
   return 0;
 }
 
@@ -577,41 +983,35 @@ static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
  *
  * Select listbox entry according to the contents of the edit control.
  */
-static INT CBUpdateLBox( LPHEADCOMBO lphc )
+static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
 {
-   INT length, idx, ret;
-   LPSTR       pText = NULL;
-   
-   idx = ret = LB_ERR;
-   length = CB_GETEDITTEXTLENGTH( lphc );
-   if( length > 0 ) 
-       pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
+   INT length, idx;
+   LPWSTR pText = NULL;
+
+   idx = LB_ERR;
+   length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
 
-   DPRINT("\t edit text length %i\n", length );
+   if( length > 0 )
+       pText = HeapAlloc( GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR));
+
+   TRACE("\t edit text length %i\n", length );
 
    if( pText )
    {
-       if( length ) GetWindowTextA( lphc->hWndEdit, pText, length + 1);
+       if( length ) GetWindowTextW( lphc->hWndEdit, pText, length + 1);
        else pText[0] = '\0';
-       idx = SendMessageA( lphc->hWndLBox, LB_FINDSTRING, 
+       idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING,
                             (WPARAM)(-1), (LPARAM)pText );
-       if( idx == LB_ERR ) idx = 0;    /* select first item */
-       else ret = idx;
        HeapFree( GetProcessHeap(), 0, pText );
    }
 
-   /* select entry */
+   SendMessageW(lphc->hWndLBox, LB_SETCURSEL, (WPARAM)(bSelect ? idx : -1), 0);
 
-   SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)idx, 0 );
-   
-   if( idx >= 0 )
-   {
-       SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)idx, 0 );
-       /* probably superfluous but Windows sends this too */
-       SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)idx, 0 );
-   }
-   return ret;
+   /* probably superfluous but Windows sends this too */
+   SendMessageW(lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0);
+   SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0);
+
+   return idx;
 }
 
 /***********************************************************************
@@ -622,54 +1022,47 @@ static INT CBUpdateLBox( LPHEADCOMBO lphc )
 static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
 {
    INT length;
-   LPSTR       pText = NULL;
-
-   DPRINT("\t %i\n", index );
+   LPWSTR pText = NULL;
+   static const WCHAR empty_stringW[] = { 0 };
 
-   if( index == -1 )
-   {
-       length = CB_GETEDITTEXTLENGTH( lphc );
-       if( length )
-       {
-           if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
-           {
-               GetWindowTextA( lphc->hWndEdit, pText, length + 1 );
-               index = SendMessageA( lphc->hWndLBox, LB_FINDSTRING,
-                                       (WPARAM)(-1), (LPARAM)pText );
-               HeapFree( GetProcessHeap(), 0, pText );
-           }
-       }
-   }
+   TRACE("\t %i\n", index );
 
    if( index >= 0 ) /* got an entry */
    {
-       length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
-       if( length )
+       length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
+       if( length != LB_ERR)
        {
-          if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
+          if( (pText = HeapAlloc( GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR))) )
           {
-               SendMessageA( lphc->hWndLBox, LB_GETTEXT, 
+               SendMessageW(lphc->hWndLBox, LB_GETTEXT,
                                (WPARAM)index, (LPARAM)pText );
-               SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
-               SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
-               HeapFree( GetProcessHeap(), 0, pText );
           }
        }
    }
+
+   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, (LPARAM)(-1));
+
+   if( pText )
+       HeapFree( GetProcessHeap(), 0, pText );
 }
 
 /***********************************************************************
  *           CBDropDown
- * 
+ *
  * Show listbox popup.
  */
 static void CBDropDown( LPHEADCOMBO lphc )
 {
-   INT index;
-   RECT        rect;
-   LPRECT      pRect = NULL;
+   RECT rect,r;
+   int nItems = 0;
+   int nDroppedHeight;
 
-   DPRINT("[%04x]: drop down\n", CB_HWND(lphc));
+   TRACE("[%p]: drop down\n", lphc->self);
 
    CB_NOTIFY( lphc, CBN_DROPDOWN );
 
@@ -678,37 +1071,80 @@ static void CBDropDown( LPHEADCOMBO lphc )
    lphc->wState |= CBF_DROPPED;
    if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
    {
-       index = CBUpdateLBox( lphc );
-       if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
+       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
    {
-       index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
-       if( index == LB_ERR ) index = 0;
-       SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)index, 0 );
-       SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
-       pRect = &lphc->RectEdit;
+       lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+       SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
+                     (WPARAM)(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);
 
-   GetWindowRect( lphc->self->hwndSelf, &rect );
-   
-   rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
-   rect.bottom = rect.top + lphc->RectCombo.bottom - 
-                           lphc->RectCombo.top - SYSMETRICS_CYBORDER;
-   rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
-   rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
+      nHeight = nIHeight*nItems;
+
+      if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
+         nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
+
+      if (nDroppedHeight < nIHeight)
+      {
+            if (nItems < 5)
+                nDroppedHeight = (nItems+1)*nIHeight;
+            else
+                nDroppedHeight = 6*nIHeight;
+      }
+   }
+
+   /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
+   if( (rect.bottom + nDroppedHeight) >= GetSystemMetrics( SM_CYSCREEN ) )
+      rect.bottom = rect.top - nDroppedHeight;
+
+   SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.bottom,
+                lphc->droppedRect.right - lphc->droppedRect.left,
+                nDroppedHeight,
+                SWP_NOACTIVATE | SWP_SHOWWINDOW);
 
-   SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.top, 
-                rect.right - rect.left, rect.bottom - rect.top, 
-                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
 
    if( !(lphc->wState & CBF_NOREDRAW) )
-       if( pRect )
-           RedrawWindow( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE | 
+     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
                           RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
-   ShowWindow( lphc->hWndLBox, SW_SHOWNA );
+
+   EnableWindow( lphc->hWndLBox, TRUE );
+   if (GetCapture() != lphc->self)
+      SetCapture(lphc->hWndLBox);
 }
 
 /***********************************************************************
@@ -716,45 +1152,50 @@ static void CBDropDown( LPHEADCOMBO lphc )
  *
  * Hide listbox popup.
  */
-static void CBRollUp( LPHEADCOMBO lphc, WINBOOL ok, WINBOOL bButton )
+static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
 {
-   HWND        hWnd = lphc->self->hwndSelf;
+   HWND        hWnd = lphc->self;
+
+   TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
+        lphc->self, (INT)ok, (INT)(lphc->wState & CBF_DROPPED));
 
    CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
 
    if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
    {
 
-       DPRINT("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok );
-
-       /* always send WM_LBUTTONUP? */
-       SendMessageA( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
-
-       if( lphc->wState & CBF_DROPPED ) 
+       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 )
           {
-              INT index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
-              CBUpdateEdit( lphc, index );
-              rect = lphc->RectButton;
+              rect = lphc->buttonRect;
           }
-          else 
+          else
            {
               if( bButton )
-                  UnionRect( &rect, &lphc->RectButton,
-                                      &lphc->RectEdit );
+              {
+                UnionRect( &rect,
+                           &lphc->buttonRect,
+                           &lphc->textRect);
+              }
               else
-                  rect = lphc->RectEdit;
+                rect = lphc->textRect;
+
               bButton = TRUE;
           }
 
           if( bButton && !(lphc->wState & CBF_NOREDRAW) )
-              RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE | 
+              RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
                               RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
           CB_NOTIFY( lphc, CBN_CLOSEUP );
        }
@@ -766,11 +1207,11 @@ static void CBRollUp( LPHEADCOMBO lphc, WINBOOL ok, WINBOOL bButton )
  *
  * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
  */
-WINBOOL COMBO_FlipListbox( LPHEADCOMBO lphc, WINBOOL bRedrawButton )
+BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
 {
    if( lphc->wState & CBF_DROPPED )
    {
-       CBRollUp( lphc, TRUE, bRedrawButton );
+       CBRollUp( lphc, ok, bRedrawButton );
        return FALSE;
    }
 
@@ -778,31 +1219,13 @@ WINBOOL COMBO_FlipListbox( LPHEADCOMBO lphc, WINBOOL bRedrawButton )
    return TRUE;
 }
 
-/***********************************************************************
- *           COMBO_GetLBWindow
- *
- * Edit control helper.
- */
-HWND COMBO_GetLBWindow( WND* pWnd )
-{
-  LPHEADCOMBO       lphc = CB_GETPTR(pWnd);
-  if( lphc ) return lphc->hWndLBox;
-  return 0;
-}
-
-
 /***********************************************************************
  *           CBRepaintButton
  */
 static void CBRepaintButton( LPHEADCOMBO lphc )
-{
-   HDC        hDC = GetDC( lphc->self->hwndSelf );
-
-   if( hDC )
    {
-       CBPaintButton( lphc, hDC );
-       ReleaseDC( lphc->self->hwndSelf, hDC );
-   }
+  InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
+  UpdateWindow(lphc->self);
 }
 
 /***********************************************************************
@@ -813,14 +1236,17 @@ static void COMBO_SetFocus( LPHEADCOMBO lphc )
    if( !(lphc->wState & CBF_FOCUSED) )
    {
        if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-           SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
+           SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
 
-       if( lphc->wState & CBF_EDIT )
-           SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
-       lphc->wState |= CBF_FOCUSED;
-       if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 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;
    }
 }
 
@@ -829,24 +1255,21 @@ static void COMBO_SetFocus( LPHEADCOMBO lphc )
  */
 static void COMBO_KillFocus( LPHEADCOMBO lphc )
 {
-   HWND        hWnd = lphc->self->hwndSelf;
+   HWND        hWnd = lphc->self;
 
    if( lphc->wState & CBF_FOCUSED )
    {
-       SendMessageA( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
-
        CBRollUp( lphc, FALSE, TRUE );
        if( IsWindow( hWnd ) )
        {
            if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
-               SendMessageA( lphc->hWndLBox, LB_CARETOFF, 0, 0 );
+               SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
 
           lphc->wState &= ~CBF_FOCUSED;
 
            /* redraw text */
-           if( lphc->wState & CBF_EDIT )
-               SendMessageA( lphc->hWndEdit, EM_SETSEL, (WPARAM)(-1), 0 );
-           else CBPaintText( lphc, 0 );
+          if( !(lphc->wState & CBF_EDIT) )
+            InvalidateRect(lphc->self, &lphc->textRect, TRUE);
 
            CB_NOTIFY( lphc, CBN_KILLFOCUS );
        }
@@ -858,28 +1281,26 @@ static void COMBO_KillFocus( LPHEADCOMBO lphc )
  */
 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
 {
-   if( lphc->wState & CBF_EDIT && lphc->hWndEdit == 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):
 
-               DPRINT("[%04x]: edit [%04x] got focus\n", 
-                            CB_HWND(lphc), lphc->hWndEdit );
+               TRACE("[%p]: edit [%p] got focus\n", lphc->self, lphc->hWndEdit );
 
-               if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
+               COMBO_SetFocus( lphc );
                break;
 
           case (EN_KILLFOCUS >> 8):
 
-               DPRINT("[%04x]: edit [%04x] lost focus\n",
-                            CB_HWND(lphc), lphc->hWndEdit );
+               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 
+                * notification (only when it happens to be a part of
                 * the combo). ?? - AK.
                 */
 
@@ -888,12 +1309,29 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
 
 
           case (EN_CHANGE >> 8):
-               CB_NOTIFY( lphc, CBN_EDITCHANGE );
-               CBUpdateLBox( lphc );
+              /*
+               * In some circumstances (when the selection of the combobox
+               * is changed for example) we don't wans 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):
-               CB_NOTIFY( lphc, CBN_EDITUPDATE );
+               if (!(lphc->wState & CBF_NOEDITNOTIFY))
+                 CB_NOTIFY( lphc, CBN_EDITUPDATE );
                break;
 
           case (EN_ERRSPACE >> 8):
@@ -902,7 +1340,7 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
    }
    else if( lphc->hWndLBox == hWnd )
    {
-       switch( HIWORD(wParam) )
+       switch( (short)HIWORD(wParam) )
        {
           case LBN_ERRSPACE:
                CB_NOTIFY( lphc, CBN_ERRSPACE );
@@ -915,18 +1353,32 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
           case LBN_SELCHANGE:
           case LBN_SELCANCEL:
 
-               DPRINT("[%04x]: lbox selection change [%04x]\n", 
-                            CB_HWND(lphc), lphc->wState );
+               TRACE("[%p]: lbox selection change [%x]\n", lphc->self, lphc->wState );
 
-               /* do not roll up if selection is being tracked 
-                * by arrowkeys in the dropdown listbox */
+               if( HIWORD(wParam) == LBN_SELCHANGE)
+               {
+                  if( lphc->wState & CBF_EDIT )
+                  {
+                      INT index = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+                      lphc->wState |= CBF_NOLBSELECT;
+                      CBUpdateEdit( lphc, index );
+                      /* select text in edit, as Windows does */
+                      SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
+                  }
+                  else
+                      InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+               }
 
-               if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
-                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
+               /* do not roll up if selection is being tracked
+                * by arrowkeys in the dropdown listbox */
+                if( ((lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP)) )
+                {
+                   CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
+                }
                else lphc->wState &= ~CBF_NOROLLUP;
 
                CB_NOTIFY( lphc, CBN_SELCHANGE );
-               CBPaintText( lphc, 0 );
+
                /* fall through */
 
           case LBN_SETFOCUS:
@@ -944,115 +1396,176 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
  *
  * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
  */
-static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, 
-                              WPARAM wParam, LPARAM lParam ) 
+static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
 {
-   HWND        hWnd = lphc->self->hwndSelf;
-
-   DPRINT("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
+   HWND hWnd = lphc->self;
+   UINT id = GetWindowLongA( hWnd, GWL_ID );
 
-#define lpIS    ((LPDELETEITEMSTRUCT)lParam)
+   TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
 
-   /* two first items are the same in all 4 structs */
-   lpIS->CtlType = ODT_COMBOBOX;
-   lpIS->CtlID   = lphc->self->wIDmenu;
-
-   switch( msg )       /* patch window handle */
+   switch( msg )
    {
-       case WM_DELETEITEM: 
-            lpIS->hwndItem = hWnd; 
-#undef  lpIS
-            break;
-       case WM_DRAWITEM: 
-#define lpIS    ((LPDRAWITEMSTRUCT)lParam)
-            lpIS->hwndItem = hWnd; 
-#undef  lpIS
-            break;
-       case WM_COMPAREITEM: 
-#define lpIS    ((LPCOMPAREITEMSTRUCT)lParam)
-            lpIS->hwndItem = hWnd; 
-#undef  lpIS
-            break;
+   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 SendMessageA( lphc->owner, msg, lphc->self->wIDmenu, lParam );
+   return SendMessageW(lphc->owner, msg, id, lParam);
 }
 
+
 /***********************************************************************
- *           COMBO_GetText
+ *           COMBO_GetTextW
  */
-static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT N, LPSTR lpText)
+static LRESULT COMBO_GetTextW( LPHEADCOMBO lphc, INT count, LPWSTR buf )
 {
-   if( lphc->wState & CBF_EDIT )
-       return SendMessageA( lphc->hWndEdit, WM_GETTEXT, 
-                            (WPARAM)N, (LPARAM)lpText );     
+    INT length;
 
-   /* get it from the listbox */
+    if( lphc->wState & CBF_EDIT )
+        return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
 
-   if( lphc->hWndLBox )
-   {
-       INT idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
-       if( idx != LB_ERR )
-       {
-           LPSTR       lpBuffer;
-           INT length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN,
-                                               (WPARAM)idx, 0 );
+    /* get it from the listbox */
 
-           /* 'length' is without the terminating character */
-           if( length >= N )
-              lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
-           else 
-              lpBuffer = lpText;
+    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)
+        {
+            LPWSTR lpBuffer = HeapAlloc(GetProcessHeap(), 0, (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;
+            }
+            HeapFree( GetProcessHeap(), 0, lpBuffer );
+        }
+        else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
 
-           if( lpBuffer )
-           {
-              INT    n = SendMessageA( lphc->hWndLBox, LB_GETTEXT, 
-                                          (WPARAM)idx, (LPARAM)lpBuffer );
+        if (length == LB_ERR) return 0;
+        return length;
+    }
 
-              /* truncate if buffer is too short */
+ error:  /* error - truncate string, return zero */
+    buf[0] = 0;
+    return 0;
+}
 
-              if( length >= N )
-              {
-                  if (N && lpText) {
-                  if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
-                  lpText[N - 1] = '\0';
-                   }
-                  HeapFree( GetProcessHeap(), 0, lpBuffer );
-              }
-              return (LRESULT)n;
-          }
-       }
-   }
-   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 = SendMessageA(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 
+ * This function sets window positions according to the updated
  * component placement struct.
  */
-static void CBResetPos( LPHEADCOMBO lphc, LPRECT lbRect, WINBOOL bRedraw )
+static void CBResetPos(
+  LPHEADCOMBO lphc,
+  LPRECT      rectEdit,
+  LPRECT      rectLB,
+  BOOL        bRedraw)
 {
-   WINBOOL     bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
+   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, lphc->RectEdit.left, lphc->RectEdit.top,
-                       lphc->RectEdit.right - lphc->RectEdit.left,
-                       lphc->RectEdit.bottom - lphc->RectEdit.top,
+     SetWindowPos( lphc->hWndEdit, 0,
+                  rectEdit->left, rectEdit->top,
+                  rectEdit->right - rectEdit->left,
+                  rectEdit->bottom - rectEdit->top,
                        SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
 
-   if( bDrop )
-       OffsetRect( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
-
-   lbRect->right -= lbRect->left;      /* convert to width */
-   lbRect->bottom -= lbRect->top;
-   SetWindowPos( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
-                   lbRect->right, lbRect->bottom, 
+   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 )
@@ -1063,15 +1576,8 @@ static void CBResetPos( LPHEADCOMBO lphc, LPRECT lbRect, WINBOOL bRedraw )
            ShowWindow( lphc->hWndLBox, SW_HIDE );
        }
 
-       lphc->wState |= CBF_NORESIZE;
-       SetWindowPos( lphc->self->hwndSelf, 0, 0, 0,
-                       lphc->RectCombo.right - lphc->RectCombo.left,
-                       lphc->RectEdit.bottom - lphc->RectEdit.top,
-                       SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
-       lphc->wState &= ~CBF_NORESIZE;
-
        if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
-           RedrawWindow( lphc->self->hwndSelf, NULL, 0,
+           RedrawWindow( lphc->self, NULL, 0,
                            RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
    }
 }
@@ -1081,51 +1587,51 @@ static void CBResetPos( LPHEADCOMBO lphc, LPRECT lbRect, WINBOOL bRedraw )
  *           COMBO_Size
  */
 static void COMBO_Size( LPHEADCOMBO lphc )
-{
-  RECT rect;
-  INT          w, h;
-
-  GetWindowRect( lphc->self->hwndSelf, &rect );
-  w = rect.right - rect.left; h = rect.bottom - rect.top;
-
-  DPRINT("w = %i, h = %i\n", w, h );
-
-  /* CreateWindow() may send a bogus WM_SIZE, ignore it */
-
-  if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
   {
-      if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
-         (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
-          return;
-      else if( (lphc->dwStyle & CBS_DROPDOWN) &&
-              (h == (lphc->RectEdit.bottom - lphc->RectEdit.top))  )
-              return;
-  }
-  lphc->RectCombo = rect;
-  CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
-  CBResetPos( lphc, &rect, TRUE );
+  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, WINBOOL bRedraw )
+static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
 {
-  RECT        rect;
-
+  /*
+   * Set the font
+   */
   lphc->hFont = hFont;
 
+  /*
+   * Propagate to owned windows.
+   */
   if( lphc->wState & CBF_EDIT )
-      SendMessageA( lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw );
-  SendMessageA( lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw );
-
-  GetWindowRect( lphc->self->hwndSelf, &rect );
-  OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
-                                  rect.top - lphc->RectCombo.top );
-  CBCalcPlacement( lphc, &lphc->RectEdit,
-                         &lphc->RectButton, &rect );
-  CBResetPos( lphc, &rect, bRedraw );
+      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);
+  }
 }
 
 
@@ -1138,22 +1644,33 @@ static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
 
    if( index == -1 ) /* set text field height */
    {
-       if( height < 768 )
+       if( height < 32768 )
        {
-           RECT        rect;
-
            lphc->editHeight = height;
-           GetWindowRect( lphc->self->hwndSelf, &rect );
-           OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
-                                          rect.top - lphc->RectCombo.top );
-           CBCalcPlacement( lphc, &lphc->RectEdit,
-                                 &lphc->RectButton, &rect );
-           CBResetPos( lphc, &rect, TRUE );
+
+        /*
+         * 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 = SendMessageA( lphc->hWndLBox, LB_SETITEMHEIGHT, 
+       lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT,
                              (WPARAM)index, (LPARAM)height );
    return lRet;
 }
@@ -1161,16 +1678,18 @@ static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
 /***********************************************************************
  *           COMBO_SelectString
  */
-static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPCSTR pText )
+static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText, BOOL unicode )
 {
-   INT index = SendMessageA( lphc->hWndLBox, LB_SELECTSTRING, 
-                                (WPARAM)start, (LPARAM)pText );
+   INT index = unicode ? SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText) :
+                         SendMessageA(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText);
    if( index >= 0 )
    {
-        if( lphc->wState & CBF_EDIT )
-           CBUpdateEdit( lphc, index );
-       else
-           CBPaintText( lphc, 0 );
+     if( lphc->wState & CBF_EDIT )
+       CBUpdateEdit( lphc, index );
+     else
+     {
+       InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+     }
    }
    return (LRESULT)index;
 }
@@ -1180,9 +1699,13 @@ static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPCSTR pText )
  */
 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
 {
-   POINT     pt = { LOWORD(lParam), HIWORD(lParam) };
-   WINBOOL      bButton = PtInRect(&lphc->RectButton, pt);
-   HWND      hWnd = lphc->self->hwndSelf;
+   POINT     pt;
+   BOOL      bButton;
+   HWND      hWnd = lphc->self;
+
+   pt.x = LOWORD(lParam);
+   pt.y = HIWORD(lParam);
+   bButton = PtInRect(&lphc->buttonRect, pt);
 
    if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
        (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
@@ -1192,6 +1715,7 @@ static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
        {
           /* got a click to cancel selection */
 
+           lphc->wState &= ~CBF_BUTTONDOWN;
            CBRollUp( lphc, TRUE, FALSE );
           if( !IsWindow( hWnd ) ) return;
 
@@ -1200,15 +1724,14 @@ static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
                lphc->wState &= ~CBF_CAPTURE;
                ReleaseCapture();
            }
-           lphc->wState &= ~CBF_BUTTONDOWN;
        }
        else
        {
           /* drop down the listbox and start tracking */
 
            lphc->wState |= CBF_CAPTURE;
-           CBDropDown( lphc );
            SetCapture( hWnd );
+           CBDropDown( lphc );
        }
        if( bButton ) CBRepaintButton( lphc );
    }
@@ -1219,17 +1742,24 @@ static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
  *
  * Release capture and stop tracking if needed.
  */
-static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
+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 );
-          CBUpdateEdit( lphc, index );
+          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 )
@@ -1247,132 +1777,195 @@ static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
  */
 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
 {
-   POINT  pt = { LOWORD(lParam), HIWORD(lParam) };
+   POINT  pt;
    RECT   lbRect;
 
+   pt.x = LOWORD(lParam);
+   pt.y = HIWORD(lParam);
+
    if( lphc->wState & CBF_BUTTONDOWN )
    {
-       WINBOOL bButton = PtInRect(&lphc->RectButton, pt);
+     BOOL bButton;
 
-       if( !bButton )
-       {
-          lphc->wState &= ~CBF_BUTTONDOWN;
-          CBRepaintButton( lphc );
-       }
+     bButton = PtInRect(&lphc->buttonRect, pt);
+
+     if( !bButton )
+     {
+       lphc->wState &= ~CBF_BUTTONDOWN;
+       CBRepaintButton( lphc );
+     }
    }
 
    GetClientRect( lphc->hWndLBox, &lbRect );
-   MapWindowPoints( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
+   MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
    if( PtInRect(&lbRect, pt) )
    {
        lphc->wState &= ~CBF_CAPTURE;
        ReleaseCapture();
-       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
 
        /* hand over pointer tracking */
-       SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
+       SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
    }
 }
 
 
 /***********************************************************************
- *           ComboWndProc
+ *           ComboWndProc_common
  *
- * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win/ctrl/src/combobox_15.htm
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
  */
-LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
-                             WPARAM wParam, LPARAM lParam )
+static LRESULT ComboWndProc_common( HWND hwnd, UINT message,
+                                    WPARAM wParam, LPARAM lParam, BOOL unicode )
 {
-    WND*       pWnd = WIN_FindWndPtr(hwnd);
-   
-    if( pWnd )
-    {
-      LPHEADCOMBO      lphc = CB_GETPTR(pWnd);
+      LPHEADCOMBO lphc = (LPHEADCOMBO)GetWindowLongA( hwnd, 0 );
 
-      DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n",
-                  pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
+      //TRACE("[%p]: msg %s wp %08x lp %08lx\n",
+      //      hwnd, SPY_GetMsgName(message, hwnd), wParam, lParam );
 
       if( lphc || message == WM_NCCREATE )
-      switch(message) 
-      {        
+      switch(message)
+      {
 
        /* System messages */
 
-       case WM_NCCREATE: 
-               return COMBO_NCCreate(pWnd, lParam);
-
-       case WM_NCDESTROY: 
+       case WM_NCCREATE:
+       {
+               LONG style = unicode ? ((LPCREATESTRUCTW)lParam)->style :
+                                      ((LPCREATESTRUCTA)lParam)->style;
+                return COMBO_NCCreate(hwnd, style);
+       }
+       case WM_NCDESTROY:
                COMBO_NCDestroy(lphc);
-               break;
+               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_CREATE: 
-               return COMBO_Create(lphc, pWnd, lParam);
+        case WM_PRINTCLIENT:
+               if (lParam & PRF_ERASEBKGND)
+                 COMBO_EraseBackground(hwnd, lphc, (HDC)wParam);
 
+               /* Fallthrough */
        case WM_PAINT:
                /* wParam may contain a valid HDC! */
-               return COMBO_Paint(lphc, wParam);
-
+               return  COMBO_Paint(lphc, (HDC)wParam);
        case WM_ERASEBKGND:
-               return TRUE;
-
-       case WM_GETDLGCODE: 
-               return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
+               return  COMBO_EraseBackground(hwnd, lphc, (HDC)wParam);
+       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_WINDOWPOSCHANGING:
+               return  COMBO_WindowPosChanging(hwnd, lphc, (LPWINDOWPOS)lParam);
+    case WM_WINDOWPOSCHANGED:
+        /* SetWindowPos can be called on a Combobox to resize its Listbox.
+         * In that case, the Combobox itself will not be resized, so we won't
+         * get a WM_SIZE. Since we still want to update the Listbox, we have to
+         * do it here.
+         */
+        /* fall through */
        case WM_SIZE:
-               if( lphc->hWndLBox && 
+               if( lphc->hWndLBox &&
                  !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
-               return TRUE;
-
+               return  TRUE;
        case WM_SETFONT:
-               COMBO_Font( lphc, (HFONT)wParam, (WINBOOL)lParam );
-               return TRUE;
-
+               COMBO_Font( lphc, (HFONT)wParam, (BOOL)lParam );
+               return  TRUE;
        case WM_GETFONT:
-               return (LRESULT)lphc->hFont;
-
+               return  (LRESULT)lphc->hFont;
        case WM_SETFOCUS:
                if( lphc->wState & CBF_EDIT )
                    SetFocus( lphc->hWndEdit );
                else
                    COMBO_SetFocus( lphc );
-               return TRUE;
-
+               return  TRUE;
        case WM_KILLFOCUS:
-#define hwndFocus ((HWND)wParam)
+            {
+#ifdef __REACTOS__
+                HWND hwndFocus = (HWND)wParam;
+#else
+                HWND hwndFocus = WIN_GetFullHandle( (HWND)wParam );
+#endif
                if( !hwndFocus ||
                    (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
                    COMBO_KillFocus( lphc );
-#undef hwndFocus
-               return TRUE;
-
+               return  TRUE;
+            }
        case WM_COMMAND:
-               return COMBO_Command( lphc, wParam, (HWND)lParam );
-
+#ifdef __REACTOS__
+               return  COMBO_Command( lphc, wParam, (HWND)lParam);
+#else
+               return  COMBO_Command( lphc, wParam, WIN_GetFullHandle( (HWND)lParam ) );
+#endif
        case WM_GETTEXT:
-               return COMBO_GetText( lphc, (UINT)wParam, (LPSTR)lParam );
-
+            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 SendMessageA( lphc->hWndEdit, message, wParam, lParam );
-               return CB_ERR;
+               {
+                   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, wParam, lParam );
-
+               return COMBO_ItemOp(lphc, message, lParam);
        case WM_ENABLE:
                if( lphc->wState & CBF_EDIT )
-                   EnableWindow( lphc->hWndEdit, (WINBOOL)wParam ); 
-               EnableWindow( lphc->hWndLBox, (WINBOOL)wParam );
-               return TRUE;
+                   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;
@@ -1380,111 +1973,220 @@ LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
                    lphc->wState |= CBF_NOREDRAW;
 
                if( lphc->wState & CBF_EDIT )
-                   SendMessageA( lphc->hWndEdit, message, wParam, lParam );
-               SendMessageA( lphc->hWndLBox, message, wParam, lParam );
-               return 0;
-               
+                   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, TRUE );
-               break;
+                       COMBO_FlipListbox( lphc, FALSE, FALSE );
+                return  0;
 
        case WM_CHAR:
+       case WM_IME_CHAR:
        case WM_KEYDOWN:
+       {
+               HWND hwndTarget;
+
+               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;
+               }
+
                if( lphc->wState & CBF_EDIT )
-                   return SendMessageA( lphc->hWndEdit, message, wParam, lParam );
+                   hwndTarget = lphc->hWndEdit;
                else
-                   return SendMessageA( lphc->hWndLBox, message, wParam, lParam );
+                   hwndTarget = lphc->hWndLBox;
 
-       case WM_LBUTTONDOWN: 
-               if( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self->hwndSelf );
+               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;
-
+               return  TRUE;
        case WM_LBUTTONUP:
-               COMBO_LButtonUp( lphc, lParam );
-               return TRUE;
-
-       case WM_MOUSEMOVE: 
-               if( lphc->wState & CBF_CAPTURE ) 
+               COMBO_LButtonUp( lphc );
+               return  TRUE;
+       case WM_MOUSEMOVE:
+               if( lphc->wState & CBF_CAPTURE )
                    COMBO_MouseMove( lphc, wParam, lParam );
-               return TRUE;
+               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 */
 
+#ifndef __REACTOS__
+       case CB_ADDSTRING16:
+               if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_ADDSTRING:
-               return SendMessageA( lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
-
+               if( unicode )
+                {
+                    if( lphc->dwStyle & CBS_LOWERCASE )
+                        strlwrW((LPWSTR)lParam);
+                    else if( lphc->dwStyle & CBS_UPPERCASE )
+                        struprW((LPWSTR)lParam);
+                    return SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+                }
+                else
+                {
+                    if( lphc->dwStyle & CBS_LOWERCASE )
+                        _strlwr((LPSTR)lParam);
+                    else if( lphc->dwStyle & CBS_UPPERCASE )
+                        _strupr((LPSTR)lParam);
+                    return SendMessageA(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+                }
+#ifndef __REACTOS__
+       case CB_INSERTSTRING16:
+               wParam = (INT)(INT16)wParam;
+               if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_INSERTSTRING:
-               return SendMessageA( lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
-
+               if( unicode )
+                {
+                    if( lphc->dwStyle & CBS_LOWERCASE )
+                        strlwrW((LPWSTR)lParam);
+                    else if( lphc->dwStyle & CBS_UPPERCASE )
+                        struprW((LPWSTR)lParam);
+                    return SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+                }
+                else
+                {
+                    if( lphc->dwStyle & CBS_LOWERCASE )
+                        _strlwr((LPSTR)lParam);
+                    else if( lphc->dwStyle & CBS_UPPERCASE )
+                        _strupr((LPSTR)lParam);
+                    return SendMessageA(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+                }
+#ifndef __REACTOS__
+       case CB_DELETESTRING16:
+#endif
        case CB_DELETESTRING:
-               return SendMessageA( lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
-
+               return unicode ? SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0) :
+                                SendMessageA(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
+#ifndef __REACTOS__
+       case CB_SELECTSTRING16:
+               wParam = (INT)(INT16)wParam;
+               if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_SELECTSTRING:
-               return COMBO_SelectString( lphc, (INT)wParam, (LPSTR)lParam );
-
+               return COMBO_SelectString(lphc, (INT)wParam, lParam, unicode);
+#ifndef __REACTOS__
+       case CB_FINDSTRING16:
+               wParam = (INT)(INT16)wParam;
+               if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_FINDSTRING:
-               return SendMessageA( lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
-
+               return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam) :
+                                SendMessageA(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
+#ifndef __REACTOS__
+       case CB_FINDSTRINGEXACT16:
+               wParam = (INT)(INT16)wParam;
+               if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_FINDSTRINGEXACT:
-               return SendMessageA( lphc->hWndLBox, LB_FINDSTRINGEXACT, 
-                                                      wParam, lParam );
-
+               return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam) :
+                                SendMessageA(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
+#ifndef __REACTOS__
+       case CB_SETITEMHEIGHT16:
+               wParam = (INT)(INT16)wParam;    /* signed integer */
+               /* fall through */
+#endif
        case CB_SETITEMHEIGHT:
-               return COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
-
+               return  COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
+#ifndef __REACTOS__
+       case CB_GETITEMHEIGHT16:
+               wParam = (INT)(INT16)wParam;
+               /* fall through */
+#endif
        case CB_GETITEMHEIGHT:
                if( (INT)wParam >= 0 )  /* listbox item */
-                   return SendMessageA( lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
-               return (lphc->RectEdit.bottom - lphc->RectEdit.top);
-
+                    return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
+                return  CBGetTextAreaHeight(hwnd, lphc);
+#ifndef __REACTOS__
+       case CB_RESETCONTENT16:
+#endif
        case CB_RESETCONTENT:
-               SendMessageA( lphc->hWndLBox, LB_RESETCONTENT, 0, 0 );
-               CBPaintText( lphc, 0 );
-               return TRUE;
-
+               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 SendMessageA( lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
-
+               return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
        case CB_GETHORIZONTALEXTENT:
-               return SendMessageA( lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
        case CB_SETHORIZONTALEXTENT:
-               return SendMessageA( lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
        case CB_GETTOPINDEX:
-               return SendMessageA( lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
        case CB_GETLOCALE:
-               return SendMessageA( lphc->hWndLBox, LB_GETLOCALE, 0, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
        case CB_SETLOCALE:
-               return SendMessageA( lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
        case CB_GETDROPPEDWIDTH:
                if( lphc->droppedWidth )
-                   return lphc->droppedWidth;
-               return lphc->RectCombo.right - lphc->RectCombo.left - 
-                          (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
-
+                    return  lphc->droppedWidth;
+               return  lphc->droppedRect.right - lphc->droppedRect.left;
        case CB_SETDROPPEDWIDTH:
                if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
-                   (INT)wParam < 768 ) lphc->droppedWidth = (INT)wParam;
-               return CB_ERR;
-
+                   (INT)wParam < 32768 ) lphc->droppedWidth = (INT)wParam;
+               return  CB_ERR;
+#ifndef __REACTOS__
+       case CB_GETDROPPEDCONTROLRECT16:
+               lParam = (LPARAM)MapSL(lParam);
+               if( lParam )
+               {
+                   RECT        r;
+                   CBGetDroppedControlRect( lphc, &r );
+                   CONV_RECT32TO16( &r, (LPRECT16)lParam );
+               }
+               return  CB_OKAY;
+#endif
        case CB_GETDROPPEDCONTROLRECT:
                if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
-               return CB_OKAY;
-
+               return  CB_OKAY;
+#ifndef __REACTOS__
+       case CB_GETDROPPEDSTATE16:
+#endif
        case CB_GETDROPPEDSTATE:
-               return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
-
-
+               return  (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
+#ifndef __REACTOS__
+       case CB_DIR16:
+               return SendMessageA(lphc->hWndLBox, LB_DIR16, wParam, lParam);
+#endif
        case CB_DIR:
-               return COMBO_Directory( lphc, (UINT)wParam, 
-                                      (LPSTR)lParam, (message == CB_DIR));
+               return unicode ? SendMessageW(lphc->hWndLBox, LB_DIR, wParam, lParam) :
+                                SendMessageA(lphc->hWndLBox, LB_DIR, wParam, lParam);
+
+#ifndef __REACTOS__
+       case CB_SHOWDROPDOWN16:
+#endif
        case CB_SHOWDROPDOWN:
                if( CB_GETTYPE(lphc) != CBS_SIMPLE )
                {
@@ -1493,78 +2195,141 @@ LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
                        if( !(lphc->wState & CBF_DROPPED) )
                            CBDropDown( lphc );
                    }
-                   else 
-                       if( lphc->wState & CBF_DROPPED ) 
+                   else
+                       if( lphc->wState & CBF_DROPPED )
                            CBRollUp( lphc, FALSE, TRUE );
                }
-               return TRUE;
-
+               return  TRUE;
+#ifndef __REACTOS__
+       case CB_GETCOUNT16:
+#endif
        case CB_GETCOUNT:
-               return SendMessageA( lphc->hWndLBox, LB_GETCOUNT, 0, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+#ifndef __REACTOS__
+       case CB_GETCURSEL16:
+#endif
        case CB_GETCURSEL:
-               return SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+#ifndef __REACTOS__
+       case CB_SETCURSEL16:
+               wParam = (INT)(INT16)wParam;
+               /* fall through */
+#endif
        case CB_SETCURSEL:
-               lParam = SendMessageA( lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
-               if( lphc->wState & CBF_SELCHANGE )
-               {
-                   /* no LBN_SELCHANGE in this case, update manually */
-                  
-                   CBPaintText( lphc, 0 );
-                   lphc->wState &= ~CBF_SELCHANGE;
-               }
-               return lParam;
-
+               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 */
+               if( lphc->wState & CBF_EDIT )
+                   CBUpdateEdit( lphc, (INT)wParam );
+               else
+                   InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+               lphc->wState &= ~CBF_SELCHANGE;
+               return  lParam;
+#ifndef __REACTOS__
+       case CB_GETLBTEXT16:
+               wParam = (INT)(INT16)wParam;
+               lParam = (LPARAM)MapSL(lParam);
+               /* fall through */
+#endif
        case CB_GETLBTEXT:
-               return SendMessageA( lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
-
+               return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam) :
+                                SendMessageA(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
+#ifndef __REACTOS__
+       case CB_GETLBTEXTLEN16:
+               wParam = (INT)(INT16)wParam;
+               /* fall through */
+#endif
        case CB_GETLBTEXTLEN:
-               return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
-
+                return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0) :
+                                 SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
+#ifndef __REACTOS__
+       case CB_GETITEMDATA16:
+               wParam = (INT)(INT16)wParam;
+               /* fall through */
+#endif
        case CB_GETITEMDATA:
-               return SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
-
+               return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
+#ifndef __REACTOS__
+       case CB_SETITEMDATA16:
+               wParam = (INT)(INT16)wParam;
+               /* fall through */
+#endif
        case CB_SETITEMDATA:
-               return SendMessageA( lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
-
+               return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
+#ifndef __REACTOS__
+       case CB_GETEDITSEL16:
+               wParam = lParam = 0;   /* just in case */
+               /* fall through */
+#endif
        case CB_GETEDITSEL:
+               /* Edit checks passed parameters itself */
                if( lphc->wState & CBF_EDIT )
-               {
-                   INT a, b;
-
-                   return SendMessageA( lphc->hWndEdit, EM_GETSEL,
-                                          (wParam) ? wParam : (WPARAM)&a,
-                                          (lParam) ? lParam : (LPARAM)&b );
-               }
-               return CB_ERR;
-
-
+                   return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
+               return  CB_ERR;
+#ifndef __REACTOS__
+       case CB_SETEDITSEL16:
+#endif
        case CB_SETEDITSEL:
-               if( lphc->wState & CBF_EDIT ) 
-                   return SendMessageA( lphc->hWndEdit, EM_SETSEL, 
-                         (INT)(INT)LOWORD(lParam), (INT)(INT)HIWORD(lParam) );
-               return CB_ERR;
-
-
+               if( lphc->wState & CBF_EDIT )
+                    return SendMessageW(lphc->hWndEdit, EM_SETSEL,
+                         (INT)(INT16)LOWORD(lParam), (INT)(INT16)HIWORD(lParam) );
+               return  CB_ERR;
+#ifndef __REACTOS__
+       case CB_SETEXTENDEDUI16:
+#endif
        case CB_SETEXTENDEDUI:
-               if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
-
+                if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+                    return  CB_ERR;
                if( wParam )
                    lphc->wState |= CBF_EUI;
                else lphc->wState &= ~CBF_EUI;
-               return CB_OKAY;
+               return  CB_OKAY;
+#ifndef __REACTOS__
+       case CB_GETEXTENDEDUI16:
+#endif
+       case CB_GETEXTENDEDUI:
+               return  (lphc->wState & CBF_EUI) ? TRUE : FALSE;
 
+       default:
+               if (message >= WM_USER)
+                   WARN("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
+                       message - WM_USER, wParam, lParam );
+               break;
+      }
+      return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
+                       DefWindowProcA(hwnd, message, wParam, lParam);
+}
 
-       case CB_GETEXTENDEDUI:
-               return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
+/***********************************************************************
+ *           ComboWndProcA
+ *
+ * This is just a wrapper for the real ComboWndProc which locks/unlocks
+ * window structs.
+ */
+static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ComboWndProc_common( hwnd, message, wParam, lParam, FALSE );
+}
 
-       case (WM_USER + 0x1B):
-               DPRINT( "[%04x]: undocumented msg!\n", hwnd );
-    }
-    return DefWindowProcA(hwnd, message, wParam, lParam);
-  }
-  return CB_ERR;
+/***********************************************************************
+ *           ComboWndProcW
+ */
+static LRESULT WINAPI ComboWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ComboWndProc_common( hwnd, message, wParam, lParam, TRUE );
 }
 
+/*************************************************************************
+ *           GetComboBoxInfo   (USER32.@)
+ */
+BOOL WINAPI GetComboBoxInfo(HWND hwndCombo,      /* [in] handle to combo box */
+                           PCOMBOBOXINFO pcbi   /* [in/out] combo box information */)
+{
+    FIXME("\n");
+    return FALSE;
+
+}