Index: trunk/src/user32/USER32.DEF
===================================================================
--- trunk/src/user32/USER32.DEF	(revision 9522)
+++ trunk/src/user32/USER32.DEF	(revision 9523)
@@ -1,3 +1,3 @@
-; $Id: USER32.DEF,v 1.74 2002-09-03 12:34:00 sandervl Exp $
+; $Id: USER32.DEF,v 1.75 2002-12-18 12:28:01 sandervl Exp $
 
 LIBRARY USER32 INITINSTANCE TERMINSTANCE
@@ -203,5 +203,5 @@
     DrawTextExW                = _DrawTextExW@24             @167
     DrawTextW                  = _DrawTextW@20               @168
-    EditWndProc                = _EditWndProc@16             @169
+    EditWndProc                = _EditWndProcA@16            @169
     EmptyClipboard             = _EmptyClipboard@0           @170
     EnableMenuItem             = _EnableMenuItem@12          @171
Index: trunk/src/user32/combo.c
===================================================================
--- trunk/src/user32/combo.c	(revision 9523)
+++ trunk/src/user32/combo.c	(revision 9523)
@@ -0,0 +1,2277 @@
+/*
+ * Combo controls
+ *
+ * Copyright 1997 Alex Korobka
+ *
+ * FIXME: roll up in Netscape 3.01.
+ */
+
+#include <string.h>
+
+#include "winbase.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/winuser16.h"
+#include "wine/unicode.h"
+#include "spy.h"
+#include "user.h"
+#include "win.h"
+#include "controls.h"
+#include "debugtools.h"
+
+#ifdef __WIN32OS2__
+#include "ctrlconf.h"
+#endif
+
+DEFAULT_DEBUG_CHANNEL(combo);
+
+  /* bits in the dwKeyData */
+#define KEYDATA_ALT             0x2000
+#define KEYDATA_PREVSTATE       0x4000
+
+/*
+ * Additional combo box definitions
+ */
+
+#define CB_NOTIFY( lphc, code ) \
+    (SendMessageW((lphc)->owner, WM_COMMAND, \
+                  MAKEWPARAM(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;
+
+/*
+ * Look and feel dependant "constants"
+ */
+
+#define COMBO_YBORDERGAP         5
+#define COMBO_XBORDERSIZE()      ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
+#define COMBO_YBORDERSIZE()      ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
+#define COMBO_EDITBUTTONSPACE()  ( (TWEAK_WineLook == WIN31_LOOK) ? 8 : 0 )
+#define EDIT_CONTROL_PADDING()   ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 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 =
+{
+    "ComboBox",           /* name */
+    CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS, /* style  */
+    ComboWndProcA,        /* procA */
+    ComboWndProcW,        /* procW */
+    sizeof(HEADCOMBO *),  /* extra */
+    IDC_ARROWA,           /* cursor */
+    0                     /* brush */
+};
+
+
+/***********************************************************************
+ *           COMBO_Init
+ *
+ * Load combo button bitmap.
+ */
+static BOOL COMBO_Init()
+{
+  HDC		hDC;
+
+  if( hComboBmp ) return TRUE;
+  if( (hDC = CreateCompatibleDC(0)) )
+  {
+    BOOL	bRet = FALSE;
+    if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
+    {
+      BITMAP      bm;
+      HBITMAP     hPrevB;
+      RECT        r;
+
+      GetObjectW( hComboBmp, sizeof(bm), &bm );
+      CBitHeight = bm.bmHeight;
+      CBitWidth  = bm.bmWidth;
+
+      TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
+
+      hPrevB = SelectObject( hDC, hComboBmp);
+      SetRect( &r, 0, 0, CBitWidth, CBitHeight );
+      InvertRect( hDC, &r );
+      SelectObject( hDC, hPrevB );
+      bRet = TRUE;
+    }
+    DeleteDC( hDC );
+    return bRet;
+  }
+  return FALSE;
+}
+
+/***********************************************************************
+ *           COMBO_NCCreate
+ */
+static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
+{
+    LPHEADCOMBO 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 = 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( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
+              lphc->dwStyle |= CBS_HASSTRINGS;
+	if( !(GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
+	      lphc->wState |= CBF_NOTIFY;
+
+        TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *           COMBO_NCDestroy
+ */
+static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
+{
+
+   if( lphc )
+   {
+       TRACE("[%04x]: freeing storage\n", lphc->self);
+
+       if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
+   	   DestroyWindow( lphc->hWndLBox );
+
+       SetWindowLongA( lphc->self, 0, 0 );
+       HeapFree( GetProcessHeap(), 0, lphc );
+   }
+   return 0;
+}
+
+/***********************************************************************
+ *           CBGetTextAreaHeight
+ *
+ * This method will calculate the height of the text area of the
+ * combobox.
+ * The height of the text area is set in two ways.
+ * It can be set explicitly through a combobox message or through a
+ * WM_MEASUREITEM callback.
+ * If this is not the case, the height is set to 13 dialog units.
+ * This height was determined through experimentation.
+ */
+static INT CBGetTextAreaHeight(
+  HWND        hwnd,
+  LPHEADCOMBO lphc)
+{
+  INT iTextItemHeight;
+
+  if( lphc->editHeight ) /* explicitly set height */
+  {
+    iTextItemHeight = lphc->editHeight;
+  }
+  else
+  {
+    TEXTMETRICW tm;
+    HDC         hDC       = GetDC(hwnd);
+    HFONT       hPrevFont = 0;
+    INT         baseUnitY;
+
+    if (lphc->hFont)
+      hPrevFont = SelectObject( hDC, lphc->hFont );
+
+    GetTextMetricsW(hDC, &tm);
+
+    baseUnitY = tm.tmHeight;
+
+    if( hPrevFont )
+      SelectObject( hDC, hPrevFont );
+
+    ReleaseDC(hwnd, hDC);
+
+    iTextItemHeight = ((13 * baseUnitY) / 8);
+
+    /*
+     * 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();
+  }
+
+  /*
+   * 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;
+    }
+
+    /*
+     * Keep the size for the next time
+     */
+    lphc->editHeight = iTextItemHeight;
+  }
+
+  return iTextItemHeight;
+}
+
+/***********************************************************************
+ *           CBForceDummyResize
+ *
+ * The dummy resize is used for listboxes that have a popup to trigger
+ * a re-arranging of the contents of the combobox and the recalculation
+ * of the size of the "real" control window.
+ */
+static void CBForceDummyResize(
+  LPHEADCOMBO lphc)
+{
+  RECT windowRect;
+  int newComboHeight;
+
+  newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
+
+  GetWindowRect(lphc->self, &windowRect);
+
+  /*
+   * We have to be careful, resizing a combobox also has the meaning that the
+   * dropped rect will be resized. In this case, we want to trigger a resize
+   * to recalculate layout but we don't want to change the dropped rectangle
+   * So, we pass the height of text area of control as the height.
+   * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
+   * message.
+   */
+  SetWindowPos( lphc->self,
+		(HWND)NULL,
+		0, 0,
+		windowRect.right  - windowRect.left,
+		newComboHeight,
+		SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+}
+
+/***********************************************************************
+ *           CBCalcPlacement
+ *
+ * Set up component coordinates given valid lphc->RectCombo.
+ */
+static void CBCalcPlacement(
+  HWND        hwnd,
+  LPHEADCOMBO lphc,
+  LPRECT      lprEdit,
+  LPRECT      lprButton,
+  LPRECT      lprLB)
+{
+  /*
+   * Again, start with the client rectangle.
+   */
+  GetClientRect(hwnd, lprEdit);
+
+  /*
+   * Remove the borders
+   */
+  InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
+
+  /*
+   * Chop off the bottom part to fit with the height of the text area.
+   */
+  lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
+
+  /*
+   * The button starts the same vertical position as the text area.
+   */
+  CopyRect(lprButton, lprEdit);
+
+  /*
+   * If the combobox is "simple" there is no button.
+   */
+  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+    lprButton->left = lprButton->right = lprButton->bottom = 0;
+  else
+  {
+    /*
+     * Let's assume the combobox button is the same width as the
+     * scrollbar button.
+     * size the button horizontally and cut-off the text area.
+     */
+    lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
+    lprEdit->right  = lprButton->left;
+  }
+
+  /*
+   * In the case of a dropdown, there is an additional spacing between the
+   * text area and the button.
+   */
+  if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+  {
+    lprEdit->right -= COMBO_EDITBUTTONSPACE();
+  }
+
+  /*
+   * If we have an edit control, we space it away from the borders slightly.
+   */
+  if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+  {
+    InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
+  }
+
+  /*
+   * Adjust the size of the listbox popup.
+   */
+  if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+  {
+    /*
+     * Use the client rectangle to initialize the listbox rectangle
+     */
+    GetClientRect(hwnd, lprLB);
+
+    /*
+     * Then, chop-off the top part.
+     */
+    lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
+  }
+  else
+  {
+    /*
+     * Make sure the dropped width is as large as the combobox itself.
+     */
+    if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
+    {
+      lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
+
+      /*
+       * In the case of a dropdown, the popup listbox is offset to the right.
+       * so, we want to make sure it's flush with the right side of the
+       * combobox
+       */
+      if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+	lprLB->right -= COMBO_EDITBUTTONSPACE();
+    }
+    else
+       lprLB->right = lprLB->left + lphc->droppedWidth;
+  }
+
+  TRACE("\ttext\t= (%i,%i-%i,%i)\n",
+	lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
+
+  TRACE("\tbutton\t= (%i,%i-%i,%i)\n",
+	lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
+
+  TRACE("\tlbox\t= (%i,%i-%i,%i)\n",
+	lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
+}
+
+/***********************************************************************
+ *           CBGetDroppedControlRect
+ */
+static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
+{
+    /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
+     of the combo box and the lower right corner of the listbox */
+
+    GetWindowRect(lphc->self, lpRect);
+
+    lpRect->right =  lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
+    lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
+
+}
+
+/***********************************************************************
+ *           COMBO_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=%d, oldtop=%d\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
+ */
+static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style )
+{
+  static const WCHAR clbName[] = {'C','o','m','b','o','L','B','o','x',0};
+  static const WCHAR editName[] = {'E','d','i','t',0};
+
+  if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
+  if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+
+  lphc->owner = hwndParent;
+
+  /*
+   * The item height and dropped width are not set when the control
+   * is created.
+   */
+  lphc->droppedWidth = lphc->editHeight = 0;
+
+  /*
+   * The first time we go through, we want to measure the ownerdraw item
+   */
+  lphc->wState |= CBF_MEASUREITEM;
+
+  /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
+
+  if( lphc->owner || !(style & WS_VISIBLE) )
+  {
+      UINT lbeStyle   = 0;
+      UINT lbeExStyle = 0;
+
+      /*
+       * Initialize the dropped rect to the size of the client area of the
+       * control and then, force all the areas of the combobox to be
+       * recalculated.
+       */
+      GetClientRect( hwnd, &lphc->droppedRect );
+      CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect );
+
+      /*
+       * Adjust the position of the popup listbox if it's necessary
+       */
+      if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
+      {
+	lphc->droppedRect.top   = lphc->textRect.bottom + COMBO_YBORDERSIZE();
+
+	/*
+	 * If it's a dropdown, the listbox is offset
+	 */
+	if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+	  lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
+
+	ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect);
+	ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect.right);
+      }
+
+      /* create listbox popup */
+
+      lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
+                 (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
+
+      if( lphc->dwStyle & CBS_SORT )
+	lbeStyle |= LBS_SORT;
+      if( lphc->dwStyle & CBS_HASSTRINGS )
+	lbeStyle |= LBS_HASSTRINGS;
+      if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
+	lbeStyle |= LBS_NOINTEGRALHEIGHT;
+      if( lphc->dwStyle & CBS_DISABLENOSCROLL )
+	lbeStyle |= LBS_DISABLENOSCROLL;
+
+      if( CB_GETTYPE(lphc) == CBS_SIMPLE ) 	/* child listbox */
+      {
+	lbeStyle |= WS_VISIBLE;
+
+	/*
+	 * In win 95 look n feel, the listbox in the simple combobox has
+	 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
+	 */
+	if (TWEAK_WineLook > WIN31_LOOK)
+	{
+	  lbeStyle   &= ~WS_BORDER;
+	  lbeExStyle |= WS_EX_CLIENTEDGE;
+	}
+      }
+
+      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,
+                                       GetWindowLongA( hwnd, GWL_HINSTANCE ), lphc );
+
+      if( lphc->hWndLBox )
+      {
+	  BOOL	bEdit = TRUE;
+	  lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
+
+	  /*
+	   * In Win95 look, the border fo the edit control is
+	   * provided by the combobox
+	   */
+	  if (TWEAK_WineLook == WIN31_LOOK)
+	    lbeStyle |= WS_BORDER;
+
+	  if( lphc->wState & CBF_EDIT )
+	  {
+	      if( lphc->dwStyle & CBS_OEMCONVERT )
+		  lbeStyle |= ES_OEMCONVERT;
+	      if( lphc->dwStyle & CBS_AUTOHSCROLL )
+		  lbeStyle |= ES_AUTOHSCROLL;
+	      if( lphc->dwStyle & CBS_LOWERCASE )
+		  lbeStyle |= ES_LOWERCASE;
+	      else if( lphc->dwStyle & CBS_UPPERCASE )
+		  lbeStyle |= ES_UPPERCASE;
+
+              if (!IsWindowEnabled(hwnd)) lbeStyle |= WS_DISABLED;
+
+	      lphc->hWndEdit = CreateWindowExW(0,
+					       editName,
+					       NULL,
+					       lbeStyle,
+					       lphc->textRect.left, lphc->textRect.top,
+					       lphc->textRect.right - lphc->textRect.left,
+					       lphc->textRect.bottom - lphc->textRect.top,
+                                               hwnd, (HMENU)ID_CB_EDIT,
+                                               GetWindowLongA( hwnd, GWL_HINSTANCE ), NULL );
+
+	      if( !lphc->hWndEdit )
+		bEdit = FALSE;
+	  }
+
+          if( bEdit )
+	  {
+	    if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+	    {
+              /* Now do the trick with parent */
+	      SetParent(lphc->hWndLBox, HWND_DESKTOP);
+              /*
+               * If the combo is a dropdown, we must resize the control
+	       * to fit only the text area and button. To do this,
+	       * we send a dummy resize and the WM_WINDOWPOSCHANGING message
+	       * will take care of setting the height for us.
+               */
+	      CBForceDummyResize(lphc);
+	    }
+
+	    TRACE("init done\n");
+	    return 0;
+	  }
+	  ERR("edit control failure.\n");
+      } else ERR("listbox failure.\n");
+  } else ERR("no owner for visible combo.\n");
+
+  /* CreateWindow() will send WM_NCDESTROY to cleanup */
+
+  return -1;
+}
+
+/***********************************************************************
+ *           CBPaintButton
+ *
+ * Paint combo button (normal, pressed, and disabled states).
+ */
+static void CBPaintButton(
+  LPHEADCOMBO lphc,
+  HDC         hdc,
+  RECT        rectButton)
+{
+    if( lphc->wState & CBF_NOREDRAW )
+      return;
+
+    if (TWEAK_WineLook == WIN31_LOOK)
+    {
+        UINT 	  x, y;
+	BOOL 	  bBool;
+	HDC       hMemDC;
+	HBRUSH    hPrevBrush;
+	COLORREF  oldTextColor, oldBkColor;
+
+
+	hPrevBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
+
+	/*
+	 * Draw the button background
+	 */
+	PatBlt( hdc,
+		rectButton.left,
+		rectButton.top,
+		rectButton.right-rectButton.left,
+		rectButton.bottom-rectButton.top,
+		PATCOPY );
+
+	if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
+	{
+	    DrawEdge( hdc, &rectButton, EDGE_SUNKEN, BF_RECT );
+	}
+	else
+	{
+	    DrawEdge( hdc, &rectButton, EDGE_RAISED, BF_RECT );
+	}
+
+	/*
+	 * Remove the edge of the button from the rectangle
+	 * and calculate the position of the bitmap.
+	 */
+	InflateRect( &rectButton, -2, -2);
+
+	x = (rectButton.left + rectButton.right - CBitWidth) >> 1;
+	y = (rectButton.top + rectButton.bottom - CBitHeight) >> 1;
+
+
+	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, CBitWidth, CBitHeight, hMemDC, 0, 0, SRCCOPY );
+	SetBkColor( hdc, oldBkColor );
+	SetTextColor( hdc, oldTextColor );
+	DeleteDC( hMemDC );
+	SelectObject( hdc, hPrevBrush );
+    }
+    else
+    {
+        UINT buttonState = DFCS_SCROLLCOMBOBOX;
+
+	if (lphc->wState & CBF_BUTTONDOWN)
+	{
+	    buttonState |= DFCS_PUSHED;
+	}
+
+	if (CB_DISABLED(lphc))
+	{
+	  buttonState |= DFCS_INACTIVE;
+	}
+
+	DrawFrameControl(hdc,
+			 &rectButton,
+			 DFC_SCROLL,
+			 buttonState);
+    }
+}
+
+/***********************************************************************
+ *           CBPaintText
+ *
+ * Paint CBS_DROPDOWNLIST text field / update edit control contents.
+ */
+static void CBPaintText(
+  LPHEADCOMBO lphc,
+  HDC         hdc,
+  RECT        rectEdit)
+{
+   INT	id, size = 0;
+   LPWSTR pText = NULL;
+
+   if( lphc->wState & CBF_NOREDRAW ) return;
+
+   TRACE("\n");
+
+   /* follow Windows combobox that sends a bunch of text
+    * inquiries to its listbox while processing WM_PAINT. */
+
+   if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
+   {
+        size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
+        if( (pText = HeapAlloc( GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR))) )
+	{
+            /* 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 )
+   {
+        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 */
+   {
+     UINT	itemState = ODS_COMBOBOXEDIT;
+     HFONT	hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
+
+     /*
+      * 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=(HRGN)NULL;
+       }
+
+       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 ) );
+       }
+
+       ExtTextOutW( hdc,
+		    rectEdit.left + 1,
+		    rectEdit.top + 1,
+		    ETO_OPAQUE | ETO_CLIPPED,
+		    &rectEdit,
+		    pText ? pText : empty_stringW , size, NULL );
+
+       if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
+	 DrawFocusRect( hdc, &rectEdit );
+     }
+
+     if( hPrevFont )
+       SelectObject(hdc, hPrevFont );
+   }
+   if (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 = SendMessageW(lphc->owner, WM_CTLCOLORSTATIC, 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 = SendMessageW(lphc->owner, WM_CTLCOLOREDIT, hDC, (LPARAM)lphc->self );
+    }
+    else
+    {
+      hBkgBrush = SendMessageW(lphc->owner, WM_CTLCOLORLISTBOX, 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
+ */
+static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
+{
+  PAINTSTRUCT ps;
+  HDC 	hDC;
+
+  hDC = (hParamDC) ? hParamDC
+		   : BeginPaint( lphc->self, &ps);
+
+  TRACE("hdc=%04x\n", hDC);
+
+  if( hDC && !(lphc->wState & CBF_NOREDRAW) )
+  {
+      HBRUSH	hPrevBrush, hBkgBrush;
+
+      /*
+       * Retrieve the background brush and select it in the
+       * DC.
+       */
+      hBkgBrush = COMBO_PrepareColors(lphc, hDC);
+
+      hPrevBrush = SelectObject( hDC, hBkgBrush );
+
+      /*
+       * In non 3.1 look, there is a sunken border on the combobox
+       */
+      if (TWEAK_WineLook != WIN31_LOOK)
+      {
+	CBPaintBorder(lphc->self, lphc, hDC);
+      }
+
+      if( !IsRectEmpty(&lphc->buttonRect) )
+      {
+	CBPaintButton(lphc, hDC, lphc->buttonRect);
+      }
+
+      /* paint the edit control padding area */
+      if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+      {
+          RECT rPadEdit = lphc->textRect;
+
+          InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+
+          FrameRect( hDC, &rPadEdit, GetSysColorBrush(COLOR_WINDOW) );
+      }
+
+      if( !(lphc->wState & CBF_EDIT) )
+      {
+	/*
+	 * The text area has a border only in Win 3.1 look.
+	 */
+	if (TWEAK_WineLook == WIN31_LOOK)
+	{
+	  HPEN hPrevPen = SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
+
+	  Rectangle( hDC,
+		     lphc->textRect.left, lphc->textRect.top,
+		     lphc->textRect.right - 1, lphc->textRect.bottom - 1);
+
+	  SelectObject( hDC, hPrevPen );
+	}
+
+	CBPaintText( lphc, hDC, lphc->textRect);
+      }
+
+      if( hPrevBrush )
+	SelectObject( hDC, hPrevBrush );
+  }
+
+  if( !hParamDC )
+    EndPaint(lphc->self, &ps);
+
+  return 0;
+}
+
+/***********************************************************************
+ *           CBUpdateLBox
+ *
+ * Select listbox entry according to the contents of the edit control.
+ */
+static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
+{
+   INT	length, idx;
+   LPWSTR pText = NULL;
+
+   idx = LB_ERR;
+   length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
+
+   if( length > 0 )
+       pText = HeapAlloc( GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR));
+
+   TRACE("\t edit text length %i\n", length );
+
+   if( pText )
+   {
+       if( length ) GetWindowTextW( lphc->hWndEdit, pText, length + 1);
+       else pText[0] = '\0';
+       idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING,
+			     (WPARAM)(-1), (LPARAM)pText );
+       HeapFree( GetProcessHeap(), 0, pText );
+   }
+
+   SendMessageW(lphc->hWndLBox, LB_SETCURSEL, (WPARAM)(bSelect ? idx : -1), 0);
+
+   /* 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;
+}
+
+/***********************************************************************
+ *           CBUpdateEdit
+ *
+ * Copy a listbox entry to the edit control.
+ */
+static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
+{
+   INT	length;
+   LPWSTR pText = NULL;
+   static const WCHAR empty_stringW[] = { 0 };
+
+   TRACE("\t %i\n", index );
+
+   if( index >= 0 ) /* got an entry */
+   {
+       length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
+       if( length )
+       {
+	   if( (pText = HeapAlloc( GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR))) )
+	   {
+		SendMessageW(lphc->hWndLBox, LB_GETTEXT,
+				(WPARAM)index, (LPARAM)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 )
+{
+   RECT rect,r;
+   int nItems = 0;
+   int nDroppedHeight;
+
+   TRACE("[%04x]: drop down\n", lphc->self);
+
+   CB_NOTIFY( lphc, CBN_DROPDOWN );
+
+   /* set selection */
+
+   lphc->wState |= CBF_DROPPED;
+   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+   {
+       lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
+
+       /* Update edit only if item is in the list */
+       if( !(lphc->wState & CBF_CAPTURE) && lphc->droppedIndex >= 0)
+	 CBUpdateEdit( lphc, lphc->droppedIndex );
+   }
+   else
+   {
+       lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+       SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
+                     (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;
+
+      nHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
+      nHeight *= nItems;
+
+      if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
+         nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
+   }
+
+   /*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);
+
+
+   if( !(lphc->wState & CBF_NOREDRAW) )
+     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
+			   RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+
+   EnableWindow( lphc->hWndLBox, TRUE );
+   if (GetCapture() != lphc->self)
+      SetCapture(lphc->hWndLBox);
+}
+
+/***********************************************************************
+ *           CBRollUp
+ *
+ * Hide listbox popup.
+ */
+static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
+{
+   HWND	hWnd = lphc->self;
+
+   TRACE("[%04x]: 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 )
+   {
+
+       if( lphc->wState & CBF_DROPPED )
+       {
+	   RECT	rect;
+
+	   lphc->wState &= ~CBF_DROPPED;
+	   ShowWindow( lphc->hWndLBox, SW_HIDE );
+
+           if(GetCapture() == lphc->hWndLBox)
+           {
+               ReleaseCapture();
+           }
+
+	   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+	   {
+	       rect = lphc->buttonRect;
+	   }
+	   else
+           {
+	       if( bButton )
+	       {
+		 UnionRect( &rect,
+			    &lphc->buttonRect,
+			    &lphc->textRect);
+	       }
+	       else
+		 rect = lphc->textRect;
+
+	       bButton = TRUE;
+	   }
+
+	   if( bButton && !(lphc->wState & CBF_NOREDRAW) )
+	       RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
+			       RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+	   CB_NOTIFY( lphc, CBN_CLOSEUP );
+       }
+   }
+}
+
+/***********************************************************************
+ *           COMBO_FlipListbox
+ *
+ * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
+ */
+BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
+{
+   if( lphc->wState & CBF_DROPPED )
+   {
+       CBRollUp( lphc, ok, bRedrawButton );
+       return FALSE;
+   }
+
+   CBDropDown( lphc );
+   return TRUE;
+}
+
+/***********************************************************************
+ *           CBRepaintButton
+ */
+static void CBRepaintButton( LPHEADCOMBO lphc )
+   {
+  InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
+  UpdateWindow(lphc->self);
+}
+
+/***********************************************************************
+ *           COMBO_SetFocus
+ */
+static void COMBO_SetFocus( LPHEADCOMBO lphc )
+{
+   if( !(lphc->wState & CBF_FOCUSED) )
+   {
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+           SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
+
+       /* This is wrong. Message sequences seem to indicate that this
+          is set *after* the notify. */
+       /* lphc->wState |= CBF_FOCUSED;  */
+
+       if( !(lphc->wState & CBF_EDIT) )
+	 InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+       CB_NOTIFY( lphc, CBN_SETFOCUS );
+       lphc->wState |= CBF_FOCUSED;
+   }
+}
+
+/***********************************************************************
+ *           COMBO_KillFocus
+ */
+static void COMBO_KillFocus( LPHEADCOMBO lphc )
+{
+   HWND	hWnd = lphc->self;
+
+   if( lphc->wState & CBF_FOCUSED )
+   {
+       CBRollUp( lphc, FALSE, TRUE );
+       if( IsWindow( hWnd ) )
+       {
+           if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+               SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
+
+ 	   lphc->wState &= ~CBF_FOCUSED;
+
+           /* redraw text */
+	   if( !(lphc->wState & CBF_EDIT) )
+	     InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+           CB_NOTIFY( lphc, CBN_KILLFOCUS );
+       }
+   }
+}
+
+/***********************************************************************
+ *           COMBO_Command
+ */
+static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
+{
+   if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
+   {
+       /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
+
+       switch( HIWORD(wParam) >> 8 )
+       {
+	   case (EN_SETFOCUS >> 8):
+
+		TRACE("[%04x]: edit [%04x] got focus\n",
+			     lphc->self, lphc->hWndEdit );
+
+		COMBO_SetFocus( lphc );
+	        break;
+
+	   case (EN_KILLFOCUS >> 8):
+
+		TRACE("[%04x]: edit [%04x] lost focus\n",
+			     lphc->self, lphc->hWndEdit );
+
+		/* NOTE: it seems that Windows' edit control sends an
+		 * undocumented message WM_USER + 0x1B instead of this
+		 * notification (only when it happens to be a part of
+		 * the combo). ?? - AK.
+		 */
+
+		COMBO_KillFocus( lphc );
+		break;
+
+
+	   case (EN_CHANGE >> 8):
+	       /*
+	        * In some circumstances (when the selection of the combobox
+		* is changed for example) we don't 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):
+	        if (!(lphc->wState & CBF_NOEDITNOTIFY))
+		  CB_NOTIFY( lphc, CBN_EDITUPDATE );
+		break;
+
+	   case (EN_ERRSPACE >> 8):
+		CB_NOTIFY( lphc, CBN_ERRSPACE );
+       }
+   }
+   else if( lphc->hWndLBox == hWnd )
+   {
+       switch( HIWORD(wParam) )
+       {
+	   case LBN_ERRSPACE:
+		CB_NOTIFY( lphc, CBN_ERRSPACE );
+		break;
+
+	   case LBN_DBLCLK:
+		CB_NOTIFY( lphc, CBN_DBLCLK );
+		break;
+
+	   case LBN_SELCHANGE:
+	   case LBN_SELCANCEL:
+
+		TRACE("[%04x]: lbox selection change [%04x]\n",
+			     lphc->self, lphc->wState );
+
+		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);
+		}
+
+		/* 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 );
+
+		/* fall through */
+
+	   case LBN_SETFOCUS:
+	   case LBN_KILLFOCUS:
+		/* nothing to do here since ComboLBox always resets the focus to its
+		 * combo/edit counterpart */
+		 break;
+       }
+   }
+   return 0;
+}
+
+/***********************************************************************
+ *           COMBO_ItemOp
+ *
+ * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
+ */
+static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
+{
+   HWND hWnd = lphc->self;
+   UINT id = GetWindowLongA( hWnd, GWL_ID );
+
+   TRACE("[%04x]: ownerdraw op %04x\n", lphc->self, msg );
+
+   switch( msg )
+   {
+   case WM_DELETEITEM:
+       {
+           DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_DRAWITEM:
+       {
+           DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_COMPAREITEM:
+       {
+           COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           lpIS->hwndItem = hWnd;
+           break;
+       }
+   case WM_MEASUREITEM:
+       {
+           MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
+           lpIS->CtlType  = ODT_COMBOBOX;
+           lpIS->CtlID    = id;
+           break;
+       }
+   }
+   return SendMessageW(lphc->owner, msg, id, lParam);
+}
+
+/***********************************************************************
+ *           COMBO_GetText
+ *
+ * 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_GetText( LPHEADCOMBO lphc, INT N, LPARAM lParam, BOOL unicode)
+{
+   if( lphc->wState & CBF_EDIT )
+       return unicode ? SendMessageW(lphc->hWndEdit, WM_GETTEXT, (WPARAM)N, lParam) :
+                        SendMessageA(lphc->hWndEdit, WM_GETTEXT, (WPARAM)N, lParam);
+
+   /* get it from the listbox */
+
+   if( lphc->hWndLBox )
+   {
+       INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+       if( idx != LB_ERR )
+       {
+	   INT n = 0;
+           INT length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN,
+					        (WPARAM)idx, 0 );
+
+	    if(unicode)
+	    {
+		LPWSTR lpBuffer, lpText = (LPWSTR)lParam;
+
+		/* 'length' is without the terminating character */
+		if(length >= N)
+		    lpBuffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR));
+		else
+		    lpBuffer = lpText;
+
+		if(lpBuffer)
+		{
+		    n = SendMessageW(lphc->hWndLBox, LB_GETTEXT, (WPARAM)idx, (LPARAM)lpBuffer);
+
+		    /* truncate if buffer is too short */
+		    if(length >= N)
+		    {
+			if(N && lpText)
+			{
+			    if(n != LB_ERR)
+				strncpyW(lpText, lpBuffer, (N > n) ? n+1 : N-1);
+			    lpText[N - 1] = '\0';
+			}
+	                HeapFree( GetProcessHeap(), 0, lpBuffer );
+                   }
+	       }
+	   }
+	   else
+	   {
+		LPSTR lpBuffer, lpText = (LPSTR)lParam;
+
+		/* 'length' is without the terminating character */
+		if(length >= N)
+		    lpBuffer = HeapAlloc(GetProcessHeap(), 0, length + 1);
+		else
+		    lpBuffer = lpText;
+
+		if(lpBuffer)
+		{
+		    n = SendMessageA(lphc->hWndLBox, LB_GETTEXT, (WPARAM)idx, (LPARAM)lpBuffer);
+
+		    /* truncate if buffer is too short */
+		    if(length >= N)
+		    {
+			if(N && lpText)
+			{
+			    if(n != LB_ERR)
+				strncpy(lpText, lpBuffer, (N > n) ? n+1 : N-1);
+			    lpText[N - 1] = '\0';
+			}
+	                HeapFree( GetProcessHeap(), 0, lpBuffer );
+                   }
+	       }
+	   }
+	   if (n<0)
+	       n=0;
+	   else
+	       n++;
+	   return (LRESULT)n;
+       }
+   }
+   return 0;
+}
+
+
+/***********************************************************************
+ *           CBResetPos
+ *
+ * This function sets window positions according to the updated
+ * component placement struct.
+ */
+static void CBResetPos(
+  LPHEADCOMBO lphc,
+  LPRECT      rectEdit,
+  LPRECT      rectLB,
+  BOOL        bRedraw)
+{
+   BOOL	bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
+
+   /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
+    * sizing messages */
+
+   if( lphc->wState & CBF_EDIT )
+     SetWindowPos( lphc->hWndEdit, 0,
+		   rectEdit->left, rectEdit->top,
+		   rectEdit->right - rectEdit->left,
+		   rectEdit->bottom - rectEdit->top,
+                       SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   SetWindowPos( lphc->hWndLBox, 0,
+		 rectLB->left, rectLB->top,
+                 rectLB->right - rectLB->left,
+		 rectLB->bottom - rectLB->top,
+		   SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   if( bDrop )
+   {
+       if( lphc->wState & CBF_DROPPED )
+       {
+           lphc->wState &= ~CBF_DROPPED;
+           ShowWindow( lphc->hWndLBox, SW_HIDE );
+       }
+
+       if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
+           RedrawWindow( lphc->self, NULL, 0,
+                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
+   }
+}
+
+
+/***********************************************************************
+ *           COMBO_Size
+ */
+static void COMBO_Size( LPHEADCOMBO lphc )
+  {
+  CBCalcPlacement(lphc->self,
+		  lphc,
+		  &lphc->textRect,
+		  &lphc->buttonRect,
+		  &lphc->droppedRect);
+
+  CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+}
+
+
+/***********************************************************************
+ *           COMBO_Font
+ */
+static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
+{
+  /*
+   * Set the font
+   */
+  lphc->hFont = hFont;
+
+  /*
+   * Propagate to owned windows.
+   */
+  if( lphc->wState & CBF_EDIT )
+      SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
+  SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
+
+  /*
+   * Redo the layout of the control.
+   */
+  if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+  {
+    CBCalcPlacement(lphc->self,
+		    lphc,
+		    &lphc->textRect,
+		    &lphc->buttonRect,
+		    &lphc->droppedRect);
+
+    CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+  }
+  else
+  {
+    CBForceDummyResize(lphc);
+  }
+}
+
+
+/***********************************************************************
+ *           COMBO_SetItemHeight
+ */
+static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
+{
+   LRESULT	lRet = CB_ERR;
+
+   if( index == -1 ) /* set text field height */
+   {
+       if( height < 32768 )
+       {
+           lphc->editHeight = height;
+
+	 /*
+	  * Redo the layout of the control.
+	  */
+	 if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+	 {
+	   CBCalcPlacement(lphc->self,
+			   lphc,
+			   &lphc->textRect,
+			   &lphc->buttonRect,
+			   &lphc->droppedRect);
+
+	   CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+	 }
+	 else
+	 {
+	   CBForceDummyResize(lphc);
+	 }
+
+	   lRet = height;
+       }
+   }
+   else if ( CB_OWNERDRAWN(lphc) )	/* set listbox item height */
+	lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT,
+			      (WPARAM)index, (LPARAM)height );
+   return lRet;
+}
+
+/***********************************************************************
+ *           COMBO_SelectString
+ */
+static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText, BOOL unicode )
+{
+   INT index = unicode ? SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText) :
+                         SendMessageA(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText);
+   if( index >= 0 )
+   {
+     if( lphc->wState & CBF_EDIT )
+       CBUpdateEdit( lphc, index );
+     else
+     {
+       InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+     }
+   }
+   return (LRESULT)index;
+}
+
+/***********************************************************************
+ *           COMBO_LButtonDown
+ */
+static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
+{
+   POINT     pt;
+   BOOL      bButton;
+   HWND      hWnd = lphc->self;
+
+   pt.x = LOWORD(lParam);
+   pt.y = HIWORD(lParam);
+   bButton = PtInRect(&lphc->buttonRect, pt);
+
+   if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
+       (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
+   {
+       lphc->wState |= CBF_BUTTONDOWN;
+       if( lphc->wState & CBF_DROPPED )
+       {
+	   /* got a click to cancel selection */
+
+           lphc->wState &= ~CBF_BUTTONDOWN;
+           CBRollUp( lphc, TRUE, FALSE );
+	   if( !IsWindow( hWnd ) ) return;
+
+           if( lphc->wState & CBF_CAPTURE )
+           {
+               lphc->wState &= ~CBF_CAPTURE;
+               ReleaseCapture();
+           }
+       }
+       else
+       {
+	   /* drop down the listbox and start tracking */
+
+           lphc->wState |= CBF_CAPTURE;
+           SetCapture( hWnd );
+           CBDropDown( lphc );
+       }
+       if( bButton ) CBRepaintButton( lphc );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_LButtonUp
+ *
+ * Release capture and stop tracking if needed.
+ */
+static void COMBO_LButtonUp( LPHEADCOMBO lphc )
+{
+   if( lphc->wState & CBF_CAPTURE )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+       {
+	   INT index = CBUpdateLBox( lphc, TRUE );
+	   /* Update edit only if item is in the list */
+	   if(index >= 0)
+	   {
+	       lphc->wState |= CBF_NOLBSELECT;
+	       CBUpdateEdit( lphc, index );
+	       lphc->wState &= ~CBF_NOLBSELECT;
+	   }
+       }
+       ReleaseCapture();
+       SetCapture(lphc->hWndLBox);
+   }
+
+   if( lphc->wState & CBF_BUTTONDOWN )
+   {
+       lphc->wState &= ~CBF_BUTTONDOWN;
+       CBRepaintButton( lphc );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_MouseMove
+ *
+ * Two things to do - track combo button and release capture when
+ * pointer goes into the listbox.
+ */
+static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
+{
+   POINT  pt;
+   RECT   lbRect;
+
+   pt.x = LOWORD(lParam);
+   pt.y = HIWORD(lParam);
+
+   if( lphc->wState & CBF_BUTTONDOWN )
+   {
+     BOOL bButton;
+
+     bButton = PtInRect(&lphc->buttonRect, pt);
+
+     if( !bButton )
+     {
+       lphc->wState &= ~CBF_BUTTONDOWN;
+       CBRepaintButton( lphc );
+     }
+   }
+
+   GetClientRect( lphc->hWndLBox, &lbRect );
+   MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
+   if( PtInRect(&lbRect, pt) )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       ReleaseCapture();
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
+
+       /* hand over pointer tracking */
+       SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
+   }
+}
+
+
+/***********************************************************************
+ *           ComboWndProc_common
+ *
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
+ */
+static LRESULT ComboWndProc_common( HWND hwnd, UINT message,
+                                    WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+      LPHEADCOMBO lphc = (LPHEADCOMBO)GetWindowLongA( hwnd, 0 );
+
+      TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
+            hwnd, SPY_GetMsgName(message, hwnd), wParam, lParam );
+
+      if( lphc || message == WM_NCCREATE )
+      switch(message)
+      {
+
+	/* System messages */
+
+     	case WM_NCCREATE:
+	{
+		LONG style = unicode ? ((LPCREATESTRUCTW)lParam)->style :
+				       ((LPCREATESTRUCTA)lParam)->style;
+                return COMBO_NCCreate(hwnd, style);
+	}
+     	case WM_NCDESTROY:
+		COMBO_NCDestroy(lphc);
+		break;/* -> DefWindowProc */
+
+     	case WM_CREATE:
+	{
+		HWND hwndParent;
+		LONG style;
+		if(unicode)
+		{
+		    hwndParent = ((LPCREATESTRUCTW)lParam)->hwndParent;
+		    style = ((LPCREATESTRUCTW)lParam)->style;
+		}
+		else
+		{
+		    hwndParent = ((LPCREATESTRUCTA)lParam)->hwndParent;
+		    style = ((LPCREATESTRUCTA)lParam)->style;
+		}
+                return COMBO_Create(hwnd, lphc, hwndParent, style);
+	}
+
+        case WM_PRINTCLIENT:
+	        if (lParam & PRF_ERASEBKGND)
+		  COMBO_EraseBackground(hwnd, lphc, wParam);
+
+		/* Fallthrough */
+     	case WM_PAINT:
+		/* wParam may contain a valid HDC! */
+		return  COMBO_Paint(lphc, wParam);
+	case WM_ERASEBKGND:
+		return  COMBO_EraseBackground(hwnd, lphc, 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 &&
+		  !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
+		return  TRUE;
+	case WM_SETFONT:
+		COMBO_Font( lphc, (HFONT16)wParam, (BOOL)lParam );
+		return  TRUE;
+	case WM_GETFONT:
+		return  (LRESULT)lphc->hFont;
+	case WM_SETFOCUS:
+		if( lphc->wState & CBF_EDIT )
+		    SetFocus( lphc->hWndEdit );
+		else
+		    COMBO_SetFocus( lphc );
+		return  TRUE;
+	case WM_KILLFOCUS:
+            {
+                HWND hwndFocus = WIN_GetFullHandle( (HWND)wParam );
+		if( !hwndFocus ||
+		    (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
+		    COMBO_KillFocus( lphc );
+		return  TRUE;
+            }
+	case WM_COMMAND:
+		return  COMBO_Command( lphc, wParam, WIN_GetFullHandle( (HWND)lParam ) );
+	case WM_GETTEXT:
+		return COMBO_GetText( lphc, (INT)wParam, lParam, unicode );
+	case WM_SETTEXT:
+	case WM_GETTEXTLENGTH:
+	case WM_CLEAR:
+                if ((message == WM_GETTEXTLENGTH) && !ISWIN31 && !(lphc->wState & CBF_EDIT))
+                {
+                int j = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+                if (j == -1) return 0;
+                return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
+                }
+		else if( lphc->wState & CBF_EDIT )
+		{
+		    LRESULT ret;
+		    lphc->wState |= CBF_NOEDITNOTIFY;
+		    ret = unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
+				    SendMessageA(lphc->hWndEdit, message, wParam, lParam);
+		    lphc->wState &= ~CBF_NOEDITNOTIFY;
+		    return ret;
+		}
+		else return CB_ERR;
+	case WM_CUT:
+        case WM_PASTE:
+	case WM_COPY:
+		if( lphc->wState & CBF_EDIT )
+		{
+		    return unicode ? SendMessageW(lphc->hWndEdit, message, wParam, lParam) :
+				     SendMessageA(lphc->hWndEdit, message, wParam, lParam);
+		}
+		else return  CB_ERR;
+
+	case WM_DRAWITEM:
+	case WM_DELETEITEM:
+	case WM_COMPAREITEM:
+	case WM_MEASUREITEM:
+		return COMBO_ItemOp(lphc, message, lParam);
+	case WM_ENABLE:
+		if( lphc->wState & CBF_EDIT )
+		    EnableWindow( lphc->hWndEdit, (BOOL)wParam );
+		EnableWindow( lphc->hWndLBox, (BOOL)wParam );
+
+		/* Force the control to repaint when the enabled state changes. */
+		InvalidateRect(lphc->self, NULL, TRUE);
+		return  TRUE;
+	case WM_SETREDRAW:
+		if( wParam )
+		    lphc->wState &= ~CBF_NOREDRAW;
+		else
+		    lphc->wState |= CBF_NOREDRAW;
+
+		if( lphc->wState & CBF_EDIT )
+		    SendMessageW(lphc->hWndEdit, message, wParam, lParam);
+		SendMessageW(lphc->hWndLBox, message, wParam, lParam);
+		return  0;
+	case WM_SYSKEYDOWN:
+		if( KEYDATA_ALT & HIWORD(lParam) )
+		    if( wParam == VK_UP || wParam == VK_DOWN )
+			COMBO_FlipListbox( lphc, FALSE, FALSE );
+                return  0;
+
+	case WM_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;
+		}
+
+		if( lphc->wState & CBF_EDIT )
+		    hwndTarget = lphc->hWndEdit;
+		else
+		    hwndTarget = lphc->hWndLBox;
+
+		return unicode ? SendMessageW(hwndTarget, message, wParam, lParam) :
+				 SendMessageA(hwndTarget, message, wParam, lParam);
+	}
+	case WM_LBUTTONDOWN:
+		if( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self );
+		if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
+		return  TRUE;
+	case WM_LBUTTONUP:
+		COMBO_LButtonUp( lphc );
+		return  TRUE;
+	case WM_MOUSEMOVE:
+		if( lphc->wState & CBF_CAPTURE )
+		    COMBO_MouseMove( lphc, wParam, lParam );
+		return  TRUE;
+
+        case WM_MOUSEWHEEL:
+                if (wParam & (MK_SHIFT | MK_CONTROL))
+                    return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
+				     DefWindowProcA(hwnd, message, wParam, lParam);
+                if (SHIWORD(wParam) > 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_UP, 0);
+                if (SHIWORD(wParam) < 0) return SendMessageW(hwnd, WM_KEYDOWN, VK_DOWN, 0);
+                return TRUE;
+
+	/* Combo messages */
+
+	case CB_ADDSTRING16:
+		if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_ADDSTRING:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam) :
+				 SendMessageA(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+	case CB_INSERTSTRING16:
+		wParam = (INT)(INT16)wParam;
+		if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_INSERTSTRING:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam) :
+				 SendMessageA(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+	case CB_DELETESTRING16:
+	case CB_DELETESTRING:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0) :
+				 SendMessageA(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
+	case CB_SELECTSTRING16:
+		wParam = (INT)(INT16)wParam;
+		if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_SELECTSTRING:
+		return COMBO_SelectString(lphc, (INT)wParam, lParam, unicode);
+	case CB_FINDSTRING16:
+		wParam = (INT)(INT16)wParam;
+		if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_FINDSTRING:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam) :
+				 SendMessageA(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
+	case CB_FINDSTRINGEXACT16:
+		wParam = (INT)(INT16)wParam;
+		if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_FINDSTRINGEXACT:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam) :
+				 SendMessageA(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
+	case CB_SETITEMHEIGHT16:
+		wParam = (INT)(INT16)wParam;	/* signed integer */
+		/* fall through */
+	case CB_SETITEMHEIGHT:
+		return  COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
+	case CB_GETITEMHEIGHT16:
+		wParam = (INT)(INT16)wParam;
+		/* fall through */
+	case CB_GETITEMHEIGHT:
+		if( (INT)wParam >= 0 )	/* listbox item */
+                    return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
+                return  CBGetTextAreaHeight(hwnd, lphc);
+	case CB_RESETCONTENT16:
+	case CB_RESETCONTENT:
+		SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
+                if( (lphc->wState & CBF_EDIT) && CB_HASSTRINGS(lphc) )
+		{
+		    static const WCHAR empty_stringW[] = { 0 };
+                    SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)empty_stringW);
+		}
+                else
+                    InvalidateRect(lphc->self, NULL, TRUE);
+		return  TRUE;
+	case CB_INITSTORAGE:
+		return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
+	case CB_GETHORIZONTALEXTENT:
+		return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
+	case CB_SETHORIZONTALEXTENT:
+		return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
+	case CB_GETTOPINDEX:
+		return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
+	case CB_GETLOCALE:
+		return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
+	case CB_SETLOCALE:
+		return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
+	case CB_GETDROPPEDWIDTH:
+		if( lphc->droppedWidth )
+                    return  lphc->droppedWidth;
+		return  lphc->droppedRect.right - lphc->droppedRect.left;
+	case CB_SETDROPPEDWIDTH:
+		if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
+		    (INT)wParam < 32768 ) lphc->droppedWidth = (INT)wParam;
+		return  CB_ERR;
+	case CB_GETDROPPEDCONTROLRECT16:
+		lParam = (LPARAM)MapSL(lParam);
+		if( lParam )
+		{
+		    RECT	r;
+		    CBGetDroppedControlRect( lphc, &r );
+		    CONV_RECT32TO16( &r, (LPRECT16)lParam );
+		}
+		return  CB_OKAY;
+	case CB_GETDROPPEDCONTROLRECT:
+		if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
+		return  CB_OKAY;
+	case CB_GETDROPPEDSTATE16:
+	case CB_GETDROPPEDSTATE:
+		return  (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
+	case CB_DIR16:
+                lParam = (LPARAM)MapSL(lParam);
+		message = LB_DIR16;
+                /* fall through */
+	case CB_DIR:
+		if(message == CB_DIR) message = LB_DIR;
+		return unicode ? SendMessageW(lphc->hWndLBox, message, wParam, lParam) :
+				 SendMessageA(lphc->hWndLBox, message, wParam, lParam);
+
+	case CB_SHOWDROPDOWN16:
+	case CB_SHOWDROPDOWN:
+		if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+		{
+		    if( wParam )
+		    {
+			if( !(lphc->wState & CBF_DROPPED) )
+			    CBDropDown( lphc );
+		    }
+		    else
+			if( lphc->wState & CBF_DROPPED )
+		            CBRollUp( lphc, FALSE, TRUE );
+		}
+		return  TRUE;
+	case CB_GETCOUNT16:
+	case CB_GETCOUNT:
+		return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+	case CB_GETCURSEL16:
+	case CB_GETCURSEL:
+		return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+	case CB_SETCURSEL16:
+		wParam = (INT)(INT16)wParam;
+		/* fall through */
+	case CB_SETCURSEL:
+		lParam = SendMessageW(lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
+	        if( lParam >= 0 )
+	            SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
+
+		/* no LBN_SELCHANGE in this case, update manually */
+		if( lphc->wState & CBF_EDIT )
+		    CBUpdateEdit( lphc, (INT)wParam );
+		else
+		    InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+		lphc->wState &= ~CBF_SELCHANGE;
+	        return  lParam;
+	case CB_GETLBTEXT16:
+		wParam = (INT)(INT16)wParam;
+		lParam = (LPARAM)MapSL(lParam);
+		/* fall through */
+	case CB_GETLBTEXT:
+		return unicode ? SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam) :
+				 SendMessageA(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
+	case CB_GETLBTEXTLEN16:
+		wParam = (INT)(INT16)wParam;
+		/* fall through */
+	case CB_GETLBTEXTLEN:
+		return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
+	case CB_GETITEMDATA16:
+		wParam = (INT)(INT16)wParam;
+		/* fall through */
+	case CB_GETITEMDATA:
+		return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
+	case CB_SETITEMDATA16:
+		wParam = (INT)(INT16)wParam;
+		/* fall through */
+	case CB_SETITEMDATA:
+		return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
+	case CB_GETEDITSEL16:
+		wParam = lParam = 0;   /* just in case */
+		/* fall through */
+	case CB_GETEDITSEL:
+		/* Edit checks passed parameters itself */
+		if( lphc->wState & CBF_EDIT )
+		    return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
+		return  CB_ERR;
+	case CB_SETEDITSEL16:
+	case CB_SETEDITSEL:
+		if( lphc->wState & CBF_EDIT )
+                    return SendMessageW(lphc->hWndEdit, EM_SETSEL,
+			  (INT)(INT16)LOWORD(lParam), (INT)(INT16)HIWORD(lParam) );
+		return  CB_ERR;
+	case CB_SETEXTENDEDUI16:
+	case CB_SETEXTENDEDUI:
+                if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+                    return  CB_ERR;
+		if( wParam )
+		    lphc->wState |= CBF_EUI;
+		else lphc->wState &= ~CBF_EUI;
+		return  CB_OKAY;
+	case CB_GETEXTENDEDUI16:
+	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);
+}
+
+/***********************************************************************
+ *           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 );
+}
+
+/***********************************************************************
+ *           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 );
+}
Index: trunk/src/user32/controls.cpp
===================================================================
--- trunk/src/user32/controls.cpp	(revision 9522)
+++ trunk/src/user32/controls.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: controls.cpp,v 1.10 2000-02-16 14:34:08 sandervl Exp $ */
+/* $Id: controls.cpp,v 1.11 2002-12-18 12:28:02 sandervl Exp $ */
 /* File: controls.cpp -- Win32 common controls
  *
@@ -13,12 +13,13 @@
 #include "static.h"
 #include "scroll.h"
-#include "combo.h" //listbox,combo,edit
 #include "win32wmdiclient.h"
 #include "win32dlg.h"
 #include "win32wdesktop.h"
+#include "win32class.h"
 #include "winswitch.h"
 #include "icontitle.h"
 #include "menu.h"
 #include "controls.h"
+#include "ctrlconf.h"
 
 #define DBG_LOCALLOG	DBG_controls
@@ -51,21 +52,59 @@
 
   dprintf(("Register LISTBOX class"));
-  controlAtoms[LISTBOX_CONTROL] = LISTBOX_Register();
+  controlAtoms[LISTBOX_CONTROL] = 
+          InternalRegisterClass((LPSTR)LISTBOX_builtin_class.name,
+                                LISTBOX_builtin_class.style,
+                                LISTBOX_builtin_class.procA,
+                                LISTBOX_builtin_class.procW,
+                                LISTBOX_builtin_class.extra,
+                                LISTBOX_builtin_class.cursor,
+                                LISTBOX_builtin_class.brush);
+
   if (!controlAtoms[LISTBOX_CONTROL]) dprintf(("failed!!!"));
 
   dprintf(("Register COMBOLBOX class"));
-  controlAtoms[COMBOLBOX_CONTROL] = COMBOLBOX_Register();
+  controlAtoms[COMBOLBOX_CONTROL] = 
+          InternalRegisterClass((LPSTR)COMBOLBOX_builtin_class.name,
+                                COMBOLBOX_builtin_class.style,
+                                COMBOLBOX_builtin_class.procA,
+                                COMBOLBOX_builtin_class.procW,
+                                COMBOLBOX_builtin_class.extra,
+                                COMBOLBOX_builtin_class.cursor,
+                                COMBOLBOX_builtin_class.brush);
   if (!controlAtoms[COMBOLBOX_CONTROL]) dprintf(("failed!!!"));
 
   dprintf(("Register COMBOBOX class"));
-  controlAtoms[COMBOBOX_CONTROL] = COMBOBOX_Register();
+  controlAtoms[COMBOBOX_CONTROL] = 
+          InternalRegisterClass((LPSTR)COMBO_builtin_class.name,
+                                COMBO_builtin_class.style,
+                                COMBO_builtin_class.procA,
+                                COMBO_builtin_class.procW,
+                                COMBO_builtin_class.extra,
+                                COMBO_builtin_class.cursor,
+                                COMBO_builtin_class.brush);
   if (!controlAtoms[COMBOBOX_CONTROL]) dprintf(("failed!!!"));
 
   dprintf(("Register EDIT class"));
-  controlAtoms[EDIT_CONTROL] = EDIT_Register();
+  controlAtoms[EDIT_CONTROL] = 
+          InternalRegisterClass((LPSTR)EDIT_builtin_class.name,
+                                EDIT_builtin_class.style,
+                                EDIT_builtin_class.procA,
+                                EDIT_builtin_class.procW,
+                                EDIT_builtin_class.extra,
+                                EDIT_builtin_class.cursor,
+                                EDIT_builtin_class.brush);
   if (!controlAtoms[EDIT_CONTROL]) dprintf(("failed!!!"));
 
   dprintf(("Register MDICLIENT class"));
-  controlAtoms[MDICLIENT_CONTROL] = MDICLIENT_Register();
+  controlAtoms[MDICLIENT_CONTROL] = 
+          InternalRegisterClass((LPSTR)MDICLIENT_builtin_class.name,
+                                MDICLIENT_builtin_class.style,
+                                MDICLIENT_builtin_class.procA,
+                                MDICLIENT_builtin_class.procW,
+                                MDICLIENT_builtin_class.extra,
+                                MDICLIENT_builtin_class.cursor,
+//Default brush is ugly light gray; use this one instead
+                                GetStockObject(GRAY_BRUSH));
+//                                MDICLIENT_builtin_class.brush);
   if (!controlAtoms[MDICLIENT_CONTROL]) dprintf(("failed!!!"));
 
@@ -99,17 +138,17 @@
 
   dprintf(("Unregister LISTBOX class"));
-  if (!LISTBOX_Unregister()) dprintf(("failed!!!"));
+  if (!UnregisterClassA((LPSTR)LISTBOX_builtin_class.name, NULL)) dprintf(("failed!!!"));
 
   dprintf(("Unregister COMBOLBOX class"));
-  if (!COMBOLBOX_Unregister()) dprintf(("failed!!!"));
+  if (!UnregisterClassA((LPSTR)COMBOLBOX_builtin_class.name, NULL)) dprintf(("failed!!!"));
 
   dprintf(("Unregister COMBOBOX class"));
-  if (!COMBOBOX_Unregister()) dprintf(("failed!!!"));
+  if (!UnregisterClassA((LPSTR)COMBO_builtin_class.name, NULL)) dprintf(("failed!!!"));
 
   dprintf(("Unregister EDIT class"));
-  if (!EDIT_Unregister()) dprintf(("failed!!!"));
+  if (!UnregisterClassA((LPSTR)EDIT_builtin_class.name, NULL)) dprintf(("failed!!!"));
 
   dprintf(("Unregister MDICLIENT class"));
-  if (!MDICLIENT_Unregister()) dprintf(("failed!!!"));
+  if (!UnregisterClassA((LPSTR)MDICLIENT_builtin_class.name, NULL)) dprintf(("failed!!!"));
 
   dprintf(("Unregister DIALOG class"));
Index: trunk/src/user32/controls.h
===================================================================
--- trunk/src/user32/controls.h	(revision 9522)
+++ trunk/src/user32/controls.h	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: controls.h,v 1.5 2001-04-26 17:02:28 sandervl Exp $ */
+/* $Id: controls.h,v 1.6 2002-12-18 12:28:02 sandervl Exp $ */
 /*
  * Win32 common controls
@@ -45,3 +45,43 @@
 #define ID_CB_EDIT              1001
 
+/* internal flags */
+#define CBF_DROPPED             0x0001
+#define CBF_BUTTONDOWN          0x0002
+#define CBF_NOROLLUP            0x0004
+#define CBF_MEASUREITEM         0x0008
+#define CBF_FOCUSED             0x0010
+#define CBF_CAPTURE             0x0020
+#define CBF_EDIT                0x0040
+#define CBF_NORESIZE            0x0080
+#define CBF_NOTIFY              0x0100
+#define CBF_NOREDRAW            0x0200
+#define CBF_SELCHANGE           0x0400
+#define CBF_NOEDITNOTIFY        0x1000
+#define CBF_NOLBSELECT          0x2000  /* do not change current selection */
+#define CBF_EUI                 0x8000
+
+/* combo state struct */
+typedef struct
+{
+   HWND           self;
+   HWND           owner;
+   UINT           dwStyle;
+   HWND           hWndEdit;
+   HWND           hWndLBox;
+   UINT           wState;
+   HFONT          hFont;
+   RECT           textRect;
+   RECT           buttonRect;
+   RECT           droppedRect;
+   INT            droppedIndex;
+   INT            fixedOwnerDrawHeight;
+   INT            droppedWidth;   /* last two are not used unless set */
+   INT            editHeight;     /* explicitly */
+} HEADCOMBO,*LPHEADCOMBO;
+
+/* Note, that CBS_DROPDOWNLIST style is actually (CBS_SIMPLE | CBS_DROPDOWN) */
+#define CB_GETTYPE( lphc )    ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
+
+extern BOOL COMBO_FlipListbox( LPHEADCOMBO, BOOL, BOOL );
+
 #endif // __CONTROLS_H
Index: trunk/src/user32/ctrlconf.h
===================================================================
--- trunk/src/user32/ctrlconf.h	(revision 9523)
+++ trunk/src/user32/ctrlconf.h	(revision 9523)
@@ -0,0 +1,68 @@
+/* $Id: ctrlconf.h,v 1.1 2002-12-18 12:28:02 sandervl Exp $ */
+/*
+ * Win32 common controls
+ *
+ */
+
+#ifndef __CTRLCONF_H
+#define __CTRLCONF_H
+
+#include "wndmsg.h"
+
+#define SPY_GetMsgName(msg, hwnd)	GetMsgText(msg)
+
+#define MapSL(a)			a
+
+#define SendMessage16			SendMessageA
+
+#define WIN_GetFullHandle(hwnd)		hwnd
+
+#define  WIN_SuspendWndsLock()		0
+#define  WIN_RestoreWndsLock(ipreviousLock)
+
+#define LOCAL_Alloc(ds, flags, size)		0
+#define LOCAL_ReAlloc(ds, handle, size, flags )	0
+#define LOCAL_Lock(ds, handle )			NULL
+#define LOCAL_Unlock(ds, handle )		1
+#define LOCAL_Size(ds, handle )			0
+
+/* Wine look */
+
+typedef enum
+{
+    WIN31_LOOK,
+    WIN95_LOOK,
+    WIN98_LOOK
+} WINE_LOOK;
+
+#define TWEAK_WineLook WIN98_LOOK
+
+typedef LPDRAGINFO LPDRAGINFO16;
+
+/* Built-in class descriptor */
+struct builtin_class_descr
+{
+    LPCSTR  name;    /* class name */
+    UINT    style;   /* class style */
+    WNDPROC procA;   /* ASCII window procedure */
+    WNDPROC procW;   /* Unicode window procedure */
+    INT     extra;   /* window extra bytes */
+    LPCSTR  cursor;  /* cursor name */
+    HBRUSH  brush;   /* brush or system color */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const struct builtin_class_descr LISTBOX_builtin_class;
+extern const struct builtin_class_descr COMBOLBOX_builtin_class;
+extern const struct builtin_class_descr COMBO_builtin_class;
+extern const struct builtin_class_descr EDIT_builtin_class;
+extern const struct builtin_class_descr MDICLIENT_builtin_class;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CTRLCONF_H
Index: trunk/src/user32/dbgwrap.cpp
===================================================================
--- trunk/src/user32/dbgwrap.cpp	(revision 9522)
+++ trunk/src/user32/dbgwrap.cpp	(revision 9523)
@@ -144,5 +144,5 @@
 BOOL WIN32API SysErrorBox(DWORD x1, DWORD x2, DWORD x3);
 BOOL WIN32API EndTask(DWORD x1, DWORD x2, DWORD x3);
-LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+LRESULT WINAPI EditWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
 
 
@@ -169,5 +169,5 @@
 DEBUGWRAP12(DragDetect)
 DEBUGWRAP20(DragObject)
-DEBUGWRAP16(EditWndProc)
+DEBUGWRAP16(EditWndProcA)
 DEBUGWRAP12(EndTask)
 DEBUGWRAP12(EnumDesktopWindows)
Index: trunk/src/user32/edit.c
===================================================================
--- trunk/src/user32/edit.c	(revision 9523)
+++ trunk/src/user32/edit.c	(revision 9523)
@@ -0,0 +1,4995 @@
+/*
+ *	Edit control
+ *
+ *	Copyright  David W. Metcalfe, 1994
+ *	Copyright  William Magro, 1995, 1996
+ *	Copyright  Frans van Dorsselaer, 1996, 1997
+ *
+ */
+
+/*
+ *	please read EDIT.TODO (and update it when you change things)
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "winbase.h"
+#include "winnt.h"
+#include "win.h"
+#include "wine/winbase16.h"
+#include "wine/winuser16.h"
+#include "wine/unicode.h"
+#include "controls.h"
+#include "local.h"
+#include "user.h"
+#include "debugtools.h"
+
+#ifdef __WIN32OS2__
+#include "ctrlconf.h"
+#endif
+
+DEFAULT_DEBUG_CHANNEL(edit);
+DECLARE_DEBUG_CHANNEL(combo);
+#ifndef __WIN32OS2__
+DECLARE_DEBUG_CHANNEL(relay);
+#endif
+
+#define BUFLIMIT_MULTI		65534	/* maximum buffer size (not including '\0')
+					   FIXME: BTW, new specs say 65535 (do you dare ???) */
+#define BUFLIMIT_SINGLE		32766	/* maximum buffer size (not including '\0') */
+#define GROWLENGTH		32	/* buffers granularity in bytes: must be power of 2 */
+#define ROUND_TO_GROW(size)	(((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1))
+#define HSCROLL_FRACTION	3	/* scroll window by 1/3 width */
+
+/*
+ *	extra flags for EDITSTATE.flags field
+ */
+#define EF_MODIFIED		0x0001	/* text has been modified */
+#define EF_FOCUSED		0x0002	/* we have input focus */
+#define EF_UPDATE		0x0004	/* notify parent of changed state */
+#define EF_VSCROLL_TRACK	0x0008	/* don't SetScrollPos() since we are tracking the thumb */
+#define EF_HSCROLL_TRACK	0x0010	/* don't SetScrollPos() since we are tracking the thumb */
+#define EF_AFTER_WRAP		0x0080	/* the caret is displayed after the last character of a
+					   wrapped line, instead of in front of the next character */
+#define EF_USE_SOFTBRK		0x0100	/* Enable soft breaks in text. */
+
+typedef enum
+{
+	END_0 = 0,	/* line ends with terminating '\0' character */
+	END_WRAP,	/* line is wrapped */
+	END_HARD,	/* line ends with a hard return '\r\n' */
+	END_SOFT	/* line ends with a soft return '\r\r\n' */
+} LINE_END;
+
+typedef struct tagLINEDEF {
+	INT length;		/* bruto length of a line in bytes */
+	INT net_length;	/* netto length of a line in visible characters */
+	LINE_END ending;
+	INT width;		/* width of the line in pixels */
+	INT index; /* line index into the buffer */
+	struct tagLINEDEF *next;
+} LINEDEF;
+
+typedef struct
+{
+	BOOL is_unicode;		/* how the control was created */
+	LPWSTR text;			/* the actual contents of the control */
+	UINT buffer_size;		/* the size of the buffer in characters */
+	UINT buffer_limit;		/* the maximum size to which the buffer may grow in characters */
+	HFONT font;			/* NULL means standard system font */
+	INT x_offset;			/* scroll offset	for multi lines this is in pixels
+								for single lines it's in characters */
+	INT line_height;		/* height of a screen line in pixels */
+	INT char_width;		/* average character width in pixels */
+	DWORD style;			/* sane version of wnd->dwStyle */
+	WORD flags;			/* flags that are not in es->style or wnd->flags (EF_XXX) */
+	INT undo_insert_count;	/* number of characters inserted in sequence */
+	UINT undo_position;		/* character index of the insertion and deletion */
+	LPWSTR undo_text;		/* deleted text */
+	UINT undo_buffer_size;		/* size of the deleted text buffer */
+	INT selection_start;		/* == selection_end if no selection */
+	INT selection_end;		/* == current caret position */
+	WCHAR password_char;		/* == 0 if no password char, and for multi line controls */
+	INT left_margin;		/* in pixels */
+	INT right_margin;		/* in pixels */
+	RECT format_rect;
+	INT text_width;			/* width of the widest line in pixels for multi line controls
+					   and just line width for single line controls	*/
+	INT region_posx;		/* Position of cursor relative to region: */
+	INT region_posy;		/* -1: to left, 0: within, 1: to right */
+	EDITWORDBREAKPROC16 word_break_proc16;
+	void *word_break_proc;		/* 32-bit word break proc: ANSI or Unicode */
+	INT line_count;		/* number of lines */
+	INT y_offset;			/* scroll offset in number of lines */
+	BOOL bCaptureState; /* flag indicating whether mouse was captured */
+	BOOL bEnableState;             /* flag keeping the enable state */
+	HWND hwndParent;               /* Handle of parent for sending EN_* messages.
+				          Even if parent will change, EN_* messages
+					  should be sent to the first parent. */
+	HWND hwndListBox;              /* handle of ComboBox's listbox or NULL */
+	/*
+	 *	only for multi line controls
+	 */
+	INT lock_count;		/* amount of re-entries in the EditWndProc */
+	INT tabs_count;
+	LPINT tabs;
+	LINEDEF *first_line_def;	/* linked list of (soft) linebreaks */
+	HLOCAL hloc32W;		/* our unicode local memory block */
+	HLOCAL16 hloc16;	/* alias for 16-bit control receiving EM_GETHANDLE16
+				   or EM_SETHANDLE16 */
+	HLOCAL hloc32A;		/* alias for ANSI control receiving EM_GETHANDLE
+				   or EM_SETHANDLE */
+} EDITSTATE;
+
+
+#define SWAP_INT32(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0)
+#define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT32((x),(y)); } while(0)
+
+#define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
+#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
+
+#define DPRINTF_EDIT_NOTIFY(hwnd, str) \
+	do {TRACE("notification " str " sent to hwnd=%08x\n", \
+		       (UINT)(hwnd));} while(0)
+
+/* used for disabled or read-only edit control */
+#define EDIT_SEND_CTLCOLORSTATIC(hwnd,hdc) \
+	(SendMessageW(GetParent(hwnd), WM_CTLCOLORSTATIC, \
+			(WPARAM)(hdc), (LPARAM)(hwnd)))
+#define EDIT_SEND_CTLCOLOR(hwnd,hdc) \
+	(SendMessageW(GetParent(hwnd), WM_CTLCOLOREDIT, \
+			(WPARAM)(hdc), (LPARAM)(hwnd)))
+#define EDIT_NOTIFY_PARENT(hwnd, es, wNotifyCode, str) \
+	do \
+	{ /* Notify parent which has created this edit control */ \
+	    DPRINTF_EDIT_NOTIFY((es)->hwndParent, str); \
+	    SendMessageW((es)->hwndParent, WM_COMMAND, \
+		     MAKEWPARAM(GetWindowLongA((hwnd),GWL_ID), wNotifyCode), \
+		     (LPARAM)(hwnd)); \
+	} while(0)
+#define DPRINTF_EDIT_MSG16(str) \
+	TRACE(\
+		     "16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
+		     hwnd, (UINT)wParam, (UINT)lParam)
+#define DPRINTF_EDIT_MSG32(str) \
+	TRACE(\
+		     "32 bit %c : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
+		     unicode ? 'W' : 'A', \
+		     hwnd, (UINT)wParam, (UINT)lParam)
+
+/*********************************************************************
+ *
+ *	Declarations
+ *
+ */
+
+/*
+ *	These functions have trivial implementations
+ *	We still like to call them internally
+ *	"static inline" makes them more like macro's
+ */
+static inline BOOL	EDIT_EM_CanUndo(EDITSTATE *es);
+static inline void	EDIT_EM_EmptyUndoBuffer(EDITSTATE *es);
+static inline void	EDIT_WM_Clear(HWND hwnd, EDITSTATE *es);
+static inline void	EDIT_WM_Cut(HWND hwnd, EDITSTATE *es);
+
+/*
+ *	Helper functions only valid for one type of control
+ */
+static void	EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT iStart, INT iEnd, INT delta, HRGN hrgn);
+static void	EDIT_CalcLineWidth_SL(HWND hwnd, EDITSTATE *es);
+static LPWSTR	EDIT_GetPasswordPointer_SL(EDITSTATE *es);
+static void	EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
+/*
+ *	Helper functions valid for both single line _and_ multi line controls
+ */
+static INT	EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action);
+static INT	EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
+static void	EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y);
+static void	EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
+static void	EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end);
+static void	EDIT_LockBuffer(HWND hwnd, EDITSTATE *es);
+static BOOL	EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size);
+static BOOL	EDIT_MakeUndoFit(EDITSTATE *es, UINT size);
+static void	EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend);
+static void	EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev);
+static INT	EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
+static void	EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, BOOL after_wrap);
+static void	EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT lprc);
+static void	EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force);
+static void	EDIT_UpdateScrollInfo(HWND hwnd, EDITSTATE *es);
+static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action);
+/*
+ *	EM_XXX message handlers
+ */
+static LRESULT	EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y);
+static BOOL	EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol);
+static HLOCAL	EDIT_EM_GetHandle(EDITSTATE *es);
+#ifndef __WIN32OS2__
+static HLOCAL16	EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es);
+#endif
+static INT	EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode);
+static LRESULT	EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end);
+static LRESULT	EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es);
+static INT	EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
+static INT	EDIT_EM_LineIndex(EDITSTATE *es, INT line);
+static INT	EDIT_EM_LineLength(EDITSTATE *es, INT index);
+static BOOL	EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
+static BOOL	EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
+static LRESULT	EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap);
+static void	EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update);
+static LRESULT	EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action);
+static void	EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es);
+static void	EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc);
+#ifndef __WIN32OS2__
+static void	EDIT_EM_SetHandle16(HWND hwnd, EDITSTATE *es, HLOCAL16 hloc);
+#endif
+static void	EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
+static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
+static void	EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, WCHAR c);
+static void	EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
+static BOOL	EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
+static BOOL	EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
+static void	EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam);
+#ifndef __WIN32OS2__
+static void	EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
+#endif
+static BOOL	EDIT_EM_Undo(HWND hwnd, EDITSTATE *es);
+/*
+ *	WM_XXX message handlers
+ */
+static void	EDIT_WM_Char(HWND hwnd, EDITSTATE *es, WCHAR c);
+static void	EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND conrtol);
+static void	EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y);
+static void	EDIT_WM_Copy(HWND hwnd, EDITSTATE *es);
+static LRESULT	EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name);
+static void	EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es);
+static LRESULT	EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc);
+static INT	EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode);
+static LRESULT	EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos);
+static LRESULT	EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key);
+static LRESULT	EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es);
+static LRESULT	EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es);
+static LRESULT	EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
+static LRESULT	EDIT_WM_LButtonUp(HWND hwndSelf, EDITSTATE *es);
+static LRESULT	EDIT_WM_MButtonDown(HWND hwnd);
+static LRESULT	EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y);
+static LRESULT	EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode);
+static void	EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam);
+static void	EDIT_WM_Paste(HWND hwnd, EDITSTATE *es);
+static void	EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es);
+static void	EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw);
+static void	EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPARAM lParam, BOOL unicode);
+static void	EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height);
+static LRESULT  EDIT_WM_StyleChanged (HWND hwnd, EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
+static LRESULT	EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
+static void	EDIT_WM_Timer(HWND hwnd, EDITSTATE *es);
+static LRESULT	EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos);
+static void EDIT_UpdateText(HWND hwnd, EDITSTATE *es, LPRECT rc, BOOL bErase);
+static void EDIT_UpdateTextRegion(HWND hwnd, EDITSTATE *es, HRGN hrgn, BOOL bErase);
+
+LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/*********************************************************************
+ * edit class descriptor
+ */
+const struct builtin_class_descr EDIT_builtin_class =
+{
+    "Edit",               /* name */
+    CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/,   /* style */
+    EditWndProcA,         /* procA */
+    EditWndProcW,         /* procW */
+    sizeof(EDITSTATE *),  /* extra */
+    IDC_IBEAMA,           /* cursor */
+    0                     /* brush */
+};
+
+
+/*********************************************************************
+ *
+ *	EM_CANUNDO
+ *
+ */
+static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es)
+{
+	return (es->undo_insert_count || strlenW(es->undo_text));
+}
+
+
+/*********************************************************************
+ *
+ *	EM_EMPTYUNDOBUFFER
+ *
+ */
+static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es)
+{
+	es->undo_insert_count = 0;
+	*es->undo_text = '\0';
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CLEAR
+ *
+ */
+static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es)
+{
+	static const WCHAR empty_stringW[] = {0};
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return;
+
+	EDIT_EM_ReplaceSel(hwnd, es, TRUE, empty_stringW, TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CUT
+ *
+ */
+static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es)
+{
+	EDIT_WM_Copy(hwnd, es);
+	EDIT_WM_Clear(hwnd, es);
+}
+
+
+/**********************************************************************
+ *         get_app_version
+ *
+ * Returns the window version in case Wine emulates a later version
+ * of windows then the application expects.
+ *
+ * In a number of cases when windows runs an application that was
+ * designed for an earlier windows version, windows reverts
+ * to "old" behaviour of that earlier version.
+ *
+ * An example is a disabled  edit control that needs to be painted.
+ * Old style behaviour is to send a WM_CTLCOLOREDIT message. This was
+ * changed in Win95, NT4.0 by a WM_CTLCOLORSTATIC message _only_ for
+ * applications with an expected version 0f 4.0 or higher.
+ *
+ */
+static DWORD get_app_version(void)
+{
+    static DWORD version;
+    if (!version)
+    {
+        DWORD dwEmulatedVersion;
+        OSVERSIONINFOW info;
+        DWORD dwProcVersion = GetProcessVersion(0);
+
+	info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
+        GetVersionExW( &info );
+        dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion );
+        /* FIXME: this may not be 100% correct; see discussion on the
+         * wine developer list in Nov 1999 */
+        version = dwProcVersion < dwEmulatedVersion ? dwProcVersion : dwEmulatedVersion;
+    }
+    return version;
+}
+
+
+/*********************************************************************
+ *
+ *	EditWndProc_common
+ *
+ *	The messages are in the order of the actual integer values
+ *	(which can be found in include/windows.h)
+ *	Wherever possible the 16 bit versions are converted to
+ *	the 32 bit ones, so that we can 'fall through' to the
+ *	helper functions.  These are mostly 32 bit (with a few
+ *	exceptions, clearly indicated by a '16' extension to their
+ *	names).
+ *
+ */
+static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
+                                          WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+	EDITSTATE *es = (EDITSTATE *)GetWindowLongA( hwnd, 0 );
+	LRESULT result = 0;
+
+	switch (msg) {
+	case WM_DESTROY:
+		DPRINTF_EDIT_MSG32("WM_DESTROY");
+		if (es) EDIT_WM_Destroy(hwnd, es);
+                result = 0;
+                goto END;
+
+	case WM_NCCREATE:
+		DPRINTF_EDIT_MSG32("WM_NCCREATE");
+		if(unicode)
+		{
+		    LPCREATESTRUCTW cs = (LPCREATESTRUCTW)lParam;
+		    result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, TRUE);
+		}
+		else
+		{
+		    LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
+		    result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, FALSE);
+		}
+                goto END;
+	}
+
+	if (!es)
+        {
+	    if(unicode)
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+	    else
+		result = DefWindowProcA(hwnd, msg, wParam, lParam);
+            goto END;
+        }
+
+
+	EDIT_LockBuffer(hwnd, es);
+	switch (msg) {
+	case EM_GETSEL16:
+		DPRINTF_EDIT_MSG16("EM_GETSEL");
+		wParam = 0;
+		lParam = 0;
+		/* fall through */
+	case EM_GETSEL:
+		DPRINTF_EDIT_MSG32("EM_GETSEL");
+		result = EDIT_EM_GetSel(es, (LPUINT)wParam, (LPUINT)lParam);
+		break;
+
+	case EM_SETSEL16:
+		DPRINTF_EDIT_MSG16("EM_SETSEL");
+		if (SLOWORD(lParam) == -1)
+			EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
+		else
+			EDIT_EM_SetSel(hwnd, es, LOWORD(lParam), HIWORD(lParam), FALSE);
+		if (!wParam)
+			EDIT_EM_ScrollCaret(hwnd, es);
+		result = 1;
+		break;
+	case EM_SETSEL:
+		DPRINTF_EDIT_MSG32("EM_SETSEL");
+		EDIT_EM_SetSel(hwnd, es, wParam, lParam, FALSE);
+		EDIT_EM_ScrollCaret(hwnd, es);
+		result = 1;
+		break;
+
+	case EM_GETRECT16:
+		DPRINTF_EDIT_MSG16("EM_GETRECT");
+		if (lParam)
+			CONV_RECT32TO16(&es->format_rect, MapSL(lParam));
+		break;
+	case EM_GETRECT:
+		DPRINTF_EDIT_MSG32("EM_GETRECT");
+		if (lParam)
+			CopyRect((LPRECT)lParam, &es->format_rect);
+		break;
+
+	case EM_SETRECT16:
+		DPRINTF_EDIT_MSG16("EM_SETRECT");
+		if ((es->style & ES_MULTILINE) && lParam) {
+			RECT rc;
+			CONV_RECT16TO32(MapSL(lParam), &rc);
+			EDIT_SetRectNP(hwnd, es, &rc);
+			EDIT_UpdateText(hwnd, es, NULL, TRUE);
+		}
+		break;
+	case EM_SETRECT:
+		DPRINTF_EDIT_MSG32("EM_SETRECT");
+		if ((es->style & ES_MULTILINE) && lParam) {
+			EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
+			EDIT_UpdateText(hwnd, es, NULL, TRUE);
+		}
+		break;
+
+	case EM_SETRECTNP16:
+		DPRINTF_EDIT_MSG16("EM_SETRECTNP");
+		if ((es->style & ES_MULTILINE) && lParam) {
+			RECT rc;
+			CONV_RECT16TO32(MapSL(lParam), &rc);
+			EDIT_SetRectNP(hwnd, es, &rc);
+		}
+		break;
+	case EM_SETRECTNP:
+		DPRINTF_EDIT_MSG32("EM_SETRECTNP");
+		if ((es->style & ES_MULTILINE) && lParam)
+			EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
+		break;
+
+	case EM_SCROLL16:
+		DPRINTF_EDIT_MSG16("EM_SCROLL");
+		/* fall through */
+	case EM_SCROLL:
+		DPRINTF_EDIT_MSG32("EM_SCROLL");
+		result = EDIT_EM_Scroll(hwnd, es, (INT)wParam);
+ 		break;
+
+	case EM_LINESCROLL16:
+		DPRINTF_EDIT_MSG16("EM_LINESCROLL");
+		wParam = (WPARAM)(INT)SHIWORD(lParam);
+		lParam = (LPARAM)(INT)SLOWORD(lParam);
+		/* fall through */
+	case EM_LINESCROLL:
+		DPRINTF_EDIT_MSG32("EM_LINESCROLL");
+		result = (LRESULT)EDIT_EM_LineScroll(hwnd, es, (INT)wParam, (INT)lParam);
+		break;
+
+	case EM_SCROLLCARET16:
+		DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
+		/* fall through */
+	case EM_SCROLLCARET:
+		DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
+		EDIT_EM_ScrollCaret(hwnd, es);
+		result = 1;
+		break;
+
+	case EM_GETMODIFY16:
+		DPRINTF_EDIT_MSG16("EM_GETMODIFY");
+		/* fall through */
+	case EM_GETMODIFY:
+		DPRINTF_EDIT_MSG32("EM_GETMODIFY");
+		result = ((es->flags & EF_MODIFIED) != 0);
+		break;
+
+	case EM_SETMODIFY16:
+		DPRINTF_EDIT_MSG16("EM_SETMODIFY");
+		/* fall through */
+	case EM_SETMODIFY:
+		DPRINTF_EDIT_MSG32("EM_SETMODIFY");
+		if (wParam)
+			es->flags |= EF_MODIFIED;
+		else
+                        es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
+		break;
+
+	case EM_GETLINECOUNT16:
+		DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
+		/* fall through */
+	case EM_GETLINECOUNT:
+		DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
+		result = (es->style & ES_MULTILINE) ? es->line_count : 1;
+		break;
+
+	case EM_LINEINDEX16:
+		DPRINTF_EDIT_MSG16("EM_LINEINDEX");
+		if ((INT16)wParam == -1)
+			wParam = (WPARAM)-1;
+		/* fall through */
+	case EM_LINEINDEX:
+		DPRINTF_EDIT_MSG32("EM_LINEINDEX");
+		result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
+		break;
+
+#ifndef __WIN32OS2__
+	case EM_SETHANDLE16:
+		DPRINTF_EDIT_MSG16("EM_SETHANDLE");
+		EDIT_EM_SetHandle16(hwnd, es, (HLOCAL16)wParam);
+		break;
+#endif
+	case EM_SETHANDLE:
+		DPRINTF_EDIT_MSG32("EM_SETHANDLE");
+		EDIT_EM_SetHandle(hwnd, es, (HLOCAL)wParam);
+		break;
+
+#ifndef __WIN32OS2__
+	case EM_GETHANDLE16:
+		DPRINTF_EDIT_MSG16("EM_GETHANDLE");
+		result = (LRESULT)EDIT_EM_GetHandle16(hwnd, es);
+		break;
+#endif
+	case EM_GETHANDLE:
+		DPRINTF_EDIT_MSG32("EM_GETHANDLE");
+		result = (LRESULT)EDIT_EM_GetHandle(es);
+		break;
+
+	case EM_GETTHUMB16:
+		DPRINTF_EDIT_MSG16("EM_GETTHUMB");
+		/* fall through */
+	case EM_GETTHUMB:
+		DPRINTF_EDIT_MSG32("EM_GETTHUMB");
+		result = EDIT_EM_GetThumb(hwnd, es);
+		break;
+
+	/* messages 0x00bf and 0x00c0 missing from specs */
+
+	case WM_USER+15:
+		DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
+		/* fall through */
+	case 0x00bf:
+		DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		break;
+
+	case WM_USER+16:
+		DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
+		/* fall through */
+	case 0x00c0:
+		DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		break;
+
+	case EM_LINELENGTH16:
+		DPRINTF_EDIT_MSG16("EM_LINELENGTH");
+		/* fall through */
+	case EM_LINELENGTH:
+		DPRINTF_EDIT_MSG32("EM_LINELENGTH");
+		result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
+		break;
+
+	case EM_REPLACESEL16:
+		DPRINTF_EDIT_MSG16("EM_REPLACESEL");
+		lParam = (LPARAM)MapSL(lParam);
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_REPLACESEL:
+	{
+		LPWSTR textW;
+		DPRINTF_EDIT_MSG32("EM_REPLACESEL");
+
+		if(unicode)
+		    textW = (LPWSTR)lParam;
+		else
+		{
+		    LPSTR textA = (LPSTR)lParam;
+		    INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+		    if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+			MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+		}
+
+		EDIT_EM_ReplaceSel(hwnd, es, (BOOL)wParam, textW, TRUE);
+		result = 1;
+
+		if(!unicode)
+		    HeapFree(GetProcessHeap(), 0, textW);
+		break;
+	}
+	/* message 0x00c3 missing from specs */
+
+	case WM_USER+19:
+		DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
+		/* fall through */
+	case 0x00c3:
+		DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		break;
+
+	case EM_GETLINE16:
+		DPRINTF_EDIT_MSG16("EM_GETLINE");
+		lParam = (LPARAM)MapSL(lParam);
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_GETLINE:
+		DPRINTF_EDIT_MSG32("EM_GETLINE");
+		result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, lParam, unicode);
+		break;
+
+	case EM_LIMITTEXT16:
+		DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
+		/* fall through */
+	case EM_SETLIMITTEXT:
+		DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
+		EDIT_EM_SetLimitText(es, (INT)wParam);
+		break;
+
+	case EM_CANUNDO16:
+		DPRINTF_EDIT_MSG16("EM_CANUNDO");
+		/* fall through */
+	case EM_CANUNDO:
+		DPRINTF_EDIT_MSG32("EM_CANUNDO");
+		result = (LRESULT)EDIT_EM_CanUndo(es);
+		break;
+
+	case EM_UNDO16:
+		DPRINTF_EDIT_MSG16("EM_UNDO");
+		/* fall through */
+	case EM_UNDO:
+		/* fall through */
+	case WM_UNDO:
+		DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
+		result = (LRESULT)EDIT_EM_Undo(hwnd, es);
+		break;
+
+	case EM_FMTLINES16:
+		DPRINTF_EDIT_MSG16("EM_FMTLINES");
+		/* fall through */
+	case EM_FMTLINES:
+		DPRINTF_EDIT_MSG32("EM_FMTLINES");
+		result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
+		break;
+
+	case EM_LINEFROMCHAR16:
+		DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
+		/* fall through */
+	case EM_LINEFROMCHAR:
+		DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
+		result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
+		break;
+
+	/* message 0x00ca missing from specs */
+
+	case WM_USER+26:
+		DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
+		/* fall through */
+	case 0x00ca:
+		DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		break;
+
+	case EM_SETTABSTOPS16:
+		DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
+		result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam));
+		break;
+	case EM_SETTABSTOPS:
+		DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
+		result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
+		break;
+
+	case EM_SETPASSWORDCHAR16:
+		DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_SETPASSWORDCHAR:
+	{
+		WCHAR charW = 0;
+		DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
+
+		if(unicode)
+		    charW = (WCHAR)wParam;
+		else
+		{
+		    CHAR charA = wParam;
+		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+		}
+
+		EDIT_EM_SetPasswordChar(hwnd, es, charW);
+		break;
+	}
+
+	case EM_EMPTYUNDOBUFFER16:
+		DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
+		/* fall through */
+	case EM_EMPTYUNDOBUFFER:
+		DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
+		EDIT_EM_EmptyUndoBuffer(es);
+		break;
+
+	case EM_GETFIRSTVISIBLELINE16:
+		DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
+		result = es->y_offset;
+		break;
+	case EM_GETFIRSTVISIBLELINE:
+		DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
+		result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
+		break;
+
+	case EM_SETREADONLY16:
+		DPRINTF_EDIT_MSG16("EM_SETREADONLY");
+		/* fall through */
+	case EM_SETREADONLY:
+		DPRINTF_EDIT_MSG32("EM_SETREADONLY");
+		if (wParam) {
+                    SetWindowLongA( hwnd, GWL_STYLE,
+                                    GetWindowLongA( hwnd, GWL_STYLE ) | ES_READONLY );
+                    es->style |= ES_READONLY;
+		} else {
+                    SetWindowLongA( hwnd, GWL_STYLE,
+                                    GetWindowLongA( hwnd, GWL_STYLE ) & ~ES_READONLY );
+                    es->style &= ~ES_READONLY;
+		}
+                result = 1;
+ 		break;
+#ifndef __WIN32OS2__
+	case EM_SETWORDBREAKPROC16:
+		DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
+		EDIT_EM_SetWordBreakProc16(hwnd, es, (EDITWORDBREAKPROC16)lParam);
+		break;
+#endif
+	case EM_SETWORDBREAKPROC:
+		DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
+		EDIT_EM_SetWordBreakProc(hwnd, es, lParam);
+		break;
+
+	case EM_GETWORDBREAKPROC16:
+		DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
+		result = (LRESULT)es->word_break_proc16;
+		break;
+	case EM_GETWORDBREAKPROC:
+		DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
+		result = (LRESULT)es->word_break_proc;
+		break;
+
+	case EM_GETPASSWORDCHAR16:
+		DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_GETPASSWORDCHAR:
+	{
+		DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
+
+		if(unicode)
+		    result = es->password_char;
+		else
+		{
+		    WCHAR charW = es->password_char;
+		    CHAR charA = 0;
+		    WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
+		    result = charA;
+		}
+		break;
+	}
+
+	/* The following EM_xxx are new to win95 and don't exist for 16 bit */
+
+	case EM_SETMARGINS:
+		DPRINTF_EDIT_MSG32("EM_SETMARGINS");
+		EDIT_EM_SetMargins(es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam));
+		break;
+
+	case EM_GETMARGINS:
+		DPRINTF_EDIT_MSG32("EM_GETMARGINS");
+		result = MAKELONG(es->left_margin, es->right_margin);
+		break;
+
+	case EM_GETLIMITTEXT:
+		DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
+		result = es->buffer_limit;
+		break;
+
+	case EM_POSFROMCHAR:
+		DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
+		result = EDIT_EM_PosFromChar(hwnd, es, (INT)wParam, FALSE);
+		break;
+
+	case EM_CHARFROMPOS:
+		DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
+		result = EDIT_EM_CharFromPos(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
+		break;
+
+        /* End of the EM_ messages which were in numerical order; what order
+         * are these in?  vaguely alphabetical?
+         */
+
+	case WM_GETDLGCODE:
+		DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
+		result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
+
+		if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
+		{
+		   int vk = (int)((LPMSG)lParam)->wParam;
+
+		   if (vk == VK_RETURN && (GetWindowLongA( hwnd, GWL_STYLE ) & ES_WANTRETURN))
+		   {
+		      result |= DLGC_WANTMESSAGE;
+		   }
+		   else if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE))
+		   {
+		      if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
+		         result |= DLGC_WANTMESSAGE;
+		   }
+		}
+		break;
+
+	case WM_CHAR:
+	{
+		WCHAR charW;
+		DPRINTF_EDIT_MSG32("WM_CHAR");
+
+		if(unicode)
+		    charW = wParam;
+		else
+		{
+		    CHAR charA = wParam;
+		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+		}
+
+		if ((charW == VK_RETURN || charW == VK_ESCAPE) && es->hwndListBox)
+		{
+		   if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
+		      SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
+		   break;
+		}
+		EDIT_WM_Char(hwnd, es, charW);
+		break;
+	}
+
+	case WM_CLEAR:
+		DPRINTF_EDIT_MSG32("WM_CLEAR");
+		EDIT_WM_Clear(hwnd, es);
+		break;
+
+	case WM_COMMAND:
+		DPRINTF_EDIT_MSG32("WM_COMMAND");
+		EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
+		break;
+
+ 	case WM_CONTEXTMENU:
+		DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
+		EDIT_WM_ContextMenu(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
+		break;
+
+	case WM_COPY:
+		DPRINTF_EDIT_MSG32("WM_COPY");
+		EDIT_WM_Copy(hwnd, es);
+		break;
+
+	case WM_CREATE:
+		DPRINTF_EDIT_MSG32("WM_CREATE");
+		if(unicode)
+		    result = EDIT_WM_Create(hwnd, es, ((LPCREATESTRUCTW)lParam)->lpszName);
+		else
+		{
+		    LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
+		    LPWSTR nameW = NULL;
+		    if(nameA)
+		    {
+			INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
+			if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+			    MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
+		    }
+		    result = EDIT_WM_Create(hwnd, es, nameW);
+		    if(nameW)
+			HeapFree(GetProcessHeap(), 0, nameW);
+		}
+		break;
+
+	case WM_CUT:
+		DPRINTF_EDIT_MSG32("WM_CUT");
+		EDIT_WM_Cut(hwnd, es);
+		break;
+
+	case WM_ENABLE:
+		DPRINTF_EDIT_MSG32("WM_ENABLE");
+                es->bEnableState = (BOOL) wParam;
+		EDIT_UpdateText(hwnd, es, NULL, TRUE);
+		break;
+
+	case WM_ERASEBKGND:
+		DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
+		result = EDIT_WM_EraseBkGnd(hwnd, es, (HDC)wParam);
+		break;
+
+	case WM_GETFONT:
+		DPRINTF_EDIT_MSG32("WM_GETFONT");
+		result = (LRESULT)es->font;
+		break;
+
+	case WM_GETTEXT:
+		DPRINTF_EDIT_MSG32("WM_GETTEXT");
+		result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, lParam, unicode);
+		break;
+
+	case WM_GETTEXTLENGTH:
+		DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
+		result = strlenW(es->text);
+		break;
+
+	case WM_HSCROLL:
+		DPRINTF_EDIT_MSG32("WM_HSCROLL");
+		result = EDIT_WM_HScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam));
+		break;
+
+	case WM_KEYDOWN:
+		DPRINTF_EDIT_MSG32("WM_KEYDOWN");
+		result = EDIT_WM_KeyDown(hwnd, es, (INT)wParam);
+		break;
+
+	case WM_KILLFOCUS:
+		DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
+		result = EDIT_WM_KillFocus(hwnd, es);
+		break;
+
+	case WM_LBUTTONDBLCLK:
+		DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
+		result = EDIT_WM_LButtonDblClk(hwnd, es);
+		break;
+
+	case WM_LBUTTONDOWN:
+		DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
+		result = EDIT_WM_LButtonDown(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
+		break;
+
+	case WM_LBUTTONUP:
+		DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
+		result = EDIT_WM_LButtonUp(hwnd, es);
+		break;
+
+	case WM_MBUTTONDOWN:
+  		DPRINTF_EDIT_MSG32("WM_MBUTTONDOWN");
+  		result = EDIT_WM_MButtonDown(hwnd);
+		break;
+
+	case WM_MOUSEACTIVATE:
+		/*
+		 *	FIXME: maybe DefWindowProc() screws up, but it seems that
+		 *		modeless dialog boxes need this.  If we don't do this, the focus
+		 *		will _not_ be set by DefWindowProc() for edit controls in a
+		 *		modeless dialog box ???
+		 */
+		DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
+		SetFocus(hwnd);
+		result = MA_ACTIVATE;
+		break;
+
+	case WM_MOUSEMOVE:
+		/*
+		 *	DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
+		 */
+		result = EDIT_WM_MouseMove(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
+		break;
+
+	case WM_PAINT:
+		DPRINTF_EDIT_MSG32("WM_PAINT");
+	        EDIT_WM_Paint(hwnd, es, wParam);
+		break;
+
+	case WM_PASTE:
+		DPRINTF_EDIT_MSG32("WM_PASTE");
+		EDIT_WM_Paste(hwnd, es);
+		break;
+
+	case WM_SETFOCUS:
+		DPRINTF_EDIT_MSG32("WM_SETFOCUS");
+		EDIT_WM_SetFocus(hwnd, es);
+		break;
+
+	case WM_SETFONT:
+		DPRINTF_EDIT_MSG32("WM_SETFONT");
+		EDIT_WM_SetFont(hwnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
+		break;
+
+	case WM_SETREDRAW:
+		/* FIXME: actually set an internal flag and behave accordingly */
+		break;
+
+	case WM_SETTEXT:
+		DPRINTF_EDIT_MSG32("WM_SETTEXT");
+		EDIT_WM_SetText(hwnd, es, lParam, unicode);
+		result = TRUE;
+		break;
+
+	case WM_SIZE:
+		DPRINTF_EDIT_MSG32("WM_SIZE");
+		EDIT_WM_Size(hwnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
+		break;
+
+        case WM_STYLECHANGED:
+		DPRINTF_EDIT_MSG32("WM_STYLECHANGED");
+                result = EDIT_WM_StyleChanged (hwnd, es, wParam, (const STYLESTRUCT *)lParam);
+                break;
+
+        case WM_STYLECHANGING:
+		DPRINTF_EDIT_MSG32("WM_STYLECHANGING");
+                result = 0; /* See EDIT_WM_StyleChanged */
+                break;
+
+	case WM_SYSKEYDOWN:
+		DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
+		result = EDIT_WM_SysKeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
+		break;
+
+	case WM_TIMER:
+		DPRINTF_EDIT_MSG32("WM_TIMER");
+		EDIT_WM_Timer(hwnd, es);
+		break;
+
+	case WM_VSCROLL:
+		DPRINTF_EDIT_MSG32("WM_VSCROLL");
+		result = EDIT_WM_VScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam));
+		break;
+
+        case WM_MOUSEWHEEL:
+                {
+                    int gcWheelDelta = 0;
+                    UINT pulScrollLines = 3;
+                    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+
+                    if (wParam & (MK_SHIFT | MK_CONTROL)) {
+                        result = DefWindowProcW(hwnd, msg, wParam, lParam);
+                        break;
+                    }
+                    gcWheelDelta -= SHIWORD(wParam);
+                    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
+                    {
+                        int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
+                        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
+			result = EDIT_EM_LineScroll(hwnd, es, 0, cLineScroll);
+                    }
+                }
+                break;
+	default:
+		if(unicode)
+		    result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		else
+		    result = DefWindowProcA(hwnd, msg, wParam, lParam);
+		break;
+	}
+	EDIT_UnlockBuffer(hwnd, es, FALSE);
+    END:
+	return result;
+}
+
+/*********************************************************************
+ *
+ *	EditWndProcW   (USER32.@)
+ */
+LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    if (!IsWindow( hWnd )) return 0;
+    return EditWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
+}
+
+/*********************************************************************
+ *
+ *	EditWndProc   (USER32.@)
+ */
+LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    if (!IsWindow( hWnd )) return 0;
+    return EditWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
+}
+
+/*********************************************************************
+ *
+ *	EDIT_BuildLineDefs_ML
+ *
+ *	Build linked list of text lines.
+ *	Lines can end with '\0' (last line), a character (if it is wrapped),
+ *	a soft return '\r\r\n' or a hard return '\r\n'
+ *
+ */
+static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn)
+{
+	HDC dc;
+	HFONT old_font = 0;
+	LPWSTR current_position, cp;
+	INT fw;
+	LINEDEF *current_line;
+	LINEDEF *previous_line;
+	LINEDEF *start_line;
+	INT line_index = 0, nstart_line = 0, nstart_index = 0;
+	INT line_count = es->line_count;
+	INT orig_net_length;
+	RECT rc;
+
+	if (istart == iend && delta == 0)
+		return;
+
+	dc = GetDC(hwnd);
+	if (es->font)
+		old_font = SelectObject(dc, es->font);
+
+	previous_line = NULL;
+	current_line = es->first_line_def;
+
+	/* Find starting line. istart must lie inside an existing line or
+	 * at the end of buffer */
+	do {
+		if (istart < current_line->index + current_line->length ||
+				current_line->ending == END_0)
+			break;
+
+		previous_line = current_line;
+		current_line = current_line->next;
+		line_index++;
+	} while (current_line);
+
+	if (!current_line) /* Error occurred start is not inside previous buffer */
+	{
+		FIXME(" modification occurred outside buffer\n");
+		return;
+	}
+
+	/* Remember start of modifications in order to calculate update region */
+	nstart_line = line_index;
+	nstart_index = current_line->index;
+
+	/* We must start to reformat from the previous line since the modifications
+	 * may have caused the line to wrap upwards. */
+	if (!(es->style & ES_AUTOHSCROLL) && line_index > 0)
+	{
+		line_index--;
+		current_line = previous_line;
+	}
+	start_line = current_line;
+
+	fw = es->format_rect.right - es->format_rect.left;
+	current_position = es->text + current_line->index;
+	do {
+		if (current_line != start_line)
+		{
+			if (!current_line || current_line->index + delta > current_position - es->text)
+			{
+				/* The buffer has been expanded, create a new line and
+				   insert it into the link list */
+				LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF));
+				new_line->next = previous_line->next;
+				previous_line->next = new_line;
+				current_line = new_line;
+				es->line_count++;
+			}
+			else if (current_line->index + delta < current_position - es->text)
+			{
+				/* The previous line merged with this line so we delete this extra entry */
+				previous_line->next = current_line->next;
+				HeapFree(GetProcessHeap(), 0, current_line);
+				current_line = previous_line->next;
+				es->line_count--;
+				continue;
+			}
+			else /* current_line->index + delta == current_position */
+			{
+				if (current_position - es->text > iend)
+					break; /* We reached end of line modifications */
+				/* else recalulate this line */
+			}
+		}
+
+		current_line->index = current_position - es->text;
+		orig_net_length = current_line->net_length;
+
+		/* Find end of line */
+		cp = current_position;
+		while (*cp) {
+			if ((*cp == '\r') && (*(cp + 1) == '\n'))
+				break;
+			cp++;
+		}
+
+		/* Mark type of line termination */
+		if (!(*cp)) {
+			current_line->ending = END_0;
+			current_line->net_length = strlenW(current_position);
+		} else if ((cp > current_position) && (*(cp - 1) == '\r')) {
+			current_line->ending = END_SOFT;
+			current_line->net_length = cp - current_position - 1;
+		} else {
+			current_line->ending = END_HARD;
+			current_line->net_length = cp - current_position;
+		}
+
+		/* Calculate line width */
+		current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
+					current_position, current_line->net_length,
+					es->tabs_count, es->tabs));
+
+		/* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
+		if ((!(es->style & ES_AUTOHSCROLL)) && (current_line->width > fw)) {
+			INT next = 0;
+			INT prev;
+			do {
+				prev = next;
+				next = EDIT_CallWordBreakProc(es, current_position - es->text,
+						prev + 1, current_line->net_length, WB_RIGHT);
+				current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
+							current_position, next, es->tabs_count, es->tabs));
+			} while (current_line->width <= fw);
+			if (!prev) { /* Didn't find a line break so force a break */
+				next = 0;
+				do {
+					prev = next;
+					next++;
+					current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
+								current_position, next, es->tabs_count, es->tabs));
+				} while (current_line->width <= fw);
+				if (!prev)
+					prev = 1;
+			}
+
+			/* If the first line we are calculating, wrapped before istart, we must
+			 * adjust istart in order for this to be reflected in the update region. */
+			if (current_line->index == nstart_index && istart > current_line->index + prev)
+				istart = current_line->index + prev;
+			/* else if we are updating the previous line before the first line we
+			 * are re-calculating and it expanded */
+			else if (current_line == start_line &&
+					current_line->index != nstart_index && orig_net_length < prev)
+			{
+			  /* Line expanded due to an upwards line wrap so we must partially include
+			   * previous line in update region */
+				nstart_line = line_index;
+				nstart_index = current_line->index;
+				istart = current_line->index + orig_net_length;
+			}
+
+			current_line->net_length = prev;
+			current_line->ending = END_WRAP;
+			current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position,
+					current_line->net_length, es->tabs_count, es->tabs));
+		}
+
+
+		/* Adjust length to include line termination */
+		switch (current_line->ending) {
+		case END_SOFT:
+			current_line->length = current_line->net_length + 3;
+			break;
+		case END_HARD:
+			current_line->length = current_line->net_length + 2;
+			break;
+		case END_WRAP:
+		case END_0:
+			current_line->length = current_line->net_length;
+			break;
+		}
+		es->text_width = max(es->text_width, current_line->width);
+		current_position += current_line->length;
+		previous_line = current_line;
+		current_line = current_line->next;
+		line_index++;
+	} while (previous_line->ending != END_0);
+
+	/* Finish adjusting line indexes by delta or remove hanging lines */
+	if (previous_line->ending == END_0)
+	{
+		LINEDEF *pnext = NULL;
+
+		previous_line->next = NULL;
+		while (current_line)
+		{
+			pnext = current_line->next;
+			HeapFree(GetProcessHeap(), 0, current_line);
+			current_line = pnext;
+			es->line_count--;
+		}
+	}
+	else
+	{
+		while (current_line)
+		{
+			current_line->index += delta;
+			current_line = current_line->next;
+		}
+	}
+
+	/* Calculate rest of modification rectangle */
+	if (hrgn)
+	{
+		HRGN tmphrgn;
+	   /*
+		* We calculate two rectangles. One for the first line which may have
+		* an indent with respect to the format rect. The other is a format-width
+		* rectangle that spans the rest of the lines that changed or moved.
+		*/
+		rc.top = es->format_rect.top + nstart_line * es->line_height -
+			(es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
+		rc.bottom = rc.top + es->line_height;
+		rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
+					es->text + nstart_index, istart - nstart_index,
+					es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
+		rc.right = es->format_rect.right;
+		SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom);
+
+		rc.top = rc.bottom;
+		rc.left = es->format_rect.left;
+		rc.right = es->format_rect.right;
+	   /*
+		* If lines were added or removed we must re-paint the remainder of the
+	    * lines since the remaining lines were either shifted up or down.
+		*/
+		if (line_count < es->line_count) /* We added lines */
+			rc.bottom = es->line_count * es->line_height;
+		else if (line_count > es->line_count) /* We removed lines */
+			rc.bottom = line_count * es->line_height;
+		else
+			rc.bottom = line_index * es->line_height;
+		rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
+		tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
+		CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
+		DeleteObject(tmphrgn);
+	}
+
+	if (es->font)
+		SelectObject(dc, old_font);
+
+	ReleaseDC(hwnd, dc);
+}
+
+/*********************************************************************
+ *
+ *	EDIT_CalcLineWidth_SL
+ *
+ */
+static void EDIT_CalcLineWidth_SL(HWND hwnd, EDITSTATE *es)
+{
+    es->text_width = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, strlenW(es->text), FALSE));
+}
+
+/*********************************************************************
+ *
+ *	EDIT_CallWordBreakProc
+ *
+ *	Call appropriate WordBreakProc (internal or external).
+ *
+ *	Note: The "start" argument should always be an index referring
+ *		to es->text.  The actual wordbreak proc might be
+ *		16 bit, so we can't always pass any 32 bit LPSTR.
+ *		Hence we assume that es->text is the buffer that holds
+ *		the string under examination (we can decide this for ourselves).
+ *
+ */
+/* ### start build ### */
+extern WORD CALLBACK EDIT_CallTo16_word_lwww(EDITWORDBREAKPROC16,SEGPTR,WORD,WORD,WORD);
+/* ### stop build ### */
+static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
+{
+    INT ret, iWndsLocks;
+
+    /* To avoid any deadlocks, all the locks on the window structures
+       must be suspended before the control is passed to the application */
+    iWndsLocks = WIN_SuspendWndsLock();
+
+#ifndef __WIN32OS2__
+	if (es->word_break_proc16) {
+	    HGLOBAL16 hglob16;
+	    SEGPTR segptr;
+	    INT countA;
+
+	    countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
+	    hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA);
+	    segptr = K32WOWGlobalLock16(hglob16);
+	    WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL);
+	    ret = (INT)EDIT_CallTo16_word_lwww(es->word_break_proc16,
+						segptr, index, countA, action);
+	    GlobalUnlock16(hglob16);
+	    GlobalFree16(hglob16);
+	}
+	else 
+#endif
+        if (es->word_break_proc)
+        {
+	    if(es->is_unicode)
+	    {
+		EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
+
+		TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
+			es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
+		ret = wbpW(es->text + start, index, count, action);
+	    }
+	    else
+	    {
+		EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
+		INT countA;
+		CHAR *textA;
+
+		countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
+		textA = HeapAlloc(GetProcessHeap(), 0, countA);
+		WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
+		TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
+			es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
+		ret = wbpA(textA, index, countA, action);
+		HeapFree(GetProcessHeap(), 0, textA);
+	    }
+        }
+	else
+            ret = EDIT_WordBreakProc(es->text + start, index, count, action);
+
+    WIN_RestoreWndsLock(iWndsLocks);
+    return ret;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_CharFromPos
+ *
+ *	Beware: This is not the function called on EM_CHARFROMPOS
+ *		The position _can_ be outside the formatting / client
+ *		rectangle
+ *		The return value is only the character index
+ *
+ */
+static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
+{
+	INT index;
+	HDC dc;
+	HFONT old_font = 0;
+
+	if (es->style & ES_MULTILINE) {
+		INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
+		INT line_index = 0;
+		LINEDEF *line_def = es->first_line_def;
+		INT low, high;
+		while ((line > 0) && line_def->next) {
+			line_index += line_def->length;
+			line_def = line_def->next;
+			line--;
+		}
+		x += es->x_offset - es->format_rect.left;
+		if (x >= line_def->width) {
+			if (after_wrap)
+				*after_wrap = (line_def->ending == END_WRAP);
+			return line_index + line_def->net_length;
+		}
+		if (x <= 0) {
+			if (after_wrap)
+				*after_wrap = FALSE;
+			return line_index;
+		}
+		dc = GetDC(hwnd);
+		if (es->font)
+			old_font = SelectObject(dc, es->font);
+                    low = line_index + 1;
+                    high = line_index + line_def->net_length + 1;
+                    while (low < high - 1)
+                    {
+                        INT mid = (low + high) / 2;
+			if (LOWORD(GetTabbedTextExtentW(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
+                        else low = mid;
+                    }
+                    index = low;
+
+		if (after_wrap)
+			*after_wrap = ((index == line_index + line_def->net_length) &&
+							(line_def->ending == END_WRAP));
+	} else {
+		LPWSTR text;
+		SIZE size;
+		if (after_wrap)
+			*after_wrap = FALSE;
+		x -= es->format_rect.left;
+		if (!x)
+			return es->x_offset;
+		text = EDIT_GetPasswordPointer_SL(es);
+		dc = GetDC(hwnd);
+		if (es->font)
+			old_font = SelectObject(dc, es->font);
+		if (x < 0)
+                {
+                    INT low = 0;
+                    INT high = es->x_offset;
+                    while (low < high - 1)
+                    {
+                        INT mid = (low + high) / 2;
+                        GetTextExtentPoint32W( dc, text + mid,
+                                               es->x_offset - mid, &size );
+                        if (size.cx > -x) low = mid;
+                        else high = mid;
+                    }
+                    index = low;
+		}
+                else
+                {
+                    INT low = es->x_offset;
+                    INT high = strlenW(es->text) + 1;
+                    while (low < high - 1)
+                    {
+                        INT mid = (low + high) / 2;
+                        GetTextExtentPoint32W( dc, text + es->x_offset,
+                                               mid - es->x_offset, &size );
+                        if (size.cx > x) high = mid;
+                        else low = mid;
+                    }
+                    index = low;
+		}
+		if (es->style & ES_PASSWORD)
+			HeapFree(GetProcessHeap(), 0, text);
+	}
+	if (es->font)
+		SelectObject(dc, old_font);
+	ReleaseDC(hwnd, dc);
+	return index;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_ConfinePoint
+ *
+ *	adjusts the point to be within the formatting rectangle
+ *	(so CharFromPos returns the nearest _visible_ character)
+ *
+ */
+static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y)
+{
+	*x = min(max(*x, es->format_rect.left), es->format_rect.right - 1);
+	*y = min(max(*y, es->format_rect.top), es->format_rect.bottom - 1);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_GetLineRect
+ *
+ *	Calculates the bounding rectangle for a line from a starting
+ *	column to an ending column.
+ *
+ */
+static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
+{
+	INT line_index =  EDIT_EM_LineIndex(es, line);
+
+	if (es->style & ES_MULTILINE)
+		rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
+	else
+		rc->top = es->format_rect.top;
+	rc->bottom = rc->top + es->line_height;
+	rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + scol, TRUE));
+	rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + ecol, TRUE));
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_GetPasswordPointer_SL
+ *
+ *	note: caller should free the (optionally) allocated buffer
+ *
+ */
+static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
+{
+	if (es->style & ES_PASSWORD) {
+		INT len = strlenW(es->text);
+		LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+		text[len] = '\0';
+		while(len) text[--len] = es->password_char;
+		return text;
+	} else
+		return es->text;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_LockBuffer
+ *
+ *	This acts as a LOCAL_Lock(), but it locks only once.  This way
+ *	you can call it whenever you like, without unlocking.
+ *
+ */
+static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+	if (!es) {
+		ERR("no EDITSTATE ... please report\n");
+		return;
+	}
+	if (!es->text) {
+	    CHAR *textA = NULL;
+	    UINT countA = 0;
+	    BOOL _16bit = FALSE;
+
+	    if(es->hloc32W)
+	    {
+		if(es->hloc32A)
+		{
+		    TRACE("Synchronizing with 32-bit ANSI buffer\n");
+		    textA = LocalLock(es->hloc32A);
+		    countA = strlen(textA) + 1;
+		}
+		else if(es->hloc16)
+		{
+		    TRACE("Synchronizing with 16-bit ANSI buffer\n");
+		    textA = LOCAL_Lock(hInstance, es->hloc16);
+		    countA = strlen(textA) + 1;
+		    _16bit = TRUE;
+		}
+	    }
+	    else {
+		ERR("no buffer ... please report\n");
+		return;
+	    }
+
+	    if(textA)
+	    {
+		HLOCAL hloc32W_new;
+		UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
+		TRACE("%d bytes translated to %d WCHARs\n", countA, countW_new);
+		if(countW_new > es->buffer_size + 1)
+		{
+		    UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR));
+		    TRACE("Resizing 32-bit UNICODE buffer from %d+1 to %d WCHARs\n", es->buffer_size, countW_new);
+		    hloc32W_new = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
+		    if(hloc32W_new)
+		    {
+			es->hloc32W = hloc32W_new;
+			es->buffer_size = LocalSize(hloc32W_new)/sizeof(WCHAR) - 1;
+			TRACE("Real new size %d+1 WCHARs\n", es->buffer_size);
+		    }
+		    else
+			WARN("FAILED! Will synchronize partially\n");
+		}
+	    }
+
+	    /*TRACE("Locking 32-bit UNICODE buffer\n");*/
+	    es->text = LocalLock(es->hloc32W);
+
+	    if(textA)
+	    {
+		MultiByteToWideChar(CP_ACP, 0, textA, countA, es->text, es->buffer_size + 1);
+		if(_16bit)
+		    LOCAL_Unlock(hInstance, es->hloc16);
+		else
+		    LocalUnlock(es->hloc32A);
+	    }
+	}
+	es->lock_count++;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_SL_InvalidateText
+ *
+ *	Called from EDIT_InvalidateText().
+ *	Does the job for single-line controls only.
+ *
+ */
+static void EDIT_SL_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
+{
+	RECT line_rect;
+	RECT rc;
+
+	EDIT_GetLineRect(hwnd, es, 0, start, end, &line_rect);
+	if (IntersectRect(&rc, &line_rect, &es->format_rect))
+		EDIT_UpdateText(hwnd, es, &rc, FALSE);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_ML_InvalidateText
+ *
+ *	Called from EDIT_InvalidateText().
+ *	Does the job for multi-line controls only.
+ *
+ */
+static void EDIT_ML_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
+{
+	INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	INT sl = EDIT_EM_LineFromChar(es, start);
+	INT el = EDIT_EM_LineFromChar(es, end);
+	INT sc;
+	INT ec;
+	RECT rc1;
+	RECT rcWnd;
+	RECT rcLine;
+	RECT rcUpdate;
+	INT l;
+
+	if ((el < es->y_offset) || (sl > es->y_offset + vlc))
+		return;
+
+	sc = start - EDIT_EM_LineIndex(es, sl);
+	ec = end - EDIT_EM_LineIndex(es, el);
+	if (sl < es->y_offset) {
+		sl = es->y_offset;
+		sc = 0;
+	}
+	if (el > es->y_offset + vlc) {
+		el = es->y_offset + vlc;
+		ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el));
+	}
+	GetClientRect(hwnd, &rc1);
+	IntersectRect(&rcWnd, &rc1, &es->format_rect);
+	if (sl == el) {
+		EDIT_GetLineRect(hwnd, es, sl, sc, ec, &rcLine);
+		if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+			EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE);
+	} else {
+		EDIT_GetLineRect(hwnd, es, sl, sc,
+				EDIT_EM_LineLength(es,
+					EDIT_EM_LineIndex(es, sl)),
+				&rcLine);
+		if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+			EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE);
+		for (l = sl + 1 ; l < el ; l++) {
+			EDIT_GetLineRect(hwnd, es, l, 0,
+				EDIT_EM_LineLength(es,
+					EDIT_EM_LineIndex(es, l)),
+				&rcLine);
+			if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+				EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE);
+		}
+		EDIT_GetLineRect(hwnd, es, el, 0, ec, &rcLine);
+		if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+			EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE);
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_InvalidateText
+ *
+ *	Invalidate the text from offset start upto, but not including,
+ *	offset end.  Useful for (re)painting the selection.
+ *	Regions outside the linewidth are not invalidated.
+ *	end == -1 means end == TextLength.
+ *	start and end need not be ordered.
+ *
+ */
+static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
+{
+	if (end == start)
+		return;
+
+	if (end == -1)
+		end = strlenW(es->text);
+
+	ORDER_INT(start, end);
+
+	if (es->style & ES_MULTILINE)
+		EDIT_ML_InvalidateText(hwnd, es, start, end);
+	else
+		EDIT_SL_InvalidateText(hwnd, es, start, end);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MakeFit
+ *
+ *	Try to fit size + 1 characters in the buffer. Constrain to limits.
+ *
+ */
+static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size)
+{
+	HLOCAL hNew32W;
+
+	if (size <= es->buffer_size)
+		return TRUE;
+	if (size > es->buffer_limit) {
+		EDIT_NOTIFY_PARENT(hwnd, es, EN_MAXTEXT, "EN_MAXTEXT");
+		return FALSE;
+	}
+	if (size > es->buffer_limit)
+		size = es->buffer_limit;
+
+	TRACE("trying to ReAlloc to %d+1 characters\n", size);
+
+	/* Force edit to unlock it's buffer. es->text now NULL */
+	EDIT_UnlockBuffer(hwnd, es, TRUE);
+
+	if (es->hloc32W) {
+	    UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
+	    if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
+		TRACE("Old 32 bit handle %08x, new handle %08x\n", es->hloc32W, hNew32W);
+		es->hloc32W = hNew32W;
+		es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
+	    }
+	}
+
+	EDIT_LockBuffer(hwnd, es);
+
+	if (es->buffer_size < size) {
+		WARN("FAILED !  We now have %d+1\n", es->buffer_size);
+		EDIT_NOTIFY_PARENT(hwnd, es, EN_ERRSPACE, "EN_ERRSPACE");
+		return FALSE;
+	} else {
+		TRACE("We now have %d+1\n", es->buffer_size);
+		return TRUE;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MakeUndoFit
+ *
+ *	Try to fit size + 1 bytes in the undo buffer.
+ *
+ */
+static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
+{
+	UINT alloc_size;
+
+	if (size <= es->undo_buffer_size)
+		return TRUE;
+
+	TRACE("trying to ReAlloc to %d+1\n", size);
+
+	alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
+	if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
+		es->undo_buffer_size = alloc_size/sizeof(WCHAR);
+		return TRUE;
+	}
+	else
+	{
+		WARN("FAILED !  We now have %d+1\n", es->undo_buffer_size);
+		return FALSE;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveBackward
+ *
+ */
+static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT e = es->selection_end;
+
+	if (e) {
+		e--;
+		if ((es->style & ES_MULTILINE) && e &&
+				(es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
+			e--;
+			if (e && (es->text[e - 1] == '\r'))
+				e--;
+		}
+	}
+	EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveDown_ML
+ *
+ *	Only for multi line controls
+ *	Move the caret one line down, on a column with the nearest
+ *	x coordinate on the screen (might be a different column).
+ *
+ */
+static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
+	LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
+	INT x = SLOWORD(pos);
+	INT y = SHIWORD(pos);
+
+	e = EDIT_CharFromPos(hwnd, es, x, y + es->line_height, &after_wrap);
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveEnd
+ *
+ */
+static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	BOOL after_wrap = FALSE;
+	INT e;
+
+	/* Pass a high value in x to make sure of receiving the end of the line */
+	if (es->style & ES_MULTILINE)
+		e = EDIT_CharFromPos(hwnd, es, 0x3fffffff,
+			HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
+	else
+		e = strlenW(es->text);
+	EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveForward
+ *
+ */
+static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT e = es->selection_end;
+
+	if (es->text[e]) {
+		e++;
+		if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
+			if (es->text[e] == '\n')
+				e++;
+			else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
+				e += 2;
+		}
+	}
+	EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveHome
+ *
+ *	Home key: move to beginning of line.
+ *
+ */
+static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT e;
+
+	/* Pass the x_offset in x to make sure of receiving the first position of the line */
+	if (es->style & ES_MULTILINE)
+		e = EDIT_CharFromPos(hwnd, es, -es->x_offset,
+			HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
+	else
+		e = 0;
+	EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MovePageDown_ML
+ *
+ *	Only for multi line controls
+ *	Move the caret one page down, on a column with the nearest
+ *	x coordinate on the screen (might be a different column).
+ *
+ */
+static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
+	LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
+	INT x = SLOWORD(pos);
+	INT y = SHIWORD(pos);
+
+	e = EDIT_CharFromPos(hwnd, es, x,
+		y + (es->format_rect.bottom - es->format_rect.top),
+		&after_wrap);
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MovePageUp_ML
+ *
+ *	Only for multi line controls
+ *	Move the caret one page up, on a column with the nearest
+ *	x coordinate on the screen (might be a different column).
+ *
+ */
+static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
+	LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
+	INT x = SLOWORD(pos);
+	INT y = SHIWORD(pos);
+
+	e = EDIT_CharFromPos(hwnd, es, x,
+		y - (es->format_rect.bottom - es->format_rect.top),
+		&after_wrap);
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveUp_ML
+ *
+ *	Only for multi line controls
+ *	Move the caret one line up, on a column with the nearest
+ *	x coordinate on the screen (might be a different column).
+ *
+ */
+static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
+	LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
+	INT x = SLOWORD(pos);
+	INT y = SHIWORD(pos);
+
+	e = EDIT_CharFromPos(hwnd, es, x, y - es->line_height, &after_wrap);
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveWordBackward
+ *
+ */
+static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	INT l;
+	INT ll;
+	INT li;
+
+	l = EDIT_EM_LineFromChar(es, e);
+	ll = EDIT_EM_LineLength(es, e);
+	li = EDIT_EM_LineIndex(es, l);
+	if (e - li == 0) {
+		if (l) {
+			li = EDIT_EM_LineIndex(es, l - 1);
+			e = li + EDIT_EM_LineLength(es, li);
+		}
+	} else {
+		e = li + (INT)EDIT_CallWordBreakProc(es,
+				li, e - li, ll, WB_LEFT);
+	}
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MoveWordForward
+ *
+ */
+static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	INT l;
+	INT ll;
+	INT li;
+
+	l = EDIT_EM_LineFromChar(es, e);
+	ll = EDIT_EM_LineLength(es, e);
+	li = EDIT_EM_LineIndex(es, l);
+	if (e - li == ll) {
+		if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
+			e = EDIT_EM_LineIndex(es, l + 1);
+	} else {
+		e = li + EDIT_CallWordBreakProc(es,
+				li, e - li + 1, ll, WB_RIGHT);
+	}
+	if (!extend)
+		s = e;
+	EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_PaintLine
+ *
+ */
+static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC dc, INT line, BOOL rev)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	INT li;
+	INT ll;
+	INT x;
+	INT y;
+	LRESULT pos;
+
+	if (es->style & ES_MULTILINE) {
+		INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
+			return;
+	} else if (line)
+		return;
+
+	TRACE("line=%d\n", line);
+
+	pos = EDIT_EM_PosFromChar(hwnd, es, EDIT_EM_LineIndex(es, line), FALSE);
+	x = SLOWORD(pos);
+	y = SHIWORD(pos);
+	li = EDIT_EM_LineIndex(es, line);
+	ll = EDIT_EM_LineLength(es, li);
+	s = es->selection_start;
+	e = es->selection_end;
+	ORDER_INT(s, e);
+	s = min(li + ll, max(li, s));
+	e = min(li + ll, max(li, e));
+	if (rev && (s != e) &&
+			((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
+		x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
+		x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
+		x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
+	} else
+		x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_PaintText
+ *
+ */
+static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
+{
+	COLORREF BkColor;
+	COLORREF TextColor;
+	INT ret;
+	INT li;
+	INT BkMode;
+	SIZE size;
+
+	if (!count)
+		return 0;
+	BkMode = GetBkMode(dc);
+	BkColor = GetBkColor(dc);
+	TextColor = GetTextColor(dc);
+	if (rev) {
+		SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
+		SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+		SetBkMode( dc, OPAQUE);
+	}
+	li = EDIT_EM_LineIndex(es, line);
+	if (es->style & ES_MULTILINE) {
+		ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
+					es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
+	} else {
+		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
+		TextOutW(dc, x, y, text + li + col, count);
+		GetTextExtentPoint32W(dc, text + li + col, count, &size);
+		ret = size.cx;
+		if (es->style & ES_PASSWORD)
+			HeapFree(GetProcessHeap(), 0, text);
+	}
+	if (rev) {
+		SetBkColor(dc, BkColor);
+		SetTextColor(dc, TextColor);
+		SetBkMode( dc, BkMode);
+	}
+	return ret;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_SetCaretPos
+ *
+ */
+static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos,
+			     BOOL after_wrap)
+{
+	LRESULT res = EDIT_EM_PosFromChar(hwnd, es, pos, after_wrap);
+	SetCaretPos(SLOWORD(res), SHIWORD(res));
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_SetRectNP
+ *
+ *	note:	this is not (exactly) the handler called on EM_SETRECTNP
+ *		it is also used to set the rect of a single line control
+ *
+ */
+static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT rc)
+{
+	CopyRect(&es->format_rect, rc);
+	if (es->style & WS_BORDER) {
+		INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
+		if(TWEAK_WineLook == WIN31_LOOK)
+			bw += 2;
+		es->format_rect.left += bw;
+		es->format_rect.top += bw;
+		es->format_rect.right -= bw;
+		es->format_rect.bottom -= bw;
+	}
+	es->format_rect.left += es->left_margin;
+	es->format_rect.right -= es->right_margin;
+	es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
+	if (es->style & ES_MULTILINE)
+	{
+	    INT fw, vlc, max_x_offset, max_y_offset;
+
+	    vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	    es->format_rect.bottom = es->format_rect.top + max(1, vlc) * es->line_height;
+
+	    /* correct es->x_offset */
+	    fw = es->format_rect.right - es->format_rect.left;
+	    max_x_offset = es->text_width - fw;
+	    if(max_x_offset < 0) max_x_offset = 0;
+	    if(es->x_offset > max_x_offset)
+		es->x_offset = max_x_offset;
+
+	    /* correct es->y_offset */
+	    max_y_offset = es->line_count - vlc;
+	    if(max_y_offset < 0) max_y_offset = 0;
+	    if(es->y_offset > max_y_offset)
+		es->y_offset = max_y_offset;
+
+	    /* force scroll info update */
+	    EDIT_UpdateScrollInfo(hwnd, es);
+	}
+	else
+	/* Windows doesn't care to fix text placement for SL controls */
+		es->format_rect.bottom = es->format_rect.top + es->line_height;
+
+	if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
+		EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_UnlockBuffer
+ *
+ */
+static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+
+    /* Edit window might be already destroyed */
+    if(!IsWindow(hwnd))
+    {
+	WARN("edit hwnd %04x already destroyed\n", hwnd);
+	return;
+    }
+
+	if (!es) {
+		ERR("no EDITSTATE ... please report\n");
+		return;
+	}
+	if (!es->lock_count) {
+		ERR("lock_count == 0 ... please report\n");
+		return;
+	}
+	if (!es->text) {
+		ERR("es->text == 0 ... please report\n");
+		return;
+	}
+
+	if (force || (es->lock_count == 1)) {
+	    if (es->hloc32W) {
+		CHAR *textA = NULL;
+		BOOL _16bit = FALSE;
+		UINT countA = 0;
+		UINT countW = strlenW(es->text) + 1;
+
+		if(es->hloc32A)
+		{
+		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
+		    TRACE("Synchronizing with 32-bit ANSI buffer\n");
+		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
+		    countA = LocalSize(es->hloc32A);
+		    if(countA_new > countA)
+		    {
+			HLOCAL hloc32A_new;
+			UINT alloc_size = ROUND_TO_GROW(countA_new);
+			TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
+			hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
+			if(hloc32A_new)
+			{
+			    es->hloc32A = hloc32A_new;
+			    countA = LocalSize(hloc32A_new);
+			    TRACE("Real new size %d bytes\n", countA);
+			}
+			else
+			    WARN("FAILED! Will synchronize partially\n");
+		    }
+		    textA = LocalLock(es->hloc32A);
+		}
+		else if(es->hloc16)
+		{
+		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
+		    TRACE("Synchronizing with 16-bit ANSI buffer\n");
+		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
+		    countA = LOCAL_Size(hInstance, es->hloc16);
+		    if(countA_new > countA)
+		    {
+			HLOCAL16 hloc16_new;
+			UINT alloc_size = ROUND_TO_GROW(countA_new);
+			TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
+			hloc16_new = LOCAL_ReAlloc(hInstance, es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
+			if(hloc16_new)
+			{
+			    es->hloc16 = hloc16_new;
+			    countA = LOCAL_Size(hInstance, hloc16_new);
+			    TRACE("Real new size %d bytes\n", countA);
+			}
+			else
+			    WARN("FAILED! Will synchronize partially\n");
+		    }
+		    textA = LOCAL_Lock(hInstance, es->hloc16);
+		    _16bit = TRUE;
+		}
+		if(textA)
+		{
+		    WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL);
+		    if(_16bit)
+			LOCAL_Unlock(hInstance, es->hloc16);
+		    else
+			LocalUnlock(es->hloc32A);
+		}
+
+		LocalUnlock(es->hloc32W);
+		es->text = NULL;
+	    }
+	    else {
+		ERR("no buffer ... please report\n");
+		return;
+	    }
+	}
+	es->lock_count--;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_UpdateScrollInfo
+ *
+ */
+static void EDIT_UpdateScrollInfo(HWND hwnd, EDITSTATE *es)
+{
+    if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
+    {
+	SCROLLINFO si;
+	si.cbSize	= sizeof(SCROLLINFO);
+	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+	si.nMin		= 0;
+	si.nMax		= es->line_count - 1;
+	si.nPage	= (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	si.nPos		= es->y_offset;
+	TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+		si.nMin, si.nMax, si.nPage, si.nPos);
+	SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+    }
+
+    if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
+    {
+	SCROLLINFO si;
+	si.cbSize	= sizeof(SCROLLINFO);
+	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+	si.nMin		= 0;
+	si.nMax		= es->text_width - 1;
+	si.nPage	= es->format_rect.right - es->format_rect.left;
+	si.nPos		= es->x_offset;
+	TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+		si.nMin, si.nMax, si.nPage, si.nPos);
+	SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
+    }
+}
+
+/*********************************************************************
+ *
+ *	EDIT_WordBreakProc
+ *
+ *	Find the beginning of words.
+ *	Note:	unlike the specs for a WordBreakProc, this function only
+ *		allows to be called without linebreaks between s[0] upto
+ *		s[count - 1].  Remember it is only called
+ *		internally, so we can decide this for ourselves.
+ *
+ */
+static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
+{
+	INT ret = 0;
+
+	TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
+
+	if(!s) return 0;
+
+	switch (action) {
+	case WB_LEFT:
+		if (!count)
+			break;
+		if (index)
+			index--;
+		if (s[index] == ' ') {
+			while (index && (s[index] == ' '))
+				index--;
+			if (index) {
+				while (index && (s[index] != ' '))
+					index--;
+				if (s[index] == ' ')
+					index++;
+			}
+		} else {
+			while (index && (s[index] != ' '))
+				index--;
+			if (s[index] == ' ')
+				index++;
+		}
+		ret = index;
+		break;
+	case WB_RIGHT:
+		if (!count)
+			break;
+		if (index)
+			index--;
+		if (s[index] == ' ')
+			while ((index < count) && (s[index] == ' ')) index++;
+		else {
+			while (s[index] && (s[index] != ' ') && (index < count))
+				index++;
+			while ((s[index] == ' ') && (index < count)) index++;
+		}
+		ret = index;
+		break;
+	case WB_ISDELIMITER:
+		ret = (s[index] == ' ');
+		break;
+	default:
+		ERR("unknown action code, please report !\n");
+		break;
+	}
+	return ret;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_CHARFROMPOS
+ *
+ *      returns line number (not index) in high-order word of result.
+ *      NB : Q137805 is unclear about this. POINT * pointer in lParam apply
+ *      to Richedit, not to the edit control. Original documentation is valid.
+ *	FIXME: do the specs mean to return -1 if outside client area or
+ *		if outside formatting rectangle ???
+ *
+ */
+static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y)
+{
+	POINT pt;
+	RECT rc;
+	INT index;
+
+	pt.x = x;
+	pt.y = y;
+	GetClientRect(hwnd, &rc);
+	if (!PtInRect(&rc, pt))
+		return -1;
+
+	index = EDIT_CharFromPos(hwnd, es, x, y, NULL);
+	return MAKELONG(index, EDIT_EM_LineFromChar(es, index));
+}
+
+
+/*********************************************************************
+ *
+ *	EM_FMTLINES
+ *
+ * Enable or disable soft breaks.
+ */
+static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol)
+{
+	es->flags &= ~EF_USE_SOFTBRK;
+	if (add_eol) {
+		es->flags |= EF_USE_SOFTBRK;
+		FIXME("soft break enabled, not implemented\n");
+	}
+	return add_eol;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_GETHANDLE
+ *
+ *	Hopefully this won't fire back at us.
+ *	We always start with a fixed buffer in the local heap.
+ *	Despite of the documentation says that the local heap is used
+ *	only if DS_LOCALEDIT flag is set, NT and 2000 always allocate
+ *	buffer on the local heap.
+ *
+ */
+static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es)
+{
+	HLOCAL hLocal;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+
+	if(es->is_unicode)
+	    hLocal = es->hloc32W;
+	else
+	{
+	    if(!es->hloc32A)
+	    {
+		CHAR *textA;
+		UINT countA, alloc_size;
+		TRACE("Allocating 32-bit ANSI alias buffer\n");
+		countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
+		alloc_size = ROUND_TO_GROW(countA);
+		if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
+		{
+		    ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size);
+		    return 0;
+		}
+		textA = LocalLock(es->hloc32A);
+		WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
+		LocalUnlock(es->hloc32A);
+	    }
+	    hLocal = es->hloc32A;
+	}
+
+	TRACE("Returning %04X, LocalSize() = %d\n", hLocal, LocalSize(hLocal));
+	return hLocal;
+}
+
+#ifndef __WIN32OS2__
+/*********************************************************************
+ *
+ *	EM_GETHANDLE16
+ *
+ *	Hopefully this won't fire back at us.
+ *	We always start with a buffer in 32 bit linear memory.
+ *	However, with this message a 16 bit application requests
+ *	a handle of 16 bit local heap memory, where it expects to find
+ *	the text.
+ *	It's a pitty that from this moment on we have to use this
+ *	local heap, because applications may rely on the handle
+ *	in the future.
+ *
+ *	In this function we'll try to switch to local heap.
+ */
+static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+	CHAR *textA;
+	UINT countA, alloc_size;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+
+	if (es->hloc16)
+		return es->hloc16;
+
+	if (!LOCAL_HeapSize(hInstance)) {
+		if (!LocalInit16(hInstance, 0,
+				GlobalSize16(hInstance))) {
+			ERR("could not initialize local heap\n");
+			return 0;
+		}
+		TRACE("local heap initialized\n");
+	}
+
+	countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
+	alloc_size = ROUND_TO_GROW(countA);
+
+	TRACE("Allocating 16-bit ANSI alias buffer\n");
+	if (!(es->hloc16 = LOCAL_Alloc(hInstance, LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) {
+		ERR("could not allocate new 16 bit buffer\n");
+		return 0;
+	}
+
+	if (!(textA = (LPSTR)LOCAL_Lock(hInstance, es->hloc16))) {
+		ERR("could not lock new 16 bit buffer\n");
+		LOCAL_Free(hInstance, es->hloc16);
+		es->hloc16 = 0;
+		return 0;
+	}
+
+	WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
+	LOCAL_Unlock(hInstance, es->hloc16);
+
+	TRACE("Returning %04X, LocalSize() = %d\n", es->hloc16, LOCAL_Size(hInstance, es->hloc16));
+	return es->hloc16;
+}
+#endif
+
+/*********************************************************************
+ *
+ *	EM_GETLINE
+ *
+ */
+static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode)
+{
+	LPWSTR src;
+	INT line_len, dst_len;
+	INT i;
+
+	if (es->style & ES_MULTILINE) {
+		if (line >= es->line_count)
+			return 0;
+	} else
+		line = 0;
+	i = EDIT_EM_LineIndex(es, line);
+	src = es->text + i;
+	line_len = EDIT_EM_LineLength(es, i);
+	dst_len = *(WORD *)lParam;
+	if(unicode)
+	{
+	    LPWSTR dst = (LPWSTR)lParam;
+	    if(dst_len <= line_len)
+	    {
+		memcpy(dst, src, dst_len * sizeof(WCHAR));
+		return dst_len;
+	    }
+	    else /* Append 0 if enough space */
+	    {
+		memcpy(dst, src, line_len * sizeof(WCHAR));
+		dst[line_len] = 0;
+		return line_len;
+	    }
+	}
+	else
+	{
+	    LPSTR dst = (LPSTR)lParam;
+	    INT ret;
+	    ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, dst, dst_len, NULL, NULL);
+	    if(!ret) /* Insufficient buffer size */
+		return dst_len;
+	    if(ret < dst_len) /* Append 0 if enough space */
+		dst[ret] = 0;
+	    return ret;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EM_GETSEL
+ *
+ */
+static LRESULT EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end)
+{
+	UINT s = es->selection_start;
+	UINT e = es->selection_end;
+
+	ORDER_UINT(s, e);
+	if (start)
+		*start = s;
+	if (end)
+		*end = e;
+	return MAKELONG(s, e);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_GETTHUMB
+ *
+ *	FIXME: is this right ?  (or should it be only VSCROLL)
+ *	(and maybe only for edit controls that really have their
+ *	own scrollbars) (and maybe only for multiline controls ?)
+ *	All in all: very poorly documented
+ *
+ */
+static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es)
+{
+	return MAKELONG(EDIT_WM_VScroll(hwnd, es, EM_GETTHUMB16, 0),
+		EDIT_WM_HScroll(hwnd, es, EM_GETTHUMB16, 0));
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINEFROMCHAR
+ *
+ */
+static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
+{
+	INT line;
+	LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+	if (index > (INT)strlenW(es->text))
+		return es->line_count - 1;
+	if (index == -1)
+		index = min(es->selection_start, es->selection_end);
+
+	line = 0;
+	line_def = es->first_line_def;
+	index -= line_def->length;
+	while ((index >= 0) && line_def->next) {
+		line++;
+		line_def = line_def->next;
+		index -= line_def->length;
+	}
+	return line;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINEINDEX
+ *
+ */
+static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line)
+{
+	INT line_index;
+	LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+	if (line >= es->line_count)
+		return -1;
+
+	line_index = 0;
+	line_def = es->first_line_def;
+	if (line == -1) {
+		INT index = es->selection_end - line_def->length;
+		while ((index >= 0) && line_def->next) {
+			line_index += line_def->length;
+			line_def = line_def->next;
+			index -= line_def->length;
+		}
+	} else {
+		while (line > 0) {
+			line_index += line_def->length;
+			line_def = line_def->next;
+			line--;
+		}
+	}
+	return line_index;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINELENGTH
+ *
+ */
+static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
+{
+	LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return strlenW(es->text);
+
+	if (index == -1) {
+		/* get the number of remaining non-selected chars of selected lines */
+		INT32 l; /* line number */
+		INT32 li; /* index of first char in line */
+		INT32 count;
+		l = EDIT_EM_LineFromChar(es, es->selection_start);
+		/* # chars before start of selection area */
+		count = es->selection_start - EDIT_EM_LineIndex(es, l);
+		l = EDIT_EM_LineFromChar(es, es->selection_end);
+		/* # chars after end of selection */
+		li = EDIT_EM_LineIndex(es, l);
+		count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
+		return count;
+	}
+	line_def = es->first_line_def;
+	index -= line_def->length;
+	while ((index >= 0) && line_def->next) {
+		line_def = line_def->next;
+		index -= line_def->length;
+	}
+	return line_def->net_length;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINESCROLL
+ *
+ *	NOTE: dx is in average character widths, dy - in lines;
+ *
+ */
+static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
+{
+	if (!(es->style & ES_MULTILINE))
+		return FALSE;
+
+	dx *= es->char_width;
+	return EDIT_EM_LineScroll_internal(hwnd, es, dx, dy);
+}
+
+/*********************************************************************
+ *
+ *	EDIT_EM_LineScroll_internal
+ *
+ *	Version of EDIT_EM_LineScroll for internal use.
+ *	It doesn't refuse if ES_MULTILINE is set and assumes that
+ *	dx is in pixels, dy - in lines.
+ *
+ */
+static BOOL EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
+{
+	INT nyoff;
+	INT x_offset_in_pixels;
+
+	if (es->style & ES_MULTILINE)
+	{
+	    x_offset_in_pixels = es->x_offset;
+	}
+	else
+	{
+	    dy = 0;
+	    x_offset_in_pixels = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->x_offset, FALSE));
+	}
+
+	if (-dx > x_offset_in_pixels)
+		dx = -x_offset_in_pixels;
+	if (dx > es->text_width - x_offset_in_pixels)
+		dx = es->text_width - x_offset_in_pixels;
+	nyoff = max(0, es->y_offset + dy);
+	if (nyoff >= es->line_count)
+		nyoff = es->line_count - 1;
+	dy = (es->y_offset - nyoff) * es->line_height;
+	if (dx || dy) {
+		RECT rc1;
+		RECT rc;
+
+		es->y_offset = nyoff;
+		if(es->style & ES_MULTILINE)
+		    es->x_offset += dx;
+		else
+		    es->x_offset += dx / es->char_width;
+
+		GetClientRect(hwnd, &rc1);
+		IntersectRect(&rc, &rc1, &es->format_rect);
+		ScrollWindowEx(hwnd, -dx, dy,
+				NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
+		/* force scroll info update */
+		EDIT_UpdateScrollInfo(hwnd, es);
+	}
+	if (dx && !(es->flags & EF_HSCROLL_TRACK))
+		EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL");
+	if (dy && !(es->flags & EF_VSCROLL_TRACK))
+		EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL");
+	return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_POSFROMCHAR
+ *
+ */
+static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap)
+{
+	INT len = strlenW(es->text);
+	INT l;
+	INT li;
+	INT x;
+	INT y = 0;
+	HDC dc;
+	HFONT old_font = 0;
+	SIZE size;
+
+	index = min(index, len);
+	dc = GetDC(hwnd);
+	if (es->font)
+		old_font = SelectObject(dc, es->font);
+	if (es->style & ES_MULTILINE) {
+		l = EDIT_EM_LineFromChar(es, index);
+		y = (l - es->y_offset) * es->line_height;
+		li = EDIT_EM_LineIndex(es, l);
+		if (after_wrap && (li == index) && l) {
+			INT l2 = l - 1;
+			LINEDEF *line_def = es->first_line_def;
+			while (l2) {
+				line_def = line_def->next;
+				l2--;
+			}
+			if (line_def->ending == END_WRAP) {
+				l--;
+				y -= es->line_height;
+				li = EDIT_EM_LineIndex(es, l);
+			}
+		}
+		x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+				es->tabs_count, es->tabs)) - es->x_offset;
+	} else {
+		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
+		if (index < es->x_offset) {
+			GetTextExtentPoint32W(dc, text + index,
+					es->x_offset - index, &size);
+			x = -size.cx;
+		} else {
+			GetTextExtentPoint32W(dc, text + es->x_offset,
+					index - es->x_offset, &size);
+			 x = size.cx;
+		}
+		y = 0;
+		if (es->style & ES_PASSWORD)
+			HeapFree(GetProcessHeap(), 0, text);
+	}
+	x += es->format_rect.left;
+	y += es->format_rect.top;
+	if (es->font)
+		SelectObject(dc, old_font);
+	ReleaseDC(hwnd, dc);
+	return MAKELONG((INT16)x, (INT16)y);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_REPLACESEL
+ *
+ *	FIXME: handle ES_NUMBER and ES_OEMCONVERT here
+ *
+ */
+static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update)
+{
+	UINT strl = strlenW(lpsz_replace);
+	UINT tl = strlenW(es->text);
+	UINT utl;
+	UINT s;
+	UINT e;
+	UINT i;
+	LPWSTR p;
+	HRGN hrgn = 0;
+
+	TRACE("%s, can_undo %d, send_update %d\n",
+	    debugstr_w(lpsz_replace), can_undo, send_update);
+
+	s = es->selection_start;
+	e = es->selection_end;
+
+	if ((s == e) && !strl)
+		return;
+
+	ORDER_UINT(s, e);
+
+	if (!EDIT_MakeFit(hwnd, es, tl - (e - s) + strl))
+		return;
+
+	if (e != s) {
+		/* there is something to be deleted */
+		TRACE("deleting stuff.\n");
+		if (can_undo) {
+			utl = strlenW(es->undo_text);
+			if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
+				/* undo-buffer is extended to the right */
+				EDIT_MakeUndoFit(es, utl + e - s);
+				strncpyW(es->undo_text + utl, es->text + s, e - s + 1);
+				(es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
+			} else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
+				/* undo-buffer is extended to the left */
+				EDIT_MakeUndoFit(es, utl + e - s);
+				for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
+					p[e - s] = p[0];
+				for (i = 0 , p = es->undo_text ; i < e - s ; i++)
+					p[i] = (es->text + s)[i];
+				es->undo_position = s;
+			} else {
+				/* new undo-buffer */
+				EDIT_MakeUndoFit(es, e - s);
+				strncpyW(es->undo_text, es->text + s, e - s + 1);
+				es->undo_text[e - s] = 0; /* ensure 0 termination */
+				es->undo_position = s;
+			}
+			/* any deletion makes the old insertion-undo invalid */
+			es->undo_insert_count = 0;
+		} else
+			EDIT_EM_EmptyUndoBuffer(es);
+
+		/* now delete */
+		strcpyW(es->text + s, es->text + e);
+	}
+	if (strl) {
+		/* there is an insertion */
+		if (can_undo) {
+			if ((s == es->undo_position) ||
+					((es->undo_insert_count) &&
+					(s == es->undo_position + es->undo_insert_count)))
+				/*
+				 * insertion is new and at delete position or
+				 * an extension to either left or right
+				 */
+				es->undo_insert_count += strl;
+			else {
+				/* new insertion undo */
+				es->undo_position = s;
+				es->undo_insert_count = strl;
+				/* new insertion makes old delete-buffer invalid */
+				*es->undo_text = '\0';
+			}
+		} else
+			EDIT_EM_EmptyUndoBuffer(es);
+
+		/* now insert */
+		tl = strlenW(es->text);
+		TRACE("inserting stuff (tl %d, strl %d, selstart %d ('%s'), text '%s')\n", tl, strl, s, debugstr_w(es->text + s), debugstr_w(es->text));
+		for (p = es->text + tl ; p >= es->text + s ; p--)
+			p[strl] = p[0];
+		for (i = 0 , p = es->text + s ; i < strl ; i++)
+			p[i] = lpsz_replace[i];
+		if(es->style & ES_UPPERCASE)
+			CharUpperBuffW(p, strl);
+		else if(es->style & ES_LOWERCASE)
+			CharLowerBuffW(p, strl);
+		s += strl;
+	}
+	if (es->style & ES_MULTILINE)
+	{
+		INT s = min(es->selection_start, es->selection_end);
+
+		hrgn = CreateRectRgn(0, 0, 0, 0);
+		EDIT_BuildLineDefs_ML(hwnd, es, s, s + strl,
+				strl - abs(es->selection_end - es->selection_start), hrgn);
+	}
+	else
+	    EDIT_CalcLineWidth_SL(hwnd, es);
+
+	EDIT_EM_SetSel(hwnd, es, s, s, FALSE);
+	es->flags |= EF_MODIFIED;
+	if (send_update) es->flags |= EF_UPDATE;
+	EDIT_EM_ScrollCaret(hwnd, es);
+
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(hwnd, es);
+
+	if (hrgn)
+	{
+		EDIT_UpdateTextRegion(hwnd, es, hrgn, TRUE);
+		DeleteObject(hrgn);
+	}
+	else
+	EDIT_UpdateText(hwnd, es, NULL, TRUE);
+
+	if(es->flags & EF_UPDATE)
+	{
+	    es->flags &= ~EF_UPDATE;
+	    EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SCROLL
+ *
+ */
+static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action)
+{
+	INT dy;
+
+	if (!(es->style & ES_MULTILINE))
+		return (LRESULT)FALSE;
+
+	dy = 0;
+
+	switch (action) {
+	case SB_LINEUP:
+		if (es->y_offset)
+			dy = -1;
+		break;
+	case SB_LINEDOWN:
+		if (es->y_offset < es->line_count - 1)
+			dy = 1;
+		break;
+	case SB_PAGEUP:
+		if (es->y_offset)
+			dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		break;
+	case SB_PAGEDOWN:
+		if (es->y_offset < es->line_count - 1)
+			dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		break;
+	default:
+		return (LRESULT)FALSE;
+	}
+	if (dy) {
+	    INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	    /* check if we are going to move too far */
+	    if(es->y_offset + dy > es->line_count - vlc)
+		dy = es->line_count - vlc - es->y_offset;
+
+	    /* Notification is done in EDIT_EM_LineScroll */
+	    if(dy)
+		EDIT_EM_LineScroll(hwnd, es, 0, dy);
+	}
+	return MAKELONG((INT16)dy, (BOOL16)TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SCROLLCARET
+ *
+ */
+static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es)
+{
+	if (es->style & ES_MULTILINE) {
+		INT l;
+		INT li;
+		INT vlc;
+		INT ww;
+		INT cw = es->char_width;
+		INT x;
+		INT dy = 0;
+		INT dx = 0;
+
+		l = EDIT_EM_LineFromChar(es, es->selection_end);
+		li = EDIT_EM_LineIndex(es, l);
+		x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP));
+		vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		if (l >= es->y_offset + vlc)
+			dy = l - vlc + 1 - es->y_offset;
+		if (l < es->y_offset)
+			dy = l - es->y_offset;
+		ww = es->format_rect.right - es->format_rect.left;
+		if (x < es->format_rect.left)
+			dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
+		if (x > es->format_rect.right)
+			dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
+		if (dy || dx)
+		{
+		    /* check if we are going to move too far */
+		    if(es->x_offset + dx + ww > es->text_width)
+			dx = es->text_width - ww - es->x_offset;
+		    if(dx || dy)
+			EDIT_EM_LineScroll_internal(hwnd, es, dx, dy);
+		}
+	} else {
+		INT x;
+		INT goal;
+		INT format_width;
+
+		if (!(es->style & ES_AUTOHSCROLL))
+			return;
+
+		x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
+		format_width = es->format_rect.right - es->format_rect.left;
+		if (x < es->format_rect.left) {
+			goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
+			do {
+				es->x_offset--;
+				x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
+			} while ((x < goal) && es->x_offset);
+			/* FIXME: use ScrollWindow() somehow to improve performance */
+			EDIT_UpdateText(hwnd, es, NULL, TRUE);
+		} else if (x > es->format_rect.right) {
+			INT x_last;
+			INT len = strlenW(es->text);
+			goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
+			do {
+				es->x_offset++;
+				x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
+				x_last = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, len, FALSE));
+			} while ((x > goal) && (x_last > es->format_rect.right));
+			/* FIXME: use ScrollWindow() somehow to improve performance */
+			EDIT_UpdateText(hwnd, es, NULL, TRUE);
+		}
+	}
+
+    if(es->flags & EF_FOCUSED)
+	EDIT_SetCaretPos(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETHANDLE
+ *
+ *	FIXME:	ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
+ *
+ */
+static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+
+	if (!(es->style & ES_MULTILINE))
+		return;
+
+	if (!hloc) {
+		WARN("called with NULL handle\n");
+		return;
+	}
+
+	EDIT_UnlockBuffer(hwnd, es, TRUE);
+
+#ifndef __WIN32OS2__
+	if(es->hloc16)
+	{
+	    LOCAL_Free(hInstance, es->hloc16);
+	    es->hloc16 = (HLOCAL16)NULL;
+	}
+#endif
+	if(es->is_unicode)
+	{
+	    if(es->hloc32A)
+	    {
+		LocalFree(es->hloc32A);
+		es->hloc32A = (HLOCAL)NULL;
+	    }
+	    es->hloc32W = hloc;
+	}
+	else
+	{
+	    INT countW, countA;
+	    HLOCAL hloc32W_new;
+	    WCHAR *textW;
+	    CHAR *textA;
+
+	    countA = LocalSize(hloc);
+	    textA = LocalLock(hloc);
+	    countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
+	    if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
+	    {
+		ERR("Could not allocate new unicode buffer\n");
+		return;
+	    }
+	    textW = LocalLock(hloc32W_new);
+	    MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
+	    LocalUnlock(hloc32W_new);
+	    LocalUnlock(hloc);
+
+	    if(es->hloc32W)
+		LocalFree(es->hloc32W);
+
+	    es->hloc32W = hloc32W_new;
+	    es->hloc32A = hloc;
+	}
+
+	es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
+
+	EDIT_LockBuffer(hwnd, es);
+
+	es->x_offset = es->y_offset = 0;
+	es->selection_start = es->selection_end = 0;
+	EDIT_EM_EmptyUndoBuffer(es);
+	es->flags &= ~EF_MODIFIED;
+	es->flags &= ~EF_UPDATE;
+	EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+	EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(hwnd, es);
+}
+
+
+#ifndef __WIN32OS2__
+/*********************************************************************
+ *
+ *	EM_SETHANDLE16
+ *
+ *	FIXME:	ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
+ *
+ */
+static void EDIT_EM_SetHandle16(HWND hwnd, EDITSTATE *es, HLOCAL16 hloc)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+	INT countW, countA;
+	HLOCAL hloc32W_new;
+	WCHAR *textW;
+	CHAR *textA;
+
+	if (!(es->style & ES_MULTILINE))
+		return;
+
+	if (!hloc) {
+		WARN("called with NULL handle\n");
+		return;
+	}
+
+	EDIT_UnlockBuffer(hwnd, es, TRUE);
+
+	if(es->hloc32A)
+	{
+	    LocalFree(es->hloc32A);
+	    es->hloc32A = (HLOCAL)NULL;
+	}
+
+	countA = LOCAL_Size(hInstance, hloc);
+	textA = LOCAL_Lock(hInstance, hloc);
+	countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
+	if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
+	{
+	    ERR("Could not allocate new unicode buffer\n");
+	    return;
+	}
+	textW = LocalLock(hloc32W_new);
+	MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
+	LocalUnlock(hloc32W_new);
+	LOCAL_Unlock(hInstance, hloc);
+
+	if(es->hloc32W)
+	    LocalFree(es->hloc32W);
+
+	es->hloc32W = hloc32W_new;
+	es->hloc16 = hloc;
+
+	es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
+
+	EDIT_LockBuffer(hwnd, es);
+
+	es->x_offset = es->y_offset = 0;
+	es->selection_start = es->selection_end = 0;
+	EDIT_EM_EmptyUndoBuffer(es);
+	es->flags &= ~EF_MODIFIED;
+	es->flags &= ~EF_UPDATE;
+	EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+	EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(hwnd, es);
+}
+#endif
+
+/*********************************************************************
+ *
+ *	EM_SETLIMITTEXT
+ *
+ *	FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
+ *	However, the windows version is not complied to yet in all of edit.c
+ *
+ */
+static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit)
+{
+	if (es->style & ES_MULTILINE) {
+		if (limit)
+			es->buffer_limit = min(limit, BUFLIMIT_MULTI);
+		else
+			es->buffer_limit = BUFLIMIT_MULTI;
+	} else {
+		if (limit)
+			es->buffer_limit = min(limit, BUFLIMIT_SINGLE);
+		else
+			es->buffer_limit = BUFLIMIT_SINGLE;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETMARGINS
+ *
+ * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
+ * action wParam despite what the docs say. EC_USEFONTINFO means one third
+ * of the char's width, according to the new docs.
+ *
+ */
+static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
+			       INT left, INT right)
+{
+	if (action & EC_LEFTMARGIN) {
+		if (left != EC_USEFONTINFO)
+			es->left_margin = left;
+		else
+			es->left_margin = es->char_width / 3;
+	}
+
+	if (action & EC_RIGHTMARGIN) {
+		if (right != EC_USEFONTINFO)
+ 			es->right_margin = right;
+		else
+			es->right_margin = es->char_width / 3;
+	}
+	TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETPASSWORDCHAR
+ *
+ */
+static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, WCHAR c)
+{
+    LONG style;
+
+	if (es->style & ES_MULTILINE)
+		return;
+
+	if (es->password_char == c)
+		return;
+
+        style = GetWindowLongA( hwnd, GWL_STYLE );
+	es->password_char = c;
+	if (c) {
+            SetWindowLongA( hwnd, GWL_STYLE, style | ES_PASSWORD );
+            es->style |= ES_PASSWORD;
+	} else {
+            SetWindowLongA( hwnd, GWL_STYLE, style & ~ES_PASSWORD );
+            es->style &= ~ES_PASSWORD;
+	}
+	EDIT_UpdateText(hwnd, es, NULL, TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_EM_SetSel
+ *
+ *	note:	unlike the specs say: the order of start and end
+ *		_is_ preserved in Windows.  (i.e. start can be > end)
+ *		In other words: this handler is OK
+ *
+ */
+static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
+{
+	UINT old_start = es->selection_start;
+	UINT old_end = es->selection_end;
+	UINT len = strlenW(es->text);
+
+	if (start == (UINT)-1) {
+		start = es->selection_end;
+		end = es->selection_end;
+	} else {
+		start = min(start, len);
+		end = min(end, len);
+	}
+	es->selection_start = start;
+	es->selection_end = end;
+	if (after_wrap)
+		es->flags |= EF_AFTER_WRAP;
+	else
+		es->flags &= ~EF_AFTER_WRAP;
+/* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
+        ORDER_UINT(start, end);
+        ORDER_UINT(end, old_end);
+        ORDER_UINT(start, old_start);
+        ORDER_UINT(old_start, old_end);
+	if (end != old_start)
+        {
+/*
+ * One can also do
+ *          ORDER_UINT32(end, old_start);
+ *          EDIT_InvalidateText(hwnd, es, start, end);
+ *          EDIT_InvalidateText(hwnd, es, old_start, old_end);
+ * in place of the following if statement.
+ */
+            if (old_start > end )
+            {
+                EDIT_InvalidateText(hwnd, es, start, end);
+                EDIT_InvalidateText(hwnd, es, old_start, old_end);
+            }
+            else
+            {
+                EDIT_InvalidateText(hwnd, es, start, old_start);
+                EDIT_InvalidateText(hwnd, es, end, old_end);
+            }
+	}
+        else EDIT_InvalidateText(hwnd, es, start, old_end);
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETTABSTOPS
+ *
+ */
+static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs)
+{
+	if (!(es->style & ES_MULTILINE))
+		return FALSE;
+	if (es->tabs)
+		HeapFree(GetProcessHeap(), 0, es->tabs);
+	es->tabs_count = count;
+	if (!count)
+		es->tabs = NULL;
+	else {
+		es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
+		memcpy(es->tabs, tabs, count * sizeof(INT));
+	}
+	return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETTABSTOPS16
+ *
+ */
+static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs)
+{
+	if (!(es->style & ES_MULTILINE))
+		return FALSE;
+	if (es->tabs)
+		HeapFree(GetProcessHeap(), 0, es->tabs);
+	es->tabs_count = count;
+	if (!count)
+		es->tabs = NULL;
+	else {
+		INT i;
+		es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
+		for (i = 0 ; i < count ; i++)
+			es->tabs[i] = *tabs++;
+	}
+	return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SETWORDBREAKPROC
+ *
+ */
+static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam)
+{
+	if (es->word_break_proc == (void *)lParam)
+		return;
+
+	es->word_break_proc = (void *)lParam;
+	es->word_break_proc16 = NULL;
+
+	if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
+		EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+		EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	}
+}
+
+
+#ifndef __WIN32OS2__
+/*********************************************************************
+ *
+ *	EM_SETWORDBREAKPROC16
+ *
+ */
+static void EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp)
+{
+	if (es->word_break_proc16 == wbp)
+		return;
+
+	es->word_break_proc = NULL;
+	es->word_break_proc16 = wbp;
+	if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
+		EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+		EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	}
+}
+#endif
+
+/*********************************************************************
+ *
+ *	EM_UNDO / WM_UNDO
+ *
+ */
+static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es)
+{
+	INT ulength;
+	LPWSTR utext;
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return FALSE;
+
+	ulength = strlenW(es->undo_text);
+	utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR));
+
+	strcpyW(utext, es->undo_text);
+
+	TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
+		     es->undo_insert_count, debugstr_w(utext));
+
+	EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+	EDIT_EM_EmptyUndoBuffer(es);
+	EDIT_EM_ReplaceSel(hwnd, es, TRUE, utext, FALSE);
+	EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+        /* send the notification after the selection start and end are set */
+        EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
+	EDIT_EM_ScrollCaret(hwnd, es);
+	HeapFree(GetProcessHeap(), 0, utext);
+
+	TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
+			es->undo_insert_count, debugstr_w(es->undo_text));
+	return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CHAR
+ *
+ */
+static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, WCHAR c)
+{
+        BOOL control;
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return;
+
+	control = GetKeyState(VK_CONTROL) & 0x8000;
+
+	switch (c) {
+	case '\r':
+	    /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
+	    if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
+		break;
+	case '\n':
+		if (es->style & ES_MULTILINE) {
+			if (es->style & ES_READONLY) {
+				EDIT_MoveHome(hwnd, es, FALSE);
+				EDIT_MoveDown_ML(hwnd, es, FALSE);
+			} else {
+				static const WCHAR cr_lfW[] = {'\r','\n',0};
+				EDIT_EM_ReplaceSel(hwnd, es, TRUE, cr_lfW, TRUE);
+			}
+		}
+		break;
+	case '\t':
+		if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
+		{
+			static const WCHAR tabW[] = {'\t',0};
+			EDIT_EM_ReplaceSel(hwnd, es, TRUE, tabW, TRUE);
+		}
+		break;
+	case VK_BACK:
+		if (!(es->style & ES_READONLY) && !control) {
+			if (es->selection_start != es->selection_end)
+				EDIT_WM_Clear(hwnd, es);
+			else {
+				/* delete character left of caret */
+				EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
+				EDIT_MoveBackward(hwnd, es, TRUE);
+				EDIT_WM_Clear(hwnd, es);
+			}
+		}
+		break;
+	case 0x03: /* ^C */
+		SendMessageW(hwnd, WM_COPY, 0, 0);
+		break;
+	case 0x16: /* ^V */
+		SendMessageW(hwnd, WM_PASTE, 0, 0);
+		break;
+	case 0x18: /* ^X */
+		SendMessageW(hwnd, WM_CUT, 0, 0);
+		break;
+
+	default:
+		if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) {
+			WCHAR str[2];
+ 			str[0] = c;
+ 			str[1] = '\0';
+ 			EDIT_EM_ReplaceSel(hwnd, es, TRUE, str, TRUE);
+ 		}
+		break;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	WM_COMMAND
+ *
+ */
+static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND control)
+{
+	if (code || control)
+		return;
+
+	switch (id) {
+		case EM_UNDO:
+			EDIT_EM_Undo(hwnd, es);
+			break;
+		case WM_CUT:
+			EDIT_WM_Cut(hwnd, es);
+			break;
+		case WM_COPY:
+			EDIT_WM_Copy(hwnd, es);
+			break;
+		case WM_PASTE:
+			EDIT_WM_Paste(hwnd, es);
+			break;
+		case WM_CLEAR:
+			EDIT_WM_Clear(hwnd, es);
+			break;
+		case EM_SETSEL:
+			EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE);
+			EDIT_EM_ScrollCaret(hwnd, es);
+			break;
+		default:
+			ERR("unknown menu item, please report\n");
+			break;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CONTEXTMENU
+ *
+ *	Note: the resource files resource/sysres_??.rc cannot define a
+ *		single popup menu.  Hence we use a (dummy) menubar
+ *		containing the single popup menu as its first item.
+ *
+ *	FIXME: the message identifiers have been chosen arbitrarily,
+ *		hence we use MF_BYPOSITION.
+ *		We might as well use the "real" values (anybody knows ?)
+ *		The menu definition is in resources/sysres_??.rc.
+ *		Once these are OK, we better use MF_BYCOMMAND here
+ *		(as we do in EDIT_WM_Command()).
+ *
+ */
+static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y)
+{
+	HMENU menu = LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU");
+	HMENU popup = GetSubMenu(menu, 0);
+	UINT start = es->selection_start;
+	UINT end = es->selection_end;
+
+	ORDER_UINT(start, end);
+
+	/* undo */
+	EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
+	/* cut */
+	EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
+	/* copy */
+	EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
+	/* paste */
+	EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
+	/* delete */
+	EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
+	/* select all */
+	EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != strlenW(es->text)) ? MF_ENABLED : MF_GRAYED));
+
+	TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hwnd, NULL);
+	DestroyMenu(menu);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_COPY
+ *
+ */
+static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es)
+{
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	HGLOBAL hdst;
+	LPWSTR dst;
+
+	if (e == s)
+		return;
+	ORDER_INT(s, e);
+	hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR));
+	dst = GlobalLock(hdst);
+	strncpyW(dst, es->text + s, e - s);
+	dst[e - s] = 0; /* ensure 0 termination */
+	TRACE("%s\n", debugstr_w(dst));
+	GlobalUnlock(hdst);
+	OpenClipboard(hwnd);
+	EmptyClipboard();
+	SetClipboardData(CF_UNICODETEXT, hdst);
+	CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CREATE
+ *
+ */
+static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name)
+{
+	TRACE("%s\n", debugstr_w(name));
+       /*
+        *	To initialize some final structure members, we call some helper
+        *	functions.  However, since the EDITSTATE is not consistent (i.e.
+        *	not fully initialized), we should be very careful which
+        *	functions can be called, and in what order.
+        */
+        EDIT_WM_SetFont(hwnd, es, 0, FALSE);
+        EDIT_EM_EmptyUndoBuffer(es);
+
+       if (name && *name) {
+	   EDIT_EM_ReplaceSel(hwnd, es, FALSE, name, FALSE);
+	   /* if we insert text to the editline, the text scrolls out
+            * of the window, as the caret is placed after the insert
+            * pos normally; thus we reset es->selection... to 0 and
+            * update caret
+            */
+	   es->selection_start = es->selection_end = 0;
+           /* send the notification after the selection start and end are set */
+           EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
+	   EDIT_EM_ScrollCaret(hwnd, es);
+       }
+       /* force scroll info update */
+       EDIT_UpdateScrollInfo(hwnd, es);
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_DESTROY
+ *
+ */
+static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es)
+{
+    HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
+	LINEDEF *pc, *pp;
+
+	if (es->hloc32W) {
+		while (LocalUnlock(es->hloc32W)) ;
+		LocalFree(es->hloc32W);
+	}
+	if (es->hloc32A) {
+		while (LocalUnlock(es->hloc32A)) ;
+		LocalFree(es->hloc32A);
+	}
+#ifndef __WIN32OS2__
+	if (es->hloc16) {
+		while (LOCAL_Unlock(hInstance, es->hloc16)) ;
+		LOCAL_Free(hInstance, es->hloc16);
+	}
+#endif
+	pc = es->first_line_def;
+	while (pc)
+	{
+		pp = pc->next;
+		HeapFree(GetProcessHeap(), 0, pc);
+		pc = pp;
+	}
+
+        SetWindowLongA( hwnd, 0, 0 );
+	HeapFree(GetProcessHeap(), 0, es);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_ERASEBKGND
+ *
+ */
+static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc)
+{
+	HBRUSH brush;
+	RECT rc;
+
+        if ( get_app_version() >= 0x40000 &&(
+                    !es->bEnableState || (es->style & ES_READONLY)))
+                brush = (HBRUSH)EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
+        else
+                brush = (HBRUSH)EDIT_SEND_CTLCOLOR(hwnd, dc);
+
+        if (!brush)
+                brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
+
+	GetClientRect(hwnd, &rc);
+	IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
+	GetClipBox(dc, &rc);
+	/*
+	 *	FIXME:	specs say that we should UnrealizeObject() the brush,
+	 *		but the specs of UnrealizeObject() say that we shouldn't
+	 *		unrealize a stock object.  The default brush that
+	 *		DefWndProc() returns is ... a stock object.
+	 */
+	FillRect(dc, &rc, brush);
+	return -1;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_GETTEXT
+ *
+ */
+static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode)
+{
+    if(!count) return 0;
+
+    if(unicode)
+    {
+	LPWSTR textW = (LPWSTR)lParam;
+	strncpyW(textW, es->text, count);
+	textW[count - 1] = 0; /* ensure 0 termination */
+	return strlenW(textW);
+    }
+    else
+    {
+	LPSTR textA = (LPSTR)lParam;
+	WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL);
+	textA[count - 1] = 0; /* ensure 0 termination */
+	return strlen(textA);
+    }
+}
+
+/*********************************************************************
+ *
+ *	WM_HSCROLL
+ *
+ */
+static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos)
+{
+	INT dx;
+	INT fw;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+
+	if (!(es->style & ES_AUTOHSCROLL))
+		return 0;
+
+	dx = 0;
+	fw = es->format_rect.right - es->format_rect.left;
+	switch (action) {
+	case SB_LINELEFT:
+		TRACE("SB_LINELEFT\n");
+		if (es->x_offset)
+			dx = -es->char_width;
+		break;
+	case SB_LINERIGHT:
+		TRACE("SB_LINERIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = es->char_width;
+		break;
+	case SB_PAGELEFT:
+		TRACE("SB_PAGELEFT\n");
+		if (es->x_offset)
+			dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
+		break;
+	case SB_PAGERIGHT:
+		TRACE("SB_PAGERIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
+		break;
+	case SB_LEFT:
+		TRACE("SB_LEFT\n");
+		if (es->x_offset)
+			dx = -es->x_offset;
+		break;
+	case SB_RIGHT:
+		TRACE("SB_RIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = es->text_width - es->x_offset;
+		break;
+	case SB_THUMBTRACK:
+		TRACE("SB_THUMBTRACK %d\n", pos);
+		es->flags |= EF_HSCROLL_TRACK;
+		if(es->style & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
+		break;
+	case SB_THUMBPOSITION:
+		TRACE("SB_THUMBPOSITION %d\n", pos);
+		es->flags &= ~EF_HSCROLL_TRACK;
+		if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
+		if (!dx) {
+			/* force scroll info update */
+			EDIT_UpdateScrollInfo(hwnd, es);
+			EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL");
+		}
+		break;
+	case SB_ENDSCROLL:
+		TRACE("SB_ENDSCROLL\n");
+		break;
+	/*
+	 *	FIXME : the next two are undocumented !
+	 *	Are we doing the right thing ?
+	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
+	 *	although it's also a regular control message.
+	 */
+	case EM_GETTHUMB: /* this one is used by NT notepad */
+	case EM_GETTHUMB16:
+	{
+		LRESULT ret;
+		if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL)
+		    ret = GetScrollPos(hwnd, SB_HORZ);
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT fw = es->format_rect.right - es->format_rect.left;
+		    ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
+		}
+		TRACE("EM_GETTHUMB: returning %ld\n", ret);
+		return ret;
+	}
+	case EM_LINESCROLL16:
+		TRACE("EM_LINESCROLL16\n");
+		dx = pos;
+		break;
+
+	default:
+		ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
+                    action, action);
+		return 0;
+	}
+	if (dx)
+	{
+	    INT fw = es->format_rect.right - es->format_rect.left;
+	    /* check if we are going to move too far */
+	    if(es->x_offset + dx + fw > es->text_width)
+		dx = es->text_width - fw - es->x_offset;
+	    if(dx)
+		EDIT_EM_LineScroll_internal(hwnd, es, dx, 0);
+	}
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_CheckCombo
+ *
+ */
+static BOOL EDIT_CheckCombo(HWND hwnd, EDITSTATE *es, UINT msg, INT key)
+{
+   HWND hLBox = es->hwndListBox;
+   HWND hCombo;
+   BOOL bDropped;
+   int  nEUI;
+
+   if (!hLBox)
+      return FALSE;
+
+   hCombo   = GetParent(hwnd);
+   bDropped = TRUE;
+   nEUI     = 0;
+
+   TRACE_(combo)("[%04x]: handling msg %04x (%04x)\n",
+       		     hwnd, (UINT16)msg, (UINT16)key);
+
+   if (key == VK_UP || key == VK_DOWN)
+   {
+      if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0))
+         nEUI = 1;
+
+      if (msg == WM_KEYDOWN || nEUI)
+          bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0);
+   }
+
+   switch (msg)
+   {
+      case WM_KEYDOWN:
+         if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
+         {
+            /* make sure ComboLBox pops up */
+            SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
+            key = VK_F4;
+            nEUI = 2;
+         }
+
+         SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
+         break;
+
+      case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
+         if (nEUI)
+            SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
+         else
+            SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)VK_F4, 0);
+         break;
+   }
+
+   if(nEUI == 2)
+      SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
+
+   return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_KEYDOWN
+ *
+ *	Handling of special keys that don't produce a WM_CHAR
+ *	(i.e. non-printable keys) & Backspace & Delete
+ *
+ */
+static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key)
+{
+	BOOL shift;
+	BOOL control;
+
+	if (GetKeyState(VK_MENU) & 0x8000)
+		return 0;
+
+	shift = GetKeyState(VK_SHIFT) & 0x8000;
+	control = GetKeyState(VK_CONTROL) & 0x8000;
+
+	switch (key) {
+	case VK_F4:
+	case VK_UP:
+		if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key) || key == VK_F4)
+			break;
+
+		/* fall through */
+	case VK_LEFT:
+		if ((es->style & ES_MULTILINE) && (key == VK_UP))
+			EDIT_MoveUp_ML(hwnd, es, shift);
+		else
+			if (control)
+				EDIT_MoveWordBackward(hwnd, es, shift);
+			else
+				EDIT_MoveBackward(hwnd, es, shift);
+		break;
+	case VK_DOWN:
+		if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key))
+			break;
+		/* fall through */
+	case VK_RIGHT:
+		if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
+			EDIT_MoveDown_ML(hwnd, es, shift);
+		else if (control)
+			EDIT_MoveWordForward(hwnd, es, shift);
+		else
+			EDIT_MoveForward(hwnd, es, shift);
+		break;
+	case VK_HOME:
+		EDIT_MoveHome(hwnd, es, shift);
+		break;
+	case VK_END:
+		EDIT_MoveEnd(hwnd, es, shift);
+		break;
+	case VK_PRIOR:
+		if (es->style & ES_MULTILINE)
+			EDIT_MovePageUp_ML(hwnd, es, shift);
+		else
+			EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key);
+		break;
+	case VK_NEXT:
+		if (es->style & ES_MULTILINE)
+			EDIT_MovePageDown_ML(hwnd, es, shift);
+		else
+			EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key);
+		break;
+	case VK_DELETE:
+		if (!(es->style & ES_READONLY) && !(shift && control)) {
+			if (es->selection_start != es->selection_end) {
+				if (shift)
+					EDIT_WM_Cut(hwnd, es);
+				else
+					EDIT_WM_Clear(hwnd, es);
+			} else {
+				if (shift) {
+					/* delete character left of caret */
+					EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
+					EDIT_MoveBackward(hwnd, es, TRUE);
+					EDIT_WM_Clear(hwnd, es);
+				} else if (control) {
+					/* delete to end of line */
+					EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
+					EDIT_MoveEnd(hwnd, es, TRUE);
+					EDIT_WM_Clear(hwnd, es);
+				} else {
+					/* delete character right of caret */
+					EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
+					EDIT_MoveForward(hwnd, es, TRUE);
+					EDIT_WM_Clear(hwnd, es);
+				}
+			}
+		}
+		break;
+	case VK_INSERT:
+		if (shift) {
+			if (!(es->style & ES_READONLY))
+				EDIT_WM_Paste(hwnd, es);
+		} else if (control)
+			EDIT_WM_Copy(hwnd, es);
+		break;
+	case VK_RETURN:
+	    /* If the edit doesn't want the return send a message to the default object */
+	    if(!(es->style & ES_WANTRETURN))
+	    {
+		HWND hwndParent = GetParent(hwnd);
+		DWORD dw = SendMessageW( hwndParent, DM_GETDEFID, 0, 0 );
+		if (HIWORD(dw) == DC_HASDEFID)
+		{
+		    SendMessageW( hwndParent, WM_COMMAND,
+				  MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
+ 			      (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
+		}
+	    }
+	    break;
+	}
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_KILLFOCUS
+ *
+ */
+static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es)
+{
+	es->flags &= ~EF_FOCUSED;
+	DestroyCaret();
+	if(!(es->style & ES_NOHIDESEL))
+		EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
+	EDIT_NOTIFY_PARENT(hwnd, es, EN_KILLFOCUS, "EN_KILLFOCUS");
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_LBUTTONDBLCLK
+ *
+ *	The caret position has been set on the WM_LBUTTONDOWN message
+ *
+ */
+static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es)
+{
+	INT s;
+	INT e = es->selection_end;
+	INT l;
+	INT li;
+	INT ll;
+
+	if (!(es->flags & EF_FOCUSED))
+		return 0;
+
+	l = EDIT_EM_LineFromChar(es, e);
+	li = EDIT_EM_LineIndex(es, l);
+	ll = EDIT_EM_LineLength(es, e);
+	s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
+	e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
+	EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
+	EDIT_EM_ScrollCaret(hwnd, es);
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_LBUTTONDOWN
+ *
+ */
+static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
+{
+	INT e;
+	BOOL after_wrap;
+
+	if (!(es->flags & EF_FOCUSED))
+		return 0;
+
+	es->bCaptureState = TRUE;
+	SetCapture(hwnd);
+	EDIT_ConfinePoint(es, &x, &y);
+	e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
+	EDIT_EM_SetSel(hwnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
+	EDIT_EM_ScrollCaret(hwnd, es);
+	es->region_posx = es->region_posy = 0;
+	SetTimer(hwnd, 0, 100, NULL);
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_LBUTTONUP
+ *
+ */
+static LRESULT EDIT_WM_LButtonUp(HWND hwndSelf, EDITSTATE *es)
+{
+	if (es->bCaptureState && GetCapture() == hwndSelf) {
+		KillTimer(hwndSelf, 0);
+		ReleaseCapture();
+	}
+	es->bCaptureState = FALSE;
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_MBUTTONDOWN
+ *
+ */
+static LRESULT EDIT_WM_MButtonDown(HWND hwnd)
+{
+    SendMessageW(hwnd,WM_PASTE,0,0);
+    return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_MOUSEMOVE
+ *
+ */
+static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y)
+{
+	INT e;
+	BOOL after_wrap;
+	INT prex, prey;
+
+	if (GetCapture() != hwnd)
+		return 0;
+
+	/*
+	 *	FIXME: gotta do some scrolling if outside client
+	 *		area.  Maybe reset the timer ?
+	 */
+	prex = x; prey = y;
+	EDIT_ConfinePoint(es, &x, &y);
+	es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
+	es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
+	e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
+	EDIT_EM_SetSel(hwnd, es, es->selection_start, e, after_wrap);
+	return 0;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_NCCREATE
+ *
+ * See also EDIT_WM_StyleChanged
+ */
+static LRESULT EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode)
+{
+	EDITSTATE *es;
+	UINT alloc_size;
+
+	TRACE("Creating %s edit control, style = %08lx\n",
+		unicode ? "Unicode" : "ANSI", style);
+
+	if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
+		return FALSE;
+        SetWindowLongA( hwnd, 0, (LONG)es );
+
+       /*
+        *      Note: since the EDITSTATE has not been fully initialized yet,
+        *            we can't use any API calls that may send
+        *            WM_XXX messages before WM_NCCREATE is completed.
+        */
+
+ 	es->is_unicode = unicode;
+ 	es->style = style;
+
+        es->bEnableState = !(style & WS_DISABLED);
+
+	/* Save parent, which will be notified by EN_* messages */
+	es->hwndParent = hwndParent;
+
+	if (es->style & ES_COMBO)
+	   es->hwndListBox = GetDlgItem(hwndParent, ID_CB_LISTBOX);
+
+        /* Number overrides lowercase overrides uppercase (at least it
+         * does in Win95).  However I'll bet that ES_NUMBER would be
+         * invalid under Win 3.1.
+         */
+        if (es->style & ES_NUMBER) {
+                ; /* do not override the ES_NUMBER */
+        }  else if (es->style & ES_LOWERCASE) {
+                es->style &= ~ES_UPPERCASE;
+        }
+	if (es->style & ES_MULTILINE) {
+		es->buffer_limit = BUFLIMIT_MULTI;
+		if (es->style & WS_VSCROLL)
+			es->style |= ES_AUTOVSCROLL;
+		if (es->style & WS_HSCROLL)
+			es->style |= ES_AUTOHSCROLL;
+		es->style &= ~ES_PASSWORD;
+		if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
+                        /* Confirmed - RIGHT overrides CENTER */
+			if (es->style & ES_RIGHT)
+				es->style &= ~ES_CENTER;
+			es->style &= ~WS_HSCROLL;
+			es->style &= ~ES_AUTOHSCROLL;
+		}
+
+		/* FIXME: for now, all multi line controls are AUTOVSCROLL */
+		es->style |= ES_AUTOVSCROLL;
+	} else {
+		es->buffer_limit = BUFLIMIT_SINGLE;
+                if (WIN31_LOOK == TWEAK_WineLook ||
+                    WIN95_LOOK == TWEAK_WineLook) {
+		        es->style &= ~ES_CENTER;
+		        es->style &= ~ES_RIGHT;
+                } else {
+			if (es->style & ES_RIGHT)
+				es->style &= ~ES_CENTER;
+                }
+		es->style &= ~WS_HSCROLL;
+		es->style &= ~WS_VSCROLL;
+		es->style &= ~ES_AUTOVSCROLL;
+		es->style &= ~ES_WANTRETURN;
+		if (es->style & ES_PASSWORD)
+			es->password_char = '*';
+
+		/* FIXME: for now, all single line controls are AUTOHSCROLL */
+		es->style |= ES_AUTOHSCROLL;
+	}
+
+	alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
+	if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
+	    return FALSE;
+	es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
+
+	if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
+		return FALSE;
+	es->undo_buffer_size = es->buffer_size;
+
+	if (es->style & ES_MULTILINE)
+		if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
+			return FALSE;
+	es->line_count = 1;
+
+	/*
+	 * In Win95 look and feel, the WS_BORDER style is replaced by the
+	 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
+	 * control a non client area.  Not always.  This coordinates in some
+         * way with the window creation code in dialog.c  When making
+         * modifications please ensure that the code still works for edit
+         * controls created directly with style 0x50800000, exStyle 0 (
+         * which should have a single pixel border)
+	 */
+	if (TWEAK_WineLook != WIN31_LOOK)
+	{
+	  es->style      &= ~WS_BORDER;
+	}
+	else
+	{
+	  if ((es->style & WS_BORDER) && !(es->style & WS_DLGFRAME))
+              SetWindowLongA( hwnd, GWL_STYLE,
+                              GetWindowLongA( hwnd, GWL_STYLE ) & ~WS_BORDER );
+	}
+
+	return TRUE;
+}
+
+/*********************************************************************
+ *
+ *	WM_PAINT
+ *
+ */
+static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam)
+{
+	PAINTSTRUCT ps;
+	INT i;
+	HDC dc;
+	HFONT old_font = 0;
+	RECT rc;
+	RECT rcLine;
+	RECT rcRgn;
+	BOOL rev = es->bEnableState &&
+				((es->flags & EF_FOCUSED) ||
+					(es->style & ES_NOHIDESEL));
+        if (!wParam)
+            dc = BeginPaint(hwnd, &ps);
+        else
+            dc = (HDC) wParam;
+	if(es->style & WS_BORDER) {
+		GetClientRect(hwnd, &rc);
+		if(es->style & ES_MULTILINE) {
+			if(es->style & WS_HSCROLL) rc.bottom++;
+			if(es->style & WS_VSCROLL) rc.right++;
+		}
+		Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom);
+	}
+	IntersectClipRect(dc, es->format_rect.left,
+				es->format_rect.top,
+				es->format_rect.right,
+				es->format_rect.bottom);
+	if (es->style & ES_MULTILINE) {
+		GetClientRect(hwnd, &rc);
+		IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
+	}
+	if (es->font)
+		old_font = SelectObject(dc, es->font);
+        if ( get_app_version() >= 0x40000 &&(
+                    !es->bEnableState || (es->style & ES_READONLY)))
+                EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
+        else
+                EDIT_SEND_CTLCOLOR(hwnd, dc);
+
+	if (!es->bEnableState)
+		SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
+	GetClipBox(dc, &rcRgn);
+	if (es->style & ES_MULTILINE) {
+		INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
+			EDIT_GetLineRect(hwnd, es, i, 0, -1, &rcLine);
+			if (IntersectRect(&rc, &rcRgn, &rcLine))
+				EDIT_PaintLine(hwnd, es, dc, i, rev);
+		}
+	} else {
+		EDIT_GetLineRect(hwnd, es, 0, 0, -1, &rcLine);
+		if (IntersectRect(&rc, &rcRgn, &rcLine))
+			EDIT_PaintLine(hwnd, es, dc, 0, rev);
+	}
+	if (es->font)
+		SelectObject(dc, old_font);
+
+        if (!wParam)
+            EndPaint(hwnd, &ps);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_PASTE
+ *
+ */
+static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es)
+{
+	HGLOBAL hsrc;
+	LPWSTR src;
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return;
+
+	OpenClipboard(hwnd);
+	if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
+		src = (LPWSTR)GlobalLock(hsrc);
+		EDIT_EM_ReplaceSel(hwnd, es, TRUE, src, TRUE);
+		GlobalUnlock(hsrc);
+	}
+	CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *	WM_SETFOCUS
+ *
+ */
+static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es)
+{
+	es->flags |= EF_FOCUSED;
+	CreateCaret(hwnd, 0, 2, es->line_height);
+	EDIT_SetCaretPos(hwnd, es, es->selection_end,
+			 es->flags & EF_AFTER_WRAP);
+	if(!(es->style & ES_NOHIDESEL))
+		EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
+	ShowCaret(hwnd);
+	EDIT_NOTIFY_PARENT(hwnd, es, EN_SETFOCUS, "EN_SETFOCUS");
+}
+
+
+/*********************************************************************
+ *
+ *	WM_SETFONT
+ *
+ * With Win95 look the margins are set to default font value unless
+ * the system font (font == 0) is being set, in which case they are left
+ * unchanged.
+ *
+ */
+static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw)
+{
+	TEXTMETRICW tm;
+	HDC dc;
+	HFONT old_font = 0;
+	RECT r;
+
+	es->font = font;
+	dc = GetDC(hwnd);
+	if (font)
+		old_font = SelectObject(dc, font);
+	GetTextMetricsW(dc, &tm);
+	es->line_height = tm.tmHeight;
+	es->char_width = tm.tmAveCharWidth;
+	if (font)
+		SelectObject(dc, old_font);
+	ReleaseDC(hwnd, dc);
+	if (font && (TWEAK_WineLook > WIN31_LOOK))
+		EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
+				   EC_USEFONTINFO, EC_USEFONTINFO);
+
+	/* Force the recalculation of the format rect for each font change */
+	GetClientRect(hwnd, &r);
+	EDIT_SetRectNP(hwnd, es, &r);
+
+	if (es->style & ES_MULTILINE)
+		EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
+	else
+	    EDIT_CalcLineWidth_SL(hwnd, es);
+
+	if (redraw)
+		EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	if (es->flags & EF_FOCUSED) {
+		DestroyCaret();
+		CreateCaret(hwnd, 0, 2, es->line_height);
+		EDIT_SetCaretPos(hwnd, es, es->selection_end,
+				 es->flags & EF_AFTER_WRAP);
+		ShowCaret(hwnd);
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	WM_SETTEXT
+ *
+ * NOTES
+ *  For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
+ *  The modified flag is reset. No notifications are sent.
+ *
+ *  For single-line controls, reception of WM_SETTEXT triggers:
+ *  The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
+ *
+ */
+static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPARAM lParam, BOOL unicode)
+{
+    LPWSTR text = NULL;
+
+    if(unicode)
+	text = (LPWSTR)lParam;
+    else if (lParam)
+    {
+	LPCSTR textA = (LPCSTR)lParam;
+	INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+	if((text = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+	    MultiByteToWideChar(CP_ACP, 0, textA, -1, text, countW);
+    }
+
+	EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE);
+	if (text) {
+		TRACE("%s\n", debugstr_w(text));
+		EDIT_EM_ReplaceSel(hwnd, es, FALSE, text, FALSE);
+		if(!unicode)
+		    HeapFree(GetProcessHeap(), 0, text);
+	} else {
+		static const WCHAR empty_stringW[] = {0};
+		TRACE("<NULL>\n");
+		EDIT_EM_ReplaceSel(hwnd, es, FALSE, empty_stringW, FALSE);
+	}
+	es->x_offset = 0;
+	es->flags &= ~EF_MODIFIED;
+	EDIT_EM_SetSel(hwnd, es, 0, 0, FALSE);
+        /* Send the notification after the selection start and end have been set
+         * edit control doesn't send notification on WM_SETTEXT
+         * if it is multiline, or it is part of combobox
+         */
+	if( !((es->style & ES_MULTILINE) || es->hwndListBox))
+       {
+	    EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
+           EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
+       }
+	EDIT_EM_ScrollCaret(hwnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_SIZE
+ *
+ */
+static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height)
+{
+	if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
+		RECT rc;
+		TRACE("width = %d, height = %d\n", width, height);
+		SetRect(&rc, 0, 0, width, height);
+		EDIT_SetRectNP(hwnd, es, &rc);
+		EDIT_UpdateText(hwnd, es, NULL, TRUE);
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	WM_STYLECHANGED
+ *
+ * This message is sent by SetWindowLong on having changed either the Style
+ * or the extended style.
+ *
+ * We ensure that the window's version of the styles and the EDITSTATE's agree.
+ *
+ * See also EDIT_WM_NCCreate
+ *
+ * It appears that the Windows version of the edit control allows the style
+ * (as retrieved by GetWindowLong) to be any value and maintains an internal
+ * style variable which will generally be different.  In this function we
+ * update the internal style based on what changed in the externally visible
+ * style.
+ *
+ * Much of this content as based upon the MSDN, especially:
+ *  Platform SDK Documentation -> User Interface Services ->
+ *      Windows User Interface -> Edit Controls -> Edit Control Reference ->
+ *      Edit Control Styles
+ */
+static LRESULT  EDIT_WM_StyleChanged (HWND hwnd,
+                                      EDITSTATE *es,
+                                      WPARAM which,
+                                      const STYLESTRUCT *style)
+{
+        if (GWL_STYLE == which) {
+                DWORD style_change_mask;
+                DWORD new_style;
+                /* Only a subset of changes can be applied after the control
+                 * has been created.
+                 */
+                style_change_mask = ES_UPPERCASE | ES_LOWERCASE |
+                                    ES_NUMBER;
+                if (es->style & ES_MULTILINE)
+                        style_change_mask |= ES_WANTRETURN;
+
+                new_style = style->styleNew & style_change_mask;
+
+                /* Number overrides lowercase overrides uppercase (at least it
+                 * does in Win95).  However I'll bet that ES_NUMBER would be
+                 * invalid under Win 3.1.
+                 */
+                if (new_style & ES_NUMBER) {
+                        ; /* do not override the ES_NUMBER */
+                }  else if (new_style & ES_LOWERCASE) {
+                        new_style &= ~ES_UPPERCASE;
+                }
+
+                es->style = (es->style & ~style_change_mask) | new_style;
+        } else if (GWL_EXSTYLE == which) {
+                ; /* FIXME - what is needed here */
+        } else {
+                WARN ("Invalid style change %d\n",which);
+        }
+
+        return 0;
+}
+
+/*********************************************************************
+ *
+ *	WM_SYSKEYDOWN
+ *
+ */
+static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
+{
+	if ((key == VK_BACK) && (key_data & 0x2000)) {
+		if (EDIT_EM_CanUndo(es))
+			EDIT_EM_Undo(hwnd, es);
+		return 0;
+	} else if (key == VK_UP || key == VK_DOWN) {
+		if (EDIT_CheckCombo(hwnd, es, WM_SYSKEYDOWN, key))
+			return 0;
+	}
+	return DefWindowProcW(hwnd, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_TIMER
+ *
+ */
+static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es)
+{
+	if (es->region_posx < 0) {
+		EDIT_MoveBackward(hwnd, es, TRUE);
+	} else if (es->region_posx > 0) {
+		EDIT_MoveForward(hwnd, es, TRUE);
+	}
+/*
+ *	FIXME: gotta do some vertical scrolling here, like
+ *		EDIT_EM_LineScroll(hwnd, 0, 1);
+ */
+}
+
+/*********************************************************************
+ *
+ *	WM_VSCROLL
+ *
+ */
+static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos)
+{
+	INT dy;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+
+	if (!(es->style & ES_AUTOVSCROLL))
+		return 0;
+
+	dy = 0;
+	switch (action) {
+	case SB_LINEUP:
+	case SB_LINEDOWN:
+	case SB_PAGEUP:
+	case SB_PAGEDOWN:
+		TRACE("action %d\n", action);
+		EDIT_EM_Scroll(hwnd, es, action);
+		return 0;
+	case SB_TOP:
+		TRACE("SB_TOP\n");
+		dy = -es->y_offset;
+		break;
+	case SB_BOTTOM:
+		TRACE("SB_BOTTOM\n");
+		dy = es->line_count - 1 - es->y_offset;
+		break;
+	case SB_THUMBTRACK:
+		TRACE("SB_THUMBTRACK %d\n", pos);
+		es->flags |= EF_VSCROLL_TRACK;
+		if(es->style & WS_VSCROLL)
+		    dy = pos - es->y_offset;
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc, new_y;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    new_y = pos * (es->line_count - vlc) / 100;
+		    dy = es->line_count ? (new_y - es->y_offset) : 0;
+		    TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
+			    es->line_count, es->y_offset, pos, dy);
+		}
+		break;
+	case SB_THUMBPOSITION:
+		TRACE("SB_THUMBPOSITION %d\n", pos);
+		es->flags &= ~EF_VSCROLL_TRACK;
+		if(es->style & WS_VSCROLL)
+		    dy = pos - es->y_offset;
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc, new_y;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    new_y = pos * (es->line_count - vlc) / 100;
+		    dy = es->line_count ? (new_y - es->y_offset) : 0;
+		    TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
+			    es->line_count, es->y_offset, pos, dy);
+		}
+		if (!dy)
+		{
+			/* force scroll info update */
+			EDIT_UpdateScrollInfo(hwnd, es);
+			EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL");
+		}
+		break;
+	case SB_ENDSCROLL:
+		TRACE("SB_ENDSCROLL\n");
+		break;
+	/*
+	 *	FIXME : the next two are undocumented !
+	 *	Are we doing the right thing ?
+	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
+	 *	although it's also a regular control message.
+	 */
+	case EM_GETTHUMB: /* this one is used by NT notepad */
+	case EM_GETTHUMB16:
+	{
+		LRESULT ret;
+		if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_VSCROLL)
+		    ret = GetScrollPos(hwnd, SB_VERT);
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
+		}
+		TRACE("EM_GETTHUMB: returning %ld\n", ret);
+		return ret;
+	}
+	case EM_LINESCROLL16:
+		TRACE("EM_LINESCROLL16 %d\n", pos);
+		dy = pos;
+		break;
+
+	default:
+		ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
+                    action, action);
+		return 0;
+	}
+	if (dy)
+		EDIT_EM_LineScroll(hwnd, es, 0, dy);
+	return 0;
+}
+
+/*********************************************************************
+ *
+ *	EDIT_UpdateText
+ *
+ */
+static void EDIT_UpdateTextRegion(HWND hwnd, EDITSTATE *es, HRGN hrgn, BOOL bErase)
+{
+    if (es->flags & EF_UPDATE) EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
+    InvalidateRgn(hwnd, hrgn, bErase);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_UpdateText
+ *
+ */
+static void EDIT_UpdateText(HWND hwnd, EDITSTATE *es, LPRECT rc, BOOL bErase)
+{
+    if (es->flags & EF_UPDATE) EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
+    InvalidateRect(hwnd, rc, bErase);
+}
Index: trunk/src/user32/edit.cpp
===================================================================
--- trunk/src/user32/edit.cpp	(revision 9522)
+++ 	(revision )
@@ -1,4395 +1,0 @@
-/* $Id: edit.cpp,v 1.47 2002-09-06 12:31:40 sandervl Exp $ */
-/*
- *      Edit control
- *
- *      Copyright  David W. Metcalfe, 1994
- *      Copyright  William Magro, 1995, 1996
- *      Copyright  Frans van Dorsselaer, 1996, 1997
- *
- *      Copyright  1999 Christoph Bratschi
- *
- * Corel version: 20000513
- * (WINE version: 991212)
- *
- * Status:  complete
- * Version: 5.00
- */
-
-/* CB: todo
-  - EN_ALIGN_LTR_EC, EN_ALIGN_RTL_EC -> undocumented notifications
-  - text alignment for single and multi line (ES_LEFT, ES_RIGHT, ES_CENTER)
-    new in Win98, Win2k: for single line too
-  - WinNT/Win2k: higher size limits (single: 0x7FFFFFFE, multi: none)
-    SvL: Limits removed. EM_SETTEXTLIMIT has no effect in NT4, SP6 (EM_GETTEXTLIMIT
-         only returns that value); limits are simply ignored, no EN_MAXTEXT is ever sent)
-  - too many redraws and recalculations!
-*/
-
-#include <stdlib.h>
-#include <os2win.h>
-#include <string.h>
-#include "controls.h"
-#include "combo.h"
-
-#define DBG_LOCALLOG    DBG_edit
-#include "dbglocal.h"
-
-#ifdef DEBUG
-char *GetMsgText(int Msg);
-#endif
-
-#define BUFLIMIT_MULTI          65534   /* maximum buffer size (not including '\0')
-                                           FIXME: BTW, Win95 specs say 65535 (do you dare ???) */
-#define BUFLIMIT_SINGLE         32766   /* maximum buffer size (not including '\0') */
-
-#ifdef __WIN32OS2__
-#define BUFLIMIT_SINGLE_NT	0x7FFFFFFF
-#endif
-//#define BUFLIMIT_MULTI  0xFFFFFFFE
-//#define BUFLIMIT_SINGLE 0x7FFFFFFF
-
-#define BUFSTART_MULTI          1024    /* starting size */
-#define BUFSTART_SINGLE         256     /* starting size */
-#define GROWLENGTH              64      /* buffers grow by this much */
-#define HSCROLL_FRACTION        3       /* scroll window by 1/3 width */
-
-/*
- *      extra flags for EDITSTATE.flags field
- */
-#define EF_MODIFIED             0x0001  /* text has been modified */
-#define EF_FOCUSED              0x0002  /* we have input focus */
-#define EF_UPDATE               0x0004  /* notify parent of changed state on next WM_PAINT */
-#define EF_VSCROLL_TRACK        0x0008  /* don't SetScrollPos() since we are tracking the thumb */
-#define EF_HSCROLL_TRACK        0x0010  /* don't SetScrollPos() since we are tracking the thumb */
-#define EF_VSCROLL_HACK         0x0020  /* we already have informed the user of the hacked handler */
-#define EF_HSCROLL_HACK         0x0040  /* we already have informed the user of the hacked handler */
-#define EF_AFTER_WRAP           0x0080  /* the caret is displayed after the last character of a
-                                           wrapped line, instead of in front of the next character */
-#define EF_USE_SOFTBRK          0x0100  /* Enable soft breaks in text. */
-
-typedef enum
-{
-        END_0 = 0,      /* line ends with terminating '\0' character */
-        END_WRAP,       /* line is wrapped */
-        END_HARD,       /* line ends with a hard return '\r\n' */
-        END_SOFT        /* line ends with a soft return '\r\r\n' */
-} LINE_END;
-
-typedef struct tagLINEDEF {
-        INT length;             /* bruto length of a line in bytes */
-        INT net_length; /* netto length of a line in visible characters */
-        LINE_END ending;
-        INT width;              /* width of the line in pixels */
-        struct tagLINEDEF *next;
-} LINEDEF;
-
-typedef struct
-{
-        HANDLE heap;                    /* our own heap */
-        LPSTR text;                     /* the actual contents of the control */
-        INT buffer_size;                /* the size of the buffer */
-        INT buffer_limit;               /* the maximum size to which the buffer may grow */
-        HFONT font;                     /* NULL means standard system font */
-        INT x_offset;                   /* scroll offset        for multi lines this is in pixels
-                                                                for single lines it's in characters */
-        INT line_height;                /* height of a screen line in pixels */
-        INT char_width;         /* average character width in pixels */
-        DWORD style;                    /* sane version of wnd->dwStyle */
-        WORD flags;                     /* flags that are not in es->style or wnd->flags (EF_XXX) */
-        INT undo_insert_count;  /* number of characters inserted in sequence */
-        INT undo_position;              /* character index of the insertion and deletion */
-        LPSTR undo_text;                /* deleted text */
-        INT undo_buffer_size;           /* size of the deleted text buffer */
-        INT selection_start;            /* == selection_end if no selection */
-        INT selection_end;              /* == current caret position */
-        CHAR password_char;             /* == 0 if no password char, and for multi line controls */
-        INT left_margin;                /* in pixels */
-        INT right_margin;               /* in pixels */
-        RECT format_rect;
-        INT region_posx;                /* Position of cursor relative to region: */
-        INT region_posy;                /* -1: to left, 0: within, 1: to right */
-        EDITWORDBREAKPROCA word_break_procA;
-        INT line_count;         /* number of lines */
-        INT y_offset;                   /* scroll offset in number of lines */
-        BOOL bCaptureState; /* flag indicating whether mouse was captured */
-        BOOL bEnableState;             /* flag keeping the enable state */
-	HWND hwndListBox;              /* handle of ComboBox's listbox or NULL */
-        /*
-         *      only for multi line controls
-         */
-        INT lock_count;         /* amount of re-entries in the EditWndProc */
-        INT tabs_count;
-        LPINT tabs;
-        INT text_width;         /* width of the widest line in pixels */
-        LINEDEF *first_line_def;        /* linked list of (soft) linebreaks */
-        HLOCAL hloc;          /* for controls receiving EM_GETHANDLE */
-} EDITSTATE;
-
-
-#define SWAP_INT32(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0)
-#define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT32((x),(y)); } while(0)
-
-#define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
-#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
-
-/* used for disabled or read-only edit control */
-#define EDIT_SEND_CTLCOLORSTATIC(hwnd,hdc) \
-        (SendMessageA(GetParent(hwnd), WM_CTLCOLORSTATIC, \
-                        (WPARAM)(hdc), (LPARAM)hwnd))
-#define EDIT_SEND_CTLCOLOR(hwnd,hdc) \
-        (SendMessageA(GetParent(hwnd), WM_CTLCOLOREDIT, \
-                        (WPARAM)(hdc), (LPARAM)hwnd))
-#define EDIT_NOTIFY_PARENT(hwnd, wNotifyCode) \
-        (SendMessageA(GetParent(hwnd), WM_COMMAND, \
-                     MAKEWPARAM(GetWindowLongA(hwnd,GWL_ID), wNotifyCode), (LPARAM)hwnd))
-
-/*********************************************************************
- *
- *      Declarations
- *
- */
-
-/*
- *      These functions have trivial implementations
- *      We still like to call them internally
- *      "static inline" makes them more like macro's
- */
-static inline BOOL      EDIT_EM_CanUndo(HWND hwnd, EDITSTATE *es);
-static inline void      EDIT_EM_EmptyUndoBuffer(HWND hwnd, EDITSTATE *es);
-static inline void      EDIT_WM_Clear(HWND hwnd, EDITSTATE *es);
-static inline void      EDIT_WM_Cut(HWND hwnd, EDITSTATE *es);
-
-/*
- *      Helper functions only valid for one type of control
- */
-static void     EDIT_BuildLineDefs_ML(HWND hwnd,EDITSTATE *es);
-static LPSTR    EDIT_GetPasswordPointer_SL(HWND hwnd, EDITSTATE *es);
-static void     EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
-static VOID     EDIT_UpdateScrollBars(HWND hwnd,EDITSTATE *es,BOOL updateHorz,BOOL updateVert);
-/*
- *      Helper functions valid for both single line _and_ multi line controls
- */
-static INT      EDIT_CallWordBreakProc(HWND hwnd, EDITSTATE *es, INT start, INT index, INT count, INT action);
-static INT      EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
-static void     EDIT_ConfinePoint(HWND hwnd, EDITSTATE *es, LPINT x, LPINT y);
-static void     EDIT_GetLineRect(HWND hwnd,HDC dc,EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
-static void     EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end);
-static void     EDIT_LockBuffer(HWND hwnd, EDITSTATE *es);
-static BOOL     EDIT_MakeFit(HWND hwnd, EDITSTATE *es, INT size);
-static BOOL     EDIT_MakeUndoFit(HWND hwnd, EDITSTATE *es, INT size);
-static void     EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend);
-static void     EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev);
-static INT      EDIT_PaintText(HWND hwnd, EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
-static void     EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, BOOL after_wrap);
-static void     EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT lprc);
-static void     EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force);
-static INT      EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action);
-static VOID     EDIT_Draw(HWND hwnd,EDITSTATE *es,HDC hdc);
-static VOID     EDIT_Refresh(HWND hwnd,EDITSTATE *es,BOOL useCache);
-
-/*
- *      EM_XXX message handlers
- */
-static LRESULT  EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y);
-static BOOL     EDIT_EM_FmtLines(HWND hwnd, EDITSTATE *es, BOOL add_eol);
-static INT      EDIT_EM_GetFirstVisibleLine(HWND hwnd,EDITSTATE *es);
-static HLOCAL   EDIT_EM_GetHandle(HWND hwnd, EDITSTATE *es);
-static INT      EDIT_EM_GetLimitText(HWND hwnd,EDITSTATE *es);
-static INT      EDIT_EM_GetLine(HWND hwnd, EDITSTATE *es, INT line, LPSTR lpch);
-static INT      EDIT_EM_GetLineCount(HWND hwnd,EDITSTATE *es);
-static LONG     EDIT_EM_GetMargins(HWND hwnd,EDITSTATE *es);
-static BOOL     EDIT_EM_GetModify(HWND hwnd,EDITSTATE *es);
-static CHAR     EDIT_EM_GetPasswordChar(HWND hwnd,EDITSTATE *es);
-static VOID     EDIT_EM_GetRect(HWND hwnd,EDITSTATE *es,LPRECT lprc);
-static LRESULT  EDIT_EM_GetSel(HWND hwnd, EDITSTATE *es, LPUINT start, LPUINT end);
-static LRESULT  EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es);
-static PVOID    EDIT_EM_GetWordbreakProc(HWND hwnd,EDITSTATE *es);
-static INT      EDIT_EM_LineFromChar(HWND hwnd, EDITSTATE *es, INT index);
-static INT      EDIT_EM_LineIndex(HWND hwnd, EDITSTATE *es, INT line);
-static INT      EDIT_EM_LineLength(HWND hwnd, EDITSTATE *es, INT index);
-static BOOL     EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
-static LRESULT  EDIT_EM_PosFromChar(HWND hwnd,HDC dc, EDITSTATE *es, INT index, BOOL after_wrap);
-static void     EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace);
-static LRESULT  EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action);
-static void     EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es);
-static void     EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc);
-static void     EDIT_EM_SetLimitText(HWND hwnd, EDITSTATE *es, INT limit);
-static void     EDIT_EM_SetMargins(HWND hwnd, EDITSTATE *es, INT action, INT left, INT right);
-static void     EDIT_EM_SetModify(HWND hwnd,EDITSTATE *es,BOOL fModified);
-static void     EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, CHAR c);
-static BOOL     EDIT_EM_SetReadOnly(HWND hwnd,EDITSTATE *es,BOOL fReadOnly);
-static void     EDIT_EM_SetRect(HWND hwnd,EDITSTATE *es,LPRECT lprc);
-static void     EDIT_EM_SetRectNP(HWND hwnd,EDITSTATE *es,LPRECT lprc);
-static void     EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
-static BOOL     EDIT_EM_SetTabStops(HWND hwnd, EDITSTATE *es, INT count, LPINT tabs);
-static void     EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp);
-static BOOL     EDIT_EM_Undo(HWND hwnd, EDITSTATE *es);
-static LRESULT  EDIT_EM_SetIMEStatus(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam);
-static LRESULT  EDIT_EM_GetIMEStatus(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam);
-/*
- *      WM_XXX message handlers
- */
-static void     EDIT_WM_Char(HWND hwnd, EDITSTATE *es, CHAR c, DWORD key_data);
-static void     EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND conrtol);
-static void     EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, HWND hwndBtn, INT x, INT y);
-static void     EDIT_WM_Copy(HWND hwnd, EDITSTATE *es);
-static LRESULT  EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCREATESTRUCTA cs);
-static void     EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es);
-static LRESULT  EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc);
-static INT      EDIT_WM_GetText(HWND hwnd, EDITSTATE *es, INT count, LPSTR text);
-static LRESULT  EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
-static LRESULT  EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
-static LRESULT  EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es, HWND window_getting_focus);
-static LRESULT  EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
-static LRESULT  EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
-static LRESULT  EDIT_WM_LButtonUp(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
-static LRESULT  EDIT_WM_CaptureChanged(HWND hwnd,EDITSTATE *es);
-static LRESULT  EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
-static LRESULT  EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTA cs);
-static void     EDIT_WM_Paint(HWND hwnd, EDITSTATE *es,WPARAM wParam);
-static void     EDIT_WM_Paste(HWND hwnd, EDITSTATE *es);
-static void     EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es, HWND window_losing_focus);
-static void     EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw);
-static void     EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPCSTR text);
-static void     EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height);
-static LRESULT  EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
-static void     EDIT_WM_Timer(HWND hwnd, EDITSTATE *es, INT id, TIMERPROC timer_proc);
-static LRESULT  EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
-static LRESULT EDIT_WM_MouseWheel(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam);
-
-/*********************************************************************
- *
- *      EM_CANUNDO
- *
- */
-static inline BOOL EDIT_EM_CanUndo(HWND hwnd, EDITSTATE *es)
-{
-        return (es->undo_insert_count || lstrlenA(es->undo_text));
-}
-
-
-/*********************************************************************
- *
- *      EM_EMPTYUNDOBUFFER
- *
- */
-static inline void EDIT_EM_EmptyUndoBuffer(HWND hwnd, EDITSTATE *es)
-{
-        es->undo_insert_count = 0;
-        *es->undo_text = '\0';
-}
-
-
-/*********************************************************************
- *
- *      WM_CLEAR
- *
- */
-static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es)
-{
-        EDIT_EM_ReplaceSel(hwnd, es, TRUE, "");
-        if (es->flags & EF_UPDATE) {
-                es->flags &= ~EF_UPDATE;
-                EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_CUT
- *
- */
-static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es)
-{
-        EDIT_WM_Copy(hwnd, es);
-        EDIT_WM_Clear(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EditWndProc()
- *
- *      The messages are in the order of the actual integer values
- *      (which can be found in include/windows.h)
- *      Whereever possible the 16 bit versions are converted to
- *      the 32 bit ones, so that we can 'fall through' to the
- *      helper functions.  These are mostly 32 bit (with a few
- *      exceptions, clearly indicated by a '16' extension to their
- *      names).
- *
- */
-LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg,
-                            WPARAM wParam, LPARAM lParam )
-{
-        EDITSTATE *es = (EDITSTATE*)GetInfoPtr(hwnd);
-        LRESULT result = 0;
-
-//      dprintf(("EditWndProc hwnd: %04x, msg %s, wp %08x lp %08lx\n",
-//               hwnd, GetMsgText(msg), wParam, lParam));
-
-        switch (msg) {
-        case WM_DESTROY:
-                //DPRINTF_EDIT_MSG32("WM_DESTROY");
-                EDIT_WM_Destroy(hwnd, es);
-                result = 0;
-                goto END;
-
-        case WM_NCCREATE:
-                //DPRINTF_EDIT_MSG32("WM_NCCREATE");
-                result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTA)lParam);
-                goto END;
-        }
-
-        if (!es)
-        {
-            result = DefWindowProcA(hwnd, msg, wParam, lParam);
-            goto END;
-        }
-
-
-        EDIT_LockBuffer(hwnd, es);
-        switch (msg) {
-        case EM_GETSEL:
-                //DPRINTF_EDIT_MSG32("EM_GETSEL");
-                result = EDIT_EM_GetSel(hwnd, es, (LPUINT)wParam, (LPUINT)lParam);
-                break;
-
-        case EM_SETSEL:
-                //DPRINTF_EDIT_MSG32("EM_SETSEL");
-                EDIT_EM_SetSel(hwnd, es, wParam, lParam, FALSE);
-                EDIT_EM_ScrollCaret(hwnd,es);
-                result = 1;
-                break;
-
-        case EM_GETRECT:
-                //DPRINTF_EDIT_MSG32("EM_GETRECT");
-                EDIT_EM_GetRect(hwnd,es,(LPRECT)lParam);
-                break;
-
-        case EM_SETRECT:
-                //DPRINTF_EDIT_MSG32("EM_SETRECT");
-                EDIT_EM_SetRect(hwnd,es,(LPRECT)lParam);
-                break;
-
-        case EM_SETRECTNP:
-                //DPRINTF_EDIT_MSG32("EM_SETRECTNP");
-                EDIT_EM_SetRectNP(hwnd,es,(LPRECT)lParam);
-                break;
-
-        case EM_SCROLL:
-                //DPRINTF_EDIT_MSG32("EM_SCROLL");
-                result = EDIT_EM_Scroll(hwnd, es, (INT)wParam);
-                break;
-
-        case EM_LINESCROLL:
-                //DPRINTF_EDIT_MSG32("EM_LINESCROLL");
-                result = (LRESULT)EDIT_EM_LineScroll(hwnd, es, (INT)wParam, (INT)lParam);
-                break;
-
-        case EM_SCROLLCARET:
-                //DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
-                EDIT_EM_ScrollCaret(hwnd, es);
-                result = 1;
-                break;
-
-        case EM_GETMODIFY:
-                //DPRINTF_EDIT_MSG32("EM_GETMODIFY");
-                result = (LRESULT)EDIT_EM_GetModify(hwnd,es);
-                break;
-
-        case EM_SETMODIFY:
-                //DPRINTF_EDIT_MSG32("EM_SETMODIFY");
-                EDIT_EM_SetModify(hwnd,es,(BOOL)wParam);
-                break;
-
-        case EM_GETLINECOUNT:
-                //DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
-                result = (LRESULT)EDIT_EM_GetLineCount(hwnd,es);
-                break;
-
-        case EM_LINEINDEX:
-                //DPRINTF_EDIT_MSG32("EM_LINEINDEX");
-                result = (LRESULT)EDIT_EM_LineIndex(hwnd, es, (INT)wParam);
-                break;
-
-        case EM_SETHANDLE:
-                //DPRINTF_EDIT_MSG32("EM_SETHANDLE");
-                EDIT_EM_SetHandle(hwnd, es, (HLOCAL)wParam);
-                break;
-
-        case EM_GETHANDLE:
-                //DPRINTF_EDIT_MSG32("EM_GETHANDLE");
-                result = (LRESULT)EDIT_EM_GetHandle(hwnd, es);
-                break;
-
-        case EM_GETTHUMB:
-                //DPRINTF_EDIT_MSG32("EM_GETTHUMB");
-                result = EDIT_EM_GetThumb(hwnd, es);
-                break;
-
-        /* messages 0x00bf and 0x00c0 missing from specs */
-
-        case WM_USER+15:
-                //DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
-                /* fall through */
-        case 0x00bf:
-                //DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
-                result = DefWindowProcA(hwnd, msg, wParam, lParam);
-                break;
-
-        case WM_USER+16:
-                //DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
-                /* fall through */
-        case 0x00c0:
-                //DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
-                result = DefWindowProcA(hwnd, msg, wParam, lParam);
-                break;
-
-        case EM_LINELENGTH:
-                //DPRINTF_EDIT_MSG32("EM_LINELENGTH");
-                result = (LRESULT)EDIT_EM_LineLength(hwnd, es, (INT)wParam);
-                break;
-
-        case EM_REPLACESEL:
-                //DPRINTF_EDIT_MSG32("EM_REPLACESEL");
-                EDIT_EM_ReplaceSel(hwnd, es, (BOOL)wParam, (LPCSTR)lParam);
-                result = 1;
-                break;
-
-        /* message 0x00c3 missing from specs */
-
-        case WM_USER+19:
-                //DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
-                /* fall through */
-        case 0x00c3:
-                //DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
-                result = DefWindowProcA(hwnd, msg, wParam, lParam);
-                break;
-
-        case EM_GETLINE:
-                //DPRINTF_EDIT_MSG32("EM_GETLINE");
-                result = (LRESULT)EDIT_EM_GetLine(hwnd, es, (INT)wParam, (LPSTR)lParam);
-                break;
-
-        case EM_SETLIMITTEXT:
-                //DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
-                EDIT_EM_SetLimitText(hwnd, es, (INT)wParam);
-                break;
-
-        case EM_CANUNDO:
-                //DPRINTF_EDIT_MSG32("EM_CANUNDO");
-                result = (LRESULT)EDIT_EM_CanUndo(hwnd, es);
-                break;
-
-        case EM_UNDO:
-                /* fall through */
-        case WM_UNDO:
-                //DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
-                result = (LRESULT)EDIT_EM_Undo(hwnd, es);
-                break;
-
-        case EM_FMTLINES:
-                //DPRINTF_EDIT_MSG32("EM_FMTLINES");
-                result = (LRESULT)EDIT_EM_FmtLines(hwnd, es, (BOOL)wParam);
-                break;
-
-        case EM_LINEFROMCHAR:
-                //DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
-                result = (LRESULT)EDIT_EM_LineFromChar(hwnd, es, (INT)wParam);
-                break;
-
-        /* message 0x00ca missing from specs */
-
-        case WM_USER+26:
-                //DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
-                /* fall through */
-        case 0x00ca:
-                //DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
-                result = DefWindowProcA(hwnd, msg, wParam, lParam);
-                break;
-
-        case EM_SETTABSTOPS:
-                //DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
-                result = (LRESULT)EDIT_EM_SetTabStops(hwnd, es, (INT)wParam, (LPINT)lParam);
-                break;
-
-        case EM_SETPASSWORDCHAR:
-                //DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
-                EDIT_EM_SetPasswordChar(hwnd, es, (CHAR)wParam);
-                break;
-
-        case EM_EMPTYUNDOBUFFER:
-                //DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
-                EDIT_EM_EmptyUndoBuffer(hwnd, es);
-                break;
-
-        case EM_GETFIRSTVISIBLELINE:
-                //DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
-                result = (LRESULT)EDIT_EM_GetFirstVisibleLine(hwnd,es);
-                break;
-
-        case EM_SETREADONLY:
-                //DPRINTF_EDIT_MSG32("EM_SETREADONLY");
-                result = (LRESULT)EDIT_EM_SetReadOnly(hwnd,es,(BOOL)wParam);
-                break;
-
-        case EM_SETWORDBREAKPROC:
-                //DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
-                EDIT_EM_SetWordBreakProc(hwnd, es, (EDITWORDBREAKPROCA)lParam);
-                break;
-
-        case EM_GETWORDBREAKPROC:
-                //DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
-                result = (LRESULT)EDIT_EM_GetWordbreakProc(hwnd,es);
-                break;
-
-        case EM_GETPASSWORDCHAR:
-                //DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
-                result = (LRESULT)EDIT_EM_GetPasswordChar(hwnd,es);
-                break;
-
-        /* The following EM_xxx are new to win95 and don't exist for 16 bit */
-
-        case EM_SETMARGINS:
-                //DPRINTF_EDIT_MSG32("EM_SETMARGINS");
-                EDIT_EM_SetMargins(hwnd, es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case EM_GETMARGINS:
-                //DPRINTF_EDIT_MSG32("EM_GETMARGINS");
-                result = EDIT_EM_GetMargins(hwnd,es);
-                break;
-
-        case EM_GETLIMITTEXT:
-                //DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
-                result = (LRESULT)EDIT_EM_GetLimitText(hwnd,es);
-                break;
-
-        case EM_POSFROMCHAR:
-                //DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
-                result = EDIT_EM_PosFromChar(hwnd,0, es, (INT)wParam, FALSE);
-                break;
-
-        case EM_CHARFROMPOS:
-                //DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
-                result = EDIT_EM_CharFromPos(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case EM_SETIMESTATUS:
-                result = EDIT_EM_SetIMEStatus(hwnd,es,wParam,lParam);
-                break;
-
-        case EM_GETIMESTATUS:
-                result = EDIT_EM_GetIMEStatus(hwnd,es,wParam,lParam);
-                break;
-
-        case WM_GETDLGCODE:
-                //DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
-                result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
-
-       		if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
-		{
-		   int vk = (int)((LPMSG)lParam)->wParam;
-
-		   if ((GetWindowLongA(hwnd,GWL_STYLE) & ES_WANTRETURN) && vk == VK_RETURN)
-		   {
-		      result |= DLGC_WANTMESSAGE;
-		   }
-		   else if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE))
-		   {
-		      if (SendMessageA(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
-		         result |= DLGC_WANTMESSAGE;
-		   }
-		}
-		break;
-
-        case WM_CHAR:
-                //DPRINTF_EDIT_MSG32("WM_CHAR");
-		if (((CHAR)wParam == VK_RETURN || (CHAR)wParam == VK_ESCAPE) && es->hwndListBox)
-		{
-		   HWND hwndParent = GetParent(hwnd);
-		
-		   if (SendMessageA(hwndParent, CB_GETDROPPEDSTATE, 0, 0))
-		      SendMessageA(hwndParent, WM_KEYDOWN, wParam, 0);
-		   break;
-		}
-                EDIT_WM_Char(hwnd, es, (CHAR)wParam, (DWORD)lParam);
-                break;
-
-        case WM_CLEAR:
-                //DPRINTF_EDIT_MSG32("WM_CLEAR");
-                EDIT_WM_Clear(hwnd, es);
-                break;
-
-        case WM_COMMAND:
-                //DPRINTF_EDIT_MSG32("WM_COMMAND");
-                EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
-                break;
-
-        case WM_CONTEXTMENU:
-                //DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
-                EDIT_WM_ContextMenu(hwnd, es, (HWND)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case WM_COPY:
-                //DPRINTF_EDIT_MSG32("WM_COPY");
-                EDIT_WM_Copy(hwnd, es);
-                break;
-
-        case WM_CREATE:
-                //DPRINTF_EDIT_MSG32("WM_CREATE");
-                result = EDIT_WM_Create(hwnd, es, (LPCREATESTRUCTA)lParam);
-                break;
-
-        case WM_CUT:
-                //DPRINTF_EDIT_MSG32("WM_CUT");
-                EDIT_WM_Cut(hwnd, es);
-                break;
-
-        case WM_ENABLE:
-                //DPRINTF_EDIT_MSG32("WM_ENABLE");
-                es->bEnableState = (BOOL)wParam;
-                EDIT_Refresh(hwnd,es,FALSE);
-                break;
-
-        case WM_ERASEBKGND:
-                //DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
-                result = EDIT_WM_EraseBkGnd(hwnd, es, (HDC)wParam);
-                break;
-
-        case WM_GETFONT:
-                //DPRINTF_EDIT_MSG32("WM_GETFONT");
-                result = (LRESULT)es->font;
-                break;
-
-        case WM_GETTEXT:
-                //DPRINTF_EDIT_MSG32("WM_GETTEXT");
-                result = (LRESULT)EDIT_WM_GetText(hwnd, es, (INT)wParam, (LPSTR)lParam);
-                break;
-
-        case WM_GETTEXTLENGTH:
-                //DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
-                result = lstrlenA(es->text);
-                break;
-
-        case WM_HSCROLL:
-                //DPRINTF_EDIT_MSG32("WM_HSCROLL");
-                result = EDIT_WM_HScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)lParam);
-                break;
-
-        case WM_KEYDOWN:
-                //DPRINTF_EDIT_MSG32("WM_KEYDOWN");
-                result = EDIT_WM_KeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
-                break;
-
-        case WM_KILLFOCUS:
-                //DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
-                result = EDIT_WM_KillFocus(hwnd, es, (HWND)wParam);
-                break;
-
-        case WM_LBUTTONDBLCLK:
-                //DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
-                result = EDIT_WM_LButtonDblClk(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case WM_LBUTTONDOWN:
-                //DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
-                result = EDIT_WM_LButtonDown(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case WM_LBUTTONUP:
-                //DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
-                result = EDIT_WM_LButtonUp(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case WM_CAPTURECHANGED:
-                result = EDIT_WM_CaptureChanged(hwnd,es);
-                break;
-
-        case WM_MOUSEACTIVATE:
-                /*
-                 *      FIXME: maybe DefWindowProc() screws up, but it seems that
-                 *              modalless dialog boxes need this.  If we don't do this, the focus
-                 *              will _not_ be set by DefWindowProc() for edit controls in a
-                 *              modalless dialog box ???
-                 */
-                //DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
-		SetFocus(hwnd);
-                result = MA_ACTIVATE;
-                break;
-
-        case WM_MOUSEMOVE:
-                /*
-                 *      DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
-                 */
-                result = EDIT_WM_MouseMove(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
-                break;
-
-        case WM_PAINT:
-                //DPRINTF_EDIT_MSG32("WM_PAINT");
-                EDIT_WM_Paint(hwnd, es,wParam);
-                break;
-
-        case WM_PASTE:
-                //DPRINTF_EDIT_MSG32("WM_PASTE");
-                EDIT_WM_Paste(hwnd, es);
-                break;
-
-        case WM_SETFOCUS:
-                //DPRINTF_EDIT_MSG32("WM_SETFOCUS");
-                EDIT_WM_SetFocus(hwnd, es, (HWND)wParam);
-                break;
-
-        case WM_SETFONT:
-                //DPRINTF_EDIT_MSG32("WM_SETFONT");
-                EDIT_WM_SetFont(hwnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
-                break;
-
-        case WM_SETTEXT:
-                //DPRINTF_EDIT_MSG32("WM_SETTEXT");
-                EDIT_WM_SetText(hwnd, es, (LPCSTR)lParam);
-                result = TRUE;
-                break;
-
-        case WM_SIZE:
-                //DPRINTF_EDIT_MSG32("WM_SIZE");
-                EDIT_WM_Size(hwnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
-                break;
-
-        case WM_SYSKEYDOWN:
-                //DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
-                result = EDIT_WM_SysKeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
-                break;
-
-        case WM_TIMER:
-                //DPRINTF_EDIT_MSG32("WM_TIMER");
-                EDIT_WM_Timer(hwnd, es, (INT)wParam, (TIMERPROC)lParam);
-                break;
-
-        case WM_VSCROLL:
-                //DPRINTF_EDIT_MSG32("WM_VSCROLL");
-                result = EDIT_WM_VScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)(lParam));
-                break;
-
-        case WM_MOUSEWHEEL:
-                result = EDIT_WM_MouseWheel(hwnd,es,wParam,lParam);
-                break;
-
-        default:
-                result = DefWindowProcA(hwnd, msg, wParam, lParam);
-                break;
-        }
-        EDIT_UnlockBuffer(hwnd, es, FALSE);
-    END:
-        return result;
-
-}
-
-
-/*********************************************************************
- *
- *      EDIT_BuildLineDefs_ML
- *
- *      Build linked list of text lines.
- *      Lines can end with '\0' (last line), a character (if it is wrapped),
- *      a soft return '\r\r\n' or a hard return '\r\n'
- *
- */
-static void EDIT_BuildLineDefs_ML(HWND hwnd,EDITSTATE *es)
-{
-        HDC hdc = 0;
-        HFONT old_font = 0;
-        LPSTR start, cp;
-        INT fw;
-        LINEDEF *current_def;
-        LINEDEF **previous_next;
-
-        current_def = es->first_line_def;
-        do {
-                LINEDEF *next_def = current_def->next;
-                HeapFree(es->heap, 0, current_def);
-                current_def = next_def;
-        } while (current_def);
-        es->line_count = 0;
-        es->text_width = 0;
-
-        fw = es->format_rect.right - es->format_rect.left;
-        start = es->text;
-        previous_next = &es->first_line_def;
-        do {
-                current_def = (LINEDEF*)HeapAlloc(es->heap, 0, sizeof(LINEDEF));
-                current_def->next = NULL;
-                cp = start;
-                while (*cp) {
-                        if ((*cp == '\r') && (*(cp + 1) == '\n'))
-                                break;
-                        cp++;
-                }
-                if (!(*cp)) {
-                        current_def->ending = END_0;
-                        current_def->net_length = lstrlenA(start);
-                } else if ((cp > start) && (*(cp - 1) == '\r')) {
-                        current_def->ending = END_SOFT;
-                        current_def->net_length = cp - start - 1;
-                } else {
-                        current_def->ending = END_HARD;
-                        current_def->net_length = cp - start;
-                }
-
-                if (!hdc)
-                {
-                  hdc = GetDC(hwnd);
-                  if (es->font)
-                    old_font = SelectObject(hdc, es->font);
-                }
-
-                current_def->width = (INT)LOWORD(GetTabbedTextExtentA(hdc,
-                                        start, current_def->net_length,
-                                        es->tabs_count, es->tabs));
-                /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
-                if ((!(es->style & ES_AUTOHSCROLL)) && (current_def->width > fw)) {
-                        INT next = 0;
-                        INT prev;
-                        do {
-                                prev = next;
-                                next = EDIT_CallWordBreakProc(hwnd, es, start - es->text,
-                                                prev + 1, current_def->net_length, WB_RIGHT);
-                                current_def->width = (INT)LOWORD(GetTabbedTextExtentA(hdc,
-                                                        start, next, es->tabs_count, es->tabs));
-                        } while (current_def->width <= fw);
-                        if (!prev) {
-                                next = 0;
-                                do {
-                                        prev = next;
-                                        next++;
-                                        current_def->width = (INT)LOWORD(GetTabbedTextExtentA(hdc,
-                                                                start, next, es->tabs_count, es->tabs));
-                                } while (current_def->width <= fw);
-                                if (!prev)
-                                        prev = 1;
-                        }
-                        current_def->net_length = prev;
-                        current_def->ending = END_WRAP;
-                        current_def->width = (INT)LOWORD(GetTabbedTextExtentA(hdc, start,
-                                                current_def->net_length, es->tabs_count, es->tabs));
-                }
-                switch (current_def->ending) {
-                case END_SOFT:
-                        current_def->length = current_def->net_length + 3;
-                        break;
-                case END_HARD:
-                        current_def->length = current_def->net_length + 2;
-                        break;
-                case END_WRAP:
-                case END_0:
-                        current_def->length = current_def->net_length;
-                        break;
-                }
-                es->text_width = MAX(es->text_width, current_def->width);
-                start += current_def->length;
-                *previous_next = current_def;
-                previous_next = &current_def->next;
-                es->line_count++;
-        } while (current_def->ending != END_0);
-        if (hdc)
-        {
-          if (es->font)
-                  SelectObject(hdc, old_font);
-          ReleaseDC(hwnd, hdc);
-        }
-        EDIT_UpdateScrollBars(hwnd,es,TRUE,TRUE);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_CallWordBreakProc
- *
- *      Call appropriate WordBreakProc (internal or external).
- *
- *      Note: The "start" argument should always be an index refering
- *              to es->text.  The actual wordbreak proc might be
- *              16 bit, so we can't always pass any 32 bit LPSTR.
- *              Hence we assume that es->text is the buffer that holds
- *              the string under examination (we can decide this for ourselves).
- *
- */
-static INT EDIT_CallWordBreakProc(HWND hwnd, EDITSTATE *es, INT start, INT index, INT count, INT action)
-{
-        if (es->word_break_procA)
-        {
-            //TRACE_(relay)("(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n",
-            //               es->word_break_proc32A, es->text + start, index,
-            //               count, action );
-            return (INT)es->word_break_procA( es->text + start, index,
-                                                  count, action );
-        }
-        else
-            return EDIT_WordBreakProc(es->text + start, index, count, action);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_CharFromPos
- *
- *      Beware: This is not the function called on EM_CHARFROMPOS
- *              The position _can_ be outside the formatting / client
- *              rectangle
- *              The return value is only the character index
- *
- */
-static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
-{
-        INT index;
-        HDC dc = 0;
-        HFONT old_font = 0;
-
-        if (es->style & ES_MULTILINE) {
-                INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
-                INT line_index = 0;
-                LINEDEF *line_def = es->first_line_def;
-                INT low, high;
-                while ((line > 0) && line_def->next) {
-                        line_index += line_def->length;
-                        line_def = line_def->next;
-                        line--;
-                }
-                x += es->x_offset - es->format_rect.left;
-                if (x >= line_def->width) {
-                        if (after_wrap)
-                                *after_wrap = (line_def->ending == END_WRAP);
-                        return line_index + line_def->net_length;
-                }
-                if (x <= 0) {
-                        if (after_wrap)
-                                *after_wrap = FALSE;
-                        return line_index;
-                }
-                low = line_index + 1;
-                high = line_index + line_def->net_length + 1;
-                if (low < high-1)
-                {
-                  if (!dc)
-                  {
-                    dc = GetDC(hwnd);
-                    if (es->font)
-                      old_font = SelectObject(dc, es->font);
-                  }
-
-                  while (low < high-1)
-                  {
-                    INT mid = (low + high) / 2;
-                    if (LOWORD(GetTabbedTextExtentA(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
-                    else low = mid;
-                  }
-                }
-                index = low;
-
-                if (after_wrap)
-                        *after_wrap = ((index == line_index + line_def->net_length) &&
-                                                        (line_def->ending == END_WRAP));
-        } else {
-                LPSTR text;
-                SIZE size;
-                if (after_wrap)
-                        *after_wrap = FALSE;
-                x -= es->format_rect.left;
-                if (!x)
-                        return es->x_offset;
-                text = EDIT_GetPasswordPointer_SL(hwnd, es);
-                if (x < 0)
-                {
-                  INT low = 0;
-                  INT high = es->x_offset;
-
-                  if (low < high-1)
-                  {
-                    if (!dc)
-                    {
-                      dc = GetDC(hwnd);
-                      if (es->font)
-                        old_font = SelectObject(dc, es->font);
-                    }
-
-                    while (low < high-1)
-                    {
-                      INT mid = (low + high) / 2;
-
-                      GetTextExtentPoint32A( dc, text + mid,
-                                             es->x_offset - mid, &size );
-                      if (size.cx > -x) low = mid;
-                      else high = mid;
-                    }
-                  }
-                  index = low;
-                } else
-                {
-                  INT low = es->x_offset;
-                  INT high = lstrlenA(es->text) + 1;
-
-                  if (low < high-1)
-                  {
-                    if (!dc)
-                    {
-                      dc = GetDC(hwnd);
-                      if (es->font)
-                        old_font = SelectObject(dc, es->font);
-                    }
-
-                    while (low < high-1)
-                    {
-                      INT mid = (low + high) / 2;
-
-                      GetTextExtentPoint32A( dc, text + es->x_offset,
-                                             mid - es->x_offset, &size );
-                      if (size.cx > x) high = mid;
-                      else low = mid;
-                    }
-                  }
-                  index = low;
-                }
-                if (es->style & ES_PASSWORD)
-                        HeapFree(es->heap, 0 ,text);
-        }
-        if (dc)
-        {
-          if (es->font)
-            SelectObject(dc, old_font);
-          ReleaseDC(hwnd, dc);
-        }
-        return index;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_ConfinePoint
- *
- *      adjusts the point to be within the formatting rectangle
- *      (so CharFromPos returns the nearest _visible_ character)
- *
- */
-static void EDIT_ConfinePoint(HWND hwnd, EDITSTATE *es, LPINT x, LPINT y)
-{
-        *x = MIN(MAX(*x, es->format_rect.left), es->format_rect.right - 1);
-        *y = MIN(MAX(*y, es->format_rect.top), es->format_rect.bottom - 1);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_GetLineRect
- *
- *      Calculates the bounding rectangle for a line from a starting
- *      column to an ending column.
- *
- */
-static void EDIT_GetLineRect(HWND hwnd,HDC dc,EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
-{
-        INT line_index =  EDIT_EM_LineIndex(hwnd, es, line);
-
-        if (es->style & ES_MULTILINE)
-                rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
-        else
-                rc->top = es->format_rect.top;
-        rc->bottom = rc->top + es->line_height;
-
-        rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(hwnd,dc, es, line_index + scol, TRUE));
-        rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(hwnd,dc, es, line_index + ecol, TRUE))+1;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_GetPasswordPointer_SL
- *
- *      note: caller should free the (optionally) allocated buffer
- *
- */
-static LPSTR EDIT_GetPasswordPointer_SL(HWND hwnd, EDITSTATE *es)
-{
-        if (es->style & ES_PASSWORD) {
-                INT len = lstrlenA(es->text);
-                LPSTR text = (LPSTR)HeapAlloc(es->heap, 0, len + 1);
-                RtlFillMemory(text, len, es->password_char);
-                text[len] = '\0';
-                return text;
-        } else
-                return es->text;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_LockBuffer
- *
- *      This acts as a LOCAL_Lock(), but it locks only once.  This way
- *      you can call it whenever you like, without unlocking.
- *
- */
-static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es)
-{
-        if (!es) {
-                //ERR_(edit)("no EDITSTATE ... please report\n");
-                return;
-        }
-        if (!(es->style & ES_MULTILINE))
-                return;
-        if (!es->text) {
-                if (es->hloc)
-                        es->text = (char*)LocalLock(es->hloc);
-                else {
-                        //ERR_(edit)("no buffer ... please report\n");
-                        return;
-                }
-        }
-        es->lock_count++;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_SL_InvalidateText
- *
- *      Called from EDIT_InvalidateText().
- *      Does the job for single-line controls only.
- *
- */
-static void EDIT_SL_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
-{
-        RECT line_rect;
-        RECT rc;
-
-        EDIT_GetLineRect(hwnd,0, es, 0, start, end, &line_rect);
-
-        if (IntersectRect(&rc, &line_rect, &es->format_rect))
-        {
-          HideCaret(hwnd);
-          InvalidateRect(hwnd, &rc, TRUE);
-          ShowCaret(hwnd);
-        }
-}
-
-
-/*********************************************************************
- *
- *      EDIT_ML_InvalidateText
- *
- *      Called from EDIT_InvalidateText().
- *      Does the job for multi-line controls only.
- *
- */
-static void EDIT_ML_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
-{
-        INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-        INT sl = EDIT_EM_LineFromChar(hwnd, es, start);
-        INT el = EDIT_EM_LineFromChar(hwnd, es, end);
-        INT sc;
-        INT ec;
-        RECT rc1;
-        RECT rcWnd;
-        RECT rcLine;
-        RECT rcUpdate;
-        INT l;
-
-        if ((el < es->y_offset) || (sl > es->y_offset + vlc))
-                return;
-
-        sc = start - EDIT_EM_LineIndex(hwnd, es, sl);
-        ec = end - EDIT_EM_LineIndex(hwnd, es, el);
-        if (sl < es->y_offset) {
-                sl = es->y_offset;
-                sc = 0;
-        }
-        if (el > es->y_offset + vlc) {
-                el = es->y_offset + vlc;
-                ec = EDIT_EM_LineLength(hwnd, es, EDIT_EM_LineIndex(hwnd, es, el));
-        }
-        GetClientRect(hwnd, &rc1);
-        IntersectRect(&rcWnd, &rc1, &es->format_rect);
-        HideCaret(hwnd);
-        if (sl == el) {
-                EDIT_GetLineRect(hwnd,0, es, sl, sc, ec, &rcLine);
-
-                if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
-                        InvalidateRect(hwnd, &rcUpdate, TRUE);
-        } else {
-                EDIT_GetLineRect(hwnd,0, es, sl, sc,
-                                EDIT_EM_LineLength(hwnd, es,
-                                        EDIT_EM_LineIndex(hwnd, es, sl)),
-                                &rcLine);
-                if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
-                        InvalidateRect(hwnd, &rcUpdate, TRUE);
-                for (l = sl + 1 ; l < el ; l++) {
-                        EDIT_GetLineRect(hwnd,0, es, l, 0,
-                                EDIT_EM_LineLength(hwnd, es,
-                                        EDIT_EM_LineIndex(hwnd, es, l)),
-                                &rcLine);
-                        if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
-                                InvalidateRect(hwnd, &rcUpdate, TRUE);
-                }
-                EDIT_GetLineRect(hwnd,0, es, el, 0, ec, &rcLine);
-                if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
-                        InvalidateRect(hwnd, &rcUpdate, TRUE);
-        }
-        ShowCaret(hwnd);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_InvalidateText
- *
- *      Invalidate the text from offset start upto, but not including,
- *      offset end.  Useful for (re)painting the selection.
- *      Regions outside the linewidth are not invalidated.
- *      end == -1 means end == TextLength.
- *      start and end need not be ordered.
- *
- */
-static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
-{
-        if (end == start)
-                return;
-
-        if (end == -1)
-                end = lstrlenA(es->text);
-
-        ORDER_INT(start, end);
-
-        if (es->style & ES_MULTILINE)
-                EDIT_ML_InvalidateText(hwnd, es, start, end);
-        else
-                EDIT_SL_InvalidateText(hwnd, es, start, end);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MakeFit
- *
- *      Try to fit size + 1 bytes in the buffer.  Constrain to limits.
- *
- */
-static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, INT size)
-{
-        HLOCAL hNew32;
-
-#ifndef __WIN32OS2__
-        if (size > es->buffer_limit) {
-                EDIT_NOTIFY_PARENT(hwnd, EN_MAXTEXT);
-                return FALSE;
-        }
-#endif
-
-        if (size <= es->buffer_size)
-                return TRUE;
-        size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
-
-#ifndef __WIN32OS2__
-        if (size > es->buffer_limit)
-                size = es->buffer_limit;
-#endif
-
-        //TRACE_(edit)("trying to ReAlloc to %d+1\n", size);
-
-        EDIT_UnlockBuffer(hwnd, es, TRUE);
-        if (es->text) {
-                es->text = (char*)HeapReAlloc(es->heap, 0, es->text, size + 1);
-                if (es->text)
-#ifdef __WIN32OS2__
-                        es->buffer_size = HeapSize(es->heap, 0, es->text) - 1;
-#else
-                        es->buffer_size = MIN(HeapSize(es->heap, 0, es->text) - 1, es->buffer_limit);
-#endif
-                else
-                        es->buffer_size = 0;
-        } else if (es->hloc) {
-                hNew32 = LocalReAlloc(es->hloc, size + 1, 0);
-                if (hNew32) {
-                        //TRACE_(edit)("Old 32 bit handle %08x, new handle %08x\n", es->hloc32, hNew32);
-                        es->hloc = hNew32;
-#ifdef __WIN32OS2__
-                        es->buffer_size = LocalSize(es->hloc) - 1;
-#else
-                        es->buffer_size = MIN(LocalSize(es->hloc) - 1, es->buffer_limit);
-#endif
-                }
-        }
-        if (es->buffer_size < size) {
-                EDIT_LockBuffer(hwnd, es);
-                //WARN_(edit)("FAILED !  We now have %d+1\n", es->buffer_size);
-                EDIT_NOTIFY_PARENT(hwnd, EN_ERRSPACE);
-                return FALSE;
-        } else {
-                EDIT_LockBuffer(hwnd, es);
-                //TRACE_(edit)("We now have %d+1\n", es->buffer_size);
-                return TRUE;
-        }
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MakeUndoFit
- *
- *      Try to fit size + 1 bytes in the undo buffer.
- *
- */
-static BOOL EDIT_MakeUndoFit(HWND hwnd, EDITSTATE *es, INT size)
-{
-        if (size <= es->undo_buffer_size)
-                return TRUE;
-        size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
-
-        //TRACE_(edit)("trying to ReAlloc to %d+1\n", size);
-        es->undo_text = (char*)HeapReAlloc(es->heap, 0, es->undo_text, size + 1);
-        if (es->undo_text) {
-                es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1;
-                if (es->undo_buffer_size < size) {
-                        //WARN_(edit)("FAILED !  We now have %d+1\n", es->undo_buffer_size);
-                        return FALSE;
-                }
-                return TRUE;
-        }
-        return FALSE;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveBackward
- *
- */
-static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT e = es->selection_end;
-
-        if (e) {
-                e--;
-                if ((es->style & ES_MULTILINE) && e &&
-                                (es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
-                        e--;
-                        if (e && (es->text[e - 1] == '\r'))
-                                e--;
-                }
-        }
-        EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveDown_ML
- *
- *      Only for multi line controls
- *      Move the caret one line down, on a column with the nearest
- *      x coordinate on the screen (might be a different column).
- *
- */
-static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
-        LRESULT pos = EDIT_EM_PosFromChar(hwnd,0, es, e, after_wrap);
-        INT x = SLOWORD(pos);
-        INT y = SHIWORD(pos);
-
-        e = EDIT_CharFromPos(hwnd, es, x, y + es->line_height, &after_wrap);
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveEnd
- *
- */
-static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        BOOL after_wrap = FALSE;
-        INT e;
-
-        /* Pass a high value in x to make sure of receiving the en of the line */
-        if (es->style & ES_MULTILINE)
-                e = EDIT_CharFromPos(hwnd, es, 0x3fffffff,
-                        HIWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
-        else
-                e = lstrlenA(es->text);
-        EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveForward
- *
- */
-static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT e = es->selection_end;
-
-        if (es->text[e]) {
-                e++;
-                if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
-                        if (es->text[e] == '\n')
-                                e++;
-                        else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
-                                e += 2;
-                }
-        }
-        EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveHome
- *
- *      Home key: move to beginning of line.
- *
- */
-static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT e;
-
-        /* Pass the x_offset in x to make sure of receiving the first position of the line */
-        if (es->style & ES_MULTILINE)
-                e = EDIT_CharFromPos(hwnd, es, -es->x_offset,
-                        HIWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
-        else
-                e = 0;
-        EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MovePageDown_ML
- *
- *      Only for multi line controls
- *      Move the caret one page down, on a column with the nearest
- *      x coordinate on the screen (might be a different column).
- *
- */
-static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
-        LRESULT pos = EDIT_EM_PosFromChar(hwnd,0, es, e, after_wrap);
-        INT x = SLOWORD(pos);
-        INT y = SHIWORD(pos);
-
-        e = EDIT_CharFromPos(hwnd, es, x,
-                y + (es->format_rect.bottom - es->format_rect.top),
-                &after_wrap);
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MovePageUp_ML
- *
- *      Only for multi line controls
- *      Move the caret one page up, on a column with the nearest
- *      x coordinate on the screen (might be a different column).
- *
- */
-static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
-        LRESULT pos = EDIT_EM_PosFromChar(hwnd,0, es, e, after_wrap);
-        INT x = SLOWORD(pos);
-        INT y = SHIWORD(pos);
-
-        e = EDIT_CharFromPos(hwnd, es, x,
-                y - (es->format_rect.bottom - es->format_rect.top),
-                &after_wrap);
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveUp_ML
- *
- *      Only for multi line controls
- *      Move the caret one line up, on a column with the nearest
- *      x coordinate on the screen (might be a different column).
- *
- */
-static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
-        LRESULT pos = EDIT_EM_PosFromChar(hwnd,0, es, e, after_wrap);
-        INT x = SLOWORD(pos);
-        INT y = SHIWORD(pos);
-
-        e = EDIT_CharFromPos(hwnd, es, x, y - es->line_height, &after_wrap);
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveWordBackward
- *
- */
-static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        INT l;
-        INT ll;
-        INT li;
-
-        l = EDIT_EM_LineFromChar(hwnd, es, e);
-        ll = EDIT_EM_LineLength(hwnd, es, e);
-        li = EDIT_EM_LineIndex(hwnd, es, l);
-        if (e - li == 0) {
-                if (l) {
-                        li = EDIT_EM_LineIndex(hwnd, es, l - 1);
-                        e = li + EDIT_EM_LineLength(hwnd, es, li);
-                }
-        } else {
-                e = li + (INT)EDIT_CallWordBreakProc(hwnd, es,
-                                li, e - li, ll, WB_LEFT);
-        }
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_MoveWordForward
- *
- */
-static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        INT l;
-        INT ll;
-        INT li;
-
-        l = EDIT_EM_LineFromChar(hwnd, es, e);
-        ll = EDIT_EM_LineLength(hwnd, es, e);
-        li = EDIT_EM_LineIndex(hwnd, es, l);
-        if (e - li == ll) {
-                if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
-                        e = EDIT_EM_LineIndex(hwnd, es, l + 1);
-        } else {
-                e = li + EDIT_CallWordBreakProc(hwnd, es,
-                                li, e - li + 1, ll, WB_RIGHT);
-        }
-        if (!extend)
-                s = e;
-        EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_PaintLine
- *
- */
-static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC dc, INT line, BOOL rev)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        INT li;
-        INT ll;
-        INT x;
-        INT y;
-        LRESULT pos;
-
-        if (es->style & ES_MULTILINE) {
-                INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-                if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
-                        return;
-        } else if (line)
-                return;
-
-        //TRACE_(edit)("line=%d\n", line);
-
-        pos = EDIT_EM_PosFromChar(hwnd,dc, es, EDIT_EM_LineIndex(hwnd, es, line), FALSE);
-        x = SLOWORD(pos);
-        y = SHIWORD(pos);
-        li = EDIT_EM_LineIndex(hwnd, es, line);
-        ll = EDIT_EM_LineLength(hwnd, es, li);
-        s = es->selection_start;
-        e = es->selection_end;
-        ORDER_INT(s, e);
-        s = MIN(li + ll, MAX(li, s));
-        e = MIN(li + ll, MAX(li, e));
-
-	if (rev && (s != e) &&
-			((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
-		x += EDIT_PaintText(hwnd, es, dc, x, y, line, 0, s - li, FALSE);
-		x += EDIT_PaintText(hwnd, es, dc, x, y, line, s - li, e - s, TRUE);
-		x += EDIT_PaintText(hwnd, es, dc, x, y, line, e - li, li + ll - e, FALSE);
-	} else
-		x += EDIT_PaintText(hwnd, es, dc, x, y, line, 0, ll, FALSE);
-#if 0
-        if (rev && (s != e) && ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL)))
-        {
-          HRGN oldRgn,newRgn,combRgn;
-          RECT rect;
-          //CB: OS/2 has problems with relative string positions (i.e. Communicator)
-          //    fix: always calculate string from starting point, tab bugs fixed too
-          //    otherwise we have 'dancing characters'
-
-          if (!(es->style & ES_MULTILINE))
-          {
-            SIZE size;
-
-            rect.top = y;
-            rect.bottom = y+es->line_height;
-            GetTextExtentPoint32A(dc,es->text+li,s-li,&size);
-            rect.left = x+size.cx;
-            GetTextExtentPoint32A(dc,es->text+li,e-li,&size);
-            rect.right = x+size.cx;
-
-            oldRgn = CreateRectRgnIndirect(&rect); //dummy parameter
-            GetClipRgn(dc,oldRgn);
-            newRgn = CreateRectRgnIndirect(&rect);
-            combRgn = CreateRectRgnIndirect(&rect); //dummy parameter
-            CombineRgn(combRgn,oldRgn,newRgn,RGN_XOR);
-            CombineRgn(combRgn,oldRgn,combRgn,RGN_AND);
-            SelectClipRgn(dc,combRgn);
-            EDIT_PaintText(hwnd,es,dc,x,y,line,0,ll,FALSE);
-            CombineRgn(combRgn,oldRgn,newRgn,RGN_AND);
-            SelectClipRgn(dc,combRgn);
-            EDIT_PaintText(hwnd,es,dc,x,y,line,0,e-li,TRUE);
-            DeleteObject(oldRgn);
-            DeleteObject(newRgn);
-            DeleteObject(combRgn);
-          } else
-          {
-            rect.top = y;
-            rect.bottom = y+es->line_height;
-            rect.left = x+LOWORD(TabbedTextOutA(dc,x,y,es->text+li,s-li,es->tabs_count,es->tabs,es->format_rect.left-es->x_offset));
-            rect.right = x+LOWORD(TabbedTextOutA(dc,x,y,es->text+li,e-li,es->tabs_count,es->tabs,es->format_rect.left-es->x_offset));
-
-            oldRgn = CreateRectRgnIndirect(&rect); //dummy parameter
-            GetClipRgn(dc,oldRgn);
-            newRgn = CreateRectRgnIndirect(&rect);
-            combRgn = CreateRectRgnIndirect(&rect); //dummy parameter
-            CombineRgn(combRgn,oldRgn,newRgn,RGN_XOR);
-            CombineRgn(combRgn,oldRgn,combRgn,RGN_AND);
-            SelectClipRgn(dc,combRgn);
-            EDIT_PaintText(hwnd,es,dc,x,y,line,0,ll,FALSE);
-            CombineRgn(combRgn,oldRgn,newRgn,RGN_AND);
-            SelectClipRgn(dc,combRgn);
-            EDIT_PaintText(hwnd,es,dc,x,y,line,0,e-li,TRUE);
-            SelectClipRgn(dc,oldRgn);
-            DeleteObject(oldRgn);
-            DeleteObject(newRgn);
-            DeleteObject(combRgn);
-          }
-        } else  EDIT_PaintText(hwnd, es, dc, x, y, line, 0, ll, FALSE);
-#endif // 0
-}
-
-
-/*********************************************************************
- *
- *      EDIT_PaintText
- *
- */
-static INT EDIT_PaintText(HWND hwnd, EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
-{
-        COLORREF BkColor;
-        COLORREF TextColor;
-	INT ret;
-	INT li;
-	INT BkMode;
-	SIZE size;
-
-        if (!count)
-                return 0;
-	BkMode = GetBkMode(dc);
-        BkColor = GetBkColor(dc);
-        TextColor = GetTextColor(dc);
-        if (rev)
-        {
-                SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
-                SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
-		SetBkMode( dc, OPAQUE);
-        }
-        li = EDIT_EM_LineIndex(hwnd, es, line);
-        if (es->style & ES_MULTILINE)
-        {
-                //TabbedTextOutA(dc, x, y, es->text + li + col, count,
-                //               es->tabs_count, es->tabs, es->format_rect.left - es->x_offset);
-		ret = (INT)LOWORD(TabbedTextOutA(dc, x, y, (LPCSTR) (es->text + li + col), count,
-					es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
-        } else
-        {
-          LPSTR text = EDIT_GetPasswordPointer_SL(hwnd, es);
-          POINT pt;
-
-          TextOutA(dc,x,y,text+li+col,count);
-		GetTextExtentPoint32A(dc, text + li + col, count, &size);
-		ret = size.cx;
-          if (es->style & ES_PASSWORD)
-            HeapFree(es->heap, 0, text);
-        }
-        if (rev)
-        {
-                SetBkColor(dc, BkColor);
-                SetTextColor(dc, TextColor);
-		SetBkMode( dc, BkMode);
-        }
-	return ret;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_SetCaretPos
- *
- */
-static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos,
-                             BOOL after_wrap)
-{
-        LRESULT res = EDIT_EM_PosFromChar(hwnd,0, es, pos, after_wrap);
-        INT x = SLOWORD(res);
-        INT y = SHIWORD(res);
-
-        if(x < es->format_rect.left)
-                x = es->format_rect.left;
-        if(x > es->format_rect.right - 2)
-                x = es->format_rect.right - 2;
-        if(y > es->format_rect.bottom)
-                y = es->format_rect.bottom;
-        if(y < es->format_rect.top)
-                y = es->format_rect.top;
-        SetCaretPos(x, y);
-        return;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_SetRectNP
- *
- *      note:   this is not (exactly) the handler called on EM_SETRECTNP
- *              it is also used to set the rect of a single line control
- *
- */
-static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT rc)
-{
-        CopyRect(&es->format_rect, rc);
-        if (es->style & WS_BORDER)
-        {
-          INT bw = GetSystemMetrics(SM_CXBORDER)+1,bh = GetSystemMetrics(SM_CYBORDER)+1;
-
-          es->format_rect.left += bw;
-          es->format_rect.top += bh;
-          es->format_rect.right -= bw;
-          es->format_rect.bottom -= bh;
-        }
-        es->format_rect.left += es->left_margin;
-        es->format_rect.right -= es->right_margin;
-        es->format_rect.right = MAX(es->format_rect.right, es->format_rect.left + es->char_width);
-        if (es->style & ES_MULTILINE)
-                es->format_rect.bottom = es->format_rect.top +
-                        MAX(1, (es->format_rect.bottom - es->format_rect.top) / es->line_height) * es->line_height;
-        else
-                es->format_rect.bottom = es->format_rect.top + es->line_height;
-        if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
-                EDIT_BuildLineDefs_ML(hwnd,es);
-        EDIT_UpdateScrollBars(hwnd,es,TRUE,TRUE);
-}
-
-
-/*********************************************************************
- *
- *      EDIT_UnlockBuffer
- *
- */
-static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force)
-{
-        if (!es) {
-                //ERR_(edit)("no EDITSTATE ... please report\n");
-                return;
-        }
-        if (!(es->style & ES_MULTILINE))
-                return;
-        if (!es->lock_count) {
-                //ERR_(edit)("lock_count == 0 ... please report\n");
-                return;
-        }
-        if (!es->text) {
-                //ERR_(edit)("es->text == 0 ... please report\n");
-                return;
-        }
-        if (force || (es->lock_count == 1)) {
-                if (es->hloc) {
-                        LocalUnlock(es->hloc);
-                        es->text = NULL;
-                }
-        }
-        es->lock_count--;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_WordBreakProc
- *
- *      Find the beginning of words.
- *      Note:   unlike the specs for a WordBreakProc, this function only
- *              allows to be called without linebreaks between s[0] upto
- *              s[count - 1].  Remember it is only called
- *              internally, so we can decide this for ourselves.
- *
- */
-static INT EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action)
-{
-        INT ret = 0;
-
-        //TRACE_(edit)("s=%p, index=%u, count=%u, action=%d\n",
-        //             s, index, count, action);
-
-        switch (action) {
-        case WB_LEFT:
-                if (!count)
-                        break;
-                if (index)
-                        index--;
-                if (s[index] == ' ') {
-                        while (index && (s[index] == ' '))
-                                index--;
-                        if (index) {
-                                while (index && (s[index] != ' '))
-                                        index--;
-                                if (s[index] == ' ')
-                                        index++;
-                        }
-                } else {
-                        while (index && (s[index] != ' '))
-                                index--;
-                        if (s[index] == ' ')
-                                index++;
-                }
-                ret = index;
-                break;
-        case WB_RIGHT:
-                if (!count)
-                        break;
-                if (index)
-                        index--;
-                if (s[index] == ' ')
-                        while ((index < count) && (s[index] == ' ')) index++;
-                else {
-                        while (s[index] && (s[index] != ' ') && (index < count))
-                                index++;
-                        while ((s[index] == ' ') && (index < count)) index++;
-                }
-                ret = index;
-                break;
-        case WB_ISDELIMITER:
-                ret = (s[index] == ' ');
-                break;
-        default:
-                //ERR_(edit)("unknown action code, please report !\n");
-                break;
-        }
-        return ret;
-}
-
-
-/*********************************************************************
- *
- *      EM_CHARFROMPOS
- *
- *      returns line number (not index) in high-order word of result.
- *      NB : Q137805 is unclear about this. POINT * pointer in lParam apply
- *      to Richedit, not to the edit control. Original documentation is valid.
- *
- */
-static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y)
-{
-        POINT pt;
-        INT index;
-
-        pt.x = x;
-        pt.y = y;
-
-        if (!PtInRect(&es->format_rect,pt)) return -1;
-
-        index = EDIT_CharFromPos(hwnd, es, x, y, NULL);
-        return MAKELONG(index, EDIT_EM_LineFromChar(hwnd, es, index));
-}
-
-
-/*********************************************************************
- *
- *      EM_FMTLINES
- *
- * Enable or disable soft breaks.
- */
-static BOOL EDIT_EM_FmtLines(HWND hwnd, EDITSTATE *es, BOOL add_eol)
-{
-        es->flags &= ~EF_USE_SOFTBRK;
-        if (add_eol) {
-                es->flags |= EF_USE_SOFTBRK;
-                dprintf(("EDIT: EM_FMTLINES: soft break enabled, not implemented\n"));
-        }
-        return add_eol;
-}
-
-static INT EDIT_EM_GetFirstVisibleLine(HWND hwnd,EDITSTATE *es)
-{
-  return (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
-}
-
-/*********************************************************************
- *
- *      EM_GETHANDLE
- *
- *      Hopefully this won't fire back at us.
- *      We always start with a fixed buffer in our own heap.
- *      However, with this message a 32 bit application requests
- *      a handle to 32 bit moveable local heap memory, where it expects
- *      to find the text.
- *      It's a pity that from this moment on we have to use this
- *      local heap, because applications may rely on the handle
- *      in the future.
- *
- *      In this function we'll try to switch to local heap.
- *
- */
-static HLOCAL EDIT_EM_GetHandle(HWND hwnd, EDITSTATE *es)
-{
-        HLOCAL newBuf;
-        LPSTR newText;
-        INT newSize;
-
-        if (!(es->style & ES_MULTILINE))
-                return 0;
-
-        if (es->hloc)
-                return es->hloc;
-
-        if (!(newBuf = LocalAlloc(LMEM_MOVEABLE, lstrlenA(es->text) + 1))) {
-                //ERR_(edit)("could not allocate new 32 bit buffer\n");
-                return 0;
-        }
-#ifdef __WIN32OS2__
-        newSize = LocalSize(newBuf) - 1;
-#else
-        newSize = MIN(LocalSize(newBuf) - 1, es->buffer_limit);
-#endif
-        if (!(newText = (char*)LocalLock(newBuf))) {
-                //ERR_(edit)("could not lock new 32 bit buffer\n");
-                LocalFree(newBuf);
-                return 0;
-        }
-        lstrcpyA(newText, es->text);
-        EDIT_UnlockBuffer(hwnd, es, TRUE);
-        if (es->text)
-                HeapFree(es->heap, 0, es->text);
-        es->hloc = newBuf;
-        es->buffer_size = newSize;
-        es->text = newText;
-        EDIT_LockBuffer(hwnd, es);
-        //TRACE_(edit)("switched to 32 bit local heap\n");
-
-        return es->hloc;
-}
-
-static INT EDIT_EM_GetLimitText(HWND hwnd,EDITSTATE *es)
-{
-  return es->buffer_limit;
-}
-
-/*********************************************************************
- *
- *      EM_GETLINE
- *
- */
-static INT EDIT_EM_GetLine(HWND hwnd, EDITSTATE *es, INT line, LPSTR lpch)
-{
-        LPSTR src;
-        INT len;
-        INT i;
-
-        if (!lpch || (*(WORD*)lpch == 0)) return 0;
-
-        if (es->style & ES_MULTILINE) {
-                if (line >= es->line_count)
-                        return 0;
-        } else
-                line = 0;
-        i = EDIT_EM_LineIndex(hwnd, es, line);
-        src = es->text + i;
-        len = MIN(*(WORD *)lpch, EDIT_EM_LineLength(hwnd, es, i));
-        for (i = 0 ; i < len ; i++) {
-                *lpch = *src;
-                src++;
-                lpch++;
-        }
-        //SvL: Terminate string
-        *lpch = 0;
-        return (LRESULT)len;
-}
-
-static INT EDIT_EM_GetLineCount(HWND hwnd,EDITSTATE *es)
-{
-  return (es->style & ES_MULTILINE) ? es->line_count : 1;
-}
-
-static LONG EDIT_EM_GetMargins(HWND hwnd,EDITSTATE *es)
-{
-  return MAKELONG(es->left_margin, es->right_margin);
-}
-
-static BOOL EDIT_EM_GetModify(HWND hwnd,EDITSTATE *es)
-{
-  return ((es->flags & EF_MODIFIED) != 0);
-}
-
-static CHAR EDIT_EM_GetPasswordChar(HWND hwnd,EDITSTATE *es)
-{
-  return es->password_char;
-}
-
-static VOID EDIT_EM_GetRect(HWND hwnd,EDITSTATE *es,LPRECT lprc)
-{
-  if (lprc) CopyRect(lprc,&es->format_rect);
-}
-
-/*********************************************************************
- *
- *      EM_GETSEL
- *
- */
-static LRESULT EDIT_EM_GetSel(HWND hwnd, EDITSTATE *es, LPUINT start, LPUINT end)
-{
-        UINT s = es->selection_start;
-        UINT e = es->selection_end;
-
-        ORDER_UINT(s, e);
-
-        if (start)
-                *start = s;
-        if (end)
-                *end = e;
-        return MAKELONG(s, e);
-}
-
-/*********************************************************************
- *
- *      EM_GETTHUMB
- */
-static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es)
-{
-  SCROLLINFO si;
-
-  if (!(es->style & ES_MULTILINE)) return 0;
-
-  si.cbSize = sizeof(si);
-  si.fMask  = SIF_TRACKPOS;
-  return GetScrollInfo(hwnd,SB_VERT,&si) ? si.nTrackPos:0;
-}
-
-static PVOID EDIT_EM_GetWordbreakProc(HWND hwnd,EDITSTATE *es)
-{
-  return es->word_break_procA;
-}
-
-/*********************************************************************
- *
- *      EM_LINEFROMCHAR
- *
- */
-static INT EDIT_EM_LineFromChar(HWND hwnd, EDITSTATE *es, INT index)
-{
-        INT line;
-        LINEDEF *line_def;
-
-        if (!(es->style & ES_MULTILINE))
-                return 0;
-        if (index > lstrlenA(es->text))
-                return es->line_count - 1;
-        if (index == -1)
-                index = MIN(es->selection_start, es->selection_end); //selection_end == caret pos
-
-        line = 0;
-        line_def = es->first_line_def;
-        index -= line_def->length;
-        while ((index >= 0) && line_def->next) {
-                line++;
-                line_def = line_def->next;
-                index -= line_def->length;
-        }
-        return line;
-}
-
-
-/*********************************************************************
- *
- *      EM_LINEINDEX
- *
- */
-static INT EDIT_EM_LineIndex(HWND hwnd, EDITSTATE *es, INT line)
-{
-        INT line_index;
-        LINEDEF *line_def;
-
-        if (!(es->style & ES_MULTILINE))
-                return 0;
-        if (line >= es->line_count)
-                return -1;
-
-        line_index = 0;
-        line_def = es->first_line_def;
-        if (line == -1) {
-                INT index = es->selection_end - line_def->length;
-                while ((index >= 0) && line_def->next) {
-                        line_index += line_def->length;
-                        line_def = line_def->next;
-                        index -= line_def->length;
-                }
-        } else {
-                while (line > 0) {
-                        line_index += line_def->length;
-                        line_def = line_def->next;
-                        line--;
-                }
-        }
-        return line_index;
-}
-
-
-/*********************************************************************
- *
- *      EM_LINELENGTH
- *
- */
-static INT EDIT_EM_LineLength(HWND hwnd, EDITSTATE *es, INT index)
-{
-        LINEDEF *line_def;
-
-        if (!(es->style & ES_MULTILINE))
-                return lstrlenA(es->text);
-
-        if (index == -1)
-        {
-          INT sl = EDIT_EM_LineFromChar(hwnd,es,MIN(es->selection_start,es->selection_end));
-          INT el = EDIT_EM_LineFromChar(hwnd,es,MAX(es->selection_start,es->selection_end));
-
-          if (sl == el)
-            return EDIT_EM_LineLength(hwnd,es,sl)+es->selection_start-es->selection_end;
-          else
-            return es->selection_start+EDIT_EM_LineLength(hwnd,es,el)-es->selection_end;
-        }
-        line_def = es->first_line_def;
-        index -= line_def->length;
-        while ((index >= 0) && line_def->next) {
-                line_def = line_def->next;
-                index -= line_def->length;
-        }
-        return line_def->net_length;
-}
-
-static VOID EDIT_UpdateScrollBars(HWND hwnd,EDITSTATE *es,BOOL updateHorz,BOOL updateVert)
-{
-  if (updateHorz && (es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
-  {
-    SCROLLINFO si;
-    INT fw = es->format_rect.right - es->format_rect.left;
-
-    si.cbSize       = sizeof(SCROLLINFO);
-    si.fMask        = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
-    si.nMin         = 0;
-    si.nMax         = es->text_width + fw - 1;
-    si.nPage        = fw;
-    si.nPos         = es->x_offset;
-    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
-  }
-
-  if (updateVert && (es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
-  {
-    INT vlc = (es->format_rect.bottom-es->format_rect.top)/es->line_height;
-    SCROLLINFO si;
-
-    si.cbSize       = sizeof(SCROLLINFO);
-    si.fMask        = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
-    si.nMin         = 0;
-    si.nMax         = es->line_count + vlc - 2;
-    si.nPage        = vlc;
-    si.nPos         = es->y_offset;
-    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
-  }
-}
-
-
-/*********************************************************************
- *
- *      EM_LINESCROLL
- *
- *      FIXME: dx is in average character widths
- *              However, we assume it is in pixels when we use this
- *              function internally
- *
- */
-static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
-{
-        INT nyoff;
-        INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-
-        if (!(es->style & ES_MULTILINE))
-                return FALSE;
-
-        if (-dx > es->x_offset)
-                dx = -es->x_offset;
-        if (dx > es->text_width - es->x_offset)
-                dx = es->text_width - es->x_offset;
-        nyoff = MAX(0, es->y_offset + dy);
-
-        //SvL: If nyoff > nr lines in control -> last line in control
-        //     window should show last line of control
-        //     Wine code shows last line at the top of the control
-        //     (Quake 3 startup edit control shows the problem)
-        if (nyoff >= es->line_count) {
-                if(es->line_count <= vlc) {
-                        nyoff = es->y_offset;   //no need to scroll
-                }
-                else    nyoff = es->line_count - vlc - 1;
-        }
-        dy = (es->y_offset - nyoff) * es->line_height;
-        if (dx || dy)
-        {
-                RECT rc1;
-                RECT rc;
-
-                if (dx && !(es->flags & EF_HSCROLL_TRACK))
-                  EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL);
-                if (dy && !(es->flags & EF_VSCROLL_TRACK))
-                  EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL);
-
-                GetClientRect(hwnd, &rc1);
-                IntersectRect(&rc, &rc1, &es->format_rect);
-
-                ScrollWindowEx(hwnd,-dx,dy,NULL,&rc,(HRGN)NULL,NULL,SW_INVALIDATE);
-                es->y_offset = nyoff;
-                es->x_offset += dx;
-                EDIT_UpdateScrollBars(hwnd,es,dx,dy);
-        }
-
-        return TRUE;
-}
-
-
-/*********************************************************************
- *
- *      EM_POSFROMCHAR
- *
- */
-static LRESULT EDIT_EM_PosFromChar(HWND hwnd,HDC dc, EDITSTATE *es, INT index, BOOL after_wrap)
-{
-        INT len = lstrlenA(es->text);
-        INT l;
-        INT li;
-        INT x;
-        INT y = 0;
-        BOOL createdDC = FALSE;
-        HFONT old_font = 0;
-        SIZE size;
-
-        index = MIN(index, len);
-        if (!dc)
-        {
-          dc = GetDC(hwnd);
-          if (es->font)
-            old_font = SelectObject(dc, es->font);
-          createdDC = TRUE;
-        }
-        if (es->style & ES_MULTILINE) {
-                l = EDIT_EM_LineFromChar(hwnd, es, index);
-                y = (l - es->y_offset) * es->line_height;
-                li = EDIT_EM_LineIndex(hwnd, es, l);
-                if (after_wrap && (li == index) && l) {
-                        INT l2 = l - 1;
-                        LINEDEF *line_def = es->first_line_def;
-                        while (l2) {
-                                line_def = line_def->next;
-                                l2--;
-                        }
-                        if (line_def->ending == END_WRAP) {
-                                l--;
-                                y -= es->line_height;
-                                li = EDIT_EM_LineIndex(hwnd, es, l);
-                        }
-                }
-                x = LOWORD(GetTabbedTextExtentA(dc, es->text + li, index - li,
-                                es->tabs_count, es->tabs)) - es->x_offset;
-        } else
-        {
-          LPSTR text = EDIT_GetPasswordPointer_SL(hwnd, es);
-
-          GetTextExtentPoint32A(dc,text,index,&size);
-          x = size.cx;
-          if (es->x_offset)
-          {
-            GetTextExtentPoint32A(dc,text,es->x_offset,&size);
-            x -= size.cx;
-          }
-          y = 0;
-          if (es->style & ES_PASSWORD)
-            HeapFree(es->heap, 0 ,text);
-        }
-        x += es->format_rect.left;
-        y += es->format_rect.top;
-        if (createdDC)
-        {
-          if (es->font)
-            SelectObject(dc, old_font);
-          ReleaseDC(hwnd, dc);
-        }
-        return MAKELONG((INT16)x, (INT16)y);
-}
-
-BOOL EDIT_CheckNumber(CHAR *text)
-{
-  if (!text) return TRUE;
-
-  while (text[0] != 0)
-  {
-    if ((BYTE)text[0] < '0' || (BYTE)text[0] > '9') return FALSE;
-    text++;
-  }
-
-  return TRUE;
-}
-
-/*********************************************************************
- *
- *      EM_REPLACESEL
- *
- */
-static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace)
-{
-        INT strl = lstrlenA(lpsz_replace);
-        INT tl = lstrlenA(es->text);
-        INT utl;
-        UINT s;
-        UINT e;
-        INT i;
-        LPSTR p;
-
-        s = es->selection_start;
-        e = es->selection_end;
-
-        if ((s == e) && !strl)
-                return;
-
-        ORDER_UINT(s, e);
-
-        if (!EDIT_MakeFit(hwnd, es, tl - (e - s) + strl))
-                return;
-
-        if (e != s) {
-                /* there is something to be deleted */
-                if (can_undo) {
-                        utl = lstrlenA(es->undo_text);
-                        if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
-                                /* undo-buffer is extended to the right */
-                                EDIT_MakeUndoFit(hwnd, es, utl + e - s);
-                                lstrcpynA(es->undo_text + utl, es->text + s, e - s + 1);
-                        } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
-                                /* undo-buffer is extended to the left */
-                                EDIT_MakeUndoFit(hwnd, es, utl + e - s);
-                                for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
-                                        p[e - s] = p[0];
-                                for (i = 0 , p = es->undo_text ; i < e - s ; i++)
-                                        p[i] = (es->text + s)[i];
-                                es->undo_position = s;
-                        } else {
-                                /* new undo-buffer */
-                                EDIT_MakeUndoFit(hwnd, es, e - s);
-                                lstrcpynA(es->undo_text, es->text + s, e - s + 1);
-                                es->undo_position = s;
-                        }
-                        /* any deletion makes the old insertion-undo invalid */
-                        es->undo_insert_count = 0;
-                } else
-                        EDIT_EM_EmptyUndoBuffer(hwnd, es);
-
-                /* now delete */
-                lstrcpyA(es->text + s, es->text + e);
-        }
-        if (strl)
-        {
-          if ((es->style & ES_NUMBER) && !EDIT_CheckNumber((CHAR*)lpsz_replace))
-            MessageBeep(MB_ICONEXCLAMATION);
-          else
-          {
-            /* there is an insertion */
-            if (can_undo) {
-              if ((s == es->undo_position) ||
-                  ((es->undo_insert_count) &&
-                  (s == es->undo_position + es->undo_insert_count)))
-                  /*
-                   * insertion is new and at delete position or
-                   * an extension to either left or right
-                   */
-                  es->undo_insert_count += strl;
-              else {
-                /* new insertion undo */
-                es->undo_position = s;
-                es->undo_insert_count = strl;
-                /* new insertion makes old delete-buffer invalid */
-                *es->undo_text = '\0';
-              }
-            } else
-              EDIT_EM_EmptyUndoBuffer(hwnd, es);
-
-
-            /* now insert */
-            tl = lstrlenA(es->text);
-            for (p = es->text + tl ; p >= es->text + s ; p--)
-            p[strl] = p[0];
-            for (i = 0 , p = es->text + s ; i < strl ; i++)
-              p[i] = lpsz_replace[i];
-
-            if (es->style & ES_OEMCONVERT)
-            {
-              CHAR *text = (LPSTR)HeapAlloc(es->heap,0,strl);
-
-              CharToOemBuffA(lpsz_replace,text,strl);
-              OemToCharBuffA(text,p,strl);
-              HeapFree(es->heap,0,text);
-            }
-
-            if(es->style & ES_UPPERCASE)
-              CharUpperBuffA(p, strl);
-            else if(es->style & ES_LOWERCASE)
-              CharLowerBuffA(p, strl);
-
-            s += strl;
-          }
-        }
-        /* FIXME: really inefficient */
-        if (es->style & ES_MULTILINE)
-                EDIT_BuildLineDefs_ML(hwnd,es);
-
-        EDIT_EM_SetSel(hwnd, es, s, s, FALSE);
-
-        es->flags |= EF_MODIFIED;
-        es->flags |= EF_UPDATE;
-        EDIT_EM_ScrollCaret(hwnd, es);
-
-        /* FIXME: really inefficient */
-        EDIT_Refresh(hwnd,es,TRUE);
-}
-
-
-/*********************************************************************
- *
- *      EM_SCROLL
- *
- */
-static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action)
-{
-        INT dy;
-
-        if (!(es->style & ES_MULTILINE))
-                return (LRESULT)FALSE;
-
-        dy = 0;
-
-        switch (action) {
-        case SB_LINEUP:
-                if (es->y_offset)
-                        dy = -1;
-                break;
-        case SB_LINEDOWN:
-                if (es->y_offset < es->line_count - 1)
-                        dy = 1;
-                break;
-        case SB_PAGEUP:
-                if (es->y_offset)
-                        dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
-                break;
-        case SB_PAGEDOWN:
-                if (es->y_offset < es->line_count - 1)
-                        dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-                break;
-        default:
-                return (LRESULT)FALSE;
-        }
-        if (dy) {
-                EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL);
-                EDIT_EM_LineScroll(hwnd, es, 0, dy);
-        }
-        return MAKELONG((INT16)dy, (BOOL16)TRUE);
-}
-
-
-/*********************************************************************
- *
- *      EM_SCROLLCARET
- *
- */
-static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es)
-{
-        if (es->style & ES_MULTILINE) {
-                INT l;
-                INT li;
-                INT vlc;
-                INT ww;
-                INT cw = es->char_width;
-                INT x;
-                INT dy = 0;
-                INT dx = 0;
-
-                l = EDIT_EM_LineFromChar(hwnd, es, es->selection_end);
-                li = EDIT_EM_LineIndex(hwnd, es, l);
-                x = SLOWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, es->flags & EF_AFTER_WRAP));
-                vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-                if (l >= es->y_offset + vlc)
-                        dy = l - vlc + 1 - es->y_offset;
-                if (l < es->y_offset)
-                        dy = l - es->y_offset;
-                ww = es->format_rect.right - es->format_rect.left;
-                if (x < es->format_rect.left)
-                        dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
-                if (x > es->format_rect.right)
-                        dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
-                if (dy || dx)
-                        EDIT_EM_LineScroll(hwnd, es, dx, dy);
-        } else {
-                INT x;
-                INT goal;
-                INT format_width;
-
-                if (!(es->style & ES_AUTOHSCROLL))
-                        return;
-
-                x = SLOWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, FALSE));
-                format_width = es->format_rect.right - es->format_rect.left;
-                if (x < es->format_rect.left)
-                {
-                        goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
-                        do {
-                                es->x_offset--;
-                                x = SLOWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, FALSE));
-                        } while ((x < goal) && es->x_offset);
-                        /* FIXME: use ScrollWindow() somehow to improve performance */
-                        EDIT_Refresh(hwnd,es,TRUE);
-                        EDIT_UpdateScrollBars(hwnd,es,TRUE,FALSE);
-                } else if (x > es->format_rect.right)
-                {
-                        INT x_last;
-                        INT len = lstrlenA(es->text);
-                        goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
-                        do {
-                                es->x_offset++;
-                                x = SLOWORD(EDIT_EM_PosFromChar(hwnd,0, es, es->selection_end, FALSE));
-                                x_last = SLOWORD(EDIT_EM_PosFromChar(hwnd,0, es, len, FALSE));
-                        } while ((x > goal) && (x_last > es->format_rect.right));
-                        /* FIXME: use ScrollWindow() somehow to improve performance */
-                        EDIT_Refresh(hwnd,es,TRUE);
-                        EDIT_UpdateScrollBars(hwnd,es,TRUE,FALSE);
-                }
-        }
-}
-
-
-/*********************************************************************
- *
- *      EM_SETHANDLE
- *
- */
-static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc)
-{
-        if (!(es->style & ES_MULTILINE))
-                return;
-
-        if (!hloc) {
-                //WARN_(edit)("called with NULL handle\n");
-                return;
-        }
-
-        EDIT_UnlockBuffer(hwnd, es, TRUE);
-        /*
-         *      old buffer is freed by caller, unless
-         *      it is still in our own heap.  (in that case
-         *      we free it, correcting the buggy caller.)
-         */
-        if (es->text)
-                HeapFree(es->heap, 0, es->text);
-
-        es->hloc = hloc;
-        es->text = NULL;
-        es->buffer_size = LocalSize(es->hloc) - 1;
-        EDIT_LockBuffer(hwnd, es);
-
-        if (es->text && (es->text[0] != 0))
-        {
-          if (es->style & ES_NUMBER)
-          {
-            //CB: todo
-          }
-
-          if (es->style & ES_OEMCONVERT)
-          {
-            INT len = lstrlenA(es->text);
-            CHAR *text = (LPSTR)HeapAlloc(es->heap,0,len);
-
-            CharToOemBuffA(es->text,text,len);
-            OemToCharBuffA(text,es->text,len);
-            HeapFree(es->heap,0,text);
-          }
-
-          if(es->style & ES_UPPERCASE)
-            CharUpperA(es->text);
-          else if(es->style & ES_LOWERCASE)
-            CharLowerA(es->text);
-        }
-
-        es->x_offset = es->y_offset = 0;
-        es->selection_start = es->selection_end = 0;
-        EDIT_EM_EmptyUndoBuffer(hwnd, es);
-        es->flags &= ~EF_MODIFIED;
-        es->flags &= ~EF_UPDATE;
-        EDIT_BuildLineDefs_ML(hwnd,es);
-        EDIT_Refresh(hwnd,es,FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-        EDIT_UpdateScrollBars(hwnd,es,TRUE,TRUE);
-}
-
-/*********************************************************************
- *
- *      EM_SETLIMITTEXT
- *
- *      FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
- *      However, the windows version is not complied to yet in all of edit.c
- *
- */
-static void EDIT_EM_SetLimitText(HWND hwnd, EDITSTATE *es, INT limit)
-{
-        if (es->style & ES_MULTILINE) {
-                if (limit)
-#ifdef __WIN32OS2__
-                        es->buffer_limit = limit;
-#else
-                        es->buffer_limit = MIN(limit, BUFLIMIT_MULTI);
-#endif
-                else
-                        es->buffer_limit = BUFLIMIT_MULTI;
-        } else {
-                if (limit)
-#ifdef __WIN32OS2__
-                        es->buffer_limit = MIN(limit, BUFLIMIT_SINGLE_NT);
-#else
-                        es->buffer_limit = MIN(limit, BUFLIMIT_SINGLE);
-#endif
-                else
-                        es->buffer_limit = BUFLIMIT_SINGLE;
-        }
-}
-
-
-/*********************************************************************
- *
- *      EM_SETMARGINS
- *
- * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
- * action wParam despite what the docs say. EC_USEFONTINFO means one third
- * of the char's width, according to the new docs.
- *
- */
-static void EDIT_EM_SetMargins(HWND hwnd, EDITSTATE *es, INT action,
-                               INT left, INT right)
-{
-        RECT r;
-        INT oldLeft = es->left_margin,oldRight = es->right_margin;
-
-        if (action & EC_LEFTMARGIN) {
-                if (left != EC_USEFONTINFO)
-                        es->left_margin = left;
-                else
-                        es->left_margin = es->char_width / 3;
-        }
-
-        if (action & EC_RIGHTMARGIN) {
-                if (right != EC_USEFONTINFO)
-                        es->right_margin = right;
-                else
-                        es->right_margin = es->char_width / 3;
-        }
-        //TRACE_(edit)("left=%d, right=%d\n", es->left_margin, es->right_margin);
-
-        if ((oldLeft != es->left_margin) || (oldRight != es->right_margin))
-        {
-          GetClientRect(hwnd, &r);
-          EDIT_SetRectNP(hwnd, es, &r);
-          if (es->style & ES_MULTILINE)
-                  EDIT_BuildLineDefs_ML(hwnd,es);
-
-          EDIT_Refresh(hwnd,es,FALSE);
-          if (es->flags & EF_FOCUSED) {
-                  DestroyCaret();
-                  CreateCaret(hwnd, 0, 2, es->line_height);
-                  EDIT_SetCaretPos(hwnd, es, es->selection_end,
-                                   es->flags & EF_AFTER_WRAP);
-                  ShowCaret(hwnd);
-          }
-        }
-}
-
-static void EDIT_EM_SetModify(HWND hwnd,EDITSTATE *es,BOOL fModified)
-{
-  if (fModified)
-    es->flags |= EF_MODIFIED;
-  else
-    es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
-}
-
-/*********************************************************************
- *
- *      EM_SETPASSWORDCHAR
- *
- */
-static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, CHAR c)
-{
-        if (es->style & ES_MULTILINE)
-                return;
-
-        if (es->password_char == c)
-                return;
-
-        es->password_char = c;
-        if (c) {
-                SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) | ES_PASSWORD);
-                es->style |= ES_PASSWORD;
-        } else {
-                SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~ES_PASSWORD);
-                es->style &= ~ES_PASSWORD;
-        }
-        EDIT_Refresh(hwnd,es,FALSE);
-}
-
-static BOOL EDIT_EM_SetReadOnly(HWND hwnd,EDITSTATE *es,BOOL fReadOnly)
-{
-  if (fReadOnly)
-  {
-    SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) | ES_READONLY);
-    es->style |= ES_READONLY;
-  } else
-  {
-    SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~ES_READONLY);
-    es->style &= ~ES_READONLY;
-  }
-
-  return TRUE;
-}
-
-static void EDIT_EM_SetRect(HWND hwnd,EDITSTATE *es,LPRECT lprc)
-{
-  if ((es->style & ES_MULTILINE) && lprc)
-  {
-    EDIT_SetRectNP(hwnd,es,lprc);
-    EDIT_Refresh(hwnd,es,FALSE);
-  }
-}
-
-static void EDIT_EM_SetRectNP(HWND hwnd,EDITSTATE *es,LPRECT lprc)
-{
-  if ((es->style & ES_MULTILINE) && lprc)
-    EDIT_SetRectNP(hwnd,es,lprc);
-}
-
-/*********************************************************************
- *
- *      EDIT_EM_SetSel
- *
- *      note:   unlike the specs say: the order of start and end
- *              _is_ preserved in Windows.  (i.e. start can be > end)
- *              In other words: this handler is OK
- *
- */
-static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
-{
-        UINT old_start = es->selection_start;
-        UINT old_end = es->selection_end;
-        UINT len = lstrlenA(es->text);
-
-        if (start == -1) {
-                start = es->selection_end;
-                end = es->selection_end;
-        } else {
-                start = MIN(start, len);
-                end = MIN(end, len);
-        }
-        es->selection_start = start;
-        es->selection_end = end;
-        if (after_wrap)
-                es->flags |= EF_AFTER_WRAP;
-        else
-                es->flags &= ~EF_AFTER_WRAP;
-        if (es->flags & EF_FOCUSED)
-                EDIT_SetCaretPos(hwnd, es, end, after_wrap);
-/* This is little  bit more efficient than before, not sure if it can be improved. FIXME? */
-        ORDER_UINT(start, end);
-        ORDER_UINT(end, old_end);
-        ORDER_UINT(start, old_start);
-        ORDER_UINT(old_start, old_end);
-        if ((start == old_start) && (end == old_end)) return;
-        if (end != old_start)
-        {
-/*
- * One can also do
- *          ORDER_UINT32(end, old_start);
- *          EDIT_InvalidateText(wnd, es, start, end);
- *          EDIT_InvalidateText(wnd, es, old_start, old_end);
- * in place of the following if statement.
- */
-            if (old_start > end )
-            {
-                EDIT_InvalidateText(hwnd, es, start, end);
-                EDIT_InvalidateText(hwnd, es, old_start, old_end);
-            }
-            else
-            {
-                EDIT_InvalidateText(hwnd, es, start, old_start);
-                EDIT_InvalidateText(hwnd, es, end, old_end);
-            }
-        }
-        else EDIT_InvalidateText(hwnd, es, start, old_end);
-}
-
-
-/*********************************************************************
- *
- *      EM_SETTABSTOPS
- *
- */
-static BOOL EDIT_EM_SetTabStops(HWND hwnd, EDITSTATE *es, INT count, LPINT tabs)
-{
-        if (!(es->style & ES_MULTILINE))
-                return FALSE;
-        if (es->tabs)
-                HeapFree(es->heap, 0, es->tabs);
-        es->tabs_count = count;
-        if (!count)
-                es->tabs = NULL;
-        else {
-                es->tabs = (INT*)HeapAlloc(es->heap, 0, count * sizeof(INT));
-                memcpy(es->tabs, tabs, count * sizeof(INT));
-        }
-        return TRUE;
-}
-
-
-/*********************************************************************
- *
- *      EM_SETWORDBREAKPROC
- *
- */
-static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp)
-{
-        if (es->word_break_procA == wbp)
-                return;
-
-        es->word_break_procA = wbp;
-        if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
-                EDIT_BuildLineDefs_ML(hwnd,es);
-                EDIT_Refresh(hwnd,es,FALSE);
-        }
-}
-
-
-/*********************************************************************
- *
- *      EM_UNDO / WM_UNDO
- *
- */
-static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es)
-{
-        INT ulength = lstrlenA(es->undo_text);
-        LPSTR utext = (LPSTR)HeapAlloc(es->heap, 0, ulength + 1);
-
-        lstrcpyA(utext, es->undo_text);
-
-        //TRACE_(edit)("before UNDO:insertion length = %d, deletion buffer = %s\n",
-        //             es->undo_insert_count, utext);
-
-        EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
-        EDIT_EM_EmptyUndoBuffer(hwnd, es);
-        EDIT_EM_ReplaceSel(hwnd, es, TRUE, utext);
-        EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
-        HeapFree(es->heap, 0, utext);
-
-        //TRACE_(edit)("after UNDO:insertion length = %d, deletion buffer = %s\n",
-        //                es->undo_insert_count, es->undo_text);
-
-        if (es->flags & EF_UPDATE) {
-                es->flags &= ~EF_UPDATE;
-                EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-        }
-
-        return TRUE;
-}
-
-static LRESULT EDIT_EM_SetIMEStatus(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam)
-{
-  if (wParam == EMSIS_COMPOSITIONSTRING)
-  {
-    //CB: todo
-  }
-
-  return 0;
-}
-
-static LRESULT EDIT_EM_GetIMEStatus(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam)
-{
-  //CB: todo
-
-  return 0; //default
-}
-
-/*********************************************************************
- *
- *      WM_CHAR
- *
- */
-static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, CHAR c, DWORD key_data)
-{
-        BOOL control = GetKeyState(VK_CONTROL) & 0x8000;
-        switch (c) {
-        case '\r':
-            /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
-            if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
-            {
-              break;
-            }
-        case '\n':
-                if (es->style & ES_MULTILINE) {
-                        if (es->style & ES_READONLY) {
-                                EDIT_MoveHome(hwnd, es, FALSE);
-                                EDIT_MoveDown_ML(hwnd, es, FALSE);
-                        } else
-                        {
-                                EDIT_EM_ReplaceSel(hwnd, es, TRUE, "\r\n");
-                                if (es->flags & EF_UPDATE) {
-                                        es->flags &= ~EF_UPDATE;
-                                        EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-                                }
-                        }
-                }
-                break;
-        case '\t':
-                if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
-                {
-                        EDIT_EM_ReplaceSel(hwnd, es, TRUE, "\t");
-                        if (es->flags & EF_UPDATE) {
-                                es->flags &= ~EF_UPDATE;
-                                EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-                        }
-                }
-                break;
-        case VK_BACK:
-                if (!(es->style & ES_READONLY) && !control) {
-                        if (es->selection_start != es->selection_end)
-                                EDIT_WM_Clear(hwnd, es);
-                        else {
-                                /* delete character left of caret */
-                                EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
-                                EDIT_MoveBackward(hwnd, es, TRUE);
-                                EDIT_WM_Clear(hwnd, es);
-                        }
-                }
-                break;
-//CB: are these three keys documented or Linux style???
-        case 0x03: /* ^C */
-                SendMessageA(hwnd, WM_COPY, 0, 0);
-                break;
-        case 0x16: /* ^V */
-                SendMessageA(hwnd, WM_PASTE, 0, 0);
-                break;
-        case 0x18: /* ^X */
-                SendMessageA(hwnd, WM_CUT, 0, 0);
-                break;
-
-        default:
-                if (!(es->style & ES_READONLY) && ((BYTE)c >= ' ') && (c != 127))
-                {
-                  char str[2];
-
-                  if (es->style & ES_NUMBER)
-                  {
-                    	if (((BYTE)c < '0') || ((BYTE)c > '9')) {
-				MessageBeep(MB_ICONEXCLAMATION);
-                    		return;
-			}
-                  }
-                  str[0] = c;
-                  str[1] = '\0';
-                  EDIT_EM_ReplaceSel(hwnd, es, TRUE, str);
-                  if (es->flags & EF_UPDATE)
-                  {
-                    es->flags &= ~EF_UPDATE;
-                    EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-                  }
-                } else MessageBeep(MB_ICONEXCLAMATION);
-                break;
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_COMMAND
- *
- */
-static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND control)
-{
-        if (code || control)
-                return;
-
-        switch (id) {
-                case EM_UNDO:
-                        EDIT_EM_Undo(hwnd, es);
-                        break;
-                case WM_CUT:
-                        EDIT_WM_Cut(hwnd, es);
-                        break;
-                case WM_COPY:
-                        EDIT_WM_Copy(hwnd, es);
-                        break;
-                case WM_PASTE:
-                        EDIT_WM_Paste(hwnd, es);
-                        break;
-                case WM_CLEAR:
-                        EDIT_WM_Clear(hwnd, es);
-                        break;
-                case EM_SETSEL:
-                        EDIT_EM_SetSel(hwnd, es, 0, -1, FALSE);
-                        EDIT_EM_ScrollCaret(hwnd, es);
-                        break;
-                default:
-                        //ERR_(edit)("unknown menu item, please report\n");
-                        break;
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_CONTEXTMENU
- *
- *      Note: the resource files resource/sysres_??.rc cannot define a
- *              single popup menu.  Hence we use a (dummy) menubar
- *              containing the single popup menu as its first item.
- *
- *      FIXME: the message identifiers have been chosen arbitrarily,
- *              hence we use MF_BYPOSITION.
- *              We might as well use the "real" values (anybody knows ?)
- *              The menu definition is in resources/sysres_??.rc.
- *              Once these are OK, we better use MF_BYCOMMAND here
- *              (as we do in EDIT_WM_Command()).
- *
- */
-static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, HWND hwndBtn, INT x, INT y)
-{
-        HMENU menu = LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU");
-        HMENU popup = GetSubMenu(menu, 0);
-        UINT start = es->selection_start;
-        UINT end = es->selection_end;
-
-        ORDER_UINT(start, end);
-
-        /* undo */
-        EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(hwnd, es) ? MF_ENABLED : MF_GRAYED));
-        /* cut */
-        EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & (ES_PASSWORD | ES_READONLY)) ? MF_ENABLED : MF_GRAYED));
-        /* copy */
-        EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
-        /* paste */
-        EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_TEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
-        /* delete */
-        EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
-        /* select all */
-        EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != lstrlenA(es->text)) ? MF_ENABLED : MF_GRAYED));
-
-        TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hwnd, NULL);
-        DestroyMenu(menu);
-}
-
-
-/*********************************************************************
- *
- *      WM_COPY
- *
- */
-static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es)
-{
-        INT s = es->selection_start;
-        INT e = es->selection_end;
-        HGLOBAL hdst;
-        LPSTR dst;
-
-        if (e == s)
-                return;
-        ORDER_INT(s, e);
-        hdst = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(e - s + 1));
-        dst = (LPSTR)GlobalLock(hdst);
-        lstrcpynA(dst, es->text + s, e - s + 1);
-        GlobalUnlock(hdst);
-        OpenClipboard(hwnd);
-        EmptyClipboard();
-        SetClipboardData(CF_TEXT, hdst);
-        CloseClipboard();
-}
-
-
-/*********************************************************************
- *
- *      WM_CREATE
- *
- */
-static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCREATESTRUCTA cs)
-{
-       /*
-        *       To initialize some final structure members, we call some helper
-        *       functions.  However, since the EDITSTATE is not consistent (i.e.
-        *       not fully initialized), we should be very careful which
-        *       functions can be called, and in what order.
-        */
-        EDIT_WM_SetFont(hwnd, es, 0, FALSE);
-        EDIT_EM_EmptyUndoBuffer(hwnd, es);
-       if (cs->lpszName && *(cs->lpszName) != '\0') {
-           EDIT_EM_ReplaceSel(hwnd, es, FALSE, cs->lpszName);
-           /* if we insert text to the editline, the text scrolls out
-            * of the window, as the caret is placed after the insert
-            * pos normally; thus we reset es->selection... to 0 and
-            * update caret
-            */
-           es->selection_start = es->selection_end = 0;
-           EDIT_EM_ScrollCaret(hwnd, es);
-           if (es->flags & EF_UPDATE) {
-                es->flags &= ~EF_UPDATE;
-                EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-           }
-       }
-       return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_DESTROY
- *
- */
-static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es)
-{
-        if (!es) /* Protect against multiple destroy messages */
-            return;
-
-        if (es->hloc) {
-                while (LocalUnlock(es->hloc)) ;
-                LocalFree(es->hloc);
-        }
-
-        HeapDestroy(es->heap);
-        HeapFree(GetProcessHeap(), 0, es);
-        SetInfoPtr(hwnd,0);
-}
-
-
-/*********************************************************************
- *
- *      WM_ERASEBKGND
- *
- */
-static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc)
-{
-        HBRUSH brush;
-        RECT rc;
-
-        HideCaret(hwnd);
-
-        if (!es->bEnableState || (es->style & ES_READONLY))
-                brush = (HBRUSH)EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
-        else
-                brush = (HBRUSH)EDIT_SEND_CTLCOLOR(hwnd, dc);
-
-        if (!brush)
-                brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
-
-        GetClientRect(hwnd, &rc);
-        IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
-        GetClipBox(dc, &rc);
-        /*
-         *      FIXME:  specs say that we should UnrealizeObject() the brush,
-         *              but the specs of UnrealizeObject() say that we shouldn't
-         *              unrealize a stock object.  The default brush that
-         *              DefWndProc() returns is ... a stock object.
-         */
-        FillRect(dc, &rc, brush);
-        ShowCaret(hwnd);
-        return -1;
-}
-
-
-/*********************************************************************
- *
- *      WM_GETTEXT
- *
- */
-static INT EDIT_WM_GetText(HWND hwnd, EDITSTATE *es, INT count, LPSTR text)
-{
-  INT len;
-
-  if (es->text == NULL)  // the only case of failure i can imagine
-    return 0;
-
-  len = min(count, lstrlenA(es->text)+1); // determine length
-  lstrcpynA(text, es->text, len);       // copy as much as possible
-  return len;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_HScroll_Hack
- *
- *      16 bit notepad needs this.  Actually it is not _our_ hack,
- *      it is notepad's.  Notepad is sending us scrollbar messages with
- *      undocumented parameters without us even having a scrollbar ... !?!?
- *
- */
-static LRESULT EDIT_HScroll_Hack(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
-{
-        INT dx = 0;
-        INT fw = es->format_rect.right - es->format_rect.left;
-        LRESULT ret = 0;
-
-        if (!(es->flags & EF_HSCROLL_HACK)) {
-                //ERR_(edit)("hacked WM_HSCROLL handler invoked\n");
-                //ERR_(edit)("      if you are _not_ running 16 bit notepad, please report\n");
-                //ERR_(edit)("      (this message is only displayed once per edit control)\n");
-                es->flags |= EF_HSCROLL_HACK;
-        }
-
-        switch (action) {
-        case SB_LINELEFT:
-                if (es->x_offset)
-                        dx = -es->char_width;
-                break;
-        case SB_LINERIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = es->char_width;
-                break;
-        case SB_PAGELEFT:
-                if (es->x_offset)
-                        dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-                break;
-        case SB_PAGERIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-                break;
-        case SB_LEFT:
-                if (es->x_offset)
-                        dx = -es->x_offset;
-                break;
-        case SB_RIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = es->text_width - es->x_offset;
-                break;
-        case SB_THUMBTRACK:
-                es->flags |= EF_HSCROLL_TRACK;
-                dx = pos * es->text_width / 100 - es->x_offset;
-                break;
-        case SB_THUMBPOSITION:
-                es->flags &= ~EF_HSCROLL_TRACK;
-                if (!(dx = pos * es->text_width / 100 - es->x_offset))
-                        EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL);
-                break;
-        case SB_ENDSCROLL:
-                break;
-
-        default:
-                //ERR_(edit)("undocumented (hacked) WM_HSCROLL parameter, please report\n");
-                return 0;
-        }
-        if (dx)
-                EDIT_EM_LineScroll(hwnd, es, dx, 0);
-        return ret;
-}
-
-
-/*********************************************************************
- *
- *      WM_HSCROLL
- *
- */
-static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
-{
-        INT dx;
-        INT fw;
-
-        if (!(es->style & ES_MULTILINE))
-                return 0;
-
-        if (!(es->style & ES_AUTOHSCROLL))
-                return 0;
-
-        if (!(es->style & WS_HSCROLL))
-                return EDIT_HScroll_Hack(hwnd, es, action, pos, scroll_bar);
-
-        dx = 0;
-        fw = es->format_rect.right - es->format_rect.left;
-        switch (action) {
-        case SB_LINELEFT:
-                if (es->x_offset)
-                        dx = -es->char_width;
-                break;
-        case SB_LINERIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = es->char_width;
-                break;
-        case SB_PAGELEFT:
-                if (es->x_offset)
-                        dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-                break;
-        case SB_PAGERIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-                break;
-        case SB_LEFT:
-                if (es->x_offset)
-                        dx = -es->x_offset;
-                break;
-        case SB_RIGHT:
-                if (es->x_offset < es->text_width)
-                        dx = es->text_width - es->x_offset;
-                break;
-        case SB_THUMBTRACK:
-                es->flags |= EF_HSCROLL_TRACK;
-                dx = pos - es->x_offset;
-                break;
-        case SB_THUMBPOSITION:
-                es->flags &= ~EF_HSCROLL_TRACK;
-                if (!(dx = pos - es->x_offset)) {
-                        SetScrollPos(hwnd, SB_HORZ, pos, TRUE);
-                        EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL);
-                }
-                break;
-        case SB_ENDSCROLL:
-                break;
-
-        default:
-                //ERR_(edit)("undocumented WM_HSCROLL parameter, please report\n");
-                return 0;
-        }
-        if (dx)
-                EDIT_EM_LineScroll(hwnd, es, dx, 0);
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      EDIT_CheckCombo
- *
- */
-static BOOL EDIT_CheckCombo(HWND hwnd, EDITSTATE *es, UINT msg, INT key, DWORD key_data)
-{
-   HWND hLBox = es->hwndListBox;
-   HWND hCombo;
-   BOOL bDropped;
-   int  nEUI;
-
-   if (!hLBox)
-      return FALSE;
-
-   hCombo   = GetParent(hwnd);
-   bDropped = TRUE;
-   nEUI     = 0;
-
-   //TRACE_(combo)("[%04x]: handling msg %04x (%04x)\n",
-   //    		     wnd->hwndSelf, (UINT16)msg, (UINT16)key);
-
-   if (key == VK_UP || key == VK_DOWN)
-   {
-      if (SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0))
-         nEUI = 1;
-
-      if (msg == WM_KEYDOWN || nEUI)
-          bDropped = (BOOL)SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
-   }
-
-   switch (msg)
-   {
-      case WM_KEYDOWN:
-         if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
-         {
-            /* make sure ComboLBox pops up */
-            SendMessageA(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
-            key = VK_F4;
-            nEUI = 2;
-         }
-
-         SendMessageA(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
-         break;
-
-      case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
-         if (nEUI)
-            SendMessageA(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
-         else
-            SendMessageA(hLBox, WM_KEYDOWN, (WPARAM)VK_F4, 0);
-         break;
-   }
-
-   if(nEUI == 2)
-      SendMessageA(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
-
-   return TRUE;
-}
-
-/*********************************************************************
- *
- *      WM_KEYDOWN
- *
- *      Handling of special keys that don't produce a WM_CHAR
- *      (i.e. non-printable keys) & Backspace & Delete
- *
- */
-static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
-{
-        BOOL shift;
-        BOOL control;
-
-        if (GetKeyState(VK_MENU) & 0x8000)
-                return 0;
-
-        shift = GetKeyState(VK_SHIFT) & 0x8000;
-        control = GetKeyState(VK_CONTROL) & 0x8000;
-
-        switch (key) {
-        case VK_F4:
-        case VK_UP:
-                if (EDIT_CheckCombo(hwnd,es, WM_KEYDOWN, key, key_data) || key == VK_F4)
-                        break;
-                /* fall through */
-        case VK_LEFT:
-                if ((es->style & ES_MULTILINE) && (key == VK_UP))
-                        EDIT_MoveUp_ML(hwnd, es, shift);
-                else
-                        if (control)
-                                EDIT_MoveWordBackward(hwnd, es, shift);
-                        else
-                                EDIT_MoveBackward(hwnd, es, shift);
-                break;
-        case VK_DOWN:
-                if (EDIT_CheckCombo(hwnd,es, WM_KEYDOWN, key, key_data))
-                        break;
-                /* fall through */
-        case VK_RIGHT:
-                if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
-                        EDIT_MoveDown_ML(hwnd, es, shift);
-                else if (control)
-                        EDIT_MoveWordForward(hwnd, es, shift);
-                else
-                        EDIT_MoveForward(hwnd, es, shift);
-                break;
-        case VK_HOME:
-                EDIT_MoveHome(hwnd, es, shift);
-                break;
-        case VK_END:
-                EDIT_MoveEnd(hwnd, es, shift);
-                break;
-        case VK_PRIOR:
-                if (es->style & ES_MULTILINE)
-                        EDIT_MovePageUp_ML(hwnd, es, shift);
-		else
-			EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key, key_data);
-                break;
-        case VK_NEXT:
-                if (es->style & ES_MULTILINE)
-                        EDIT_MovePageDown_ML(hwnd, es, shift);
-		else
-			EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key, key_data);
-                break;
-        case VK_DELETE:
-                if (!(es->style & ES_READONLY) && !(shift && control)) {
-                        if (es->selection_start != es->selection_end) {
-                                if (shift)
-                                        EDIT_WM_Cut(hwnd, es);
-                                else
-                                        EDIT_WM_Clear(hwnd, es);
-                        } else {
-                                if (shift) {
-                                        /* delete character left of caret */
-                                        EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
-                                        EDIT_MoveBackward(hwnd, es, TRUE);
-                                        EDIT_WM_Clear(hwnd, es);
-                                } else if (control) {
-                                        /* delete to end of line */
-                                        EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
-                                        EDIT_MoveEnd(hwnd, es, TRUE);
-                                        EDIT_WM_Clear(hwnd, es);
-                                } else {
-                                        /* delete character right of caret */
-                                        EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
-                                        EDIT_MoveForward(hwnd, es, TRUE);
-                                        EDIT_WM_Clear(hwnd, es);
-                                }
-                        }
-                }
-                break;
-        case VK_INSERT:
-                if (shift) {
-                        if (!(es->style & ES_READONLY))
-                                EDIT_WM_Paste(hwnd, es);
-                } else if (control)
-                        EDIT_WM_Copy(hwnd, es);
-                break;
-        case VK_RETURN:
-            /* If the edit doesn't want the return send a message to the default object */
-            if(!(es->style & ES_WANTRETURN))
-            {
-                HWND hwndParent = GetParent(hwnd);
-                DWORD dw = SendMessageA( hwndParent, DM_GETDEFID, 0, 0 );
-                if (HIWORD(dw) == DC_HASDEFID)
-                {
-                    SendMessageA( hwndParent, WM_COMMAND,
-                                  MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
-                              (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
-                }
-            }
-            break;
-        }
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_KILLFOCUS
- *
- */
-static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es, HWND window_getting_focus)
-{
-        es->flags &= ~EF_FOCUSED;
-        DestroyCaret();
-        if(!(es->style & ES_NOHIDESEL))
-                EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
-        EDIT_NOTIFY_PARENT(hwnd, EN_KILLFOCUS);
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_LBUTTONDBLCLK
- *
- *      The caret position has been set on the WM_LBUTTONDOWN message
- *
- */
-static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
-{
-        INT s;
-        INT e = es->selection_end;
-        INT l;
-        INT li;
-        INT ll;
-
-        if (!(es->flags & EF_FOCUSED))
-                return 0;
-
-        l = EDIT_EM_LineFromChar(hwnd, es, e);
-        li = EDIT_EM_LineIndex(hwnd, es, l);
-        ll = EDIT_EM_LineLength(hwnd, es, e);
-        s = li + EDIT_CallWordBreakProc (hwnd, es, li, e - li, ll, WB_LEFT);
-        e = li + EDIT_CallWordBreakProc(hwnd, es, li, e - li, ll, WB_RIGHT);
-        EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_LBUTTONDOWN
- *
- */
-static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
-{
-        INT e;
-        BOOL after_wrap;
-
-        if (!(es->flags & EF_FOCUSED))
-          return 0;
-
-        es->bCaptureState = TRUE;
-        SetCapture(hwnd);
-        EDIT_ConfinePoint(hwnd, es, &x, &y);
-        e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
-        EDIT_EM_SetSel(hwnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
-        EDIT_EM_ScrollCaret(hwnd, es);
-        es->region_posx = es->region_posy = 0;
-        SetTimer(hwnd, 0, 100, NULL);
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_LBUTTONUP
- *
- */
-static LRESULT EDIT_WM_LButtonUp(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
-{
-  if (es->bCaptureState)
-  {
-    KillTimer(hwnd,0);
-    ReleaseCapture();
-  }
-  es->bCaptureState = FALSE;
-
-  return 0;
-}
-
-static LRESULT EDIT_WM_CaptureChanged(HWND hwnd,EDITSTATE *es)
-{
-  if (es->bCaptureState) KillTimer(hwnd,0);
-  es->bCaptureState = FALSE;
-
-  return 0;
-}
-
-/*********************************************************************
- *
- *      WM_MOUSEMOVE
- *
- */
-static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
-{
-        INT e;
-        BOOL after_wrap;
-        INT prex, prey;
-
-        if (!es->bCaptureState) return 0;
-
-        /*
-         *      FIXME: gotta do some scrolling if outside client
-         *              area.  Maybe reset the timer ?
-         */
-        prex = x; prey = y;
-        EDIT_ConfinePoint(hwnd, es, &x, &y);
-        es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
-        es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
-        e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
-        EDIT_EM_SetSel(hwnd, es, es->selection_start, e, after_wrap);
-
-        return 0;
-}
-
-
-/*********************************************************************
- *
- *      WM_NCCREATE
- *
- */
-static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTA cs)
-{
-        EDITSTATE *es;
-
-        if (!(es = (EDITSTATE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
-                return FALSE;
-        SetInfoPtr(hwnd,(DWORD)es);
-
-       /*
-        *      Note: since the EDITSTATE has not been fully initialized yet,
-        *            we can't use any API calls that may send
-        *            WM_XXX messages before WM_NCCREATE is completed.
-        */
-
-        if (!(es->heap = HeapCreate(0, 0x10000, 0)))
-                return FALSE;
-        es->style = cs->style;
-
-        es->bEnableState = !(cs->style & WS_DISABLED);
-
-        /*
-         * In Win95 look and feel, the WS_BORDER style is replaced by the
-         * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
-         * control a non client area.
-         */
-        if (es->style & WS_BORDER)
-        {
-          es->style      &= ~WS_BORDER;
-          SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~WS_BORDER);
-          SetWindowLongA(hwnd,GWL_EXSTYLE,GetWindowLongA(hwnd,GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
-        }
-
-	if (es->style & ES_COMBO)
-	   es->hwndListBox = GetDlgItem(cs->hwndParent, ID_CB_LISTBOX);
-
-        if (es->style & ES_MULTILINE) {
-                es->buffer_size = BUFSTART_MULTI;
-                es->buffer_limit = BUFLIMIT_MULTI;
-                if (es->style & WS_VSCROLL)
-                        es->style |= ES_AUTOVSCROLL;
-                if (es->style & WS_HSCROLL)
-                        es->style |= ES_AUTOHSCROLL;
-                es->style &= ~ES_PASSWORD;
-                if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
-                        if (es->style & ES_RIGHT)
-                                es->style &= ~ES_CENTER;
-                        es->style &= ~WS_HSCROLL;
-                        es->style &= ~ES_AUTOHSCROLL;
-                }
-
-                /* FIXME: for now, all multi line controls are AUTOVSCROLL */
-                es->style |= ES_AUTOVSCROLL;
-        } else {
-                es->buffer_size = BUFSTART_SINGLE;
-                es->buffer_limit = BUFLIMIT_SINGLE;
-                es->style &= ~ES_CENTER;
-                es->style &= ~ES_RIGHT;
-                es->style &= ~WS_HSCROLL;
-                es->style &= ~WS_VSCROLL;
-                es->style &= ~ES_AUTOVSCROLL;
-                es->style &= ~ES_WANTRETURN;
-                if (es->style & ES_UPPERCASE) {
-                        es->style &= ~ES_LOWERCASE;
-                        es->style &= ~ES_NUMBER;
-                } else if (es->style & ES_LOWERCASE)
-                        es->style &= ~ES_NUMBER;
-                if (es->style & ES_PASSWORD)
-                        es->password_char = '*';
-
-                /* FIXME: for now, all single line controls are AUTOHSCROLL */
-                es->style |= ES_AUTOHSCROLL;
-        }
-        if (!(es->text = (char*)HeapAlloc(es->heap, 0, es->buffer_size + 1)))
-                return FALSE;
-        es->buffer_size = HeapSize(es->heap, 0, es->text) - 1;
-        if (!(es->undo_text = (char*)HeapAlloc(es->heap, 0, es->buffer_size + 1)))
-                return FALSE;
-        es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1;
-        *es->text = '\0';
-        if (es->style & ES_MULTILINE)
-                if (!(es->first_line_def = (LINEDEF*)HeapAlloc(es->heap, HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
-                        return FALSE;
-        es->line_count = 1;
-
-        return TRUE;
-}
-
-static VOID EDIT_Draw(HWND hwnd,EDITSTATE *es,HDC hdc,BOOL eraseBkGnd)
-{
-  INT i;
-  HFONT old_font = 0;
-  RECT rc;
-  RECT rcLine;
-  RECT rcRgn;
-  BOOL rev = es->bEnableState && ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL));
-
-  HideCaret(hwnd);
-
-  if (eraseBkGnd)
-  {
-    HBRUSH brush;
-
-    if (!es->bEnableState || (es->style & ES_READONLY))
-      brush = (HBRUSH)EDIT_SEND_CTLCOLORSTATIC(hwnd, hdc);
-    else
-      brush = (HBRUSH)EDIT_SEND_CTLCOLOR(hwnd, hdc);
-
-    if (!brush)
-      brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
-
-    GetClientRect(hwnd, &rc);
-    /*
-     *      FIXME:  specs say that we should UnrealizeObject() the brush,
-     *              but the specs of UnrealizeObject() say that we shouldn't
-     *              unrealize a stock object.  The default brush that
-     *              DefWndProc() returns is ... a stock object.
-     */
-    FillRect(hdc, &rc, brush);
-  }
-
-  if(es->style & WS_BORDER)
-  {
-    GetClientRect(hwnd, &rc);
-    if(es->style & ES_MULTILINE)
-    {
-      if(es->style & WS_HSCROLL) rc.bottom++;
-      if(es->style & WS_VSCROLL) rc.right++;
-    }
-    Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
-  }
-
-  IntersectClipRect(hdc, es->format_rect.left,
-                        es->format_rect.top,
-                        es->format_rect.right,
-                        es->format_rect.bottom);
-  if (es->style & ES_MULTILINE)
-  {
-    GetClientRect(hwnd, &rc);
-    IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
-  }
-  if (es->font) old_font = SelectObject(hdc, es->font);
-  if (!es->bEnableState || (es->style & ES_READONLY))
-    EDIT_SEND_CTLCOLORSTATIC(hwnd, hdc);
-  else
-    EDIT_SEND_CTLCOLOR(hwnd, hdc);
-  if (!es->bEnableState)
-    SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
-  GetClipBox(hdc, &rcRgn);
-  if (es->style & ES_MULTILINE)
-  {
-    INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-
-    for (i = es->y_offset ; i <= MIN(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++)
-    {
-      EDIT_GetLineRect(hwnd,hdc, es, i, 0, -1, &rcLine);
-      if (IntersectRect(&rc, &rcRgn, &rcLine))
-        EDIT_PaintLine(hwnd, es, hdc, i, rev);
-    }
-  } else
-  {
-    EDIT_GetLineRect(hwnd,hdc, es, 0, 0, -1, &rcLine);
-    if (IntersectRect(&rc, &rcRgn, &rcLine))
-      EDIT_PaintLine(hwnd, es, hdc, 0, rev);
-  }
-  if (es->font) SelectObject(hdc, old_font);
-  if (es->flags & EF_FOCUSED)
-    EDIT_SetCaretPos(hwnd, es, es->selection_end,es->flags & EF_AFTER_WRAP);
-
-  ShowCaret(hwnd);
-}
-
-static VOID EDIT_Refresh(HWND hwnd,EDITSTATE *es,BOOL useCache)
-{
-  HDC hdc,hdcCompatible;
-  HBITMAP bitmap,oldbmp;
-  RECT rect;
-
-  if (es->flags & EF_UPDATE)
-  {
-    //CB: don't reset flag or EN_CHANGE is lost!
-    //es->flags &= ~EF_UPDATE;
-    EDIT_NOTIFY_PARENT(hwnd,EN_UPDATE);
-  }
-
-  if (!IsWindowVisible(hwnd)) return;
-
-  if (!useCache)
-  {
-    InvalidateRect(hwnd,NULL,TRUE);
-    return;
-  }
-
-  //CB: original control redraws many times, cache drawing
-  HideCaret(hwnd);
-  GetClientRect(hwnd,&rect);
-  hdc = GetDC(hwnd);
-  hdcCompatible = CreateCompatibleDC(hdc);
-  bitmap = CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
-  oldbmp = SelectObject(hdcCompatible,bitmap);
-  EDIT_Draw(hwnd,es,hdcCompatible,TRUE);
-  SelectClipRgn(hdcCompatible,0);
-  BitBlt(hdc,0,0,rect.right,rect.bottom,hdcCompatible,0,0,SRCCOPY);
-  SelectObject(hdcCompatible,oldbmp);
-  DeleteObject(bitmap);
-  DeleteDC(hdcCompatible);
-  ReleaseDC(hwnd,hdc);
-  ShowCaret(hwnd);
-}
-
-/*********************************************************************
- *
- *      WM_PAINT
- *
- */
-static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es,WPARAM wParam)
-{
-	PAINTSTRUCT ps;
-	INT i;
-	HDC dc;
-	HFONT old_font = 0;
-	RECT rc;
-	RECT rcLine;
-	RECT rcRgn;
-	BOOL rev = es->bEnableState &&
-				((es->flags & EF_FOCUSED) ||
-					(es->style & ES_NOHIDESEL));
-        if (!wParam)
-            dc = BeginPaint(hwnd, &ps);
-        else
-            dc = (HDC) wParam;
-	if(es->style & WS_BORDER) {
-		GetClientRect(hwnd, &rc);
-		if(es->style & ES_MULTILINE) {
-			if(es->style & WS_HSCROLL) rc.bottom++;
-			if(es->style & WS_VSCROLL) rc.right++;
-		}
-		Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom);
-	}
-	IntersectClipRect(dc, es->format_rect.left,
-				es->format_rect.top,
-				es->format_rect.right,
-				es->format_rect.bottom);
-	if (es->style & ES_MULTILINE) {
-		GetClientRect(hwnd, &rc);
-		IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
-	}
-	if (es->font)
-		old_font = SelectObject(dc, es->font);
-        if (!es->bEnableState || (es->style & ES_READONLY))
-                EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
-        else
-                EDIT_SEND_CTLCOLOR(hwnd, dc);
-
-	if (!es->bEnableState)
-		SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
-	GetClipBox(dc, &rcRgn);
-	if (es->style & ES_MULTILINE) {
-		INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-		for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
-			EDIT_GetLineRect(hwnd, dc, es, i, 0, -1, &rcLine);
-			if (IntersectRect(&rc, &rcRgn, &rcLine))
-				EDIT_PaintLine(hwnd, es, dc, i, rev);
-		}
-	} else {
-		EDIT_GetLineRect(hwnd, dc, es, 0, 0, -1, &rcLine);
-		if (IntersectRect(&rc, &rcRgn, &rcLine))
-			EDIT_PaintLine(hwnd, es, dc, 0, rev);
-	}
-	if (es->font)
-		SelectObject(dc, old_font);
-
-        if (!wParam)
-            EndPaint(hwnd, &ps);
-}
-
-
-/*********************************************************************
- *
- *      WM_PASTE
- *
- */
-static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es)
-{
-        HGLOBAL hsrc;
-        LPSTR src;
-
-	/* Protect read-only edit control from modification */
-	if(es->style & ES_READONLY)
-	    return;
-
-        OpenClipboard(hwnd);
-        hsrc = GetClipboardData(CF_TEXT);
-        if (hsrc) {
-                src = (LPSTR)GlobalLock(hsrc);
-                EDIT_EM_ReplaceSel(hwnd, es, TRUE, src);
-                GlobalUnlock(hsrc);
-
-                if (es->flags & EF_UPDATE) {
-                        es->flags &= ~EF_UPDATE;
-                        EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-                }
-        }
-        CloseClipboard();
-}
-
-
-/*********************************************************************
- *
- *      WM_SETFOCUS
- *
- */
-static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es, HWND window_losing_focus)
-{
-        es->flags |= EF_FOCUSED;
-        CreateCaret(hwnd, 0, 2, es->line_height);
-        EDIT_SetCaretPos(hwnd, es, es->selection_end,
-                         es->flags & EF_AFTER_WRAP);
-        if(!(es->style & ES_NOHIDESEL))
-                EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
-        ShowCaret(hwnd);
-        EDIT_NOTIFY_PARENT(hwnd, EN_SETFOCUS);
-}
-
-/*********************************************************************
- *
- *      WM_SETFONT
- *
- * With Win95 look the margins are set to default font value unless
- * the system font (font == 0) is being set, in which case they are left
- * unchanged.
- *
- */
-static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw)
-{
-        TEXTMETRICA tm;
-        HDC dc;
-        HFONT old_font = 0;
-        RECT r;
-
-        dc = GetDC(hwnd);
-        if (font)
-                old_font = SelectObject(dc, font);
-        if (!GetTextMetricsA(dc, &tm))
-        {
-          if (font) SelectObject(dc,old_font);
-          ReleaseDC(hwnd,dc);
-
-          return;
-        }
-        es->font = font;
-        es->line_height = tm.tmHeight;
-
-        es->char_width = tm.tmAveCharWidth;
-        if (font)
-                SelectObject(dc, old_font);
-        ReleaseDC(hwnd, dc);
-        if (font)
-                EDIT_EM_SetMargins(hwnd, es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
-                                   EC_USEFONTINFO, EC_USEFONTINFO);
-        /* Force the recalculation of the format rect for each font change */
-        GetClientRect(hwnd, &r);
-        EDIT_SetRectNP(hwnd, es, &r);
-        if (es->style & ES_MULTILINE)
-                EDIT_BuildLineDefs_ML(hwnd,es);
-
-        if (redraw)
-                EDIT_Refresh(hwnd,es,FALSE);
-        if (es->flags & EF_FOCUSED) {
-                DestroyCaret();
-                CreateCaret(hwnd, 0, 2, es->line_height);
-                EDIT_SetCaretPos(hwnd, es, es->selection_end,
-                                 es->flags & EF_AFTER_WRAP);
-                ShowCaret(hwnd);
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_SETTEXT
- *
- * NOTES
- *  For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
- *  The modified flag is reset. No notifications are sent.
- *
- *  For single-line controls, reception of WM_SETTEXT triggers:
- *  The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
- *
- */
-static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPCSTR text)
-{
-#ifdef __WIN32OS2__
-        //SvL: Acrobat Distiller keeps on sending WM_SETTEXT with the same
-        //     string in responds to a WM_COMMAND with EN_UPDATE -> stack
-        //     overflow (TODO: Need to check if this behaviour is correct compared to NT)
-        if(text && es->text) {
-		if(!strcmp(es->text, text)) {
-			return;
-		}
-        }
-#endif
-        es->selection_start = 0;
-        es->selection_end = lstrlenA(es->text);
-        if (es->flags & EF_FOCUSED)
-          EDIT_SetCaretPos(hwnd, es, es->selection_end, FALSE);
-
-        if (text) {
-                //TRACE_(edit)("\t'%s'\n", text);
-                EDIT_EM_ReplaceSel(hwnd, es, FALSE, text);
-        } else {
-                //TRACE_(edit)("\t<NULL>\n");
-                EDIT_EM_ReplaceSel(hwnd, es, FALSE, "");
-        }
-        es->x_offset = 0;
-        if (es->style & ES_MULTILINE) {
-                es->flags &= ~EF_UPDATE;
-        } else {
-                es->flags |= EF_UPDATE;
-        }
-        es->flags &= ~EF_MODIFIED;
-        EDIT_EM_SetSel(hwnd, es, 0, 0, FALSE);
-        EDIT_EM_ScrollCaret(hwnd, es);
-        EDIT_UpdateScrollBars(hwnd,es,TRUE,TRUE);
-        if (es->flags & EF_UPDATE)
-        {
-          EDIT_NOTIFY_PARENT(hwnd,EN_UPDATE);
-          /* EN_CHANGE notification need to be sent too
-             Windows doc says it's only done after the display,
-             the doc is WRONG. EN_CHANGE notification is sent
-             while processing WM_SETTEXT */
-          EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE);
-          es->flags &= ~EF_UPDATE;
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_SIZE
- *
- */
-static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height)
-{
-        if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
-                RECT rc;
-                SetRect(&rc, 0, 0, width, height);
-                EDIT_SetRectNP(hwnd, es, &rc);
-                EDIT_Refresh(hwnd,es,FALSE);
-        }
-}
-
-
-/*********************************************************************
- *
- *      WM_SYSKEYDOWN
- *
- */
-static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
-{
-        if ((key == VK_BACK) && (key_data & 0x2000)) {
-                if (EDIT_EM_CanUndo(hwnd, es))
-                        EDIT_EM_Undo(hwnd, es);
-                return 0;
-        } else if ((key == VK_UP) || (key == VK_DOWN))
-        {
-                if (EDIT_CheckCombo(hwnd,es, WM_SYSKEYDOWN, key, key_data))
-                        return 0;
-         }
-        return DefWindowProcA(hwnd, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
-}
-
-
-/*********************************************************************
- *
- *      WM_TIMER
- *
- */
-static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es, INT id, TIMERPROC timer_proc)
-{
-        if (es->region_posx < 0) {
-                EDIT_MoveBackward(hwnd, es, TRUE);
-        } else if (es->region_posx > 0) {
-                EDIT_MoveForward(hwnd, es, TRUE);
-        }
-
-        if (!(es->style & ES_MULTILINE)) return;
-
-        if (es->region_posy < 0)
-        {
-          EDIT_MoveUp_ML(hwnd,es,TRUE);
-        } else if (es->region_posy > 0)
-        {
-          EDIT_MoveDown_ML(hwnd,es,TRUE);
-        }
-}
-
-
-/*********************************************************************
- *
- *      EDIT_VScroll_Hack
- *
- *      16 bit notepad needs this.  Actually it is not _our_ hack,
- *      it is notepad's.  Notepad is sending us scrollbar messages with
- *      undocumented parameters without us even having a scrollbar ... !?!?
- *
- */
-static LRESULT EDIT_VScroll_Hack(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
-{
-        INT dy = 0;
-        LRESULT ret = 0;
-
-        if (!(es->flags & EF_VSCROLL_HACK)) {
-                //ERR_(edit)("hacked WM_VSCROLL handler invoked\n");
-                //ERR_(edit)("      if you are _not_ running 16 bit notepad, please report\n");
-                //ERR_(edit)("      (this message is only displayed once per edit control)\n");
-                es->flags |= EF_VSCROLL_HACK;
-        }
-
-        switch (action) {
-        case SB_LINEUP:
-        case SB_LINEDOWN:
-        case SB_PAGEUP:
-        case SB_PAGEDOWN:
-                EDIT_EM_Scroll(hwnd, es, action);
-                return 0;
-        case SB_TOP:
-                dy = -es->y_offset;
-                break;
-        case SB_BOTTOM:
-                dy = es->line_count - 1 - es->y_offset;
-                break;
-        case SB_THUMBTRACK:
-                es->flags |= EF_VSCROLL_TRACK;
-                dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset;
-                break;
-        case SB_THUMBPOSITION:
-                es->flags &= ~EF_VSCROLL_TRACK;
-                if (!(dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset))
-                        EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL);
-                break;
-        case SB_ENDSCROLL:
-                break;
-
-        default:
-                //ERR_(edit)("undocumented (hacked) WM_VSCROLL parameter, please report\n");
-                return 0;
-        }
-        if (dy)
-                EDIT_EM_LineScroll(hwnd, es, 0, dy);
-        return ret;
-}
-
-
-/*********************************************************************
- *
- *      WM_VSCROLL
- *
- */
-static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
-{
-        INT dy;
-
-        if (!(es->style & ES_MULTILINE))
-                return 0;
-
-        if (!(es->style & ES_AUTOVSCROLL))
-                return 0;
-
-        if (!(es->style & WS_VSCROLL))
-                return EDIT_VScroll_Hack(hwnd, es, action, pos, scroll_bar);
-
-        dy = 0;
-        switch (action) {
-        case SB_LINEUP:
-        case SB_LINEDOWN:
-        case SB_PAGEUP:
-        case SB_PAGEDOWN:
-                EDIT_EM_Scroll(hwnd, es, action);
-                return 0;
-
-        case SB_TOP:
-                dy = -es->y_offset;
-                break;
-        case SB_BOTTOM:
-                dy = es->line_count - 1 - es->y_offset;
-                break;
-        case SB_THUMBTRACK:
-                es->flags |= EF_VSCROLL_TRACK;
-                dy = pos - es->y_offset;
-                break;
-        case SB_THUMBPOSITION:
-                es->flags &= ~EF_VSCROLL_TRACK;
-                if (!(dy = pos - es->y_offset)) {
-                        SetScrollPos(hwnd, SB_VERT, pos, TRUE);
-                        EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL);
-                }
-                break;
-        case SB_ENDSCROLL:
-                break;
-
-        default:
-                //ERR_(edit)("undocumented WM_VSCROLL action %d, please report\n",
-                //        action);
-                return 0;
-        }
-        if (dy)
-                EDIT_EM_LineScroll(hwnd, es, 0, dy);
-        return 0;
-}
-
-static LRESULT EDIT_WM_MouseWheel(HWND hwnd,EDITSTATE *es,WPARAM wParam,LPARAM lParam)
-{
-  short gcWheelDelta = 0;
-  UINT pulScrollLines = 3;
-  SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
-
-  if (wParam & (MK_SHIFT | MK_CONTROL))
-    return DefWindowProcA(hwnd,WM_MOUSEWHEEL, wParam, lParam);
-  gcWheelDelta -= (short) HIWORD(wParam);
-  if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
-  {
-    int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
-
-    cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
-    return EDIT_EM_LineScroll(hwnd, es, 0, cLineScroll);
-  }
-
-  return 0;
-}
-
-BOOL EDIT_Register()
-{
-    WNDCLASSA wndClass;
-
-//SvL: Don't check this now
-//    if (GlobalFindAtomA(EDITCLASSNAME)) return FALSE;
-
-    ZeroMemory(&wndClass,sizeof(WNDCLASSA));
-    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
-    wndClass.lpfnWndProc   = (WNDPROC)EditWndProc;
-    wndClass.cbClsExtra    = 0;
-    wndClass.cbWndExtra    = sizeof(VOID*);
-    wndClass.hCursor       = LoadCursorA(0,IDC_IBEAMA);
-    wndClass.hbrBackground = (HBRUSH)0;
-    wndClass.lpszClassName = EDITCLASSNAME;
-
-    return RegisterClassA(&wndClass);
-}
-
-BOOL EDIT_Unregister()
-{
-    if (GlobalFindAtomA(EDITCLASSNAME))
-        return UnregisterClassA(EDITCLASSNAME,(HINSTANCE)NULL);
-    else return FALSE;
-}
Index: trunk/src/user32/listbox.c
===================================================================
--- trunk/src/user32/listbox.c	(revision 9523)
+++ trunk/src/user32/listbox.c	(revision 9523)
@@ -0,0 +1,3208 @@
+/*
+ * Listbox controls
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "windef.h"
+#include "wingdi.h"
+#include "wine/winuser16.h"
+#include "wine/winbase16.h"
+#include "wine/unicode.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "spy.h"
+#include "user.h"
+#include "controls.h"
+#include "debugtools.h"
+
+#ifdef __WIN32OS2__
+#include "ctrlconf.h"
+#endif
+
+DEFAULT_DEBUG_CHANNEL(listbox);
+DECLARE_DEBUG_CHANNEL(combo);
+
+/* Unimplemented yet:
+ * - LBS_USETABSTOPS
+ * - Locale handling
+ *
+ * Probably needs improvement:
+ * - LBS_NOSEL
+ */
+
+/* Items array granularity */
+#define LB_ARRAY_GRANULARITY 16
+
+/* Scrolling timeout in ms */
+#define LB_SCROLL_TIMEOUT 50
+
+/* Listbox system timer id */
+#define LB_TIMER_ID  2
+
+/* flag listbox changed while setredraw false - internal style */
+#define LBS_DISPLAYCHANGED 0x80000000
+
+/* Item structure */
+typedef struct
+{
+    LPWSTR  str;       /* Item text */
+    BOOL    selected;  /* Is item selected? */
+    UINT    height;    /* Item height (only for OWNERDRAWVARIABLE) */
+    DWORD   data;      /* User data */
+} LB_ITEMDATA;
+
+/* Listbox structure */
+typedef struct
+{
+    HWND        owner;          /* Owner window to send notifications to */
+    UINT        style;          /* Window style */
+    INT         width;          /* Window width */
+    INT         height;         /* Window height */
+    LB_ITEMDATA  *items;          /* Array of items */
+    INT         nb_items;       /* Number of items */
+    INT         top_item;       /* Top visible item */
+    INT         selected_item;  /* Selected item */
+    INT         focus_item;     /* Item that has the focus */
+    INT         anchor_item;    /* Anchor item for extended selection */
+    INT         item_height;    /* Default item height */
+    INT         page_size;      /* Items per listbox page */
+    INT         column_width;   /* Column width for multi-column listboxes */
+    INT         horz_extent;    /* Horizontal extent (0 if no hscroll) */
+    INT         horz_pos;       /* Horizontal position */
+    INT         nb_tabs;        /* Number of tabs in array */
+    INT        *tabs;           /* Array of tabs */
+    BOOL        caret_on;       /* Is caret on? */
+    BOOL        captured;       /* Is mouse captured? */
+    BOOL	in_focus;
+    HFONT       font;           /* Current font */
+    LCID          locale;         /* Current locale for string comparisons */
+    LPHEADCOMBO   lphc;		  /* ComboLBox */
+} LB_DESCR;
+
+
+#define IS_OWNERDRAW(descr) \
+    ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
+
+#define HAS_STRINGS(descr) \
+    (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
+
+
+#define IS_MULTISELECT(descr) \
+    ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
+
+#define SEND_NOTIFICATION(hwnd,descr,code) \
+    (SendMessageW( (descr)->owner, WM_COMMAND, \
+     MAKEWPARAM( GetWindowLongA((hwnd),GWL_ID), (code)), (hwnd) ))
+
+#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
+
+/* Current timer status */
+typedef enum
+{
+    LB_TIMER_NONE,
+    LB_TIMER_UP,
+    LB_TIMER_LEFT,
+    LB_TIMER_DOWN,
+    LB_TIMER_RIGHT
+} TIMER_DIRECTION;
+
+static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
+
+static LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+static LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+
+static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );
+
+/*********************************************************************
+ * listbox class descriptor
+ */
+const struct builtin_class_descr LISTBOX_builtin_class =
+{
+    "ListBox",            /* name */
+    CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/,  /* style */
+    ListBoxWndProcA,      /* procA */
+    ListBoxWndProcW,      /* procW */
+    sizeof(LB_DESCR *),   /* extra */
+    IDC_ARROWA,           /* cursor */
+    0                     /* brush */
+};
+
+
+/*********************************************************************
+ * combolbox class descriptor
+ */
+const struct builtin_class_descr COMBOLBOX_builtin_class =
+{
+    "ComboLBox",          /* name */
+    CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS,  /* style */
+    ComboLBWndProcA,      /* procA */
+    ComboLBWndProcW,      /* procW */
+    sizeof(LB_DESCR *),   /* extra */
+    IDC_ARROWA,           /* cursor */
+    0                     /* brush */
+};
+
+
+#ifdef __WIN32OS2__
+#define is_old_app( hwnd )	0
+#else
+/* check whether app is a Win 3.1 app */
+inline static BOOL is_old_app( HWND hwnd )
+{
+    return (GetExpWinVer16( GetWindowLongA(hwnd,GWL_HINSTANCE) ) & 0xFF00 ) == 0x0300;
+}
+#endif
+
+/***********************************************************************
+ *           LISTBOX_Dump
+ */
+void LISTBOX_Dump( HWND hwnd )
+{
+    INT i;
+    LB_ITEMDATA *item;
+    LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );
+
+    TRACE( "Listbox:\n" );
+    TRACE( "hwnd=%04x descr=%08x items=%d top=%d\n",
+                     hwnd, (UINT)descr, descr->nb_items,
+                     descr->top_item );
+    for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
+    {
+        TRACE( "%4d: %-40s %d %08lx %3d\n",
+               i, debugstr_w(item->str), item->selected, item->data, item->height );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetCurrentPageSize
+ *
+ * Return the current page size
+ */
+static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
+{
+    INT i, height;
+    if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
+    for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
+    {
+        if ((height += descr->items[i].height) > descr->height) break;
+    }
+    if (i == descr->top_item) return 1;
+    else return i - descr->top_item;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetMaxTopIndex
+ *
+ * Return the maximum possible index for the top of the listbox.
+ */
+static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
+{
+    INT max, page;
+
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        page = descr->height;
+        for (max = descr->nb_items - 1; max >= 0; max--)
+            if ((page -= descr->items[max].height) < 0) break;
+        if (max < descr->nb_items - 1) max++;
+    }
+    else if (descr->style & LBS_MULTICOLUMN)
+    {
+        if ((page = descr->width / descr->column_width) < 1) page = 1;
+        max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
+        max = (max - page) * descr->page_size;
+    }
+    else
+    {
+        max = descr->nb_items - descr->page_size;
+    }
+    if (max < 0) max = 0;
+    return max;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_UpdateScroll
+ *
+ * Update the scrollbars. Should be called whenever the content
+ * of the listbox changes.
+ */
+static void LISTBOX_UpdateScroll( HWND hwnd, LB_DESCR *descr )
+{
+    SCROLLINFO info;
+
+    /* Check the listbox scroll bar flags individually before we call
+       SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
+       no WS_VSCROLL, we end up with an uninitialized, visible horizontal
+       scroll bar when we do not need one.
+    if (!(descr->style & WS_VSCROLL)) return;
+    */
+
+    /*   It is important that we check descr->style, and not wnd->dwStyle,
+       for WS_VSCROLL, as the former is exactly the one passed in
+       argument to CreateWindow.
+         In Windows (and from now on in Wine :) a listbox created
+       with such a style (no WS_SCROLL) does not update
+       the scrollbar with listbox-related data, thus letting
+       the programmer use it for his/her own purposes. */
+
+    if (descr->style & LBS_NOREDRAW) return;
+    info.cbSize = sizeof(info);
+
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        info.nMin  = 0;
+        info.nMax  = (descr->nb_items - 1) / descr->page_size;
+        info.nPos  = descr->top_item / descr->page_size;
+        info.nPage = descr->width / descr->column_width;
+        if (info.nPage < 1) info.nPage = 1;
+        info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+        if (descr->style & LBS_DISABLENOSCROLL)
+            info.fMask |= SIF_DISABLENOSCROLL;
+        if (descr->style & WS_HSCROLL)
+            SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
+        info.nMax = 0;
+        info.fMask = SIF_RANGE;
+        if (descr->style & WS_VSCROLL)
+            SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
+    }
+    else
+    {
+        info.nMin  = 0;
+        info.nMax  = descr->nb_items - 1;
+        info.nPos  = descr->top_item;
+        info.nPage = LISTBOX_GetCurrentPageSize( descr );
+        info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+        if (descr->style & LBS_DISABLENOSCROLL)
+            info.fMask |= SIF_DISABLENOSCROLL;
+        if (descr->style & WS_VSCROLL)
+            SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
+
+        if (descr->horz_extent)
+        {
+            info.nMin  = 0;
+            info.nMax  = descr->horz_extent - 1;
+            info.nPos  = descr->horz_pos;
+            info.nPage = descr->width;
+            info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+            if (descr->style & LBS_DISABLENOSCROLL)
+                info.fMask |= SIF_DISABLENOSCROLL;
+            if (descr->style & WS_HSCROLL)
+                SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
+        }
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetTopItem
+ *
+ * Set the top item of the listbox, scrolling up or down if necessary.
+ */
+static LRESULT LISTBOX_SetTopItem( HWND hwnd, LB_DESCR *descr, INT index,
+                                   BOOL scroll )
+{
+    INT max = LISTBOX_GetMaxTopIndex( descr );
+    if (index > max) index = max;
+    if (index < 0) index = 0;
+    if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
+    if (descr->top_item == index) return LB_OKAY;
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
+        if (scroll && (abs(diff) < descr->width))
+            ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
+                              SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+
+        else
+            scroll = FALSE;
+    }
+    else if (scroll)
+    {
+        INT diff;
+        if (descr->style & LBS_OWNERDRAWVARIABLE)
+        {
+            INT i;
+            diff = 0;
+            if (index > descr->top_item)
+            {
+                for (i = index - 1; i >= descr->top_item; i--)
+                    diff -= descr->items[i].height;
+            }
+            else
+            {
+                for (i = index; i < descr->top_item; i++)
+                    diff += descr->items[i].height;
+            }
+        }
+        else
+            diff = (descr->top_item - index) * descr->item_height;
+
+        if (abs(diff) < descr->height)
+            ScrollWindowEx( hwnd, 0, diff, NULL, NULL, 0, NULL,
+                              SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+        else
+            scroll = FALSE;
+    }
+    if (!scroll) InvalidateRect( hwnd, NULL, TRUE );
+    descr->top_item = index;
+    LISTBOX_UpdateScroll( hwnd, descr );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_UpdatePage
+ *
+ * Update the page size. Should be called when the size of
+ * the client area or the item height changes.
+ */
+static void LISTBOX_UpdatePage( HWND hwnd, LB_DESCR *descr )
+{
+    INT page_size;
+
+    if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
+                       page_size = 1;
+    if (page_size == descr->page_size) return;
+    descr->page_size = page_size;
+    if (descr->style & LBS_MULTICOLUMN)
+        InvalidateRect( hwnd, NULL, TRUE );
+    LISTBOX_SetTopItem( hwnd, descr, descr->top_item, FALSE );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_UpdateSize
+ *
+ * Update the size of the listbox. Should be called when the size of
+ * the client area changes.
+ */
+static void LISTBOX_UpdateSize( HWND hwnd, LB_DESCR *descr )
+{
+    RECT rect;
+
+    GetClientRect( hwnd, &rect );
+    descr->width  = rect.right - rect.left;
+    descr->height = rect.bottom - rect.top;
+    if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
+    {
+        INT remaining;
+        RECT rect;
+
+        GetWindowRect( hwnd, &rect );
+        if(descr->item_height != 0)
+            remaining = descr->height % descr->item_height;
+        else
+            remaining = 0;
+        if ((descr->height > descr->item_height) && remaining)
+        {
+            if (is_old_app(hwnd))
+            { /* give a margin for error to 16 bits programs - if we need
+                 less than the height of the nonclient area, round to the
+                 *next* number of items */
+                int ncheight = rect.bottom - rect.top - descr->height;
+                if ((descr->item_height - remaining) <= ncheight)
+                    remaining = remaining - descr->item_height;
+            }
+            TRACE("[%04x]: changing height %d -> %d\n",
+                  hwnd, descr->height, descr->height - remaining );
+            SetWindowPos( hwnd, 0, 0, 0, rect.right - rect.left,
+                            rect.bottom - rect.top - remaining,
+                            SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
+            return;
+        }
+    }
+    TRACE("[%04x]: new size = %d,%d\n", hwnd, descr->width, descr->height );
+    LISTBOX_UpdatePage( hwnd, descr );
+    LISTBOX_UpdateScroll( hwnd, descr );
+
+    /* Invalidate the focused item so it will be repainted correctly */
+    if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
+    {
+        InvalidateRect( hwnd, &rect, FALSE );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetItemRect
+ *
+ * Get the rectangle enclosing an item, in listbox client coordinates.
+ * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
+ */
+static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
+{
+    /* Index <= 0 is legal even on empty listboxes */
+    if (index && (index >= descr->nb_items)) return -1;
+    SetRect( rect, 0, 0, descr->width, descr->height );
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        INT col = (index / descr->page_size) -
+                        (descr->top_item / descr->page_size);
+        rect->left += col * descr->column_width;
+        rect->right = rect->left + descr->column_width;
+        rect->top += (index % descr->page_size) * descr->item_height;
+        rect->bottom = rect->top + descr->item_height;
+    }
+    else if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        INT i;
+        rect->right += descr->horz_pos;
+        if ((index >= 0) && (index < descr->nb_items))
+        {
+            if (index < descr->top_item)
+            {
+                for (i = descr->top_item-1; i >= index; i--)
+                    rect->top -= descr->items[i].height;
+            }
+            else
+            {
+                for (i = descr->top_item; i < index; i++)
+                    rect->top += descr->items[i].height;
+            }
+            rect->bottom = rect->top + descr->items[index].height;
+
+        }
+    }
+    else
+    {
+        rect->top += (index - descr->top_item) * descr->item_height;
+        rect->bottom = rect->top + descr->item_height;
+        rect->right += descr->horz_pos;
+    }
+
+    return ((rect->left < descr->width) && (rect->right > 0) &&
+            (rect->top < descr->height) && (rect->bottom > 0));
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetItemFromPoint
+ *
+ * Return the item nearest from point (x,y) (in client coordinates).
+ */
+static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
+{
+    INT index = descr->top_item;
+
+    if (!descr->nb_items) return -1;  /* No items */
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        INT pos = 0;
+        if (y >= 0)
+        {
+            while (index < descr->nb_items)
+            {
+                if ((pos += descr->items[index].height) > y) break;
+                index++;
+            }
+        }
+        else
+        {
+            while (index > 0)
+            {
+                index--;
+                if ((pos -= descr->items[index].height) <= y) break;
+            }
+        }
+    }
+    else if (descr->style & LBS_MULTICOLUMN)
+    {
+        if (y >= descr->item_height * descr->page_size) return -1;
+        if (y >= 0) index += y / descr->item_height;
+        if (x >= 0) index += (x / descr->column_width) * descr->page_size;
+        else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
+    }
+    else
+    {
+        index += (y / descr->item_height);
+    }
+    if (index < 0) return 0;
+    if (index >= descr->nb_items) return -1;
+    return index;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_PaintItem
+ *
+ * Paint an item.
+ */
+static void LISTBOX_PaintItem( HWND hwnd, LB_DESCR *descr, HDC hdc,
+                               const RECT *rect, INT index, UINT action, BOOL ignoreFocus )
+{
+    LB_ITEMDATA *item = NULL;
+    if (index < descr->nb_items) item = &descr->items[index];
+
+    if (IS_OWNERDRAW(descr))
+    {
+        DRAWITEMSTRUCT dis;
+        RECT r;
+        HRGN hrgn;
+        UINT id = GetWindowLongA( hwnd, GWL_ID );
+
+	if (!item)
+	{
+	    if (action == ODA_FOCUS)
+		DrawFocusRect( hdc, rect );
+	    else
+	        FIXME("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
+	    return;
+	}
+
+        /* some programs mess with the clipping region when
+        drawing the item, *and* restore the previous region
+        after they are done, so a region has better to exist
+        else everything ends clipped */
+        GetClientRect(hwnd, &r);
+        hrgn = CreateRectRgnIndirect(&r);
+        SelectClipRgn( hdc, hrgn);
+        DeleteObject( hrgn );
+
+        dis.CtlType      = ODT_LISTBOX;
+        dis.CtlID        = id;
+        dis.hwndItem     = hwnd;
+        dis.itemAction   = action;
+        dis.hDC          = hdc;
+        dis.itemID       = index;
+        dis.itemState    = 0;
+        if (item && item->selected) dis.itemState |= ODS_SELECTED;
+        if (!ignoreFocus && (descr->focus_item == index) &&
+            (descr->caret_on) &&
+            (descr->in_focus)) dis.itemState |= ODS_FOCUS;
+        if (!IsWindowEnabled(hwnd)) dis.itemState |= ODS_DISABLED;
+        dis.itemData     = item ? item->data : 0;
+        dis.rcItem       = *rect;
+        TRACE("[%04x]: drawitem %d (%s) action=%02x state=%02x rect=%d,%d-%d,%d\n",
+              hwnd, index, item ? debugstr_w(item->str) : "", action,
+              dis.itemState, rect->left, rect->top, rect->right, rect->bottom );
+        SendMessageW(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
+    }
+    else
+    {
+        COLORREF oldText = 0, oldBk = 0;
+
+        if (action == ODA_FOCUS)
+        {
+            DrawFocusRect( hdc, rect );
+            return;
+        }
+        if (item && item->selected)
+        {
+            oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
+            oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+        }
+
+        TRACE("[%04x]: painting %d (%s) action=%02x rect=%d,%d-%d,%d\n",
+              hwnd, index, item ? debugstr_w(item->str) : "", action,
+              rect->left, rect->top, rect->right, rect->bottom );
+        if (!item)
+            ExtTextOutW( hdc, rect->left + 1, rect->top,
+                           ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+        else if (!(descr->style & LBS_USETABSTOPS))
+            ExtTextOutW( hdc, rect->left + 1, rect->top,
+                         ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
+                         strlenW(item->str), NULL );
+        else
+	{
+	    /* Output empty string to paint background in the full width. */
+            ExtTextOutW( hdc, rect->left + 1, rect->top,
+                         ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+            TabbedTextOutW( hdc, rect->left + 1 , rect->top,
+                            item->str, strlenW(item->str),
+                            descr->nb_tabs, descr->tabs, 0);
+	}
+        if (item && item->selected)
+        {
+            SetBkColor( hdc, oldBk );
+            SetTextColor( hdc, oldText );
+        }
+        if (!ignoreFocus && (descr->focus_item == index) &&
+            (descr->caret_on) &&
+            (descr->in_focus)) DrawFocusRect( hdc, rect );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetRedraw
+ *
+ * Change the redraw flag.
+ */
+static void LISTBOX_SetRedraw( HWND hwnd, LB_DESCR *descr, BOOL on )
+{
+    if (on)
+    {
+        if (!(descr->style & LBS_NOREDRAW)) return;
+        descr->style &= ~LBS_NOREDRAW;
+        if (descr->style & LBS_DISPLAYCHANGED)
+        {     /* page was changed while setredraw false, refresh automatically */
+            InvalidateRect(hwnd, NULL, TRUE);
+            if ((descr->top_item + descr->page_size) > descr->nb_items)
+            {      /* reset top of page if less than number of items/page */
+                descr->top_item = descr->nb_items - descr->page_size;
+                if (descr->top_item < 0) descr->top_item = 0;
+            }
+            descr->style &= ~LBS_DISPLAYCHANGED;
+        }
+        LISTBOX_UpdateScroll( hwnd, descr );
+    }
+    else descr->style |= LBS_NOREDRAW;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_RepaintItem
+ *
+ * Repaint a single item synchronously.
+ */
+static void LISTBOX_RepaintItem( HWND hwnd, LB_DESCR *descr, INT index,
+                                 UINT action )
+{
+    HDC hdc;
+    RECT rect;
+    HFONT oldFont = 0;
+    HBRUSH hbrush, oldBrush = 0;
+
+    /* Do not repaint the item if the item is not visible */
+    if (!IsWindowVisible(hwnd)) return;
+    if (descr->style & LBS_NOREDRAW)
+    {
+       descr->style |= LBS_DISPLAYCHANGED;
+       return;
+    }
+    if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
+    if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) return;
+    if (descr->font) oldFont = SelectObject( hdc, descr->font );
+    hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+                             hdc, (LPARAM)hwnd );
+    if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+    if (!IsWindowEnabled(hwnd))
+        SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+    SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+    LISTBOX_PaintItem( hwnd, descr, hdc, &rect, index, action, FALSE );
+    if (oldFont) SelectObject( hdc, oldFont );
+    if (oldBrush) SelectObject( hdc, oldBrush );
+    ReleaseDC( hwnd, hdc );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InitStorage
+ */
+static LRESULT LISTBOX_InitStorage( HWND hwnd, LB_DESCR *descr, INT nb_items )
+{
+    LB_ITEMDATA *item;
+
+    nb_items += LB_ARRAY_GRANULARITY - 1;
+    nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
+    if (descr->items)
+        nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
+    if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+                              nb_items * sizeof(LB_ITEMDATA) )))
+    {
+        SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
+        return LB_ERRSPACE;
+    }
+    descr->items = item;
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetTabStops
+ */
+static BOOL LISTBOX_SetTabStops( HWND hwnd, LB_DESCR *descr, INT count,
+                                   LPINT tabs, BOOL short_ints )
+{
+    if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
+    if (descr->tabs) HeapFree( GetProcessHeap(), 0, descr->tabs );
+    if (!(descr->nb_tabs = count))
+    {
+        descr->tabs = NULL;
+        return TRUE;
+    }
+    /* FIXME: count = 1 */
+    if (!(descr->tabs = (INT *)HeapAlloc( GetProcessHeap(), 0,
+                                            descr->nb_tabs * sizeof(INT) )))
+        return FALSE;
+    if (short_ints)
+    {
+        INT i;
+        LPINT16 p = (LPINT16)tabs;
+
+        TRACE("[%04x]: settabstops ", hwnd );
+        for (i = 0; i < descr->nb_tabs; i++) {
+	    descr->tabs[i] = *p++<<1; /* FIXME */
+            if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
+	}
+        if (TRACE_ON(listbox)) DPRINTF("\n");
+    }
+    else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
+    /* FIXME: repaint the window? */
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetText
+ */
+static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPARAM lParam, BOOL unicode )
+{
+    if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+    if (HAS_STRINGS(descr))
+    {
+        if (!lParam)
+            return strlenW(descr->items[index].str);
+
+	TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
+
+        if(unicode)
+        {
+            LPWSTR buffer = (LPWSTR)lParam;
+            strcpyW( buffer, descr->items[index].str );
+            return strlenW(buffer);
+        }
+        else
+        {
+            LPSTR buffer = (LPSTR)lParam;
+            return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1;
+        }
+    } else {
+        if (lParam)
+            *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data);
+        return sizeof(DWORD);
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_FindStringPos
+ *
+ * Find the nearest string located before a given string in sort order.
+ * If 'exact' is TRUE, return an error if we don't get an exact match.
+ */
+static INT LISTBOX_FindStringPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str,
+                                    BOOL exact )
+{
+    INT index, min, max, res = -1;
+
+    if (!(descr->style & LBS_SORT)) return -1;  /* Add it at the end */
+    min = 0;
+    max = descr->nb_items;
+    while (min != max)
+    {
+        index = (min + max) / 2;
+        if (HAS_STRINGS(descr))
+            res = lstrcmpiW( descr->items[index].str, str );
+        else
+        {
+            COMPAREITEMSTRUCT cis;
+            UINT id = GetWindowLongA( hwnd, GWL_ID );
+
+            cis.CtlType    = ODT_LISTBOX;
+            cis.CtlID      = id;
+            cis.hwndItem   = hwnd;
+            cis.itemID1    = index;
+            cis.itemData1  = descr->items[index].data;
+            cis.itemID2    = -1;
+            cis.itemData2  = (DWORD)str;
+            cis.dwLocaleId = descr->locale;
+            res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
+        }
+        if (!res) return index;
+        if (res > 0) max = index;
+        else min = index + 1;
+    }
+    return exact ? -1 : max;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_FindFileStrPos
+ *
+ * Find the nearest string located before a given string in directory
+ * sort order (i.e. first files, then directories, then drives).
+ */
+static INT LISTBOX_FindFileStrPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str )
+{
+    INT min, max, res = -1;
+
+    if (!HAS_STRINGS(descr))
+        return LISTBOX_FindStringPos( hwnd, descr, str, FALSE );
+    min = 0;
+    max = descr->nb_items;
+    while (min != max)
+    {
+        INT index = (min + max) / 2;
+        LPCWSTR p = descr->items[index].str;
+        if (*p == '[')  /* drive or directory */
+        {
+            if (*str != '[') res = -1;
+            else if (p[1] == '-')  /* drive */
+            {
+                if (str[1] == '-') res = str[2] - p[2];
+                else res = -1;
+            }
+            else  /* directory */
+            {
+                if (str[1] == '-') res = 1;
+                else res = lstrcmpiW( str, p );
+            }
+        }
+        else  /* filename */
+        {
+            if (*str == '[') res = 1;
+            else res = lstrcmpiW( str, p );
+        }
+        if (!res) return index;
+        if (res < 0) max = index;
+        else min = index + 1;
+    }
+    return max;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_FindString
+ *
+ * Find the item beginning with a given string.
+ */
+static INT LISTBOX_FindString( HWND hwnd, LB_DESCR *descr, INT start,
+                                 LPCWSTR str, BOOL exact )
+{
+    INT i;
+    LB_ITEMDATA *item;
+
+    if (start >= descr->nb_items) start = -1;
+    item = descr->items + start + 1;
+    if (HAS_STRINGS(descr))
+    {
+        if (!str || ! str[0] ) return LB_ERR;
+        if (exact)
+        {
+            for (i = start + 1; i < descr->nb_items; i++, item++)
+                if (!lstrcmpiW( str, item->str )) return i;
+            for (i = 0, item = descr->items; i <= start; i++, item++)
+                if (!lstrcmpiW( str, item->str )) return i;
+        }
+        else
+        {
+ /* Special case for drives and directories: ignore prefix */
+#define CHECK_DRIVE(item) \
+    if ((item)->str[0] == '[') \
+    { \
+        if (!strncmpiW( str, (item)->str+1, len )) return i; \
+        if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
+        return i; \
+    }
+
+            INT len = strlenW(str);
+            for (i = start + 1; i < descr->nb_items; i++, item++)
+            {
+               if (!strncmpiW( str, item->str, len )) return i;
+               CHECK_DRIVE(item);
+            }
+            for (i = 0, item = descr->items; i <= start; i++, item++)
+            {
+               if (!strncmpiW( str, item->str, len )) return i;
+               CHECK_DRIVE(item);
+            }
+#undef CHECK_DRIVE
+        }
+    }
+    else
+    {
+        if (exact && (descr->style & LBS_SORT))
+            /* If sorted, use a WM_COMPAREITEM binary search */
+            return LISTBOX_FindStringPos( hwnd, descr, str, TRUE );
+
+        /* Otherwise use a linear search */
+        for (i = start + 1; i < descr->nb_items; i++, item++)
+            if (item->data == (DWORD)str) return i;
+        for (i = 0, item = descr->items; i <= start; i++, item++)
+            if (item->data == (DWORD)str) return i;
+    }
+    return LB_ERR;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetSelCount
+ */
+static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
+{
+    INT i, count;
+    LB_ITEMDATA *item = descr->items;
+
+    if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+    for (i = count = 0; i < descr->nb_items; i++, item++)
+        if (item->selected) count++;
+    return count;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetSelItems16
+ */
+static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
+{
+    INT i, count;
+    LB_ITEMDATA *item = descr->items;
+
+    if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+    for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
+        if (item->selected) array[count++] = (INT16)i;
+    return count;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetSelItems
+ */
+static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
+{
+    INT i, count;
+    LB_ITEMDATA *item = descr->items;
+
+    if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+    for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
+        if (item->selected) array[count++] = i;
+    return count;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Paint
+ */
+static LRESULT LISTBOX_Paint( HWND hwnd, LB_DESCR *descr, HDC hdc )
+{
+    INT i, col_pos = descr->page_size - 1;
+    RECT rect;
+    RECT focusRect = {-1, -1, -1, -1};
+    HFONT oldFont = 0;
+    HBRUSH hbrush, oldBrush = 0;
+
+    if (descr->style & LBS_NOREDRAW) return 0;
+
+    SetRect( &rect, 0, 0, descr->width, descr->height );
+    if (descr->style & LBS_MULTICOLUMN)
+        rect.right = rect.left + descr->column_width;
+    else if (descr->horz_pos)
+    {
+        SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+        rect.right += descr->horz_pos;
+    }
+
+    if (descr->font) oldFont = SelectObject( hdc, descr->font );
+    hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+                             hdc, (LPARAM)hwnd );
+    if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+    if (!IsWindowEnabled(hwnd)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+
+    if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
+        (descr->in_focus))
+    {
+        /* Special case for empty listbox: paint focus rect */
+        rect.bottom = rect.top + descr->item_height;
+        LISTBOX_PaintItem( hwnd, descr, hdc, &rect, descr->focus_item,
+                           ODA_FOCUS, FALSE );
+        rect.top = rect.bottom;
+    }
+
+    /* Paint all the item, regarding the selection
+       Focus state will be painted after  */
+
+    for (i = descr->top_item; i < descr->nb_items; i++)
+    {
+        if (!(descr->style & LBS_OWNERDRAWVARIABLE))
+            rect.bottom = rect.top + descr->item_height;
+        else
+            rect.bottom = rect.top + descr->items[i].height;
+
+        if (i == descr->focus_item)
+        {
+	    /* keep the focus rect, to paint the focus item after */
+	    focusRect.left = rect.left;
+	    focusRect.right = rect.right;
+	    focusRect.top = rect.top;
+	    focusRect.bottom = rect.bottom;
+        }
+        LISTBOX_PaintItem( hwnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
+        rect.top = rect.bottom;
+
+        if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
+        {
+            if (!IS_OWNERDRAW(descr))
+            {
+                /* Clear the bottom of the column */
+                if (rect.top < descr->height)
+                {
+                    rect.bottom = descr->height;
+                    ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+                                   &rect, NULL, 0, NULL );
+                }
+            }
+
+            /* Go to the next column */
+            rect.left += descr->column_width;
+            rect.right += descr->column_width;
+            rect.top = 0;
+            col_pos = descr->page_size - 1;
+        }
+        else
+        {
+            col_pos--;
+            if (rect.top >= descr->height) break;
+        }
+    }
+
+    /* Paint the focus item now */
+    if (focusRect.top != focusRect.bottom && descr->caret_on)
+        LISTBOX_PaintItem( hwnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
+
+    if (!IS_OWNERDRAW(descr))
+    {
+        /* Clear the remainder of the client area */
+        if (rect.top < descr->height)
+        {
+            rect.bottom = descr->height;
+            ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+                           &rect, NULL, 0, NULL );
+        }
+        if (rect.right < descr->width)
+        {
+            rect.left   = rect.right;
+            rect.right  = descr->width;
+            rect.top    = 0;
+            rect.bottom = descr->height;
+            ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+                           &rect, NULL, 0, NULL );
+        }
+    }
+    if (oldFont) SelectObject( hdc, oldFont );
+    if (oldBrush) SelectObject( hdc, oldBrush );
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InvalidateItems
+ *
+ * Invalidate all items from a given item. If the specified item is not
+ * visible, nothing happens.
+ */
+static void LISTBOX_InvalidateItems( HWND hwnd, LB_DESCR *descr, INT index )
+{
+    RECT rect;
+
+    if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
+    {
+        if (descr->style & LBS_NOREDRAW)
+        {
+            descr->style |= LBS_DISPLAYCHANGED;
+            return;
+        }
+        rect.bottom = descr->height;
+        InvalidateRect( hwnd, &rect, TRUE );
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            /* Repaint the other columns */
+            rect.left  = rect.right;
+            rect.right = descr->width;
+            rect.top   = 0;
+            InvalidateRect( hwnd, &rect, TRUE );
+        }
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetItemHeight
+ */
+static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
+{
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+        return descr->items[index].height;
+    }
+    else return descr->item_height;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetItemHeight
+ */
+static LRESULT LISTBOX_SetItemHeight( HWND hwnd, LB_DESCR *descr, INT index,
+                                      INT height, BOOL repaint )
+{
+    if (!height) height = 1;
+
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+        TRACE("[%04x]: item %d height = %d\n", hwnd, index, height );
+        descr->items[index].height = height;
+        LISTBOX_UpdateScroll( hwnd, descr );
+	if (repaint)
+	    LISTBOX_InvalidateItems( hwnd, descr, index );
+    }
+    else if (height != descr->item_height)
+    {
+        TRACE("[%04x]: new height = %d\n", hwnd, height );
+        descr->item_height = height;
+        LISTBOX_UpdatePage( hwnd, descr );
+        LISTBOX_UpdateScroll( hwnd, descr );
+	if (repaint)
+	    InvalidateRect( hwnd, 0, TRUE );
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetHorizontalPos
+ */
+static void LISTBOX_SetHorizontalPos( HWND hwnd, LB_DESCR *descr, INT pos )
+{
+    INT diff;
+
+    if (pos > descr->horz_extent - descr->width)
+        pos = descr->horz_extent - descr->width;
+    if (pos < 0) pos = 0;
+    if (!(diff = descr->horz_pos - pos)) return;
+    TRACE("[%04x]: new horz pos = %d\n", hwnd, pos );
+    descr->horz_pos = pos;
+    LISTBOX_UpdateScroll( hwnd, descr );
+    if (abs(diff) < descr->width)
+        ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
+                          SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+    else
+        InvalidateRect( hwnd, NULL, TRUE );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetHorizontalExtent
+ */
+static LRESULT LISTBOX_SetHorizontalExtent( HWND hwnd, LB_DESCR *descr,
+                                            INT extent )
+{
+    if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
+        return LB_OKAY;
+    if (extent <= 0) extent = 1;
+    if (extent == descr->horz_extent) return LB_OKAY;
+    TRACE("[%04x]: new horz extent = %d\n", hwnd, extent );
+    descr->horz_extent = extent;
+    if (descr->horz_pos > extent - descr->width)
+        LISTBOX_SetHorizontalPos( hwnd, descr, extent - descr->width );
+    else
+        LISTBOX_UpdateScroll( hwnd, descr );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetColumnWidth
+ */
+static LRESULT LISTBOX_SetColumnWidth( HWND hwnd, LB_DESCR *descr, INT width)
+{
+    if (width == descr->column_width) return LB_OKAY;
+    TRACE("[%04x]: new column width = %d\n", hwnd, width );
+    descr->column_width = width;
+    LISTBOX_UpdatePage( hwnd, descr );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetFont
+ *
+ * Returns the item height.
+ */
+static INT LISTBOX_SetFont( HWND hwnd, LB_DESCR *descr, HFONT font )
+{
+    HDC hdc;
+    HFONT oldFont = 0;
+    TEXTMETRICW tm;
+
+    descr->font = font;
+
+    if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE )))
+    {
+        ERR("unable to get DC.\n" );
+        return 16;
+    }
+    if (font) oldFont = SelectObject( hdc, font );
+    GetTextMetricsW( hdc, &tm );
+    if (oldFont) SelectObject( hdc, oldFont );
+    ReleaseDC( hwnd, hdc );
+    if (!IS_OWNERDRAW(descr))
+        LISTBOX_SetItemHeight( hwnd, descr, 0, tm.tmHeight, FALSE );
+    return tm.tmHeight ;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_MakeItemVisible
+ *
+ * Make sure that a given item is partially or fully visible.
+ */
+static void LISTBOX_MakeItemVisible( HWND hwnd, LB_DESCR *descr, INT index,
+                                     BOOL fully )
+{
+    INT top;
+
+    if (index <= descr->top_item) top = index;
+    else if (descr->style & LBS_MULTICOLUMN)
+    {
+        INT cols = descr->width;
+        if (!fully) cols += descr->column_width - 1;
+        if (cols >= descr->column_width) cols /= descr->column_width;
+        else cols = 1;
+        if (index < descr->top_item + (descr->page_size * cols)) return;
+        top = index - descr->page_size * (cols - 1);
+    }
+    else if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        INT height = fully ? descr->items[index].height : 1;
+        for (top = index; top > descr->top_item; top--)
+            if ((height += descr->items[top-1].height) > descr->height) break;
+    }
+    else
+    {
+        if (index < descr->top_item + descr->page_size) return;
+        if (!fully && (index == descr->top_item + descr->page_size) &&
+            (descr->height > (descr->page_size * descr->item_height))) return;
+        top = index - descr->page_size + 1;
+    }
+    LISTBOX_SetTopItem( hwnd, descr, top, TRUE );
+}
+
+/***********************************************************************
+ *           LISTBOX_SetCaretIndex
+ *
+ * NOTES
+ *   index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
+ *
+ */
+static LRESULT LISTBOX_SetCaretIndex( HWND hwnd, LB_DESCR *descr, INT index,
+                                      BOOL fully_visible )
+{
+    INT oldfocus = descr->focus_item;
+
+    if (descr->style & LBS_NOSEL) return LB_ERR;
+    if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+    if (index == oldfocus) return LB_OKAY;
+    descr->focus_item = index;
+    if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
+        LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
+
+    LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
+    if (descr->caret_on && (descr->in_focus))
+        LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
+
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SelectItemRange
+ *
+ * Select a range of items. Should only be used on a MULTIPLESEL listbox.
+ */
+static LRESULT LISTBOX_SelectItemRange( HWND hwnd, LB_DESCR *descr, INT first,
+                                        INT last, BOOL on )
+{
+    INT i;
+
+    /* A few sanity checks */
+
+    if (descr->style & LBS_NOSEL) return LB_ERR;
+    if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
+    if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+    if (last == -1) last = descr->nb_items - 1;
+    if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
+    if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
+    /* selected_item reflects last selected/unselected item on multiple sel */
+    descr->selected_item = last;
+
+    if (on)  /* Turn selection on */
+    {
+        for (i = first; i <= last; i++)
+        {
+            if (descr->items[i].selected) continue;
+            descr->items[i].selected = TRUE;
+            LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
+        }
+        LISTBOX_SetCaretIndex( hwnd, descr, last, TRUE );
+    }
+    else  /* Turn selection off */
+    {
+        for (i = first; i <= last; i++)
+        {
+            if (!descr->items[i].selected) continue;
+            descr->items[i].selected = FALSE;
+            LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
+        }
+    }
+    return LB_OKAY;
+}
+
+/***********************************************************************
+ *           LISTBOX_SetSelection
+ */
+static LRESULT LISTBOX_SetSelection( HWND hwnd, LB_DESCR *descr, INT index,
+                                     BOOL on, BOOL send_notify )
+{
+    TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
+
+    if (descr->style & LBS_NOSEL) return LB_ERR;
+    if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
+    if (descr->style & LBS_MULTIPLESEL)
+    {
+        if (index == -1)  /* Select all items */
+            return LISTBOX_SelectItemRange( hwnd, descr, 0, -1, on );
+        else  /* Only one item */
+            return LISTBOX_SelectItemRange( hwnd, descr, index, index, on );
+    }
+    else
+    {
+        INT oldsel = descr->selected_item;
+        if (index == oldsel) return LB_OKAY;
+        if (oldsel != -1) descr->items[oldsel].selected = FALSE;
+        if (index != -1) descr->items[index].selected = TRUE;
+        descr->selected_item = index;
+        if (oldsel != -1) LISTBOX_RepaintItem( hwnd, descr, oldsel, ODA_SELECT );
+        if (index != -1) LISTBOX_RepaintItem( hwnd, descr, index, ODA_SELECT );
+        if (send_notify && descr->nb_items) SEND_NOTIFICATION( hwnd, descr,
+                               (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
+	else
+	    if( descr->lphc ) /* set selection change flag for parent combo */
+		descr->lphc->wState |= CBF_SELCHANGE;
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_MoveCaret
+ *
+ * Change the caret position and extend the selection to the new caret.
+ */
+static void LISTBOX_MoveCaret( HWND hwnd, LB_DESCR *descr, INT index,
+                               BOOL fully_visible )
+{
+    INT oldfocus = descr->focus_item;
+
+    if ((index <  0) || (index >= descr->nb_items))
+        return;
+
+    /* Important, repaint needs to be done in this order if
+       you want to mimic Windows behavior:
+       1. Remove the focus and paint the item
+       2. Remove the selection and paint the item(s)
+       3. Set the selection and repaint the item(s)
+       4. Set the focus to 'index' and repaint the item */
+
+    /* 1. remove the focus and repaint the item */
+    descr->focus_item = -1;
+    if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
+        LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
+
+    /* 2. then turn off the previous selection */
+    /* 3. repaint the new selected item */
+    if (descr->style & LBS_EXTENDEDSEL)
+    {
+        if (descr->anchor_item != -1)
+        {
+            INT first = min( index, descr->anchor_item );
+            INT last  = max( index, descr->anchor_item );
+            if (first > 0)
+                LISTBOX_SelectItemRange( hwnd, descr, 0, first - 1, FALSE );
+            LISTBOX_SelectItemRange( hwnd, descr, last + 1, -1, FALSE );
+            LISTBOX_SelectItemRange( hwnd, descr, first, last, TRUE );
+        }
+    }
+    else if (!(descr->style & LBS_MULTIPLESEL))
+    {
+        /* Set selection to new caret item */
+        LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
+    }
+
+    /* 4. repaint the new item with the focus */
+    descr->focus_item = index;
+    LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
+    if (descr->caret_on && (descr->in_focus))
+        LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InsertItem
+ */
+static LRESULT LISTBOX_InsertItem( HWND hwnd, LB_DESCR *descr, INT index,
+                                   LPWSTR str, DWORD data )
+{
+    LB_ITEMDATA *item;
+    INT max_items;
+    INT oldfocus = descr->focus_item;
+
+    if (index == -1) index = descr->nb_items;
+    else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
+    if (!descr->items) max_items = 0;
+    else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
+    if (descr->nb_items == max_items)
+    {
+        /* We need to grow the array */
+        max_items += LB_ARRAY_GRANULARITY;
+        if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+                                  max_items * sizeof(LB_ITEMDATA) )))
+        {
+            SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
+            return LB_ERRSPACE;
+        }
+        descr->items = item;
+    }
+
+    /* Insert the item structure */
+
+    item = &descr->items[index];
+    if (index < descr->nb_items)
+        RtlMoveMemory( item + 1, item,
+                       (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
+    item->str      = str;
+    item->data     = data;
+    item->height   = 0;
+    item->selected = FALSE;
+    descr->nb_items++;
+
+    /* Get item height */
+
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        MEASUREITEMSTRUCT mis;
+        UINT id = GetWindowLongA( hwnd, GWL_ID );
+
+        mis.CtlType    = ODT_LISTBOX;
+        mis.CtlID      = id;
+        mis.itemID     = index;
+        mis.itemData   = descr->items[index].data;
+        mis.itemHeight = descr->item_height;
+        SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+        item->height = mis.itemHeight ? mis.itemHeight : 1;
+        TRACE("[%04x]: measure item %d (%s) = %d\n",
+              hwnd, index, str ? debugstr_w(str) : "", item->height );
+    }
+
+    /* Repaint the items */
+
+    LISTBOX_UpdateScroll( hwnd, descr );
+    LISTBOX_InvalidateItems( hwnd, descr, index );
+
+    /* Move selection and focused item */
+    /* If listbox was empty, set focus to the first item */
+    if (descr->nb_items == 1)
+         LISTBOX_SetCaretIndex( hwnd, descr, 0, FALSE );
+    /* single select don't change selection index in win31 */
+    else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
+    {
+        descr->selected_item++;
+        LISTBOX_SetSelection( hwnd, descr, descr->selected_item-1, TRUE, FALSE );
+    }
+    else
+    {
+        if (index <= descr->selected_item)
+        {
+           descr->selected_item++;
+           descr->focus_item = oldfocus; /* focus not changed */
+        }
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InsertString
+ */
+static LRESULT LISTBOX_InsertString( HWND hwnd, LB_DESCR *descr, INT index,
+                                     LPCWSTR str )
+{
+    LPWSTR new_str = NULL;
+    DWORD data = 0;
+    LRESULT ret;
+
+    if (HAS_STRINGS(descr))
+    {
+        static const WCHAR empty_stringW[] = { 0 };
+        if (!str) str = empty_stringW;
+        if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
+        {
+            SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
+            return LB_ERRSPACE;
+        }
+        strcpyW(new_str, str);
+    }
+    else data = (DWORD)str;
+
+    if (index == -1) index = descr->nb_items;
+    if ((ret = LISTBOX_InsertItem( hwnd, descr, index, new_str, data )) != 0)
+    {
+        if (new_str) HeapFree( GetProcessHeap(), 0, new_str );
+        return ret;
+    }
+
+    TRACE("[%04x]: added item %d %s\n",
+          hwnd, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
+    return index;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_DeleteItem
+ *
+ * Delete the content of an item. 'index' must be a valid index.
+ */
+static void LISTBOX_DeleteItem( HWND hwnd, LB_DESCR *descr, INT index )
+{
+    /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
+     *       while Win95 sends it for all items with user data.
+     *       It's probably better to send it too often than not
+     *       often enough, so this is what we do here.
+     */
+    if (IS_OWNERDRAW(descr) || descr->items[index].data)
+    {
+        DELETEITEMSTRUCT dis;
+        UINT id = GetWindowLongA( hwnd, GWL_ID );
+
+        dis.CtlType  = ODT_LISTBOX;
+        dis.CtlID    = id;
+        dis.itemID   = index;
+        dis.hwndItem = hwnd;
+        dis.itemData = descr->items[index].data;
+        SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
+    }
+    if (HAS_STRINGS(descr) && descr->items[index].str)
+        HeapFree( GetProcessHeap(), 0, descr->items[index].str );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_RemoveItem
+ *
+ * Remove an item from the listbox and delete its content.
+ */
+static LRESULT LISTBOX_RemoveItem( HWND hwnd, LB_DESCR *descr, INT index )
+{
+    LB_ITEMDATA *item;
+    INT max_items;
+
+    if ((index == -1) && (descr->nb_items > 0)) index = descr->nb_items - 1;
+    else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+
+    /* We need to invalidate the original rect instead of the updated one. */
+    LISTBOX_InvalidateItems( hwnd, descr, index );
+
+    LISTBOX_DeleteItem( hwnd, descr, index );
+
+    /* Remove the item */
+
+    item = &descr->items[index];
+    if (index < descr->nb_items-1)
+        RtlMoveMemory( item, item + 1,
+                       (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
+    descr->nb_items--;
+    if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
+
+    /* Shrink the item array if possible */
+
+    max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
+    if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
+    {
+        max_items -= LB_ARRAY_GRANULARITY;
+        item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+                            max_items * sizeof(LB_ITEMDATA) );
+        if (item) descr->items = item;
+    }
+    /* Repaint the items */
+
+    LISTBOX_UpdateScroll( hwnd, descr );
+    /* if we removed the scrollbar, reset the top of the list
+      (correct for owner-drawn ???) */
+    if (descr->nb_items == descr->page_size)
+        LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
+
+    /* Move selection and focused item */
+    if (!IS_MULTISELECT(descr))
+    {
+        if (index == descr->selected_item)
+            descr->selected_item = -1;
+        else if (index < descr->selected_item)
+    {
+            descr->selected_item--;
+            if (ISWIN31) /* win 31 do not change the selected item number */
+               LISTBOX_SetSelection( hwnd, descr, descr->selected_item + 1, TRUE, FALSE);
+    }
+    }
+
+    if (descr->focus_item >= descr->nb_items)
+    {
+          descr->focus_item = descr->nb_items - 1;
+          if (descr->focus_item < 0) descr->focus_item = 0;
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_ResetContent
+ */
+static void LISTBOX_ResetContent( HWND hwnd, LB_DESCR *descr )
+{
+    INT i;
+
+    for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( hwnd, descr, i );
+    if (descr->items) HeapFree( GetProcessHeap(), 0, descr->items );
+    descr->nb_items      = 0;
+    descr->top_item      = 0;
+    descr->selected_item = -1;
+    descr->focus_item    = 0;
+    descr->anchor_item   = -1;
+    descr->items         = NULL;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetCount
+ */
+static LRESULT LISTBOX_SetCount( HWND hwnd, LB_DESCR *descr, INT count )
+{
+    LRESULT ret;
+
+    if (HAS_STRINGS(descr)) return LB_ERR;
+    /* FIXME: this is far from optimal... */
+    if (count > descr->nb_items)
+    {
+        while (count > descr->nb_items)
+            if ((ret = LISTBOX_InsertString( hwnd, descr, -1, 0 )) < 0)
+                return ret;
+    }
+    else if (count < descr->nb_items)
+    {
+        while (count < descr->nb_items)
+            if ((ret = LISTBOX_RemoveItem( hwnd, descr, -1 )) < 0)
+                return ret;
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Directory
+ */
+static LRESULT LISTBOX_Directory( HWND hwnd, LB_DESCR *descr, UINT attrib,
+                                  LPCWSTR filespec, BOOL long_names )
+{
+    HANDLE handle;
+    LRESULT ret = LB_OKAY;
+    WIN32_FIND_DATAW entry;
+    int pos;
+
+    /* don't scan directory if we just want drives exclusively */
+    if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
+        /* scan directory */
+        if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
+        {
+            if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
+        }
+        else
+        {
+            do
+            {
+                WCHAR buffer[270];
+                if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                {
+                    static const WCHAR bracketW[]  = { ']',0 };
+                    static const WCHAR dotW[] = { '.',0 };
+                    if (!(attrib & DDL_DIRECTORY) ||
+                        !strcmpW( entry.cAlternateFileName, dotW )) continue;
+                    buffer[0] = '[';
+                    if (long_names) strcpyW( buffer + 1, entry.cFileName );
+                    else strcpyW( buffer + 1, entry.cAlternateFileName );
+                    strcatW(buffer, bracketW);
+                }
+                else  /* not a directory */
+                {
+#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
+                 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
+
+                    if ((attrib & DDL_EXCLUSIVE) &&
+                        ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
+                        continue;
+#undef ATTRIBS
+                    if (long_names) strcpyW( buffer, entry.cFileName );
+                    else strcpyW( buffer, entry.cAlternateFileName );
+                }
+                if (!long_names) CharLowerW( buffer );
+                pos = LISTBOX_FindFileStrPos( hwnd, descr, buffer );
+                if ((ret = LISTBOX_InsertString( hwnd, descr, pos, buffer )) < 0)
+                    break;
+            } while (FindNextFileW( handle, &entry ));
+            FindClose( handle );
+        }
+    }
+
+    /* scan drives */
+    if ((ret >= 0) && (attrib & DDL_DRIVES))
+    {
+        WCHAR buffer[] = {'[','-','a','-',']',0};
+        WCHAR root[] = {'A',':','\\',0};
+        int drive;
+        for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
+        {
+            if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
+            if ((ret = LISTBOX_InsertString( hwnd, descr, -1, buffer )) < 0)
+                break;
+        }
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleVScroll
+ */
+static LRESULT LISTBOX_HandleVScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
+{
+    SCROLLINFO info;
+
+    if (descr->style & LBS_MULTICOLUMN) return 0;
+    switch(LOWORD(wParam))
+    {
+    case SB_LINEUP:
+        LISTBOX_SetTopItem( hwnd, descr, descr->top_item - 1, TRUE );
+        break;
+    case SB_LINEDOWN:
+        LISTBOX_SetTopItem( hwnd, descr, descr->top_item + 1, TRUE );
+        break;
+    case SB_PAGEUP:
+        LISTBOX_SetTopItem( hwnd, descr, descr->top_item -
+                            LISTBOX_GetCurrentPageSize( descr ), TRUE );
+        break;
+    case SB_PAGEDOWN:
+        LISTBOX_SetTopItem( hwnd, descr, descr->top_item +
+                            LISTBOX_GetCurrentPageSize( descr ), TRUE );
+        break;
+    case SB_THUMBPOSITION:
+        LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam), TRUE );
+        break;
+    case SB_THUMBTRACK:
+        info.cbSize = sizeof(info);
+        info.fMask = SIF_TRACKPOS;
+        GetScrollInfo( hwnd, SB_VERT, &info );
+        LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos, TRUE );
+        break;
+    case SB_TOP:
+        LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
+        break;
+    case SB_BOTTOM:
+        LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
+        break;
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleHScroll
+ */
+static LRESULT LISTBOX_HandleHScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
+{
+    SCROLLINFO info;
+    INT page;
+
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        switch(LOWORD(wParam))
+        {
+        case SB_LINELEFT:
+            LISTBOX_SetTopItem( hwnd, descr, descr->top_item-descr->page_size,
+                                TRUE );
+            break;
+        case SB_LINERIGHT:
+            LISTBOX_SetTopItem( hwnd, descr, descr->top_item+descr->page_size,
+                                TRUE );
+            break;
+        case SB_PAGELEFT:
+            page = descr->width / descr->column_width;
+            if (page < 1) page = 1;
+            LISTBOX_SetTopItem( hwnd, descr,
+                             descr->top_item - page * descr->page_size, TRUE );
+            break;
+        case SB_PAGERIGHT:
+            page = descr->width / descr->column_width;
+            if (page < 1) page = 1;
+            LISTBOX_SetTopItem( hwnd, descr,
+                             descr->top_item + page * descr->page_size, TRUE );
+            break;
+        case SB_THUMBPOSITION:
+            LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam)*descr->page_size,
+                                TRUE );
+            break;
+        case SB_THUMBTRACK:
+            info.cbSize = sizeof(info);
+            info.fMask  = SIF_TRACKPOS;
+            GetScrollInfo( hwnd, SB_VERT, &info );
+            LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos*descr->page_size,
+                                TRUE );
+            break;
+        case SB_LEFT:
+            LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
+            break;
+        case SB_RIGHT:
+            LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
+            break;
+        }
+    }
+    else if (descr->horz_extent)
+    {
+        switch(LOWORD(wParam))
+        {
+        case SB_LINELEFT:
+            LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos - 1 );
+            break;
+        case SB_LINERIGHT:
+            LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos + 1 );
+            break;
+        case SB_PAGELEFT:
+            LISTBOX_SetHorizontalPos( hwnd, descr,
+                                      descr->horz_pos - descr->width );
+            break;
+        case SB_PAGERIGHT:
+            LISTBOX_SetHorizontalPos( hwnd, descr,
+                                      descr->horz_pos + descr->width );
+            break;
+        case SB_THUMBPOSITION:
+            LISTBOX_SetHorizontalPos( hwnd, descr, HIWORD(wParam) );
+            break;
+        case SB_THUMBTRACK:
+            info.cbSize = sizeof(info);
+            info.fMask = SIF_TRACKPOS;
+            GetScrollInfo( hwnd, SB_HORZ, &info );
+            LISTBOX_SetHorizontalPos( hwnd, descr, info.nTrackPos );
+            break;
+        case SB_LEFT:
+            LISTBOX_SetHorizontalPos( hwnd, descr, 0 );
+            break;
+        case SB_RIGHT:
+            LISTBOX_SetHorizontalPos( hwnd, descr,
+                                      descr->horz_extent - descr->width );
+            break;
+        }
+    }
+    return 0;
+}
+
+static LRESULT LISTBOX_HandleMouseWheel(HWND hwnd, LB_DESCR *descr, WPARAM wParam )
+{
+    short gcWheelDelta = 0;
+    UINT pulScrollLines = 3;
+
+    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+
+    gcWheelDelta -= (short) HIWORD(wParam);
+
+    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
+    {
+        int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
+        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
+        LISTBOX_SetTopItem( hwnd, descr, descr->top_item + cLineScroll, TRUE );
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           LISTBOX_HandleLButtonDown
+ */
+static LRESULT LISTBOX_HandleLButtonDown( HWND hwnd, LB_DESCR *descr,
+                                          WPARAM wParam, INT x, INT y )
+{
+    INT index = LISTBOX_GetItemFromPoint( descr, x, y );
+    TRACE("[%04x]: lbuttondown %d,%d item %d\n", hwnd, x, y, index );
+    if (!descr->caret_on && (descr->in_focus)) return 0;
+
+    if (!descr->in_focus)
+    {
+        if( !descr->lphc ) SetFocus( hwnd );
+        else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
+    }
+
+    if (index == -1) return 0;
+
+    if (descr->style & LBS_EXTENDEDSEL)
+    {
+        /* we should perhaps make sure that all items are deselected
+           FIXME: needed for !LBS_EXTENDEDSEL, too ?
+           if (!(wParam & (MK_SHIFT|MK_CONTROL)))
+           LISTBOX_SetSelection( hwnd, descr, -1, FALSE, FALSE);
+        */
+
+        if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
+        if (wParam & MK_CONTROL)
+        {
+            LISTBOX_SetCaretIndex( hwnd, descr, index, FALSE );
+            LISTBOX_SetSelection( hwnd, descr, index,
+                                  !descr->items[index].selected,
+                                  (descr->style & LBS_NOTIFY) != 0);
+        }
+        else LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
+    }
+    else
+    {
+        LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
+        LISTBOX_SetSelection( hwnd, descr, index,
+                              (!(descr->style & LBS_MULTIPLESEL) ||
+                               !descr->items[index].selected),
+                              (descr->style & LBS_NOTIFY) != 0 );
+    }
+
+    descr->captured = TRUE;
+    SetCapture( hwnd );
+
+    if (!descr->lphc)
+    {
+        if (descr->style & LBS_NOTIFY )
+            SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
+                            MAKELPARAM( x, y ) );
+        if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
+        {
+            POINT pt;
+
+	    pt.x = x;
+	    pt.y = y;
+
+            if (DragDetect( hwnd, pt ))
+                SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
+        }
+    }
+    return 0;
+}
+
+
+/*************************************************************************
+ * LISTBOX_HandleLButtonDownCombo [Internal]
+ *
+ * Process LButtonDown message for the ComboListBox
+ *
+nn * PARAMS
+ *     pWnd       [I] The windows internal structure
+ *     pDescr     [I] The ListBox internal structure
+ *     wParam     [I] Key Flag (WM_LBUTTONDOWN doc for more info)
+ *     x          [I] X Mouse Coordinate
+ *     y          [I] Y Mouse Coordinate
+ *
+ * RETURNS
+ *     0 since we are processing the WM_LBUTTONDOWN Message
+ *
+ * NOTES
+ *  This function is only to be used when a ListBox is a ComboListBox
+ */
+
+static LRESULT LISTBOX_HandleLButtonDownCombo( HWND hwnd, LB_DESCR *pDescr,
+                                               UINT msg, WPARAM wParam, INT x, INT y)
+{
+    RECT clientRect, screenRect;
+    POINT mousePos;
+
+    mousePos.x = x;
+    mousePos.y = y;
+
+    GetClientRect(hwnd, &clientRect);
+
+    if(PtInRect(&clientRect, mousePos))
+    {
+       /* MousePos is in client, resume normal processing */
+        if (msg == WM_LBUTTONDOWN)
+        {
+           pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
+           return LISTBOX_HandleLButtonDown( hwnd, pDescr, wParam, x, y);
+        }
+        else if (pDescr->style & LBS_NOTIFY)
+            SEND_NOTIFICATION( hwnd, pDescr, LBN_DBLCLK );
+        return 0;
+    }
+    else
+    {
+        POINT screenMousePos;
+        HWND hWndOldCapture;
+
+        /* Check the Non-Client Area */
+        screenMousePos = mousePos;
+        hWndOldCapture = GetCapture();
+        ReleaseCapture();
+        GetWindowRect(hwnd, &screenRect);
+        ClientToScreen(hwnd, &screenMousePos);
+
+        if(!PtInRect(&screenRect, screenMousePos))
+        {
+            LISTBOX_SetCaretIndex( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE );
+            LISTBOX_SetSelection( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
+            COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
+            return 0;
+        }
+        else
+        {
+            /* Check to see the NC is a scrollbar */
+            INT nHitTestType=0;
+            LONG style = GetWindowLongA( hwnd, GWL_STYLE );
+            /* Check Vertical scroll bar */
+            if (style & WS_VSCROLL)
+            {
+                clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
+                if (PtInRect( &clientRect, mousePos ))
+                {
+                    nHitTestType = HTVSCROLL;
+                }
+            }
+              /* Check horizontal scroll bar */
+            if (style & WS_HSCROLL)
+            {
+                clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
+                if (PtInRect( &clientRect, mousePos ))
+                {
+                    nHitTestType = HTHSCROLL;
+                }
+            }
+            /* Windows sends this message when a scrollbar is clicked
+             */
+
+            if(nHitTestType != 0)
+            {
+                SendMessageW(hwnd, WM_NCLBUTTONDOWN, nHitTestType,
+                    MAKELONG(screenMousePos.x, screenMousePos.y));
+            }
+            /* Resume the Capture after scrolling is complete
+             */
+            if(hWndOldCapture != 0)
+            {
+                SetCapture(hWndOldCapture);
+            }
+        }
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           LISTBOX_HandleLButtonUp
+ */
+static LRESULT LISTBOX_HandleLButtonUp( HWND hwnd, LB_DESCR *descr )
+{
+    if (LISTBOX_Timer != LB_TIMER_NONE)
+        KillSystemTimer( hwnd, LB_TIMER_ID );
+    LISTBOX_Timer = LB_TIMER_NONE;
+    if (descr->captured)
+    {
+        descr->captured = FALSE;
+        if (GetCapture() == hwnd) ReleaseCapture();
+        if ((descr->style & LBS_NOTIFY) && descr->nb_items)
+            SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleTimer
+ *
+ * Handle scrolling upon a timer event.
+ * Return TRUE if scrolling should continue.
+ */
+static LRESULT LISTBOX_HandleTimer( HWND hwnd, LB_DESCR *descr,
+                                    INT index, TIMER_DIRECTION dir )
+{
+    switch(dir)
+    {
+    case LB_TIMER_UP:
+        if (descr->top_item) index = descr->top_item - 1;
+        else index = 0;
+        break;
+    case LB_TIMER_LEFT:
+        if (descr->top_item) index -= descr->page_size;
+        break;
+    case LB_TIMER_DOWN:
+        index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
+        if (index == descr->focus_item) index++;
+        if (index >= descr->nb_items) index = descr->nb_items - 1;
+        break;
+    case LB_TIMER_RIGHT:
+        if (index + descr->page_size < descr->nb_items)
+            index += descr->page_size;
+        break;
+    case LB_TIMER_NONE:
+        break;
+    }
+    if (index == descr->focus_item) return FALSE;
+    LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleSystemTimer
+ *
+ * WM_SYSTIMER handler.
+ */
+static LRESULT LISTBOX_HandleSystemTimer( HWND hwnd, LB_DESCR *descr )
+{
+    if (!LISTBOX_HandleTimer( hwnd, descr, descr->focus_item, LISTBOX_Timer ))
+    {
+        KillSystemTimer( hwnd, LB_TIMER_ID );
+        LISTBOX_Timer = LB_TIMER_NONE;
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleMouseMove
+ *
+ * WM_MOUSEMOVE handler.
+ */
+static void LISTBOX_HandleMouseMove( HWND hwnd, LB_DESCR *descr,
+                                     INT x, INT y )
+{
+    INT index;
+    TIMER_DIRECTION dir = LB_TIMER_NONE;
+
+    if (!descr->captured) return;
+
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        if (y < 0) y = 0;
+        else if (y >= descr->item_height * descr->page_size)
+            y = descr->item_height * descr->page_size - 1;
+
+        if (x < 0)
+        {
+            dir = LB_TIMER_LEFT;
+            x = 0;
+        }
+        else if (x >= descr->width)
+        {
+            dir = LB_TIMER_RIGHT;
+            x = descr->width - 1;
+        }
+    }
+    else
+    {
+        if (y < 0) dir = LB_TIMER_UP;  /* above */
+        else if (y >= descr->height) dir = LB_TIMER_DOWN;  /* below */
+    }
+
+    index = LISTBOX_GetItemFromPoint( descr, x, y );
+    if (index == -1) index = descr->focus_item;
+    if (!LISTBOX_HandleTimer( hwnd, descr, index, dir )) dir = LB_TIMER_NONE;
+
+    /* Start/stop the system timer */
+
+    if (dir != LB_TIMER_NONE)
+        SetSystemTimer( hwnd, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
+    else if (LISTBOX_Timer != LB_TIMER_NONE)
+        KillSystemTimer( hwnd, LB_TIMER_ID );
+    LISTBOX_Timer = dir;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleKeyDown
+ */
+static LRESULT LISTBOX_HandleKeyDown( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
+{
+    INT caret = -1;
+    BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
+    if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
+       bForceSelection = FALSE; /* only for single select list */
+
+    if (descr->style & LBS_WANTKEYBOARDINPUT)
+    {
+        caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
+                                MAKEWPARAM(LOWORD(wParam), descr->focus_item),
+                                hwnd );
+        if (caret == -2) return 0;
+    }
+    if (caret == -1) switch(wParam)
+    {
+    case VK_LEFT:
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            bForceSelection = FALSE;
+            if (descr->focus_item >= descr->page_size)
+                caret = descr->focus_item - descr->page_size;
+            break;
+        }
+        /* fall through */
+    case VK_UP:
+        caret = descr->focus_item - 1;
+        if (caret < 0) caret = 0;
+        break;
+    case VK_RIGHT:
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            bForceSelection = FALSE;
+            if (descr->focus_item + descr->page_size < descr->nb_items)
+                caret = descr->focus_item + descr->page_size;
+            break;
+        }
+        /* fall through */
+    case VK_DOWN:
+        caret = descr->focus_item + 1;
+        if (caret >= descr->nb_items) caret = descr->nb_items - 1;
+        break;
+
+    case VK_PRIOR:
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            INT page = descr->width / descr->column_width;
+            if (page < 1) page = 1;
+            caret = descr->focus_item - (page * descr->page_size) + 1;
+        }
+        else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
+        if (caret < 0) caret = 0;
+        break;
+    case VK_NEXT:
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            INT page = descr->width / descr->column_width;
+            if (page < 1) page = 1;
+            caret = descr->focus_item + (page * descr->page_size) - 1;
+        }
+        else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
+        if (caret >= descr->nb_items) caret = descr->nb_items - 1;
+        break;
+    case VK_HOME:
+        caret = 0;
+        break;
+    case VK_END:
+        caret = descr->nb_items - 1;
+        break;
+    case VK_SPACE:
+        if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
+        else if (descr->style & LBS_MULTIPLESEL)
+        {
+            LISTBOX_SetSelection( hwnd, descr, descr->focus_item,
+                                  !descr->items[descr->focus_item].selected,
+                                  (descr->style & LBS_NOTIFY) != 0 );
+        }
+        break;
+    default:
+        bForceSelection = FALSE;
+    }
+    if (bForceSelection) /* focused item is used instead of key */
+        caret = descr->focus_item;
+    if (caret >= 0)
+    {
+        if ((descr->style & LBS_EXTENDEDSEL) &&
+            !(GetKeyState( VK_SHIFT ) & 0x8000))
+            descr->anchor_item = caret;
+        LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
+        LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
+        if (descr->style & LBS_NOTIFY)
+        {
+	    if( descr->lphc )
+            {
+		/* make sure that combo parent doesn't hide us */
+		descr->lphc->wState |= CBF_NOROLLUP;
+	    }
+            if (descr->nb_items) SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
+        }
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleChar
+ */
+static LRESULT LISTBOX_HandleChar( HWND hwnd, LB_DESCR *descr, WCHAR charW )
+{
+    INT caret = -1;
+    WCHAR str[2];
+
+    str[0] = charW;
+    str[1] = '\0';
+
+    if (descr->style & LBS_WANTKEYBOARDINPUT)
+    {
+        caret = SendMessageW( descr->owner, WM_CHARTOITEM,
+                                MAKEWPARAM(charW, descr->focus_item),
+                                hwnd );
+        if (caret == -2) return 0;
+    }
+    if (caret == -1)
+        caret = LISTBOX_FindString( hwnd, descr, descr->focus_item, str, FALSE);
+    if (caret != -1)
+    {
+        if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
+           LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
+        LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
+        if ((descr->style & LBS_NOTIFY) && descr->nb_items)
+            SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Create
+ */
+static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
+{
+    LB_DESCR *descr;
+    MEASUREITEMSTRUCT mis;
+    RECT rect;
+
+    if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
+        return FALSE;
+
+    GetClientRect( hwnd, &rect );
+    descr->owner         = GetParent( hwnd );
+    descr->style         = GetWindowLongA( hwnd, GWL_STYLE );
+    descr->width         = rect.right - rect.left;
+    descr->height        = rect.bottom - rect.top;
+    descr->items         = NULL;
+    descr->nb_items      = 0;
+    descr->top_item      = 0;
+    descr->selected_item = -1;
+    descr->focus_item    = 0;
+    descr->anchor_item   = -1;
+    descr->item_height   = 1;
+    descr->page_size     = 1;
+    descr->column_width  = 150;
+    descr->horz_extent   = (descr->style & WS_HSCROLL) ? 1 : 0;
+    descr->horz_pos      = 0;
+    descr->nb_tabs       = 0;
+    descr->tabs          = NULL;
+    descr->caret_on      = lphc ? FALSE : TRUE;
+    if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
+    descr->in_focus 	 = FALSE;
+    descr->captured      = FALSE;
+    descr->font          = 0;
+    descr->locale        = 0;  /* FIXME */
+    descr->lphc		 = lphc;
+
+    if (is_old_app(hwnd) && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
+    {
+	/* Win95 document "List Box Differences" from MSDN:
+	   If a list box in a version 3.x application has either the
+	   WS_HSCROLL or WS_VSCROLL style, the list box receives both
+	   horizontal and vertical scroll bars.
+	*/
+	descr->style |= WS_VSCROLL | WS_HSCROLL;
+    }
+
+    if( lphc )
+    {
+	TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
+                      hwnd, descr->owner, lphc->self );
+        descr->owner = lphc->self;
+    }
+
+    SetWindowLongA( hwnd, 0, (LONG)descr );
+
+/*    if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
+ */
+    if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
+    if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
+    if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
+    descr->item_height = LISTBOX_SetFont( hwnd, descr, 0 );
+
+    if (descr->style & LBS_OWNERDRAWFIXED)
+    {
+	if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
+	{
+	    /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
+	  descr->item_height = lphc->fixedOwnerDrawHeight;
+	}
+	else
+	{
+            UINT id = GetWindowLongA( hwnd, GWL_ID );
+            mis.CtlType    = ODT_LISTBOX;
+            mis.CtlID      = id;
+            mis.itemID     = -1;
+            mis.itemWidth  =  0;
+            mis.itemData   =  0;
+            mis.itemHeight = descr->item_height;
+            SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+            descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
+	}
+    }
+
+    TRACE("owner: %04x, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Destroy
+ */
+static BOOL LISTBOX_Destroy( HWND hwnd, LB_DESCR *descr )
+{
+    LISTBOX_ResetContent( hwnd, descr );
+    SetWindowLongA( hwnd, 0, 0 );
+    HeapFree( GetProcessHeap(), 0, descr );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           ListBoxWndProc_common
+ */
+static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
+                                             WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+    LRESULT ret;
+    LB_DESCR *descr;
+
+    if (!(descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 )))
+    {
+        if (msg == WM_CREATE)
+        {
+            if (!LISTBOX_Create( hwnd, NULL ))
+                return -1;
+            TRACE("creating wnd=%04x descr=%lx\n", hwnd, GetWindowLongA( hwnd, 0 ) );
+            return 0;
+        }
+        /* Ignore all other messages before we get a WM_CREATE */
+        return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
+                         DefWindowProcA( hwnd, msg, wParam, lParam );
+    }
+
+    TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
+          hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
+    switch(msg)
+    {
+    case LB_RESETCONTENT16:
+    case LB_RESETCONTENT:
+        LISTBOX_ResetContent( hwnd, descr );
+        LISTBOX_UpdateScroll( hwnd, descr );
+        InvalidateRect( hwnd, NULL, TRUE );
+        return 0;
+
+    case LB_ADDSTRING16:
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_ADDSTRING:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        wParam = LISTBOX_FindStringPos( hwnd, descr, textW, FALSE );
+        ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
+        if (!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_INSERTSTRING16:
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        wParam = (INT)(INT16)wParam;
+        /* fall through */
+    case LB_INSERTSTRING:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
+        if(!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_ADDFILE16:
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_ADDFILE:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        wParam = LISTBOX_FindFileStrPos( hwnd, descr, textW );
+        ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
+        if(!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_DELETESTRING16:
+    case LB_DELETESTRING:
+        if (LISTBOX_RemoveItem( hwnd, descr, wParam) != LB_ERR)
+           return descr->nb_items;
+        else
+           return LB_ERR;
+
+    case LB_GETITEMDATA16:
+    case LB_GETITEMDATA:
+        if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        return descr->items[wParam].data;
+
+    case LB_SETITEMDATA16:
+    case LB_SETITEMDATA:
+        if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        descr->items[wParam].data = (DWORD)lParam;
+        return LB_OKAY;
+
+    case LB_GETCOUNT16:
+    case LB_GETCOUNT:
+        return descr->nb_items;
+
+    case LB_GETTEXT16:
+        lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_GETTEXT:
+        return LISTBOX_GetText( descr, wParam, lParam, unicode );
+
+    case LB_GETTEXTLEN16:
+        /* fall through */
+    case LB_GETTEXTLEN:
+        if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
+            return LB_ERR;
+        return (HAS_STRINGS(descr) ? strlenW(descr->items[wParam].str)
+                                   : sizeof(DWORD));
+
+    case LB_GETCURSEL16:
+    case LB_GETCURSEL:
+        if (descr->nb_items==0)
+	  return LB_ERR;
+        if (!IS_MULTISELECT(descr))
+          return descr->selected_item;
+	/* else */
+	if (descr->selected_item!=-1)
+	  return descr->selected_item;
+	/* else */
+	return descr->focus_item;
+        /* otherwise, if the user tries to move the selection with the    */
+        /* arrow keys, we will give the application something to choke on */
+    case LB_GETTOPINDEX16:
+    case LB_GETTOPINDEX:
+        return descr->top_item;
+
+    case LB_GETITEMHEIGHT16:
+    case LB_GETITEMHEIGHT:
+        return LISTBOX_GetItemHeight( descr, wParam );
+
+    case LB_SETITEMHEIGHT16:
+        lParam = LOWORD(lParam);
+        /* fall through */
+    case LB_SETITEMHEIGHT:
+        return LISTBOX_SetItemHeight( hwnd, descr, wParam, lParam, TRUE );
+
+    case LB_ITEMFROMPOINT:
+        {
+            POINT pt;
+            RECT rect;
+
+	    pt.x = LOWORD(lParam);
+	    pt.y = HIWORD(lParam);
+	    rect.left = 0;
+	    rect.top = 0;
+	    rect.right = descr->width;
+	    rect.bottom = descr->height;
+
+            return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
+                             !PtInRect( &rect, pt ) );
+        }
+
+    case LB_SETCARETINDEX16:
+    case LB_SETCARETINDEX:
+        if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
+        if (LISTBOX_SetCaretIndex( hwnd, descr, wParam, !lParam ) == LB_ERR)
+            return LB_ERR;
+        else if (ISWIN31)
+             return wParam;
+        else
+             return LB_OKAY;
+
+    case LB_GETCARETINDEX16:
+    case LB_GETCARETINDEX:
+        return descr->focus_item;
+
+    case LB_SETTOPINDEX16:
+    case LB_SETTOPINDEX:
+        return LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
+
+    case LB_SETCOLUMNWIDTH16:
+    case LB_SETCOLUMNWIDTH:
+        return LISTBOX_SetColumnWidth( hwnd, descr, wParam );
+
+    case LB_GETITEMRECT16:
+        {
+            RECT rect;
+            ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
+            CONV_RECT32TO16( &rect, MapSL(lParam) );
+        }
+	return ret;
+
+    case LB_GETITEMRECT:
+        return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
+
+    case LB_FINDSTRING16:
+        wParam = (INT)(INT16)wParam;
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_FINDSTRING:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        ret = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
+        if(!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_FINDSTRINGEXACT16:
+        wParam = (INT)(INT16)wParam;
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_FINDSTRINGEXACT:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        ret = LISTBOX_FindString( hwnd, descr, wParam, textW, TRUE );
+        if(!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_SELECTSTRING16:
+        wParam = (INT)(INT16)wParam;
+        if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_SELECTSTRING:
+    {
+        INT index;
+        LPWSTR textW;
+
+	if(HAS_STRINGS(descr))
+	    TRACE("LB_SELECTSTRING: %s\n", unicode ? debugstr_w((LPWSTR)lParam) :
+						     debugstr_a((LPSTR)lParam));
+        if(unicode || !HAS_STRINGS(descr))
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        index = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
+        if(!unicode && HAS_STRINGS(descr))
+            HeapFree(GetProcessHeap(), 0, textW);
+        if (index != LB_ERR)
+	{
+            LISTBOX_SetCaretIndex( hwnd, descr, index, TRUE );
+            LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
+	}
+        return index;
+    }
+
+    case LB_GETSEL16:
+        wParam = (INT)(INT16)wParam;
+        /* fall through */
+    case LB_GETSEL:
+        if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        return descr->items[wParam].selected;
+
+    case LB_SETSEL16:
+        lParam = (INT)(INT16)lParam;
+        /* fall through */
+    case LB_SETSEL:
+        return LISTBOX_SetSelection( hwnd, descr, lParam, wParam, FALSE );
+
+    case LB_SETCURSEL16:
+        wParam = (INT)(INT16)wParam;
+        /* fall through */
+    case LB_SETCURSEL:
+        if (IS_MULTISELECT(descr)) return LB_ERR;
+        LISTBOX_SetCaretIndex( hwnd, descr, wParam, TRUE );
+        return LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
+
+    case LB_GETSELCOUNT16:
+    case LB_GETSELCOUNT:
+        return LISTBOX_GetSelCount( descr );
+
+    case LB_GETSELITEMS16:
+        return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
+
+    case LB_GETSELITEMS:
+        return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
+
+    case LB_SELITEMRANGE16:
+    case LB_SELITEMRANGE:
+        if (LOWORD(lParam) <= HIWORD(lParam))
+            return LISTBOX_SelectItemRange( hwnd, descr, LOWORD(lParam),
+                                            HIWORD(lParam), wParam );
+        else
+            return LISTBOX_SelectItemRange( hwnd, descr, HIWORD(lParam),
+                                            LOWORD(lParam), wParam );
+
+    case LB_SELITEMRANGEEX16:
+    case LB_SELITEMRANGEEX:
+        if ((INT)lParam >= (INT)wParam)
+            return LISTBOX_SelectItemRange( hwnd, descr, wParam, lParam, TRUE );
+        else
+            return LISTBOX_SelectItemRange( hwnd, descr, lParam, wParam, FALSE);
+
+    case LB_GETHORIZONTALEXTENT16:
+    case LB_GETHORIZONTALEXTENT:
+        return descr->horz_extent;
+
+    case LB_SETHORIZONTALEXTENT16:
+    case LB_SETHORIZONTALEXTENT:
+        return LISTBOX_SetHorizontalExtent( hwnd, descr, wParam );
+
+    case LB_GETANCHORINDEX16:
+    case LB_GETANCHORINDEX:
+        return descr->anchor_item;
+
+    case LB_SETANCHORINDEX16:
+        wParam = (INT)(INT16)wParam;
+        /* fall through */
+    case LB_SETANCHORINDEX:
+        if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        descr->anchor_item = (INT)wParam;
+        return LB_OKAY;
+
+    case LB_DIR16:
+        /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
+         * be set automatically (this is different in Win32) */
+        if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
+	lParam = (LPARAM)MapSL(lParam);
+        /* fall through */
+    case LB_DIR:
+    {
+        INT ret;
+        LPWSTR textW;
+        if(unicode)
+            textW = (LPWSTR)lParam;
+        else
+        {
+            LPSTR textA = (LPSTR)lParam;
+            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+                MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+        }
+        ret = LISTBOX_Directory( hwnd, descr, wParam, textW, msg == LB_DIR );
+        if(!unicode)
+            HeapFree(GetProcessHeap(), 0, textW);
+        return ret;
+    }
+
+    case LB_GETLOCALE:
+        return descr->locale;
+
+    case LB_SETLOCALE:
+        descr->locale = (LCID)wParam;  /* FIXME: should check for valid lcid */
+        return LB_OKAY;
+
+    case LB_INITSTORAGE:
+        return LISTBOX_InitStorage( hwnd, descr, wParam );
+
+    case LB_SETCOUNT:
+        return LISTBOX_SetCount( hwnd, descr, (INT)wParam );
+
+    case LB_SETTABSTOPS16:
+        return LISTBOX_SetTabStops( hwnd, descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
+
+    case LB_SETTABSTOPS:
+        return LISTBOX_SetTabStops( hwnd, descr, wParam, (LPINT)lParam, FALSE );
+
+    case LB_CARETON16:
+    case LB_CARETON:
+        if (descr->caret_on)
+            return LB_OKAY;
+        descr->caret_on = TRUE;
+        if ((descr->focus_item != -1) && (descr->in_focus))
+            LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
+        return LB_OKAY;
+
+    case LB_CARETOFF16:
+    case LB_CARETOFF:
+        if (!descr->caret_on)
+            return LB_OKAY;
+        descr->caret_on = FALSE;
+        if ((descr->focus_item != -1) && (descr->in_focus))
+            LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
+        return LB_OKAY;
+
+    case WM_DESTROY:
+        return LISTBOX_Destroy( hwnd, descr );
+
+    case WM_ENABLE:
+        InvalidateRect( hwnd, NULL, TRUE );
+        return 0;
+
+    case WM_SETREDRAW:
+        LISTBOX_SetRedraw( hwnd, descr, wParam != 0 );
+        return 0;
+
+    case WM_GETDLGCODE:
+        return DLGC_WANTARROWS | DLGC_WANTCHARS;
+
+    case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            HDC hdc = ( wParam ) ? ((HDC)wParam) :  BeginPaint( hwnd, &ps );
+            ret = LISTBOX_Paint( hwnd, descr, hdc );
+            if( !wParam ) EndPaint( hwnd, &ps );
+        }
+        return ret;
+    case WM_SIZE:
+        LISTBOX_UpdateSize( hwnd, descr );
+        return 0;
+    case WM_GETFONT:
+        return descr->font;
+    case WM_SETFONT:
+        LISTBOX_SetFont( hwnd, descr, (HFONT)wParam );
+        if (lParam) InvalidateRect( hwnd, 0, TRUE );
+        return 0;
+    case WM_SETFOCUS:
+        descr->in_focus = TRUE;
+        descr->caret_on = TRUE;
+        if (descr->focus_item != -1)
+            LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
+        SEND_NOTIFICATION( hwnd, descr, LBN_SETFOCUS );
+        return 0;
+    case WM_KILLFOCUS:
+        descr->in_focus = FALSE;
+        if ((descr->focus_item != -1) && descr->caret_on)
+            LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
+        SEND_NOTIFICATION( hwnd, descr, LBN_KILLFOCUS );
+        return 0;
+    case WM_HSCROLL:
+        return LISTBOX_HandleHScroll( hwnd, descr, wParam );
+    case WM_VSCROLL:
+        return LISTBOX_HandleVScroll( hwnd, descr, wParam );
+    case WM_MOUSEWHEEL:
+        if (wParam & (MK_SHIFT | MK_CONTROL))
+            return DefWindowProcW( hwnd, msg, wParam, lParam );
+        return LISTBOX_HandleMouseWheel( hwnd, descr, wParam );
+    case WM_LBUTTONDOWN:
+        return LISTBOX_HandleLButtonDown( hwnd, descr, wParam,
+                                          (INT16)LOWORD(lParam),
+                                          (INT16)HIWORD(lParam) );
+    case WM_LBUTTONDBLCLK:
+        if (descr->style & LBS_NOTIFY)
+            SEND_NOTIFICATION( hwnd, descr, LBN_DBLCLK );
+        return 0;
+    case WM_MOUSEMOVE:
+        if (GetCapture() == hwnd)
+            LISTBOX_HandleMouseMove( hwnd, descr, (INT16)LOWORD(lParam),
+                                     (INT16)HIWORD(lParam) );
+        return 0;
+    case WM_LBUTTONUP:
+        return LISTBOX_HandleLButtonUp( hwnd, descr );
+    case WM_KEYDOWN:
+        return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
+    case WM_CHAR:
+    {
+        WCHAR charW;
+        if(unicode)
+            charW = (WCHAR)wParam;
+        else
+        {
+            CHAR charA = (CHAR)wParam;
+            MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+        }
+        return LISTBOX_HandleChar( hwnd, descr, charW );
+    }
+    case WM_SYSTIMER:
+        return LISTBOX_HandleSystemTimer( hwnd, descr );
+    case WM_ERASEBKGND:
+        if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
+        {
+            RECT rect;
+            HBRUSH hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+                                              wParam, (LPARAM)hwnd );
+	    TRACE("hbrush = %04x\n", hbrush);
+	    if(!hbrush)
+		hbrush = GetSysColorBrush(COLOR_WINDOW);
+	    if(hbrush)
+	    {
+		GetClientRect(hwnd, &rect);
+		FillRect((HDC)wParam, &rect, hbrush);
+	    }
+        }
+        return 1;
+    case WM_DROPFILES:
+        if( !descr->lphc )
+            return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
+                             SendMessageA( descr->owner, msg, wParam, lParam );
+        break;
+
+    case WM_DROPOBJECT:
+    case WM_QUERYDROPOBJECT:
+    case WM_DRAGSELECT:
+    case WM_DRAGMOVE:
+	if( !descr->lphc )
+        {
+            LPDRAGINFO16 dragInfo = MapSL( lParam );
+            dragInfo->l = LISTBOX_GetItemFromPoint( descr, dragInfo->pt.x,
+                                                dragInfo->pt.y );
+            return SendMessage16( descr->owner, msg, wParam, lParam );
+        }
+	break;
+
+    default:
+        if ((msg >= WM_USER) && (msg < 0xc000))
+            WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
+                 hwnd, msg, wParam, lParam );
+        return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
+                         DefWindowProcA( hwnd, msg, wParam, lParam );
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           ListBoxWndProcA
+ *
+ * This is just a wrapper for the real wndproc, it only does window locking
+ * and unlocking.
+ */
+static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ListBoxWndProc_common( hwnd, msg, wParam, lParam, FALSE );
+}
+
+/***********************************************************************
+ *           ListBoxWndProcW
+ */
+static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ListBoxWndProc_common( hwnd, msg, wParam, lParam, TRUE );
+}
+
+/***********************************************************************
+ *           ComboLBWndProc_common
+ *
+ * The real combo listbox wndproc
+ */
+static LRESULT WINAPI ComboLBWndProc_common( HWND hwnd, UINT msg,
+                                             WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+    LRESULT lRet = 0;
+    LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );
+
+    TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
+                  hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
+
+    if( descr || msg == WM_CREATE )
+    {
+        LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
+
+        switch( msg )
+        {
+        case WM_CREATE:
+            {
+                CREATESTRUCTA *lpcs = (CREATESTRUCTA *)lParam;
+                TRACE_(combo)("\tpassed parent handle = %p\n",lpcs->lpCreateParams);
+                lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
+                return LISTBOX_Create( hwnd, lphc );
+            }
+        case WM_MOUSEMOVE:
+            if ( (TWEAK_WineLook > WIN31_LOOK) &&
+                 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
+            {
+                POINT   mousePos;
+                BOOL    captured;
+                RECT    clientRect;
+
+                mousePos.x = (INT16)LOWORD(lParam);
+                mousePos.y = (INT16)HIWORD(lParam);
+
+                /*
+                 * If we are in a dropdown combobox, we simulate that
+                 * the mouse is captured to show the tracking of the item.
+                 */
+                GetClientRect(hwnd, &clientRect);
+
+                if (PtInRect( &clientRect, mousePos ))
+                {
+                    captured = descr->captured;
+                    descr->captured = TRUE;
+
+                    LISTBOX_HandleMouseMove( hwnd, descr,
+                                             mousePos.x, mousePos.y);
+
+                    descr->captured = captured;
+
+                }
+                else
+                {
+                    LISTBOX_HandleMouseMove( hwnd, descr,
+                                             mousePos.x, mousePos.y);
+                }
+
+                return 0;
+
+            }
+            else
+            {
+                /*
+                 * If we are in Win3.1 look, go with the default behavior.
+                 */
+                return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
+                    ListBoxWndProcA( hwnd, msg, wParam, lParam );
+            }
+        case WM_LBUTTONUP:
+            if (TWEAK_WineLook > WIN31_LOOK)
+            {
+                POINT mousePos;
+                RECT  clientRect;
+
+                /*
+                 * If the mouse button "up" is not in the listbox,
+                 * we make sure there is no selection by re-selecting the
+                 * item that was selected when the listbox was made visible.
+                 */
+                mousePos.x = (INT16)LOWORD(lParam);
+                mousePos.y = (INT16)HIWORD(lParam);
+
+                GetClientRect(hwnd, &clientRect);
+
+                /*
+                 * When the user clicks outside the combobox and the focus
+                 * is lost, the owning combobox will send a fake buttonup with
+                 * 0xFFFFFFF as the mouse location, we must also revert the
+                 * selection to the original selection.
+                 */
+                if ( (lParam == (LPARAM)-1) ||
+                     (!PtInRect( &clientRect, mousePos )) )
+                {
+                    LISTBOX_MoveCaret( hwnd, descr, lphc->droppedIndex, FALSE );
+                }
+            }
+            return LISTBOX_HandleLButtonUp( hwnd, descr );
+        case WM_LBUTTONDBLCLK:
+        case WM_LBUTTONDOWN:
+            return LISTBOX_HandleLButtonDownCombo(hwnd, descr, msg, wParam,
+                                                  (INT16)LOWORD(lParam),
+                                                  (INT16)HIWORD(lParam) );
+        case WM_NCACTIVATE:
+            return FALSE;
+        case WM_KEYDOWN:
+            if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+            {
+                /* for some reason(?) Windows makes it possible to
+                 * show/hide ComboLBox by sending it WM_KEYDOWNs */
+
+                if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
+                    ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
+                      && (wParam == VK_DOWN || wParam == VK_UP)) )
+                {
+                    COMBO_FlipListbox( lphc, FALSE, FALSE );
+                    return 0;
+                }
+            }
+            return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
+
+        case LB_SETCURSEL16:
+        case LB_SETCURSEL:
+            lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
+                ListBoxWndProcA( hwnd, msg, wParam, lParam );
+            lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
+            return lRet;
+        case WM_NCDESTROY:
+            if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+                lphc->hWndLBox = 0;
+            /* fall through */
+
+        default:
+            return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
+                ListBoxWndProcA( hwnd, msg, wParam, lParam );
+        }
+    }
+    lRet = unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
+        DefWindowProcA( hwnd, msg, wParam, lParam );
+
+    TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
+
+    return lRet;
+}
+
+/***********************************************************************
+ *           ComboLBWndProcA
+ *
+ *  NOTE: in Windows, winproc address of the ComboLBox is the same
+ *	  as that of the Listbox.
+ */
+LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ComboLBWndProc_common( hwnd, msg, wParam, lParam, FALSE );
+}
+
+/***********************************************************************
+ *           ComboLBWndProcW
+ */
+LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    if (!IsWindow(hwnd)) return 0;
+    return ComboLBWndProc_common( hwnd, msg, wParam, lParam, TRUE );
+}
Index: trunk/src/user32/mdi.c
===================================================================
--- trunk/src/user32/mdi.c	(revision 9522)
+++ trunk/src/user32/mdi.c	(revision 9523)
@@ -91,5 +91,6 @@
 #include "pmwindow.h"
 #include <heapstring.h>
-#define WIN_GetFullHandle(a)	a
+
+#include "ctrlconf.h"
 #endif
 
@@ -142,11 +143,6 @@
 static HWND MDI_MoreWindowsDialog(HWND);
 static void MDI_SwapMenuItems(HWND, UINT, UINT);
-#ifdef __WIN32OS2__
-       LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
-       LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
-#else
 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
-#endif
 
 /* -------- Miscellaneous service functions ----------
@@ -181,5 +177,4 @@
 
 
-#ifndef __WIN32OS2__
 /*********************************************************************
  * MDIClient class descriptor
@@ -196,4 +191,5 @@
 };
 
+#ifndef __WIN32OS2__
 static MDICLIENTINFO *get_client_info( HWND client )
 {
@@ -2379,38 +2375,2 @@
 }
 
-#ifdef __WIN32OS2__
-
-#define MDICLIENTCLASSNAMEA "MDICLIENT"
-#define MDICLIENTCLASSNAMEW L"MDICLIENT"
-
-//******************************************************************************
-//******************************************************************************
-BOOL MDICLIENT_Register()
-{
-    WNDCLASSA wndClass;
-
-//SvL: Don't check this now
-//    if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
-
-    ZeroMemory(&wndClass,sizeof(WNDCLASSA));
-    wndClass.style         = CS_GLOBALCLASS;
-    wndClass.lpfnWndProc   = (WNDPROC)MDIClientWndProcA;
-    wndClass.cbClsExtra    = 0;
-    wndClass.cbWndExtra    = 0;
-    wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);;
-    wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
-    wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
-
-    return RegisterClassA(&wndClass);
-}
-//******************************************************************************
-//******************************************************************************
-BOOL MDICLIENT_Unregister()
-{
-    if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
-            return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
-    else    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-#endif
Index: trunk/src/user32/oslibres.cpp
===================================================================
--- trunk/src/user32/oslibres.cpp	(revision 9522)
+++ trunk/src/user32/oslibres.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: oslibres.cpp,v 1.32 2002-12-13 16:46:12 sandervl Exp $ */
+/* $Id: oslibres.cpp,v 1.33 2002-12-18 12:28:05 sandervl Exp $ */
 /*
  * Window API wrappers for OS/2
@@ -799,6 +799,4 @@
                                  temp, CO_REPLACEIFEXISTS);
    }
-// If SysCreateObject("WPProgram", "WarpMix", "<ICHAUDIO>",,
-//                    "PROGTYPE=PM;OBJECTID=<WARPMIX>;ICONFILE=WARPMIX.ICO;EXENAME="||bootDrive||"\MMOS2\WARPMIX.EXE")
 
    free(pszSetupString);
Index: trunk/src/user32/user32dbg.def
===================================================================
--- trunk/src/user32/user32dbg.def	(revision 9522)
+++ trunk/src/user32/user32dbg.def	(revision 9523)
@@ -1,3 +1,3 @@
-; $Id: user32dbg.def,v 1.7 2002-09-03 12:34:01 sandervl Exp $
+; $Id: user32dbg.def,v 1.8 2002-12-18 12:28:05 sandervl Exp $
 
 LIBRARY USER32 INITINSTANCE TERMINSTANCE
@@ -203,5 +203,5 @@
     DrawTextExW                = _DbgDrawTextExW@24             @167
     DrawTextW                  = _DbgDrawTextW@20               @168
-    EditWndProc                = _DbgEditWndProc@16             @169
+    EditWndProc                = _DbgEditWndProcA@16            @169
     EmptyClipboard             = _DbgEmptyClipboard@0           @170
     EnableMenuItem             = _DbgEnableMenuItem@12          @171
Index: trunk/src/user32/win32class.cpp
===================================================================
--- trunk/src/user32/win32class.cpp	(revision 9522)
+++ trunk/src/user32/win32class.cpp	(revision 9523)
@@ -1,7 +1,12 @@
-/* $Id: win32class.cpp,v 1.29 2001-12-20 20:45:55 sandervl Exp $ */
+/* $Id: win32class.cpp,v 1.30 2002-12-18 12:28:06 sandervl Exp $ */
 /*
  * Win32 Window Class Managment Code for OS/2
  *
  * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Parts copied from ReWind (Get/SetClassLong for GCL_WNDPROC)
+ *     Copyright 1993, 1996 Alexandre Julliard
+ *               1998 Juergen Schmied (jsch)
  *
  *
@@ -40,12 +45,13 @@
 //Win32WndClass methods:
 //******************************************************************************
-Win32WndClass::Win32WndClass(WNDCLASSEXA *wndclass, BOOL fUnicode) 
+Win32WndClass::Win32WndClass(WNDCLASSEXA *wndclass, WNDCLASS_TYPE fClassType) 
                   : GenericObject(&wndclasses, &critsect)
 {
-  isUnicode = fUnicode;
+  this->fClassType = fClassType;
   processId = 0;
 
-  if(HIWORD(wndclass->lpszClassName)) {
-        if(isUnicode) {
+  if(HIWORD(wndclass->lpszClassName)) 
+  {
+        if(fClassType == WNDCLASS_UNICODE) {
                 INT len = lstrlenW((LPWSTR)wndclass->lpszClassName)+1;
 
@@ -63,5 +69,5 @@
                 exit(1);
         }
-        if(isUnicode) {
+        if(fClassType == WNDCLASS_UNICODE) {
                 lstrcpyW(classNameW, (LPWSTR)wndclass->lpszClassName);
                 UnicodeToAscii(classNameW, classNameA);
@@ -126,7 +132,13 @@
   windowStyle           = wndclass->style;
 
-  windowProc = 0;
-  WINPROC_SetProc((HWINDOWPROC *)&windowProc, wndclass->lpfnWndProc, (isUnicode) ? WIN_PROC_32W : WIN_PROC_32A, WIN_PROC_CLASS);
-  dprintf2(("Window class ptr %x", windowProc));
+  pfnWindowProcA = 0;
+  pfnWindowProcW = 0;
+  if(fClassType == WNDCLASS_UNICODE) {
+      WINPROC_SetProc((HWINDOWPROC *)&pfnWindowProcW, wndclass->lpfnWndProc,  WIN_PROC_32W, WIN_PROC_CLASS);
+  }
+  else {
+      WINPROC_SetProc((HWINDOWPROC *)&pfnWindowProcA, wndclass->lpfnWndProc, WIN_PROC_32A, WIN_PROC_CLASS);
+  }
+  dprintf2(("Window class ptr %x/%x", pfnWindowProcA, pfnWindowProcW));
 
   //User data class words/longs
@@ -156,5 +168,8 @@
   }
 
-  WINPROC_FreeProc(windowProc, WIN_PROC_CLASS);
+  if(pfnWindowProcA)
+      WINPROC_FreeProc(pfnWindowProcA, WIN_PROC_CLASS);
+  if(pfnWindowProcW)
+      WINPROC_FreeProc(pfnWindowProcW, WIN_PROC_CLASS);
 
   if(userClassBytes)    free(userClassBytes);
@@ -179,5 +194,5 @@
 {
   if(HIWORD(classname) == 0) {
-    return classAtom == (DWORD)classname;
+      return classAtom == (DWORD)classname;
   }
   if(fUnicode) {
@@ -349,4 +364,28 @@
 //******************************************************************************
 //******************************************************************************
+WNDPROC Win32WndClass::getWindowProc(WNDPROC_TYPE type)
+{
+    WNDPROC proc;
+
+    if(type == WNDPROC_UNICODE) {
+         proc = (pfnWindowProcW) ? pfnWindowProcW : pfnWindowProcA;
+    }
+    else proc = (pfnWindowProcA) ? pfnWindowProcA : pfnWindowProcW;
+
+    return proc; 
+};
+//******************************************************************************
+//NOTE: Only to be used when a class has both ascii & unicode window procedures!
+//      Otherwise use SetClassLong GCL_WNDPROC
+//******************************************************************************
+void Win32WndClass::setWindowProc(WNDPROC pfnWindowProc, WNDPROC_TYPE type)
+{
+    if(type == WNDPROC_UNICODE) {
+         WINPROC_SetProc((HWINDOWPROC *)&pfnWindowProcW, pfnWindowProc,  WIN_PROC_32W, WIN_PROC_CLASS);
+    }
+    else WINPROC_SetProc((HWINDOWPROC *)&pfnWindowProcA, pfnWindowProc,  WIN_PROC_32A, WIN_PROC_CLASS);
+}
+//******************************************************************************
+//******************************************************************************
 void Win32WndClass::setMenuName(LPSTR newMenuName)
 {
@@ -358,5 +397,5 @@
   }
   if(HIWORD(newMenuName)) {
-        if(isUnicode) {
+        if(fClassType == WNDCLASS_UNICODE) {
                 menuNameA = (PCHAR)_smalloc(lstrlenW((LPWSTR)newMenuName)+1);
                 menuNameW = (WCHAR *)_smalloc((lstrlenW((LPWSTR)newMenuName)+1)*sizeof(WCHAR));
@@ -368,7 +407,8 @@
         if(menuNameA == NULL || menuNameW == NULL) {
                 dprintf(("Win32Class ctr; menuName/menuNameW == NULL"));
-                exit(1);
-        }
-        if(isUnicode) {
+                DebugInt3();
+                return;
+        }
+        if(fClassType == WNDCLASS_UNICODE) {
                 lstrcpyW(menuNameW, (LPWSTR)newMenuName);
                 UnicodeToAscii(menuNameW, menuNameA);
@@ -405,9 +445,18 @@
                 return hInstance;
         case GCL_MENUNAME:
-                return (isUnicode) ? (ULONG)menuNameW : (ULONG)menuNameA;
+                return (fUnicode) ? (ULONG)menuNameW : (ULONG)menuNameA;
         case GCL_STYLE:
                 return windowStyle;
         case GCL_WNDPROC:
-                return (ULONG) WINPROC_GetProc(windowProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A);
+        {
+                WNDPROC pfnWindowProc = pfnWindowProcA;
+
+                if(pfnWindowProcW) 
+                {
+                    if(!pfnWindowProc || fUnicode) 
+                        pfnWindowProc = pfnWindowProcW;
+                }
+                return (ULONG) WINPROC_GetProc(pfnWindowProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A);
+        }
         case GCW_ATOM: //TODO: does this really happen in windows?
                 SetLastError(ERROR_INVALID_PARAMETER);
@@ -493,4 +542,5 @@
                 break;
         case GCL_WNDPROC:
+        {
                 //Note: Type of SetWindowLong determines new window proc type
                 //      UNLESS the new window proc has already been registered
@@ -498,7 +548,31 @@
                 //      (VERIFIED in NT 4, SP6)
                 //TODO: Is that also true for GCL_WNDPROC???????????????
-                rc = (LONG)WINPROC_GetProc(windowProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A );
-                WINPROC_SetProc((HWINDOWPROC *)&windowProc, (WNDPROC)lNewVal, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A, WIN_PROC_CLASS );
-                break;
+                WNDPROC *proc = &pfnWindowProcA;
+                WINDOWPROCTYPE type = (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A;
+
+                if(pfnWindowProcW) 
+                {
+                    if(!*proc || fUnicode) 
+                        proc = &pfnWindowProcW;
+                }
+                rc = (LONG)WINPROC_GetProc(*proc, type );
+                WINPROC_SetProc((HWINDOWPROC *)proc, (WNDPROC)lNewVal, type, WIN_PROC_CLASS);
+
+                /* now free the one that we didn't set */
+                if(pfnWindowProcA && pfnWindowProcW)
+                {
+                    if (proc == &pfnWindowProcA)
+                    {
+                        WINPROC_FreeProc( pfnWindowProcW, WIN_PROC_CLASS );
+                        pfnWindowProcW = 0;
+                    }
+                    else
+                    {
+                        WINPROC_FreeProc( pfnWindowProcA, WIN_PROC_CLASS );
+                        pfnWindowProcA = 0;
+                    }
+                }
+                break;
+        }
         case GCW_ATOM: //TODO: does this really happen in windows?
                 SetLastError(ERROR_INVALID_PARAMETER);
Index: trunk/src/user32/win32class.h
===================================================================
--- trunk/src/user32/win32class.h	(revision 9522)
+++ trunk/src/user32/win32class.h	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: win32class.h,v 1.15 2001-06-09 14:50:20 sandervl Exp $ */
+/* $Id: win32class.h,v 1.16 2002-12-18 12:28:06 sandervl Exp $ */
 /*
  * Win32 Window Class Managment Code for OS/2
@@ -15,11 +15,21 @@
 #define RELEASE_CLASSOBJ(a)       { a->release(); a = NULL; }
 
+typedef enum {
+  WNDCLASS_ASCII,
+  WNDCLASS_UNICODE
+} WNDCLASS_TYPE;
+
+typedef enum {
+  WNDPROC_ASCII,
+  WNDPROC_UNICODE
+} WNDPROC_TYPE;
+
 class Win32WndClass : public GenericObject
 {
 public:
-        Win32WndClass(WNDCLASSEXA *wndclass, BOOL fUnicode = FALSE);
+        Win32WndClass(WNDCLASSEXA *wndclass, WNDCLASS_TYPE fClassType = WNDCLASS_ASCII);
        ~Win32WndClass();
 
-         ULONG  getClassLongA(int index, BOOL fUnicode = FALSE);
+         ULONG  getClassLongA(int index, BOOL fUnicode = TRUE);
          ULONG  getClassLongW(int index)
          {
@@ -28,5 +38,5 @@
          WORD   getClassWord(int index);
 
-         ULONG  setClassLongA(int index, LONG lNewVal, BOOL fUnicode = FALSE);
+         ULONG  setClassLongA(int index, LONG lNewVal, BOOL fUnicode = TRUE);
          ULONG  setClassLongW(int index, LONG lNewVal)
          {
@@ -42,5 +52,8 @@
          ULONG  getClassName(LPWSTR lpszClassName, ULONG cchClassName);
 
-       WNDPROC  getWindowProc()         { return windowProc; };
+       WNDPROC  getWindowProc(WNDPROC_TYPE type);
+         //NOTE: Only to be used when a class has both ascii & unicode window procedures!
+         void   setWindowProc(WNDPROC pfnWindowProc, WNDPROC_TYPE type);
+
          LPSTR  getMenuNameA()          { return menuNameA; };
          DWORD  getExtraWndBytes()      { return nrExtraWindowBytes; };
@@ -59,5 +72,5 @@
           void  setMenuName(LPSTR newMenuName);
 
-          BOOL  hasClassName(LPSTR classname, BOOL fUnicode = FALSE);
+          BOOL  hasClassName(LPSTR classname, BOOL fUnicode);
 
           BOOL  isAppClass(ULONG curProcessId);
@@ -73,5 +86,5 @@
 
 private:
- BOOL           isUnicode;
+ WNDCLASS_TYPE  fClassType;
 
  //Standard class words/longs
@@ -85,5 +98,6 @@
  PCHAR          menuNameA;              //GCL_MENUNAME
  WCHAR         *menuNameW;              //GCL_MENUNAME
- WNDPROC        windowProc;             //GCL_WNDPROC
+ WNDPROC        pfnWindowProcA;         //GCL_WNDPROC
+ WNDPROC        pfnWindowProcW;         //GCL_WNDPROC
  ULONG          classAtom;              //GCW_ATOM
 
@@ -101,3 +115,8 @@
 };
 
+ATOM WIN32API InternalRegisterClass(LPSTR lpszClassName, DWORD dwStyle,
+                                    WNDPROC pfnClassA, WNDPROC pfnClassW,
+                                    UINT cbExtraWindowWords, LPCSTR lpszCursor,
+                                    HBRUSH hBrush);
+
 #endif //__WIN32CLASS_H__
Index: trunk/src/user32/win32dlg.cpp
===================================================================
--- trunk/src/user32/win32dlg.cpp	(revision 9522)
+++ trunk/src/user32/win32dlg.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: win32dlg.cpp,v 1.78 2002-07-08 11:43:44 sandervl Exp $ */
+/* $Id: win32dlg.cpp,v 1.79 2002-12-18 12:28:06 sandervl Exp $ */
 /*
  * Win32 Dialog Code for OS/2
@@ -708,4 +708,11 @@
         dlgtemplate = (LPCSTR)getControl( (WORD *)dlgtemplate, &info, dlgInfo.dialogEx );
 
+        /* Is this it? */
+        if (info.style & WS_BORDER)
+        {
+            info.style &= ~WS_BORDER;
+            info.exStyle |= WS_EX_CLIENTEDGE;
+        }
+
         dprintf(("Create CONTROL %d", info.id));
 
Index: trunk/src/user32/win32wbase.cpp
===================================================================
--- trunk/src/user32/win32wbase.cpp	(revision 9522)
+++ trunk/src/user32/win32wbase.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: win32wbase.cpp,v 1.345 2002-12-05 09:25:06 sandervl Exp $ */
+/* $Id: win32wbase.cpp,v 1.346 2002-12-18 12:28:07 sandervl Exp $ */
 /*
  * Win32 Window Base Class for OS/2
@@ -115,5 +115,5 @@
     }
 
-    WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, windowClass->getWindowProc(), WINPROC_GetProcType(windowClass->getWindowProc()), WIN_PROC_WINDOW);
+    WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII), WINPROC_GetProcType(windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII)), WIN_PROC_WINDOW);
     hInstance  = NULL;
     dwStyle    = WS_VISIBLE;
@@ -523,5 +523,5 @@
     }
 
-    WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, windowClass->getWindowProc(), WINPROC_GetProcType(windowClass->getWindowProc()), WIN_PROC_WINDOW);
+    WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII), WINPROC_GetProcType(windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII)), WIN_PROC_WINDOW);
     hInstance  = cs->hInstance;
     dwStyle    = cs->style & ~WS_VISIBLE;
Index: trunk/src/user32/win32wdesktop.cpp
===================================================================
--- trunk/src/user32/win32wdesktop.cpp	(revision 9522)
+++ trunk/src/user32/win32wdesktop.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: win32wdesktop.cpp,v 1.19 2002-04-07 21:37:35 sandervl Exp $ */
+/* $Id: win32wdesktop.cpp,v 1.20 2002-12-18 12:28:07 sandervl Exp $ */
 /*
  * Win32 Desktop Window for OS/2
@@ -60,5 +60,5 @@
   windowClass = Win32WndClass::FindClass(0, (LPSTR)DESKTOP_CLASS_ATOM);
 
-  setWindowProc(windowClass->getWindowProc());
+  setWindowProc(windowClass->getWindowProc(WNDPROC_ASCII));
 
   dwStyle |= WS_VISIBLE;
Index: trunk/src/user32/win32wmdichild.cpp
===================================================================
--- trunk/src/user32/win32wmdichild.cpp	(revision 9522)
+++ 	(revision )
@@ -1,546 +1,0 @@
-/* $Id: win32wmdichild.cpp,v 1.27 2001-06-11 20:08:25 sandervl Exp $ */
-/*
- * Win32 MDI Child Window Class for OS/2
- *
- * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
- *
- * Based on Wine (windows\mdi.c) (990815)
- *
- * Copyright 1994, Bob Amstadt
- *           1995,1996 Alex Korobka
- * Copyright 1993, 1994 Alexandre Julliard
- *
- *
- *
- * TODO: See #if 0's
- *
- * Project Odin Software License can be found in LICENSE.TXT
- *
- */
-#include <os2win.h>
-#include <win.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <misc.h>
-#include <heapstring.h>
-#include <win32wnd.h>
-#include <win32wmdiclient.h>
-#include <win32wmdichild.h>
-#include <spy.h>
-#include "wndmsg.h"
-#include <oslibwin.h>
-#include <oslibutil.h>
-#include <oslibgdi.h>
-#include <oslibres.h>
-#include "oslibdos.h"
-#include "syscolor.h"
-#include "win32wndhandle.h"
-
-#define DBG_LOCALLOG	DBG_win32wmdichild
-#include "dbglocal.h"
-
-//******************************************************************************
-//******************************************************************************
-Win32MDIChildWindow::Win32MDIChildWindow(CREATESTRUCTA *lpCreateStructA, ATOM classAtom, BOOL fUnicode)
-                    : Win32BaseWindow()
-{
-    isUnicode = fUnicode;
-    CreateWindowExA(lpCreateStructA, classAtom);
-}
-//******************************************************************************
-//******************************************************************************
-Win32MDIChildWindow::~Win32MDIChildWindow()
-{
-}
-//******************************************************************************
-//******************************************************************************
-BOOL Win32MDIChildWindow::isMDIChild()
-{
-    return TRUE;
-}
-//******************************************************************************
-//******************************************************************************
-LRESULT Win32MDIChildWindow::DefMDIChildProcA(UINT Msg, WPARAM wParam, LPARAM lParam)
-{
- Win32MDIClientWindow *client = (Win32MDIClientWindow *)getParent();
-
-    switch (Msg)
-    {
-    case WM_SETTEXT:
-        DefWindowProcA(Msg, wParam, lParam);
-        menuModifyItem();
-        if( client->getMaximizedChild() == getWindowHandle() )
-                client->updateFrameText(MDI_REPAINTFRAME, NULL);
-        return 0;
-
-    case WM_GETMINMAXINFO:
-    {
-        childGetMinMaxInfo((MINMAXINFO *)lParam);
-        return 0;
-    }
-
-    case WM_MENUCHAR:
-        /* MDI children don't have menu bars */
-        PostMessageA(client->getWindowHandle(), WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
-        return 0x00010000L;
-
-    case WM_CLOSE:
-        client->SendMessageA(WM_MDIDESTROY,(WPARAM)getWindowHandle(), 0L);
-        return 0;
-
-    case WM_SETFOCUS:
-        if(client->getActiveChild() != getWindowHandle() )
-            client->childActivate(this);
-        break;
-
-    case WM_CHILDACTIVATE:
-       	client->childActivate(this);
-        return 0;
-
-    case WM_NCPAINT:
-        break;
-
-    case WM_SYSCOMMAND:
-        switch( wParam )
-        {
-        case SC_MOVE:
-            if( client->getMaximizedChild() == getWindowHandle())
-            {
-                return 0;
-            }
-            break;
-        case SC_RESTORE:
-        case SC_MINIMIZE:
-            setStyle(getStyle() | WS_SYSMENU);
-            break;
-
-        case SC_MAXIMIZE:
-            if( client->getMaximizedChild() == getWindowHandle())
-            {
-                  return client->SendMessageA(Msg, wParam, lParam);
-            }
-            setStyle(getStyle() & ~WS_SYSMENU);
-            break;
-
-        case SC_NEXTWINDOW:
-             client->SendMessageA(WM_MDINEXT, 0, 0);
-             return 0;
-
-        case SC_PREVWINDOW: //WM_MDINEXT??
-             client->SendMessageA(WM_MDINEXT, 0, 0);
-             return 0;
-        }
-        break;
-
-    case WM_SETVISIBLE:
-        if( client->getMaximizedChild()) {
-                client->setMdiFlags(client->getMdiFlags() & ~MDIF_NEEDUPDATE);
-        }
-        else    client->postUpdate(SB_BOTH+1);
-        break;
-
-    case WM_SIZE:
-        /* do not change */
-        if( client->getActiveChild() == getWindowHandle() && wParam != SIZE_MAXIMIZED )
-        {
-            client->setMaximizedChild(NULL);
-            client->restoreFrameMenu(getWindowHandle());
-            client->updateFrameText(MDI_REPAINTFRAME, NULL );
-        }
-
-        if( wParam == SIZE_MAXIMIZED )
-        {
-            HWND maxChild = client->getMaximizedChild();
-
-            if( maxChild == getWindowHandle() ) break;
-
-            if( maxChild)
-            {
-                ::SendMessageA(maxChild, WM_SETREDRAW, FALSE, 0L );
-                client->restoreFrameMenu(maxChild);
-                ::ShowWindow(maxChild, SW_SHOWNOACTIVATE);
-
-                ::SendMessageA(maxChild, WM_SETREDRAW, TRUE, 0L );
-            }
-
-            client->setMaximizedChild(getWindowHandle());
-            client->setActiveChild(getWindowHandle());
-
-            client->augmentFrameMenu(getWindowHandle());
-
-            client->updateFrameText(MDI_REPAINTFRAME, NULL );
-        }
-
-        if( wParam == SIZE_MINIMIZED )
-        {
-            Win32MDIChildWindow *switchTo = client->getWindow(this, TRUE, WS_MINIMIZE);
-
-            if( switchTo )
-                switchTo->SendMessageA(WM_CHILDACTIVATE, 0, 0L);
-        }
-
-        client->postUpdate(SB_BOTH+1);
-        break;
-
-#if 0
-    case WM_NEXTMENU:
-        if( wParam == VK_LEFT )     /* switch to frame system menu */
-        {
-            return MAKELONG( GetSubMenu(clientWnd->parent->hSysMenu, 0),
-               clientWnd->parent->hwndSelf );
-            goto END;
-        }
-        if( wParam == VK_RIGHT )    /* to frame menu bar */
-        {
-            retvalue = MAKELONG( clientWnd->parent->wIDmenu,
-               clientWnd->parent->hwndSelf );
-            goto END;
-        }
-#endif
-    case WM_SYSCHAR:
-        if (wParam == '-')
-        {
-            SendInternalMessageA(WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
-            return 0;
-        }
-    }
-    return DefWindowProcA(Msg, wParam, lParam);
-}
-//******************************************************************************
-//******************************************************************************
-LRESULT Win32MDIChildWindow::DefMDIChildProcW(UINT Msg, WPARAM wParam, LPARAM lParam)
-{
- Win32MDIClientWindow *client = (Win32MDIClientWindow *)getParent();
-
-    switch (Msg)
-    {
-    case WM_SETTEXT:
-        DefWindowProcW(Msg, wParam, lParam);
-        menuModifyItem();
-        if( client->getMaximizedChild() == getWindowHandle() )
-                client->updateFrameText(MDI_REPAINTFRAME, NULL );
-
-        return 0;
-
-    case WM_GETMINMAXINFO:
-    case WM_MENUCHAR:
-    case WM_CLOSE:
-    case WM_SETFOCUS:
-    case WM_CHILDACTIVATE:
-    case WM_NCPAINT:
-    case WM_SYSCOMMAND:
-    case WM_SETVISIBLE:
-    case WM_SIZE:
-    case WM_NEXTMENU:
-        return DefMDIChildProcA(Msg, wParam, lParam );
-
-    case WM_SYSCHAR:
-        if (wParam == '-')
-        {
-            SendInternalMessageW(WM_SYSCOMMAND, SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
-            return 0;
-        }
-        break;
-    }
-    return DefWindowProcW(Msg, wParam, lParam);
-}
-/**********************************************************************
- *                  MDICreateChild
- */
-HWND Win32MDIChildWindow::createChild(Win32MDIClientWindow *client, LPMDICREATESTRUCTA cs )
-{
-  POINT        pos[2];
-  DWORD        style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
-  WORD         wIDmenu = client->getFirstChildId() + client->getNrOfChildren();
-  char         lpstrDef[]="junk!";
-  Win32MDIChildWindow *newchild;
-  HWND         maximizedChild;
-  CREATESTRUCTA createstruct;
-  ATOM         classAtom;
-  char         tmpClassA[20] = "";
-  WCHAR        tmpClassW[20];
-  LPSTR        className;
-
-    dprintf(("Win32MDIChildWindow::createChild %i,%i - dim %i,%i, style %08x\n",
-             cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style));
-
-    /* calculate placement */
-    calcDefaultChildPos(client, client->incTotalCreated()-1, pos, 0);
-
-    if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
-    if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
-
-    if( cs->x == CW_USEDEFAULT )
-    {
-        cs->x = pos[0].x;
-        cs->y = pos[0].y;
-    }
-
-    /* restore current maximized child */
-    if( style & WS_VISIBLE && client->getMaximizedChild() )
-    {
-        if( style & WS_MAXIMIZE )
-            client->SendMessageA(WM_SETREDRAW, FALSE, 0L );
-
-        maximizedChild = client->getMaximizedChild();
-
-        ::ShowWindow(maximizedChild, SW_SHOWNOACTIVATE );
-
-        if( style & WS_MAXIMIZE )
-            client->SendMessageA(WM_SETREDRAW, TRUE, 0L );
-    }
-
-    /* this menu is needed to set a check mark in MDI_ChildActivate */
-    if(client->getMDIMenu())
-    	AppendMenuA(client->getMDIMenu(), MF_STRING ,wIDmenu, lpstrDef );
-
-    client->incNrActiveChildren();
-
-    /* fix window style */
-    if( !(client->getStyle() & MDIS_ALLCHILDSTYLES) )
-    {
-        dprintf(("Fixing MDI window style! %x -> %x", style, style | WS_VISIBLE | WS_OVERLAPPEDWINDOW));
-        style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
-                  WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
-        style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
-    }
-
-    createstruct.lpszName  = cs->szTitle;
-    createstruct.style     = style;
-    createstruct.dwExStyle = 0;
-    createstruct.x         = cs->x;
-    createstruct.y         = cs->y;
-    createstruct.cx        = cs->cx;
-    createstruct.cy        = cs->cy;
-    createstruct.hInstance = cs->hOwner;
-    createstruct.hMenu     = wIDmenu;
-    createstruct.hwndParent= client->getWindowHandle();
-    createstruct.lpCreateParams = (LPVOID)cs;
-
-    className = (LPSTR)cs->szClass;
-    /* Find the class atom */
-    classAtom = GlobalFindAtomA(cs->szClass);
-    if(classAtom == 0)
-    {
-        if (!HIWORD(cs->szClass))
-        {
-            sprintf(tmpClassA,"#%d", (int) className);
-            classAtom = GlobalFindAtomA(tmpClassA);
-            className = tmpClassA;
-        }
-        if (!classAtom)
-        {
-          if (!HIWORD(cs->szClass)) {
-                  dprintf(("createChild: bad class name %04x\n", LOWORD(className)));
-          }
-          else    dprintf(("createChild: bad class name '%s'\n", tmpClassA ));
-
-          SetLastError(ERROR_INVALID_PARAMETER);
-          return 0;
-        }
-    }
-    createstruct.lpszClass = className;
-
-    newchild = new Win32MDIChildWindow(&createstruct, classAtom, FALSE);
-
-    if(newchild && GetLastError() == 0)
-    {
-	/* All MDI child windows have the WS_EX_MDICHILD style */
-	newchild->setExStyle(newchild->getExStyle() | WS_EX_MDICHILD);
-
-        newchild->menuModifyItem();
-
-        if( newchild->getStyle() & WS_MINIMIZE && client->getActiveChild()) {
-            newchild->ShowWindow(SW_SHOWMINNOACTIVE);
-        }
-        else
-        {
-            /* WS_VISIBLE is clear if a) the MDI client has
-             * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
-             * MDICreateStruct. If so the created window is not shown nor
-             * activated.
-             */
-            int showflag = newchild->getStyle() & WS_VISIBLE;
-            /* clear visible flag, otherwise SetWindoPos32 ignores
-             * the SWP_SHOWWINDOW command.
-             */
-            newchild->setStyle(newchild->getStyle() & ~WS_VISIBLE);
-
-            if(showflag){
-		dprintf(("newchild->SetWindowPos active window %x", GetActiveWindow()));
-                newchild->SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
-		dprintf(("newchild->SetWindowPos active window %x", GetActiveWindow()));
-
-                /* Set maximized state here in case hwnd didn't receive WM_SIZE
-                 * during CreateWindow - bad!
-                 */
-
-                if((newchild->getStyle() & WS_MAXIMIZE) && !client->getMaximizedChild() )
-                {
-                    client->setMaximizedChild(newchild->getWindowHandle());
-
-                    client->augmentFrameMenu(newchild->getWindowHandle());
-
-                    client->updateFrameText(MDI_REPAINTFRAME, NULL );
-                }
-            }
-            else
-                /* needed, harmless ? */
-                newchild->SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
-
-        }
-    }
-    else
-    {
-        client->decNrActiveChildren();
-	if(client->getMDIMenu()) {
-        	DeleteMenu(client->getMDIMenu(), wIDmenu,MF_BYCOMMAND);
-	}
-
-        maximizedChild = client->getMaximizedChild();
-        if( ::IsWindow(maximizedChild) )
-            ::ShowWindow(maximizedChild, SW_SHOWMAXIMIZED);
-
-        dprintf(("MDI child creation failed!!"));
-        return 0;
-    }
-    return newchild->getWindowHandle();
-}
-/**********************************************************************
- *          MDI_MenuModifyItem
- */
-BOOL Win32MDIChildWindow::menuModifyItem()
-{
-    Win32MDIClientWindow *client = (Win32MDIClientWindow *)getParent();
-    char   buffer[128];
-    UINT   id   = getWindowId()-client->getFirstChildId()+1;
-    UINT   n    = sprintf(buffer,(id > 9) ? "%d":"&%d ",id);
-    BOOL   bRet = 0;
-
-    if( !client->getMDIMenu() )
-    {
-        return FALSE;
-    }
-
-    if (getWindowNameA()) lstrcpynA(buffer + n, getWindowNameA(), sizeof(buffer) - n );
-
-    n    = GetMenuState(client->getMDIMenu(), getWindowId() ,MF_BYCOMMAND);
-    bRet = ModifyMenuA(client->getMDIMenu() , getWindowId(),
-                       MF_BYCOMMAND | MF_STRING, getWindowId(), buffer );
-    CheckMenuItem(client->getMDIMenu(), getWindowId() , n & MF_CHECKED);
-
-    return bRet;
-}
-
-/**********************************************************************
- *          MDI_MenuDeleteItem
- */
-BOOL Win32MDIChildWindow::menuDeleteItem()
-{
-    Win32MDIClientWindow *client = (Win32MDIClientWindow *)getParent();
-    char    buffer[128];
-    UINT    index      = 0,id,n;
-    BOOL    retvalue;
-
-    if( !client->getNrOfChildren() ||
-        !client->getMDIMenu())
-    {
-        return FALSE;
-    }
-
-    id = getWindowId();
-    DeleteMenu(client->getMDIMenu(),id,MF_BYCOMMAND);
-
-    /* walk the rest of MDI children to prevent gaps in the id
-     * sequence and in the menu child list */
-
-    lock();
-    for( index = id+1; index <= client->getNrOfChildren() +
-         client->getFirstChildId(); index++ )
-    {
-        Win32MDIChildWindow *tmpWnd = (Win32MDIChildWindow *)GetWindowFromHandle(client->getChildByID(index));
-        if( !tmpWnd )
-        {
-            dprintf(("no window for id=%i\n",index));
-            continue;
-        }
-
-        /* set correct id */
-        tmpWnd->setWindowId(tmpWnd->getWindowId()-1);
-
-        n = sprintf(buffer, "%d ",index - client->getFirstChildId());
-        if (tmpWnd->getWindowNameA())
-            lstrcpynA(buffer + n, tmpWnd->getWindowNameA(), sizeof(buffer) - n );
-
-        RELEASE_WNDOBJ(tmpWnd);
-
-        unlock();
-        /* change menu */
-        ModifyMenuA(client->getMDIMenu(), index ,MF_BYCOMMAND | MF_STRING,
-                    index - 1 , buffer );
-        lock();
-    }
-    unlock();
-    return TRUE;
-}
-/**********************************************************************
- *          MDI_CalcDefaultChildPos
- *
- *  It seems that the default height is about 2/3 of the client rect
- */
-void Win32MDIChildWindow::calcDefaultChildPos(Win32MDIClientWindow *client, WORD n, LPPOINT lpPos, INT delta)
-{
-    INT  nstagger;
-    RECT rect;
-    INT  spacing = GetSystemMetrics(SM_CYCAPTION) +
-                   GetSystemMetrics(SM_CYFRAME) - 1;
-
-    client->getClientRect(&rect);
-    if( rect.bottom - rect.top - delta >= spacing )
-        rect.bottom -= delta;
-
-    nstagger = (rect.bottom - rect.top)/(3 * spacing);
-    lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
-    lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
-    lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
-}
-
-/**********************************************************************
- *          MDI_ChildGetMinMaxInfo
- *
- * Note: The rule here is that client rect of the maximized MDI child
- *   is equal to the client rect of the MDI client window.
- */
-void Win32MDIChildWindow::childGetMinMaxInfo(MINMAXINFO* lpMinMax )
-{
-    Win32MDIClientWindow *client = (Win32MDIClientWindow *)getParent();
-    RECT rect;
-
-    if(client == NULL) {
-        dprintf(("Win32MDIChildWindow::childGetMinMaxInfo:: client == NULL!!"));
-        return;
-    }
-
-    client->getClientRect(&rect);
-    if(client->getParent() == NULL) {
-        dprintf(("Win32MDIChildWindow::childGetMinMaxInfo:: client parent == NULL!!"));
-        return;
-    }
-    //SvL: No mapping required as our client rectangle is in frame coordinates (not relative to parent!)
-/////    MapWindowPoints(client->getParent()->getWindowHandle(), client->getWindowHandle(), (LPPOINT)&rect, 2);
-
-    AdjustWindowRectEx( &rect, getStyle(), 0, getExStyle());
-
-    lpMinMax->ptMaxSize.x = rect.right -= rect.left;
-    lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
-
-    lpMinMax->ptMaxPosition.x = rect.left;
-    lpMinMax->ptMaxPosition.y = rect.top;
-}
-
-//******************************************************************************
-//******************************************************************************
-
Index: trunk/src/user32/win32wmdichild.h
===================================================================
--- trunk/src/user32/win32wmdichild.h	(revision 9522)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* $Id: win32wmdichild.h,v 1.7 2000-01-27 21:50:03 sandervl Exp $ */
-/*
- * Win32 MDI Client Window Class for OS/2
- *
- * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
- *
- * Project Odin Software License can be found in LICENSE.TXT
- *
- */
-#ifndef __WIN32WMDICHILD_H__
-#define __WIN32WMDICHILD_H__
-
-#include <win32wbase.h>
-#include <mdi.h>
-
-class Win32MDIClientWindow;
-
-//******************************************************************************
-//******************************************************************************
-class Win32MDIChildWindow : public Win32BaseWindow
-{
-public:
-                Win32MDIChildWindow(CREATESTRUCTA *lpCreateStructA, ATOM classAtom, BOOL fUnicode);
-virtual        ~Win32MDIChildWindow();
-
-   static HWND  createChild(Win32MDIClientWindow *client, LPMDICREATESTRUCTA cs);
-           void childGetMinMaxInfo(MINMAXINFO* lpMinMax);
-
-           BOOL menuModifyItem();
-	   BOOL menuDeleteItem();
-
-virtual  BOOL   isMDIChild();
-
-        LRESULT DefMDIChildProcA(UINT Msg, WPARAM wParam, LPARAM lParam);
-        LRESULT DefMDIChildProcW(UINT Msg, WPARAM wParam, LPARAM lParam);
-
-   static  void calcDefaultChildPos(Win32MDIClientWindow *client, WORD n, LPPOINT lpPos, INT delta);
-private:
-
-   friend class Win32MDIClientWindow;
-};
-//******************************************************************************
-//******************************************************************************
-
-#endif //__WIN32WMDICHILD_H__
Index: trunk/src/user32/win32wmdiclient.cpp
===================================================================
--- trunk/src/user32/win32wmdiclient.cpp	(revision 9522)
+++ trunk/src/user32/win32wmdiclient.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: win32wmdiclient.cpp,v 1.40 2002-02-11 13:48:42 sandervl Exp $ */
+/* $Id: win32wmdiclient.cpp,v 1.41 2002-12-18 12:28:08 sandervl Exp $ */
 /*
  * Win32 MDI Client Window Class for OS/2
@@ -127,33 +127,4 @@
   return (FALSE); /* default */
 }
-
 //******************************************************************************
 //******************************************************************************
-BOOL MDICLIENT_Register()
-{
-    WNDCLASSA wndClass;
-
-//SvL: Don't check this now
-//    if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
-
-    ZeroMemory(&wndClass,sizeof(WNDCLASSA));
-    wndClass.style         = CS_GLOBALCLASS;
-    wndClass.lpfnWndProc   = (WNDPROC)MDIClientWndProcA;
-    wndClass.cbClsExtra    = 0;
-    wndClass.cbWndExtra    = 0;
-    wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);;
-    wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
-    wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
-
-    return RegisterClassA(&wndClass);
-}
-//******************************************************************************
-//******************************************************************************
-BOOL MDICLIENT_Unregister()
-{
-    if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
-            return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
-    else    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
Index: trunk/src/user32/windowclass.cpp
===================================================================
--- trunk/src/user32/windowclass.cpp	(revision 9522)
+++ trunk/src/user32/windowclass.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: windowclass.cpp,v 1.25 2002-02-11 16:06:00 sandervl Exp $ */
+/* $Id: windowclass.cpp,v 1.26 2002-12-18 12:28:08 sandervl Exp $ */
 /*
  * Win32 Window Class Code for OS/2
@@ -80,5 +80,5 @@
                                LR_COPYFROMRESOURCE);
 
-    wclass = new Win32WndClass(&wc,FALSE);
+    wclass = new Win32WndClass(&wc, WNDCLASS_ASCII);
     if(wclass == NULL) {
         dprintf(("ERROR: RegisterClassA winclass == NULL!"));
@@ -109,5 +109,5 @@
 
     dprintf(("RegisterClassExA"));
-    wclass = new Win32WndClass((WNDCLASSEXA *)lpWndClass,FALSE);
+    wclass = new Win32WndClass((WNDCLASSEXA *)lpWndClass, WNDCLASS_ASCII);
     if(wclass == NULL) {
         dprintf(("ERROR: RegisterClassExA winclass == NULL!"));
@@ -115,4 +115,49 @@
         return(0);
     }
+    ATOM atom = wclass->getAtom();
+    RELEASE_CLASSOBJ(wclass);
+    return atom;
+}
+//******************************************************************************
+//Used for user32 control class registration only
+//******************************************************************************
+ATOM WIN32API InternalRegisterClass(LPSTR lpszClassName, DWORD dwStyle,
+                                    WNDPROC pfnClassA, WNDPROC pfnClassW,
+                                    UINT cbExtraWindowWords, LPCSTR lpszCursor,
+                                    HBRUSH hBrush)
+{
+    WNDCLASSEXA wc;
+    Win32WndClass *wclass;
+
+    wclass = Win32WndClass::FindClass(0, lpszClassName);
+    if(wclass) {
+        RELEASE_CLASSOBJ(wclass);
+        DebugInt3(); //this must never happen
+        dprintf(("ERROR: InternalRegisterClass %s already exists", lpszClassName));
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return 0;
+    }
+
+    dprintf(("InternalRegisterClass %s %x %x %x %d %x %x", lpszClassName, dwStyle, pfnClassA, pfnClassW, cbExtraWindowWords, lpszCursor, hBrush));
+    wc.cbSize        = sizeof(wc);
+    wc.style         = dwStyle;
+    wc.lpfnWndProc   = pfnClassA;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = cbExtraWindowWords;
+    wc.hInstance     = NULL;
+    wc.hIcon         = 0;
+    wc.hCursor       = LoadCursorA(0, lpszCursor);
+    wc.hbrBackground = hBrush;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = lpszClassName;
+    wc.hIconSm       = 0;
+
+    wclass = new Win32WndClass(&wc, WNDCLASS_ASCII);
+    if(wclass == NULL) {
+        dprintf(("ERROR: InternalRegisterClass winclass == NULL!"));
+        DebugInt3();
+        return(0);
+    }
+    wclass->setWindowProc(pfnClassW, WNDPROC_UNICODE);
     ATOM atom = wclass->getAtom();
     RELEASE_CLASSOBJ(wclass);
@@ -154,5 +199,5 @@
 
     dprintf(("RegisterClassW"));
-    winclass = new Win32WndClass((WNDCLASSEXA *)&wc, TRUE);
+    winclass = new Win32WndClass((WNDCLASSEXA *)&wc, WNDCLASS_UNICODE);
     if(winclass == NULL) {
         dprintf(("ERROR: RegisterClassW winclass == NULL!"));
@@ -187,5 +232,5 @@
 
     dprintf(("RegisterClassExW"));
-    winclass = new Win32WndClass((WNDCLASSEXA *)&wc, TRUE);
+    winclass = new Win32WndClass((WNDCLASSEXA *)&wc, WNDCLASS_UNICODE);
     if(winclass == NULL) {
         dprintf(("ERROR: RegisterClassExW winclass == NULL!"));
Index: trunk/src/user32/wingdi.cpp
===================================================================
--- trunk/src/user32/wingdi.cpp	(revision 9522)
+++ 	(revision )
@@ -1,136 +1,0 @@
-/* $Id: wingdi.cpp,v 1.6 2000-02-16 14:28:27 sandervl Exp $ */
-/*
- * Win32 Window graphics apis for OS/2
- *
- *
- * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
- * Copyright 1999 Daniela Engert (dani@ngrt.de)
- *
- *
- * Project Odin Software License can be found in LICENSE.TXT
- *
- */
-#include <os2win.h>
-#include <misc.h>
-
-#include <win32wbase.h>
-#include <oslibwin.h>
-#include <oslibgdi.h>
-
-#define DBG_LOCALLOG	DBG_wingdi
-#include "dbglocal.h"
-
-#define OPEN32_GDI
-
-#if 0
-//******************************************************************************
-//TODO: Not complete
-//******************************************************************************
-HDC WIN32API BeginPaint(HWND hwnd, PPAINTSTRUCT lps)
-{
-  Win32BaseWindow *window;
-  HDC hdc;
-
-    window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-    if(!window) {
-    dprintf(("GetDC, window %x not found", hwnd));
-    return 0;
-    }
-// !! there is no HDC to paint on !!!    window->MsgEraseBackGround(hdc);
-#ifdef OPEN32_GDI
-    hdc = O32_BeginPaint(window->getOS2WindowHandle(),lps);
-    //CB: conflict with Open32 mechanism
-#else
-    hdc = OSLibWinBeginPaint(window->getOS2WindowHandle(), &lps->rcPaint);
-    lps->hdc = hdc;
-#endif
-    dprintf(("BeginPaint %X returned %x\n", hwnd, hdc));
-
-    lps->fErase = !window->MsgEraseBackGround(hdc);
-    return hdc;
-
-//    return lps->hdc;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WIN32API EndPaint(HWND hwnd, const PAINTSTRUCT *lps)
-{
-    dprintf(("EndPaint %x\n", hwnd));
-#ifdef OPEN32_GDI
-    return O32_EndPaint(hwnd,lps);
-    //CB: dito
-#else
-    return OSLibWinEndPaint(lps->hdc);
-#endif
-}
-
-//******************************************************************************
-//TODO: PARENT_DC flag
-//******************************************************************************
-HDC WIN32API GetDC(HWND hwnd)
-{
-  Win32BaseWindow *window;
-
-   window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-   if(!window) {
-    dprintf(("GetDC, window %x not found", hwnd));
-#ifdef OPEN32_GDI
-    dprintf(("GetDC %x", hwnd));
-    return O32_GetDC(0);
-#else
-    //desktop window?
-    dprintf(("GetDC %x", hwnd));
-    return OSLibWinGetPS(OSLIB_HWND_DESKTOP);
-#endif
-   }
-   dprintf(("GetDC %x", hwnd));
-#ifdef OPEN32_GDI
-   return O32_GetDC(window->getOS2WindowHandle());
-#else
-   return OSLibWinGetPS(window->getOS2WindowHandle());
-#endif
-}
-//******************************************************************************
-//TODO
-//******************************************************************************
-HDC WIN32API GetDCEx(HWND hwnd, HRGN arg2, DWORD arg3)
-{
-#ifdef DEBUG
-    WriteLog("USER32:  GetDCEx NOT CORRECT!\n");
-#endif
-    return GetDC(hwnd);
-}
-
-//******************************************************************************
-//******************************************************************************
-int WIN32API ReleaseDC(HWND hwnd, HDC hdc)
-{
-    dprintf(("ReleaseDC %x %x", hwnd, hdc));
-#ifdef OPEN32_GDI
-    return O32_ReleaseDC(hwnd,hdc);
-#else
-    return OSLibWinReleasePS(hdc);
-#endif
-}
-//******************************************************************************
-//******************************************************************************
-
-HDC WIN32API GetWindowDC(HWND hwnd)
-{
-  Win32BaseWindow *window;
-
-   window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-   if(!window) {
-        dprintf(("GetWindowDC, window %x not found", hwnd));
-        return 0;
-   }
-   dprintf(("GetWindowDC %x", hwnd));
-#ifdef OPEN32_GDI
-   return O32_GetWindowDC(window->getOS2FrameWindowHandle());
-#else
-   return OSLibWinGetPS(window->getOS2FrameWindowHandle());
-#endif
-}
-#endif
-//******************************************************************************
-//******************************************************************************
Index: trunk/src/user32/winmenu.cpp
===================================================================
--- trunk/src/user32/winmenu.cpp	(revision 9522)
+++ 	(revision )
@@ -1,1318 +1,0 @@
-/* $Id: winmenu.cpp,v 1.25 2000-01-18 20:11:17 sandervl Exp $ */
-
-/*
- * Win32 menu API functions for OS/2
- *
- * Copyright 1998 Sander van Leeuwen
- * Copyright 1998 Patrick Haller
- *
- * Parts ported from Wine:
- * Copyright 1993 Martin Ayotte
- * Copyright 1994 Alexandre Julliard
- * Copyright 1997 Morten Welinder
- *
- *
- * TODO: Set/GetMenu(Item)Info only partially implemented
- * TODO: Memory leak when deleting submenus
- * TODO: Check error nrs
- *
- * Project Odin Software License can be found in LICENSE.TXT
- *
- */
-#include <os2win.h>
-#include <odin.h>
-#include <odinwrap.h>
-#include <stdlib.h>
-#include <string.h>
-#include <win32wbase.h>
-#include "oslibmenu.h"
-#include "oslibwin.h"
-#include "winmenudef.h"
-
-ODINDEBUGCHANNEL(USER32)
-
-BOOL  ODIN_INTERNAL ODIN_InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
-BOOL  ODIN_INTERNAL ODIN_InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
-BOOL  ODIN_INTERNAL ODIN_InsertMenuItemA(HMENU,UINT,BOOL,const MENUITEMINFOA*);
-BOOL  ODIN_INTERNAL ODIN_InsertMenuItemW(HMENU,UINT,BOOL,const MENUITEMINFOW*);
-BOOL  ODIN_INTERNAL ODIN_AppendMenuA(HMENU,UINT,UINT,LPCSTR);
-BOOL  ODIN_INTERNAL ODIN_AppendMenuW(HMENU,UINT,UINT,LPCWSTR);
-HMENU ODIN_INTERNAL ODIN_CreateMenu(void);
-HMENU ODIN_INTERNAL ODIN_CreatePopupMenu(void);
-BOOL  ODIN_INTERNAL ODIN_DestroyMenu(HMENU);
-BOOL  ODIN_INTERNAL ODIN_DeleteMenu(HMENU, UINT, UINT);
-
-//@@@PH: experiment with WINE LoadMenuIndirect code
-#include <heapstring.h>
-#define MENU_ITEM_TYPE(flags) \
-  ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
-
-#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
-#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
-
-/**********************************************************************
- *         MENU_ParseResource
- *
- * Parse a standard menu resource and add items to the menu.
- * Return a pointer to the end of the resource.
- */
-static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
-{
-    WORD flags, id = 0;
-    LPCSTR str;
-
-    do
-    {
-        flags = GET_WORD(res);
-        res += sizeof(WORD);
-        if (!(flags & MF_POPUP))
-        {
-            id = GET_WORD(res);
-            res += sizeof(WORD);
-        }
-        if (!IS_STRING_ITEM(flags))
-            dprintf(("USER32: WinMenu: MENU_ParseResource: not a string item %04x\n", flags ));
-        str = res;
-
-        res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
-        if (flags & MF_POPUP)
-        {
-            HMENU hSubMenu = ODIN_CreatePopupMenu();
-            if (!hSubMenu) return NULL;
-            if (!(res = MENU_ParseResource( res, hSubMenu)))
-                return NULL;
-            ODIN_AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
-        }
-        else  /* Not a popup */
-        {
-            ODIN_AppendMenuW( hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL );
-        }
-    } while (!(flags & MF_END));
-    return res;
-}
-
-
-/**********************************************************************
- *         MENUEX_ParseResource
- *
- * Parse an extended menu resource and add items to the menu.
- * Return a pointer to the end of the resource.
- */
-static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
-{
-   WORD resinfo;
-
-    do {
-        MENUITEMINFOW mii;
-
-        mii.cbSize = sizeof(mii);
-        mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
-        mii.fType = GET_DWORD(res);
-        res += sizeof(DWORD);
-        mii.fState = GET_DWORD(res);
-        res += sizeof(DWORD);
-        mii.wID = GET_DWORD(res);
-        res += sizeof(DWORD);
-        resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte.  */
-        res += sizeof(WORD);
-
-        /* Align the text on a word boundary.  */
-        res += (~((int)res - 1)) & 1;
-        mii.dwTypeData = (LPWSTR) res;
-        res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
-        /* Align the following fields on a dword boundary.  */
-        res += (~((int)res - 1)) & 3;
-
-        /* FIXME: This is inefficient and cannot be optimised away by gcc.  */
-        {
-            LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(), 0, mii.dwTypeData);
-
-            dprintf(("USER32:WinMenu:MENUEX_ParseResource Menu item: [%08x,%08x,%04x,%04x,%s]\n",
-                     mii.fType, mii.fState, mii.wID, resinfo, newstr));
-            HeapFree( GetProcessHeap(), 0, newstr );
-        }
-
-        if (resinfo & 1) {                    /* Pop-up? */
-            /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
-            res += sizeof(DWORD);
-            mii.hSubMenu = ODIN_CreatePopupMenu();
-            if (!mii.hSubMenu)
-                return NULL;
-            if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
-                DestroyMenu(mii.hSubMenu);
-                return NULL;
-            }
-            mii.fMask |= MIIM_SUBMENU;
-            mii.fType |= MF_POPUP;
-        }
-        ODIN_InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
-    }
-    while (!(resinfo & MF_END));
-
-    return res;
-}
-/**********************************************************************
- *    myLoadMenuIndirect
- */
-HMENU myLoadMenuIndirect(LPCVOID pMenuTemplate)
-{
-  HMENU hMenu;
-  WORD  version,
-        offset;
-  LPCSTR p = (LPCSTR)pMenuTemplate;
-
-    version = GET_WORD(p);
-    p += sizeof(WORD);
-
-    switch (version)
-    {
-    case 0:
-        offset = GET_WORD(p);
-        p += sizeof(WORD) + offset;
-        if (!(hMenu = ODIN_CreateMenu()))
-            return 0;
-        if (!MENU_ParseResource( p, hMenu))
-        {
-            DestroyMenu( hMenu );
-            return 0;
-        }
-        return hMenu;
-
-    case 1:
-        offset = GET_WORD(p);
-        p += sizeof(WORD) + offset;
-        if (!(hMenu = ODIN_CreateMenu()))
-            return 0;
-        if (!MENUEX_ParseResource( p, hMenu))
-        {
-            ODIN_DestroyMenu( hMenu );
-            return 0;
-        }
-        return hMenu;
-
-    default:
-        dprintf(("USER32: LoadMenuIndirectA: version %d not supported.\n", version));
-        return 0;
-    }
-}
-//******************************************************************************
-//******************************************************************************
-void SetInternalMenuInfo(HMENU hMenu)
-{
-  LPPOPUPMENU lpMenuInfo;
-
-    lpMenuInfo = (LPPOPUPMENU)malloc(sizeof(*lpMenuInfo));
-    memset(lpMenuInfo, 0, sizeof(*lpMenuInfo));
-    OSLibWinSetWindowULong(hMenu, OSLIB_QWL_USER, (ULONG)lpMenuInfo);
-}
-//******************************************************************************
-//******************************************************************************
-LPPOPUPMENU GetInternalMenuInfo(HMENU hMenu)
-{
-    return (LPPOPUPMENU)OSLibWinGetWindowULong(hMenu, OSLIB_QWL_USER);
-}
-//******************************************************************************
-//******************************************************************************
-void DeleteInternalMenuInfo(HMENU hMenu)
-{
-  LPPOPUPMENU lpMenuInfo;
-
-    lpMenuInfo = (LPPOPUPMENU)OSLibWinGetWindowULong(hMenu, OSLIB_QWL_USER);
-    if(lpMenuInfo) {
-        free(lpMenuInfo);
-        OSLibWinSetWindowULong(hMenu, OSLIB_QWL_USER, 0);
-    }
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION0(HMENU, CreateMenu)
-{
-  HMENU hMenu;
-
-    dprintf(("USER32: CreateMenu\n"));
-
-    hMenu = OSLibWinCreateEmptyMenu();
-    if(hMenu) {
-            SetInternalMenuInfo(hMenu);
-    }
-    else    SetLastError(ERROR_INVALID_PARAMETER); //wrong error
-
-    return hMenu;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION0(HMENU, CreatePopupMenu)
-{
-  HMENU hMenu;
-
-    dprintf(("USER32: CreatePopupMenu\n"));
-
-    hMenu = OSLibWinCreateEmptyPopupMenu();
-    if(hMenu) {
-            SetInternalMenuInfo(hMenu);
-    }
-    else    SetLastError(ERROR_INVALID_PARAMETER); //wrong error
-
-    return hMenu;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(HMENU,     LoadMenuA,
-              HINSTANCE, hinst,
-              LPCSTR,    lpszMenu)
-{
-  Win32Resource *winres;
-  HMENU hMenu;
-
-    winres = (Win32Resource *)FindResourceA(hinst, lpszMenu, RT_MENUA);
-    if(winres)
-    {
-        hMenu = myLoadMenuIndirect((MENUITEMTEMPLATEHEADER *)winres->lockResource());
-        if(hMenu) {
-                SetInternalMenuInfo(hMenu);
-        }
-        else    SetLastError(ERROR_INVALID_PARAMETER);
-
-        delete winres;
-        return hMenu;
-    }
-    return 0;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(HMENU, LoadMenuW,
-              HINSTANCE, hinst,
-              LPCWSTR, lpszMenu)
-{
-  Win32Resource *winres;
-  HMENU hMenu;
-
-    winres = (Win32Resource *)FindResourceW(hinst, lpszMenu, RT_MENUW);
-    if(winres) {
-        hMenu = myLoadMenuIndirect((MENUITEMTEMPLATEHEADER *)winres->lockResource());
-        if(hMenu) {
-                SetInternalMenuInfo(hMenu);
-        }
-        else    SetLastError(ERROR_INVALID_PARAMETER);
-
-        delete winres;
-        return hMenu;
-    }
-    return 0;
-}
-//******************************************************************************
-//NOTE: menutemplate strings are always in Unicode format
-//******************************************************************************
-ODINFUNCTION1(HMENU, LoadMenuIndirectW,
-              const MENUITEMTEMPLATEHEADER *, menuTemplate)
-{
-  HMENU hMenu;
-
-    hMenu = myLoadMenuIndirect(menuTemplate);
-    if(hMenu) {
-            SetInternalMenuInfo(hMenu);
-    }
-    else    SetLastError(ERROR_INVALID_PARAMETER);
-
-    return (HMENU)hMenu;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION1(BOOL,  DestroyMenu,
-              HMENU, hMenu)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    DeleteInternalMenuInfo(hMenu);
-    return O32_DestroyMenu(hMenu);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION1(HMENU, GetMenu,
-              HWND,  hwnd)
-{
-  Win32BaseWindow *window;
-
-    window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-    if(!window)
-    {
-        dprintf(("GetMenu, window %x not found", hwnd));
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return 0;
-    }
-
-    return window->GetMenu();
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(BOOL,  SetMenu,
-              HWND,  hwnd,
-              HMENU, hMenu)
-{
-  Win32BaseWindow *window;
-
-    window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-    if(!window)
-    {
-        dprintf(("SetMenu, window %x not found", hwnd));
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return 0;
-    }
-
-    window->SetMenu(hMenu);
-    return TRUE;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION0(DWORD, GetMenuCheckMarkDimensions)
-{
-  return O32_GetMenuCheckMarkDimensions();
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION1(int,   GetMenuItemCount,
-              HMENU, hMenu)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return OSLibGetMenuItemCount(hMenu);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(UINT,  GetMenuItemID,
-              HMENU, hMenu,
-              int,   nPos)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return O32_GetMenuItemID(hMenu, nPos);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(UINT,  GetMenuState,
-              HMENU, hMenu,
-              UINT,  arg2,
-              UINT,  arg3)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_GetMenuState(hMenu, arg2, arg3);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(int,   GetMenuStringA,
-              HMENU, hMenu,
-              UINT,  idItem,
-              LPSTR, lpsz,
-              int,   cchMax,
-              UINT,  fuFlags)
-{
- int rc, nritems;
-
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    if(!lpsz || !cchMax) {//determine menu string length
-        char menustr[256];
-        rc = O32_GetMenuString(hMenu, idItem, menustr, sizeof(menustr), fuFlags);
-        //SvL: Open32 returns the wrong error
-        return (rc == -1) ? 0 : rc;
-    }
-    rc = O32_GetMenuString(hMenu, idItem, lpsz, cchMax, fuFlags);
-    //SvL: Open32 returns the wrong error
-    return (rc == -1) ? 0 : rc;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(int,   GetMenuStringW,
-              HMENU, hMenu,
-              UINT,  idItem,
-              LPWSTR,lpsz,
-              int,   cchMax,
-              UINT,  fuFlags)
-{
-  char *astring = (char *)malloc(cchMax);
-  int   rc;
-
-    rc = ODIN_GetMenuStringA(hMenu, idItem, astring, cchMax, fuFlags);
-    if(rc)
-    {
-            dprintf(("USER32: GetMenuStringW %s\n", astring));
-            AsciiToUnicode(astring, lpsz);
-    }
-    else    lpsz[0] = 0;
-    free(astring);
-
-    return(rc);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, SetMenuItemBitmaps,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3,
-              HBITMAP, arg4,
-              HBITMAP, arg5)
-{
-    dprintf(("USER32:  SetMenuItemBitmaps\n"));
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return O32_SetMenuItemBitmaps(hMenu, arg2, arg3, arg4, arg5);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(HMENU, GetSubMenu,
-              HWND, hMenu,
-              int, arg2)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_GetSubMenu(hMenu, arg2);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(HMENU, GetSystemMenu,
-              HWND,  hSystemWindow,
-              BOOL,  bRevert)
-{
-    Win32BaseWindow *window;
-
-    window = Win32BaseWindow::GetWindowFromHandle(hSystemWindow);
-    if(!window)
-    {
-        dprintf(("GetSystemMenu, window %x not found", hSystemWindow));
-        return 0;
-    }
-
-    return window->GetSystemMenu(bRevert);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION1(BOOL, IsMenu,
-              HMENU, hMenu)
-{
-    dprintf(("USER32:  IsMenu\n"));
-    return O32_IsMenu(hMenu);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION7(BOOL, TrackPopupMenu,
-              HMENU, hMenu,
-              UINT, arg2,
-              int, arg3,
-              int, arg4,
-              int, arg5,
-              HWND, arg6,
-              const RECT *, arg7)
-{
-  Win32BaseWindow *window;
-
-    window = Win32BaseWindow::GetWindowFromHandle(arg6);
-    if(!window)
-    {
-        dprintf(("TrackPopupMenu, window %x not found", arg6));
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return 0;
-    }
-    dprintf(("USER32:  TrackPopupMenu\n"));
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return O32_TrackPopupMenu(hMenu, arg2, arg3, arg4, arg5, window->getOS2WindowHandle(),
-                              arg7);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION6(BOOL, TrackPopupMenuEx,
-              HMENU, hMenu,
-              UINT, flags,
-              int, X,
-              int, Y,
-              HWND, hwnd,
-              LPTPMPARAMS, lpPM)
-{
-  RECT *rect = NULL;
-  Win32BaseWindow *window;
-
-    window = Win32BaseWindow::GetWindowFromHandle(hwnd);
-    if(!window)
-    {
-        dprintf(("TrackPopupMenu, window %x not found", hwnd));
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return 0;
-    }
-
-    dprintf(("USER32:  TrackPopupMenuEx, not completely implemented\n"));
-
-    if (lpPM != NULL) // this parameter can be NULL
-      if(lpPM->cbSize != 0)
-        rect = &lpPM->rcExclude;
-
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return O32_TrackPopupMenu(hMenu, flags, X, Y, 0, window->getOS2WindowHandle(), rect);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION4(BOOL, AppendMenuA,
-              HMENU, hMenu,
-              UINT, uFlags,
-              UINT, id,
-              LPCSTR, lpNewItem)
-{
-     return ODIN_InsertMenuA( hMenu, -1, uFlags | MF_BYPOSITION, id, lpNewItem );
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION4(BOOL, AppendMenuW,
-              HMENU, hMenu,
-              UINT, uFlags,
-              UINT, id,
-              LPCWSTR, lpNewItem)
-{
-     return ODIN_InsertMenuW( hMenu, -1, uFlags | MF_BYPOSITION, id, lpNewItem );
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(DWORD, CheckMenuItem,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    return O32_CheckMenuItem(hMenu, arg2, arg3);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(BOOL,EnableMenuItem,HMENU,hMenu,
-                                  UINT, uIDEnableItem,
-                                  UINT, uEnable)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_EnableMenuItem(hMenu,
-                              uIDEnableItem,
-                              uEnable);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, ModifyMenuA,
-              HMENU, hMenu,
-              UINT, uItem,
-              UINT, fuFlags,
-              UINT, idNewItem,
-              LPCSTR, lpszNewItem)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    if(IS_STRING_ITEM(fuFlags) && HIWORD(lpszNewItem) != 0) {
-        dprintf(("ModifyMenuA %s", lpszNewItem));
-    }
-/* //CB: doesn't compile, but don't need it anyway
-    if(((fuFlags & (MF_BYCOMMAND|MF_BYPOSITION|MF_POPUP)) == MF_BYCOMMAND) && uItem != idNewItem) {
-        DWORD pos = OSLibGetMenuItemPos(hMenu, uItem);
-        ODIN_DeleteMenu(hMenu, uItem, MF_BYCOMMAND);
-        return ODIN_InsertMenuA(hMenu, pos, fuFlags | MF_BYPOSITION, idNewItem, lpszNewItem);
-    }
-*/
-    return O32_ModifyMenu(hMenu, uItem, fuFlags, idNewItem, lpszNewItem);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, ModifyMenuW,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3,
-              UINT, arg4,
-              LPCWSTR, arg5)
-{
- BOOL  rc;
- char *astring = NULL;
-
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    if(IS_STRING_ITEM(arg3) && HIWORD(arg5) != 0)
-      astring = UnicodeToAsciiString((LPWSTR)arg5);
-    else
-      astring = (char *) arg5;
-
-    rc = ODIN_ModifyMenuA(hMenu, arg2, arg3, arg4, astring);
-    if(IS_STRING_ITEM(arg3) && HIWORD(arg5) != 0)
-      FreeAsciiString(astring);
-
-    return(rc);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(BOOL, RemoveMenu,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_RemoveMenu(hMenu, arg2, arg3);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(BOOL, DeleteMenu,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3)
-{
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_DeleteMenu(hMenu, arg2, arg3);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION4(BOOL, HiliteMenuItem,
-              HWND, hMenu,
-              HMENU, arg2,
-              UINT, arg3,
-              UINT, arg4)
-{
-    dprintf(("USER32:  OS2HiliteMenuItem\n"));
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    return O32_HiliteMenuItem(hMenu, arg2, arg3, arg4);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, InsertMenuA,
-              HMENU, hMenu,
-              UINT, pos,
-              UINT, flags,
-              UINT, id,
-              LPCSTR, str)
-{
-    if(IS_STRING_ITEM(flags) && HIWORD(str)) {
-         dprintf(("USER32: InsertMenuA %x %d %x %d %s", hMenu, pos, flags, id, str));
-    }
-    else dprintf(("USER32: InsertMenuA %x %d %x %d %x", hMenu, pos, flags, id, str));
-
-    if(hMenu == 0)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    if(IS_STRING_ITEM(flags) && (!str || *str == NULL)) {
-        flags |= MF_SEPARATOR;
-    }
-    //SvL: RealPlayer calls InsertMenu with flag 0 & pos -1
-    if((flags & (MF_BYCOMMAND|MF_BYPOSITION)) == 0 && (pos == 0xffffffff))
-        flags |= MF_BYPOSITION;
-
-    return O32_InsertMenu(hMenu, pos, flags, id, str);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, InsertMenuW,
-              HMENU, hMenu,
-              UINT, arg2,
-              UINT, arg3,
-              UINT, arg4,
-              LPCWSTR, arg5)
-{
- BOOL  rc;
- char *astring = NULL;
-
-    if(IS_STRING_ITEM(arg3) && HIWORD(arg5) != 0)
-      astring = UnicodeToAsciiString((LPWSTR)arg5);
-    else
-      astring = (char *) arg5;
-
-    rc = ODIN_InsertMenuA(hMenu, arg2, arg3, arg4, astring);
-
-    if(IS_STRING_ITEM(arg3) && HIWORD(arg5) != 0)
-      FreeAsciiString(astring);
-
-    return(rc);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION2(BOOL, SetMenuContextHelpId,
-              HMENU, hMenu,
-              DWORD, dwContextHelpId)
-{
- POPUPMENU *menu;
-
-    menu = GetInternalMenuInfo(hMenu);
-    if(menu == NULL) {
-        dprintf(("USER32: SetMenuContextHelpId(%x) No POPUPMENU structure found!", hMenu));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    dprintf(("USER32:  SetMenuContextHelpId %x %d", hMenu, dwContextHelpId));
-    menu->dwContextHelpID = dwContextHelpId;
-    return(TRUE);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION1(DWORD, GetMenuContextHelpId,
-              HMENU, hMenu)
-{
- POPUPMENU *menu;
-
-    menu = GetInternalMenuInfo(hMenu);
-    if(menu == NULL) {
-        dprintf(("USER32: GetMenuContextHelpId(%x) No POPUPMENU structure found!", hMenu));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-    dprintf(("USER32:  GetMenuContextHelpId %x %d", hMenu, menu->dwContextHelpID));
-    return menu->dwContextHelpID;
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, CheckMenuRadioItem,
-              HMENU, hMenu,
-              UINT, idFirst,
-              UINT, idLast,
-              UINT, idCheck,
-              UINT, uFlags)
-{
-  dprintf(("USER32:  OS2CheckMenuRadioItem, not implemented\n"));
-  return(TRUE);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, ChangeMenuA,
-              HMENU, hMenu,
-              UINT, pos,
-              LPCSTR, data,
-              UINT, id,
-              UINT, flags)
-{
-    dprintf(("USER32:  ChangeMenuA flags %X\n", flags));
-
-    if (flags & MF_APPEND) return ODIN_AppendMenuA(hMenu, flags & ~MF_APPEND,
-                                                   id, data );
-    if (flags & MF_DELETE) return ODIN_DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
-    if (flags & MF_CHANGE) return ODIN_ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
-                                                   id, data );
-    if (flags & MF_REMOVE) return ODIN_RemoveMenu(hMenu,
-                                                  flags & MF_BYPOSITION ? pos : id,
-                                                  flags & ~MF_REMOVE );
-    /* Default: MF_INSERT */
-    return InsertMenuA( hMenu, pos, flags, id, data );
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION5(BOOL, ChangeMenuW,
-              HMENU, hMenu,
-              UINT, pos,
-              LPCWSTR, data,
-              UINT, id,
-              UINT, flags)
-{
-    dprintf(("USER32:  ChangeMenuW flags %X\n", flags));
-
-    if (flags & MF_APPEND) return ODIN_AppendMenuW(hMenu, flags & ~MF_APPEND,
-                                                   id, data );
-    if (flags & MF_DELETE) return ODIN_DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
-    if (flags & MF_CHANGE) return ODIN_ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
-                                                   id, data );
-    if (flags & MF_REMOVE) return ODIN_RemoveMenu(hMenu,
-                                                  flags & MF_BYPOSITION ? pos : id,
-                                                     flags & ~MF_REMOVE );
-    /* Default: MF_INSERT */
-    return InsertMenuW(hMenu, pos, flags, id, data);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION4(BOOL, SetMenuItemInfoA,
-              HMENU, hMenu,
-              UINT, par1,
-              BOOL, par2,
-              const MENUITEMINFOA *, lpmii)
-{
-    dprintf(("USER32:  SetMenuItemInfoA faked %x", hMenu));
-
-    if (!hMenu) {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    return TRUE;
-}
-/*****************************************************************************
- * Function  : SetMenuItemInfoW
- * Purpose   : The SetMenuItemInfo function changes information about a menu item.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is TRUE.
- *             If the function fails, the return value is FALSE. To get extended
- *               error information, use the GetLastError function.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION4(BOOL, SetMenuItemInfoW,
-              HMENU, hMenu,
-              UINT, uItem,
-              BOOL, fByPosition,
-              const MENUITEMINFOW *, lpmmi)
-{
-  dprintf(("USER32:SetMenuItemInfoW (%08xh,%08xh,%08xh,%08x) not implemented.\n",
-         hMenu,
-         uItem,
-         fByPosition,
-         lpmmi));
-
-  return (SetMenuItemInfoA(hMenu,
-                           uItem,
-                           fByPosition,
-                           (const MENUITEMINFOA *)lpmmi));
-}
-/*****************************************************************************
- * Function  : GetMenuDefaultItem
- * Purpose   : TheGetMenuDefaultItem function determines the default menu item
- *             on the specified menu.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is the identifier or
- *             position of the menu item.
- *             If the function fails, the return value is - 1.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION3(UINT, GetMenuDefaultItem,
-              HMENU, hMenu,
-              UINT, fByPos,
-              UINT, gmdiFlags)
-{
-  dprintf(("USER32:GetMenuDefaultItem (%08xh,%u,%08x) not implemented.\n",
-         hMenu,
-         fByPos,
-         gmdiFlags));
-
-  return (-1);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION3(BOOL, SetMenuDefaultItem,
-              HMENU, hMenu,
-              UINT, uItem,
-              UINT, fByPos)
-{
-    dprintf(("USER32:  SetMenuDefaultItem, faked\n"));
-    return(TRUE);
-}
-//******************************************************************************
-//******************************************************************************
-BOOL GetMenuItemInfoAW(HMENU hMenu, UINT uItem, BOOL byPos, MENUITEMINFOA *lpmii, BOOL unicode)
-{
-    if(byPos) {
-        uItem = GetMenuItemID(hMenu, uItem);
-    }
-    if(ODIN_GetMenuState(hMenu, uItem, MF_BYCOMMAND) == -1) {
-        //item doesn't exist
-        dprintf(("USER32:  GetMenuItemInfoAW %x item %d doesn't exist", hMenu, uItem));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    if (lpmii->fMask & MIIM_TYPE)
-    {
-        lpmii->fType = ODIN_GetMenuState(hMenu, uItem, MF_BYCOMMAND); //not correct
-//      lpmii->fType = menu->fType;
-        if (unicode) {
-            lpmii->cch = ODIN_GetMenuStringW(hMenu, uItem, (LPWSTR)lpmii->dwTypeData, lpmii->cch, MF_BYCOMMAND);
-        }
-        else {
-            lpmii->cch = ODIN_GetMenuStringA(hMenu, uItem, (LPSTR)lpmii->dwTypeData, lpmii->cch, MF_BYCOMMAND);
-        }
-//TODO:
-#if 0
-        switch (MENU_ITEM_TYPE(menu->fType)) {
-        case MF_STRING:
-            if (menu->text && lpmii->dwTypeData && lpmii->cch) {
-                if (unicode) {
-                    lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text, lpmii->cch);
-                    lpmii->cch = lstrlenW((LPWSTR)menu->text);
-                }
-                else {
-                    lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
-                    lpmii->cch = lstrlenA(menu->text);
-                }
-            }
-            break;
-        case MF_OWNERDRAW:
-        case MF_BITMAP:
-            lpmii->dwTypeData = menu->text;
-            /* fall through */
-        default:
-            lpmii->cch = 0;
-        }
-#endif
-    }
-
-    if (lpmii->fMask & MIIM_STRING) {
-        if (unicode) {
-            lpmii->cch = ODIN_GetMenuStringW(hMenu, uItem, (LPWSTR)lpmii->dwTypeData, lpmii->cch, MF_BYCOMMAND);
-        }
-        else {
-            lpmii->cch = ODIN_GetMenuStringA(hMenu, uItem, (LPSTR)lpmii->dwTypeData, lpmii->cch, MF_BYCOMMAND);
-        }
-    }
-
-//TODO:
-#if 0
-    if (lpmii->fMask & MIIM_FTYPE)
-        lpmii->fType = menu->fType;
-
-    if (lpmii->fMask & MIIM_BITMAP)
-        lpmii->hbmpItem = menu->hbmpItem;
-#endif
-
-    if (lpmii->fMask & MIIM_STATE)
-        lpmii->fState = ODIN_GetMenuState(hMenu, uItem, MF_BYCOMMAND);
-
-    if (lpmii->fMask & MIIM_ID)
-        lpmii->wID = uItem;
-
-//TODO:
-#if 1
-    lpmii->hSubMenu = 0;
-    lpmii->hbmpChecked = 0;
-    lpmii->hbmpUnchecked = 0;
-    lpmii->dwItemData = 0;
-#else
-    if (lpmii->fMask & MIIM_SUBMENU)
-        lpmii->hSubMenu = ODIN_GetSubMenu(hMenu, uItem); //need index, not id
-
-    if (lpmii->fMask & MIIM_CHECKMARKS) {
-        lpmii->hbmpChecked = menu->hCheckBit;
-        lpmii->hbmpUnchecked = menu->hUnCheckBit;
-    }
-    if (lpmii->fMask & MIIM_DATA)
-        lpmii->dwItemData = menu->dwItemData;
-#endif
-
-    return(FALSE);
-}
-//******************************************************************************
-//******************************************************************************
-ODINFUNCTION4(BOOL, GetMenuItemInfoA,
-              HMENU, hMenu,
-              UINT, uItem,
-              BOOL, byPos,
-              MENUITEMINFOA *, lpMenuItemInfo)
-{
-    return GetMenuItemInfoAW(hMenu, uItem, byPos, lpMenuItemInfo, FALSE);
-}
-/*****************************************************************************
- * Function  : GetMenuItemInfoW
- * Purpose   : The GetMenuItemInfo function retrieves information about a menu item.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is TRUE.
- *             If the function fails, the return value is FALSE. To get extended
- *             error information, use the GetLastError function.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION4(BOOL, GetMenuItemInfoW,
-              HMENU, hMenu,
-              UINT, uItem,
-              BOOL, byPos,
-              MENUITEMINFOW *, lpMenuItemInfo)
-{
-    return GetMenuItemInfoAW(hMenu, uItem, byPos, (MENUITEMINFOA*)lpMenuItemInfo, TRUE);
-}
-/*****************************************************************************
- * Function  : GetMenuItemRect
- * Purpose   : The GetMenuItemRect function retrieves the bounding rectangle
- *             for the specified menu item.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is TRUE.
- *             If the function fails, the return value is FALSE. To get
- *             extended error information, use the GetLastError function.
- * Remark    :
- * Status    :
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-BOOL GetMenuItemRect(HWND hwnd, HMENU hMenu, UINT uItem, LPRECT lprcItem)
-{
- BOOL rc;
-
-    rc = OSLibGetMenuItemRect(hMenu, uItem, lprcItem);
-    dprintf(("GetMenuItemRect %x %x %x (%d,%d)(%d,%d)", hwnd, hMenu, uItem, lprcItem->top, lprcItem->left, lprcItem->bottom, lprcItem->right));
-    return rc;
-}
-/*****************************************************************************
- * Function  : InsertMenuItemA
- * Purpose   : The InsertMenuItem function inserts a new menu item at the specified
- *             position in a menu bar or pop-up menu.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is TRUE.
- *             If the function fails, the return value is FALSE. To get extended
- *             error information, use the GetLastError function.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION4(BOOL, InsertMenuItemA,
-              HMENU, hMenu,
-              UINT, uItem,
-              BOOL, fByPosition,
-              const MENUITEMINFOA*, lpmii)
-{
- DWORD dwType;
- BOOL rc;
-
-    dprintf(("USER32:InsertMenuItemA (%08xh,%08xh,%u,%08x) not correctly implemented.\n",
-         hMenu,
-         uItem,
-         fByPosition,
-         lpmii));
-
-    if(fByPosition) {
-            dwType = lpmii->fType | MF_BYPOSITION;
-    }
-    else    dwType = lpmii->fType | MF_BYCOMMAND;
-
-    if(lpmii->fMask & MIIM_SUBMENU && lpmii->hSubMenu) {
-        rc &= ODIN_InsertMenuA(hMenu, uItem, dwType | MF_POPUP, lpmii->hSubMenu, lpmii->dwTypeData);
-    }
-    else
-    if(lpmii->fMask & MIIM_ID) {
-        rc = ODIN_InsertMenuA(hMenu, uItem, dwType, lpmii->wID, lpmii->dwTypeData);
-    }
-    if(lpmii->fMask & MIIM_STATE) {
-    //TODO
-    }
-    return rc;
-}
-
-
-/*****************************************************************************
- * Function  : InsertMenuItemW
- * Purpose   : The InsertMenuItem function inserts a new menu item at the specified
- *             position in a menu bar or pop-up menu.
- * Parameters:
- * Variables :
- * Result    : If the function succeeds, the return value is TRUE.
- *             If the function fails, the return value is FALSE. To get extended
- *             error information, use the GetLastError function.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION4(BOOL, InsertMenuItemW,
-              HMENU, hMenu,
-              UINT, uItem,
-              BOOL, fByPosition,
-              const MENUITEMINFOW *, lpmii)
-{
-    dprintf(("USER32:InsertMenuItemW (%08xh,%08xh,%u,%08x) not correctly implemented.\n",
-         hMenu,
-         uItem,
-         fByPosition,
-         lpmii));
-
-    if(fByPosition) {
-            return ODIN_InsertMenuW(hMenu, uItem, lpmii->fType | MF_BYPOSITION, (lpmii->fType & MF_POPUP) ? lpmii->hSubMenu : lpmii->wID, lpmii->dwTypeData);
-    }
-    else    return ODIN_InsertMenuW(hMenu, uItem, lpmii->fType | MF_BYCOMMAND, (lpmii->fType & MF_POPUP) ? lpmii->hSubMenu : lpmii->wID, lpmii->dwTypeData);
-}
-/*****************************************************************************
- * Function  : MenuItemFromPoint
- * Purpose   : TheMenuItemFromPoint function determines which menu item, if
- *             any, is at the specified location.
- * Parameters:
- * Variables :
- * Result    : Returns the zero-based position of the menu item at the specified
- *             location or -1 if no menu item is at the specified location.
- * Remark    :
- * Status    : UNTESTED STUB
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION3(UINT, MenuItemFromPoint,
-              HWND, hWnd,
-              HMENU, hMenu,
-              POINT, ptScreen)
-{
-  dprintf(("USER32:MenuItemFromPoint (%08xh,%08xh,%u) not implemented.\n",
-         hWnd,
-         hMenu,
-         ptScreen));
-
-  return (-1);
-}
-
-
-/*****************************************************************************
- * Function  :  GetMenuInfo
- * Parameters:
- * Variables :
- * Result    :
- * Remark    :
- * Status    : UNTESTED STUB win98/NT5.0
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION2(BOOL, GetMenuInfo,
-              HMENU, hMenu,
-              LPMENUINFO, lpmi)
-{
- POPUPMENU *menu;
-
-    menu = GetInternalMenuInfo(hMenu);
-    if(menu == NULL) {
-        dprintf(("USER32: GetMenuInfo(%08xh,%08xh) No POPUPMENU structure found!", hMenu, lpmi));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    dprintf(("USER32: GetMenuInfo(%08xh,%08xh)", hMenu, lpmi));
-
-    if (lpmi)
-    {
-        if (lpmi->fMask & MIM_BACKGROUND)
-            lpmi->hbrBack = menu->hbrBack;
-
-        if (lpmi->fMask & MIM_HELPID)
-            lpmi->dwContextHelpID = menu->dwContextHelpID;
-
-        if (lpmi->fMask & MIM_MAXHEIGHT)
-            lpmi->cyMax = menu->cyMax;
-
-        if (lpmi->fMask & MIM_MENUDATA)
-            lpmi->dwMenuData = menu->dwMenuData;
-
-        if (lpmi->fMask & MIM_STYLE)
-            lpmi->dwStyle = menu->dwStyle;
-
-        return TRUE;
-    }
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return FALSE;
-}
-/*****************************************************************************
- * Function  :  SetMenuInfo
- * Purpose   :
- * Parameters:
- * Variables :
- * Result    :
- * Remark    :
- * FIXME
- * MIM_APPLYTOSUBMENUS
- * actually use the items to draw the menu
- * Status    : UNTESTED STUB win98/NT5.0
- *
- * Author    : Patrick Haller [Thu, 1998/02/26 11:55]
- *****************************************************************************/
-
-ODINFUNCTION2(BOOL, SetMenuInfo,
-              HMENU, hMenu,
-              LPCMENUINFO, lpmi)
-{
- POPUPMENU *menu;
-
-    menu = GetInternalMenuInfo(hMenu);
-    if(menu == NULL) {
-        dprintf(("USER32: SetMenuInfo(%08xh,%08xh) No POPUPMENU structure found!", hMenu, lpmi));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    dprintf(("USER32: SetMenuInfo(%08xh,%08xh)", hMenu, lpmi));
-
-    if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)))
-    {
-        if (lpmi->fMask & MIM_BACKGROUND)
-            menu->hbrBack = lpmi->hbrBack;
-
-        if (lpmi->fMask & MIM_HELPID)
-            menu->dwContextHelpID = lpmi->dwContextHelpID;
-
-        if (lpmi->fMask & MIM_MAXHEIGHT)
-            menu->cyMax = lpmi->cyMax;
-
-        if (lpmi->fMask & MIM_MENUDATA)
-            menu->dwMenuData = lpmi->dwMenuData;
-
-        if (lpmi->fMask & MIM_STYLE)
-            menu->dwStyle = lpmi->dwStyle;
-
-        return TRUE;
-    }
-    SetLastError(ERROR_INVALID_PARAMETER);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-
Index: trunk/src/user32/winmenudef.h
===================================================================
--- trunk/src/user32/winmenudef.h	(revision 9522)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/* $Id: winmenudef.h,v 1.3 2000-01-18 20:08:18 sandervl Exp $ */
-
-/*
- * Win32 menu API functions for OS/2
- *
- * Copyright 1998 Sander van Leeuwen
- * Copyright 1998 Patrick Haller
- *
- * Parts ported from Wine: 
- * Copyright 1993 Martin Ayotte
- * Copyright 1994 Alexandre Julliard
- * Copyright 1997 Morten Welinder
- *
- *
- * Project Odin Software License can be found in LICENSE.TXT
- *
- */
-
-#ifndef __WINMENUDEF_H__
-#define __WINMENUDEF_H__
-
-/* Menu item structure */
-typedef struct {
-    /* ----------- MENUITEMINFO Stuff ----------- */
-    UINT fType;			/* Item type. */
-    UINT fState;		/* Item state.  */
-    UINT wID;			/* Item id.  */
-    HMENU hSubMenu;		/* Pop-up menu.  */
-    HBITMAP hCheckBit;		/* Bitmap when checked.  */
-    HBITMAP hUnCheckBit;	/* Bitmap when unchecked.  */
-    LPSTR text;			/* Item text or bitmap handle.  */
-    DWORD dwItemData;		/* Application defined.  */
-    DWORD dwTypeData;		/* depends on fMask */
-    HBITMAP hbmpItem;		/* bitmap in win98 style menus */
-    /* ----------- Wine stuff ----------- */
-    RECT      rect;		/* Item area (relative to menu window) */
-    UINT      xTab;		/* X position of text after Tab */
-} MENUITEM;
-
-/* Popup menu structure */
-typedef struct {
-    WORD        wFlags;       /* Menu flags (MF_POPUP, MF_SYSMENU) */
-    WORD        wMagic;       /* Magic number */
-    HQUEUE16    hTaskQ;       /* Task queue for this menu */
-    WORD	Width;        /* Width of the whole menu */
-    WORD	Height;       /* Height of the whole menu */
-    WORD	nItems;       /* Number of items in the menu */
-    HWND        hWnd;         /* Window containing the menu */
-    MENUITEM    *items;       /* Array of menu items */
-    UINT        FocusedItem;  /* Currently focused item */
-    HWND	hwndOwner;    /* window receiving the messages for ownerdraw */
-    /* ------------ MENUINFO members ------ */
-    DWORD	dwStyle;	/* Extended mennu style */
-    UINT	cyMax;		/* max hight of the whole menu, 0 is screen hight */
-    HBRUSH	hbrBack;	/* brush for menu background */
-    DWORD	dwContextHelpID;
-    DWORD	dwMenuData;	/* application defined value */
-    HMENU       hSysMenuOwner;  /* Handle to the dummy sys menu holder */
-} POPUPMENU, *LPPOPUPMENU;
-
-#endif //__WINMENUDEF_H__
Index: trunk/src/user32/wndmsg.cpp
===================================================================
--- trunk/src/user32/wndmsg.cpp	(revision 9522)
+++ trunk/src/user32/wndmsg.cpp	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: wndmsg.cpp,v 1.18 2002-06-03 13:37:19 sandervl Exp $ */
+/* $Id: wndmsg.cpp,v 1.19 2002-12-18 12:28:08 sandervl Exp $ */
 /*
  * Win32 window message text function for OS/2
@@ -15,4 +15,5 @@
 #include <win\winmfcmsg.h>
 #include <spy.h>
+#include "wndmsg.h"
 
 #define DBG_LOCALLOG	DBG_wndmsg
Index: trunk/src/user32/wndmsg.h
===================================================================
--- trunk/src/user32/wndmsg.h	(revision 9522)
+++ trunk/src/user32/wndmsg.h	(revision 9523)
@@ -1,3 +1,3 @@
-/* $Id: wndmsg.h,v 1.6 2000-01-18 20:08:18 sandervl Exp $ */
+/* $Id: wndmsg.h,v 1.7 2002-12-18 12:28:08 sandervl Exp $ */
 /*
  * Win32 window message text function for OS/2
@@ -12,6 +12,11 @@
 #define __WNDMSG_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef DEBUG
 char *GetMsgText(int Msg);
+
 void DebugPrintMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, BOOL fInternalMsg);
 #else
@@ -19,3 +24,7 @@
 #endif
 
+#ifdef __cplusplus
+}
 #endif
+
+#endif
