Small additions, not yet finished
authorBoudewijn Dekker <ariadne@xs4all.nl>
Fri, 20 Aug 1999 09:37:25 +0000 (09:37 +0000)
committerBoudewijn Dekker <ariadne@xs4all.nl>
Fri, 20 Aug 1999 09:37:25 +0000 (09:37 +0000)
svn path=/trunk/; revision=618

37 files changed:
reactos/lib/user32/controls/button.c [new file with mode: 0644]
reactos/lib/user32/controls/combo.c [new file with mode: 0644]
reactos/lib/user32/controls/edit.c [new file with mode: 0644]
reactos/lib/user32/controls/icontitle.c [new file with mode: 0644]
reactos/lib/user32/controls/listbox.c [new file with mode: 0644]
reactos/lib/user32/controls/menu.c [moved from reactos/lib/user32/windows/menu.c with 94% similarity]
reactos/lib/user32/controls/scroll.c [new file with mode: 0644]
reactos/lib/user32/controls/static.c [new file with mode: 0644]
reactos/lib/user32/controls/widgets.c [new file with mode: 0644]
reactos/lib/user32/graphics/fill.c
reactos/lib/user32/graphics/icon.c
reactos/lib/user32/graphics/syscol.c
reactos/lib/user32/graphics/text.c
reactos/lib/user32/internal/defwnd.c
reactos/lib/user32/internal/dialog.c
reactos/lib/user32/internal/heapdup.c
reactos/lib/user32/internal/menu.c
reactos/lib/user32/internal/msg.c
reactos/lib/user32/internal/nc.c
reactos/lib/user32/internal/paint.c
reactos/lib/user32/internal/scroll.c
reactos/lib/user32/internal/uitools.c
reactos/lib/user32/internal/win.c
reactos/lib/user32/makefile.main
reactos/lib/user32/misc/bitmap.c
reactos/lib/user32/misc/main.c
reactos/lib/user32/resources/sysres.c
reactos/lib/user32/user32.rc
reactos/lib/user32/windows/class.c
reactos/lib/user32/windows/defdlg.c [new file with mode: 0644]
reactos/lib/user32/windows/dialog.c
reactos/lib/user32/windows/hook.c
reactos/lib/user32/windows/msg.c
reactos/lib/user32/windows/msgbox.c
reactos/lib/user32/windows/scroll.c [new file with mode: 0644]
reactos/lib/user32/windows/win.c
reactos/lib/user32/windows/winpos.c

diff --git a/reactos/lib/user32/controls/button.c b/reactos/lib/user32/controls/button.c
new file mode 100644 (file)
index 0000000..fe8ed5b
--- /dev/null
@@ -0,0 +1,598 @@
+/* File: button.c -- Button type widgets
+ *
+ * Copyright (C) 1993 Johannes Ruscheinski
+ * Copyright (C) 1993 David Metcalfe
+ * Copyright (C) 1994 Alexandre Julliard
+ */
+#include <windows.h>
+#include <user32/win.h>
+#include <user32/button.h>
+#include <user32/paint.h>
+#include <user32/nc.h>
+#include <user32/syscolor.h>
+#include <user32/defwnd.h>
+
+
+static void PB_Paint( WND *wndPtr, HDC hDC, WORD action );
+static void PB_PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text);
+static void CB_Paint( WND *wndPtr, HDC hDC, WORD action );
+static void GB_Paint( WND *wndPtr, HDC hDC, WORD action );
+static void UB_Paint( WND *wndPtr, HDC hDC, WORD action );
+static void OB_Paint( WND *wndPtr, HDC hDC, WORD action );
+static void BUTTON_CheckAutoRadioButton( WND *wndPtr );
+
+#define MAX_BTN_TYPE  12
+
+static const WORD maxCheckState[MAX_BTN_TYPE] =
+{
+    BUTTON_UNCHECKED,   /* BS_PUSHBUTTON */
+    BUTTON_UNCHECKED,   /* BS_DEFPUSHBUTTON */
+    BUTTON_CHECKED,     /* BS_CHECKBOX */
+    BUTTON_CHECKED,     /* BS_AUTOCHECKBOX */
+    BUTTON_CHECKED,     /* BS_RADIOBUTTON */
+    BUTTON_3STATE,      /* BS_3STATE */
+    BUTTON_3STATE,      /* BS_AUTO3STATE */
+    BUTTON_UNCHECKED,   /* BS_GROUPBOX */
+    BUTTON_UNCHECKED,   /* BS_USERBUTTON */
+    BUTTON_CHECKED,     /* BS_AUTORADIOBUTTON */
+    BUTTON_UNCHECKED,   /* Not defined */
+    BUTTON_UNCHECKED    /* BS_OWNERDRAW */
+};
+
+typedef void (*pfPaint)( WND *wndPtr, HDC hdc, WORD action );
+
+static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
+{
+    PB_Paint,    /* BS_PUSHBUTTON */
+    PB_Paint,    /* BS_DEFPUSHBUTTON */
+    CB_Paint,    /* BS_CHECKBOX */
+    CB_Paint,    /* BS_AUTOCHECKBOX */
+    CB_Paint,    /* BS_RADIOBUTTON */
+    CB_Paint,    /* BS_3STATE */
+    CB_Paint,    /* BS_AUTO3STATE */
+    GB_Paint,    /* BS_GROUPBOX */
+    UB_Paint,    /* BS_USERBUTTON */
+    CB_Paint,    /* BS_AUTORADIOBUTTON */
+    NULL,        /* Not defined */
+    OB_Paint     /* BS_OWNERDRAW */
+};
+
+#define PAINT_BUTTON(wndPtr,style,action) \
+     if (btnPaintFunc[style]) { \
+         HDC hdc = GetDC( (wndPtr)->hwndSelf ); \
+         (btnPaintFunc[style])(wndPtr,hdc,action); \
+         ReleaseDC( (wndPtr)->hwndSelf, hdc ); }
+
+#define BUTTON_SEND_CTLCOLOR(wndPtr,hdc) \
+    SendMessageA( GetParent((wndPtr)->hwndSelf), WM_CTLCOLORBTN, \
+                    (WPARAM)(hdc), (LPARAM)(wndPtr)->hwndSelf )
+
+static HBITMAP hbitmapCheckBoxes = 0;
+static WORD checkBoxWidth = 0, checkBoxHeight = 0;
+
+
+/***********************************************************************
+ *           ButtonWndProc
+ */
+LRESULT WINAPI ButtonWndProc( HWND hWnd, UINT uMsg,
+                              WPARAM wParam, LPARAM lParam )
+{
+    RECT rect;
+    POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+    WND *wndPtr = WIN_FindWndPtr(hWnd);
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+    LONG style = wndPtr->dwStyle & 0x0f;
+
+    switch (uMsg)
+    {
+    case WM_GETDLGCODE:
+        switch(style)
+        {
+        case BS_PUSHBUTTON:      return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
+        case BS_DEFPUSHBUTTON:   return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
+        case BS_RADIOBUTTON:
+        case BS_AUTORADIOBUTTON: return DLGC_BUTTON | DLGC_RADIOBUTTON;
+        default:                 return DLGC_BUTTON;
+        }
+
+    case WM_ENABLE:
+        PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
+        break;
+
+    case WM_CREATE:
+        if (!hbitmapCheckBoxes)
+        {
+            BITMAP bmp;
+            hbitmapCheckBoxes = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECKBOXES));
+            GetObjectA( hbitmapCheckBoxes, sizeof(bmp), &bmp );
+            checkBoxWidth  = bmp.bmWidth / 4;
+            checkBoxHeight = bmp.bmHeight / 3;
+        }
+        if (style < 0L || style >= MAX_BTN_TYPE) return -1; /* abort */
+        infoPtr->state = BUTTON_UNCHECKED;
+        infoPtr->hFont = 0;
+        return 0;
+
+    case WM_ERASEBKGND:
+        return 1;
+
+    case WM_PAINT:
+        if (btnPaintFunc[style])
+        {
+            PAINTSTRUCT ps;
+            HDC hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps );
+           SetBkMode( hdc, OPAQUE );
+            (btnPaintFunc[style])( wndPtr, hdc, ODA_DRAWENTIRE );
+            if( !wParam ) EndPaint( hWnd, &ps );
+        }
+        break;
+
+    case WM_LBUTTONDOWN:
+    case WM_LBUTTONDBLCLK:
+        SendMessageA( hWnd, BM_SETSTATE, TRUE, 0 );
+        SetFocus( hWnd );
+        SetCapture( hWnd );
+        break;
+
+    case WM_LBUTTONUP:
+        ReleaseCapture();
+        if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
+        SendMessageA( hWnd, BM_SETSTATE, FALSE, 0 );
+        GetClientRect( hWnd, &rect );
+        if (PtInRect( &rect, pt ))
+        {
+            switch(style)
+            {
+            case BS_AUTOCHECKBOX:
+                SendMessageA( hWnd, BM_SETCHECK,
+                                !(infoPtr->state & BUTTON_CHECKED), 0 );
+                break;
+            case BS_AUTORADIOBUTTON:
+                SendMessageA( hWnd, BM_SETCHECK, TRUE, 0 );
+                break;
+            case BS_AUTO3STATE:
+                SendMessageA( hWnd, BM_SETCHECK,
+                                (infoPtr->state & BUTTON_3STATE) ? 0 :
+                                ((infoPtr->state & 3) + 1), 0 );
+                break;
+            }
+            SendMessageA( GetParent(hWnd), WM_COMMAND,
+                            MAKEWPARAM( wndPtr->wIDmenu, BN_CLICKED ), (LPARAM)hWnd);
+        }
+        break;
+
+    case WM_MOUSEMOVE:
+        if (GetCapture() == hWnd)
+        {
+            GetClientRect( hWnd, &rect );
+            SendMessageA( hWnd, BM_SETSTATE, PtInRect(&rect, pt), 0 );
+        }
+        break;
+
+    case WM_NCHITTEST:
+        if(style == BS_GROUPBOX) return HTTRANSPARENT;
+        return DefWindowProcA( hWnd, uMsg, wParam, lParam );
+
+    case WM_SETTEXT:
+        DEFWND_SetTextA( wndPtr, (LPCSTR)lParam );
+       if( wndPtr->dwStyle & WS_VISIBLE )
+            PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
+        return 0;
+
+    case WM_SETFONT:
+        infoPtr->hFont = (HFONT)wParam;
+        if (lParam && (wndPtr->dwStyle & WS_VISIBLE)) 
+           PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
+        break;
+
+    case WM_GETFONT:
+        return (LRESULT)infoPtr->hFont;
+
+    case WM_SETFOCUS:
+        infoPtr->state |= BUTTON_HASFOCUS;
+       if (style == BS_AUTORADIOBUTTON)
+       {
+           SendMessageA( hWnd, BM_SETCHECK, 1, 0 );
+       }
+        PAINT_BUTTON( wndPtr, style, ODA_FOCUS );
+        break;
+
+    case WM_KILLFOCUS:
+        infoPtr->state &= ~BUTTON_HASFOCUS;
+       PAINT_BUTTON( wndPtr, style, ODA_FOCUS );
+       InvalidateRect( hWnd, NULL, TRUE );
+        break;
+
+    case WM_SYSCOLORCHANGE:
+        InvalidateRect( hWnd, NULL, FALSE );
+        break;
+
+    case BM_SETSTYLE:
+        if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
+        wndPtr->dwStyle = (wndPtr->dwStyle & 0xfffffff0) 
+                           | (wParam & 0x0000000f);
+        style = wndPtr->dwStyle & 0x0000000f;
+        PAINT_BUTTON( wndPtr, style, ODA_DRAWENTIRE );
+        break;
+
+    case BM_GETCHECK:
+        return infoPtr->state & 3;
+
+    case BM_SETCHECK:
+        if (wParam > maxCheckState[style]) wParam = maxCheckState[style];
+        if ((infoPtr->state & 3) != wParam)
+        {
+           if ((style == BS_RADIOBUTTON) || (style == BS_AUTORADIOBUTTON))
+           {
+               if (wParam)
+                   wndPtr->dwStyle |= WS_TABSTOP;
+               else
+                   wndPtr->dwStyle &= ~WS_TABSTOP;
+           }
+            infoPtr->state = (infoPtr->state & ~3) | wParam;
+            PAINT_BUTTON( wndPtr, style, ODA_SELECT );
+        }
+        if ((style == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED))
+            BUTTON_CheckAutoRadioButton( wndPtr );
+        break;
+
+    case BM_GETSTATE:
+        return infoPtr->state;
+
+    case BM_SETSTATE:
+        if (wParam)
+        {
+            if (infoPtr->state & BUTTON_HIGHLIGHTED) break;
+            infoPtr->state |= BUTTON_HIGHLIGHTED;
+        }
+        else
+        {
+            if (!(infoPtr->state & BUTTON_HIGHLIGHTED)) break;
+            infoPtr->state &= ~BUTTON_HIGHLIGHTED;
+        }
+        PAINT_BUTTON( wndPtr, style, ODA_SELECT );
+        break;
+
+    default:
+        return DefWindowProcA(hWnd, uMsg, wParam, lParam);
+    }
+    return 0;
+}
+
+
+/**********************************************************************
+ *       Push Button Functions
+ */
+
+static void PB_Paint( WND *wndPtr, HDC hDC, WORD action )
+{
+    RECT rc;
+    HPEN hOldPen;
+    HBRUSH hOldBrush;
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+
+    GetClientRect( wndPtr->hwndSelf, &rc );
+
+      /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
+    if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
+    BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
+    hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
+    hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
+    SetBkMode(hDC, TRANSPARENT);
+    Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
+    if (action == ODA_DRAWENTIRE)
+    {
+        SetPixel( hDC, rc.left, rc.top, GetSysColor(COLOR_WINDOW) );
+        SetPixel( hDC, rc.left, rc.bottom-1, GetSysColor(COLOR_WINDOW) );
+        SetPixel( hDC, rc.right-1, rc.top, GetSysColor(COLOR_WINDOW) );
+        SetPixel( hDC, rc.right-1, rc.bottom-1, GetSysColor(COLOR_WINDOW));
+    }
+    InflateRect( &rc, -1, -1 );
+
+    if ((wndPtr->dwStyle & 0x000f) == BS_DEFPUSHBUTTON)
+    {
+        Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
+        InflateRect( &rc, -1, -1 );
+    }
+
+    if (infoPtr->state & BUTTON_HIGHLIGHTED)
+    {
+        /* draw button shadow: */
+        SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
+        PatBlt(hDC, rc.left, rc.top, 1, rc.bottom-rc.top, PATCOPY );
+        PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, 1, PATCOPY );
+        rc.left += 2;  /* To position the text down and right */
+        rc.top  += 2;
+    } else {
+        rc.right++, rc.bottom++;
+       DrawEdge( hDC, &rc, EDGE_RAISED, BF_RECT );
+        rc.right--, rc.bottom--;
+    }
+       
+    /* draw button label, if any: */
+// && wndPtr->text[0]
+    if (wndPtr->text )
+    {
+        LOGBRUSH lb;
+        GetObject( GetSysColorBrush(COLOR_BTNFACE), sizeof(lb), &lb );
+        if (wndPtr->dwStyle & WS_DISABLED &&
+            GetSysColor(COLOR_GRAYTEXT)==lb.lbColor)
+            /* don't write gray text on gray bkg */
+            PB_PaintGrayOnGray(hDC,infoPtr->hFont,&rc,wndPtr->text);
+        else
+        {
+            SetTextColor( hDC, (wndPtr->dwStyle & WS_DISABLED) ?
+                                 GetSysColor(COLOR_GRAYTEXT) :
+                                 GetSysColor(COLOR_BTNTEXT) );
+            DrawTextA( hDC, wndPtr->text, -1, &rc,
+                         DT_SINGLELINE | DT_CENTER | DT_VCENTER );
+            /* do we have the focus? */
+            if (infoPtr->state & BUTTON_HASFOCUS)
+            {
+                RECT r = { 0, 0, 0, 0 };
+                INT xdelta, ydelta;
+
+                DrawTextA( hDC, wndPtr->text, -1, &r,
+                             DT_SINGLELINE | DT_CALCRECT );
+                xdelta = ((rc.right - rc.left) - (r.right - r.left) - 1) / 2;
+                ydelta = ((rc.bottom - rc.top) - (r.bottom - r.top) - 1) / 2;
+                if (xdelta < 0) xdelta = 0;
+                if (ydelta < 0) ydelta = 0;
+                InflateRect( &rc, -xdelta, -ydelta );
+                DrawFocusRect( hDC, &rc );
+            }
+        }   
+    }
+
+    SelectObject( hDC, hOldPen );
+    SelectObject( hDC, hOldBrush );
+}
+
+
+/**********************************************************************
+ *   Push Button sub function                               [internal]
+ *   using a raster brush to avoid gray text on gray background
+ */
+
+void PB_PaintGrayOnGray(HDC hDC,HFONT hFont,RECT *rc,char *text)
+{
+    static const int Pattern[] = {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55};
+    HBITMAP hbm  = CreateBitmap( 8, 8, 1, 1, Pattern );
+    HDC hdcMem = CreateCompatibleDC(hDC);
+    HBITMAP hbmMem;
+    HBRUSH hBr;
+    RECT rect,rc2;
+
+    rect=*rc;
+    DrawTextA( hDC, text, -1, &rect, DT_SINGLELINE | DT_CALCRECT);
+    rc2=rect;
+    rect.left=(rc->right-rect.right)/2;       /* for centering text bitmap */
+    rect.top=(rc->bottom-rect.bottom)/2;
+    hbmMem = CreateCompatibleBitmap( hDC,rect.right,rect.bottom );
+    SelectObject( hdcMem, hbmMem);
+    hBr = SelectObject( hdcMem, CreatePatternBrush(hbm) );
+    DeleteObject( hbm );
+    PatBlt( hdcMem,0,0,rect.right,rect.bottom,WHITENESS);
+    if (hFont) SelectObject( hdcMem, hFont);
+    DrawTextA( hdcMem, text, -1, &rc2, DT_SINGLELINE);  
+    PatBlt( hdcMem,0,0,rect.right,rect.bottom,0xFA0089);
+    DeleteObject( SelectObject( hdcMem,hBr) );
+    BitBlt(hDC,rect.left,rect.top,rect.right,rect.bottom,hdcMem,0,0,0x990000);
+    DeleteDC( hdcMem);
+    DeleteObject( hbmMem );
+}
+
+
+/**********************************************************************
+ *       Check Box & Radio Button Functions
+ */
+
+static void CB_Paint( WND *wndPtr, HDC hDC, WORD action )
+{
+    RECT rbox, rtext, client;
+    HBRUSH hBrush;
+    int textlen, delta;
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+
+    textlen = 0;
+    GetClientRect(wndPtr->hwndSelf, &client);
+    rbox = rtext = client;
+
+    if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
+
+    /* Something is still not right, checkboxes (and edit controls)
+     * in wsping have white backgrounds instead of dark grey.
+     * BUTTON_SEND_CTLCOLOR() is even worse since it returns 0 in this
+     * particular case and the background is not painted at all.
+     */
+
+    hBrush = GetControlBrush( wndPtr->hwndSelf, hDC, CTLCOLOR_BTN );
+
+    if (wndPtr->dwStyle & BS_LEFTTEXT) 
+    {
+       /* magic +4 is what CTL3D expects */
+
+        rtext.right -= checkBoxWidth + 4;
+        rbox.left = rbox.right - checkBoxWidth;
+    }
+    else 
+    {
+        rtext.left += checkBoxWidth + 4;
+        rbox.right = checkBoxWidth;
+    }
+
+      /* Draw the check-box bitmap */
+
+    
+    if (wndPtr->text) {
+       textlen = lstrlenA( wndPtr->text );
+    }
+    if (action == ODA_DRAWENTIRE || action == ODA_SELECT)
+    { 
+        HDC hMemDC = CreateCompatibleDC( hDC );
+        int x = 0, y = 0;
+        delta = (rbox.bottom - rbox.top - checkBoxHeight) >> 1;
+
+        if (action == ODA_SELECT) FillRect( hDC, &rbox, hBrush );
+        else FillRect( hDC, &client, hBrush );
+
+        if (infoPtr->state & BUTTON_HIGHLIGHTED) x += 2 * checkBoxWidth;
+        if (infoPtr->state & (BUTTON_CHECKED | BUTTON_3STATE)) x += checkBoxWidth;
+        if (((wndPtr->dwStyle & 0x0f) == BS_RADIOBUTTON) ||
+            ((wndPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON)) y += checkBoxHeight;
+        else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
+
+       SelectObject( hMemDC, hbitmapCheckBoxes );
+       BitBlt( hDC, rbox.left, rbox.top + delta, checkBoxWidth,
+                 checkBoxHeight, hMemDC, x, y, SRCCOPY );
+       DeleteDC( hMemDC );
+
+        if( textlen && action != ODA_SELECT )
+        {
+            if (wndPtr->dwStyle & WS_DISABLED)
+                SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
+            DrawTextA( hDC, wndPtr->text, textlen, &rtext,
+                        DT_SINGLELINE | DT_VCENTER );
+           textlen = 0; /* skip DrawText() below */
+        }
+    }
+
+    if ((action == ODA_FOCUS) ||
+        ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
+    {
+       /* again, this is what CTL3D expects */
+
+        SetRectEmpty(&rbox);
+        if( textlen )
+            DrawTextA( hDC, wndPtr->text, textlen, &rbox,
+                        DT_SINGLELINE | DT_CALCRECT );
+        textlen = rbox.bottom - rbox.top;
+        delta = ((rtext.bottom - rtext.top) - textlen)/2;
+        rbox.bottom = (rbox.top = rtext.top + delta - 1) + textlen + 2;
+        textlen = rbox.right - rbox.left;
+        rbox.right = (rbox.left += --rtext.left) + textlen + 2;
+        IntersectRect(&rbox, &rbox, &rtext);
+        DrawFocusRect( hDC, &rbox );
+    }
+}
+
+
+/**********************************************************************
+ *       BUTTON_CheckAutoRadioButton
+ *
+ * wndPtr is checked, uncheck every other auto radio button in group
+ */
+static void BUTTON_CheckAutoRadioButton( WND *wndPtr )
+{
+    HWND parent, sibling, start;
+    WND *sibPtr;
+    if (!(wndPtr->dwStyle & WS_CHILD)) return;
+    parent = wndPtr->parent->hwndSelf;
+    /* assure that starting control is not disabled or invisible */
+    start = sibling = GetNextDlgGroupItem( parent, wndPtr->hwndSelf, TRUE );
+    do
+    {
+       
+        if (!sibling) break;
+       sibPtr = WIN_FindWndPtr(sibling);
+       if (!sibPtr) break;
+        if ((wndPtr->hwndSelf != sibling) &&
+            ((sibPtr->dwStyle & 0x0f) == BS_AUTORADIOBUTTON))
+            SendMessageA( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 );
+        sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
+    } while (sibling != start);
+}
+
+
+/**********************************************************************
+ *       Group Box Functions
+ */
+
+static void GB_Paint( WND *wndPtr, HDC hDC, WORD action )
+{
+    RECT rc, rcFrame;
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+
+    if (action != ODA_DRAWENTIRE) return;
+
+    BUTTON_SEND_CTLCOLOR( wndPtr, hDC );
+
+    GetClientRect( wndPtr->hwndSelf, &rc);
+    if (TWEAK_WineLook == WIN31_LOOK) {
+        HPEN hPrevPen = SelectObject( hDC,
+                                         GetSysColorPen(COLOR_WINDOWFRAME));
+       HBRUSH hPrevBrush = SelectObject( hDC,
+                                             GetStockObject(NULL_BRUSH) );
+
+       Rectangle( hDC, rc.left, rc.top + 2, rc.right - 1, rc.bottom - 1 );
+       SelectObject( hDC, hPrevBrush );
+       SelectObject( hDC, hPrevPen );
+    } else {
+       TEXTMETRIC tm;
+       rcFrame = rc;
+
+       if (infoPtr->hFont)
+           SelectObject (hDC, infoPtr->hFont);
+       GetTextMetricsA (hDC, &tm);
+       rcFrame.top += (tm.tmHeight / 2) - 1;
+       DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT);
+    }
+
+    if (wndPtr->text)
+    {
+       if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
+        if (wndPtr->dwStyle & WS_DISABLED)
+            SetTextColor( hDC, GetSysColor(COLOR_GRAYTEXT) );
+        rc.left += 10;
+        DrawTextA( hDC, wndPtr->text, -1, &rc, DT_SINGLELINE | DT_NOCLIP );
+    }
+}
+
+
+/**********************************************************************
+ *       User Button Functions
+ */
+
+static void UB_Paint( WND *wndPtr, HDC hDC, WORD action )
+{
+    RECT rc;
+    HBRUSH hBrush;
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+
+    if (action == ODA_SELECT) return;
+
+    GetClientRect( wndPtr->hwndSelf, &rc);
+
+    if (infoPtr->hFont) SelectObject( hDC, infoPtr->hFont );
+    hBrush = GetControlBrush( wndPtr->hwndSelf, hDC, CTLCOLOR_BTN );
+
+    FillRect( hDC, &rc, hBrush );
+    if ((action == ODA_FOCUS) ||
+        ((action == ODA_DRAWENTIRE) && (infoPtr->state & BUTTON_HASFOCUS)))
+        DrawFocusRect( hDC, &rc );
+}
+
+
+/**********************************************************************
+ *       Ownerdrawn Button Functions
+ */
+
+static void OB_Paint( WND *wndPtr, HDC hDC, WORD action )
+{
+    BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
+    DRAWITEMSTRUCT dis;
+
+    dis.CtlType    = ODT_BUTTON;
+    dis.CtlID      = wndPtr->wIDmenu;
+    dis.itemID     = 0;
+    dis.itemAction = action;
+    dis.itemState  = ((infoPtr->state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) |
+                     ((infoPtr->state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) |
+                     ((wndPtr->dwStyle & WS_DISABLED) ? ODS_DISABLED : 0);
+    dis.hwndItem   = wndPtr->hwndSelf;
+    dis.hDC        = hDC;
+    dis.itemData   = 0;
+    GetClientRect( wndPtr->hwndSelf, &dis.rcItem );
+    SendMessageA( GetParent(wndPtr->hwndSelf), WM_DRAWITEM,
+                    wndPtr->wIDmenu, (LPARAM)&dis );
+}
diff --git a/reactos/lib/user32/controls/combo.c b/reactos/lib/user32/controls/combo.c
new file mode 100644 (file)
index 0000000..4b5bb20
--- /dev/null
@@ -0,0 +1,1570 @@
+/*
+ * Combo controls
+ * 
+ * Copyright 1997 Alex Korobka
+ * 
+ * FIXME: roll up in Netscape 3.01.
+ */
+
+#include <string.h>
+
+#include <windows.h>
+#include <user32/sysmetr.h>
+#include <user32/win.h>
+
+#include <user32/heapdup.h>
+#include <user32/combo.h>
+#include <user32/debug.h>
+
+  /* bits in the dwKeyData */
+#define KEYDATA_ALT             0x2000
+#define KEYDATA_PREVSTATE       0x4000
+
+/*
+ * Additional combo box definitions
+ */
+
+#define CB_GETPTR( wnd )      (*(LPHEADCOMBO*)((wnd)->wExtra))
+#define CB_NOTIFY( lphc, code ) \
+       (SendMessageA( (lphc)->owner, WM_COMMAND, \
+                        MAKEWPARAM((lphc)->self->wIDmenu, (code)), (LPARAM)(lphc)->self->hwndSelf))
+#define CB_GETEDITTEXTLENGTH( lphc ) \
+       (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
+
+static HBITMAP         hComboBmp = 0;
+static UINT            CBitHeight, CBitWidth;
+static UINT            CBitOffset = 8;
+
+/***********************************************************************
+ *           COMBO_Init
+ *
+ * Load combo button bitmap.
+ */
+WINBOOL COMBO_Init(void)
+{
+  HDC          hDC;
+  
+  if( hComboBmp ) return TRUE;
+  if( (hDC = CreateCompatibleDC(0)) )
+  {
+    WINBOOL    bRet = FALSE;
+    if( (hComboBmp = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO))) )
+    {
+      BITMAP      bm;
+      HBITMAP     hPrevB;
+      RECT        r;
+
+      GetObjectA( hComboBmp, sizeof(bm), &bm );
+      CBitHeight = bm.bmHeight;
+      CBitWidth  = bm.bmWidth;
+
+      DPRINT( "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(WND* wnd, LPARAM lParam)
+{
+   LPHEADCOMBO                 lphc;
+
+   if ( wnd && COMBO_Init() &&
+      (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
+   {
+       LPCREATESTRUCTA     lpcs = (CREATESTRUCTA*)lParam;
+       
+       memset( lphc, 0, sizeof(HEADCOMBO) );
+       *(LPHEADCOMBO*)wnd->wExtra = lphc;
+
+       /* some braindead apps do try to use scrollbar/border flags */
+
+       lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
+       wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
+
+       if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
+              lphc->dwStyle |= CBS_HASSTRINGS;
+       if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
+             lphc->wState |= CBF_NOTIFY;
+
+       DPRINT( "[0x%08x], style = %08x\n", 
+                    (UINT)lphc, lphc->dwStyle );
+
+       return (LRESULT)(UINT)wnd->hwndSelf; 
+    }
+    return (LRESULT)FALSE;
+}
+
+/***********************************************************************
+ *           COMBO_NCDestroy
+ */
+static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
+{
+
+   if( lphc )
+   {
+       WND*            wnd = lphc->self;
+
+       DPRINT("[%04x]: freeing storage\n", CB_HWND(lphc));
+
+       if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox ) 
+          DestroyWindow( lphc->hWndLBox );
+
+       HeapFree( GetProcessHeap(), 0, lphc );
+       wnd->wExtra[0] = 0;
+   }
+   return 0;
+}
+
+/***********************************************************************
+ *           CBGetDefaultTextHeight
+ */
+static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE lpSize )
+{
+   if( lphc->editHeight ) /* explicitly set height */
+       lpSize->cy = lphc->editHeight;
+   else
+   {
+       HDC    hDC = GetDC( lphc->self->hwndSelf );
+       HFONT  hPrevFont = 0;
+
+       if( lphc->hFont ) hPrevFont = SelectObject( hDC, lphc->hFont );
+
+       GetTextExtentPointA( hDC, "0", 1, lpSize);
+
+       lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER;
+
+       if( hPrevFont ) SelectObject( hDC, hPrevFont );
+       ReleaseDC( lphc->self->hwndSelf, hDC );
+   }
+   lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left;
+}
+
+
+/***********************************************************************
+ *           CBCalcPlacement
+ *
+ * Set up component coordinates given valid lphc->RectCombo.
+ */
+static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT lprEdit, 
+                            LPRECT lprButton, LPRECT lprLB )
+{
+   RECT        rect = lphc->RectCombo;
+   SIZE        size;
+
+   /* get combo height and width */
+
+   if( CB_OWNERDRAWN(lphc) )
+   {
+       UINT    u = lphc->RectEdit.bottom - lphc->RectEdit.top;
+
+       if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
+       {
+          MEASUREITEMSTRUCT        mi;
+
+          /* calculate defaults before sending WM_MEASUREITEM */
+
+          CBGetDefaultTextHeight( lphc, &size );
+
+          lphc->wState &= ~CBF_MEASUREITEM;
+
+          mi.CtlType = ODT_COMBOBOX;
+          mi.CtlID   = lphc->self->wIDmenu;
+          mi.itemID  = -1;
+          mi.itemWidth  = size.cx;
+          mi.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
+          mi.itemData   = 0;
+          SendMessageA(lphc->owner, WM_MEASUREITEM, 
+                               (WPARAM)mi.CtlID, (LPARAM)&mi);
+          u = 6 + (UINT)mi.itemHeight;
+       }
+       else
+          size.cx = rect.right - rect.left;
+       size.cy = u;
+   }
+   else 
+       CBGetDefaultTextHeight( lphc, &size );
+
+   /* calculate text and button placement */
+
+   lprEdit->left = lprEdit->top = lprButton->top = 0;
+   if( CB_GETTYPE(lphc) == CBS_SIMPLE )        /* no button */
+       lprButton->left = lprButton->right = lprButton->bottom = 0;
+   else
+   {
+       INT     i = size.cx - CBitWidth - 10;   /* seems ok */
+
+       lprButton->right = size.cx;
+       lprButton->left = (INT)i;
+       lprButton->bottom = lprButton->top + size.cy;
+
+       if( i < 0 ) size.cx = 0;
+       else size.cx = i;
+   }
+
+   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+   {
+       size.cx -= CBitOffset;
+       if( size.cx < 0 ) size.cx = 0;
+   }
+
+   lprEdit->right = size.cx; lprEdit->bottom = size.cy;
+
+   /* listbox placement */
+
+   lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
+   lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
+   lprLB->right = rect.right - rect.left;
+   lprLB->bottom = rect.bottom - rect.top;
+
+   if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
+       lprLB->right = lprLB->left + lphc->droppedWidth;
+
+   DPRINT("[%04x]: (%i,%i-%i,%i) placement\n",
+               CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top, 
+               lphc->RectCombo.right, lphc->RectCombo.bottom);
+
+   DPRINT("\ttext\t= (%i,%i-%i,%i)\n",
+               lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
+
+   DPRINT("\tbutton\t= (%i,%i-%i,%i)\n",
+               lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
+
+   DPRINT("\tlbox\t= (%i,%i-%i,%i)\n", 
+               lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
+}
+
+/***********************************************************************
+ *           CBGetDroppedControlRect
+ */
+static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
+{
+   lpRect->left = lphc->RectCombo.left +
+                      (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
+   lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
+                                             SYSMETRICS_CYBORDER;
+   lpRect->right = lphc->RectCombo.right;
+   lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
+}
+
+/***********************************************************************
+ *           COMBO_Create
+ */
+LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
+{
+  static char clbName[] = "ComboLBox";
+  static char editName[] = "Edit";
+
+  LPCREATESTRUCT  lpcs = (CREATESTRUCT*)lParam;
+  
+  if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
+  else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+
+  lphc->self  = wnd;
+  lphc->owner = lpcs->hwndParent;
+
+  /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
+
+  if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
+  {
+      UINT     lbeStyle;
+      RECT     editRect, btnRect, lbRect;
+
+      GetWindowRect( wnd->hwndSelf, &lphc->RectCombo );
+
+      lphc->wState |= CBF_MEASUREITEM;
+      CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
+      lphc->RectButton = btnRect;
+      lphc->droppedWidth = lphc->editHeight = 0;
+
+      /* create listbox popup */
+
+      lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) | 
+                 (lpcs->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_CHILD | WS_VISIBLE;
+      else                                     /* popup listbox */
+      {
+       lbeStyle |= WS_POPUP;
+       OffsetRect( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
+      }
+
+     /* Dropdown ComboLBox is not a child window and we cannot pass 
+      * ID_CB_LISTBOX directly because it will be treated as a menu handle.
+      */
+
+      lphc->hWndLBox = CreateWindowExA( 0, clbName, NULL, lbeStyle, 
+                       lbRect.left + SYSMETRICS_CXBORDER, 
+                       lbRect.top + SYSMETRICS_CYBORDER, 
+                       lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER, 
+                       lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER, 
+                       lphc->self->hwndSelf, 
+                      (lphc->dwStyle & CBS_DROPDOWN)? (HMENU)0 : (HMENU)ID_CB_LISTBOX,
+                       lphc->self->hInstance, (LPVOID)lphc );
+      if( lphc->hWndLBox )
+      {
+         WINBOOL       bEdit = TRUE;
+         lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
+         if( lphc->wState & CBF_EDIT ) 
+         {
+             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;
+             lphc->hWndEdit = CreateWindowExA( 0, editName, NULL, lbeStyle,
+                       editRect.left, editRect.top, editRect.right - editRect.left,
+                       editRect.bottom - editRect.top, lphc->self->hwndSelf, 
+                       (HMENU)ID_CB_EDIT, lphc->self->hInstance, NULL );
+             if( !lphc->hWndEdit ) bEdit = FALSE;
+         } 
+
+          if( bEdit )
+         {
+             lphc->RectEdit = editRect;
+             if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+             {
+               lphc->wState |= CBF_NORESIZE;
+               SetWindowPos( wnd->hwndSelf, 0, 0, 0, 
+                               lphc->RectCombo.right - lphc->RectCombo.left,
+                               lphc->RectEdit.bottom - lphc->RectEdit.top,
+                               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+               lphc->wState &= ~CBF_NORESIZE;
+             }
+             DPRINT("init done\n");
+             return (LRESULT)wnd->hwndSelf;
+         }
+         DPRINT("edit control failure.\n");
+      } else DPRINT("listbox failure.\n");
+  } else DPRINT("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       r;
+    UINT       x, y;
+    WINBOOL    bWINBOOL;
+    HDC       hMemDC;
+    HBRUSH    hPrevBrush;
+    COLORREF    oldTextColor, oldBkColor;
+
+    if( lphc->wState & CBF_NOREDRAW ) return;
+
+    hPrevBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
+    r = lphc->RectButton;
+
+    Rectangle(hdc, r.left, r.top, r.right, r.bottom );
+    if( (bWINBOOL = lphc->wState & CBF_BUTTONDOWN) )
+    {
+       DrawEdge( hdc, &r, EDGE_SUNKEN, BF_RECT );
+       OffsetRect( &r, 1, 1 );
+    } else {
+        r.top++, r.left++;
+       DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
+       r.top--, r.left--;
+    }
+
+    InflateRect( &r, -1, -1 ); 
+
+    x = (r.left + r.right - CBitWidth) >> 1;
+    y = (r.top + r.bottom - CBitHeight) >> 1;
+
+    InflateRect( &r, -3, -3 );
+
+    hMemDC = CreateCompatibleDC( hdc );
+    SelectObject( hMemDC, hComboBmp );
+    oldTextColor = SetTextColor( hdc, GetSysColor(COLOR_BTNFACE) );
+    oldBkColor = SetBkColor( hdc, CB_DISABLED(lphc) ? RGB(128,128,128) :
+                              RGB(0,0,0) );
+    BitBlt( hdc, x, y, 8, 8, hMemDC, 0, 0, SRCCOPY );
+    SetBkColor( hdc, oldBkColor );
+    SetTextColor( hdc, oldTextColor );
+    DeleteDC( hMemDC );
+    SelectObject( hdc, hPrevBrush );
+}
+
+/***********************************************************************
+ *           CBPaintText
+ *
+ * Paint CBS_DROPDOWNLIST text field / update edit control contents.
+ */
+static void CBPaintText(LPHEADCOMBO lphc, HDC hdc)
+{
+   INT id, size = 0;
+   LPSTR       pText = NULL;
+
+   if( lphc->wState & CBF_NOREDRAW ) return;
+
+   /* follow Windows combobox that sends a bunch of text 
+    * inquiries to its listbox while processing WM_PAINT. */
+
+   if( (id = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
+   {
+        size = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
+        if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
+       {
+           SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText );
+           pText[size] = '\0'; /* just in case */
+       } else return;
+   }
+
+   if( lphc->wState & CBF_EDIT )
+   {
+       if( CB_HASSTRINGS(lphc) ) SetWindowTextA( lphc->hWndEdit, pText ? pText : "" );
+       if( lphc->wState & CBF_FOCUSED ) 
+           SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
+   }
+   else /* paint text field ourselves */
+   {
+        HBRUSH hPrevBrush = 0;
+       HDC      hDC = hdc;
+
+       if( !hDC ) 
+       {
+           if ((hDC = GetDC(lphc->self->hwndSelf)))
+            {
+                HBRUSH hBrush = (HBRUSH)SendMessageA( lphc->owner,
+                                                  WM_CTLCOLORLISTBOX, 
+                                                  (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf );
+                hPrevBrush = SelectObject( hDC, 
+                           (hBrush) ? hBrush : GetStockObject(WHITE_BRUSH) );
+            }
+       }
+       if( hDC )
+       {
+           RECT        rect;
+           UINT        itemState;
+           HFONT       hPrevFont = (lphc->hFont) ? SelectObject(hDC, lphc->hFont) : 0;
+
+           PatBlt( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
+                          (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
+                          (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
+                          (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
+           InflateRect( &rect, -1, -1 );
+
+           if( lphc->wState & CBF_FOCUSED && 
+               !(lphc->wState & CBF_DROPPED) )
+           {
+               /* highlight */
+
+               FillRect( hDC, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
+                SetBkColor( hDC, GetSysColor( COLOR_HIGHLIGHT ) );
+                SetTextColor( hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
+               itemState = ODS_SELECTED | ODS_FOCUS;
+           } else itemState = 0;
+
+           if( CB_OWNERDRAWN(lphc) )
+           {
+               DRAWITEMSTRUCT dis;
+
+               if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
+
+               dis.CtlType     = ODT_COMBOBOX;
+               dis.CtlID       = lphc->self->wIDmenu;
+               dis.hwndItem    = lphc->self->hwndSelf;
+               dis.itemAction  = ODA_DRAWENTIRE;
+               dis.itemID      = id;
+               dis.itemState   = itemState;
+               dis.hDC         = hDC;
+               dis.rcItem      = rect;
+               dis.itemData    = SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, 
+                                                                 (WPARAM)id, 0 );
+               SendMessageA( lphc->owner, WM_DRAWITEM, 
+                               lphc->self->wIDmenu, (LPARAM)&dis );
+           }
+           else
+           {
+               ExtTextOutA( hDC, rect.left + 1, rect.top + 1,
+                               ETO_OPAQUE | ETO_CLIPPED, &rect,
+                               pText ? pText : "" , size, NULL );
+               if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
+                   DrawFocusRect( hDC, &rect );
+           }
+
+           if( hPrevFont ) SelectObject(hDC, hPrevFont );
+           if( !hdc ) 
+           {
+               if( hPrevBrush ) SelectObject( hDC, hPrevBrush );
+               ReleaseDC( lphc->self->hwndSelf, hDC );
+           }
+       }
+   }
+   if (pText)
+       HeapFree( GetProcessHeap(), 0, pText );
+}
+
+/***********************************************************************
+ *           COMBO_Paint
+ */
+static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
+{
+  PAINTSTRUCT ps;
+  HDC  hDC;
+  
+  hDC = (hParamDC) ? hParamDC
+                  : BeginPaint( lphc->self->hwndSelf, &ps);
+  if( hDC && !(lphc->wState & CBF_NOREDRAW) )
+  {
+      HBRUSH   hPrevBrush, hBkgBrush;
+
+      hBkgBrush = (HBRUSH)SendMessageA( lphc->owner, WM_CTLCOLORLISTBOX,
+                                 (WPARAM)hDC, (LPARAM)lphc->self->hwndSelf );
+      if( !hBkgBrush ) hBkgBrush = GetStockObject(WHITE_BRUSH);
+
+      hPrevBrush = SelectObject( hDC, hBkgBrush );
+      if( !IsRectEmpty(&lphc->RectButton) )
+      {
+         /* paint everything to the right of the text field */
+
+         PatBlt( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
+                        lphc->RectButton.right - lphc->RectEdit.right,
+                        lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
+          CBPaintButton( lphc, hDC );
+      }
+
+      if( !(lphc->wState & CBF_EDIT) )
+      {
+         /* paint text field */
+         
+         HPEN hPrevPen = SelectObject( hDC, GetSysColorPen(
+                                                         COLOR_WINDOWFRAME) );
+
+         Rectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
+                      lphc->RectEdit.right, lphc->RectButton.bottom );
+         SelectObject( hDC, hPrevPen );
+         CBPaintText( lphc, hDC );
+      }
+      if( hPrevBrush ) SelectObject( hDC, hPrevBrush );
+  }
+  if( !hParamDC ) EndPaint(lphc->self->hwndSelf, &ps);
+  return 0;
+}
+
+/***********************************************************************
+ *           CBUpdateLBox
+ *
+ * Select listbox entry according to the contents of the edit control.
+ */
+static INT CBUpdateLBox( LPHEADCOMBO lphc )
+{
+   INT length, idx, ret;
+   LPSTR       pText = NULL;
+   
+   idx = ret = LB_ERR;
+   length = CB_GETEDITTEXTLENGTH( lphc );
+   if( length > 0 ) 
+       pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
+
+   DPRINT("\t edit text length %i\n", length );
+
+   if( pText )
+   {
+       if( length ) GetWindowTextA( lphc->hWndEdit, pText, length + 1);
+       else pText[0] = '\0';
+       idx = SendMessageA( lphc->hWndLBox, LB_FINDSTRING, 
+                            (WPARAM)(-1), (LPARAM)pText );
+       if( idx == LB_ERR ) idx = 0;    /* select first item */
+       else ret = idx;
+       HeapFree( GetProcessHeap(), 0, pText );
+   }
+
+   /* select entry */
+
+   SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)idx, 0 );
+   
+   if( idx >= 0 )
+   {
+       SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)idx, 0 );
+       /* probably superfluous but Windows sends this too */
+       SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)idx, 0 );
+   }
+   return ret;
+}
+
+/***********************************************************************
+ *           CBUpdateEdit
+ *
+ * Copy a listbox entry to the edit control.
+ */
+static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
+{
+   INT length;
+   LPSTR       pText = NULL;
+
+   DPRINT("\t %i\n", index );
+
+   if( index == -1 )
+   {
+       length = CB_GETEDITTEXTLENGTH( lphc );
+       if( length )
+       {
+           if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
+           {
+               GetWindowTextA( lphc->hWndEdit, pText, length + 1 );
+               index = SendMessageA( lphc->hWndLBox, LB_FINDSTRING,
+                                       (WPARAM)(-1), (LPARAM)pText );
+               HeapFree( GetProcessHeap(), 0, pText );
+           }
+       }
+   }
+
+   if( index >= 0 ) /* got an entry */
+   {
+       length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
+       if( length )
+       {
+          if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
+          {
+               SendMessageA( lphc->hWndLBox, LB_GETTEXT, 
+                               (WPARAM)index, (LPARAM)pText );
+               SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
+               SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
+               HeapFree( GetProcessHeap(), 0, pText );
+          }
+       }
+   }
+}
+
+/***********************************************************************
+ *           CBDropDown
+ * 
+ * Show listbox popup.
+ */
+static void CBDropDown( LPHEADCOMBO lphc )
+{
+   INT index;
+   RECT        rect;
+   LPRECT      pRect = NULL;
+
+   DPRINT("[%04x]: drop down\n", CB_HWND(lphc));
+
+   CB_NOTIFY( lphc, CBN_DROPDOWN );
+
+   /* set selection */
+
+   lphc->wState |= CBF_DROPPED;
+   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+   {
+       index = CBUpdateLBox( lphc );
+       if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
+   }
+   else
+   {
+       index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
+       if( index == LB_ERR ) index = 0;
+       SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)index, 0 );
+       SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
+       pRect = &lphc->RectEdit;
+   }
+
+   /* now set popup position */
+
+   GetWindowRect( lphc->self->hwndSelf, &rect );
+   
+   rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
+   rect.bottom = rect.top + lphc->RectCombo.bottom - 
+                           lphc->RectCombo.top - SYSMETRICS_CYBORDER;
+   rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
+   rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
+
+   SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.top, 
+                rect.right - rect.left, rect.bottom - rect.top, 
+                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
+
+   if( !(lphc->wState & CBF_NOREDRAW) )
+       if( pRect )
+           RedrawWindow( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE | 
+                          RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+   ShowWindow( lphc->hWndLBox, SW_SHOWNA );
+}
+
+/***********************************************************************
+ *           CBRollUp
+ *
+ * Hide listbox popup.
+ */
+static void CBRollUp( LPHEADCOMBO lphc, WINBOOL ok, WINBOOL bButton )
+{
+   HWND        hWnd = lphc->self->hwndSelf;
+
+   CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
+
+   if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
+   {
+
+       DPRINT("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok );
+
+       /* always send WM_LBUTTONUP? */
+       SendMessageA( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
+
+       if( lphc->wState & CBF_DROPPED ) 
+       {
+          RECT rect;
+
+          lphc->wState &= ~CBF_DROPPED;
+          ShowWindow( lphc->hWndLBox, SW_HIDE );
+
+          if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+          {
+              INT index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
+              CBUpdateEdit( lphc, index );
+              rect = lphc->RectButton;
+          }
+          else 
+           {
+              if( bButton )
+                  UnionRect( &rect, &lphc->RectButton,
+                                      &lphc->RectEdit );
+              else
+                  rect = lphc->RectEdit;
+              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...
+ */
+WINBOOL COMBO_FlipListbox( LPHEADCOMBO lphc, WINBOOL bRedrawButton )
+{
+   if( lphc->wState & CBF_DROPPED )
+   {
+       CBRollUp( lphc, TRUE, bRedrawButton );
+       return FALSE;
+   }
+
+   CBDropDown( lphc );
+   return TRUE;
+}
+
+/***********************************************************************
+ *           COMBO_GetLBWindow
+ *
+ * Edit control helper.
+ */
+HWND COMBO_GetLBWindow( WND* pWnd )
+{
+  LPHEADCOMBO       lphc = CB_GETPTR(pWnd);
+  if( lphc ) return lphc->hWndLBox;
+  return 0;
+}
+
+
+/***********************************************************************
+ *           CBRepaintButton
+ */
+static void CBRepaintButton( LPHEADCOMBO lphc )
+{
+   HDC        hDC = GetDC( lphc->self->hwndSelf );
+
+   if( hDC )
+   {
+       CBPaintButton( lphc, hDC );
+       ReleaseDC( lphc->self->hwndSelf, hDC );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_SetFocus
+ */
+static void COMBO_SetFocus( LPHEADCOMBO lphc )
+{
+   if( !(lphc->wState & CBF_FOCUSED) )
+   {
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+           SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
+
+       if( lphc->wState & CBF_EDIT )
+           SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
+       lphc->wState |= CBF_FOCUSED;
+       if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
+
+       CB_NOTIFY( lphc, CBN_SETFOCUS );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_KillFocus
+ */
+static void COMBO_KillFocus( LPHEADCOMBO lphc )
+{
+   HWND        hWnd = lphc->self->hwndSelf;
+
+   if( lphc->wState & CBF_FOCUSED )
+   {
+       SendMessageA( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
+
+       CBRollUp( lphc, FALSE, TRUE );
+       if( IsWindow( hWnd ) )
+       {
+           if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+               SendMessageA( lphc->hWndLBox, LB_CARETOFF, 0, 0 );
+
+          lphc->wState &= ~CBF_FOCUSED;
+
+           /* redraw text */
+           if( lphc->wState & CBF_EDIT )
+               SendMessageA( lphc->hWndEdit, EM_SETSEL, (WPARAM)(-1), 0 );
+           else CBPaintText( lphc, 0 );
+
+           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):
+
+               DPRINT("[%04x]: edit [%04x] got focus\n", 
+                            CB_HWND(lphc), lphc->hWndEdit );
+
+               if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
+               break;
+
+          case (EN_KILLFOCUS >> 8):
+
+               DPRINT("[%04x]: edit [%04x] lost focus\n",
+                            CB_HWND(lphc), 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):
+               CB_NOTIFY( lphc, CBN_EDITCHANGE );
+               CBUpdateLBox( lphc );
+               break;
+
+          case (EN_UPDATE >> 8):
+               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:
+
+               DPRINT("[%04x]: lbox selection change [%04x]\n", 
+                            CB_HWND(lphc), lphc->wState );
+
+               /* do not roll up if selection is being tracked 
+                * by arrowkeys in the dropdown listbox */
+
+               if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
+                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
+               else lphc->wState &= ~CBF_NOROLLUP;
+
+               CB_NOTIFY( lphc, CBN_SELCHANGE );
+               CBPaintText( lphc, 0 );
+               /* fall through */
+
+          case LBN_SETFOCUS:
+          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, 
+                              WPARAM wParam, LPARAM lParam ) 
+{
+   HWND        hWnd = lphc->self->hwndSelf;
+
+   DPRINT("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
+
+#define lpIS    ((LPDELETEITEMSTRUCT)lParam)
+
+   /* two first items are the same in all 4 structs */
+   lpIS->CtlType = ODT_COMBOBOX;
+   lpIS->CtlID   = lphc->self->wIDmenu;
+
+   switch( msg )       /* patch window handle */
+   {
+       case WM_DELETEITEM: 
+            lpIS->hwndItem = hWnd; 
+#undef  lpIS
+            break;
+       case WM_DRAWITEM: 
+#define lpIS    ((LPDRAWITEMSTRUCT)lParam)
+            lpIS->hwndItem = hWnd; 
+#undef  lpIS
+            break;
+       case WM_COMPAREITEM: 
+#define lpIS    ((LPCOMPAREITEMSTRUCT)lParam)
+            lpIS->hwndItem = hWnd; 
+#undef  lpIS
+            break;
+   }
+
+   return SendMessageA( lphc->owner, msg, lphc->self->wIDmenu, lParam );
+}
+
+/***********************************************************************
+ *           COMBO_GetText
+ */
+static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT N, LPSTR lpText)
+{
+   if( lphc->wState & CBF_EDIT )
+       return SendMessageA( lphc->hWndEdit, WM_GETTEXT, 
+                            (WPARAM)N, (LPARAM)lpText );     
+
+   /* get it from the listbox */
+
+   if( lphc->hWndLBox )
+   {
+       INT idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
+       if( idx != LB_ERR )
+       {
+           LPSTR       lpBuffer;
+           INT length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN,
+                                               (WPARAM)idx, 0 );
+
+           /* 'length' is without the terminating character */
+           if( length >= N )
+              lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
+           else 
+              lpBuffer = lpText;
+
+           if( lpBuffer )
+           {
+              INT    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 ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
+                  lpText[N - 1] = '\0';
+                   }
+                  HeapFree( GetProcessHeap(), 0, lpBuffer );
+              }
+              return (LRESULT)n;
+          }
+       }
+   }
+   return 0;
+}
+
+
+/***********************************************************************
+ *           CBResetPos
+ *
+ * This function sets window positions according to the updated 
+ * component placement struct.
+ */
+static void CBResetPos( LPHEADCOMBO lphc, LPRECT lbRect, WINBOOL bRedraw )
+{
+   WINBOOL     bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
+
+   /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
+    * sizing messages */
+
+   if( lphc->wState & CBF_EDIT )
+       SetWindowPos( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
+                       lphc->RectEdit.right - lphc->RectEdit.left,
+                       lphc->RectEdit.bottom - lphc->RectEdit.top,
+                       SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   if( bDrop )
+       OffsetRect( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
+
+   lbRect->right -= lbRect->left;      /* convert to width */
+   lbRect->bottom -= lbRect->top;
+   SetWindowPos( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
+                   lbRect->right, lbRect->bottom, 
+                  SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+   if( bDrop )
+   {
+       if( lphc->wState & CBF_DROPPED )
+       {
+           lphc->wState &= ~CBF_DROPPED;
+           ShowWindow( lphc->hWndLBox, SW_HIDE );
+       }
+
+       lphc->wState |= CBF_NORESIZE;
+       SetWindowPos( lphc->self->hwndSelf, 0, 0, 0,
+                       lphc->RectCombo.right - lphc->RectCombo.left,
+                       lphc->RectEdit.bottom - lphc->RectEdit.top,
+                       SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
+       lphc->wState &= ~CBF_NORESIZE;
+
+       if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
+           RedrawWindow( lphc->self->hwndSelf, NULL, 0,
+                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
+   }
+}
+
+
+/***********************************************************************
+ *           COMBO_Size
+ */
+static void COMBO_Size( LPHEADCOMBO lphc )
+{
+  RECT rect;
+  INT          w, h;
+
+  GetWindowRect( lphc->self->hwndSelf, &rect );
+  w = rect.right - rect.left; h = rect.bottom - rect.top;
+
+  DPRINT("w = %i, h = %i\n", w, h );
+
+  /* CreateWindow() may send a bogus WM_SIZE, ignore it */
+
+  if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
+  {
+      if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
+         (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
+          return;
+      else if( (lphc->dwStyle & CBS_DROPDOWN) &&
+              (h == (lphc->RectEdit.bottom - lphc->RectEdit.top))  )
+              return;
+  }
+  lphc->RectCombo = rect;
+  CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
+  CBResetPos( lphc, &rect, TRUE );
+}
+
+
+/***********************************************************************
+ *           COMBO_Font
+ */
+static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, WINBOOL bRedraw )
+{
+  RECT        rect;
+
+  lphc->hFont = hFont;
+
+  if( lphc->wState & CBF_EDIT )
+      SendMessageA( lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw );
+  SendMessageA( lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw );
+
+  GetWindowRect( lphc->self->hwndSelf, &rect );
+  OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
+                                  rect.top - lphc->RectCombo.top );
+  CBCalcPlacement( lphc, &lphc->RectEdit,
+                         &lphc->RectButton, &rect );
+  CBResetPos( lphc, &rect, bRedraw );
+}
+
+
+/***********************************************************************
+ *           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 < 768 )
+       {
+           RECT        rect;
+
+           lphc->editHeight = height;
+           GetWindowRect( lphc->self->hwndSelf, &rect );
+           OffsetRect( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
+                                          rect.top - lphc->RectCombo.top );
+           CBCalcPlacement( lphc, &lphc->RectEdit,
+                                 &lphc->RectButton, &rect );
+           CBResetPos( lphc, &rect, TRUE );
+          lRet = height;
+       }
+   } 
+   else if ( CB_OWNERDRAWN(lphc) )     /* set listbox item height */
+       lRet = SendMessageA( lphc->hWndLBox, LB_SETITEMHEIGHT, 
+                             (WPARAM)index, (LPARAM)height );
+   return lRet;
+}
+
+/***********************************************************************
+ *           COMBO_SelectString
+ */
+static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPCSTR pText )
+{
+   INT index = SendMessageA( lphc->hWndLBox, LB_SELECTSTRING, 
+                                (WPARAM)start, (LPARAM)pText );
+   if( index >= 0 )
+   {
+        if( lphc->wState & CBF_EDIT )
+           CBUpdateEdit( lphc, index );
+       else
+           CBPaintText( lphc, 0 );
+   }
+   return (LRESULT)index;
+}
+
+/***********************************************************************
+ *           COMBO_LButtonDown
+ */
+static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
+{
+   POINT     pt = { LOWORD(lParam), HIWORD(lParam) };
+   WINBOOL      bButton = PtInRect(&lphc->RectButton, pt);
+   HWND      hWnd = lphc->self->hwndSelf;
+
+   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 */
+
+           CBRollUp( lphc, TRUE, FALSE );
+          if( !IsWindow( hWnd ) ) return;
+
+           if( lphc->wState & CBF_CAPTURE )
+           {
+               lphc->wState &= ~CBF_CAPTURE;
+               ReleaseCapture();
+           }
+           lphc->wState &= ~CBF_BUTTONDOWN;
+       }
+       else
+       {
+          /* drop down the listbox and start tracking */
+
+           lphc->wState |= CBF_CAPTURE;
+           CBDropDown( lphc );
+           SetCapture( hWnd );
+       }
+       if( bButton ) CBRepaintButton( lphc );
+   }
+}
+
+/***********************************************************************
+ *           COMBO_LButtonUp
+ *
+ * Release capture and stop tracking if needed.
+ */
+static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
+{
+   if( lphc->wState & CBF_CAPTURE )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+       {
+          INT index = CBUpdateLBox( lphc );
+          CBUpdateEdit( lphc, index );
+       }
+       ReleaseCapture();
+   }
+
+   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 = { LOWORD(lParam), HIWORD(lParam) };
+   RECT   lbRect;
+
+   if( lphc->wState & CBF_BUTTONDOWN )
+   {
+       WINBOOL bButton = PtInRect(&lphc->RectButton, pt);
+
+       if( !bButton )
+       {
+          lphc->wState &= ~CBF_BUTTONDOWN;
+          CBRepaintButton( lphc );
+       }
+   }
+
+   GetClientRect( lphc->hWndLBox, &lbRect );
+   MapWindowPoints( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
+   if( PtInRect(&lbRect, pt) )
+   {
+       lphc->wState &= ~CBF_CAPTURE;
+       ReleaseCapture();
+       if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
+
+       /* hand over pointer tracking */
+       SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
+   }
+}
+
+
+/***********************************************************************
+ *           ComboWndProc
+ *
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win/ctrl/src/combobox_15.htm
+ */
+LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
+                             WPARAM wParam, LPARAM lParam )
+{
+    WND*       pWnd = WIN_FindWndPtr(hwnd);
+   
+    if( pWnd )
+    {
+      LPHEADCOMBO      lphc = CB_GETPTR(pWnd);
+
+      DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n",
+                  pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
+
+      if( lphc || message == WM_NCCREATE )
+      switch(message) 
+      {        
+
+       /* System messages */
+
+       case WM_NCCREATE: 
+               return COMBO_NCCreate(pWnd, lParam);
+
+       case WM_NCDESTROY: 
+               COMBO_NCDestroy(lphc);
+               break;
+
+       case WM_CREATE: 
+               return COMBO_Create(lphc, pWnd, lParam);
+
+       case WM_PAINT:
+               /* wParam may contain a valid HDC! */
+               return COMBO_Paint(lphc, wParam);
+
+       case WM_ERASEBKGND:
+               return TRUE;
+
+       case WM_GETDLGCODE: 
+               return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
+
+       case WM_SIZE:
+               if( lphc->hWndLBox && 
+                 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
+               return TRUE;
+
+       case WM_SETFONT:
+               COMBO_Font( lphc, (HFONT)wParam, (WINBOOL)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:
+#define hwndFocus ((HWND)wParam)
+               if( !hwndFocus ||
+                   (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
+                   COMBO_KillFocus( lphc );
+#undef hwndFocus
+               return TRUE;
+
+       case WM_COMMAND:
+               return COMBO_Command( lphc, wParam, (HWND)lParam );
+
+       case WM_GETTEXT:
+               return COMBO_GetText( lphc, (UINT)wParam, (LPSTR)lParam );
+
+       case WM_SETTEXT:
+       case WM_GETTEXTLENGTH:
+       case WM_CLEAR:
+       case WM_CUT:
+        case WM_PASTE:
+       case WM_COPY:
+               if( lphc->wState & CBF_EDIT )
+                   return SendMessageA( lphc->hWndEdit, message, wParam, lParam );
+               return CB_ERR;
+
+       case WM_DRAWITEM:
+       case WM_DELETEITEM:
+       case WM_COMPAREITEM:
+       case WM_MEASUREITEM:
+               return COMBO_ItemOp( lphc, message, wParam, lParam );
+
+       case WM_ENABLE:
+               if( lphc->wState & CBF_EDIT )
+                   EnableWindow( lphc->hWndEdit, (WINBOOL)wParam ); 
+               EnableWindow( lphc->hWndLBox, (WINBOOL)wParam );
+               return TRUE;
+
+       case WM_SETREDRAW:
+               if( wParam )
+                   lphc->wState &= ~CBF_NOREDRAW;
+               else
+                   lphc->wState |= CBF_NOREDRAW;
+
+               if( lphc->wState & CBF_EDIT )
+                   SendMessageA( lphc->hWndEdit, message, wParam, lParam );
+               SendMessageA( lphc->hWndLBox, message, wParam, lParam );
+               return 0;
+               
+       case WM_SYSKEYDOWN:
+               if( KEYDATA_ALT & HIWORD(lParam) )
+                   if( wParam == VK_UP || wParam == VK_DOWN )
+                       COMBO_FlipListbox( lphc, TRUE );
+               break;
+
+       case WM_CHAR:
+       case WM_KEYDOWN:
+               if( lphc->wState & CBF_EDIT )
+                   return SendMessageA( lphc->hWndEdit, message, wParam, lParam );
+               else
+                   return SendMessageA( lphc->hWndLBox, message, wParam, lParam );
+
+       case WM_LBUTTONDOWN: 
+               if( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self->hwndSelf );
+               if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
+               return TRUE;
+
+       case WM_LBUTTONUP:
+               COMBO_LButtonUp( lphc, lParam );
+               return TRUE;
+
+       case WM_MOUSEMOVE: 
+               if( lphc->wState & CBF_CAPTURE ) 
+                   COMBO_MouseMove( lphc, wParam, lParam );
+               return TRUE;
+
+       /* Combo messages */
+
+       case CB_ADDSTRING:
+               return SendMessageA( lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+
+       case CB_INSERTSTRING:
+               return SendMessageA( lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+
+       case CB_DELETESTRING:
+               return SendMessageA( lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
+
+       case CB_SELECTSTRING:
+               return COMBO_SelectString( lphc, (INT)wParam, (LPSTR)lParam );
+
+       case CB_FINDSTRING:
+               return SendMessageA( lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
+
+       case CB_FINDSTRINGEXACT:
+               return SendMessageA( lphc->hWndLBox, LB_FINDSTRINGEXACT, 
+                                                      wParam, lParam );
+
+       case CB_SETITEMHEIGHT:
+               return COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
+
+       case CB_GETITEMHEIGHT:
+               if( (INT)wParam >= 0 )  /* listbox item */
+                   return SendMessageA( lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
+               return (lphc->RectEdit.bottom - lphc->RectEdit.top);
+
+       case CB_RESETCONTENT:
+               SendMessageA( lphc->hWndLBox, LB_RESETCONTENT, 0, 0 );
+               CBPaintText( lphc, 0 );
+               return TRUE;
+
+       case CB_INITSTORAGE:
+               return SendMessageA( lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
+
+       case CB_GETHORIZONTALEXTENT:
+               return SendMessageA( lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
+
+       case CB_SETHORIZONTALEXTENT:
+               return SendMessageA( lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
+
+       case CB_GETTOPINDEX:
+               return SendMessageA( lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
+
+       case CB_GETLOCALE:
+               return SendMessageA( lphc->hWndLBox, LB_GETLOCALE, 0, 0);
+
+       case CB_SETLOCALE:
+               return SendMessageA( lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
+
+       case CB_GETDROPPEDWIDTH:
+               if( lphc->droppedWidth )
+                   return lphc->droppedWidth;
+               return lphc->RectCombo.right - lphc->RectCombo.left - 
+                          (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
+
+       case CB_SETDROPPEDWIDTH:
+               if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
+                   (INT)wParam < 768 ) lphc->droppedWidth = (INT)wParam;
+               return CB_ERR;
+
+       case CB_GETDROPPEDCONTROLRECT:
+               if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
+               return CB_OKAY;
+
+       case CB_GETDROPPEDSTATE:
+               return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
+
+
+       case CB_DIR:
+               return COMBO_Directory( lphc, (UINT)wParam, 
+                                      (LPSTR)lParam, (message == CB_DIR));
+       case CB_SHOWDROPDOWN:
+               if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+               {
+                   if( wParam )
+                   {
+                       if( !(lphc->wState & CBF_DROPPED) )
+                           CBDropDown( lphc );
+                   }
+                   else 
+                       if( lphc->wState & CBF_DROPPED ) 
+                           CBRollUp( lphc, FALSE, TRUE );
+               }
+               return TRUE;
+
+       case CB_GETCOUNT:
+               return SendMessageA( lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+
+       case CB_GETCURSEL:
+               return SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+       case CB_SETCURSEL:
+               lParam = SendMessageA( lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
+               if( lphc->wState & CBF_SELCHANGE )
+               {
+                   /* no LBN_SELCHANGE in this case, update manually */
+                  
+                   CBPaintText( lphc, 0 );
+                   lphc->wState &= ~CBF_SELCHANGE;
+               }
+               return lParam;
+
+
+       case CB_GETLBTEXT:
+               return SendMessageA( lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
+
+       case CB_GETLBTEXTLEN:
+               return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
+
+       case CB_GETITEMDATA:
+               return SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
+
+       case CB_SETITEMDATA:
+               return SendMessageA( lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
+
+       case CB_GETEDITSEL:
+               if( lphc->wState & CBF_EDIT )
+               {
+                   INT a, b;
+
+                   return SendMessageA( lphc->hWndEdit, EM_GETSEL,
+                                          (wParam) ? wParam : (WPARAM)&a,
+                                          (lParam) ? lParam : (LPARAM)&b );
+               }
+               return CB_ERR;
+
+
+       case CB_SETEDITSEL:
+               if( lphc->wState & CBF_EDIT ) 
+                   return SendMessageA( lphc->hWndEdit, EM_SETSEL, 
+                         (INT)(INT)LOWORD(lParam), (INT)(INT)HIWORD(lParam) );
+               return CB_ERR;
+
+
+       case CB_SETEXTENDEDUI:
+               if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
+
+               if( wParam )
+                   lphc->wState |= CBF_EUI;
+               else lphc->wState &= ~CBF_EUI;
+               return CB_OKAY;
+
+
+       case CB_GETEXTENDEDUI:
+               return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
+
+       case (WM_USER + 0x1B):
+               DPRINT( "[%04x]: undocumented msg!\n", hwnd );
+    }
+    return DefWindowProcA(hwnd, message, wParam, lParam);
+  }
+  return CB_ERR;
+}
+
diff --git a/reactos/lib/user32/controls/edit.c b/reactos/lib/user32/controls/edit.c
new file mode 100644 (file)
index 0000000..459bbd2
--- /dev/null
@@ -0,0 +1,3745 @@
+/*
+ *     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 <windows.h>
+#include <user32/win.h>
+#include <user32/class.h>
+#include <user32/nc.h>
+#include <user32/resource.h>
+#include <user32/combo.h>
+#include <user32/debug.h>
+
+#define MAX(x,y) x > y ? x : y 
+#define MIN(x,y) x < y ? x : y 
+
+#define BUFLIMIT_MULTI         65534   /* maximum buffer size (not including '\0')
+                                          FIXME: BTW, new specs say 65535 (do you dare ???) */
+#define BUFLIMIT_SINGLE                766     /* maximum buffer size (not including '\0') */
+#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 INT   (CALLBACK *EDITWORDBREAKPROCA)(LPSTR,INT,INT,INT);
+typedef INT   (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR,INT,INT,INT);
+
+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;
+       EDITWORDBREAKPROCW word_break_procW;
+       INT line_count;         /* number of lines */
+       INT y_offset;                   /* scroll offset in number of lines */
+       /*
+        *      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 SLOWORD(l)             ((INT)(LONG)(l))
+#define SHIWORD(l)             ((INT)((LONG)(l) >> 16))
+
+
+#define SWAP_INT(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_INT((x),(y)); } while(0)
+
+#define SWAP_UINT(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_UINT((x),(y)); } while(0)
+
+#define DPRINTF_EDIT_NOTIFY(hwnd, str) \
+       ({DPRINT( "notification " str " sent to hwnd=%08x\n", \
+                      (UINT)(hwnd));})
+
+#define EDIT_SEND_CTLCOLOR(wnd,hdc) \
+       (SendMessageA((wnd)->parent->hwndSelf, WM_CTLCOLOREDIT, \
+                       (WPARAM)(hdc), (LPARAM)(wnd)->hwndSelf))
+#define EDIT_NOTIFY_PARENT(wnd, wNotifyCode, str) \
+       (DPRINTF_EDIT_NOTIFY((wnd)->parent->hwndSelf, str), \
+       SendMessageA((wnd)->parent->hwndSelf, WM_COMMAND, \
+                       MAKEWPARAM((wnd)->wIDmenu, wNotifyCode), \
+                       (LPARAM)(wnd)->hwndSelf))
+
+#define DPRINTF_EDIT_MSG(str) \
+       DPRINT( \
+                    " bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
+                    (UINT)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(WND *wnd, EDITSTATE *es);
+static __inline__ void         EDIT_EM_EmptyUndoBuffer(WND *wnd, EDITSTATE *es);
+static __inline__ void         EDIT_WM_Clear(WND *wnd, EDITSTATE *es);
+static __inline__ void         EDIT_WM_Cut(WND *wnd, EDITSTATE *es);
+/*
+ *     This is the only exported function
+ */
+LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg,
+                            WPARAM wParam, LPARAM lParam );
+/*
+ *     Helper functions only valid for one type of control
+ */
+static void    EDIT_BuildLineDefs_ML(WND *wnd, EDITSTATE *es);
+static LPSTR   EDIT_GetPasswordPointer_SL(WND *wnd, EDITSTATE *es);
+static void    EDIT_MoveDown_ML(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MovePageDown_ML(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MovePageUp_ML(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveUp_ML(WND *wnd, EDITSTATE *es, BOOL extend);
+/*
+ *     Helper functions valid for both single line _and_ multi line controls
+ */
+static INT     EDIT_CallWordBreakProc(WND *wnd, EDITSTATE *es, INT start, INT index, INT count, INT action);
+static INT     EDIT_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
+static void    EDIT_ConfinePoint(WND *wnd, EDITSTATE *es, LPINT x, LPINT y);
+static void    EDIT_GetLineRect(WND *wnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
+static void    EDIT_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end);
+static void    EDIT_LockBuffer(WND *wnd, EDITSTATE *es);
+static BOOL    EDIT_MakeFit(WND *wnd, EDITSTATE *es, INT size);
+static BOOL    EDIT_MakeUndoFit(WND *wnd, EDITSTATE *es, INT size);
+static void    EDIT_MoveBackward(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveEnd(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveForward(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveHome(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveWordBackward(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_MoveWordForward(WND *wnd, EDITSTATE *es, BOOL extend);
+static void    EDIT_PaintLine(WND *wnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev);
+static INT     EDIT_PaintText(WND *wnd, EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
+static void    EDIT_SetCaretPos(WND *wnd, EDITSTATE *es, INT pos, BOOL after_wrap); 
+static void    EDIT_SetRectNP(WND *wnd, EDITSTATE *es, LPRECT lprc);
+static void    EDIT_UnlockBuffer(WND *wnd, EDITSTATE *es, BOOL force);
+static INT     EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action);
+/*
+ *     EM_XXX message handlers
+ */
+static LRESULT EDIT_EM_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y);
+static BOOL    EDIT_EM_FmtLines(WND *wnd, EDITSTATE *es, BOOL add_eol);
+static HLOCAL  EDIT_EM_GetHandle(WND *wnd, EDITSTATE *es);
+static INT     EDIT_EM_GetLine(WND *wnd, EDITSTATE *es, INT line, LPSTR lpch);
+static LRESULT EDIT_EM_GetSel(WND *wnd, EDITSTATE *es, UINT *start, UINT *end);
+static LRESULT EDIT_EM_GetThumb(WND *wnd, EDITSTATE *es);
+static INT     EDIT_EM_LineFromChar(WND *wnd, EDITSTATE *es, INT index);
+static INT     EDIT_EM_LineIndex(WND *wnd, EDITSTATE *es, INT line);
+static INT     EDIT_EM_LineLength(WND *wnd, EDITSTATE *es, INT index);
+static BOOL    EDIT_EM_LineScroll(WND *wnd, EDITSTATE *es, INT dx, INT dy);
+static LRESULT EDIT_EM_PosFromChar(WND *wnd, EDITSTATE *es, INT index, BOOL after_wrap);
+static void    EDIT_EM_ReplaceSel(WND *wnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace);
+static LRESULT EDIT_EM_Scroll(WND *wnd, EDITSTATE *es, INT action);
+static void    EDIT_EM_ScrollCaret(WND *wnd, EDITSTATE *es);
+static void    EDIT_EM_SetHandle(WND *wnd, EDITSTATE *es, HLOCAL hloc);
+static void    EDIT_EM_SetLimitText(WND *wnd, EDITSTATE *es, INT limit);
+static void    EDIT_EM_SetMargins(WND *wnd, EDITSTATE *es, INT action, INT left, INT right);
+static void    EDIT_EM_SetPasswordChar(WND *wnd, EDITSTATE *es, CHAR c);
+static void    EDIT_EM_SetSel(WND *wnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
+static BOOL    EDIT_EM_SetTabStops(WND *wnd, EDITSTATE *es, INT count, LPINT tabs);
+static void    EDIT_EM_SetWordBreakProc(WND *wnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp);
+static BOOL    EDIT_EM_Undo(WND *wnd, EDITSTATE *es);
+/*
+ *     WM_XXX message handlers
+ */
+static void    EDIT_WM_Char(WND *wnd, EDITSTATE *es, CHAR c, DWORD key_data);
+static void    EDIT_WM_Command(WND *wnd, EDITSTATE *es, INT code, INT id, HWND conrtol);
+static void    EDIT_WM_ContextMenu(WND *wnd, EDITSTATE *es, HWND hwnd, INT x, INT y);
+static void    EDIT_WM_Copy(WND *wnd, EDITSTATE *es);
+static LRESULT EDIT_WM_Create(WND *wnd, EDITSTATE *es, LPCREATESTRUCTA cs);
+static void    EDIT_WM_Destroy(WND *wnd, EDITSTATE *es);
+static LRESULT EDIT_WM_EraseBkGnd(WND *wnd, EDITSTATE *es, HDC dc);
+static INT     EDIT_WM_GetText(WND *wnd, EDITSTATE *es, INT count, LPSTR text);
+static LRESULT EDIT_WM_HScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
+static LRESULT EDIT_WM_KeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data);
+static LRESULT EDIT_WM_KillFocus(WND *wnd, EDITSTATE *es, HWND window_getting_focus);
+static LRESULT EDIT_WM_LButtonDblClk(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y);
+static LRESULT EDIT_WM_LButtonDown(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y);
+static LRESULT EDIT_WM_LButtonUp(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y);
+static LRESULT EDIT_WM_MouseMove(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y);
+static LRESULT EDIT_WM_NCCreate(WND *wnd, LPCREATESTRUCTA cs);
+static void    EDIT_WM_Paint(WND *wnd, EDITSTATE *es);
+static void    EDIT_WM_Paste(WND *wnd, EDITSTATE *es);
+static void    EDIT_WM_SetFocus(WND *wnd, EDITSTATE *es, HWND window_losing_focus);
+static void    EDIT_WM_SetFont(WND *wnd, EDITSTATE *es, HFONT font, BOOL redraw);
+static void    EDIT_WM_SetText(WND *wnd, EDITSTATE *es, LPCSTR text);
+static void    EDIT_WM_Size(WND *wnd, EDITSTATE *es, UINT action, INT width, INT height);
+static LRESULT EDIT_WM_SysKeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data);
+static void    EDIT_WM_Timer(WND *wnd, EDITSTATE *es, INT id, TIMERPROC timer_proc);
+static LRESULT EDIT_WM_VScroll(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
+
+
+/*********************************************************************
+ *
+ *     EM_CANUNDO
+ *
+ */
+static __inline__ BOOL EDIT_EM_CanUndo(WND *wnd, EDITSTATE *es)
+{
+       return (es->undo_insert_count || lstrlenA(es->undo_text));
+}
+
+
+/*********************************************************************
+ *
+ *     EM_EMPTYUNDOBUFFER
+ *
+ */
+static __inline__ void EDIT_EM_EmptyUndoBuffer(WND *wnd, EDITSTATE *es)
+{
+       es->undo_insert_count = 0;
+       *es->undo_text = '\0';
+}
+
+
+/*********************************************************************
+ *
+ *     WM_CLEAR
+ *
+ */
+static __inline__ void EDIT_WM_Clear(WND *wnd, EDITSTATE *es)
+{
+       EDIT_EM_ReplaceSel(wnd, es, TRUE, "");
+}
+
+
+/*********************************************************************
+ *
+ *     WM_CUT
+ *
+ */
+static __inline__ void EDIT_WM_Cut(WND *wnd, EDITSTATE *es)
+{
+       EDIT_WM_Copy(wnd, es);
+       EDIT_WM_Clear(wnd, 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  bit ones, so that we can 'fall through' to the
+ *     helper functions.  These are mostly  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 )
+{
+       WND *wnd = WIN_FindWndPtr(hwnd);
+       EDITSTATE *es = *(EDITSTATE **)((wnd)->wExtra);
+       LRESULT result = 0;
+
+       switch (msg) {
+       case WM_DESTROY:
+               DPRINTF_EDIT_MSG("WM_DESTROY");
+               EDIT_WM_Destroy(wnd, es);
+               return 0;
+
+       case WM_NCCREATE:
+               DPRINTF_EDIT_MSG("WM_NCCREATE");
+               return EDIT_WM_NCCreate(wnd, (LPCREATESTRUCTA)lParam);
+       }
+
+       if (!es)
+               return DefWindowProcA(hwnd, msg, wParam, lParam);
+
+       EDIT_LockBuffer(wnd, es);
+       switch (msg) {
+       case EM_GETSEL:
+               DPRINTF_EDIT_MSG("EM_GETSEL");
+               result = EDIT_EM_GetSel(wnd, es, (UINT *)wParam, (UINT *)lParam);
+               break;
+
+       
+       case EM_SETSEL:
+               DPRINTF_EDIT_MSG("EM_SETSEL");
+               EDIT_EM_SetSel(wnd, es, wParam, lParam, FALSE);
+               result = 1;
+               break;
+
+       
+       case EM_GETRECT:
+               DPRINTF_EDIT_MSG("EM_GETRECT");
+               if (lParam)
+                       CopyRect((LPRECT)lParam, &es->format_rect);
+               break;
+
+
+       case EM_SETRECT:
+               DPRINTF_EDIT_MSG("EM_SETRECT");
+               if ((es->style & ES_MULTILINE) && lParam) {
+                       EDIT_SetRectNP(wnd, es, (LPRECT)lParam);
+                       InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+               }
+               break;
+
+
+       case EM_SETRECTNP:
+               DPRINTF_EDIT_MSG("EM_SETRECTNP");
+               if ((es->style & ES_MULTILINE) && lParam)
+                       EDIT_SetRectNP(wnd, es, (LPRECT)lParam);
+               break;
+
+
+       case EM_SCROLL:
+               DPRINTF_EDIT_MSG("EM_SCROLL");
+               result = EDIT_EM_Scroll(wnd, es, (INT)wParam);
+               break;
+
+       
+       case EM_LINESCROLL:
+               DPRINTF_EDIT_MSG("EM_LINESCROLL");
+               result = (LRESULT)EDIT_EM_LineScroll(wnd, es, (INT)wParam, (INT)lParam);
+               break;
+
+       
+       case EM_SCROLLCARET:
+               DPRINTF_EDIT_MSG("EM_SCROLLCARET");
+               EDIT_EM_ScrollCaret(wnd, es);
+               result = 1;
+               break;
+
+       case EM_GETMODIFY:
+               DPRINTF_EDIT_MSG("EM_GETMODIFY");
+               return ((es->flags & EF_MODIFIED) != 0);
+               break;
+
+       case EM_SETMODIFY:
+               DPRINTF_EDIT_MSG("EM_SETMODIFY");
+               if (wParam)
+                       es->flags |= EF_MODIFIED;
+               else
+                       es->flags &= ~EF_MODIFIED;
+               break;
+
+       case EM_GETLINECOUNT:
+               DPRINTF_EDIT_MSG("EM_GETLINECOUNT");
+               result = (es->style & ES_MULTILINE) ? es->line_count : 1;
+               break;
+
+       case EM_LINEINDEX:
+               DPRINTF_EDIT_MSG("EM_LINEINDEX");
+               result = (LRESULT)EDIT_EM_LineIndex(wnd, es, (INT)wParam);
+               break;
+
+       case EM_SETHANDLE:
+               DPRINTF_EDIT_MSG("EM_SETHANDLE");
+               EDIT_EM_SetHandle(wnd, es, (HLOCAL)wParam);
+               break;
+
+       case EM_GETHANDLE:
+               DPRINTF_EDIT_MSG("EM_GETHANDLE");
+               result = (LRESULT)EDIT_EM_GetHandle(wnd, es);
+               break;
+
+       case EM_GETTHUMB:
+               DPRINTF_EDIT_MSG("EM_GETTHUMB");
+               result = EDIT_EM_GetThumb(wnd, es);
+               break;
+
+       /* messages 0x00bf and 0x00c0 missing from specs */
+
+       case 0x00bf:
+               DPRINTF_EDIT_MSG("undocumented 0x00bf, please report");
+               result = DefWindowProcA(hwnd, msg, wParam, lParam);
+               break;
+
+       case 0x00c0:
+               DPRINTF_EDIT_MSG("undocumented 0x00c0, please report");
+               result = DefWindowProcA(hwnd, msg, wParam, lParam);
+               break;
+
+       case EM_LINELENGTH:
+               DPRINTF_EDIT_MSG("EM_LINELENGTH");
+               result = (LRESULT)EDIT_EM_LineLength(wnd, es, (INT)wParam);
+               break;
+
+
+       case EM_REPLACESEL:
+               DPRINTF_EDIT_MSG("EM_REPLACESEL");
+               EDIT_EM_ReplaceSel(wnd, es, (BOOL)wParam, (LPCSTR)lParam);
+               result = 1;
+               break;
+
+       /* message 0x00c3 missing from specs */
+
+       case 0x00c3:
+               DPRINTF_EDIT_MSG("undocumented 0x00c3, please report");
+               result = DefWindowProcA(hwnd, msg, wParam, lParam);
+               break;
+
+       case EM_GETLINE:
+               DPRINTF_EDIT_MSG("EM_GETLINE");
+               result = (LRESULT)EDIT_EM_GetLine(wnd, es, (INT)wParam, (LPSTR)lParam);
+               break;
+
+       case EM_SETLIMITTEXT:
+               DPRINTF_EDIT_MSG("EM_SETLIMITTEXT");
+               EDIT_EM_SetLimitText(wnd, es, (INT)wParam);
+               break;
+
+       case EM_CANUNDO:
+               DPRINTF_EDIT_MSG("EM_CANUNDO");
+               result = (LRESULT)EDIT_EM_CanUndo(wnd, es);
+               break;
+
+       case EM_UNDO:
+               /* fall through */
+       case WM_UNDO:
+               DPRINTF_EDIT_MSG("EM_UNDO / WM_UNDO");
+               result = (LRESULT)EDIT_EM_Undo(wnd, es);
+               break;
+
+       case EM_FMTLINES:
+               DPRINTF_EDIT_MSG("EM_FMTLINES");
+               result = (LRESULT)EDIT_EM_FmtLines(wnd, es, (BOOL)wParam);
+               break;
+
+       case EM_LINEFROMCHAR:
+               DPRINTF_EDIT_MSG("EM_LINEFROMCHAR");
+               result = (LRESULT)EDIT_EM_LineFromChar(wnd, es, (INT)wParam);
+               break;
+
+       /* message 0x00ca missing from specs */
+
+       case 0x00ca:
+               DPRINTF_EDIT_MSG("undocumented 0x00ca, please report");
+               result = DefWindowProcA(hwnd, msg, wParam, lParam);
+               break;
+
+       case EM_SETTABSTOPS:
+               DPRINTF_EDIT_MSG("EM_SETTABSTOPS");
+               result = (LRESULT)EDIT_EM_SetTabStops(wnd, es, (INT)wParam, (LPINT)lParam);
+               break;
+
+       case EM_SETPASSWORDCHAR:
+               DPRINTF_EDIT_MSG("EM_SETPASSWORDCHAR");
+               EDIT_EM_SetPasswordChar(wnd, es, (CHAR)wParam);
+               break;
+
+       case EM_EMPTYUNDOBUFFER:
+               DPRINTF_EDIT_MSG("EM_EMPTYUNDOBUFFER");
+               EDIT_EM_EmptyUndoBuffer(wnd, es);
+               break;
+
+       case EM_GETFIRSTVISIBLELINE:
+               DPRINTF_EDIT_MSG("EM_GETFIRSTVISIBLELINE");
+               result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
+               break;
+
+       case EM_SETREADONLY:
+               DPRINTF_EDIT_MSG("EM_SETREADONLY");
+               if (wParam) {
+                       wnd->dwStyle |= ES_READONLY;
+                       es->style |= ES_READONLY;
+               } else {
+                       wnd->dwStyle &= ~ES_READONLY;
+                       es->style &= ~ES_READONLY;
+               }
+               return 1;
+               break;
+
+       case EM_SETWORDBREAKPROC:
+               DPRINTF_EDIT_MSG("EM_SETWORDBREAKPROC");
+               EDIT_EM_SetWordBreakProc(wnd, es, (EDITWORDBREAKPROCA)lParam);
+               break;
+
+       case EM_GETWORDBREAKPROC:
+               DPRINTF_EDIT_MSG("EM_GETWORDBREAKPROC");
+               result = (LRESULT)es->word_break_procA;
+               break;
+
+       case EM_GETPASSWORDCHAR:
+               DPRINTF_EDIT_MSG("EM_GETPASSWORDCHAR");
+               result = es->password_char;
+               break;
+
+       /* The following EM_xxx are new to win95 and don't exist for 16 bit */
+
+       case EM_SETMARGINS:
+               DPRINTF_EDIT_MSG("EM_SETMARGINS");
+               EDIT_EM_SetMargins(wnd, es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case EM_GETMARGINS:
+               DPRINTF_EDIT_MSG("EM_GETMARGINS");
+               result = MAKELONG(es->left_margin, es->right_margin);
+               break;
+
+       case EM_GETLIMITTEXT:
+               DPRINTF_EDIT_MSG("EM_GETLIMITTEXT");
+               result = es->buffer_limit;
+               break;
+
+       case EM_POSFROMCHAR:
+               DPRINTF_EDIT_MSG("EM_POSFROMCHAR");
+               result = EDIT_EM_PosFromChar(wnd, es, (INT)wParam, FALSE);
+               break;
+
+       case EM_CHARFROMPOS:
+               DPRINTF_EDIT_MSG("EM_CHARFROMPOS");
+               result = EDIT_EM_CharFromPos(wnd, es, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case WM_GETDLGCODE:
+               DPRINTF_EDIT_MSG("WM_GETDLGCODE");
+               result = (es->style & ES_MULTILINE) ?
+                               DLGC_WANTALLKEYS | DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS :
+                               DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
+               break;
+
+       case WM_CHAR:
+               DPRINTF_EDIT_MSG("WM_CHAR");
+               EDIT_WM_Char(wnd, es, (CHAR)wParam, (DWORD)lParam);
+               break;
+
+       case WM_CLEAR:
+               DPRINTF_EDIT_MSG("WM_CLEAR");
+               EDIT_WM_Clear(wnd, es);
+               break;
+
+       case WM_COMMAND:
+               DPRINTF_EDIT_MSG("WM_COMMAND");
+               EDIT_WM_Command(wnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
+               break;
+
+       case WM_CONTEXTMENU:
+               DPRINTF_EDIT_MSG("WM_CONTEXTMENU");
+               EDIT_WM_ContextMenu(wnd, es, (HWND)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case WM_COPY:
+               DPRINTF_EDIT_MSG("WM_COPY");
+               EDIT_WM_Copy(wnd, es);
+               break;
+
+       case WM_CREATE:
+               DPRINTF_EDIT_MSG("WM_CREATE");
+               result = EDIT_WM_Create(wnd, es, (LPCREATESTRUCTA)lParam);
+               break;
+
+       case WM_CUT:
+               DPRINTF_EDIT_MSG("WM_CUT");
+               EDIT_WM_Cut(wnd, es);
+               break;
+
+       case WM_ENABLE:
+               DPRINTF_EDIT_MSG("WM_ENABLE");
+               InvalidateRect(hwnd, NULL, TRUE);
+               break;
+
+       case WM_ERASEBKGND:
+               DPRINTF_EDIT_MSG("WM_ERASEBKGND");
+               result = EDIT_WM_EraseBkGnd(wnd, es, (HDC)wParam);
+               break;
+
+       case WM_GETFONT:
+               DPRINTF_EDIT_MSG("WM_GETFONT");
+               result = (LRESULT)es->font;
+               break;
+
+       case WM_GETTEXT:
+               DPRINTF_EDIT_MSG("WM_GETTEXT");
+               result = (LRESULT)EDIT_WM_GetText(wnd, es, (INT)wParam, (LPSTR)lParam);
+               break;
+
+       case WM_GETTEXTLENGTH:
+               DPRINTF_EDIT_MSG("WM_GETTEXTLENGTH");
+               result = lstrlenA(es->text);
+               break;
+
+       case WM_HSCROLL:
+               DPRINTF_EDIT_MSG("WM_HSCROLL");
+               result = EDIT_WM_HScroll(wnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)lParam);
+               break;
+
+       case WM_KEYDOWN:
+               DPRINTF_EDIT_MSG("WM_KEYDOWN");
+               result = EDIT_WM_KeyDown(wnd, es, (INT)wParam, (DWORD)lParam);
+               break;
+
+       case WM_KILLFOCUS:
+               DPRINTF_EDIT_MSG("WM_KILLFOCUS");
+               result = EDIT_WM_KillFocus(wnd, es, (HWND)wParam);
+               break;
+
+       case WM_LBUTTONDBLCLK:
+               DPRINTF_EDIT_MSG("WM_LBUTTONDBLCLK");
+               result = EDIT_WM_LButtonDblClk(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case WM_LBUTTONDOWN:
+               DPRINTF_EDIT_MSG("WM_LBUTTONDOWN");
+               result = EDIT_WM_LButtonDown(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case WM_LBUTTONUP:
+               DPRINTF_EDIT_MSG("WM_LBUTTONUP");
+               result = EDIT_WM_LButtonUp(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               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_MSG("WM_MOUSEACTIVATE");
+               SetFocus(wnd->hwndSelf);
+               result = MA_ACTIVATE;
+               break;
+
+       case WM_MOUSEMOVE:
+               /*
+                *      DPRINTF_EDIT_MSG("WM_MOUSEMOVE");
+                */
+               result = EDIT_WM_MouseMove(wnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
+               break;
+
+       case WM_PAINT:
+               DPRINTF_EDIT_MSG("WM_PAINT");
+               EDIT_WM_Paint(wnd, es);
+               break;
+
+       case WM_PASTE:
+               DPRINTF_EDIT_MSG("WM_PASTE");
+               EDIT_WM_Paste(wnd, es);
+               break;
+
+       case WM_SETFOCUS:
+               DPRINTF_EDIT_MSG("WM_SETFOCUS");
+               EDIT_WM_SetFocus(wnd, es, (HWND)wParam);
+               break;
+
+       case WM_SETFONT:
+               DPRINTF_EDIT_MSG("WM_SETFONT");
+               EDIT_WM_SetFont(wnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
+               break;
+
+       case WM_SETTEXT:
+               DPRINTF_EDIT_MSG("WM_SETTEXT");
+               EDIT_WM_SetText(wnd, es, (LPCSTR)lParam);
+               result = TRUE;
+               break;
+
+       case WM_SIZE:
+               DPRINTF_EDIT_MSG("WM_SIZE");
+               EDIT_WM_Size(wnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
+               break;
+
+       case WM_SYSKEYDOWN:
+               DPRINTF_EDIT_MSG("WM_SYSKEYDOWN");
+               result = EDIT_WM_SysKeyDown(wnd, es, (INT)wParam, (DWORD)lParam);
+               break;
+
+       case WM_TIMER:
+               DPRINTF_EDIT_MSG("WM_TIMER");
+               EDIT_WM_Timer(wnd, es, (INT)wParam, (TIMERPROC)lParam);
+               break;
+
+       case WM_VSCROLL:
+               DPRINTF_EDIT_MSG("WM_VSCROLL");
+               result = EDIT_WM_VScroll(wnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)(lParam));
+               break;
+
+       default:
+               result = DefWindowProcA(hwnd, msg, wParam, lParam);
+               break;
+       }
+       EDIT_UnlockBuffer(wnd, es, FALSE);
+       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(WND *wnd, EDITSTATE *es)
+{
+       HDC dc;
+       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;
+
+       dc = GetDC(wnd->hwndSelf);
+       if (es->font)
+               old_font = SelectObject(dc, es->font);
+
+       fw = es->format_rect.right - es->format_rect.left;
+       start = es->text;
+       previous_next = &es->first_line_def;
+       do {
+               current_def = 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;
+               }
+               current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc,
+                                       start, current_def->net_length,
+                                       es->tabs_count, es->tabs));
+               /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 767 ???) */
+               if ((!(es->style & ES_AUTOHSCROLL)) && (current_def->width > fw)) {
+                       INT next = 0;
+                       INT prev;
+                       do {
+                               prev = next;
+                               next = EDIT_CallWordBreakProc(wnd, es, start - es->text,
+                                               prev + 1, current_def->net_length, WB_RIGHT);
+                               current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc,
+                                                       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(dc,
+                                                               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(dc, 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 (es->font)
+               SelectObject(dc, old_font);
+       ReleaseDC(wnd->hwndSelf, dc);
+}
+
+
+/*********************************************************************
+ *
+ *     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  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(WND *wnd, EDITSTATE *es, INT start, INT index, INT count, INT action)
+{
+       if (es->word_break_procA)
+        {
+            DPRINT("(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n",
+                           es->word_break_procA, 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(WND *wnd, 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(wnd->hwndSelf);
+               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(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(wnd, es);
+               dc = GetDC(wnd->hwndSelf);
+               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;
+                        GetTextExtentPointA( 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;
+                    while (low < high - 1)
+                    {
+                        INT mid = (low + high) / 2;
+                        GetTextExtentPointA( 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 (es->font)
+               SelectObject(dc, old_font);
+       ReleaseDC(wnd->hwndSelf, 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(WND *wnd, 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(WND *wnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
+{
+       INT line_index =  EDIT_EM_LineIndex(wnd, 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(wnd, es, line_index + scol, TRUE));
+       rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(wnd, es, line_index + ecol, TRUE));
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_GetPasswordPointer_SL
+ *
+ *     note: caller should free the (optionally) allocated buffer
+ *
+ */
+static LPSTR EDIT_GetPasswordPointer_SL(WND *wnd, EDITSTATE *es)
+{
+       if (es->style & ES_PASSWORD) {
+               INT len = lstrlenA(es->text);
+               LPSTR text = HeapAlloc(es->heap, 0, len + 1);
+               HEAP_memset(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(WND *wnd, EDITSTATE *es)
+{
+       if (!es) {
+               DPRINT( "no EDITSTATE ... please report\n");
+               return;
+       }
+       if (!(es->style & ES_MULTILINE))
+               return;
+       if (!es->text) {
+               if (es->hloc)
+                       es->text = LocalLock(es->hloc);
+               else {
+                       DPRINT( "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(WND *wnd, EDITSTATE *es, INT start, INT end)
+{
+       RECT line_rect;
+       RECT rc;
+
+       EDIT_GetLineRect(wnd, es, 0, start, end, &line_rect);
+       if (IntersectRect(&rc, &line_rect, &es->format_rect))
+               InvalidateRect(wnd->hwndSelf, &rc, FALSE);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_ML_InvalidateText
+ *
+ *     Called from EDIT_InvalidateText().
+ *     Does the job for multi-line controls only.
+ *
+ */
+static void EDIT_ML_InvalidateText(WND *wnd, EDITSTATE *es, INT start, INT end)
+{
+       INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+       INT sl = EDIT_EM_LineFromChar(wnd, es, start);
+       INT el = EDIT_EM_LineFromChar(wnd, 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(wnd, es, sl);
+       ec = end - EDIT_EM_LineIndex(wnd, 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(wnd, es, EDIT_EM_LineIndex(wnd, es, el));
+       }
+       GetClientRect(wnd->hwndSelf, &rc1);
+       IntersectRect(&rcWnd, &rc1, &es->format_rect);
+       if (sl == el) {
+               EDIT_GetLineRect(wnd, es, sl, sc, ec, &rcLine);
+               if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+                       InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE);
+       } else {
+               EDIT_GetLineRect(wnd, es, sl, sc,
+                               EDIT_EM_LineLength(wnd, es,
+                                       EDIT_EM_LineIndex(wnd, es, sl)),
+                               &rcLine);
+               if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+                       InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE);
+               for (l = sl + 1 ; l < el ; l++) {
+                       EDIT_GetLineRect(wnd, es, l, 0,
+                               EDIT_EM_LineLength(wnd, es,
+                                       EDIT_EM_LineIndex(wnd, es, l)),
+                               &rcLine);
+                       if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+                               InvalidateRect(wnd->hwndSelf, &rcUpdate, FALSE);
+               }
+               EDIT_GetLineRect(wnd, es, el, 0, ec, &rcLine);
+               if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
+                       InvalidateRect(wnd->hwndSelf, &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(WND *wnd, 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(wnd, es, start, end);
+       else
+               EDIT_SL_InvalidateText(wnd, es, start, end);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MakeFit
+ *
+ *     Try to fit size + 1 bytes in the buffer.  Constrain to limits.
+ *
+ */
+static BOOL EDIT_MakeFit(WND *wnd, EDITSTATE *es, INT size)
+{
+       HLOCAL hNew;
+
+       if (size <= es->buffer_size)
+               return TRUE;
+       if (size > es->buffer_limit) {
+               EDIT_NOTIFY_PARENT(wnd, EN_MAXTEXT, "EN_MAXTEXT");
+               return FALSE;
+       }
+       size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
+       if (size > es->buffer_limit)
+               size = es->buffer_limit;
+
+       DPRINT( "trying to ReAlloc to %d+1\n", size);
+
+       EDIT_UnlockBuffer(wnd, es, TRUE);
+       if (es->text) {
+               if ((es->text = HeapReAlloc(es->heap, 0, es->text, size + 1)))
+                       es->buffer_size = MIN(HeapSize(es->heap, 0, es->text) - 1, es->buffer_limit);
+               else
+                       es->buffer_size = 0;
+       } else if (es->hloc) {
+               if ((hNew = LocalReAlloc(es->hloc, size + 1, 0))) {
+                       DPRINT( "Old  bit handle %08x, new handle %08x\n", es->hloc, hNew);
+                       es->hloc = hNew;
+                       es->buffer_size = MIN(LocalSize(es->hloc) - 1, es->buffer_limit);
+               }
+       }
+       if (es->buffer_size < size) {
+               EDIT_LockBuffer(wnd, es);
+               DPRINT( "FAILED !  We now have %d+1\n", es->buffer_size);
+               EDIT_NOTIFY_PARENT(wnd, EN_ERRSPACE, "EN_ERRSPACE");
+               return FALSE;
+       } else {
+               EDIT_LockBuffer(wnd, es);
+               DPRINT( "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(WND *wnd, EDITSTATE *es, INT size)
+{
+       if (size <= es->undo_buffer_size)
+               return TRUE;
+       size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
+
+       DPRINT( "trying to ReAlloc to %d+1\n", size);
+
+       if ((es->undo_text = HeapReAlloc(es->heap, 0, es->undo_text, size + 1))) {
+               es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1;
+               if (es->undo_buffer_size < size) {
+                       DPRINT( "FAILED !  We now have %d+1\n", es->undo_buffer_size);
+                       return FALSE;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveBackward
+ *
+ */
+static void EDIT_MoveBackward(WND *wnd, 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(wnd, es, extend ? es->selection_start : e, e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, 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(WND *wnd, 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(wnd, es, e, after_wrap);
+       INT x = SLOWORD(pos);
+       INT y = SHIWORD(pos);
+
+       e = EDIT_CharFromPos(wnd, es, x, y + es->line_height, &after_wrap);
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveEnd
+ *
+ */
+static void EDIT_MoveEnd(WND *wnd, EDITSTATE *es, BOOL extend)
+{
+       BOOL after_wrap = FALSE;
+       INT e;
+
+       if (es->style & ES_MULTILINE)
+               e = EDIT_CharFromPos(wnd, es, 0x7fffffff,
+                       HIWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
+       else
+               e = lstrlenA(es->text);
+       EDIT_EM_SetSel(wnd, es, extend ? es->selection_start : e, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveForward
+ *
+ */
+static void EDIT_MoveForward(WND *wnd, 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(wnd, es, extend ? es->selection_start : e, e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveHome
+ *
+ *     Home key: move to beginning of line.
+ *
+ */
+static void EDIT_MoveHome(WND *wnd, EDITSTATE *es, BOOL extend)
+{
+       INT e;
+
+       if (es->style & ES_MULTILINE)
+               e = EDIT_CharFromPos(wnd, es, 0x80000000,
+                       HIWORD(EDIT_EM_PosFromChar(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
+       else
+               e = 0;
+       EDIT_EM_SetSel(wnd, es, e, extend ? es->selection_start : e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, 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(WND *wnd, 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(wnd, es, e, after_wrap);
+       INT x = SLOWORD(pos);
+       INT y = SHIWORD(pos);
+
+       e = EDIT_CharFromPos(wnd, es, x,
+               y + (es->format_rect.bottom - es->format_rect.top),
+               &after_wrap);
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, 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(WND *wnd, 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(wnd, es, e, after_wrap);
+       INT x = SLOWORD(pos);
+       INT y = SHIWORD(pos);
+
+       e = EDIT_CharFromPos(wnd, es, x,
+               y - (es->format_rect.bottom - es->format_rect.top),
+               &after_wrap);
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, 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(WND *wnd, 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(wnd, es, e, after_wrap);
+       INT x = SLOWORD(pos);
+       INT y = SHIWORD(pos);
+
+       e = EDIT_CharFromPos(wnd, es, x, y - es->line_height, &after_wrap);
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveWordBackward
+ *
+ */
+static void EDIT_MoveWordBackward(WND *wnd, EDITSTATE *es, BOOL extend)
+{
+       INT s = es->selection_start;
+       INT e = es->selection_end;
+       INT l;
+       INT ll;
+       INT li;
+
+       l = EDIT_EM_LineFromChar(wnd, es, e);
+       ll = EDIT_EM_LineLength(wnd, es, e);
+       li = EDIT_EM_LineIndex(wnd, es, l);
+       if (e - li == 0) {
+               if (l) {
+                       li = EDIT_EM_LineIndex(wnd, es, l - 1);
+                       e = li + EDIT_EM_LineLength(wnd, es, li);
+               }
+       } else {
+               e = li + (INT)EDIT_CallWordBreakProc(wnd, es,
+                               li, e - li, ll, WB_LEFT);
+       }
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_MoveWordForward
+ *
+ */
+static void EDIT_MoveWordForward(WND *wnd, EDITSTATE *es, BOOL extend)
+{
+       INT s = es->selection_start;
+       INT e = es->selection_end;
+       INT l;
+       INT ll;
+       INT li;
+
+       l = EDIT_EM_LineFromChar(wnd, es, e);
+       ll = EDIT_EM_LineLength(wnd, es, e);
+       li = EDIT_EM_LineIndex(wnd, es, l);
+       if (e - li == ll) {
+               if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
+                       e = EDIT_EM_LineIndex(wnd, es, l + 1);
+       } else {
+               e = li + EDIT_CallWordBreakProc(wnd, es,
+                               li, e - li + 1, ll, WB_RIGHT);
+       }
+       if (!extend)
+               s = e;
+       EDIT_EM_SetSel(wnd, es, s, e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_PaintLine
+ *
+ */
+static void EDIT_PaintLine(WND *wnd, 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;
+
+       DPRINT( "line=%d\n", line);
+
+       pos = EDIT_EM_PosFromChar(wnd, es, EDIT_EM_LineIndex(wnd, es, line), FALSE);
+       x = SLOWORD(pos);
+       y = SHIWORD(pos);
+       li = EDIT_EM_LineIndex(wnd, es, line);
+       ll = EDIT_EM_LineLength(wnd, 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(wnd, es, dc, x, y, line, 0, s - li, FALSE);
+               x += EDIT_PaintText(wnd, es, dc, x, y, line, s - li, e - s, TRUE);
+               x += EDIT_PaintText(wnd, es, dc, x, y, line, e - li, li + ll - e, FALSE);
+       } else
+               x += EDIT_PaintText(wnd, es, dc, x, y, line, 0, ll, FALSE);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_PaintText
+ *
+ */
+static INT EDIT_PaintText(WND *wnd, EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
+{
+       COLORREF BkColor;
+       COLORREF TextColor;
+       INT ret;
+       INT li;
+       SIZE size;
+
+       if (!count)
+               return 0;
+       BkColor = GetBkColor(dc);
+       TextColor = GetTextColor(dc);
+       if (rev) {
+               SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
+               SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+       }
+       li = EDIT_EM_LineIndex(wnd, es, line);
+       if (es->style & ES_MULTILINE) {
+               ret = (INT)LOWORD(TabbedTextOutA(dc, x, y, es->text + li + col, count,
+                                       es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
+       } else {
+               LPSTR text = EDIT_GetPasswordPointer_SL(wnd, es);
+               TextOutA(dc, x, y, text + li + col, count);
+               GetTextExtentPointA(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);
+       }
+       return ret;
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_SetCaretPos
+ *
+ */
+static void EDIT_SetCaretPos(WND *wnd, EDITSTATE *es, INT pos,
+                            BOOL after_wrap)
+{
+       LRESULT res = EDIT_EM_PosFromChar(wnd, 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(WND *wnd, 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)
+               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(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_UnlockBuffer
+ *
+ */
+static void EDIT_UnlockBuffer(WND *wnd, EDITSTATE *es, BOOL force)
+{
+       if (!es) {
+               DPRINT( "no EDITSTATE ... please report\n");
+               return;
+       }
+       if (!(es->style & ES_MULTILINE))
+               return;
+       if (!es->lock_count) {
+               DPRINT( "lock_count == 0 ... please report\n");
+               return;
+       }
+       if (!es->text) {
+               DPRINT( "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;
+
+       DPRINT( "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:
+               DPRINT( "unknown action code, please report !\n");
+               break;
+       }
+       return ret;
+}
+
+
+/*********************************************************************
+ *
+ *     EM_CHARFROMPOS
+ *
+ *     FIXME: do the specs mean to return LineIndex or LineNumber ???
+ *             Let's assume LineIndex is meant
+ *     FIXME: do the specs mean to return -1 if outside client area or
+ *             if outside formatting rectangle ???
+ *
+ */
+static LRESULT EDIT_EM_CharFromPos(WND *wnd, EDITSTATE *es, INT x, INT y)
+{
+       POINT pt;
+       RECT rc;
+       INT index;
+
+       pt.x = x;
+       pt.y = y;
+       GetClientRect(wnd->hwndSelf, &rc);
+       if (!PtInRect(&rc, pt))
+               return -1;
+
+       index = EDIT_CharFromPos(wnd, es, x, y, NULL);
+       return MAKELONG(index, EDIT_EM_LineIndex(wnd, es,
+                       EDIT_EM_LineFromChar(wnd, es, index)));
+}
+
+
+/*********************************************************************
+ *
+ *     EM_FMTLINES
+ *
+ * Enable or disable soft breaks.
+ */
+static BOOL EDIT_EM_FmtLines(WND *wnd, EDITSTATE *es, BOOL add_eol)
+{
+       es->flags &= ~EF_USE_SOFTBRK;
+       if (add_eol) {
+               es->flags |= EF_USE_SOFTBRK;
+               DPRINT( "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 our own heap.
+ *     However, with this message a  bit application requests
+ *     a handle to  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(WND *wnd, 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))) {
+               DPRINT( "could not allocate new  bit buffer\n");
+               return 0;
+       }
+       newSize = MIN(LocalSize(newBuf) - 1, es->buffer_limit);
+       if (!(newText = LocalLock(newBuf))) {
+               DPRINT( "could not lock new  bit buffer\n");
+               LocalFree(newBuf);
+               return 0;
+       }
+       lstrcpyA(newText, es->text);
+       EDIT_UnlockBuffer(wnd, es, TRUE);
+       if (es->text)
+               HeapFree(es->heap, 0, es->text);
+       es->hloc = newBuf;
+       es->buffer_size = newSize;
+       es->text = newText;
+       EDIT_LockBuffer(wnd, es);
+       DPRINT( "switched to  bit local heap\n");
+
+       return es->hloc;
+}
+
+
+
+
+/*********************************************************************
+ *
+ *     EM_GETLINE
+ *
+ */
+static INT EDIT_EM_GetLine(WND *wnd, EDITSTATE *es, INT line, LPSTR lpch)
+{
+       LPSTR src;
+       INT len;
+       INT i;
+
+       if (es->style & ES_MULTILINE) {
+               if (line >= es->line_count)
+                       return 0;
+       } else
+               line = 0;
+       i = EDIT_EM_LineIndex(wnd, es, line);
+       src = es->text + i;
+       len = MIN(*(WORD *)lpch, EDIT_EM_LineLength(wnd, es, i));
+       for (i = 0 ; i < len ; i++) {
+               *lpch = *src;
+               src++;
+               lpch++;
+       }
+       return (LRESULT)len;
+}
+
+
+/*********************************************************************
+ *
+ *     EM_GETSEL
+ *
+ */
+static LRESULT EDIT_EM_GetSel(WND *wnd, EDITSTATE *es, UINT * start, UINT * 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
+ *
+ *     FIXME: now it's also broken, because of the new WM_HSCROLL /
+ *             WM_VSCROLL handlers
+ *
+ */
+static LRESULT EDIT_EM_GetThumb(WND *wnd, EDITSTATE *es)
+{
+       return MAKELONG(EDIT_WM_VScroll(wnd, es, EM_GETTHUMB, 0, 0),
+               EDIT_WM_HScroll(wnd, es, EM_GETTHUMB, 0, 0));
+}
+
+
+/*********************************************************************
+ *
+ *     EM_LINEFROMCHAR
+ *
+ */
+static INT EDIT_EM_LineFromChar(WND *wnd, 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);
+
+       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(WND *wnd, 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(WND *wnd, EDITSTATE *es, INT index)
+{
+       LINEDEF *line_def;
+
+       if (!(es->style & ES_MULTILINE))
+               return lstrlenA(es->text);
+
+       if (index == -1) {
+               /* FIXME: broken
+               INT sl = EDIT_EM_LineFromChar(wnd, es, es->selection_start);
+               INT el = EDIT_EM_LineFromChar(wnd, es, es->selection_end);
+               return es->selection_start - es->line_defs[sl].offset +
+                               es->line_defs[el].offset +
+                               es->line_defs[el].length - es->selection_end;
+               */
+               return 0;
+       }
+       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
+ *
+ *     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(WND *wnd, EDITSTATE *es, INT dx, INT dy)
+{
+       INT nyoff;
+
+       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);
+       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;
+               GetClientRect(wnd->hwndSelf, &rc1);
+               IntersectRect(&rc, &rc1, &es->format_rect);
+               ScrollWindowEx(wnd->hwndSelf, -dx, dy,
+                               NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
+               es->y_offset = nyoff;
+               es->x_offset += dx;
+       }
+       if (dx && !(es->flags & EF_HSCROLL_TRACK))
+               EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
+       if (dy && !(es->flags & EF_VSCROLL_TRACK))
+               EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
+       return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *     EM_POSFROMCHAR
+ *
+ */
+static LRESULT EDIT_EM_PosFromChar(WND *wnd, EDITSTATE *es, INT index, BOOL after_wrap)
+{
+       INT len = lstrlenA(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(wnd->hwndSelf);
+       if (es->font)
+               old_font = SelectObject(dc, es->font);
+       if (es->style & ES_MULTILINE) {
+               l = EDIT_EM_LineFromChar(wnd, es, index);
+               y = (l - es->y_offset) * es->line_height;
+               li = EDIT_EM_LineIndex(wnd, 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(wnd, 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(wnd, es);
+               if (index < es->x_offset) {
+                       GetTextExtentPointA(dc, text + index,
+                                       es->x_offset - index, &size);
+                       x = -size.cx;
+               } else {
+                       GetTextExtentPointA(dc, text + es->x_offset,
+                                       index - 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 (es->font)
+               SelectObject(dc, old_font);
+       ReleaseDC(wnd->hwndSelf, dc);
+       return MAKELONG((INT)x, (INT)y);
+}
+
+
+/*********************************************************************
+ *
+ *     EM_REPLACESEL
+ *
+ *     FIXME: handle ES_NUMBER and ES_OEMCONVERT here
+ *
+ */
+static void EDIT_EM_ReplaceSel(WND *wnd, 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(wnd, 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(wnd, 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(wnd, 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(wnd, 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(wnd, es);
+
+               /* now delete */
+               lstrcpyA(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(wnd, 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_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(wnd, es);
+
+       EDIT_EM_SetSel(wnd, es, s, s, FALSE);
+       es->flags |= EF_MODIFIED;
+       es->flags |= EF_UPDATE;
+       EDIT_EM_ScrollCaret(wnd, es);
+
+       /* FIXME: really inefficient */
+       InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *     EM_SCROLL
+ *
+ */
+static LRESULT EDIT_EM_Scroll(WND *wnd, 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_EM_LineScroll(wnd, es, 0, dy);
+               EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
+       }
+       return MAKELONG((INT)dy, (BOOL)TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *     EM_SCROLLCARET
+ *
+ */
+static void EDIT_EM_ScrollCaret(WND *wnd, 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(wnd, es, es->selection_end);
+               li = EDIT_EM_LineIndex(wnd, es, l);
+               x = SLOWORD(EDIT_EM_PosFromChar(wnd, 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(wnd, es, dx, dy);
+       } else {
+               INT x;
+               INT goal;
+               INT format_width;
+
+               if (!(es->style & ES_AUTOHSCROLL))
+                       return;
+
+               x = SLOWORD(EDIT_EM_PosFromChar(wnd, 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(wnd, es, es->selection_end, FALSE));
+                       } while ((x < goal) && es->x_offset);
+                       /* FIXME: use ScrollWindow() somehow to improve performance */
+                       InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+               } 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(wnd, es, es->selection_end, FALSE));
+                               x_last = SLOWORD(EDIT_EM_PosFromChar(wnd, es, len, FALSE));
+                       } while ((x > goal) && (x_last > es->format_rect.right));
+                       /* FIXME: use ScrollWindow() somehow to improve performance */
+                       InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+               }
+       }
+}
+
+
+/*********************************************************************
+ *
+ *     EM_SETHANDLE
+ *
+ *     FIXME:  ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
+ *
+ */
+static void EDIT_EM_SetHandle(WND *wnd, EDITSTATE *es, HLOCAL hloc)
+{
+       if (!(es->style & ES_MULTILINE))
+               return;
+
+       if (!hloc) {
+               DPRINT( "called with NULL handle\n");
+               return;
+       }
+
+       EDIT_UnlockBuffer(wnd, 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(wnd, es);
+
+       es->x_offset = es->y_offset = 0;
+       es->selection_start = es->selection_end = 0;
+       EDIT_EM_EmptyUndoBuffer(wnd, es);
+       es->flags &= ~EF_MODIFIED;
+       es->flags &= ~EF_UPDATE;
+       EDIT_BuildLineDefs_ML(wnd, es);
+       InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+
+
+
+/*********************************************************************
+ *
+ *     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(WND *wnd, 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. It also appears not to affect
+ * multiline controls??
+ *
+ */
+static void EDIT_EM_SetMargins(WND *wnd, EDITSTATE *es, INT action,
+                              INT left, INT right)
+{
+       if (action & EC_LEFTMARGIN) {
+               if (left != EC_USEFONTINFO)
+                       es->left_margin = left;
+               else
+                       if (es->style & ES_MULTILINE)
+                               es->left_margin = 0; /* ?? */
+                       else
+                         es->left_margin = es->char_width;
+       }
+
+       if (action & EC_RIGHTMARGIN) {
+               if (right != EC_USEFONTINFO)
+                       es->right_margin = right;
+               else
+                       if (es->style & ES_MULTILINE)
+                               es->right_margin = 0; /* ?? */
+                       else
+                               es->right_margin = es->char_width;
+       }
+       DPRINT( "left=%d, right=%d\n", es->left_margin, es->right_margin);
+}
+
+
+/*********************************************************************
+ *
+ *     EM_SETPASSWORDCHAR
+ *
+ */
+static void EDIT_EM_SetPasswordChar(WND *wnd, EDITSTATE *es, CHAR c)
+{
+       if (es->style & ES_MULTILINE)
+               return;
+
+       if (es->password_char == c)
+               return;
+
+       es->password_char = c;
+       if (c) {
+               wnd->dwStyle |= ES_PASSWORD;
+               es->style |= ES_PASSWORD;
+       } else {
+               wnd->dwStyle &= ~ES_PASSWORD;
+               es->style &= ~ES_PASSWORD;
+       }
+       InvalidateRect(wnd->hwndSelf, 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(WND *wnd, 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(wnd, 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 (end != old_start)
+        {
+/*
+ * One can also do 
+ *          ORDER_UINT(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(wnd, es, start, end);
+                EDIT_InvalidateText(wnd, es, old_start, old_end);
+            }
+            else
+            {
+                EDIT_InvalidateText(wnd, es, start, old_start);
+                EDIT_InvalidateText(wnd, es, end, old_end);
+            }
+       }
+        else EDIT_InvalidateText(wnd, es, start, old_end);
+}
+
+
+/*********************************************************************
+ *
+ *     EM_SETTABSTOPS
+ *
+ */
+static BOOL EDIT_EM_SetTabStops(WND *wnd, 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 = HeapAlloc(es->heap, 0, count * sizeof(INT));
+               memcpy(es->tabs, tabs, count * sizeof(INT));
+       }
+       return TRUE;
+}
+
+
+
+
+/*********************************************************************
+ *
+ *     EM_SETWORDBREAKPROC
+ *
+ */
+static void EDIT_EM_SetWordBreakProc(WND *wnd, 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(wnd, es);
+               InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+       }
+}
+
+
+
+
+
+/*********************************************************************
+ *
+ *     EM_UNDO / WM_UNDO
+ *
+ */
+static BOOL EDIT_EM_Undo(WND *wnd, EDITSTATE *es)
+{
+       INT ulength = lstrlenA(es->undo_text);
+       LPSTR utext = HeapAlloc(es->heap, 0, ulength + 1);
+
+       lstrcpyA(utext, es->undo_text);
+
+       DPRINT( "before UNDO:insertion length = %d, deletion buffer = %s\n",
+                    es->undo_insert_count, utext);
+
+       EDIT_EM_SetSel(wnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+       EDIT_EM_EmptyUndoBuffer(wnd, es);
+       EDIT_EM_ReplaceSel(wnd, es, TRUE, utext);
+       EDIT_EM_SetSel(wnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+       HeapFree(es->heap, 0, utext);
+
+       DPRINT( "after UNDO:insertion length = %d, deletion buffer = %s\n",
+                       es->undo_insert_count, es->undo_text);
+
+       return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_CHAR
+ *
+ */
+static void EDIT_WM_Char(WND *wnd, EDITSTATE *es, CHAR c, DWORD key_data)
+{
+       switch (c) {
+       case '\r':
+       case '\n':
+               if (es->style & ES_MULTILINE) {
+                       if (es->style & ES_READONLY) {
+                               EDIT_MoveHome(wnd, es, FALSE);
+                               EDIT_MoveDown_ML(wnd, es, FALSE);
+                       } else
+                               EDIT_EM_ReplaceSel(wnd, es, TRUE, "\r\n");
+               }
+               break;
+       case '\t':
+               if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
+                       EDIT_EM_ReplaceSel(wnd, es, TRUE, "\t");
+               break;
+       default:
+               if (!(es->style & ES_READONLY) && ((BYTE)c >= ' ') && (c != 127)) {
+                       char str[2];
+                       str[0] = c;
+                       str[1] = '\0';
+                       EDIT_EM_ReplaceSel(wnd, es, TRUE, str);
+               }
+               break;
+       }
+}
+
+
+/*********************************************************************
+ *
+ *     WM_COMMAND
+ *
+ */
+static void EDIT_WM_Command(WND *wnd, EDITSTATE *es, INT code, INT id, HWND control)
+{
+       if (code || control)
+               return;
+
+       switch (id) {
+               case EM_UNDO:
+                       EDIT_EM_Undo(wnd, es);
+                       break;
+               case WM_CUT:
+                       EDIT_WM_Cut(wnd, es);
+                       break;
+               case WM_COPY:
+                       EDIT_WM_Copy(wnd, es);
+                       break;
+               case WM_PASTE:
+                       EDIT_WM_Paste(wnd, es);
+                       break;
+               case WM_CLEAR:
+                       EDIT_WM_Clear(wnd, es);
+                       break;
+               case EM_SETSEL:
+                       EDIT_EM_SetSel(wnd, es, 0, -1, FALSE);
+                       EDIT_EM_ScrollCaret(wnd, es);
+                       break;
+               default:
+                       DPRINT( "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(WND *wnd, EDITSTATE *es, HWND hwnd, INT x, INT y)
+{
+       HMENU menu = LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_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(wnd, es) ? MF_ENABLED : MF_GRAYED));
+       /* cut */
+       EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? 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) ? MF_ENABLED : MF_GRAYED));
+       /* delete */
+       EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) ? 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, wnd->hwndSelf, NULL);
+       DestroyMenu(menu);
+}
+
+
+/*********************************************************************
+ *
+ *     WM_COPY
+ *
+ */
+static void EDIT_WM_Copy(WND *wnd, 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 = GlobalLock(hdst);
+       lstrcpynA(dst, es->text + s, e - s + 1);
+       GlobalUnlock(hdst);
+       OpenClipboard(wnd->hwndSelf);
+       EmptyClipboard();
+       SetClipboardData(CF_TEXT, hdst);
+       CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *     WM_CREATE
+ *
+ */
+static LRESULT EDIT_WM_Create(WND *wnd, 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(wnd, es, 0, FALSE);
+       if (cs->lpszName && *(cs->lpszName) != '\0') {
+               EDIT_EM_ReplaceSel(wnd, 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(wnd, es);
+        }
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_DESTROY
+ *
+ */
+static void EDIT_WM_Destroy(WND *wnd, EDITSTATE *es)
+{
+       if (es->hloc) {
+               while (LocalUnlock(es->hloc)) ;
+               LocalFree(es->hloc);
+       }
+       
+       HeapDestroy(es->heap);
+       HeapFree(GetProcessHeap(), 0, es);
+       *(EDITSTATE **)wnd->wExtra = NULL;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_ERASEBKGND
+ *
+ */
+static LRESULT EDIT_WM_EraseBkGnd(WND *wnd, EDITSTATE *es, HDC dc)
+{
+       HBRUSH brush;
+       RECT rc;
+
+       if (!(brush = (HBRUSH)EDIT_SEND_CTLCOLOR(wnd, dc)))
+               brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
+
+       GetClientRect(wnd->hwndSelf, &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(WND *wnd, EDITSTATE *es, INT count, LPSTR text)
+{
+       INT len = lstrlenA(es->text);
+
+       if (count > len) {
+               lstrcpyA(text, es->text);
+               return len;
+       } else
+               return -1;
+}
+
+
+/*********************************************************************
+ *
+ *     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(WND *wnd, 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)) {
+               DPRINT( "hacked WM_HSCROLL handler invoked\n");
+               DPRINT( "      if you are _not_ running 16 bit notepad, please report\n");
+               DPRINT( "      (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(wnd, EN_HSCROLL, "EN_HSCROLL");
+               break;
+       case SB_ENDSCROLL:
+               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:
+               ret = es->text_width ? es->x_offset * 100 / es->text_width : 0;
+               break;
+       case EM_LINESCROLL:
+               dx = pos;
+               break;
+
+       default:
+               DPRINT( "undocumented (hacked) WM_HSCROLL parameter, please report\n");
+               return 0;
+       }
+       if (dx)
+               EDIT_EM_LineScroll(wnd, es, dx, 0);
+       return ret;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_HSCROLL
+ *
+ */
+static LRESULT EDIT_WM_HScroll(WND *wnd, 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(wnd, 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(wnd->hwndSelf, SB_HORZ, pos, TRUE);
+                       EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
+               }
+               break;
+       case SB_ENDSCROLL:
+               break;
+
+       default:
+               DPRINT( "undocumented WM_HSCROLL parameter, please report\n");
+               return 0;
+       }
+       if (dx)
+               EDIT_EM_LineScroll(wnd, es, dx, 0);
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     EDIT_CheckCombo
+ *
+ */
+static BOOL EDIT_CheckCombo(WND *wnd, UINT msg, INT key, DWORD key_data)
+{
+       HWND hLBox;
+
+       if (WIDGETS_IsControl(wnd->parent, BIC_COMBO) &&
+                       (hLBox = COMBO_GetLBWindow(wnd->parent))) {
+               HWND hCombo = wnd->parent->hwndSelf;
+               BOOL bUIFlip = TRUE;
+
+               DPRINT( "[%04x]: handling msg %04x (%04x)\n",
+                            wnd->hwndSelf, (UINT)msg, (UINT)key);
+
+               switch (msg) {
+               case WM_KEYDOWN: /* Handle F4 and arrow keys */
+                       if (key != VK_F4) {
+                               bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0);
+                               if (SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0))
+                                       bUIFlip = FALSE;
+                       }
+                       if (!bUIFlip)
+                               SendMessageA(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
+                       else {
+                               /* make sure ComboLBox pops up */
+                               SendMessageA(hCombo, CB_SETEXTENDEDUI, 0, 0);
+                               SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0);
+                               SendMessageA(hCombo, CB_SETEXTENDEDUI, 1, 0);
+                       }
+                       break;
+               case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
+                       bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0);
+                       if (bUIFlip) {
+                               bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
+                               SendMessageA(hCombo, CB_SHOWDROPDOWN, (bUIFlip) ? FALSE : TRUE, 0);
+                       } else
+                               SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0);
+                       break;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+
+/*********************************************************************
+ *
+ *     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(WND *wnd, 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(wnd, WM_KEYDOWN, key, key_data))
+                       break;
+               if (key == VK_F4)
+                       break;
+               /* fall through */
+       case VK_LEFT:
+               if ((es->style & ES_MULTILINE) && (key == VK_UP))
+                       EDIT_MoveUp_ML(wnd, es, shift);
+               else
+                       if (control)
+                               EDIT_MoveWordBackward(wnd, es, shift);
+                       else
+                               EDIT_MoveBackward(wnd, es, shift);
+               break;
+       case VK_DOWN:
+               if (EDIT_CheckCombo(wnd, WM_KEYDOWN, key, key_data))
+                       break;
+               /* fall through */
+       case VK_RIGHT:
+               if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
+                       EDIT_MoveDown_ML(wnd, es, shift);
+               else if (control)
+                       EDIT_MoveWordForward(wnd, es, shift);
+               else
+                       EDIT_MoveForward(wnd, es, shift);
+               break;
+       case VK_HOME:
+               EDIT_MoveHome(wnd, es, shift);
+               break;
+       case VK_END:
+               EDIT_MoveEnd(wnd, es, shift);
+               break;
+       case VK_PRIOR:
+               if (es->style & ES_MULTILINE)
+                       EDIT_MovePageUp_ML(wnd, es, shift);
+               break;
+       case VK_NEXT:
+               if (es->style & ES_MULTILINE)
+                       EDIT_MovePageDown_ML(wnd, es, shift);
+               break;
+       case VK_BACK:
+               if (!(es->style & ES_READONLY) && !control) {
+                       if (es->selection_start != es->selection_end)
+                               EDIT_WM_Clear(wnd, es);
+                       else {
+                               /* delete character left of caret */
+                               EDIT_EM_SetSel(wnd, es, -1, 0, FALSE);
+                               EDIT_MoveBackward(wnd, es, TRUE);
+                               EDIT_WM_Clear(wnd, es);
+                       }
+               }
+               break;
+       case VK_DELETE:
+               if (!(es->style & ES_READONLY) && !(shift && control)) {
+                       if (es->selection_start != es->selection_end) {
+                               if (shift)
+                                       EDIT_WM_Cut(wnd, es);
+                               else
+                                       EDIT_WM_Clear(wnd, es);
+                       } else {
+                               if (shift) {
+                                       /* delete character left of caret */
+                                       EDIT_EM_SetSel(wnd, es, -1, 0, FALSE);
+                                       EDIT_MoveBackward(wnd, es, TRUE);
+                                       EDIT_WM_Clear(wnd, es);
+                               } else if (control) {
+                                       /* delete to end of line */
+                                       EDIT_EM_SetSel(wnd, es, -1, 0, FALSE);
+                                       EDIT_MoveEnd(wnd, es, TRUE);
+                                       EDIT_WM_Clear(wnd, es);
+                               } else {
+                                       /* delete character right of caret */
+                                       EDIT_EM_SetSel(wnd, es, -1, 0, FALSE);
+                                       EDIT_MoveForward(wnd, es, TRUE);
+                                       EDIT_WM_Clear(wnd, es);
+                               }
+                       }
+               }
+               break;
+       case VK_INSERT:
+               if (shift) {
+                       if (!(es->style & ES_READONLY))
+                               EDIT_WM_Paste(wnd, es);
+               } else if (control)
+                       EDIT_WM_Copy(wnd, es);
+               break;
+       }
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_KILLFOCUS
+ *
+ */
+static LRESULT EDIT_WM_KillFocus(WND *wnd, EDITSTATE *es, HWND window_getting_focus)
+{
+       es->flags &= ~EF_FOCUSED;
+       DestroyCaret();
+       if(!(es->style & ES_NOHIDESEL))
+               EDIT_InvalidateText(wnd, es, es->selection_start, es->selection_end);
+       EDIT_NOTIFY_PARENT(wnd, EN_KILLFOCUS, "EN_KILLFOCUS");
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_LBUTTONDBLCLK
+ *
+ *     The caret position has been set on the WM_LBUTTONDOWN message
+ *
+ */
+static LRESULT EDIT_WM_LButtonDblClk(WND *wnd, 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(wnd, es, e);
+       li = EDIT_EM_LineIndex(wnd, es, l);
+       ll = EDIT_EM_LineLength(wnd, es, e);
+       s = li + EDIT_CallWordBreakProc (wnd, es, li, e - li, ll, WB_LEFT);
+       e = li + EDIT_CallWordBreakProc(wnd, es, li, e - li, ll, WB_RIGHT);
+       EDIT_EM_SetSel(wnd, es, s, e, FALSE);
+       EDIT_EM_ScrollCaret(wnd, es);
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_LBUTTONDOWN
+ *
+ */
+static LRESULT EDIT_WM_LButtonDown(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y)
+{
+       INT e;
+       BOOL after_wrap;
+
+       if (!(es->flags & EF_FOCUSED))
+               return 0;
+
+       SetCapture(wnd->hwndSelf);
+       EDIT_ConfinePoint(wnd, es, &x, &y);
+       e = EDIT_CharFromPos(wnd, es, x, y, &after_wrap);
+       EDIT_EM_SetSel(wnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
+       EDIT_EM_ScrollCaret(wnd, es);
+       es->region_posx = es->region_posy = 0;
+       SetTimer(wnd->hwndSelf, 0, 100, NULL);
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_LBUTTONUP
+ *
+ */
+static LRESULT EDIT_WM_LButtonUp(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y)
+{
+       if (GetCapture() == wnd->hwndSelf) {
+               KillTimer(wnd->hwndSelf, 0);
+               ReleaseCapture();
+       }
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_MOUSEMOVE
+ *
+ */
+static LRESULT EDIT_WM_MouseMove(WND *wnd, EDITSTATE *es, DWORD keys, INT x, INT y)
+{
+       INT e;
+       BOOL after_wrap;
+       INT prex, prey;
+
+       if (GetCapture() != wnd->hwndSelf)
+               return 0;
+
+       /*
+        *      FIXME: gotta do some scrolling if outside client
+        *              area.  Maybe reset the timer ?
+        */
+       prex = x; prey = y;
+       EDIT_ConfinePoint(wnd, 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(wnd, es, x, y, &after_wrap);
+       EDIT_EM_SetSel(wnd, es, es->selection_start, e, after_wrap);
+       return 0;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_NCCREATE
+ *
+ */
+static LRESULT EDIT_WM_NCCreate(WND *wnd, LPCREATESTRUCTA cs)
+{
+       EDITSTATE *es;
+
+       if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
+               return FALSE;
+       *(EDITSTATE **)wnd->wExtra = 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;
+       if ((es->style & WS_BORDER) && !(es->style & WS_DLGFRAME))
+               wnd->dwStyle &= ~WS_BORDER;
+
+       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 = HeapAlloc(es->heap, 0, es->buffer_size + 1)))
+               return FALSE;
+       es->buffer_size = HeapSize(es->heap, 0, es->text) - 1;
+       if (!(es->undo_text = 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 = HeapAlloc(es->heap, HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
+                       return FALSE;
+       es->line_count = 1;
+
+       return TRUE;
+}
+
+/*********************************************************************
+ *
+ *     WM_PAINT
+ *
+ */
+static void EDIT_WM_Paint(WND *wnd, EDITSTATE *es)
+{
+       PAINTSTRUCT ps;
+       INT i;
+       HDC dc;
+       HFONT old_font = 0;
+       RECT rc;
+       RECT rcLine;
+       RECT rcRgn;
+       BOOL rev = IsWindowEnabled(wnd->hwndSelf) &&
+                               ((es->flags & EF_FOCUSED) ||
+                                       (es->style & ES_NOHIDESEL));
+
+       if (es->flags & EF_UPDATE)
+               EDIT_NOTIFY_PARENT(wnd, EN_UPDATE, "EN_UPDATE");
+
+       dc = BeginPaint(wnd->hwndSelf, &ps);
+       if(es->style & WS_BORDER) {
+               GetClientRect(wnd->hwndSelf, &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(wnd->hwndSelf, &rc);
+               IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
+       }
+       if (es->font)
+               old_font = SelectObject(dc, es->font);
+       EDIT_SEND_CTLCOLOR(wnd, dc);
+       if (!IsWindowEnabled(wnd->hwndSelf))
+               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(wnd, es, i, 0, -1, &rcLine);
+                       if (IntersectRect(&rc, &rcRgn, &rcLine))
+                               EDIT_PaintLine(wnd, es, dc, i, rev);
+               }
+       } else {
+               EDIT_GetLineRect(wnd, es, 0, 0, -1, &rcLine);
+               if (IntersectRect(&rc, &rcRgn, &rcLine))
+                       EDIT_PaintLine(wnd, es, dc, 0, rev);
+       }
+       if (es->font)
+               SelectObject(dc, old_font);
+       if (es->flags & EF_FOCUSED)
+               EDIT_SetCaretPos(wnd, es, es->selection_end,
+                                es->flags & EF_AFTER_WRAP);
+       EndPaint(wnd->hwndSelf, &ps);
+       if ((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(wnd->hwndSelf, SB_VERT, &si, TRUE);
+       }
+       if ((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(wnd->hwndSelf, SB_HORZ, &si, TRUE);
+       }
+
+       if (es->flags & EF_UPDATE) {
+               es->flags &= ~EF_UPDATE;
+               EDIT_NOTIFY_PARENT(wnd, EN_CHANGE, "EN_CHANGE");
+       }
+}
+
+
+/*********************************************************************
+ *
+ *     WM_PASTE
+ *
+ */
+static void EDIT_WM_Paste(WND *wnd, EDITSTATE *es)
+{
+       HGLOBAL hsrc;
+       LPSTR src;
+
+       OpenClipboard(wnd->hwndSelf);
+       if ((hsrc = GetClipboardData(CF_TEXT))) {
+               src = (LPSTR)GlobalLock(hsrc);
+               EDIT_EM_ReplaceSel(wnd, es, TRUE, src);
+               GlobalUnlock(hsrc);
+       }
+       CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *     WM_SETFOCUS
+ *
+ */
+static void EDIT_WM_SetFocus(WND *wnd, EDITSTATE *es, HWND window_losing_focus)
+{
+       es->flags |= EF_FOCUSED;
+       CreateCaret(wnd->hwndSelf, 0, 2, es->line_height);
+       EDIT_SetCaretPos(wnd, es, es->selection_end,
+                        es->flags & EF_AFTER_WRAP);
+       if(!(es->style & ES_NOHIDESEL))
+               EDIT_InvalidateText(wnd, es, es->selection_start, es->selection_end);
+       ShowCaret(wnd->hwndSelf);
+       EDIT_NOTIFY_PARENT(wnd, 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(WND *wnd, EDITSTATE *es, HFONT font, BOOL redraw)
+{
+       TEXTMETRIC tm;
+       HDC dc;
+       HFONT old_font = 0;
+
+       es->font = font;
+       dc = GetDC(wnd->hwndSelf);
+       if (font)
+               old_font = SelectObject(dc, font);
+       GetTextMetricsA(dc, &tm);
+       es->line_height = tm.tmHeight;
+       es->char_width = tm.tmAveCharWidth;
+       if (font)
+               SelectObject(dc, old_font);
+       ReleaseDC(wnd->hwndSelf, dc);
+       if (font && (TWEAK_WineLook > WIN31_LOOK))
+               EDIT_EM_SetMargins(wnd, es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
+                                  EC_USEFONTINFO, EC_USEFONTINFO);
+       if (es->style & ES_MULTILINE)
+               EDIT_BuildLineDefs_ML(wnd, es);
+       else {
+               RECT r;
+               GetClientRect(wnd->hwndSelf, &r);
+               EDIT_SetRectNP(wnd, es, &r);
+       }
+       if (redraw)
+               InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+       if (es->flags & EF_FOCUSED) {
+               DestroyCaret();
+               CreateCaret(wnd->hwndSelf, 0, 2, es->line_height);
+               EDIT_SetCaretPos(wnd, es, es->selection_end,
+                                es->flags & EF_AFTER_WRAP);
+               ShowCaret(wnd->hwndSelf);
+       }
+}
+
+
+/*********************************************************************
+ *
+ *     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(WND *wnd, EDITSTATE *es, LPCSTR text)
+{
+       EDIT_EM_SetSel(wnd, es, 0, -1, FALSE);
+       if (text) {
+               DPRINT( "\t'%s'\n", text);
+               EDIT_EM_ReplaceSel(wnd, es, FALSE, text);
+       } else {
+               DPRINT( "\t<NULL>\n");
+               EDIT_EM_ReplaceSel(wnd, 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(wnd, es, 0, 0, FALSE);
+       EDIT_EM_ScrollCaret(wnd, es);
+}
+
+
+/*********************************************************************
+ *
+ *     WM_SIZE
+ *
+ */
+static void EDIT_WM_Size(WND *wnd, 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(wnd, es, &rc);
+               InvalidateRect(wnd->hwndSelf, NULL, TRUE);
+       }
+}
+
+
+/*********************************************************************
+ *
+ *     WM_SYSKEYDOWN
+ *
+ */
+static LRESULT EDIT_WM_SysKeyDown(WND *wnd, EDITSTATE *es, INT key, DWORD key_data)
+{
+       if ((key == VK_BACK) && (key_data & 0x2000)) {
+               if (EDIT_EM_CanUndo(wnd, es))
+                       EDIT_EM_Undo(wnd, es);
+               return 0;
+       } else if (key == VK_UP || key == VK_DOWN)
+               if (EDIT_CheckCombo(wnd, WM_SYSKEYDOWN, key, key_data))
+                       return 0;
+       return DefWindowProcA(wnd->hwndSelf, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
+}
+
+
+/*********************************************************************
+ *
+ *     WM_TIMER
+ *
+ */
+static void EDIT_WM_Timer(WND *wnd, EDITSTATE *es, INT id, TIMERPROC timer_proc)
+{
+       if (es->region_posx < 0) {
+               EDIT_MoveBackward(wnd, es, TRUE);
+       } else if (es->region_posx > 0) {
+               EDIT_MoveForward(wnd, es, TRUE);
+       }
+/*
+ *     FIXME: gotta do some vertical scrolling here, like
+ *             EDIT_EM_LineScroll(wnd, 0, 1);
+ */
+}
+
+
+/*********************************************************************
+ *
+ *     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(WND *wnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
+{
+       INT dy = 0;
+       LRESULT ret = 0;
+
+       if (!(es->flags & EF_VSCROLL_HACK)) {
+               DPRINT( "hacked WM_VSCROLL handler invoked\n");
+               DPRINT( "      if you are _not_ running 16 bit notepad, please report\n");
+               DPRINT( "      (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(wnd, 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(wnd, EN_VSCROLL, "EN_VSCROLL");
+               break;
+       case SB_ENDSCROLL:
+               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:
+               ret = (es->line_count > 1) ? es->y_offset * 100 / (es->line_count - 1) : 0;
+               break;
+       case EM_LINESCROLL:
+               dy = pos;
+               break;
+
+       default:
+               DPRINT( "undocumented (hacked) WM_VSCROLL parameter, please report\n");
+               return 0;
+       }
+       if (dy)
+               EDIT_EM_LineScroll(wnd, es, 0, dy);
+       return ret;
+}
+
+
+/*********************************************************************
+ *
+ *     WM_VSCROLL
+ *
+ */
+static LRESULT EDIT_WM_VScroll(WND *wnd, 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(wnd, es, action, pos, scroll_bar);
+
+       dy = 0;
+       switch (action) {
+       case SB_LINEUP:
+       case SB_LINEDOWN:
+       case SB_PAGEUP:
+       case SB_PAGEDOWN:
+               EDIT_EM_Scroll(wnd, 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(wnd->hwndSelf, SB_VERT, pos, TRUE);
+                       EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
+               }
+               break;
+       case SB_ENDSCROLL:
+               break;
+
+       default:
+               DPRINT( "undocumented WM_VSCROLL action %d, please report\n",
+                       action);
+               return 0;
+       }
+       if (dy)
+               EDIT_EM_LineScroll(wnd, es, 0, dy);
+       return 0;
+}
+
+// temporary hack
+
+WINBOOL STDCALL IsClipboardFormatAvailable(
+    UINT  format 
+   )
+{
+       return FALSE;
+}
+
+WINBOOL
+STDCALL
+OpenClipboard(
+             HWND hWndNewOwner)
+{
+       return FALSE;
+}
+
+WINBOOL
+STDCALL
+CloseClipboard(
+              VOID)
+{
+       return TRUE;
+}
+
+WINBOOL
+STDCALL
+EmptyClipboard(
+              VOID)
+{
+       return TRUE;
+}
+
+HANDLE
+STDCALL
+SetClipboardData(
+                UINT uFormat,
+                HANDLE hMem)
+{
+       return NULL;
+}
+
+HANDLE
+STDCALL
+GetClipboardData(
+                UINT uFormat)
+{
+       return NULL;
+}
\ No newline at end of file
diff --git a/reactos/lib/user32/controls/icontitle.c b/reactos/lib/user32/controls/icontitle.c
new file mode 100644 (file)
index 0000000..c125ba6
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Icontitle window class.
+ *
+ * Copyright 1997 Alex Korobka
+ */
+
+#include <windows.h>
+#include <user32/widgets.h>
+#include <user32/sysmetr.h>
+#include <user32/win.h>
+#include <user32/heapdup.h>
+
+#define WM_ISACTIVEICON         0x0035
+
+static  LPCSTR emptyTitleText = "<...>";
+
+       WINBOOL bMultiLineTitle;
+       HFONT   hIconTitleFont;
+
+/***********************************************************************
+ *           ICONTITLE_Init
+ */
+WINBOOL ICONTITLE_Init(void)
+{
+    LOGFONT logFont;
+
+    SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
+    SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &bMultiLineTitle, 0 );
+    hIconTitleFont = CreateFontIndirectA( &logFont );
+    return (hIconTitleFont) ? TRUE : FALSE;
+}
+
+/***********************************************************************
+ *           ICONTITLE_Create
+ */
+HWND ICONTITLE_Create( WND* wnd )
+{
+    WND* wndPtr;
+    HWND hWnd;
+
+    if( wnd->dwStyle & WS_CHILD )
+       hWnd = CreateWindowExA( 0, ICONTITLE_CLASS_ATOM, NULL,
+                                 WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 1, 1,
+                                 wnd->parent->hwndSelf, 0, wnd->hInstance, NULL );
+    else
+       hWnd = CreateWindowExA( 0, ICONTITLE_CLASS_ATOM, NULL,
+                                 WS_CLIPSIBLINGS, 0, 0, 1, 1,
+                                 wnd->hwndSelf, 0, wnd->hInstance, NULL );
+    wndPtr = WIN_FindWndPtr( hWnd );
+    if( wndPtr )
+    {
+       wndPtr->owner = wnd;    /* MDI depends on this */
+       wndPtr->dwStyle &= ~(WS_CAPTION | WS_BORDER);
+       if( wnd->dwStyle & WS_DISABLED ) wndPtr->dwStyle |= WS_DISABLED;
+       return hWnd;
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           ICONTITLE_GetTitlePos
+ */
+WINBOOL ICONTITLE_GetTitlePos( WND* wnd, LPRECT lpRect )
+{
+    LPSTR str;
+    int length = lstrlenA( wnd->owner->text );
+
+    if( length )
+    {
+       str = HeapAlloc( GetProcessHeap(), 0, length + 1 );
+       lstrcpyA( str, wnd->owner->text );
+       while( str[length - 1] == ' ' ) /* remove trailing spaces */
+       { 
+           str[--length] = '\0';
+           if( !length )
+           {
+               HeapFree( GetProcessHeap(), 0, str );
+               break;
+           }
+       }
+    }
+    if( !length ) 
+    {
+       str = (LPSTR)emptyTitleText;
+       length = lstrlenA( str );
+    }
+
+    if( str )
+    {
+       HDC hDC = GetDC( wnd->hwndSelf );
+       if( hDC )
+       {
+           HFONT hPrevFont = SelectObject( hDC, hIconTitleFont );
+
+           SetRect( lpRect, 0, 0, sysMetrics[SM_CXICONSPACING] -
+                      SYSMETRICS_CXBORDER * 2, SYSMETRICS_CYBORDER * 2 );
+
+           DrawTextA( hDC, str, length, lpRect, DT_CALCRECT |
+                        DT_CENTER | DT_NOPREFIX | DT_WORDBREAK |
+                        (( bMultiLineTitle ) ? 0 : DT_SINGLELINE) );
+
+           SelectObject( hDC, hPrevFont );
+           ReleaseDC( wnd->hwndSelf, hDC );
+
+           lpRect->right += 4 * SYSMETRICS_CXBORDER - lpRect->left;
+           lpRect->left = wnd->owner->rectWindow.left + SYSMETRICS_CXICON / 2 -
+                                     (lpRect->right - lpRect->left) / 2;
+           lpRect->bottom -= lpRect->top;
+           lpRect->top = wnd->owner->rectWindow.top + SYSMETRICS_CYICON;
+       }
+       if( str != emptyTitleText ) HeapFree( GetProcessHeap(), 0, str );
+       return ( hDC ) ? TRUE : FALSE;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *           ICONTITLE_Paint
+ */
+WINBOOL ICONTITLE_Paint( WND* wnd, HDC hDC, WINBOOL bActive )
+{
+    HFONT hPrevFont;
+    HBRUSH hBrush = 0;
+    COLORREF textColor = 0;
+
+    if( bActive )
+    {
+       hBrush = GetSysColorBrush(COLOR_ACTIVECAPTION);
+       textColor = GetSysColor(COLOR_CAPTIONTEXT);
+    }
+    else 
+    {
+       if( wnd->dwStyle & WS_CHILD ) 
+       { 
+           hBrush = wnd->parent->class->hbrBackground;
+           if( hBrush )
+           {
+               INT level;
+               LOGBRUSH logBrush;
+               GetObjectA( hBrush, sizeof(logBrush), &logBrush );
+               level = GetRValue(logBrush.lbColor) +
+                          GetGValue(logBrush.lbColor) +
+                             GetBValue(logBrush.lbColor);
+               if( level < (0x7F * 3) )
+                   textColor = RGB( 0xFF, 0xFF, 0xFF );
+           }
+           else
+               hBrush = GetStockObject( WHITE_BRUSH );
+       }
+       else
+       {
+           hBrush = GetStockObject( BLACK_BRUSH );
+           textColor = RGB( 0xFF, 0xFF, 0xFF );    
+       }
+    }
+
+    FillWindow( wnd->parent->hwndSelf, wnd->hwndSelf, hDC, hBrush );
+
+    hPrevFont = SelectObject( hDC, hIconTitleFont );
+    if( hPrevFont )
+    {
+        RECT  rect;
+       INT     length;
+       char    buffer[80];
+
+       rect.left = rect.top = 0;
+       rect.right = wnd->rectWindow.right - wnd->rectWindow.left;
+       rect.bottom = wnd->rectWindow.bottom - wnd->rectWindow.top;
+
+       length = GetWindowTextA( wnd->owner->hwndSelf, buffer, 80 );
+        SetTextColor( hDC, textColor );
+        SetBkMode( hDC, TRANSPARENT );
+       
+       DrawTextA( hDC, buffer, length, &rect, DT_CENTER | DT_NOPREFIX |
+                    DT_WORDBREAK | ((bMultiLineTitle) ? 0 : DT_SINGLELINE) ); 
+
+       SelectObject( hDC, hPrevFont );
+    }
+    return ( hPrevFont ) ? TRUE : FALSE;
+}
+
+/***********************************************************************
+ *           IconTitleWndProc
+ */
+LRESULT WINAPI IconTitleWndProc( HWND hWnd, UINT msg,
+                                 WPARAM wParam, LPARAM lParam )
+{
+    WND *wnd = WIN_FindWndPtr( hWnd );
+
+    switch( msg )
+    {
+       case WM_NCHITTEST:
+            return HTCAPTION;
+
+       case WM_NCMOUSEMOVE:
+       case WM_NCLBUTTONDBLCLK:
+            return SendMessageA( wnd->owner->hwndSelf, msg, wParam, lParam );  
+
+       case WM_ACTIVATE:
+            if( wParam ) SetActiveWindow( wnd->owner->hwndSelf );
+            /* fall through */
+
+       case WM_CLOSE:
+            return 0;
+
+       case WM_SHOWWINDOW:
+            if( wnd && wParam )
+            {
+                RECT titleRect;
+
+                ICONTITLE_GetTitlePos( wnd, &titleRect );
+                if( wnd->owner->next != wnd )  /* keep icon title behind the owner */
+                    SetWindowPos( hWnd, wnd->owner->hwndSelf, 
+                                    titleRect.left, titleRect.top,
+                                    titleRect.right, titleRect.bottom, SWP_NOACTIVATE );
+                else
+                    SetWindowPos( hWnd, 0, titleRect.left, titleRect.top,
+                                    titleRect.right, titleRect.bottom, 
+                                    SWP_NOACTIVATE | SWP_NOZORDER );
+            }
+            return 0;
+
+       case WM_ERASEBKGND:
+            if( wnd )
+            {
+                WND* iconWnd = wnd->owner;
+
+                if( iconWnd->dwStyle & WS_CHILD )
+                    lParam = SendMessageA( iconWnd->hwndSelf, WM_ISACTIVEICON, 0, 0 );
+                else
+                    lParam = (iconWnd->hwndSelf == GetActiveWindow());
+
+                if( ICONTITLE_Paint( wnd, (HDC)wParam, (WINBOOL)lParam ) )
+                    ValidateRect( hWnd, NULL );
+                return 1;
+            }
+    }
+
+    return DefWindowProcA( hWnd, msg, wParam, lParam );
+}
+
+
diff --git a/reactos/lib/user32/controls/listbox.c b/reactos/lib/user32/controls/listbox.c
new file mode 100644 (file)
index 0000000..362132e
--- /dev/null
@@ -0,0 +1,2557 @@
+/*
+ * Listbox controls
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#include <string.h>
+#include <windows.h>
+#include <user32/win.h>
+#include <user32/combo.h>
+#include <user32/scroll.h>
+#include <user32/debug.h>
+#include <user32/nc.h>
+
+#define MAX_DOS_DRIVES 26
+
+#define MAX(x,y) x > y ? x : y 
+#define MIN(x,y) x < y ? x : y 
+#define abs(x)         ((x) < 0 ? -(x) : (x))
+
+#define WM_LBTRACKPOINT     0x0131
+#define WS_EX_DRAGDETECT       0x00000002L
+
+  /* D&D messages */
+#define WM_DROPOBJECT      0x022A
+#define WM_QUERYDROPOBJECT  0x022B
+#define WM_BEGINDRAG       0x022C
+#define WM_DRAGLOOP        0x022D
+#define WM_DRAGSELECT      0x022E
+#define WM_DRAGMOVE        0x022F
+
+
+/* Unimplemented yet:
+ * - LBS_NOSEL
+ * - LBS_USETABSTOPS
+ * - Unicode
+ * - Locale handling
+ */
+
+/* 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
+
+/* Item structure */
+typedef struct
+{
+    LPSTR     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
+{
+    HANDLE      heap;           /* Heap for this listbox */
+    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? */
+    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 SEND_NOTIFICATION(wnd,descr,code) \
+    (SendMessageA( (descr)->owner, WM_COMMAND, \
+     MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (LPARAM)(wnd)->hwndSelf ))
+
+/* 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;
+
+
+/***********************************************************************
+ *           LISTBOX_DPRINT
+ */
+void LISTBOX_DPRINT( WND *wnd )
+{
+    INT i;
+    LB_ITEMDATA *item;
+    LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
+
+    DPRINT( "Listbox:\n" );
+    DPRINT( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
+         wnd->hwndSelf, (UINT)descr, descr->heap, descr->nb_items,
+         descr->top_item );
+    for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
+    {
+        DPRINT( "%4d: %-40s %d %08lx %3d\n",
+             i, item->str, item->selected, item->data, item->height );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetCurrentPageSize
+ *
+ * Return the current page size
+ */
+static INT LISTBOX_GetCurrentPageSize( WND *wnd, 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( WND *wnd, 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( WND *wnd, LB_DESCR *descr )
+{
+    SCROLLINFO info;
+
+    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;
+        SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
+        info.nMax = 0;
+        info.fMask = SIF_RANGE;
+        SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
+    }
+    else
+    {
+        info.nMin  = 0;
+        info.nMax  = descr->nb_items - 1;
+        info.nPos  = descr->top_item;
+        info.nPage = LISTBOX_GetCurrentPageSize( wnd, descr );
+        info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+        if (descr->style & LBS_DISABLENOSCROLL)
+            info.fMask |= SIF_DISABLENOSCROLL;
+        SetScrollInfo( wnd->hwndSelf, 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;
+            SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
+        }
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetTopItem
+ *
+ * Set the top item of the listbox, scrolling up or down if necessary.
+ */
+static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index,
+                                   BOOL scroll )
+{
+    INT max = LISTBOX_GetMaxTopIndex( wnd, 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( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL, 
+                               SW_INVALIDATE | SW_ERASE );
+        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( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL,
+                                       SW_INVALIDATE | SW_ERASE );
+        else
+            scroll = FALSE;
+    }
+    if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE );
+    descr->top_item = index;
+    LISTBOX_UpdateScroll( wnd, 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( WND *wnd, LB_DESCR *descr )
+{
+    INT page_size;
+
+    if ((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( wnd->hwndSelf, NULL, TRUE );
+    LISTBOX_SetTopItem( wnd, 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( WND *wnd, LB_DESCR *descr )
+{
+    RECT rect;
+
+    GetClientRect( wnd->hwndSelf, &rect );
+    descr->width  = rect.right - rect.left;
+    descr->height = rect.bottom - rect.top;
+    if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !IS_OWNERDRAW(descr))
+    {
+        if ((descr->height > descr->item_height) &&
+            (descr->height % descr->item_height))
+        {
+            DPRINT( "[%04x]: changing height %d -> %d\n",
+                        wnd->hwndSelf, descr->height,
+                        descr->height - descr->height%descr->item_height );
+            SetWindowPos( wnd->hwndSelf, 0, 0, 0,
+                            wnd->rectWindow.right - wnd->rectWindow.left,
+                            wnd->rectWindow.bottom - wnd->rectWindow.top -
+                                (descr->height % descr->item_height),
+                            SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
+            return;
+        }
+    }
+    DPRINT( "[%04x]: new size = %d,%d\n",
+                wnd->hwndSelf, descr->width, descr->height );
+    LISTBOX_UpdatePage( wnd, descr );
+    LISTBOX_UpdateScroll( wnd, descr );
+}
+
+
+/***********************************************************************
+ *           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( WND *wnd, 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( WND *wnd, 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( WND *wnd, LB_DESCR *descr, HDC hdc,
+                               const RECT *rect, INT index, UINT action )
+{
+    LB_ITEMDATA *item = NULL;
+    if (index < descr->nb_items) item = &descr->items[index];
+
+    if (IS_OWNERDRAW(descr))
+    {
+        DRAWITEMSTRUCT dis;
+       UINT             id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
+
+        dis.CtlType      = ODT_LISTBOX;
+        dis.CtlID        = id;
+        dis.hwndItem     = wnd->hwndSelf;
+        dis.itemAction   = action;
+        dis.hDC          = hdc;
+        dis.itemID       = index;
+        dis.itemState    = 0;
+        if (item && item->selected) dis.itemState |= ODS_SELECTED;
+        if ((descr->focus_item == index) &&
+            (descr->caret_on) &&
+            (GetFocus() == wnd->hwndSelf)) dis.itemState |= ODS_FOCUS;
+        if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
+        dis.itemData     = item ? item->data : 0;
+        dis.rcItem       = *rect;
+        DPRINT( "[%04x]: drawitem %d (%s) action=%02x "
+                    "state=%02x rect=%d,%d-%d,%d\n",
+                    wnd->hwndSelf, index, item ? item->str : "", action,
+                    dis.itemState, rect->left, rect->top,
+                    rect->right, rect->bottom );
+        SendMessageA(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));
+        }
+
+        DPRINT( "[%04x]: painting %d (%s) action=%02x "
+                    "rect=%d,%d-%d,%d\n",
+                    wnd->hwndSelf, index, item ? item->str : "", action,
+                    rect->left, rect->top, rect->right, rect->bottom );
+        if (!item)
+            ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
+                           ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+        else if (!(descr->style & LBS_USETABSTOPS)) 
+           ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
+                          ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
+                          strlen(item->str), NULL );
+        else
+       {
+           /* Output empty string to paint background in the full width. */
+           ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
+                           ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+           TabbedTextOutA( hdc, rect->left + 1 , rect->top + 1,
+                             item->str, strlen(item->str), 
+                             descr->nb_tabs, descr->tabs, 0);
+       }
+        if (item && item->selected)
+        {
+            SetBkColor( hdc, oldBk );
+            SetTextColor( hdc, oldText );
+        }
+        if ((descr->focus_item == index) &&
+            (descr->caret_on) &&
+            (GetFocus() == wnd->hwndSelf)) DrawFocusRect( hdc, rect );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetRedraw
+ *
+ * Change the redraw flag.
+ */
+static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on )
+{
+    if (on)
+    {
+        if (!(descr->style & LBS_NOREDRAW)) return;
+        descr->style &= ~LBS_NOREDRAW;
+        LISTBOX_UpdateScroll( wnd, descr );
+    }
+    else descr->style |= LBS_NOREDRAW;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_RepaintItem
+ *
+ * Repaint a single item synchronously.
+ */
+static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index,
+                                 UINT action )
+{
+    HDC hdc;
+    RECT rect;
+    HFONT oldFont = 0;
+    HBRUSH hbrush, oldBrush = 0;
+
+    if (descr->style & LBS_NOREDRAW) return;
+    if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) != 1) return;
+    if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return;
+    if (descr->font) oldFont = SelectObject( hdc, descr->font );
+    hbrush = (HBRUSH)SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
+                             (WPARAM)hdc, (LPARAM)wnd->hwndSelf );
+    if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+    if (wnd->dwStyle & WS_DISABLED)
+        SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+    SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+    LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action );
+    if (oldFont) SelectObject( hdc, oldFont );
+    if (oldBrush) SelectObject( hdc, oldBrush );
+    ReleaseDC( wnd->hwndSelf, hdc );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InitStorage
+ */
+static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items,
+                                    DWORD bytes )
+{
+    LB_ITEMDATA *item;
+
+    nb_items += LB_ARRAY_GRANULARITY - 1;
+    nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
+    if (descr->items)
+        nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
+    if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
+                              nb_items * sizeof(LB_ITEMDATA) )))
+    {
+        SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
+        return LB_ERRSPACE;
+    }
+    descr->items = item;
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetTabStops
+ */
+static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count,
+                                   LPINT tabs, BOOL short_ints )
+{
+    if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
+    if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs );
+    if (!(descr->nb_tabs = count))
+    {
+        descr->tabs = NULL;
+        return TRUE;
+    }
+    /* FIXME: count = 1 */
+    if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0,
+                                            descr->nb_tabs * sizeof(INT) )))
+        return FALSE;
+    if (short_ints)
+    {
+        INT i;
+        INT * p = (INT *)tabs;
+//     dbg_decl_str(listbox, 256);
+
+        for (i = 0; i < descr->nb_tabs; i++) {
+           descr->tabs[i] = *p++<<1; /* FIXME */
+       //    if(TRACE_ON(listbox))
+        //      dsprintf(listbox, "%hd ", descr->tabs[i]);
+       }
+        DPRINT( "[%04x]: settabstops %s\n", 
+                    wnd->hwndSelf, dbg_str(listbox));
+    }
+    else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
+    /* FIXME: repaint the window? */
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetText
+ */
+static LRESULT LISTBOX_GetText( WND *wnd, LB_DESCR *descr, INT index,
+                                LPSTR buffer )
+{
+    if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+    if (HAS_STRINGS(descr))
+    {
+        if (!buffer)
+               return strlen(descr->items[index].str);
+        lstrcpyA( buffer, descr->items[index].str );
+        return strlen(buffer);
+    } else {
+       if (buffer)
+               *((LPDWORD)buffer)=*(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( WND *wnd, LB_DESCR *descr, LPCSTR 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 = lstrcmpiA( descr->items[index].str, str );
+        else
+        {
+            COMPAREITEMSTRUCT cis;
+           UINT                id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
+
+            cis.CtlType    = ODT_LISTBOX;
+            cis.CtlID      = id;
+            cis.hwndItem   = wnd->hwndSelf;
+            cis.itemID1    = index;
+            cis.itemData1  = descr->items[index].data;
+            cis.itemID2    = -1;
+            cis.itemData2  = (DWORD)str;
+            //cis.dwLocaleId = descr->locale;
+            res = SendMessageA( 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( WND *wnd, LB_DESCR *descr, LPCSTR str )
+{
+    INT min, max, res = -1;
+
+    if (!HAS_STRINGS(descr))
+        return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
+    min = 0;
+    max = descr->nb_items;
+    while (min != max)
+    {
+        INT index = (min + max) / 2;
+        const char *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 = lstrcmpiA( str, p );
+            }
+        }
+        else  /* filename */
+        {
+            if (*str == '[') res = 1;
+            else res = lstrcmpiA( 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( WND *wnd, LB_DESCR *descr, INT start,
+                                 LPCSTR 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) return LB_ERR;
+        if (exact)
+        {
+            for (i = start + 1; i < descr->nb_items; i++, item++)
+                if (!lstrcmpiA( str, item->str )) return i;
+            for (i = 0, item = descr->items; i <= start; i++, item++)
+                if (!lstrcmpiA( str, item->str )) return i;
+        }
+        else
+        {
+ /* Special case for drives and directories: ignore prefix */
+#define CHECK_DRIVE(item) \
+    if ((item)->str[0] == '[') \
+    { \
+        if (!lstrcmpiA( str, (item)->str+1 )) return i; \
+        if (((item)->str[1] == '-') && !lstrcmpiA(str,(item)->str+2)) \
+        return i; \
+    }
+
+            INT len = lstrlenA(str);
+            for (i = start + 1; i < descr->nb_items; i++, item++)
+            {
+               if (!lstrcmpiA( str, item->str )) return i;
+               CHECK_DRIVE(item);
+            }
+            for (i = 0, item = descr->items; i <= start; i++, item++)
+            {
+               if (!lstrcmpiA( str, item->str )) 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( wnd, 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( WND *wnd, 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_GetSelItems
+ */
+static LRESULT LISTBOX_GetSelItems( WND *wnd, 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( WND *wnd, LB_DESCR *descr, HDC hdc )
+{
+    INT i, col_pos = descr->page_size - 1;
+    RECT rect;
+    HFONT oldFont = 0;
+    HBRUSH hbrush, oldBrush = 0;
+
+    SetRect( &rect, 0, 0, descr->width, descr->height );
+    if (descr->style & LBS_NOREDRAW) return 0;
+    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 = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
+                             (WPARAM)hdc, (LPARAM)wnd->hwndSelf );
+    if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+    if (wnd->dwStyle & WS_DISABLED)
+        SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+
+    if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
+        (GetFocus() == wnd->hwndSelf))
+    {
+        /* Special case for empty listbox: paint focus rect */
+        rect.bottom = rect.top + descr->item_height;
+        LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
+                           ODA_FOCUS );
+        rect.top = rect.bottom;
+    }
+
+    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;
+
+        LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE );
+        rect.top = rect.bottom;
+
+        if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
+        {
+            if (!IS_OWNERDRAW(descr))
+            {
+                /* Clear the bottom of the column */
+                SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
+                if (rect.top < descr->height)
+                {
+                    rect.bottom = descr->height;
+                    ExtTextOutA( 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;
+        }
+    }
+
+    if (!IS_OWNERDRAW(descr))
+    {
+        /* Clear the remainder of the client area */
+        SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
+        if (rect.top < descr->height)
+        {
+            rect.bottom = descr->height;
+            ExtTextOutA( 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;
+            ExtTextOutA( 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( WND *wnd, LB_DESCR *descr, INT index )
+{
+    RECT rect;
+
+    if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) == 1)
+    {
+        rect.bottom = descr->height;
+        InvalidateRect( wnd->hwndSelf, &rect, TRUE );
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            /* Repaint the other columns */
+            rect.left  = rect.right;
+            rect.right = descr->width;
+            rect.top   = 0;
+            InvalidateRect( wnd->hwndSelf, &rect, TRUE );
+        }
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_GetItemHeight
+ */
+static LRESULT LISTBOX_GetItemHeight( WND *wnd, 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( WND *wnd, LB_DESCR *descr, INT index,
+                                      UINT height )
+{
+    if (!height) height = 1;
+
+    if (descr->style & LBS_OWNERDRAWVARIABLE)
+    {
+        if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+        DPRINT( "[%04x]: item %d height = %d\n",
+                    wnd->hwndSelf, index, height );
+        descr->items[index].height = height;
+        LISTBOX_UpdateScroll( wnd, descr );
+        LISTBOX_InvalidateItems( wnd, descr, index );
+    }
+    else if (height != descr->item_height)
+    {
+        DPRINT( "[%04x]: new height = %d\n",
+                    wnd->hwndSelf, height );
+        descr->item_height = height;
+        LISTBOX_UpdatePage( wnd, descr );
+        LISTBOX_UpdateScroll( wnd, descr );
+        InvalidateRect( wnd->hwndSelf, 0, TRUE );
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetHorizontalPos
+ */
+static void LISTBOX_SetHorizontalPos( WND *wnd, 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;
+    DPRINT( "[%04x]: new horz pos = %d\n",
+                wnd->hwndSelf, pos );
+    descr->horz_pos = pos;
+    LISTBOX_UpdateScroll( wnd, descr );
+    if (abs(diff) < descr->width)
+        ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
+                       SW_INVALIDATE | SW_ERASE );
+    else
+        InvalidateRect( wnd->hwndSelf, NULL, TRUE );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetHorizontalExtent
+ */
+static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
+                                            UINT 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;
+    DPRINT( "[%04x]: new horz extent = %d\n",
+                wnd->hwndSelf, extent );
+    descr->horz_extent = extent;
+    if (descr->horz_pos > extent - descr->width)
+        LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
+    else
+        LISTBOX_UpdateScroll( wnd, descr );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetColumnWidth
+ */
+static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, UINT width)
+{
+    width += 2;  /* For left and right margin */
+    if (width == descr->column_width) return LB_OKAY;
+    DPRINT( "[%04x]: new column width = %d\n",
+                wnd->hwndSelf, width );
+    descr->column_width = width;
+    LISTBOX_UpdatePage( wnd, descr );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetFont
+ *
+ * Returns the item height.
+ */
+static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
+{
+    HDC hdc;
+    HFONT oldFont = 0;
+    TEXTMETRIC tm;
+
+    descr->font = font;
+
+    if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
+    {
+        DPRINT("unable to get DC.\n" );
+        return 16;
+    }
+    if (font) oldFont = SelectObject( hdc, font );
+    GetTextMetricsA( hdc, &tm );
+    if (oldFont) SelectObject( hdc, oldFont );
+    ReleaseDC( wnd->hwndSelf, hdc );
+    if (!IS_OWNERDRAW(descr))
+        LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
+    return tm.tmHeight ;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_MakeItemVisible
+ *
+ * Make sure that a given item is partially or fully visible.
+ */
+static void LISTBOX_MakeItemVisible( WND *wnd, 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( wnd, descr, top, TRUE );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SelectItemRange
+ *
+ * Select a range of items. Should only be used on a MULTIPLESEL listbox.
+ */
+static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
+                                        INT last, BOOL on )
+{
+    INT i;
+
+    /* A few sanity checks */
+
+    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( wnd, descr, i, ODA_SELECT );
+        }
+    }
+    else  /* Turn selection off */
+    {
+        for (i = first; i <= last; i++)
+        {
+            if (!descr->items[i].selected) continue;
+            descr->items[i].selected = FALSE;
+            LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
+        }
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetCaretIndex
+ *
+ * NOTES
+ *   index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
+ *
+ */
+static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
+                                      BOOL fully_visible )
+{
+    INT oldfocus = descr->focus_item;          
+
+    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 && (GetFocus() == wnd->hwndSelf))
+        LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
+
+    LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
+    if (descr->caret_on && (GetFocus() == wnd->hwndSelf))
+        LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
+
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetSelection
+ */
+static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
+                                     BOOL on, BOOL send_notify )
+{
+    if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
+    if (descr->style & LBS_MULTIPLESEL)
+    {
+        if (index == -1)  /* Select all items */
+            return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
+        else  /* Only one item */
+            return LISTBOX_SelectItemRange( wnd, 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( wnd, descr, oldsel, ODA_SELECT);
+        if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
+        if (send_notify) SEND_NOTIFICATION( wnd, 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( WND *wnd, LB_DESCR *descr, INT index,
+                               BOOL fully_visible )
+{
+    LISTBOX_SetCaretIndex( wnd, descr, index, fully_visible );
+    if (descr->style & LBS_EXTENDEDSEL)
+    {
+        if (descr->anchor_item != -1)
+        {
+            INT first = MIN( descr->focus_item, descr->anchor_item );
+            INT last  = MAX( descr->focus_item, descr->anchor_item );
+            if (first > 0)
+                LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
+            LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
+            LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
+        }
+    }
+    else if (!(descr->style & LBS_MULTIPLESEL) && (descr->selected_item != -1))
+    {
+        /* Set selection to new caret item */
+        LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
+    }
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InsertItem
+ */
+static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
+                                   LPSTR str, DWORD data )
+{
+    LB_ITEMDATA *item;
+    INT max_items;
+
+    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( descr->heap, 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( descr->heap, 0, descr->items,
+                                  max_items * sizeof(LB_ITEMDATA) )))
+        {
+            SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
+            return LB_ERRSPACE;
+        }
+        descr->items = item;
+    }
+
+    /* Insert the item structure */
+
+    item = &descr->items[index];
+    if (index < descr->nb_items)
+        MoveMemory( 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 = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
+
+        mis.CtlType    = ODT_LISTBOX;
+        mis.CtlID      = id;
+        mis.itemID     = index;
+        mis.itemData   = descr->items[index].data;
+        mis.itemHeight = descr->item_height;
+        SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+        item->height = mis.itemHeight ? mis.itemHeight : 1;
+        DPRINT( "[%04x]: measure item %d (%s) = %d\n",
+                    wnd->hwndSelf, index, str ? str : "", item->height );
+    }
+
+    /* Repaint the items */
+
+    LISTBOX_UpdateScroll( wnd, descr );
+    LISTBOX_InvalidateItems( wnd, descr, index );
+
+    /* Move selection and focused item */
+
+    if (index <= descr->selected_item) descr->selected_item++;
+    if (index <= descr->focus_item)
+    {
+        descr->focus_item++;
+        LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE );
+    }
+
+    /* If listbox was empty, set focus to the first item */
+
+    if (descr->nb_items == 1) LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_InsertString
+ */
+static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
+                                     LPCSTR str )
+{
+    LPSTR new_str = NULL;
+    DWORD data = 0;
+    LRESULT ret;
+
+    if (HAS_STRINGS(descr))
+    {
+        if (!(new_str = HEAP_strdupA( descr->heap, 0, str )))
+        {
+            SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
+            return LB_ERRSPACE;
+        }
+    }
+    else data = (DWORD)str;
+
+    if (index == -1) index = descr->nb_items;
+    if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
+    {
+        if (new_str) HeapFree( descr->heap, 0, new_str );
+        return ret;
+    }
+
+    DPRINT( "[%04x]: added item %d '%s'\n",
+                wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" );
+    return index;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_DeleteItem
+ *
+ * Delete the content of an item. 'index' must be a valid index.
+ */
+static void LISTBOX_DeleteItem( WND *wnd, 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 = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
+
+        dis.CtlType  = ODT_LISTBOX;
+        dis.CtlID    = id;
+        dis.itemID   = index;
+        dis.hwndItem = wnd->hwndSelf;
+        dis.itemData = descr->items[index].data;
+        SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
+    }
+    if (HAS_STRINGS(descr) && descr->items[index].str)
+        HeapFree( descr->heap, 0, descr->items[index].str );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_RemoveItem
+ *
+ * Remove an item from the listbox and delete its content.
+ */
+static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
+{
+    LB_ITEMDATA *item;
+    INT max_items;
+
+    if (index == -1) index = descr->nb_items - 1;
+    else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+    LISTBOX_DeleteItem( wnd, descr, index );
+
+    /* Remove the item */
+
+    item = &descr->items[index];
+    if (index < descr->nb_items-1)
+        MoveMemory( 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( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA);
+    if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
+    {
+        max_items -= LB_ARRAY_GRANULARITY;
+        item = HeapReAlloc( descr->heap, 0, descr->items,
+                            max_items * sizeof(LB_ITEMDATA) );
+        if (item) descr->items = item;
+    }
+
+    /* Repaint the items */
+
+    LISTBOX_UpdateScroll( wnd, descr );
+    LISTBOX_InvalidateItems( wnd, descr, index );
+
+    /* Move selection and focused item */
+
+    if (index <= descr->selected_item) descr->selected_item--;
+    if (index <= descr->focus_item)
+    {
+        descr->focus_item--;
+        LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE );
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_ResetContent
+ */
+static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
+{
+    INT i;
+
+    for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
+    if (descr->items) HeapFree( descr->heap, 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_UpdateScroll( wnd, descr );
+    InvalidateRect( wnd->hwndSelf, NULL, TRUE );
+}
+
+
+/***********************************************************************
+ *           LISTBOX_SetCount
+ */
+static LRESULT LISTBOX_SetCount( WND *wnd, 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( wnd, descr, -1, 0 )) < 0)
+                return ret;
+    }
+    else if (count < descr->nb_items)
+    {
+        while (count < descr->nb_items)
+            if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
+                return ret;
+    }
+    return LB_OKAY;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Directory
+ */
+static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
+                                  LPCSTR filespec, BOOL long_names )
+{
+    HANDLE handle;
+    LRESULT ret = LB_OKAY;
+    WIN32_FIND_DATA entry;
+    int pos;
+
+    if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE)
+    {
+        if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
+    }
+    else
+    {
+        do
+        {
+            char buffer[270];
+            if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+            {
+                if (!(attrib & DDL_DIRECTORY) ||
+                    !strcmp( entry.cAlternateFileName, "." )) continue;
+                if (long_names) sprintf( buffer, "[%s]", entry.cFileName );
+                else sprintf( buffer, "[%s]", entry.cAlternateFileName );
+            }
+            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) strcpy( buffer, entry.cFileName );
+                else strcpy( buffer, entry.cAlternateFileName );
+            }
+            if (!long_names) CharLowerA( buffer );
+            pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
+            if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
+                break;
+        } while (FindNextFileA( handle, &entry ));
+        FindClose( handle );
+    }
+
+    if ((ret >= 0) && (attrib & DDL_DRIVES))
+    {
+        char buffer[] = "[-a-]";
+        int drive;
+        for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++)
+        {
+            //if (!DRIVE_IsValid(drive)) continue;
+            if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
+                break;
+        }
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleVScroll
+ */
+static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr,
+                                      WPARAM wParam, LPARAM lParam )
+{
+    SCROLLINFO info;
+
+    if (descr->style & LBS_MULTICOLUMN) return 0;
+    switch(LOWORD(wParam))
+    {
+    case SB_LINEUP:
+        LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
+        break;
+    case SB_LINEDOWN:
+        LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
+        break;
+    case SB_PAGEUP:
+        LISTBOX_SetTopItem( wnd, descr, descr->top_item -
+                            LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
+        break;
+    case SB_PAGEDOWN:
+        LISTBOX_SetTopItem( wnd, descr, descr->top_item +
+                            LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
+        break;
+    case SB_THUMBPOSITION:
+        LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
+        break;
+    case SB_THUMBTRACK:
+        info.cbSize = sizeof(info);
+        info.fMask = SIF_TRACKPOS;
+        GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
+        LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
+        break;
+    case SB_TOP:
+        LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
+        break;
+    case SB_BOTTOM:
+        LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
+        break;
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleHScroll
+ */
+static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr,
+                                      WPARAM wParam, LPARAM lParam )
+{
+    SCROLLINFO info;
+    INT page;
+
+    if (descr->style & LBS_MULTICOLUMN)
+    {
+        switch(LOWORD(wParam))
+        {
+        case SB_LINELEFT:
+            LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
+                                TRUE );
+            break;
+        case SB_LINERIGHT:
+            LISTBOX_SetTopItem( wnd, 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( wnd, 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( wnd, descr,
+                             descr->top_item + page * descr->page_size, TRUE );
+            break;
+        case SB_THUMBPOSITION:
+            LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
+                                TRUE );
+            break;
+        case SB_THUMBTRACK:
+            info.cbSize = sizeof(info);
+            info.fMask  = SIF_TRACKPOS;
+            GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
+            LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
+                                TRUE );
+            break;
+        case SB_LEFT:
+            LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
+            break;
+        case SB_RIGHT:
+            LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
+            break;
+        }
+    }
+    else if (descr->horz_extent)
+    {
+        switch(LOWORD(wParam))
+        {
+        case SB_LINELEFT:
+            LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
+            break;
+        case SB_LINERIGHT:
+            LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
+            break;
+        case SB_PAGELEFT:
+            LISTBOX_SetHorizontalPos( wnd, descr,
+                                      descr->horz_pos - descr->width );
+            break;
+        case SB_PAGERIGHT:
+            LISTBOX_SetHorizontalPos( wnd, descr,
+                                      descr->horz_pos + descr->width );
+            break;
+        case SB_THUMBPOSITION:
+            LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
+            break;
+        case SB_THUMBTRACK:
+            info.cbSize = sizeof(info);
+            info.fMask = SIF_TRACKPOS;
+            GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
+            LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
+            break;
+        case SB_LEFT:
+            LISTBOX_SetHorizontalPos( wnd, descr, 0 );
+            break;
+        case SB_RIGHT:
+            LISTBOX_SetHorizontalPos( wnd, descr,
+                                      descr->horz_extent - descr->width );
+            break;
+        }
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleLButtonDown
+ */
+static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
+                                          WPARAM wParam, INT x, INT y )
+{
+    INT index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
+    DPRINT( "[%04x]: lbuttondown %d,%d item %d\n",
+                wnd->hwndSelf, x, y, index );
+    if (!descr->caret_on && (GetFocus() == wnd->hwndSelf)) return 0;
+    if (index != -1)
+    {
+        if (descr->style & LBS_EXTENDEDSEL)
+        {
+            if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
+            if (wParam & MK_CONTROL)
+            {
+                LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
+                LISTBOX_SetSelection( wnd, descr, index,
+                                      !descr->items[index].selected, FALSE );
+            }
+            else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
+        }
+        else
+        {
+            LISTBOX_MoveCaret( wnd, descr, index, FALSE );
+            LISTBOX_SetSelection( wnd, descr, index,
+                                  (!(descr->style & LBS_MULTIPLESEL) || 
+                                   !descr->items[index].selected), FALSE );
+        }
+    }
+
+    if( !descr->lphc ) SetFocus( wnd->hwndSelf );
+    else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
+                                             : descr->lphc->self->hwndSelf ) ;
+
+    SetCapture( wnd->hwndSelf );
+    if (index != -1 && !descr->lphc)
+    {
+        if (descr->style & LBS_NOTIFY )
+            SendMessageA( descr->owner, WM_LBTRACKPOINT, index,
+                            MAKELPARAM( x, y ) );
+        if (wnd->dwExStyle & WS_EX_DRAGDETECT)
+        {
+            POINT pt = { x, y };
+     //       if (DragDetect( wnd->hwndSelf, pt ))
+                SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 );
+        }
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleLButtonUp
+ */
+static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
+{
+    if (LISTBOX_Timer != LB_TIMER_NONE)
+        KillTimer( wnd->hwndSelf, LB_TIMER_ID );
+    LISTBOX_Timer = LB_TIMER_NONE;
+    if (GetCapture() == wnd->hwndSelf)
+    {
+        ReleaseCapture();
+        if (descr->style & LBS_NOTIFY)
+            SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleTimer
+ *
+ * Handle scrolling upon a timer event.
+ * Return TRUE if scrolling should continue.
+ */
+static LRESULT LISTBOX_HandleTimer( WND *wnd, 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( wnd, 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( wnd, descr, index, FALSE );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleSystemTimer
+ *
+ * WM_SYSTIMER handler.
+ */
+static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
+{
+    if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
+    {
+        KillTimer( wnd->hwndSelf, LB_TIMER_ID );
+        LISTBOX_Timer = LB_TIMER_NONE;
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleMouseMove
+ *
+ * WM_MOUSEMOVE handler.
+ */
+static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
+                                     INT x, INT y )
+{
+    INT index;
+    TIMER_DIRECTION dir;
+
+    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 dir = LB_TIMER_NONE;  /* inside */
+    }
+    else
+    {
+        if (y < 0) dir = LB_TIMER_UP;  /* above */
+        else if (y >= descr->height) dir = LB_TIMER_DOWN;  /* below */
+        else dir = LB_TIMER_NONE;  /* inside */
+    }
+
+    index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
+    if (index == -1) index = descr->focus_item;
+    if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
+
+    /* Start/stop the system timer */
+
+    if (dir != LB_TIMER_NONE)
+        SetTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
+    else if (LISTBOX_Timer != LB_TIMER_NONE)
+        KillTimer( wnd->hwndSelf, LB_TIMER_ID );
+    LISTBOX_Timer = dir;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleKeyDown
+ */
+static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
+{
+    INT caret = -1;
+    if (descr->style & LBS_WANTKEYBOARDINPUT)
+    {
+        caret = SendMessageA( descr->owner, WM_VKEYTOITEM,
+                                MAKEWPARAM(LOWORD(wParam), descr->focus_item),
+                                wnd->hwndSelf );
+        if (caret == -2) return 0;
+    }
+    if (caret == -1) switch(wParam)
+    {
+    case VK_LEFT:
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            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)
+        {
+            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(wnd,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(wnd,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( wnd, descr, descr->focus_item,
+                                  !descr->items[descr->focus_item].selected,
+                                  (descr->style & LBS_NOTIFY) != 0 );
+        }
+        else if (descr->selected_item == -1)
+        {
+            LISTBOX_SetSelection( wnd, descr, descr->focus_item, TRUE,
+                                  (descr->style & LBS_NOTIFY) != 0 );
+        }
+        break;
+    }
+    if (caret >= 0)
+    {
+        if ((descr->style & LBS_EXTENDEDSEL) &&
+            !(GetKeyState( VK_SHIFT ) & 0x8000))
+            descr->anchor_item = caret;
+        LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
+        if (descr->style & LBS_NOTIFY)
+        {
+           if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE )
+            {
+               /* make sure that combo parent doesn't hide us */
+               descr->lphc->wState |= CBF_NOROLLUP;
+           }
+            SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
+        }
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_HandleChar
+ */
+static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr,
+                                   WPARAM wParam )
+{
+    INT caret = -1;
+    char str[2] = { wParam & 0xff, '\0' };
+
+    if (descr->style & LBS_WANTKEYBOARDINPUT)
+    {
+        caret = SendMessageA( descr->owner, WM_CHARTOITEM,
+                                MAKEWPARAM(LOWORD(wParam), descr->focus_item),
+                                wnd->hwndSelf );
+        if (caret == -2) return 0;
+    }
+    if (caret == -1)
+        caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
+    if (caret != -1)
+    {
+        LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
+        if (descr->style & LBS_NOTIFY)
+            SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Create
+ */
+static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
+{
+    LB_DESCR *descr;
+    MEASUREITEMSTRUCT mis;
+    RECT rect;
+
+    if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
+        return FALSE;
+    if (!(descr->heap = HeapCreate( 0, 0x10000, 0 )))
+    {
+        HeapFree( GetProcessHeap(), 0, descr );
+        return FALSE;
+    }
+    GetClientRect( wnd->hwndSelf, &rect );
+    descr->owner         = GetParent( wnd->hwndSelf );
+    descr->style         = wnd->dwStyle;
+    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   = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
+    descr->horz_pos      = 0;
+    descr->nb_tabs       = 0;
+    descr->tabs          = NULL;
+    descr->caret_on      = TRUE;
+    descr->font          = 0;
+    descr->locale        = 0;  /* FIXME */
+    descr->lphc                 = lphc;
+
+    if( lphc )
+    {
+       DPRINT("[%04x]: resetting owner %04x -> %04x\n",
+                    wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
+       descr->owner = lphc->self->hwndSelf;
+    }
+
+    *(LB_DESCR **)wnd->wExtra = 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( wnd, 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->RectButton.bottom - lphc->RectButton.top - 6;
+       }
+       else
+       {
+           UINT        id = (descr->lphc ) ? ID_CB_LISTBOX : wnd->wIDmenu;
+
+            mis.CtlType    = ODT_LISTBOX;
+            mis.CtlID      = id;
+            mis.itemID     = -1;
+            mis.itemWidth  =  0;
+            mis.itemData   =  0;
+            mis.itemHeight = descr->item_height;
+            SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+            descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
+       }
+    }
+
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           LISTBOX_Destroy
+ */
+static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
+{
+    LISTBOX_ResetContent( wnd, descr );
+    HeapDestroy( descr->heap );
+    HeapFree( GetProcessHeap(), 0, descr );
+    wnd->wExtra[0] = 0;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           ListBoxWndProc
+ */
+LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg,
+                               WPARAM wParam, LPARAM lParam )
+{
+    LRESULT ret;
+    LB_DESCR *descr;
+    WND *wnd = WIN_FindWndPtr( hwnd );
+
+    if (!wnd) return 0;
+    if (!(descr = *(LB_DESCR **)wnd->wExtra))
+    {
+        if (msg == WM_CREATE)
+        {
+            if (!LISTBOX_Create( wnd, NULL )) return -1;
+            DPRINT( "creating wnd=%04x descr=%p\n",
+                        hwnd, *(LB_DESCR **)wnd->wExtra );
+            return 0;
+        }
+        /* Ignore all other messages before we get a WM_CREATE */
+        return DefWindowProcA( hwnd, msg, wParam, lParam );
+    }
+
+    DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n",
+                wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
+    switch(msg)
+    {
+    case LB_RESETCONTENT:
+        LISTBOX_ResetContent( wnd, descr );
+        return 0;
+
+    case LB_ADDSTRING:
+        wParam = LISTBOX_FindStringPos( wnd, descr, (LPCSTR)lParam, FALSE );
+        return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
+
+    case LB_INSERTSTRING:
+        return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
+
+    case LB_ADDFILE:
+        wParam = LISTBOX_FindFileStrPos( wnd, descr, (LPCSTR)lParam );
+        return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
+
+    case LB_DELETESTRING:
+        return LISTBOX_RemoveItem( wnd, descr, wParam );
+
+    case LB_GETITEMDATA:
+        if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        return descr->items[wParam].data;
+
+    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_GETCOUNT:
+        return descr->nb_items;
+
+    case LB_GETTEXT:
+        return LISTBOX_GetText( wnd, descr, wParam, (LPSTR)lParam );
+
+    case LB_GETTEXTLEN:
+        if (wParam >= descr->nb_items) return LB_ERR;
+        return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str)
+                                   : sizeof(DWORD));
+
+   
+    case LB_GETCURSEL:
+        return descr->selected_item;
+
+
+    case LB_GETTOPINDEX:
+        return descr->top_item;
+
+    case LB_GETITEMHEIGHT:
+        return LISTBOX_GetItemHeight( wnd, descr, wParam );
+
+
+    case LB_SETITEMHEIGHT:
+        return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
+
+    case LB_ITEMFROMPOINT:
+        {
+            POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+            RECT rect = { 0, 0, descr->width, descr->height };
+            return MAKELONG( LISTBOX_GetItemFromPoint(wnd, descr, pt.x, pt.y),
+                             PtInRect( &rect, pt ) );
+        }
+
+
+    case LB_SETCARETINDEX:
+        return LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam );
+
+
+    case LB_GETCARETINDEX:
+        return descr->focus_item;
+
+    case LB_SETTOPINDEX:
+        return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
+
+
+    case LB_SETCOLUMNWIDTH:
+        return LISTBOX_SetColumnWidth( wnd, descr, wParam );
+
+
+    case LB_GETITEMRECT:
+        return LISTBOX_GetItemRect( wnd, descr, wParam, (RECT *)lParam );
+
+
+    case LB_FINDSTRING:
+        return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, FALSE );
+
+  
+    case LB_FINDSTRINGEXACT:
+        return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
+
+    case LB_SELECTSTRING:
+        {
+            INT index = LISTBOX_FindString( wnd, descr, wParam,
+                                              (LPCSTR)lParam, FALSE );
+            if (index == LB_ERR) return LB_ERR;
+            LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
+            return index;
+        }
+
+  
+    case LB_GETSEL:
+        if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+            return LB_ERR;
+        return descr->items[wParam].selected;
+
+    case LB_SETSEL:
+        return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
+
+   
+    case LB_SETCURSEL:
+        LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );  
+        return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
+
+    case LB_GETSELCOUNT:
+        return LISTBOX_GetSelCount( wnd, descr );
+
+    
+    case LB_GETSELITEMS:
+        return LISTBOX_GetSelItems( wnd, descr, wParam, (LPINT)lParam );
+
+    case LB_SELITEMRANGE:
+        if (LOWORD(lParam) <= HIWORD(lParam))
+            return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
+                                            HIWORD(lParam), wParam );
+        else
+            return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
+                                            LOWORD(lParam), wParam );
+
+
+    case LB_SELITEMRANGEEX:
+        if ((INT)lParam >= (INT)wParam)
+            return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
+        else
+            return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
+
+    case LB_GETHORIZONTALEXTENT:
+        return descr->horz_extent;
+
+
+    case LB_SETHORIZONTALEXTENT:
+        return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
+
+     case LB_GETANCHORINDEX:
+        return descr->anchor_item;
+
+
+    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_DIR:
+        return LISTBOX_Directory( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
+
+    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( wnd, descr, wParam, (DWORD)lParam );
+
+    case LB_SETCOUNT:
+        return LISTBOX_SetCount( wnd, descr, (INT)wParam );
+
+  
+
+    case LB_SETTABSTOPS:
+        return LISTBOX_SetTabStops( wnd, descr, wParam,
+                                    (LPINT)lParam, FALSE );
+
+   
+    case LB_CARETON:
+        if (descr->caret_on) return LB_OKAY;
+        descr->caret_on = TRUE;
+        if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
+            LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
+        return LB_OKAY;
+
+  
+    case LB_CARETOFF:
+        if (!descr->caret_on) return LB_OKAY;
+        descr->caret_on = FALSE;
+        if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
+            LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
+        return LB_OKAY;
+
+    case WM_DESTROY:
+        return LISTBOX_Destroy( wnd, descr );
+
+    case WM_ENABLE:
+        InvalidateRect( hwnd, NULL, TRUE );
+        return 0;
+
+    case WM_SETREDRAW:
+        LISTBOX_SetRedraw( wnd, 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( wnd, descr, hdc );
+            if( !wParam ) EndPaint( hwnd, &ps );
+        }
+        return ret;
+
+    case WM_SIZE:
+        LISTBOX_UpdateSize( wnd, descr );
+        return 0;
+
+    case WM_GETFONT:
+        return descr->font;
+
+    case WM_SETFONT:
+        LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
+        if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
+        return 0;
+
+    case WM_SETFOCUS:
+        descr->caret_on = TRUE;
+        if (descr->focus_item != -1)
+            LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
+        SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
+        return 0;
+
+    case WM_KILLFOCUS:
+        if ((descr->focus_item != -1) && descr->caret_on)
+            LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
+        SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
+        return 0;
+
+    case WM_HSCROLL:
+        return LISTBOX_HandleHScroll( wnd, descr, wParam, lParam );
+
+    case WM_VSCROLL:
+        return LISTBOX_HandleVScroll( wnd, descr, wParam, lParam );
+
+    case WM_LBUTTONDOWN:
+        return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
+                                          (INT)LOWORD(lParam),
+                                          (INT)HIWORD(lParam) );
+
+    case WM_LBUTTONDBLCLK:
+        if (descr->style & LBS_NOTIFY)
+            SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
+        return 0;
+
+    case WM_MOUSEMOVE:
+        if (GetCapture() == hwnd)
+            LISTBOX_HandleMouseMove( wnd, descr, (INT)LOWORD(lParam),
+                                     (INT)HIWORD(lParam) );
+        return 0;
+
+    case WM_LBUTTONUP:
+        return LISTBOX_HandleLButtonUp( wnd, descr );
+
+    case WM_KEYDOWN:
+        return LISTBOX_HandleKeyDown( wnd, descr, wParam );
+
+    case WM_CHAR:
+        return LISTBOX_HandleChar( wnd, descr, wParam );
+
+    case WM_SYSTIMER:
+        return LISTBOX_HandleSystemTimer( wnd, descr );
+
+    case WM_ERASEBKGND:
+        if (IS_OWNERDRAW(descr))
+        {
+            RECT rect = { 0, 0, descr->width, descr->height };
+            HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
+                                              wParam, (LPARAM)wnd->hwndSelf );
+            if (hbrush) FillRect( (HDC)wParam, &rect, hbrush );
+        }
+        return 1;
+
+    case WM_DROPFILES:
+        if( !descr->lphc ) 
+           return SendMessageA( descr->owner, msg, wParam, lParam );
+       break;
+
+    case WM_DROPOBJECT:
+    case WM_QUERYDROPOBJECT:
+    case WM_DRAGSELECT:
+    case WM_DRAGMOVE:
+       if( !descr->lphc )
+        {
+          //  LPDRAGINFO dragInfo = (LPDRAGINFO)lParam;
+          //  dragInfo->l = LISTBOX_GetItemFromPoint( wnd, descr, dragInfo->pt.x,
+            //                                    dragInfo->pt.y );
+            return SendMessageA( descr->owner, msg, wParam, lParam );
+        }
+       break;
+
+    case WM_NCCREATE:
+       if (TWEAK_WineLook > WIN31_LOOK)
+           wnd->dwExStyle |= WS_EX_CLIENTEDGE;
+        return DefWindowProcA( hwnd, msg, wParam, lParam );
+
+    default:
+        if ((msg >= WM_USER) && (msg < 0xc000))
+            DPRINT( "[%04x]: unknown msg %04x wp %08x lp %08lx\n",
+                        hwnd, msg, wParam, lParam );
+        return DefWindowProcA( hwnd, msg, wParam, lParam );
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           COMBO_Directory
+ */
+LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong)
+{
+    WND *wnd = WIN_FindWndPtr( lphc->hWndLBox );
+
+    if( wnd )
+    {
+        LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
+       if( descr )
+       {
+           LRESULT     lRet = LISTBOX_Directory( wnd, descr, attrib, dir, bLong );
+
+           RedrawWindow( lphc->self->hwndSelf, NULL, 0, 
+                           RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
+           return lRet;
+       }
+    }
+    return CB_ERR;
+}
+
+/***********************************************************************
+ *           ComboLBWndProc
+ *
+ *  NOTE: in Windows, winproc address of the ComboLBox is the same 
+ *       as that of the Listbox.
+ */
+LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg,
+                               WPARAM wParam, LPARAM lParam )
+{
+    LRESULT lRet = 0;
+    WND *wnd = WIN_FindWndPtr( hwnd );
+
+    if (wnd)
+    {
+       LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
+
+        DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n",
+                    wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
+
+       if( descr || msg == WM_CREATE )
+        {
+           LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
+
+           switch( msg )
+           {
+               case WM_CREATE:
+#define lpcs   ((LPCREATESTRUCTA)lParam)
+                    DPRINT( "\tpassed parent handle = 0x%08x\n", 
+                                 (UINT)lpcs->lpCreateParams);
+
+                    lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
+#undef  lpcs
+                    return LISTBOX_Create( wnd, lphc );
+
+               case WM_LBUTTONDOWN:
+                    return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
+                             (INT)LOWORD(lParam), (INT)HIWORD(lParam));
+
+               /* avoid activation at all costs */
+
+               case WM_MOUSEACTIVATE:
+                    return MA_NOACTIVATE;
+
+                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 );
+                            return 0;
+                        }
+                    }
+                    return LISTBOX_HandleKeyDown( wnd, descr, wParam );
+
+               case LB_SETCURSEL:
+                    lRet = ListBoxWndProc( hwnd, msg, wParam, lParam );
+                    return (lRet == LB_ERR) ? lRet : descr->selected_item; 
+
+               case WM_NCDESTROY:
+                    if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+                        lphc->hWndLBox = 0;
+                    /* fall through */
+
+               default:
+                    return ListBoxWndProc( hwnd, msg, wParam, lParam );
+           }
+        }
+        lRet = DefWindowProcA( hwnd, msg, wParam, lParam );
+
+        DPRINT("\t default on msg [%04x]\n", (UINT)msg );
+    }
+
+    return lRet;
+}
+
similarity index 94%
rename from reactos/lib/user32/windows/menu.c
rename to reactos/lib/user32/controls/menu.c
index c25327b..322925d 100644 (file)
 
 
 
-#include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
-#undef WIN32_LEAN_AND_MEAN
+
+
 #include <windows.h>
 #include <user32/win.h>
-//#include <user32/debug.h>
+#include <user32/debug.h>
 #include <user32/resource.h>
 #include <user32/sysmetr.h>
 #include <user32/menu.h>
+#include <user32/syscolor.h>
+
 
-#include<stdio.h>
-#define DPRINT printf
 
 
 /**********************************************************************
@@ -49,7 +49,7 @@ HMENU STDCALL CreateMenu(void)
     menu->hWnd   = 0;
     menu->items  = NULL;
     menu->FocusedItem = NO_SELECTED_ITEM;
-    //TRACE(menu, "return %04x\n", hMenu );
+    DPRINT( "return %04x\n", hMenu );
     return hMenu;
 }
 
@@ -254,10 +254,10 @@ WINBOOL STDCALL DrawMenuBar( HWND hWnd )
  */
 HMENU STDCALL LoadMenuA( HINSTANCE instance, LPCSTR name )
 {
-// instance should be a module handle GetModuleHandle(NULL)
-    HRSRC hrsrc = FindResourceA( instance, name, (LPCSTR)RT_MENU );
+
+    HRSRC hrsrc = FindResourceA(  GetModuleHandle(NULL), name, (LPCSTR)RT_MENU );
     if (!hrsrc) return 0;
-    return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
+    return LoadMenuIndirectA( (LPCVOID)LoadResource( GetModuleHandle(NULL), hrsrc ));
 }
 
 
@@ -267,19 +267,61 @@ HMENU STDCALL LoadMenuA( HINSTANCE instance, LPCSTR name )
 HMENU STDCALL LoadMenuW( HINSTANCE hInstance, LPCWSTR name )
 {
 
-    HRSRC hrsrc = FindResourceW( hInstance, name, (LPCWSTR)RT_MENU );
-    if (!hrsrc) 
-       return 0;
-    return LoadMenuIndirectW( (LPCVOID)LoadResource( hInstance, hrsrc ));
+    HRSRC hrsrc = FindResourceW(  GetModuleHandle(NULL), name, (LPCSTR)RT_MENU );
+    if (!hrsrc) return 0;
+    return LoadMenuIndirectW( (LPCVOID)LoadResource( GetModuleHandle(NULL), hrsrc ));
 }
 /*
 
-
-typedef struct {  
-    WORD mtOption;       
-    WORD mtID;         
-    WCHAR mtString[1];   
+A menu template consists of a MENUITEMTEMPLATEHEADER structure 
+followed by one or more contiguous MENUITEMTEMPLATE structures. 
+In Windows 95, an extended menu template consists of a 
+MENUEX_TEMPLATE_HEADER structure followed by one or more 
+contiguous MENUEX_TEMPLATE_ITEM structures.  
+
+
+typedef struct {
+  WORD  wVersion; 
+  WORD  wOffset; 
+  DWORD dwHelpId; 
+} MENUEX_TEMPLATE_HEADER;
+
+typedef struct { 
+  DWORD  dwType; 
+  DWORD  dwState; 
+  UINT   uId; 
+  BYTE   bResInfo; 
+  WCHAR  szText[1]; 
+  DWORD dwHelpId; 
+} MENUEX_TEMPLATE_ITEM; 
+
+typedef struct tagMENUITEMINFO {
+  UINT    cbSize; 
+  UINT    fMask; 
+  UINT    fType; 
+  UINT    fState; 
+  UINT    wID; 
+  HMENU   hSubMenu; 
+  HBITMAP hbmpChecked; 
+  HBITMAP hbmpUnchecked; 
+  DWORD   dwItemData; 
+  LPTSTR  dwTypeData; 
+  UINT    cch; 
+} MENUITEMINFO, *LPMENUITEMINFO; 
+typedef MENUITEMINFO CONST *LPCMENUITEMINFO;
+typedef struct {   
+  WORD mtOption;      
+  WORD mtID;          
+  WCHAR mtString[1];  
 } MENUITEMTEMPLATE; 
+typedef struct {      
+  WORD versionNumber; 
+  WORD offset;        
+} MENUITEMTEMPLATEHEADER; 
+typedef VOID MENUTEMPLATE, *LPMENUTEMPLATE;
+
 */
 
 /**********************************************************************
@@ -986,8 +1028,7 @@ INT STDCALL GetMenuStringA( HMENU hMenu, UINT wItemID,
     MENUITEM *item;
     int i;
     int len;
-    //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
-    //             hMenu, wItemID, str, nMaxSiz, wFlags );
+    DPRINT( "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",  hMenu, wItemID, str, nMaxSiz, wFlags );
     if (!str || !nMaxSiz)
         return 0;
     str[0] = '\0';
@@ -1012,8 +1053,7 @@ INT STDCALL GetMenuStringW( HMENU hMenu, UINT wItemID,
 {
     MENUITEM *item;
 
-    //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
-    //             hMenu, wItemID, str, nMaxSiz, wFlags );
+    DPRINT( "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",   hMenu, wItemID, str, nMaxSiz, wFlags );
     if (!str || !nMaxSiz) 
        return 0;
     str[0] = '\0';
@@ -1030,8 +1070,8 @@ WINBOOL STDCALL HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
                                 UINT wHilite )
 {
     LPPOPUPMENU menu;
-//    DPRINT("menu (%04x, %04x, %04x, %04x);\n", 
-//                 hWnd, hMenu, wItemID, wHilite);
+    DPRINT("menu (%04x, %04x, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
+
     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
     if (!(menu = (LPPOPUPMENU) (hMenu))) return FALSE;
     if (menu->FocusedItem == wItemID) return TRUE;
@@ -1269,7 +1309,6 @@ STDCALL
 GetMenuCheckMarkDimensions(VOID)
 {
 
-
     return MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
 }
 
diff --git a/reactos/lib/user32/controls/scroll.c b/reactos/lib/user32/controls/scroll.c
new file mode 100644 (file)
index 0000000..f0960d2
--- /dev/null
@@ -0,0 +1,1445 @@
+/*             
+ * Scrollbar control
+ *
+ * Copyright 1993 Martin Ayotte
+ * Copyright 1994, 1996 Alexandre Julliard
+ */
+
+#include <windows.h>
+#include <user32/sysmetr.h>
+#include <user32/scroll.h>
+#include <user32/heapdup.h>
+#include <user32/win.h>
+#include <user32/syscolor.h>
+#include <user32/debug.h>
+
+#define MAX(x,y) x > y ? x : y 
+#define MIN(x,y) x < y ? x : y 
+
+static HBITMAP hUpArrow = 0;
+static HBITMAP hDnArrow = 0;
+static HBITMAP hLfArrow = 0;
+static HBITMAP hRgArrow = 0;
+static HBITMAP hUpArrowD = 0;
+static HBITMAP hDnArrowD = 0;
+static HBITMAP hLfArrowD = 0;
+static HBITMAP hRgArrowD = 0;
+static HBITMAP hUpArrowI = 0;
+static HBITMAP hDnArrowI = 0;
+static HBITMAP hLfArrowI = 0;
+static HBITMAP hRgArrowI = 0;
+
+#define TOP_ARROW(flags,pressed) \
+   (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
+#define BOTTOM_ARROW(flags,pressed) \
+   (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
+#define LEFT_ARROW(flags,pressed) \
+   (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
+#define RIGHT_ARROW(flags,pressed) \
+   (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
+
+
+  /* Minimum size of the rectangle between the arrows */
+#define SCROLL_MIN_RECT  4  
+
+  /* Minimum size of the thumb in pixels */
+#define SCROLL_MIN_THUMB 6
+
+  /* Overlap between arrows and thumb */
+#define SCROLL_ARROW_THUMB_OVERLAP 1
+
+  /* Delay (in ms) before first repetition when holding the button down */
+#define SCROLL_FIRST_DELAY   200
+
+  /* Delay (in ms) between scroll repetitions */
+#define SCROLL_REPEAT_DELAY  50
+
+  /* Scroll timer id */
+#define SCROLL_TIMER   0
+
+  /* Scroll-bar hit testing */
+enum SCROLL_HITTEST
+{
+    SCROLL_NOWHERE,      /* Outside the scroll bar */
+    SCROLL_TOP_ARROW,    /* Top or left arrow */
+    SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
+    SCROLL_THUMB,        /* Thumb rectangle */
+    SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
+    SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
+};
+
+ /* What to do after SCROLL_SetScrollInfo() */
+#define SA_SSI_HIDE            0x0001
+#define SA_SSI_SHOW            0x0002
+#define SA_SSI_REFRESH         0x0004
+#define SA_SSI_REPAINT_ARROWS  0x0008
+
+ /* Thumb-tracking info */
+static HWND SCROLL_TrackingWin = 0;
+static INT  SCROLL_TrackingBar = 0;
+static INT  SCROLL_TrackingPos = 0;
+static INT  SCROLL_TrackingVal = 0;
+ /* Hit test code of the last button-down event */
+static enum SCROLL_HITTEST SCROLL_trackHitTest;
+static BOOL SCROLL_trackVertical;
+
+ /* Is the moving thumb being displayed? */
+static BOOL SCROLL_MovingThumb = FALSE;
+
+ /* Local functions */
+static BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, 
+                                   BOOL fShowH, BOOL fShowV );
+static INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, 
+                                  const SCROLLINFO *info, INT *action );
+
+/***********************************************************************
+ *           SCROLL_LoadBitmaps
+ */
+static void SCROLL_LoadBitmaps(void)
+{
+    hUpArrow  = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROW) );
+    hDnArrow  = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROW) );
+    hLfArrow  = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROW) );
+    hRgArrow  = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROW) );
+    hUpArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROWD) );
+    hDnArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROWD) );
+    hLfArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROWD) );
+    hRgArrowD = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROWD) );
+    hUpArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_UPARROWI) );
+    hDnArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_DNARROWI) );
+    hLfArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_LFARROWI) );
+    hRgArrowI = LoadBitmapA( 0, MAKEINTRESOURCE(OBM_RGARROWI) );
+}
+
+
+/***********************************************************************
+ *           SCROLL_GetPtrScrollInfo
+ */
+static SCROLLBAR_INFO *SCROLL_GetPtrScrollInfo( WND* wndPtr, INT nBar )
+{
+    SCROLLBAR_INFO *infoPtr;
+
+    if (!wndPtr) return NULL;
+    switch(nBar)
+    {
+        case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break;
+        case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break;
+        case SB_CTL:  infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break;
+        default:      return NULL;
+    }
+
+    if (!infoPtr)  /* Create the info structure if needed */
+    {
+        if ((infoPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(SCROLLBAR_INFO) )))
+        {
+            infoPtr->MinVal = infoPtr->CurVal = infoPtr->Page = 0;
+            infoPtr->MaxVal = 100;
+            infoPtr->flags  = ESB_ENABLE_BOTH;
+            if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr;
+            else wndPtr->pVScroll = infoPtr;
+        }
+        if (!hUpArrow) SCROLL_LoadBitmaps();
+    }
+    return infoPtr;
+}
+
+
+/***********************************************************************
+ *           SCROLL_GetScrollInfo
+ */
+static SCROLLBAR_INFO *SCROLL_GetScrollInfo( HWND hwnd, INT nBar )
+{
+   WND *wndPtr = WIN_FindWndPtr( hwnd );
+   return SCROLL_GetPtrScrollInfo( wndPtr, nBar );
+}
+
+
+/***********************************************************************
+ *           SCROLL_GetScrollBarRect
+ *
+ * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
+ * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
+ * 'arrowSize' returns the width or height of an arrow (depending on
+ * the orientation of the scrollbar), 'thumbSize' returns the size of
+ * the thumb, and 'thumbPos' returns the position of the thumb
+ * relative to the left or to the top.
+ * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
+ */
+static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect,
+                                       INT *arrowSize, INT *thumbSize,
+                                       INT *thumbPos )
+{
+    INT pixels;
+    BOOL vertical;
+    WND *wndPtr = WIN_FindWndPtr( hwnd );
+
+    switch(nBar)
+    {
+      case SB_HORZ:
+        lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
+        lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
+        lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
+        lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL;
+       if(wndPtr->dwStyle & WS_BORDER) {
+         lprect->left--;
+         lprect->right++;
+       } else if(wndPtr->dwStyle & WS_VSCROLL)
+         lprect->right++;
+        vertical = FALSE;
+       break;
+
+      case SB_VERT:
+        lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
+        lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
+        lprect->right  = lprect->left + SYSMETRICS_CXVSCROLL;
+        lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
+       if(wndPtr->dwStyle & WS_BORDER) {
+         lprect->top--;
+         lprect->bottom++;
+       } else if(wndPtr->dwStyle & WS_HSCROLL)
+         lprect->bottom++;
+        vertical = TRUE;
+       break;
+
+      case SB_CTL:
+       GetClientRect( hwnd, lprect );
+        vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
+       break;
+
+    default:
+        return FALSE;
+    }
+
+    if (vertical) pixels = lprect->bottom - lprect->top;
+    else pixels = lprect->right - lprect->left;
+
+    if (pixels <= 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT)
+    {
+        if (pixels > SCROLL_MIN_RECT)
+            *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
+        else
+            *arrowSize = 0;
+        *thumbPos = *thumbSize = 0;
+    }
+    else
+    {
+        SCROLLBAR_INFO *info = SCROLL_GetPtrScrollInfo( wndPtr, nBar );
+
+        *arrowSize = SYSMETRICS_CXVSCROLL;
+        pixels -= (2 * (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP));
+
+        if (info->Page)
+        {
+            *thumbSize = pixels * info->Page / (info->MaxVal-info->MinVal+1);
+            if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
+        }
+        else *thumbSize = SYSMETRICS_CXVSCROLL;
+
+        if (((pixels -= *thumbSize ) < 0) ||
+            ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
+        {
+            /* Rectangle too small or scrollbar disabled -> no thumb */
+            *thumbPos = *thumbSize = 0;
+        }
+        else
+        {
+            INT max = info->MaxVal - MAX( info->Page-1, 0 );
+            if (info->MinVal >= max)
+                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+            else
+                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
+                + pixels * (info->CurVal-info->MinVal) / (max - info->MinVal);
+        }
+    }
+    return vertical;
+}
+
+
+/***********************************************************************
+ *           SCROLL_GetThumbVal
+ *
+ * Compute the current scroll position based on the thumb position in pixels
+ * from the top of the scroll-bar.
+ */
+static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect,
+                                  BOOL vertical, INT pos )
+{
+    INT thumbSize;
+    INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
+
+    if ((pixels -= 2*(SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
+        return infoPtr->MinVal;
+
+    if (infoPtr->Page)
+    {
+        thumbSize = pixels * infoPtr->Page/(infoPtr->MaxVal-infoPtr->MinVal+1);
+        if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
+    }
+    else thumbSize = SYSMETRICS_CXVSCROLL;
+
+    if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal;
+
+    pos = MAX( 0, pos - (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP) );
+    if (pos > pixels) pos = pixels;
+
+    if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal;
+    else pos *= infoPtr->MaxVal - infoPtr->MinVal - infoPtr->Page + 1;
+    return infoPtr->MinVal + ((pos + pixels / 2) / pixels);
+}
+
+/***********************************************************************
+ *           SCROLL_PtInRectEx
+ */
+static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
+{
+    RECT rect = *lpRect;
+
+    if (vertical)
+    {
+       rect.left -= lpRect->right - lpRect->left;
+       rect.right += lpRect->right - lpRect->left;
+    }
+    else
+    {
+       rect.top -= lpRect->bottom - lpRect->top;
+       rect.bottom += lpRect->bottom - lpRect->top;
+    }
+    return PtInRect( &rect, pt );
+}
+
+/***********************************************************************
+ *           SCROLL_ClipPos
+ */
+static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
+{
+    if( pt.x < lpRect->left )
+       pt.x = lpRect->left;
+    else
+    if( pt.x > lpRect->right )
+       pt.x = lpRect->right;
+
+    if( pt.y < lpRect->top )
+       pt.y = lpRect->top;
+    else
+    if( pt.y > lpRect->bottom )
+       pt.y = lpRect->bottom;
+
+    return pt;
+}
+
+
+/***********************************************************************
+ *           SCROLL_HitTest
+ *
+ * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
+ */
+static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar,
+                                           POINT pt, BOOL bDragging )
+{
+    INT arrowSize, thumbSize, thumbPos;
+    RECT rect;
+
+    BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
+                                           &arrowSize, &thumbSize, &thumbPos );
+
+    if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
+        (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE;
+
+    if (vertical)
+    {
+        if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
+        if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
+        if (!thumbPos) return SCROLL_TOP_RECT;
+        pt.y -= rect.top;
+        if (pt.y < thumbPos) return SCROLL_TOP_RECT;
+        if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+    }
+    else  /* horizontal */
+    {
+        if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
+        if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
+        if (!thumbPos) return SCROLL_TOP_RECT;
+        pt.x -= rect.left;
+        if (pt.x < thumbPos) return SCROLL_TOP_RECT;
+        if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+    }
+    return SCROLL_THUMB;
+}
+
+
+/***********************************************************************
+ *           SCROLL_DrawArrows
+ *
+ * Draw the scroll bar arrows.
+ */
+static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr,
+                               RECT *rect, INT arrowSize, BOOL vertical,
+                               BOOL top_pressed, BOOL bottom_pressed )
+{
+    HDC hdcMem = CreateCompatibleDC( hdc );
+    HBITMAP hbmpPrev = SelectObject( hdcMem, vertical ?
+                                    TOP_ARROW(infoPtr->flags, top_pressed)
+                                    : LEFT_ARROW(infoPtr->flags, top_pressed));
+
+    SetStretchBltMode( hdc, STRETCH_DELETESCANS );
+    StretchBlt( hdc, rect->left, rect->top,
+                  vertical ? rect->right-rect->left : arrowSize,
+                  vertical ? arrowSize : rect->bottom-rect->top,
+                  hdcMem, 0, 0,
+                  SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
+                  SRCCOPY );
+
+    SelectObject( hdcMem, vertical ?
+                    BOTTOM_ARROW( infoPtr->flags, bottom_pressed )
+                    : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) );
+    if (vertical)
+        StretchBlt( hdc, rect->left, rect->bottom - arrowSize,
+                      rect->right - rect->left, arrowSize,
+                      hdcMem, 0, 0,
+                      SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
+                      SRCCOPY );
+    else
+        StretchBlt( hdc, rect->right - arrowSize, rect->top,
+                      arrowSize, rect->bottom - rect->top,
+                      hdcMem, 0, 0,
+                      SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
+                      SRCCOPY );
+    SelectObject( hdcMem, hbmpPrev );
+    DeleteDC( hdcMem );
+}
+
+
+/***********************************************************************
+ *           SCROLL_DrawMovingThumb
+ *
+ * Draw the moving thumb rectangle.
+ */
+static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
+                                    INT arrowSize, INT thumbSize )
+{
+    RECT r = *rect;
+    if (vertical)
+    {
+        r.top += SCROLL_TrackingPos;
+        if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+           r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        if (r.top + thumbSize >
+                      rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
+            r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+                                                                 - thumbSize;
+        r.bottom = r.top + thumbSize;
+    }
+    else
+    {
+        r.left += SCROLL_TrackingPos;
+        if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+           r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        if (r.left + thumbSize >
+                      rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
+            r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) 
+                                                                 - thumbSize;
+        r.right = r.left + thumbSize;
+    }
+    DrawFocusRect( hdc, &r );
+    SCROLL_MovingThumb = !SCROLL_MovingThumb;
+}
+
+
+/***********************************************************************
+ *           SCROLL_DrawInterior
+ *
+ * Draw the scroll bar interior (everything except the arrows).
+ */
+static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar, 
+                                 RECT *rect, INT arrowSize,
+                                 INT thumbSize, INT thumbPos,
+                                 UINT flags, BOOL vertical,
+                                 BOOL top_selected, BOOL bottom_selected )
+{
+    RECT r;
+
+      /* Select the correct brush and pen */
+
+    SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
+    if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
+    {
+          /* This ought to be the color of the parent window */
+        SelectObject( hdc, GetSysColorBrush(COLOR_WINDOW) );
+    }
+    else
+    {
+        if (nBar == SB_CTL)  /* Only scrollbar controls send WM_CTLCOLOR */
+        {
+            HBRUSH hbrush = SendMessageA(GetParent(hwnd),
+                                             WM_CTLCOLORSCROLLBAR, hdc, hwnd );
+            SelectObject( hdc, hbrush );
+        }
+        else SelectObject( hdc, GetSysColorBrush(COLOR_SCROLLBAR) );
+    }
+
+      /* Calculate the scroll rectangle */
+
+    r = *rect;
+    if (vertical)
+    {
+        r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    }
+    else
+    {
+        r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    }
+
+      /* Draw the scroll bar frame */
+
+    Rectangle( hdc, r.left, r.top, r.right, r.bottom );
+
+      /* Draw the scroll rectangles and thumb */
+
+    if (!thumbPos)  /* No thumb to draw */
+    {
+        PatBlt( hdc, r.left+1, r.top+1, r.right - r.left - 2,
+                  r.bottom - r.top - 2, PATCOPY );
+        return;
+    }
+
+    if (vertical)
+    {
+        PatBlt( hdc, r.left + 1, r.top + 1,
+                  r.right - r.left - 2,
+                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
+                  top_selected ? 0x0f0000 : PATCOPY );
+        r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+        PatBlt( hdc, r.left + 1, r.top + thumbSize,
+                  r.right - r.left - 2,
+                  r.bottom - r.top - thumbSize - 1,
+                  bottom_selected ? 0x0f0000 : PATCOPY );
+        r.bottom = r.top + thumbSize;
+    }
+    else  /* horizontal */
+    {
+        PatBlt( hdc, r.left + 1, r.top + 1,
+                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
+                  r.bottom - r.top - 2,
+                  top_selected ? 0x0f0000 : PATCOPY );
+        r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+        PatBlt( hdc, r.left + thumbSize, r.top + 1,
+                  r.right - r.left - thumbSize - 1,
+                  r.bottom - r.top - 2,
+                  bottom_selected ? 0x0f0000 : PATCOPY );
+        r.right = r.left + thumbSize;
+    }
+
+      /* Draw the thumb */
+
+    SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
+    Rectangle( hdc, r.left, r.top, r.right, r.bottom );
+    r.top++, r.left++;
+    DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
+    if (SCROLL_MovingThumb &&
+        (SCROLL_TrackingWin == hwnd) &&
+        (SCROLL_TrackingBar == nBar))
+    {
+        SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
+        SCROLL_MovingThumb = TRUE;
+    }
+}
+
+
+/***********************************************************************
+ *           SCROLL_DrawScrollBar
+ *
+ * Redraw the whole scrollbar.
+ */
+void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, 
+                          BOOL arrows, BOOL interior )
+{
+    INT arrowSize, thumbSize, thumbPos;
+    RECT rect;
+    BOOL vertical;
+    WND *wndPtr = WIN_FindWndPtr( hwnd );
+    SCROLLBAR_INFO *infoPtr = SCROLL_GetPtrScrollInfo( wndPtr, nBar );
+
+    if (!wndPtr || !infoPtr ||
+        ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
+        ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return;
+    if (!WIN_IsWindowDrawable( wndPtr, FALSE )) return;
+
+    vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
+                                        &arrowSize, &thumbSize, &thumbPos );
+
+      /* Draw the arrows */
+
+    if (arrows && arrowSize)
+    {
+       if( vertical == SCROLL_trackVertical && GetCapture() == hwnd )
+           SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
+                              (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
+                              (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
+       else
+           SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, 
+                                                              FALSE, FALSE );
+    }
+    if( interior )
+       SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
+                         thumbPos, infoPtr->flags, vertical, FALSE, FALSE );
+}
+
+
+/***********************************************************************
+ *           SCROLL_RefreshScrollBar
+ *
+ * Repaint the scroll bar interior after a SetScrollRange() or
+ * SetScrollPos() call.
+ */
+static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar, 
+                                    BOOL arrows, BOOL interior )
+{
+    HDC hdc = GetDCEx( hwnd, 0,
+                           DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
+    if (!hdc) return;
+
+    SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
+    ReleaseDC( hwnd, hdc );
+}
+
+
+/***********************************************************************
+ *           SCROLL_HandleKbdEvent
+ *
+ * Handle a keyboard event (only for SB_CTL scrollbars).
+ */
+static void SCROLL_HandleKbdEvent( HWND hwnd, WPARAM wParam )
+{
+    WND *wndPtr = WIN_FindWndPtr( hwnd );
+    WPARAM msg;
+    
+    switch(wParam)
+    {
+    case VK_PRIOR: msg = SB_PAGEUP; break;
+    case VK_NEXT:  msg = SB_PAGEDOWN; break;
+    case VK_HOME:  msg = SB_TOP; break;
+    case VK_END:   msg = SB_BOTTOM; break;
+    case VK_UP:    msg = SB_LINEUP; break;
+    case VK_DOWN:  msg = SB_LINEDOWN; break;
+    default:
+        return;
+    }
+    SendMessageA( GetParent(hwnd),
+                    (wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
+                    msg, hwnd );
+}
+
+
+/***********************************************************************
+ *           SCROLL_HandleScrollEvent
+ *
+ * Handle a mouse or timer event for the scrollbar.
+ * 'pt' is the location of the mouse event in client (for SB_CTL) or
+ * windows coordinates.
+ */
+void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
+{
+      /* Previous mouse position for timer events */
+    static POINT prevPt;
+      /* Thumb position when tracking started. */
+    static UINT trackThumbPos;
+      /* Position in the scroll-bar of the last button-down event. */
+    static INT lastClickPos;
+      /* Position in the scroll-bar of the last mouse event. */
+    static INT lastMousePos;
+
+    enum SCROLL_HITTEST hittest;
+    HWND hwndOwner, hwndCtl;
+    BOOL vertical;
+    INT arrowSize, thumbSize, thumbPos;
+    RECT rect;
+    HDC hdc;
+
+    SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
+    if (!infoPtr) return;
+    if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) 
+                 return;
+
+    hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
+    vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
+                                        &arrowSize, &thumbSize, &thumbPos );
+    hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
+    hwndCtl   = (nBar == SB_CTL) ? hwnd : 0;
+
+    switch(msg)
+    {
+      case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
+         SCROLL_trackVertical = vertical;
+          SCROLL_trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
+          lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
+          lastMousePos  = lastClickPos;
+          trackThumbPos = thumbPos;
+          prevPt = pt;
+          SetCapture( hwnd );
+          if (nBar == SB_CTL) SetFocus( hwnd );
+          break;
+
+      case WM_MOUSEMOVE:
+          hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
+          prevPt = pt;
+          break;
+
+      case WM_LBUTTONUP:
+          hittest = SCROLL_NOWHERE;
+          ReleaseCapture();
+          break;
+
+      case WM_TIMER:
+          pt = prevPt;
+          hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
+          break;
+
+      default:
+          return;  /* Should never happen */
+    }
+
+    DPRINT( "Event: hwnd=%04x bar=%d msg=%x pt=%d,%d hit=%d\n",
+                hwnd, nBar, msg, pt.x, pt.y, hittest );
+
+    switch(SCROLL_trackHitTest)
+    {
+    case SCROLL_NOWHERE:  /* No tracking in progress */
+        break;
+
+    case SCROLL_TOP_ARROW:
+        SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
+                           (hittest == SCROLL_trackHitTest), FALSE );
+        if (hittest == SCROLL_trackHitTest)
+        {
+            if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER))
+            {
+                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                                SB_LINEUP, hwndCtl );
+                SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                  SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                  (TIMERPROC)0 );
+            }
+        }
+        else KillTimer( hwnd, SCROLL_TIMER );
+        break;
+
+    case SCROLL_TOP_RECT:
+        SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
+                             thumbPos, infoPtr->flags, vertical,
+                             (hittest == SCROLL_trackHitTest), FALSE );
+        if (hittest == SCROLL_trackHitTest)
+        {
+            if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER))
+            {
+                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                                SB_PAGEUP, hwndCtl );
+                SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                  SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                  (TIMERPROC)0 );
+            }
+        }
+        else KillTimer( hwnd, SCROLL_TIMER );
+        break;
+
+    case SCROLL_THUMB:
+        if (msg == WM_LBUTTONDOWN)
+        {
+            SCROLL_TrackingWin = hwnd;
+            SCROLL_TrackingBar = nBar;
+            SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
+            SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
+        }
+        else if (msg == WM_LBUTTONUP)
+        {
+            SCROLL_TrackingWin = 0;
+            SCROLL_MovingThumb = FALSE;
+            SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
+                                 thumbPos, infoPtr->flags, vertical,
+                                 FALSE, FALSE );
+        }
+        else  /* WM_MOUSEMOVE */
+        {
+            UINT pos;
+
+            if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos;
+            else
+           {
+               pt = SCROLL_ClipPos( &rect, pt );
+               pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
+           }
+            if (pos != lastMousePos)
+            {
+                SCROLL_DrawMovingThumb( hdc, &rect, vertical,
+                                        arrowSize, thumbSize );
+                lastMousePos = pos;
+                SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
+                SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
+                                                         vertical,
+                                                         SCROLL_TrackingPos );
+                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                                MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
+                                hwndCtl );
+                SCROLL_DrawMovingThumb( hdc, &rect, vertical,
+                                        arrowSize, thumbSize );
+            }
+        }
+        break;
+        
+    case SCROLL_BOTTOM_RECT:
+        SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
+                             thumbPos, infoPtr->flags, vertical,
+                             FALSE, (hittest == SCROLL_trackHitTest) );
+        if (hittest == SCROLL_trackHitTest)
+        {
+            if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER))
+            {
+                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                                SB_PAGEDOWN, hwndCtl );
+                SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                  SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                  (TIMERPROC)0 );
+            }
+        }
+        else KillTimer( hwnd, SCROLL_TIMER );
+        break;
+        
+    case SCROLL_BOTTOM_ARROW:
+        SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
+                           FALSE, (hittest == SCROLL_trackHitTest) );
+        if (hittest == SCROLL_trackHitTest)
+        {
+            if ((msg == WM_LBUTTONDOWN) || (msg == WM_TIMER))
+            {
+                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                                SB_LINEDOWN, (LPARAM)hwndCtl );
+                SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+                                  SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
+                                  (TIMERPROC)0 );
+            }
+        }
+        else KillTimer( hwnd, SCROLL_TIMER );
+        break;
+    }
+
+    if (msg == WM_LBUTTONUP)
+    {
+       hittest = SCROLL_trackHitTest;
+       SCROLL_trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
+
+        if (hittest == SCROLL_THUMB)
+        {
+            UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
+                                 trackThumbPos + lastMousePos - lastClickPos );
+            SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                            MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
+        }
+        else
+            SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+                            SB_ENDSCROLL, (LPARAM)hwndCtl );
+    }
+
+    ReleaseDC( hwnd, hdc );
+}
+
+
+/***********************************************************************
+ *           ScrollBarWndProc
+ */
+LRESULT STDCALL ScrollBarWndProc( HWND hwnd, UINT message, WPARAM wParam,
+                                 LPARAM lParam )
+{
+    POINT *pt;
+    switch(message)
+    {
+    case WM_CREATE:
+        {
+           CREATESTRUCTA *lpCreat = (CREATESTRUCTA *)lParam;
+            if (lpCreat->style & SBS_SIZEBOX)
+            {
+                DPRINT( "FIXME Unimplemented style SBS_SIZEBOX.\n" );
+                return 0;
+            }
+            
+           if (lpCreat->style & SBS_VERT)
+            {
+                if (lpCreat->style & SBS_LEFTALIGN)
+                    MoveWindow( hwnd, lpCreat->x, lpCreat->y,
+                                  SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
+                else if (lpCreat->style & SBS_RIGHTALIGN)
+                    MoveWindow( hwnd, 
+                                  lpCreat->x+lpCreat->cx-SYSMETRICS_CXVSCROLL-1,
+                                  lpCreat->y,
+                                  SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
+            }
+            else  /* SBS_HORZ */
+            {
+                if (lpCreat->style & SBS_TOPALIGN)
+                    MoveWindow( hwnd, lpCreat->x, lpCreat->y,
+                                  lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
+                else if (lpCreat->style & SBS_BOTTOMALIGN)
+                    MoveWindow( hwnd, 
+                                  lpCreat->x,
+                                  lpCreat->y+lpCreat->cy-SYSMETRICS_CYHSCROLL-1,
+                                  lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
+            }
+        }
+        if (!hUpArrow) SCROLL_LoadBitmaps();
+        DPRINT( "ScrollBar creation, hwnd=%04x\n", hwnd );
+        return 0;
+       
+    case WM_LBUTTONDOWN:
+    case WM_LBUTTONUP:
+    case WM_MOUSEMOVE:
+    case WM_TIMER:
+       pt = (POINT *)&lParam;
+        SCROLL_HandleScrollEvent( hwnd, SB_CTL, message,*pt );
+        break;
+
+    case WM_KEYDOWN:
+        SCROLL_HandleKbdEvent( hwnd, wParam );
+        break;
+
+    case WM_ERASEBKGND:
+         return 1;
+
+    case WM_GETDLGCODE:
+         return DLGC_WANTARROWS; /* Windows returns this value */
+
+    case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            HDC hdc = BeginPaint( hwnd, &ps );
+            SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE, TRUE );
+            EndPaint( hwnd, &ps );
+        }
+        break;
+
+  
+    case SBM_SETPOS:
+        return SetScrollPos( hwnd, SB_CTL, wParam, (BOOL)lParam );
+
+
+    case SBM_GETPOS:
+        return GetScrollPos( hwnd, SB_CTL );
+
+    
+    case SBM_SETRANGE:
+        SetScrollRange( hwnd, SB_CTL, wParam, lParam, FALSE );
+        return 0;  /* FIXME: return previous position */
+
+   
+
+    case SBM_GETRANGE:
+        GetScrollRange( hwnd, SB_CTL, (LPINT)wParam, (LPINT)lParam );
+        return 0;
+
+   
+    case SBM_ENABLE_ARROWS:
+        return EnableScrollBar( hwnd, SB_CTL, wParam );
+
+    case SBM_SETRANGEREDRAW:
+        SetScrollRange( hwnd, SB_CTL, wParam, lParam, TRUE );
+        return 0;  /* FIXME: return previous position */
+        
+    case SBM_SETSCROLLINFO:
+        return SetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam, wParam );
+
+    case SBM_GETSCROLLINFO:
+        return GetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam );
+
+    case 0x00e5:
+    case 0x00e7:
+    case 0x00e8:
+    case 0x00eb:
+    case 0x00ec:
+    case 0x00ed:
+    case 0x00ee:
+    case 0x00ef:
+        DPRINT( "unknown Win msg %04x wp=%08x lp=%08lx\n",
+                   message, wParam, lParam );
+        break;
+
+    default:
+        if (message >= WM_USER)
+            DPRINT( "unknown msg %04x wp=%04x lp=%08lx\n",
+                        message, wParam, lParam );
+        return DefWindowProcA( hwnd, message, wParam, lParam );
+    }
+    return 0;
+}
+
+
+
+
+
+/*************************************************************************
+ *           SetScrollInfo   (USER.501)
+ * SetScrollInfo can be used to set the position, upper bound, 
+ * lower bound, and page size of a scrollbar control.
+ *
+ * RETURNS
+ *    Scrollbar position
+ *
+ * NOTE
+ *    For 100 lines of text to be displayed in a window of 25 lines,
+ *  one would for instance use info->nMin=0, info->nMax=75
+ *  (corresponding to the 76 different positions of the window on
+ *  the text), and info->nPage=25.
+ */
+INT STDCALL SetScrollInfo( HWND hwnd, INT nBar , 
+const SCROLLINFO *info , BOOL bRedraw )
+{
+    INT action;
+    INT retVal = SCROLL_SetScrollInfo( hwnd, nBar, info, &action );
+
+    if( action & SA_SSI_HIDE )
+       SCROLL_ShowScrollBar( hwnd, nBar, FALSE, FALSE );
+    else
+    {
+       if( action & SA_SSI_SHOW )
+           if( SCROLL_ShowScrollBar( hwnd, nBar, TRUE, TRUE ) )
+               return retVal; /* SetWindowPos() already did the painting */
+
+       if( bRedraw && (action & SA_SSI_REFRESH))
+           SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
+       else if( action & SA_SSI_REPAINT_ARROWS )
+           SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, FALSE );
+    }
+    return retVal;
+}
+
+INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, 
+                           const SCROLLINFO *info, INT *action  )
+{
+    /* Update the scrollbar state and set action flags according to 
+     * what has to be done graphics wise. */
+
+    SCROLLBAR_INFO *infoPtr;
+    UINT new_flags;
+
+//    dbg_decl_str(scroll, 256);
+
+   *action = 0;
+
+    if (!(infoPtr = SCROLL_GetScrollInfo(hwnd, nBar))) return 0;
+    if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
+    if ((info->cbSize != sizeof(*info)) &&
+        (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0;
+
+    /* Set the page size */
+
+    if (info->fMask & SIF_PAGE)
+    {
+  //      dsprintf(scroll, " page=%d", info->nPage );
+       if( infoPtr->Page != info->nPage )
+       {
+            infoPtr->Page = info->nPage;
+          *action |= SA_SSI_REFRESH;
+       }
+    }
+
+    /* Set the scroll pos */
+
+    if (info->fMask & SIF_POS)
+    {
+   //     dsprintf(scroll, " pos=%d", info->nPos );
+       if( infoPtr->CurVal != info->nPos )
+       {
+           infoPtr->CurVal = info->nPos;
+          *action |= SA_SSI_REFRESH;
+       }
+    }
+
+    /* Set the scroll range */
+
+    if (info->fMask & SIF_RANGE)
+    {
+     //   dsprintf(scroll, " min=%d max=%d", info->nMin, info->nMax );
+
+        /* Invalid range -> range is set to (0,0) */
+        if ((info->nMin > info->nMax) ||
+            ((UINT)(info->nMax - info->nMin) >= 0x80000000))
+        {
+            infoPtr->MinVal = 0;
+            infoPtr->MaxVal = 0;
+        }
+        else
+        {
+           if( infoPtr->MinVal != info->nMin ||
+               infoPtr->MaxVal != info->nMax )
+           {
+              *action |= SA_SSI_REFRESH;
+                infoPtr->MinVal = info->nMin;
+                infoPtr->MaxVal = info->nMax;
+           }
+        }
+    }
+
+    DPRINT( "hwnd=%04x bar=%d %s\n", 
+                   hwnd, nBar, dbg_str(scroll));
+
+    /* Make sure the page size is valid */
+
+    if (infoPtr->Page < 0) infoPtr->Page = 0;
+    else if (infoPtr->Page > infoPtr->MaxVal - infoPtr->MinVal + 1 )
+        infoPtr->Page = infoPtr->MaxVal - infoPtr->MinVal + 1;
+
+    /* Make sure the pos is inside the range */
+
+    if (infoPtr->CurVal < infoPtr->MinVal)
+        infoPtr->CurVal = infoPtr->MinVal;
+    else if (infoPtr->CurVal > infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
+        infoPtr->CurVal = infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 );
+
+    DPRINT( "    new values: page=%d pos=%d min=%d max=%d\n",
+                infoPtr->Page, infoPtr->CurVal,
+                infoPtr->MinVal, infoPtr->MaxVal );
+
+    /* Check if the scrollbar should be hidden or disabled */
+
+    if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
+    {
+        new_flags = infoPtr->flags;
+        if (infoPtr->MinVal >= infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
+        {
+            /* Hide or disable scroll-bar */
+            if (info->fMask & SIF_DISABLENOSCROLL)
+           {
+                new_flags = ESB_DISABLE_BOTH;
+              *action |= SA_SSI_REFRESH;
+           }
+            else if (nBar != SB_CTL)
+           {
+               *action = SA_SSI_HIDE;
+               goto done;
+            }
+        }
+        else  /* Show and enable scroll-bar */
+        {
+           new_flags = 0;
+            if (nBar != SB_CTL)
+               *action |= SA_SSI_SHOW;
+        }
+
+        if (infoPtr->flags != new_flags) /* check arrow flags */
+        {
+            infoPtr->flags = new_flags;
+           *action |= SA_SSI_REPAINT_ARROWS;
+        }
+    }
+
+done:
+    /* Return current position */
+
+    return infoPtr->CurVal;
+}
+
+
+
+
+/*************************************************************************
+ *           GetScrollInfo   (USER.284)
+ * GetScrollInfo can be used to retrieve the position, upper bound, 
+ * lower bound, and page size of a scrollbar control.
+ *
+ * RETURNS STD
+ */
+BOOL STDCALL GetScrollInfo( HWND hwnd , 
+  INT nBar ,   LPSCROLLINFO info )
+{
+    SCROLLBAR_INFO *infoPtr;
+
+    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
+    if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return FALSE;
+    if ((info->cbSize != sizeof(*info)) &&
+        (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return FALSE;
+
+    if (info->fMask & SIF_PAGE) info->nPage = infoPtr->Page;
+    if (info->fMask & SIF_POS) info->nPos = infoPtr->CurVal;
+    if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info)))
+        info->nTrackPos = (SCROLL_TrackingWin==hwnd) ? SCROLL_TrackingVal : 0;
+    if (info->fMask & SIF_RANGE)
+    {
+       info->nMin = infoPtr->MinVal;
+       info->nMax = infoPtr->MaxVal;
+    }
+    return (info->fMask & SIF_ALL) != 0;
+}
+
+
+
+
+/*************************************************************************
+ *           SetScrollPos   (USER.502)
+ *
+ * RETURNS
+ *    Success: Scrollbar position
+ *    Failure: 0
+ *
+ * REMARKS
+ *    Note the ambiguity when 0 is returned.  Use GetLastError
+ *    to make sure there was an error (and to know which one).
+ */
+INT STDCALL SetScrollPos( HWND hwnd , INT nBar , INT nPos ,BOOL bRedraw )
+{
+    SCROLLINFO info;
+    SCROLLBAR_INFO *infoPtr;
+    INT oldPos;
+
+    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
+    oldPos      = infoPtr->CurVal;
+    info.cbSize = sizeof(info);
+    info.nPos   = nPos;
+    info.fMask  = SIF_POS;
+    SetScrollInfo( hwnd, nBar, &info, bRedraw );
+    return oldPos;
+}
+
+
+
+
+/*************************************************************************
+ *           GetScrollPos   (USER.285)
+ *
+ * RETURNS
+ *    Success: Current position
+ *    Failure: 0   
+ *
+ * REMARKS
+ *    Note the ambiguity when 0 is returned.  Use GetLastError
+ *    to make sure there was an error (and to know which one).
+ */
+INT STDCALL GetScrollPos( HWND hwnd,INT nBar )
+{
+    SCROLLBAR_INFO *infoPtr;
+
+    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
+    return infoPtr->CurVal;
+}
+
+
+
+
+/*************************************************************************
+ *           SetScrollRange   (USER.503)
+ *
+ * RETURNS STD
+ */
+BOOL STDCALL SetScrollRange( HWND hwnd, INT nBar, 
+INT MinVal, INT MaxVal, BOOL bRedraw )
+{
+    SCROLLINFO info;
+
+    info.cbSize = sizeof(info);
+    info.nMin   = MinVal;
+    info.nMax   = MaxVal;
+    info.fMask  = SIF_RANGE;
+    SetScrollInfo( hwnd, nBar, &info, bRedraw );
+    return TRUE;
+}
+
+
+/*************************************************************************
+ *          SCROLL_SetNCSbState
+ *
+ * Updates both scrollbars at the same time. Used by MDI CalcChildScroll().
+ */
+INT SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos,
+                                      int hMin, int hMax, int hPos)
+{
+    INT vA, hA;
+    SCROLLINFO vInfo, hInfo;
+    vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
+    vInfo.nMin   = vMin;        hInfo.nMin   = hMin;
+    vInfo.nMax   = vMax;        hInfo.nMax   = hMax;
+    vInfo.nPos   = vPos;        hInfo.nPos   = hPos;
+    vInfo.fMask  = hInfo.fMask = SIF_RANGE | SIF_POS;
+
+    SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_VERT, &vInfo, &vA );
+    SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_HORZ, &hInfo, &hA );
+
+    if( !SCROLL_ShowScrollBar( wndPtr->hwndSelf, SB_BOTH,
+                             (hA & SA_SSI_SHOW),(vA & SA_SSI_SHOW) ) )
+    {
+       /* SetWindowPos() wasn't called, just redraw the scrollbars if needed */
+       if( vA & SA_SSI_REFRESH )
+           SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_VERT, FALSE, TRUE );
+
+       if( hA & SA_SSI_REFRESH )
+           SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_HORZ, FALSE, TRUE );
+    }
+    return 0;
+}
+
+
+
+
+/*************************************************************************
+ *           GetScrollRange   (USER.286)
+ *
+ * RETURNS STD
+ */
+BOOL STDCALL GetScrollRange( HWND hwnd, INT nBar, 
+       LPINT lpMin,LPINT lpMax )
+{
+    SCROLLBAR_INFO *infoPtr;
+
+    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar )))
+    {
+        if (lpMin) lpMin = 0;
+        if (lpMax) lpMax = 0;
+        return FALSE;
+    }
+    if (lpMin) *lpMin = infoPtr->MinVal;
+    if (lpMax) *lpMax = infoPtr->MaxVal;
+    return TRUE;
+}
+
+
+/*************************************************************************
+ *           SCROLL_ShowScrollBar()
+ *
+ * Back-end for ShowScrollBar(). Returns FALSE if no action was taken.
+ * NOTE: fShowV/fShowH must be zero when nBar is SB_HORZ/SB_VERT.
+ */
+BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, 
+                            BOOL fShowH, BOOL fShowV )
+{
+    WND *wndPtr = WIN_FindWndPtr( hwnd );
+
+    if (!wndPtr) return FALSE;
+    DPRINT( "hwnd=%04x bar=%d horz=%d, vert=%d\n",
+                    hwnd, nBar, fShowH, fShowV );
+
+    switch(nBar)
+    {
+    case SB_CTL:
+        ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE );
+        return TRUE;
+
+    case SB_BOTH:
+    case SB_HORZ:
+        if (fShowH)
+        {
+            fShowH = !(wndPtr->dwStyle & WS_HSCROLL);
+            wndPtr->dwStyle |= WS_HSCROLL;
+        }
+        else  /* hide it */
+        {
+            fShowH = (wndPtr->dwStyle & WS_HSCROLL);
+            wndPtr->dwStyle &= ~WS_HSCROLL;
+        }
+        if( nBar == SB_HORZ ) break; 
+       /* fall through */
+
+    case SB_VERT:
+        if (fShowV)
+        {
+            fShowV = !(wndPtr->dwStyle & WS_VSCROLL);
+            wndPtr->dwStyle |= WS_VSCROLL;
+        }
+       else  /* hide it */
+        {
+            fShowV = (wndPtr->dwStyle & WS_VSCROLL);
+            wndPtr->dwStyle &= ~WS_VSCROLL;
+        }
+        break;
+
+    default:
+        return FALSE;  /* Nothing to do! */
+    }
+
+    if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */
+    {
+       SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
+                    | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
+        return TRUE;
+    }
+
+    return FALSE; /* no frame changes */
+}
+
+
+
+/*************************************************************************
+ *             SCROLL_FixCaret
+ */
+WINBOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags)
+{
+   HWND hCaret = CARET_GetHwnd();
+
+   if( hCaret )
+   {
+       RECT    rc;
+       CARET_GetRect( &rc );
+       if( hCaret == hWnd ||
+          (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
+       {
+           POINT     pt;
+
+           pt.x = rc.left; pt.y = rc.top;
+           MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
+           if( IntersectRect(lprc, lprc, &rc) )
+           {
+               HideCaret(0);
+              lprc->left = pt.x; lprc->top = pt.y;
+              return TRUE;
+           }
+       }
+   }
+   return FALSE;
+}
+
+/*************************************************************************
+ *           ShowScrollBar   (USER.5)
+ *
+ * RETURNS STD
+ */
+BOOL STDCALL ShowScrollBar(
+       HWND hwnd, INT nBar, BOOL fShow )
+{
+    SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow,
+                                      (nBar == SB_HORZ) ? 0 : fShow );
+    return TRUE;
+}
+
+
+
+
+/*************************************************************************
+ *           EnableScrollBar   (USER.171)
+ */
+WINBOOL
+STDCALL
+EnableScrollBar(HWND hWnd,UINT wSBflags, UINT wArrows)
+{
+    BOOL bFineWithMe;
+    SCROLLBAR_INFO *infoPtr;
+
+    DPRINT( "%04x %d %d\n", hwnd, nBar, flags );
+
+     wArrows &= ESB_DISABLE_BOTH;
+
+    if (wSBflags == SB_BOTH)
+    {
+       if (!(infoPtr = SCROLL_GetScrollInfo( hWnd, SB_VERT ))) return FALSE;
+       if (!(bFineWithMe = (infoPtr->flags ==  wArrows)) )
+       {
+           infoPtr->flags =  wArrows;
+           SCROLL_RefreshScrollBar( hWnd, SB_VERT, TRUE, TRUE );
+       }
+       wSBflags = SB_HORZ;
+    }
+    else
+       bFineWithMe = TRUE;
+   
+    if (!(infoPtr = SCROLL_GetScrollInfo( hWnd, wSBflags ))) return FALSE;
+    if (bFineWithMe && infoPtr->flags ==  wArrows) return FALSE;
+    infoPtr->flags =  wArrows;
+
+    SCROLL_RefreshScrollBar( hWnd, wSBflags, TRUE, TRUE );
+    return TRUE;
+}
diff --git a/reactos/lib/user32/controls/static.c b/reactos/lib/user32/controls/static.c
new file mode 100644 (file)
index 0000000..779961e
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Static control
+ *
+ * Copyright  David W. Metcalfe, 1993
+ *
+ */
+
+#include <windows.h>
+#include <user32/win.h>
+#include <user32/static.h>
+#include <user32/debug.h>
+#include <user32/syscolor.h>
+#include <user32/nc.h>
+#include <user32/defwnd.h>
+
+
+/* Static Control Styles */
+
+
+
+
+//#define SS_ETCHEDHORZ       0x00000010L
+//#define SS_ETCHEDVERT       0x00000011L
+//#define SS_ETCHEDFRAME      0x00000012L
+#define SS_TYPEMASK         0x0000001FL
+
+//#define SS_NOPREFIX         0x00000080L
+//#define SS_NOTIFY           0x00000100L
+//#define SS_CENTERIMAGE      0x00000200L
+//#define SS_RIGHTJUST        0x00000400L
+//#define SS_REALSIZEIMAGE    0x00000800L
+//#define SS_SUNKEN           0x00001000L
+
+/* Static Control Messages */
+
+//#define STM_SETICON         0x0170
+//#define STM_GETICON         0x0171
+//#define STM_SETIMAGE        0x0172
+//#define STM_GETIMAGE        0x0173
+
+static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc );
+static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc );
+static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc );
+static void STATIC_PaintBitmapfn( WND *wndPtr, HDC hdc );
+static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc );
+
+static COLORREF color_windowframe, color_background, color_window;
+
+
+typedef void (*pfPaint)( WND *, HDC );
+
+static pfPaint staticPaintFunc[SS_TYPEMASK+1] =
+{
+    STATIC_PaintTextfn,      /* SS_LEFT */
+    STATIC_PaintTextfn,      /* SS_CENTER */
+    STATIC_PaintTextfn,      /* SS_RIGHT */
+    STATIC_PaintIconfn,      /* SS_ICON */
+    STATIC_PaintRectfn,      /* SS_BLACKRECT */
+    STATIC_PaintRectfn,      /* SS_GRAYRECT */
+    STATIC_PaintRectfn,      /* SS_WHITERECT */
+    STATIC_PaintRectfn,      /* SS_BLACKFRAME */
+    STATIC_PaintRectfn,      /* SS_GRAYFRAME */
+    STATIC_PaintRectfn,      /* SS_WHITEFRAME */
+    NULL,                    /* Not defined */
+    STATIC_PaintTextfn,      /* SS_SIMPLE */
+    STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
+    NULL,                    /* SS_OWNERDRAW */
+    STATIC_PaintBitmapfn,    /* SS_BITMAP */
+    NULL,                    /* SS_ENHMETAFILE */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDHORIZ */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
+};
+
+HICON STATIC_LoadIcon(WND *wndPtr,const void *name )
+{
+       HICON hIcon;
+       if ( wndPtr->class->bUnicode ) {
+               hIcon = LoadIconW(wndPtr->hInstance,(LPCWSTR)name);
+       }                       
+       else
+               hIcon = LoadIconA(wndPtr->hInstance,(LPCSTR)name);
+
+       return hIcon;
+}
+
+/***********************************************************************
+ *           STATIC_SetIcon
+ *
+ * Set the icon for an SS_ICON control.
+ */
+HICON STATIC_SetIcon( WND *wndPtr, HICON hicon )
+{
+    HICON prevIcon;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+    ICONINFO iconinfo;
+    BITMAP info;
+
+    if ( !GetIconInfo(hicon,   &iconinfo ) )
+       return NULL;
+
+    if ( iconinfo.hbmColor )
+       GetObject(iconinfo.hbmColor, sizeof(BITMAP),&info);
+    else
+       GetObject(iconinfo.hbmMask, sizeof(BITMAP),&info);
+   
+    if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_ICON) return 0;
+
+    prevIcon = infoPtr->hIcon;
+    infoPtr->hIcon = hicon;
+    if (hicon)
+    {
+        SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info.bmWidth, info.bmHeight,
+                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
+    }
+    return prevIcon;
+}
+
+
+HBITMAP STATIC_LoadBitmap(WND *wndPtr,const void *name )
+{
+       HBITMAP hBitmap;
+       if ( wndPtr->class->bUnicode ) {
+               hBitmap = LoadBitmapW(wndPtr->hInstance,(LPCWSTR)name);
+       }                       
+       else
+               hBitmap = LoadBitmapA(wndPtr->hInstance,(LPCSTR)name);
+       return hBitmap;
+}
+/***********************************************************************
+ *           STATIC_SetBitmap
+ *
+ * Set the bitmap for an SS_BITMAP control.
+ */
+HICON STATIC_SetBitmap( WND *wndPtr, HICON hicon )
+{
+
+    HICON prevIcon;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+    BITMAP info;
+
+    if ( hicon == NULL )
+       return NULL;
+
+    GetObject(hicon, sizeof(BITMAP),&info);
+
+    if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_BITMAP) return 0;
+   
+    prevIcon = infoPtr->hIcon;
+    infoPtr->hIcon = hicon;
+    if (hicon)
+    {
+        SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info.bmWidth, info.bmHeight,
+                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
+    }
+
+    return prevIcon;
+
+}
+
+
+
+
+/***********************************************************************
+ *           StaticWndProc
+ */
+LRESULT WINAPI StaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam,
+                              LPARAM lParam )
+{
+    LRESULT lResult = 0;
+    WND *wndPtr = WIN_FindWndPtr(hWnd);
+    LONG style = wndPtr->dwStyle & SS_TYPEMASK;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+
+    switch (uMsg)
+    {
+    case WM_NCCREATE: {
+        CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+
+       if ((TWEAK_WineLook > WIN31_LOOK) && (wndPtr->dwStyle & SS_SUNKEN))
+           wndPtr->dwExStyle |= WS_EX_STATICEDGE;
+
+        if (style == SS_ICON)
+        {
+            if (cs->lpszName) {
+               STATIC_SetIcon( wndPtr,STATIC_LoadIcon(wndPtr,cs->lpszName));
+           }
+            return 1;
+        }
+       if (style == SS_BITMAP)
+       {
+            if (cs->lpszName) {
+                STATIC_SetBitmap( wndPtr,STATIC_LoadBitmap(wndPtr,cs->lpszName));
+           }
+            return 1;
+       }
+
+       if ( wndPtr->class->bUnicode )
+               return DefWindowProcW( hWnd, uMsg, wParam, lParam );
+       else
+               return DefWindowProcA( hWnd, uMsg, wParam, lParam );
+    }
+    case WM_CREATE:
+        if (style < 0L || style > SS_TYPEMASK)
+        {
+            DPRINT( "Unknown style 0x%02lx\n", style );
+            lResult = -1L;
+            break;
+        }
+        /* initialise colours */
+        color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
+        color_background   = GetSysColor(COLOR_BACKGROUND);
+        color_window       = GetSysColor(COLOR_WINDOW);
+        break;
+
+    case WM_NCDESTROY:
+        if (style == SS_ICON) {
+/*
+ * FIXME
+ *           DestroyIcon( STATIC_SetIcon( wndPtr, 0 ) );
+ * 
+ * We don't want to do this yet because DestroyIcon is broken. If the icon
+ * had already been loaded by the application the last thing we want to do is
+ * GlobalFree the handle.
+ */
+        } else {
+               if ( wndPtr->class->bUnicode )
+                       lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam );
+               else
+                       lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam );
+        
+       }
+        break;
+
+    case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            BeginPaint( hWnd, &ps );
+            if (staticPaintFunc[style])
+                (staticPaintFunc[style])( wndPtr, ps.hdc );
+            EndPaint( hWnd, &ps );
+        }
+        break;
+
+    case WM_ENABLE:
+        InvalidateRect( hWnd, NULL, FALSE );
+        break;
+
+    case WM_SYSCOLORCHANGE:
+        color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
+        color_background   = GetSysColor(COLOR_BACKGROUND);
+        color_window       = GetSysColor(COLOR_WINDOW);
+        InvalidateRect( hWnd, NULL, TRUE );
+        break;
+
+    case WM_SETTEXT:
+       if (style == SS_ICON)
+        {
+            if (lParam) {
+               STATIC_SetIcon( wndPtr,STATIC_LoadIcon(wndPtr,(const void *)lParam));           
+           }
+            
+        }
+       else if (style == SS_BITMAP)
+       {
+            if (lParam) {
+                STATIC_SetBitmap( wndPtr,STATIC_LoadBitmap(wndPtr,(const void *)lParam));
+           }
+            
+       }
+       else {
+               DEFWND_SetText( wndPtr, (const void *)lParam );
+               
+        }
+        InvalidateRect( hWnd, NULL, FALSE );
+        UpdateWindow( hWnd );
+        break;
+
+    case WM_SETFONT:
+        if (style == SS_ICON) return 0;
+        if (style == SS_BITMAP) return 0;
+        infoPtr->hFont = (HFONT)wParam;
+        if (LOWORD(lParam))
+        {
+            InvalidateRect( hWnd, NULL, FALSE );
+            UpdateWindow( hWnd );
+        }
+        break;
+
+    case WM_GETFONT:
+        return infoPtr->hFont;
+
+    case WM_NCHITTEST:
+        return HTTRANSPARENT;
+
+    case WM_GETDLGCODE:
+        return DLGC_STATIC;
+
+    case STM_GETIMAGE:
+    case STM_GETICON:
+        return infoPtr->hIcon;
+
+    case STM_SETIMAGE:
+       /* FIXME: handle wParam */
+        lResult = STATIC_SetBitmap( wndPtr, (HBITMAP)lParam );
+        InvalidateRect( hWnd, NULL, FALSE );
+        UpdateWindow( hWnd );
+       break;
+
+
+    case STM_SETICON:
+        lResult = STATIC_SetIcon( wndPtr, (HICON)wParam );
+        InvalidateRect( hWnd, NULL, FALSE );
+        UpdateWindow( hWnd );
+        break;
+
+    default:
+       if ( wndPtr->class->bUnicode )
+               lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam );
+       else
+               lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam );
+        break;
+    }
+    
+    return lResult;
+}
+
+
+static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc )
+{
+    RECT rc;
+    HBRUSH hBrush;
+    WORD wFormat;
+
+    LONG style = wndPtr->dwStyle;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+
+    GetClientRect( wndPtr->hwndSelf, &rc);
+
+    switch (style & SS_TYPEMASK)
+    {
+    case SS_LEFT:
+       wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_CENTER:
+       wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_RIGHT:
+       wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_SIMPLE:
+       wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP;
+       break;
+
+    case SS_LEFTNOWORDWRAP:
+       wFormat = DT_LEFT | DT_SINGLELINE | DT_EXPANDTABS | DT_VCENTER | DT_NOCLIP;
+       break;
+
+    default:
+        return;
+    }
+
+    if (style & SS_NOPREFIX)
+       wFormat |= DT_NOPREFIX;
+
+    if (infoPtr->hFont) SelectObject( hdc, infoPtr->hFont );
+    hBrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC,
+                             (WPARAM)hdc,(LPARAM) wndPtr->hwndSelf );
+    if (!hBrush) hBrush = GetStockObject(WHITE_BRUSH);
+    FillRect( hdc, &rc, hBrush ); 
+    if (wndPtr->text)  {
+       if ( wndPtr->class->bUnicode ) {
+               DrawTextW( hdc, wndPtr->text, -1, &rc, wFormat );
+       }
+       else {
+               DrawTextA( hdc, wndPtr->text, -1, &rc, wFormat );
+       }
+    }
+
+}      
+       
+
+static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc )
+{
+    RECT rc;
+    HBRUSH hBrush;
+
+    GetClientRect( wndPtr->hwndSelf, &rc);
+    
+    switch (wndPtr->dwStyle & SS_TYPEMASK)
+    {
+    case SS_BLACKRECT:
+       hBrush = CreateSolidBrush(color_windowframe);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_GRAYRECT:
+       hBrush = CreateSolidBrush(color_background);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_WHITERECT:
+       hBrush = CreateSolidBrush(color_window);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_BLACKFRAME:
+       hBrush = CreateSolidBrush(color_windowframe);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    case SS_GRAYFRAME:
+       hBrush = CreateSolidBrush(color_background);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    case SS_WHITEFRAME:
+       hBrush = CreateSolidBrush(color_window);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    default:
+        return;
+    }
+    DeleteObject( hBrush );
+}
+
+
+static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc )
+{
+    RECT rc;
+    HBRUSH hbrush;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+
+    GetClientRect( wndPtr->hwndSelf, &rc );
+    hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC, 
+               (WPARAM)hdc, (LPARAM)wndPtr->hwndSelf );
+    FillRect( hdc, &rc, hbrush );
+    if (infoPtr->hIcon) DrawIcon( hdc, rc.left, rc.top, infoPtr->hIcon );
+}
+
+static void STATIC_PaintBitmapfn(WND *wndPtr, HDC hdc )
+{
+    RECT rc;
+    HBRUSH hbrush;
+    STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
+    HDC hMemDC;
+    HBITMAP oldbitmap;
+
+    GetClientRect( wndPtr->hwndSelf, &rc );
+    hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC,
+                             (WPARAM)hdc,(LPARAM) wndPtr->hwndSelf );
+    FillRect( hdc, &rc, hbrush );
+    if (infoPtr->hIcon) {
+       BITMAP bmp;
+       GetObject( infoPtr->hIcon, sizeof(BITMAP),&bmp);
+  
+        if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
+
+       oldbitmap = SelectObject(hMemDC,infoPtr->hIcon);
+       BitBlt(hdc,bmp.bmWidth,bmp.bmHeight,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY);
+//     BitBlt(hdc,bmp.size.cx,bmp.size.cy,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY);
+       DeleteDC(hMemDC);
+    }
+}
+
+
+static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc )
+{
+    RECT rc;
+    HBRUSH hbrush;
+    HPEN hpen;
+
+    if (TWEAK_WineLook == WIN31_LOOK)
+       return;
+
+    GetClientRect( wndPtr->hwndSelf, &rc );
+    hbrush = MSG_SendMessage( wndPtr->parent, WM_CTLCOLORSTATIC,
+                             (WPARAM)hdc, (LPARAM)wndPtr->hwndSelf );
+    FillRect( hdc, &rc, hbrush );
+
+    switch (wndPtr->dwStyle & SS_TYPEMASK)
+    {
+       case SS_ETCHEDHORZ:
+           hpen = SelectObject (hdc, GetSysColorPen (COLOR_3DSHADOW));
+           MoveToEx (hdc, rc.left, rc.bottom / 2 - 1, NULL);
+           LineTo (hdc, rc.right - 1, rc.bottom / 2 - 1);
+           SelectObject (hdc, GetSysColorPen (COLOR_3DHIGHLIGHT));
+           MoveToEx (hdc, rc.left, rc.bottom / 2, NULL);
+           LineTo (hdc, rc.right, rc.bottom / 2);
+           LineTo (hdc, rc.right, rc.bottom / 2 - 1);
+           SelectObject (hdc, hpen);
+           break;
+
+       case SS_ETCHEDVERT:
+           hpen = SelectObject (hdc, GetSysColorPen (COLOR_3DSHADOW));
+           MoveToEx (hdc, rc.right / 2 - 1, rc.top, NULL);
+           LineTo (hdc, rc.right / 2 - 1, rc.bottom - 1);
+           SelectObject (hdc, GetSysColorPen (COLOR_3DHIGHLIGHT));
+           MoveToEx (hdc, rc.right / 2, rc.top, NULL);
+           LineTo (hdc, rc.right / 2, rc.bottom);
+           LineTo (hdc, rc.right / 2 -1 , rc.bottom);
+           SelectObject (hdc, hpen); 
+           break;
+
+       case SS_ETCHEDFRAME:
+           DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
+           break;
+    }
+}
+
diff --git a/reactos/lib/user32/controls/widgets.c b/reactos/lib/user32/controls/widgets.c
new file mode 100644 (file)
index 0000000..aa7b544
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Windows widgets (built-in window classes)
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+#define UNICODE
+#include <windows.h>
+#include <user32/widgets.h>
+#include <user32/win.h>
+#include <user32/button.h>
+#include <user32/scroll.h>
+#include <user32/static.h>
+#include <user32/mdi.h>
+#include <user32/dialog.h>
+#include <user32/heapdup.h>
+
+
+/* Built-in classes */
+
+#define DLGWINDOWEXTRA sizeof(DIALOGINFO)
+
+
+static WNDCLASS WIDGETS_BuiltinClasses[BIC_NB_CLASSES+1] =
+{
+    /* BIC_BUTTON */
+    { CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC,
+      ButtonWndProc, 0, sizeof(BUTTONINFO), 0, 0,
+      (HCURSOR)IDC_ARROW, 0, 0, BUTTON_CLASS_NAME },
+    /* BIC_EDIT */
+    { CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/,
+      EditWndProc, 0, sizeof(void *), 0, 0,
+      (HCURSOR)IDC_IBEAM, 0, 0, EDIT_CLASS_NAME  },
+    /* BIC_LISTBOX */
+    { CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/,
+      ListBoxWndProc, 0, sizeof(void *), 0, 0,
+      (HCURSOR)IDC_ARROW, 0, 0,  LISTBOX_CLASS_NAME },
+    /* BIC_COMBO */
+    { CS_GLOBALCLASS | CS_PARENTDC | CS_DBLCLKS, 
+      ComboWndProc, 0, sizeof(void *), 0, 0,
+      (HCURSOR)IDC_ARROW, 0, 0, COMBOBOX_CLASS_NAME },
+    /* BIC_COMBOLB */
+    { CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS, ComboLBWndProc,
+      0, sizeof(void *), 0, 0, (HCURSOR)IDC_ARROW, 0, 0,COMBOLBOX_CLASS_NAME},
+    /* BIC_POPUPMENU */
+//    { CS_GLOBALCLASS | CS_SAVEBITS, PopupMenuWndProc, 0, sizeof(HMENU),
+//      0, 0, (HCURSOR)IDC_ARROW, NULL_BRUSH, 0, POPUPMENU_CLASS_NAME },
+    /* BIC_STATIC */
+    { CS_GLOBALCLASS | CS_PARENTDC, StaticWndProc,
+      0, sizeof(STATICINFO), 0, 0, (HCURSOR)IDC_ARROW, 0, 0,  STATIC_CLASS_NAME  },
+    /* BIC_SCROLL */
+    { CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC,
+      ScrollBarWndProc, 0, sizeof(SCROLLBAR_INFO), 0, 0,
+      (HCURSOR)IDC_ARROW, 0, 0, SCROLLBAR_CLASS_NAME},
+    /* BIC_MDICLIENT */
+//    { CS_GLOBALCLASS, MDIClientWndProc,
+//      0, sizeof(MDICLIENTINFO), 0, 0, 0, LTGRAY_BRUSH, 0, "MDIClient" },
+    /* BIC_DESKTOP */
+ //   { CS_GLOBALCLASS, DesktopWndProc, 0, sizeof(DESKTOPINFO),
+ //     0, 0, (HCURSOR)IDC_ARROW, 0, 0, DESKTOP_CLASS_NAME },
+    /* BIC_DIALOG */
+    { CS_GLOBALCLASS | CS_SAVEBITS, DefDlgProc, 100, 100,
+      0, 0, (HCURSOR)IDC_ARROW, 0, 0, DIALOG_CLASS_NAMEW },
+    /* BIC_ICONTITLE */
+    { CS_GLOBALCLASS, IconTitleWndProc, 0, 0, 
+      0, 0, (HCURSOR)IDC_ARROW, 0, 0, ICONTITLE_CLASS_NAME },
+    /* BIC_DIALOG Ascii */
+    { CS_GLOBALCLASS, DefDlgProcA, 100,  100,
+      0, 0, (HCURSOR)IDC_ARROW, 0, 0, (LPWSTR)DIALOG_CLASS_NAME_A }
+};
+
+
+static ATOM bicAtomTable[BIC_NB_CLASSES+1];
+
+/***********************************************************************
+ *           WIDGETS_Init
+ * 
+ * Initialize the built-in window classes.
+ */
+WINBOOL WIDGETS_Init(void)
+{
+    int i;
+    WNDCLASS *cls = WIDGETS_BuiltinClasses;
+
+    /* Create builtin classes */
+
+    for (i = 0; i < BIC_NB_CLASSES; i++)
+    {
+
+        cls[i].hCursor = LoadCursorW( 0, (LPCWSTR)cls[i].hCursor );
+        if (!(bicAtomTable[i] = RegisterClassW( &cls[i] ))) return FALSE;
+    }
+
+    cls[i].hCursor = LoadCursorW( 0, (LPCWSTR)cls[i].hCursor );
+    if (!(bicAtomTable[i] = RegisterClassA( &cls[i] ))) return FALSE;
+
+
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           WIDGETS_IsControl
+ *
+ * Check whether pWnd is a built-in control or not.
+ */
+WINBOOL        WIDGETS_IsControl( WND* pWnd, BUILTIN_CLASS cls )
+{
+    if(  cls >= BIC_NB_CLASSES )
+       return FALSE;
+    return (pWnd->class->atomName == bicAtomTable[cls]);
+}
index 29aaea6..ef49ec2 100644 (file)
@@ -1,6 +1,37 @@
 #include <windows.h>
 
 
+
+INT STDCALL FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
+{
+    HBRUSH prevBrush;
+    //int left, top, right, bottom;
+
+    if ( hdc == NULL )
+       return 0;
+
+    //left   = XLPTODP( dc, rect->left );
+    //top    = YLPTODP( dc, rect->top );
+    //right  = XLPTODP( dc, rect->right );
+    //bottom = YLPTODP( dc, rect->bottom );
+
+    //if ( (right <= left) || (bottom <= top) ) return 0;
+    if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
+    
+    PatBlt( hdc, rect->left, rect->top, 1,
+             rect->bottom - rect->top, PATCOPY );
+    PatBlt( hdc, rect->right - 1, rect->top, 1,
+             rect->bottom - rect->top, PATCOPY );
+    PatBlt( hdc, rect->left, rect->top,
+             rect->right - rect->left, 1, PATCOPY );
+    PatBlt( hdc, rect->left, rect->bottom - 1,
+             rect->right - rect->left, 1, PATCOPY );
+
+    SelectObject( hdc, prevBrush );
+    return 1;
+}
+
+
 INT STDCALL FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
 {
     HBRUSH prevBrush;
index bcb303c..d6111b6 100644 (file)
@@ -1,7 +1,9 @@
 
 #include <windows.h>
 
+#include <user32/static.h>
 
+HICON LoadStandardIcon(UINT IconId);
 
 HICON
 STDCALL
@@ -27,8 +29,42 @@ CreateIcon(
 HICON
 STDCALL
 CreateIconIndirect(
-                  PICONINFO piconinfo)
+                  PICONINFO lpIconInfo)
 {
+    BITMAP bmpXor,bmpAnd;
+    HICON hObj;
+    int        sizeXor,sizeAnd;
+
+    GetObject(lpIconInfo->hbmColor,sizeof(BITMAP),&bmpXor);
+    GetObject(lpIconInfo->hbmMask,sizeof(BITMAP),&bmpAnd);
+   
+   
+
+    sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
+    sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
+
+    hObj = GlobalAlloc( GMEM_MOVEABLE, 
+                    sizeof(ICONINFO) + sizeXor + sizeAnd );
+    if (hObj)
+    {
+       ICONINFO *info;
+
+       info = (ICONINFO *)( hObj );
+       info->xHotspot   = lpIconInfo->xHotspot;
+       info->yHotspot   = lpIconInfo->yHotspot;
+       //info->nWidth        = bmpXor.bmWidth;
+       //info->nHeight       = bmpXor.bmHeight;
+       //info->nWidthBytes   = bmpXor.bmWidthBytes;
+       //info->bPlanes       = bmpXor.bmPlanes;
+       //info->bBitsPerPixel = bmpXor.bmBitsPixel;
+
+       /* Transfer the bitmap bits to the CURSORICONINFO structure */
+
+       GetBitmapBits( lpIconInfo->hbmMask ,sizeAnd,(char*)(info + 1) );
+       GetBitmapBits( lpIconInfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
+       
+    }
+    return hObj;
 }
 
  
@@ -53,14 +89,79 @@ GetIconInfo(
 
 HICON LoadIconA(HINSTANCE hInstance,LPCSTR  lpIconName )
 {
-       return CreateIcon(hInstance,    GetSystemMetrics(SM_CXSMICON),
-       GetSystemMetrics(SM_CYSMICON),
-       0,0,NULL,NULL);
+       HRSRC hrsrc;
+       ICONINFO *IconInfo;
+       
+       if ( hInstance == NULL ) {
+               return LoadStandardIcon((UINT)lpIconName);
+       }
+//RT_GROUP_ICON
+hrsrc = FindResourceExA(hInstance,RT_GROUP_ICON, lpIconName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
+
+       if ( hrsrc == NULL )
+               return NULL;
+
+       IconInfo = (ICONINFO *)LoadResource(hInstance, hrsrc);
+       if ( IconInfo != NULL || IconInfo->fIcon == FALSE )
+               return NULL;    
+
+       return CreateIconIndirect(IconInfo);
 }
 
 HICON LoadIconW(HINSTANCE hInstance,LPCWSTR  lpIconName )
 {
-       return CreateIcon(hInstance,    GetSystemMetrics(SM_CXSMICON),
-       GetSystemMetrics(SM_CYSMICON),
-       0,0,NULL,NULL);
+       HRSRC hrsrc;
+       ICONINFO *IconInfo;
+
+       if ( hInstance == NULL ) {
+               return LoadStandardIcon((UINT)lpIconName);
+       }
+
+       hrsrc = FindResourceW(hInstance,lpIconName,RT_GROUP_ICON);
+       if ( hrsrc == NULL )
+               return NULL;
+
+       IconInfo = (ICONINFO *)LoadResource(hInstance, hrsrc);
+       if ( IconInfo != NULL || IconInfo->fIcon == FALSE )
+               return NULL;    
+
+       return CreateIconIndirect(IconInfo);
+}
+
+HICON LoadStandardIcon(UINT IconId)
+{
+       HMODULE hModule = LoadLibraryA("user32.dll");
+       switch (IconId )
+       {       
+               case IDI_APPLICATION:
+                       IconId = 100;
+                       return LoadIconW(hModule,(LPWSTR)IconId);
+                       break;
+               case IDI_ASTERISK:
+               //
+                       IconId = 103;
+                       return LoadIconW(hModule,(LPWSTR)IconId);
+                       break;
+               case IDI_EXCLAMATION:
+                       IconId = 101;
+                       return LoadIconW(hModule,(LPWSTR)IconId);
+                       break;
+               case IDI_HAND:
+               // 
+                       return LoadIconW(hModule,(LPWSTR)MAKEINTRESOURCE(104));
+                       break;
+               case IDI_QUESTION:
+                       IconId = 102;
+                       return LoadIconW(hModule,(LPWSTR)IconId);
+                       break;
+               case IDI_WINLOGO:
+                       IconId = 105;
+                       return LoadIconW(hModule,(LPWSTR)IconId);
+                       break;
+               default:
+                       return NULL;
+                       break;
+       
+       }
+       return NULL;
 }
\ No newline at end of file
index feced1c..fbceacd 100644 (file)
@@ -8,12 +8,10 @@
 
 
 #include <windows.h>
-//#include <user32/syscolor.h>
+#include <user32/syscolor.h>
 #include <user32/nc.h>
 
 
-void SYSCOLOR_SetColor( int index, COLORREF color );
-void SYSCOLOR_Init(void);
 
 static const char * const DefSysColors[] =
 {
@@ -149,7 +147,7 @@ HBRUSH STDCALL GetSysColorBrush( INT index )
  * Windows. However, it is a natural complement for GetSysColorBrush
  * in the Win API and is needed quite a bit inside Wine.
  */
-HPEN STDCALL GetSysColorPen( INT index )
+HPEN  GetSysColorPen( INT index )
 {
     /* We can assert here, because this function is internal to Wine */
     //assert (0 <= index && index < NUM_SYS_COLORS);
index 6f8b18e..3ab4c67 100644 (file)
@@ -1,4 +1,5 @@
 #include <windows.h>
+#include <user32/text.h>
 
 
 int
@@ -25,4 +26,48 @@ DrawTextW(
        dtp.iTabLength = 0;
        return TEXT_DrawTextEx(hDC,(void *)lpString,nCount,lpRect,uFormat, &dtp,TRUE);
 
-}
\ No newline at end of file
+}
+
+/***********************************************************************
+ *           GetTabbedTextExtentA    (USER32.293)
+ */
+DWORD
+STDCALL
+GetTabbedTextExtentA(HDC hDC, LPCSTR lpString, int nCount, int nTabPositions,
+    LPINT lpnTabStopPositions)
+{
+
+ return TEXT_TabbedTextOutA( hDC, 0, 0, lpString, nCount, nTabPositions,
+                                 lpnTabStopPositions,0, FALSE );
+}
+
+
+DWORD
+STDCALL
+GetTabbedTextExtentW(HDC hDC, LPCWSTR lpString, int nCount, int nTabPositions,
+    LPINT lpnTabStopPositions)
+{
+
+    return TEXT_TabbedTextOutW( hDC, 0, 0, lpString, nCount, nTabPositions,
+                               lpnTabStopPositions, 0,  FALSE );
+}
+
+
+LONG
+STDCALL
+TabbedTextOutA(    HDC hDC,    int X,    int Y,    LPCSTR lpString,
+    int nCount,    int nTabPositions,  LPINT lpnTabStopPositions, int nTabOrigin)
+{
+       return TEXT_TabbedTextOutA( hDC, X, Y, lpString, nCount, nTabPositions,
+                               lpnTabStopPositions, nTabOrigin,  TRUE );
+}
+
+LONG
+STDCALL
+TabbedTextOutW(    HDC hDC,    int X,    int Y,    LPCWSTR lpString,
+    int nCount,    int nTabPositions,  LPINT lpnTabStopPositions, int nTabOrigin)
+{
+       return TEXT_TabbedTextOutW( hDC, 0, 0, lpString, nCount, nTabPositions,
+                               lpnTabStopPositions, nTabOrigin,  TRUE );
+}
+
index ac90ae5..61c4fe2 100644 (file)
@@ -14,6 +14,7 @@
 #include <user32/dce.h>
 #include <user32/sysmetr.h>
 #include <user32/paint.h>
+#include <user32/defwnd.h>
 #include <user32/debug.h>
 
 
@@ -65,11 +66,22 @@ void DEFWND_HandleWindowPosChanged( WND *wndPtr, UINT flags )
  *
  * Set the window text.
  */
+
+void DEFWND_SetText( WND *wndPtr,const void *text )
+{
+       if ( wndPtr->class->bUnicode )
+               DEFWND_SetTextW( wndPtr, (LPCWSTR) text );
+       else
+               DEFWND_SetTextA( wndPtr, (LPCSTR) text );
+          
+}
+
 void DEFWND_SetTextA( WND *wndPtr, LPCSTR text )
 {
     if (!text) text = "";
     if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text );
-    wndPtr->text = (void *)HEAP_strdupA( GetProcessHeap(), 0, text );    
+    wndPtr->text = (void *)HEAP_strdupA( GetProcessHeap(), 0, text );   
+    NC_HandleNCPaint( wndPtr->hwndSelf , (HRGN)1 );  /* Repaint caption */
 }
 
 
@@ -77,7 +89,8 @@ void DEFWND_SetTextW( WND *wndPtr, LPCWSTR text )
 {
     if (!text) text = L"";
     if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text );
-    wndPtr->text = (void *)HEAP_strdupW( GetProcessHeap(), 0, text );    
+    wndPtr->text = (void *)HEAP_strdupW( GetProcessHeap(), 0, text );  
+    NC_HandleNCPaint( wndPtr->hwndSelf , (HRGN)1 );  /* Repaint caption */  
 
 }
 /***********************************************************************
@@ -125,7 +138,7 @@ void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam )
     {
        if( !bVisible )
        {
-           wndPtr->dwStyle |= WS_VISIBLE;
+           //wndPtr->dwStyle |= WS_VISIBLE;
            DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow );
        }
     }
@@ -136,7 +149,7 @@ void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam )
 
        PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, wParam, 0 );
        DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow );
-       wndPtr->dwStyle &= ~WS_VISIBLE;
+//     wndPtr->dwStyle &= ~WS_VISIBLE;
     }
 }
 
@@ -171,8 +184,8 @@ LRESULT DEFWND_DefWinProc( WND *wndPtr, UINT msg, WPARAM wParam,
         if ((wndPtr->flags & WIN_ISWIN) || (TWEAK_WineLook > WIN31_LOOK))
         {
            ClientToScreen(wndPtr->hwndSelf, (LPPOINT)&lParam);
-            SendMessageA( wndPtr->hwndSelf, WM_CONTEXTMENU,
-                           wndPtr->hwndSelf, lParam);
+            MSG_SendMessage( wndPtr, WM_CONTEXTMENU,
+                           (WPARAM)wndPtr->hwndSelf,(LPARAM) lParam);
         }
         break;
 
index 8fdef99..6fff013 100644 (file)
@@ -5,62 +5,24 @@
  */
 
 #include <ctype.h>
-#include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
-#include "windows.h"
-#include "dialog.h"
-#include "drive.h"
-#include "heap.h"
-#include "win.h"
-#include "ldt.h"
-#include "user.h"
-#include "winproc.h"
-#include "message.h"
-#include "sysmetrics.h"
-#include "debug.h"
-
-
-  /* Dialog control information */
-typedef struct
-{
-    DWORD      style;
-    DWORD      exStyle;
-    DWORD      helpId;
-    INT16      x;
-    INT16      y;
-    INT16      cx;
-    INT16      cy;
-    UINT32     id;
-    LPCSTR     className;
-    LPCSTR     windowName;
-    LPVOID     data;
-} DLG_CONTROL_INFO;
-
-  /* Dialog template */
-typedef struct
-{
-    DWORD      style;
-    DWORD      exStyle;
-    DWORD      helpId;
-    UINT16     nbItems;
-    INT16      x;
-    INT16      y;
-    INT16      cx;
-    INT16      cy;
-    LPCSTR     menuName;
-    LPCSTR     className;
-    LPCSTR     caption;
-    WORD       pointSize;
-    WORD       weight;
-    WINBOOL     italic;
-    LPCSTR     faceName;
-    WINBOOL     dialogEx;
-} DLG_TEMPLATE;
+
+#define UNICODE
+#include <windows.h>
+#include <user32/dialog.h>
+#include <user32/heapdup.h>
+#include <user32/win.h>
+#include <user32/sysmetr.h>
+#include <user32/debug.h>
+#include <user32/msg.h>
+#include <user32/widgets.h>
+
+
 
   /* Dialog base units */
-static WORD xBaseUnit = 0, yBaseUnit = 0;
+WORD xBaseUnit = 0, yBaseUnit = 0;
 
 
 /***********************************************************************
@@ -70,14 +32,14 @@ static WORD xBaseUnit = 0, yBaseUnit = 0;
  */
 WINBOOL DIALOG_Init(void)
 {
-    TEXTMETRIC16 tm;
-    HDC16 hdc;
+    TEXTMETRIC tm;
+    HDC hdc;
     
       /* Calculate the dialog base units */
 
-    if (!(hdc = CreateDC16( "DISPLAY", NULL, NULL, NULL ))) return FALSE;
-    GetTextMetrics16( hdc, &tm );
-    DeleteDC32( hdc );
+    if (!(hdc = CreateDC( L"DISPLAY", NULL, NULL, NULL ))) return FALSE;
+    GetTextMetrics( hdc, &tm );
+    DeleteDC( hdc );
     xBaseUnit = tm.tmAveCharWidth;
     yBaseUnit = tm.tmHeight;
 
@@ -86,488 +48,520 @@ WINBOOL DIALOG_Init(void)
     if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH))
         xBaseUnit = xBaseUnit * 5 / 4;
 
-    TRACE(dialog, "base units = %d,%d\n",
+    DPRINT( "base units = %d,%d\n",
                     xBaseUnit, yBaseUnit );
     return TRUE;
 }
 
-
 /***********************************************************************
- *           DIALOG_GetControl16
- *
- * Return the class and text of the control pointed to by ptr,
- * fill the header structure and return a pointer to the next control.
+ *           DIALOG_DoDialogBox
  */
-static LPCSTR DIALOG_GetControl16( LPCSTR p, DLG_CONTROL_INFO *info )
+INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
 {
-    static char buffer[10];
-    int int_id;
-
-    info->x       = GET_WORD(p);  p += sizeof(WORD);
-    info->y       = GET_WORD(p);  p += sizeof(WORD);
-    info->cx      = GET_WORD(p);  p += sizeof(WORD);
-    info->cy      = GET_WORD(p);  p += sizeof(WORD);
-    info->id      = GET_WORD(p);  p += sizeof(WORD);
-    info->style   = GET_DWORD(p); p += sizeof(DWORD);
-    info->exStyle = 0;
-
-    if (*p & 0x80)
-    {
-        switch((BYTE)*p)
-        {
-            case 0x80: strcpy( buffer, "BUTTON" ); break;
-            case 0x81: strcpy( buffer, "EDIT" ); break;
-            case 0x82: strcpy( buffer, "STATIC" ); break;
-            case 0x83: strcpy( buffer, "LISTBOX" ); break;
-            case 0x84: strcpy( buffer, "SCROLLBAR" ); break;
-            case 0x85: strcpy( buffer, "COMBOBOX" ); break;
-            default:   buffer[0] = '\0'; break;
-        }
-        info->className = buffer;
-        p++;
-    }
-    else 
-    {
-       info->className = p;
-       p += strlen(p) + 1;
-    }
-
-    int_id = ((BYTE)*p == 0xff);
-    if (int_id)
-    {
-         /* Integer id, not documented (?). Only works for SS_ICON controls */
-       info->windowName = (LPCSTR)(UINT32)GET_WORD(p+1);
-       p += 3;
-    }
-    else
-    {
-       info->windowName = p;
-       p += strlen(p) + 1;
-    }
-
-    info->data = (LPVOID)(*p ? p + 1 : NULL);  /* FIXME: should be a segptr */
-    p += *p + 1;
-
-    if(int_id)
-      TRACE(dialog,"   %s %04x %d, %d, %d, %d, %d, %08lx, %08lx\n", 
-                     info->className,  LOWORD(info->windowName),
-                     info->id, info->x, info->y, info->cx, info->cy,
-                     info->style, (DWORD)info->data);
-    else
-      TRACE(dialog,"   %s '%s' %d, %d, %d, %d, %d, %08lx, %08lx\n", 
-                     info->className,  info->windowName,
-                     info->id, info->x, info->y, info->cx, info->cy,
-                     info->style, (DWORD)info->data);
-
-    return p;
-}
-
-
-/***********************************************************************
- *           DIALOG_GetControl32
- *
- * Return the class and text of the control pointed to by ptr,
- * fill the header structure and return a pointer to the next control.
- */
-static const WORD *DIALOG_GetControl32( const WORD *p, DLG_CONTROL_INFO *info,
-                                        WINBOOL dialogEx )
-{
-    if (dialogEx)
-    {
-        info->helpId  = GET_DWORD(p); p += 2;
-        info->exStyle = GET_DWORD(p); p += 2;
-        info->style   = GET_DWORD(p); p += 2;
-    }
-    else
-    {
-        info->helpId  = 0;
-        info->style   = GET_DWORD(p); p += 2;
-        info->exStyle = GET_DWORD(p); p += 2;
-    }
-    info->x       = GET_WORD(p); p++;
-    info->y       = GET_WORD(p); p++;
-    info->cx      = GET_WORD(p); p++;
-    info->cy      = GET_WORD(p); p++;
-
-    if (dialogEx)
-    {
-        /* id is a DWORD for DIALOGEX */
-        info->id = GET_DWORD(p);
-        p += 2;
-    }
-    else
-    {
-        info->id = GET_WORD(p);
-        p++;
-    }
-
-    if (GET_WORD(p) == 0xffff)
-    {
-        static const WCHAR class_names[6][10] =
-        {
-            { 'B','u','t','t','o','n', },             /* 0x80 */
-            { 'E','d','i','t', },                     /* 0x81 */
-            { 'S','t','a','t','i','c', },             /* 0x82 */
-            { 'L','i','s','t','B','o','x', },         /* 0x83 */
-            { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */
-            { 'C','o','m','b','o','B','o','x', }      /* 0x85 */
-        };
-        WORD id = GET_WORD(p+1);
-        if ((id >= 0x80) && (id <= 0x85))
-            info->className = (LPCSTR)class_names[id - 0x80];
-        else
-        {
-            info->className = NULL;
-            ERR( dialog, "Unknown built-in class id %04x\n", id );
-        }
-        p += 2;
-    }
-    else
-    {
-        info->className = (LPCSTR)p;
-        p += lstrlen32W( (LPCWSTR)p ) + 1;
-    }
-
-    if (GET_WORD(p) == 0xffff)  /* Is it an integer id? */
-    {
-       info->windowName = (LPCSTR)(UINT32)GET_WORD(p + 1);
-       p += 2;
-    }
-    else
-    {
-       info->windowName = (LPCSTR)p;
-        p += lstrlen32W( (LPCWSTR)p ) + 1;
-    }
+    WND * wndPtr;
+    DIALOGINFO * dlgInfo;
+    MSG msg;
+    INT retval;
 
-    TRACE(dialog,"    %s %s %d, %d, %d, %d, %d, %08lx, %08lx, %08lx\n", 
-          debugstr_w( (LPCWSTR)info->className ),
-          debugres_w( (LPCWSTR)info->windowName ),
-          info->id, info->x, info->y, info->cx, info->cy,
-          info->style, info->exStyle, info->helpId );
+      /* Owner must be a top-level window */
+    owner = WIN_GetTopParent( owner );
+    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
+    dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
+    EnableWindow( owner, FALSE );
+    ShowWindow( hwnd, SW_SHOW );
 
-    if (GET_WORD(p))
+    while (MSG_InternalGetMessage(&msg, hwnd, owner, MSGF_DIALOGBOX, PM_REMOVE,
+                                  !(wndPtr->dwStyle & DS_NOIDLEMSG) ))
     {
-        if (TRACE_ON(dialog))
-        {
-            WORD i, count = GET_WORD(p) / sizeof(WORD);
-            TRACE(dialog, "  BEGIN\n");
-            TRACE(dialog, "    ");
-            for (i = 0; i < count; i++) DUMP( "%04x,", GET_WORD(p+i+1) );
-            DUMP("\n");
-            TRACE(dialog, "  END\n" );
-        }
-        info->data = (LPVOID)(p + 1);
-        p += GET_WORD(p) / sizeof(WORD);
+       if (!IsDialogMessage( hwnd, &msg))
+       {
+           TranslateMessage( &msg );
+           DispatchMessage( &msg );
+       }
+       if (dlgInfo->flags & DF_END) break;
     }
-    else info->data = NULL;
-    p++;
-
-    /* Next control is on dword boundary */
-    return (const WORD *)((((int)p) + 3) & ~3);
+    retval = dlgInfo->idResult;
+    EnableWindow( owner, TRUE );
+    dlgInfo->flags |= DF_ENDING;   /* try to stop it being destroyed twice */
+    DestroyWindow( hwnd );
+    return retval;
 }
 
 
-/***********************************************************************
- *           DIALOG_CreateControls
- *
- * Create the control windows for a dialog.
- */
-static WINBOOL DIALOG_CreateControls( WND *pWnd, LPCSTR template,
-                                     const DLG_TEMPLATE *dlgTemplate,
-                                     HINSTANCE32 hInst, WINBOOL win32 )
-{
-    DIALOGINFO *dlgInfo = (DIALOGINFO *)pWnd->wExtra;
-    DLG_CONTROL_INFO info;
-    HWND32 hwndCtrl, hwndDefButton = 0;
-    INT32 items = dlgTemplate->nbItems;
-
-    TRACE(dialog, " BEGIN\n" );
-    while (items--)
-    {
-        if (!win32)
-        {
-            HINSTANCE16 instance;
-            template = DIALOG_GetControl16( template, &info );
-            if (HIWORD(info.className) && !strcmp( info.className, "EDIT") &&
-                ((pWnd->dwStyle & DS_LOCALEDIT) != DS_LOCALEDIT))
-            {
-                if (!dlgInfo->hDialogHeap)
-                {
-                    dlgInfo->hDialogHeap = GlobalAlloc16(GMEM_FIXED, 0x10000);
-                    if (!dlgInfo->hDialogHeap)
-                    {
-                        ERR(dialog, "Insufficient memory to create heap for edit control\n" );
-                        continue;
-                    }
-                    LocalInit(dlgInfo->hDialogHeap, 0, 0xffff);
-                }
-                instance = dlgInfo->hDialogHeap;
-            }
-            else instance = (HINSTANCE16)hInst;
-
-            hwndCtrl = CreateWindowEx16( info.exStyle | WS_EX_NOPARENTNOTIFY,
-                                         info.className, info.windowName,
-                                         info.style | WS_CHILD,
-                                         info.x * dlgInfo->xBaseUnit / 4,
-                                         info.y * dlgInfo->yBaseUnit / 8,
-                                         info.cx * dlgInfo->xBaseUnit / 4,
-                                         info.cy * dlgInfo->yBaseUnit / 8,
-                                         pWnd->hwndSelf, (HMENU16)info.id,
-                                         instance, info.data );
-        }
-        else
-        {
-            template = (LPCSTR)DIALOG_GetControl32( (WORD *)template, &info,
-                                                    dlgTemplate->dialogEx );
-            hwndCtrl = CreateWindowEx32W( info.exStyle | WS_EX_NOPARENTNOTIFY,
-                                          (LPCWSTR)info.className,
-                                          (LPCWSTR)info.windowName,
-                                          info.style | WS_CHILD,
-                                          info.x * dlgInfo->xBaseUnit / 4,
-                                          info.y * dlgInfo->yBaseUnit / 8,
-                                          info.cx * dlgInfo->xBaseUnit / 4,
-                                          info.cy * dlgInfo->yBaseUnit / 8,
-                                          pWnd->hwndSelf, (HMENU32)info.id,
-                                          hInst, info.data );
-        }
-        if (!hwndCtrl) return FALSE;
-
-            /* Send initialisation messages to the control */
-        if (dlgInfo->hUserFont) SendMessage32A( hwndCtrl, WM_SETFONT,
-                                             (WPARAM32)dlgInfo->hUserFont, 0 );
-        if (SendMessage32A(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
-        {
-              /* If there's already a default push-button, set it back */
-              /* to normal and use this one instead. */
-            if (hwndDefButton)
-                SendMessage32A( hwndDefButton, BM_SETSTYLE32,
-                                BS_PUSHBUTTON,FALSE );
-            hwndDefButton = hwndCtrl;
-            dlgInfo->idResult = GetWindowWord32( hwndCtrl, GWW_ID );
-        }
-    }    
-    TRACE(dialog, " END\n" );
-    return TRUE;
-}
-
 
 /***********************************************************************
- *           DIALOG_ParseTemplate16
+ *           DIALOG_ParseTemplate
  *
  * Fill a DLG_TEMPLATE structure from the dialog template, and return
  * a pointer to the first control.
  */
-static LPCSTR DIALOG_ParseTemplate16( LPCSTR p, DLG_TEMPLATE * result )
+LPCDLGITEMTEMPLATE  DIALOG_ParseTemplate( LPCDLGTEMPLATE DlgTemplate, DLG_TEMPLATE * result, WINBOOL bUnicode )
 {
-    result->style   = GET_DWORD(p); p += sizeof(DWORD);
-    result->exStyle = 0;
-    result->nbItems = *p++;
-    result->x       = GET_WORD(p);  p += sizeof(WORD);
-    result->y       = GET_WORD(p);  p += sizeof(WORD);
-    result->cx      = GET_WORD(p);  p += sizeof(WORD);
-    result->cy      = GET_WORD(p);  p += sizeof(WORD);
-    TRACE(dialog, "DIALOG %d, %d, %d, %d\n",
-                    result->x, result->y, result->cx, result->cy );
-    TRACE(dialog, " STYLE %08lx\n", result->style );
+    WORD *p; 
+    
+   
+    result->dialogEx = FALSE;
+    result->helpId   = 0;
+    result->exStyle  = DlgTemplate->dwExtendedStyle;
+    
+    result->nbItems = DlgTemplate->cdit;
+    result->x       = DlgTemplate->x;
+    result->y       = DlgTemplate->y;
+    result->cx      = DlgTemplate->cx;
+    result->cy      = DlgTemplate->cy;
+    
+    p = &(DlgTemplate->cy);
+    p++;
 
-    /* Get the menu name */
+   
+   /* Get the menu name */
 
-    switch( (BYTE)*p )
+    switch((WORD)*p)
     {
-    case 0:
-        result->menuName = 0;
+    case 0x0000:
+        result->menuName = NULL;
         p++;
         break;
-    case 0xff:
-        result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
-        p += 3;
-       TRACE(dialog, " MENU %04x\n", LOWORD(result->menuName) );
+    case 0xffff:
+       p++;
+        result->menuName = (LPWSTR) *p; // Ordinal of Menu resource
+        p++;
         break;
     default:
-        result->menuName = p;
-        TRACE(dialog, " MENU '%s'\n", p );
-        p += strlen(p) + 1;
+        result->menuName = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p );
+       p++;
         break;
     }
 
     /* Get the class name */
 
-    if (*p)
+
+
+    switch((WORD)*p)
     {
-        result->className = p;
-        TRACE(dialog, " CLASS '%s'\n", result->className );
+    case 0x0000:
+       if ( bUnicode == TRUE )
+               result->className = DIALOG_CLASS_NAMEW;
+       else
+               result->className = DIALOG_CLASS_NAMEA;
+        p++;
+        break;
+    case 0xffff:
+       p++;
+        result->className = (LPCWSTR)p;  // Ordinal of predefined class
+        p++;
+        break;
+    default:
+        result->className = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p );
+       p++;
+        break;
     }
-    else result->className = DIALOG_CLASS_ATOM;
-    p += strlen(p) + 1;
 
     /* Get the window caption */
+    if ( *p != 0 ) {
+       result->caption = (LPCWSTR)p;
+       p += lstrlenW( (LPCWSTR)p ) + 1;
+       /* Get the font name */
+
+       if (result->style & DS_SETFONT)
+       {
+               result->pointSize = *p;
+                       p++;
+               if (result->dialogEx)
+               {
+                       result->weight = *p; p++;
+                       result->italic = *p; p++;
+               }
+               else
+               {
+                       result->weight = FW_DONTCARE;
+                       result->italic = FALSE;
+               }
+               result->faceName = (LPCWSTR)p;
+               p += lstrlenW( (LPCWSTR)p );
+               p++;
+       
+       }
+    } else {
+       result->caption = L"";
+    }
 
-    result->caption = p;
-    p += strlen(p) + 1;
-    TRACE(dialog, " CAPTION '%s'\n", result->caption );
 
-    /* Get the font name */
 
-    if (result->style & DS_SETFONT)
-    {
-       result->pointSize = GET_WORD(p);
-        p += sizeof(WORD);
-       result->faceName = p;
-        p += strlen(p) + 1;
-       TRACE(dialog, " FONT %d,'%s'\n",
-                        result->pointSize, result->faceName );
-    }
-    return p;
+    /* First control is on dword boundary */
+    return (LPCDLGITEMTEMPLATE )((((int)p) + 3) & ~3);
 }
 
-
 /***********************************************************************
- *           DIALOG_ParseTemplate32
+ *           DIALOG_ParseTemplate
  *
  * Fill a DLG_TEMPLATE structure from the dialog template, and return
  * a pointer to the first control.
  */
-static LPCSTR DIALOG_ParseTemplate32( LPCSTR template, DLG_TEMPLATE * result )
+LPCDLGITEMTEMPLATEEX  DIALOG_ParseTemplateEx( LPCDLGTEMPLATEEX DlgTemplate, DLG_TEMPLATE * result,WINBOOL bUnicode )
 {
-    const WORD *p = (const WORD *)template;
+    WORD *p;
 
-    result->style = GET_DWORD(p); p += 2;
-    if (result->style == 0xffff0001)  /* DIALOGEX resource */
-    {
-        result->dialogEx = TRUE;
-        result->helpId   = GET_DWORD(p); p += 2;
-        result->exStyle  = GET_DWORD(p); p += 2;
-        result->style    = GET_DWORD(p); p += 2;
-    }
-    else
-    {
-        result->dialogEx = FALSE;
-        result->helpId   = 0;
-        result->exStyle  = GET_DWORD(p); p += 2;
-    }
-    result->nbItems = GET_WORD(p); p++;
-    result->x       = GET_WORD(p); p++;
-    result->y       = GET_WORD(p); p++;
-    result->cx      = GET_WORD(p); p++;
-    result->cy      = GET_WORD(p); p++;
-    TRACE( dialog, "DIALOG%s %d, %d, %d, %d, %ld\n",
-           result->dialogEx ? "EX" : "", result->x, result->y,
-           result->cx, result->cy, result->helpId );
-    TRACE( dialog, " STYLE 0x%08lx\n", result->style );
-    TRACE( dialog, " EXSTYLE 0x%08lx\n", result->exStyle );
+
+    result->dialogEx = TRUE;
+    result->helpId   = DlgTemplate->helpID;
+    result->exStyle  = DlgTemplate->exStyle;
+    result->style    = DlgTemplate->style;
+    
+    result->nbItems = DlgTemplate->cDlgItems;
+    result->x       = DlgTemplate->x;
+    result->y       = DlgTemplate->y;
+    result->cx      = DlgTemplate->cx;
+    result->cy      = DlgTemplate->cy;
+
+    p = &(DlgTemplate->cy);
+    p++;
 
     /* Get the menu name */
 
-    switch(GET_WORD(p))
+    switch(*p)
     {
     case 0x0000:
         result->menuName = NULL;
         p++;
         break;
     case 0xffff:
-        result->menuName = (LPCSTR)(UINT32)GET_WORD( p + 1 );
-        p += 2;
-       TRACE(dialog, " MENU %04x\n", LOWORD(result->menuName) );
+       p++;
+        result->menuName = (LPCWSTR)(WORD)*( p ); // Ordinal of Menu resource
+        p++;
         break;
     default:
-        result->menuName = (LPCSTR)p;
-        TRACE(dialog, " MENU %s\n", debugstr_w( (LPCWSTR)p ));
-        p += lstrlen32W( (LPCWSTR)p ) + 1;
+        result->menuName = (LPCWSTR)p; 
+        p += lstrlenW( (LPCWSTR)p ) + 1;
         break;
     }
 
     /* Get the class name */
 
-    switch(GET_WORD(p))
+    switch(*p)
     {
     case 0x0000:
-        result->className = DIALOG_CLASS_ATOM;
+        if ( bUnicode == TRUE )
+               result->className = DIALOG_CLASS_NAMEW;
+       else
+               result->className = DIALOG_CLASS_NAMEA;
         p++;
         break;
     case 0xffff:
-        result->className = (LPCSTR)(UINT32)GET_WORD( p + 1 );
-        p += 2;
-       TRACE(dialog, " CLASS %04x\n", LOWORD(result->className) );
+       p++;
+        result->className = (LPCWSTR)(WORD)*( p );
+        p ++;
+       DPRINT( " CLASS %04x\n", LOWORD(result->className) );
         break;
     default:
-        result->className = (LPCSTR)p;
-        TRACE(dialog, " CLASS %s\n", debugstr_w( (LPCWSTR)p ));
-        p += lstrlen32W( (LPCWSTR)p ) + 1;
+        result->className = (LPCWSTR)p;
+        DPRINT( " CLASS %s\n", debugstr_w( (LPCWSTR)p ));
+        p += lstrlenW( (LPCWSTR)p ) + 1;
         break;
     }
 
     /* Get the window caption */
+    if ( *p != 0 ) {
+       result->caption = (LPCWSTR)p;
+       p += lstrlenW( (LPCWSTR)p ) + 1;
+       /* Get the font name */
+
+       if (result->style & DS_SETFONT)
+       {
+               result->pointSize = LOWORD(p);
+                       p++;
+               if (result->dialogEx)
+               {
+                       result->weight = *p; p++;
+                       result->italic = LOBYTE(*p); p++;
+               }
+               else
+               {
+                       result->weight = FW_DONTCARE;
+                       result->italic = FALSE;
+               }
+               result->faceName = (LPCWSTR)p;
+               p += lstrlenW( (LPCWSTR)p ) + 1;
+       
+       }
+    } else 
+       result->caption = L"";
+    
+
+    /* First control is on dword boundary */
+    return (LPDLGITEMTEMPLATEEX )((((int)p) + 3) & ~3);
+}
 
-    result->caption = (LPCSTR)p;
-    p += lstrlen32W( (LPCWSTR)p ) + 1;
-    TRACE(dialog, " CAPTION %s\n", debugstr_w( (LPCWSTR)result->caption ) );
 
-    /* Get the font name */
+/***********************************************************************
+ *           DIALOG_GetControl
+ *
+ * Return the class and text of the control pointed to by ptr,
+ * fill the header structure and return a pointer to the next control.
+ */
+LPCDLGITEMTEMPLATE DIALOG_GetControl( LPCDLGITEMTEMPLATE DlgItemTemplate, DLG_CONTROL_INFO *info)
+{
+    WORD *p;
+    WORD id;
 
-    if (result->style & DS_SETFONT)
+    info->helpId  = 0;
+    info->exStyle = DlgItemTemplate->dwExtendedStyle;
+    info->style   = DlgItemTemplate->style;
+    
+    info->x       = DlgItemTemplate->x;
+    info->y       = DlgItemTemplate->y;
+    info->cx      = DlgItemTemplate->cx;
+    info->cy      = DlgItemTemplate->cy;
+
+  
+    info->id = DlgItemTemplate->id;
+    
+
+    p = (char *)DlgItemTemplate + sizeof(DLGITEMTEMPLATE);
+    p--;   
+
+    if (*p == 0xffff)
     {
-       result->pointSize = GET_WORD(p);
-        p++;
-        if (result->dialogEx)
+
+       static const WCHAR class_names[6][10] =
         {
-            result->weight = GET_WORD(p); p++;
-            result->italic = LOBYTE(GET_WORD(p)); p++;
-        }
+            { BUTTON_CLASS_NAME },     /* 0x80 */
+            { EDIT_CLASS_NAME },        /* 0x81 */
+            { STATIC_CLASS_NAME  },     /* 0x82 */
+            { LISTBOX_CLASS_NAME},     /* 0x83 */
+            { SCROLLBAR_CLASS_NAME },  /* 0x84 */
+            { COMBOBOX_CLASS_NAME }    /* 0x85 */
+        };
+       p++;
+        id = (WORD)*(p);
+        if ((id >= 0x80) && (id <= 0x85))
+            info->className = (LPCSTR)HEAP_strdupW(GetProcessHeap(),0,class_names[id - 0x80]);
         else
+            info->className = NULL;
+       
+       printf("%S\n",info->className);        
+
+        p++;
+    }
+    else
+    {
+        info->className = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p ) + 1;
+    }
+
+    if (*p == 0xffff)  /* Is it an integer id? */
+    {
+       p++;
+       info->windowName = (LPCWSTR)(WORD)*(p + 1);
+       p++;
+    }
+    else
+    {
+       info->windowName = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p ) + 1;
+    }
+
+
+
+    if (*p)
+    {
+       p++;
+       info->data = (LPVOID)(p);
+       p += *p / sizeof(WORD);
+    }
+    else { 
+       info->data = NULL;
+       p++;
+    }
+
+    /* Next control is on dword boundary */
+    return (LPCDLGITEMTEMPLATE)((((int)p) + 3) & ~3);
+}
+
+
+/***********************************************************************
+ *           DIALOG_GetControl
+ *
+ * Return the class and text of the control pointed to by ptr,
+ * fill the header structure and return a pointer to the next control.
+ */
+LPCDLGITEMTEMPLATEEX DIALOG_GetControlEx( LPCDLGITEMTEMPLATEEX DlgItemTemplate, DLG_CONTROL_INFO *info )
+{
+    WORD *p;
+    WORD id;
+    info->helpId  = DlgItemTemplate->helpID;
+    info->exStyle = DlgItemTemplate->exStyle;
+    info->style   = DlgItemTemplate->style;
+  
+    info->x       = DlgItemTemplate->x;
+    info->y       = DlgItemTemplate->y;
+    info->cx      = DlgItemTemplate->cx;
+    info->cy      = DlgItemTemplate->cy;
+
+  
+    /* id is a DWORD for DIALOGEX */
+    info->id = DlgItemTemplate->id;
+  
+    p = (char *)DlgItemTemplate + sizeof(DLGITEMTEMPLATEEX);
+    p--;
+
+    if (*p == 0xffff)
+    {
+
+        static const WCHAR class_names[6][10] =
         {
-            result->weight = FW_DONTCARE;
-            result->italic = FALSE;
-        }
-       result->faceName = (LPCSTR)p;
-        p += lstrlen32W( (LPCWSTR)p ) + 1;
-       TRACE(dialog, " FONT %d, %s, %d, %s\n",
-              result->pointSize, debugstr_w( (LPCWSTR)result->faceName ),
-              result->weight, result->italic ? "TRUE" : "FALSE" );
+            { L"Button" },     /* 0x80 */
+            { L"Edit"},        /* 0x81 */
+            { L"Static" },     /* 0x82 */
+            { L"ListBox"},     /* 0x83 */
+            { L"ScrollBar" },  /* 0x84 */
+            { L"ComboBox" }    /* 0x85 */
+        };
+       p++;
+        id = (WORD)*(p);
+        if ((id >= 0x80) && (id <= 0x85))
+            info->className = (LPCSTR)HEAP_strdupW(GetProcessHeap(),0,class_names[id - 0x80]);
+        else
+            info->className = NULL;
+        
+        p++;
+    }
+    else
+    {
+        info->className = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p ) + 1;
     }
 
-    /* First control is on dword boundary */
-    return (LPCSTR)((((int)p) + 3) & ~3);
+    if (*p == 0xffff)  /* Is it an integer id? */
+    {
+       p++;
+       info->windowName = (LPCWSTR)(WORD)*(p);
+       p++;
+    }
+    else
+    {
+       
+       info->windowName = (LPCWSTR)p;
+        p += lstrlenW( (LPCWSTR)p ) + 1;
+    }
+
+
+
+    if (*p) {
+
+       p++;
+       info->data = (LPVOID)(p);
+       p += *p / sizeof(WORD);
+    }
+    else {
+       info->data = NULL;
+       p++;
+    }
+
+    /* Next control is on dword boundary */
+    return (LPCDLGITEMTEMPLATE)((((int)p) + 3) & ~3);
+}
+
+
+/***********************************************************************
+ *           DIALOG_CreateControls
+ *
+ * Create the control windows for a dialog.
+ */
+WINBOOL DIALOG_CreateControls( HANDLE hWndDialog, DIALOGINFO *dlgInfo , 
+                                     void *template, INT items,
+                                     HINSTANCE hInst, WINBOOL bDialogEx)
+{
+    DLG_CONTROL_INFO info;
+    HWND hwndCtrl, hwndDefButton = 0;
+   
+    while (items--)
+    {
+       
+       if ( bDialogEx)
+               template = (void *)DIALOG_GetControlEx( (LPDLGITEMTEMPLATEEX)template, &info );
+       else
+               template = (void *)DIALOG_GetControl( (LPDLGITEMTEMPLATE)template, &info );
+
+        hwndCtrl = CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY,
+                          (LPCWSTR)info.className,
+                          (LPCWSTR)info.windowName,
+                          info.style | WS_CHILD | WS_THICKFRAME | WS_VISIBLE,
+                          info.x * dlgInfo->xBaseUnit / 4,
+                          info.y * dlgInfo->yBaseUnit / 8,
+                          info.cx * dlgInfo->xBaseUnit / 4 ,
+                          info.cy * dlgInfo->yBaseUnit / 8,
+                          hWndDialog, (HMENU)info.id,
+                          hInst, info.data );
+      
+       
+        if (hwndCtrl) {
+
+            /* Send initialisation messages to the control */
+               if (dlgInfo->hUserFont) SendMessage( hwndCtrl, WM_SETFONT,
+                                             (WPARAM)dlgInfo->hUserFont, 0 );
+               if (SendMessage(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
+               {
+               /* If there's already a default push-button, set it back */
+               /* to normal and use this one instead. */
+                       if (hwndDefButton)
+                               SendMessage( hwndDefButton, BM_SETSTYLE, BS_PUSHBUTTON,FALSE );
+                       hwndDefButton = hwndCtrl;
+                       dlgInfo->idResult = GetWindowLong( hwndCtrl, GWL_ID );
+               }
+       }
+    }    
+    return TRUE;
 }
 
 
+
+
+
 /***********************************************************************
  *           DIALOG_CreateIndirect
  */
-HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
-                              WINBOOL win32Template, HWND32 owner,
-                              DLGPROC16 dlgProc, LPARAM param,
-                              WINDOWPROCTYPE procType )
+HWND DIALOG_CreateIndirect( HINSTANCE hInst, void *dlgTemplate, HWND owner,
+                              DLGPROC dlgProc, LPARAM param,
+                              WINBOOL bUnicode )
 {
-    HMENU16 hMenu = 0;
-    HFONT16 hFont = 0;
-    HWND32 hwnd;
-    RECT32 rect;
+    HMENU hMenu = 0;
+    HFONT hFont = 0;
+    HWND hwnd;
+    RECT rect;
     WND * wndPtr;
     DLG_TEMPLATE template;
     DIALOGINFO * dlgInfo;
     WORD xUnit = xBaseUnit;
     WORD yUnit = yBaseUnit;
+    void *dlgItemTemplate;
+
+
+
+    if ( xBaseUnit == 0 )
+       DIALOG_Init();
+
+    xUnit = xBaseUnit;
+    yUnit = yBaseUnit;
 
       /* Parse dialog template */
 
-    if (!dlgTemplate) return 0;
-    if (win32Template)
-        dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );
-    else
-        dlgTemplate = DIALOG_ParseTemplate16( dlgTemplate, &template );
+    if (((LPDLGTEMPLATEEX)dlgTemplate)->signature != 0xffff)  /* DIALOGEX resource */
+       dlgItemTemplate = (void *)DIALOG_ParseTemplate((LPCDLGTEMPLATE) dlgTemplate, &template, bUnicode );     
+    else 
+       dlgItemTemplate = (void *)DIALOG_ParseTemplateEx( (LPCDLGTEMPLATEEX)dlgTemplate, &template, bUnicode ); 
+    
 
       /* Load menu */
-
     if (template.menuName)
-    {
-        if (!win32Template)
-        {
-            LPSTR str = SEGPTR_STRDUP( template.menuName );
-           hMenu = LoadMenu16( hInst, SEGPTR_GET(str) );
-            SEGPTR_FREE( str );
-       }
-        else hMenu = LoadMenu32W( hInst, (LPCWSTR)template.menuName );
-    }
+       hMenu = LoadMenuW( hInst, (LPCWSTR)template.menuName );
+
 
       /* Create custom font if needed */
 
@@ -576,33 +570,31 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
           /* The font height must be negative as it is a point size */
           /* (see CreateFont() documentation in the Windows SDK).   */
 
-       if (win32Template)
-           hFont = CreateFont32W( -template.pointSize, 0, 0, 0,
+       
+       hFont = CreateFontW( -template.pointSize, 0, 0, 0,
                                    template.weight, template.italic, FALSE,
                                    FALSE, DEFAULT_CHARSET, 0, 0, PROOF_QUALITY,
                                    FF_DONTCARE, (LPCWSTR)template.faceName );
-       else
-           hFont = CreateFont16( -template.pointSize, 0, 0, 0, FW_DONTCARE,
-                                 FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
-                                 PROOF_QUALITY, FF_DONTCARE,
-                                 template.faceName );
+       
        if (hFont)
        {
-           TEXTMETRIC16 tm;
-           HFONT16 oldFont;
-
-           HDC32 hdc = GetDC32(0);
-           oldFont = SelectObject32( hdc, hFont );
-           GetTextMetrics16( hdc, &tm );
-           SelectObject32( hdc, oldFont );
-           ReleaseDC32( 0, hdc );
+           TEXTMETRIC tm;
+           HFONT oldFont;
+
+           HDC hdc = GetDC(0);
+           oldFont = SelectObject( hdc, hFont );
+           GetTextMetrics( hdc, &tm );
+           SelectObject( hdc, oldFont );
+           ReleaseDC( 0, hdc );
            xUnit = tm.tmAveCharWidth;
            yUnit = tm.tmHeight;
             if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH))
                 xBaseUnit = xBaseUnit * 5 / 4;  /* See DIALOG_Init() */
+
        }
     }
-    
+  
     /* Create dialog main window */
 
     rect.left = rect.top = 0;
@@ -610,15 +602,14 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
     rect.bottom = template.cy * yUnit / 8;
     if (template.style & DS_MODALFRAME)
         template.exStyle |= WS_EX_DLGMODALFRAME;
-    AdjustWindowRectEx32( &rect, template.style, 
+    AdjustWindowRectEx( &rect, template.style, 
                           hMenu ? TRUE : FALSE , template.exStyle );
     rect.right -= rect.left;
     rect.bottom -= rect.top;
 
-    if ((INT16)template.x == CW_USEDEFAULT16)
+    if ((INT)template.x == CW_USEDEFAULT)
     {
-        rect.left = rect.top = (procType == WIN_PROC_16) ? CW_USEDEFAULT16
-                                                         : CW_USEDEFAULT32;
+        rect.left = rect.top = CW_USEDEFAULT;
     }
     else
     {
@@ -634,48 +625,50 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
         }
         if ( !(template.style & WS_CHILD) )
        {
-            INT16 dX, dY;
+            INT dX, dY;
 
             if( !(template.style & DS_ABSALIGN) )
-                ClientToScreen32( owner, (POINT32 *)&rect );
+                ClientToScreen( owner, (POINT *)&rect );
            
             /* try to fit it into the desktop */
 
-            if( (dX = rect.left + rect.right + SYSMETRICS_CXDLGFRAME 
-                 - SYSMETRICS_CXSCREEN) > 0 ) rect.left -= dX;
-            if( (dY = rect.top + rect.bottom + SYSMETRICS_CYDLGFRAME
-                 - SYSMETRICS_CYSCREEN) > 0 ) rect.top -= dY;
+            if( (dX = rect.left + rect.right + SYSMETRICS_CXDLGFRAME  - SYSMETRICS_CXSCREEN) > 0 ) 
+               rect.left -= dX;
+            if( (dY = rect.top + rect.bottom + SYSMETRICS_CYDLGFRAME  - SYSMETRICS_CYSCREEN) > 0 ) 
+               rect.top -= dY;
             if( rect.left < 0 ) rect.left = 0;
             if( rect.top < 0 ) rect.top = 0;
         }
     }
 
-    if (procType == WIN_PROC_16)
-        hwnd = CreateWindowEx16(template.exStyle, template.className,
-                                template.caption, template.style & ~WS_VISIBLE,
-                                rect.left, rect.top, rect.right, rect.bottom,
-                                owner, hMenu, hInst, NULL );
-    else
-        hwnd = CreateWindowEx32W(template.exStyle, (LPCWSTR)template.className,
+
+// template.style & ~WS_VISIBLE
+
+template.style |= WS_VISIBLE;
+template.style |= WS_THICKFRAME;
+    hwnd = CreateWindowExW(template.exStyle, (LPCWSTR)template.className,
                                  (LPCWSTR)template.caption,
-                                 template.style & ~WS_VISIBLE,
-                                 rect.left, rect.top, rect.right, rect.bottom,
+                                 template.style ,
+                                 rect.left, rect.top, rect.right, rect.bottom ,
                                  owner, hMenu, hInst, NULL );
+  
+    
        
     if (!hwnd)
     {
-       if (hFont) DeleteObject32( hFont );
-       if (hMenu) DestroyMenu32( hMenu );
+       if (hFont) DeleteObject( hFont );
+       if (hMenu) DestroyMenu( hMenu );
        return 0;
     }
     wndPtr = WIN_FindWndPtr( hwnd );
     wndPtr->flags |= WIN_ISDIALOG;
     wndPtr->helpContext = template.helpId;
+    wndPtr->winproc = dlgProc;
 
       /* Initialise dialog extra data */
 
     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
-    WINPROC_SetProc( &dlgInfo->dlgProc, dlgProc, procType, WIN_PROC_WINDOW );
+    dlgInfo->dlgProc   = dlgProc;
     dlgInfo->hUserFont = hFont;
     dlgInfo->hMenu     = hMenu;
     dlgInfo->xBaseUnit = xUnit;
@@ -686,220 +679,246 @@ HWND32 DIALOG_CreateIndirect( HINSTANCE32 hInst, LPCSTR dlgTemplate,
     dlgInfo->hDialogHeap = 0;
 
     if (dlgInfo->hUserFont)
-        SendMessage32A( hwnd, WM_SETFONT, (WPARAM32)dlgInfo->hUserFont, 0 );
+        MSG_SendMessage( wndPtr, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0L);
 
     /* Create controls */
 
-    if (DIALOG_CreateControls( wndPtr, dlgTemplate, &template,
-                               hInst, win32Template ))
+
+
+    if (!DIALOG_CreateControls( hwnd, dlgInfo, dlgItemTemplate, template.nbItems, hInst , template.dialogEx))
     {
+       DestroyWindow( hwnd );
+       if (hFont) DeleteObject( hFont );
+       if (hMenu) DestroyMenu( hMenu );
+       return 0;
+    }
+   
+       
        /* Send initialisation messages and set focus */
 
-       dlgInfo->hwndFocus = GetNextDlgTabItem32( hwnd, 0, FALSE );
+    dlgInfo->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
 
-       if (SendMessage32A( hwnd, WM_INITDIALOG, (WPARAM32)dlgInfo->hwndFocus, param ))
-            SetFocus32( dlgInfo->hwndFocus );
+    if (MSG_SendMessage( wndPtr, WM_INITDIALOG, (WPARAM)dlgInfo->hwndFocus, param))
+            SetFocus( dlgInfo->hwndFocus );
 
-       if (template.style & WS_VISIBLE && !(wndPtr->dwStyle & WS_VISIBLE)) 
-       {
-          ShowWindow32( hwnd, SW_SHOWNORMAL ); /* SW_SHOW doesn't always work */
-          UpdateWindow32( hwnd );
-       }
-       return hwnd;
-    }
 
-    if( IsWindow32(hwnd) ) DestroyWindow32( hwnd );
-    return 0;
+    //if (template.style & WS_VISIBLE && !(wndPtr->dwStyle & WS_VISIBLE)) 
+    //{
+          ShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
+          UpdateWindow( hwnd );
+   // }
+
+
+  PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0,
+                                RDW_INVALIDATE | RDW_ALLCHILDREN |
+                                RDW_FRAME | RDW_ERASENOW | RDW_ERASE, 0 );
+    return hwnd;
 }
 
 
 
-/**********************************************************************
- *           DIALOG_DlgDirSelect
- *
- * Helper function for DlgDirSelect*
- */
-static WINBOOL DIALOG_DlgDirSelect( HWND32 hwnd, LPSTR str, INT32 len,
-                                   INT32 id, WINBOOL win32, WINBOOL unicode,
-                                   WINBOOL combo )
-{
-    char *buffer, *ptr;
-    INT32 item, size;
-    WINBOOL ret;
-    HWND32 listbox = GetDlgItem32( hwnd, id );
-
-    TRACE(dialog, "%04x '%s' %d\n", hwnd, str, id );
-    if (!listbox) return FALSE;
-    if (win32)
-    {
-        item = SendMessage32A(listbox, combo ? CB_GETCURSEL32
-                                             : LB_GETCURSEL32, 0, 0 );
-        if (item == LB_ERR) return FALSE;
-        size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN32
-                                             : LB_GETTEXTLEN32, 0, 0 );
-        if (size == LB_ERR) return FALSE;
-    }
-    else
-    {
-        item = SendMessage32A(listbox, combo ? CB_GETCURSEL16
-                                             : LB_GETCURSEL16, 0, 0 );
-        if (item == LB_ERR) return FALSE;
-        size = SendMessage32A(listbox, combo ? CB_GETLBTEXTLEN16
-                                             : LB_GETTEXTLEN16, 0, 0 );
-        if (size == LB_ERR) return FALSE;
-    }
 
-    if (!(buffer = SEGPTR_ALLOC( size+1 ))) return FALSE;
 
-    if (win32)
-        SendMessage32A( listbox, combo ? CB_GETLBTEXT32 : LB_GETTEXT32,
-                        item, (LPARAM)buffer );
-    else
-        SendMessage16( listbox, combo ? CB_GETLBTEXT16 : LB_GETTEXT16,
-                       item, (LPARAM)SEGPTR_GET(buffer) );
 
-    if ((ret = (buffer[0] == '[')))  /* drive or directory */
+/***********************************************************************
+ *           DIALOG_IsAccelerator
+ */
+WINBOOL DIALOG_IsAccelerator( HWND hwnd, HWND hwndDlg, WPARAM vKey )
+{
+    HWND hwndControl = hwnd;
+    HWND hwndNext;
+    WND *wndPtr;
+    WINBOOL RetVal = FALSE;
+    INT dlgCode;
+
+    if (vKey == VK_SPACE)
     {
-        if (buffer[1] == '-')  /* drive */
+        dlgCode = SendMessage( hwndControl, WM_GETDLGCODE, 0, 0 );
+        if (dlgCode & DLGC_BUTTON)
         {
-            buffer[3] = ':';
-            buffer[4] = 0;
-            ptr = buffer + 2;
+            SendMessage( hwndControl, WM_LBUTTONDOWN, 0, 0);
+            SendMessage( hwndControl, WM_LBUTTONUP, 0, 0);
+            RetVal = TRUE;
         }
-        else
+    }
+    else
+    {
+        do
         {
-            buffer[strlen(buffer)-1] = '\\';
-            ptr = buffer + 1;
+            wndPtr = WIN_FindWndPtr( hwndControl );
+            if (wndPtr != NULL && wndPtr->text != NULL && 
+                    (wndPtr->dwStyle & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)
+            {
+                dlgCode = SendMessage( hwndControl, WM_GETDLGCODE, 0, 0 );
+                if (dlgCode & (DLGC_BUTTON | DLGC_STATIC))
+                {
+                    /* find the accelerator key */
+                    LPSTR p = wndPtr->text - 2;
+                    do
+                    {
+                        p = strchr( p + 2, '&' );
+                    }
+                    while (p != NULL && p[1] == '&');
+
+                    /* and check if it's the one we're looking for */
+                    if (p != NULL && toupper( p[1] ) == toupper( vKey ) )
+                    {
+                        if ((dlgCode & DLGC_STATIC) || 
+                            (wndPtr->dwStyle & 0x0f) == BS_GROUPBOX )
+                        {
+                            /* set focus to the control */
+                            SendMessage( hwndDlg, WM_NEXTDLGCTL,
+                                    hwndControl, 1);
+                            /* and bump it on to next */
+                            SendMessage( hwndDlg, WM_NEXTDLGCTL, 0, 0);
+                        }
+                        else if (dlgCode & 
+                           (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))
+                        {
+                            /* send command message as from the control */
+                            SendMessage( hwndDlg, WM_COMMAND, 
+                                MAKEWPARAM( LOWORD(wndPtr->wIDmenu), 
+                                    BN_CLICKED ),
+                                (LPARAM)hwndControl );
+                        }
+                        else
+                        {
+                            /* click the control */
+                            SendMessage( hwndControl, WM_LBUTTONDOWN, (WPARAM) 0, (LPARAM)0);
+                            SendMessage( hwndControl, WM_LBUTTONUP, (WPARAM)0, (LPARAM)0);
+                        }
+                        RetVal = TRUE;
+                        break;
+                    }
+                }
+            }
+           hwndNext = GetWindow( hwndControl, GW_CHILD );
+           if (!hwndNext)
+           {
+               hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
+           }
+           while (!hwndNext)
+           {
+               hwndControl = GetParent( hwndControl );
+               if (hwndControl == hwndDlg)
+               {
+                   hwndNext = GetWindow( hwndDlg, GW_CHILD );
+               }
+               else
+               {
+                   hwndNext = GetWindow( hwndControl, GW_HWNDNEXT );
+               }
+           }
+            hwndControl = hwndNext;
         }
+        while (hwndControl != hwnd);
     }
-    else ptr = buffer;
-
-    if (unicode) lstrcpynAtoW( (LPWSTR)str, ptr, len );
-    else lstrcpyn32A( str, ptr, len );
-    SEGPTR_FREE( buffer );
-    TRACE(dialog, "Returning %d '%s'\n", ret, str );
-    return ret;
+    return RetVal;
 }
 
-
-/**********************************************************************
- *         DIALOG_DlgDirList
- *
- * Helper function for DlgDirList*
+/***********************************************************************
+ *           DIALOG_IsDialogMessage
  */
-static INT32 DIALOG_DlgDirList( HWND32 hDlg, LPSTR spec, INT32 idLBox,
-                                INT32 idStatic, UINT32 attrib, WINBOOL combo )
+WINBOOL DIALOG_IsDialogMessage( HWND hwnd, HWND hwndDlg,
+                                      UINT message, WPARAM wParam,
+                                      LPARAM lParam, WINBOOL *translate,
+                                      WINBOOL *dispatch, INT dlgCode )
 {
-    int drive;
-    HWND32 hwnd;
-    LPSTR orig_spec = spec;
+    *translate = *dispatch = FALSE;
 
-#define SENDMSG(msg,wparam,lparam) \
-    ((attrib & DDL_POSTMSGS) ? PostMessage32A( hwnd, msg, wparam, lparam ) \
-                             : SendMessage32A( hwnd, msg, wparam, lparam ))
+    if (message == WM_PAINT)
+    {
+        /* Apparently, we have to handle this one as well */
+        *dispatch = TRUE;
+        return TRUE;
+    }
 
-    TRACE(dialog, "%04x '%s' %d %d %04x\n",
-                    hDlg, spec ? spec : "NULL", idLBox, idStatic, attrib );
+      /* Only the key messages get special processing */
+    if ((message != WM_KEYDOWN) &&
+        (message != WM_SYSCHAR) &&
+       (message != WM_CHAR))
+        return FALSE;
 
-    if (spec && spec[0] && (spec[1] == ':'))
+    if (dlgCode & DLGC_WANTMESSAGE)
     {
-        drive = toupper( spec[0] ) - 'A';
-        spec += 2;
-        if (!DRIVE_SetCurrentDrive( drive )) return FALSE;
+        *translate = *dispatch = TRUE;
+        return TRUE;
     }
-    else drive = DRIVE_GetCurrentDrive();
 
-    /* If the path exists and is a directory, chdir to it */
-    if (!spec || !spec[0] || DRIVE_Chdir( drive, spec )) spec = "*.*";
-    else
+    switch(message)
     {
-        char *p, *p2;
-        p = spec;
-        if ((p2 = strrchr( p, '\\' ))) p = p2;
-        if ((p2 = strrchr( p, '/' ))) p = p2;
-        if (p != spec)
+    case WM_KEYDOWN:
+        switch(wParam)
         {
-            char sep = *p;
-            *p = 0;
-            if (!DRIVE_Chdir( drive, spec ))
+        case VK_TAB:
+            if (!(dlgCode & DLGC_WANTTAB))
             {
-                *p = sep;  /* Restore the original spec */
-                return FALSE;
+                SendMessageA( hwndDlg, WM_NEXTDLGCTL,
+                                (GetKeyState(VK_SHIFT) & 0x8000), 0 );
+                return TRUE;
             }
-            spec = p + 1;
-        }
-    }
+            break;
+            
+        case VK_RIGHT:
+        case VK_DOWN:
+        case VK_LEFT:
+        case VK_UP:
+            if (!(dlgCode & DLGC_WANTARROWS))
+            {
+                WINBOOL fPrevious = (wParam == VK_LEFT || wParam == VK_UP);
+                HWND hwndNext = 
+                    GetNextDlgGroupItem (hwndDlg, GetFocus(), fPrevious );
+                SendMessageA( hwndDlg, WM_NEXTDLGCTL, hwndNext, 1 );
+                return TRUE;
+            }
+            break;
 
-    TRACE(dialog, "path=%c:\\%s mask=%s\n",
-                    'A' + drive, DRIVE_GetDosCwd(drive), spec );
+        case VK_ESCAPE:
+            SendMessageA( hwndDlg, WM_COMMAND, IDCANCEL,
+                            (LPARAM)GetDlgItem( hwndDlg, IDCANCEL ) );
+            return TRUE;
 
-    if (idLBox && ((hwnd = GetDlgItem32( hDlg, idLBox )) != 0))
-    {
-        SENDMSG( combo ? CB_RESETCONTENT32 : LB_RESETCONTENT32, 0, 0 );
-        if (attrib & DDL_DIRECTORY)
-        {
-            if (!(attrib & DDL_EXCLUSIVE))
+        case VK_RETURN:
             {
-                if (SENDMSG( combo ? CB_DIR32 : LB_DIR32,
-                             attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
-                             (LPARAM)spec ) == LB_ERR)
-                    return FALSE;
+                DWORD dw = SendMessage( hwndDlg, DM_GETDEFID, 0, 0 );
+                if (HIWORD(dw) == DC_HASDEFID)
+                {
+                    SendMessageA( hwndDlg, WM_COMMAND, 
+                                    MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
+                                    (LPARAM)GetDlgItem(hwndDlg, LOWORD(dw)));
+                }
+                else
+                {
+                    SendMessageA( hwndDlg, WM_COMMAND, IDOK,
+                                    (LPARAM)GetDlgItem( hwndDlg, IDOK ) );
+    
+                }
             }
-            if (SENDMSG( combo ? CB_DIR32 : LB_DIR32,
-                       (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
-                         (LPARAM)"*.*" ) == LB_ERR)
-                return FALSE;
+            return TRUE;
         }
-        else
-        {
-            if (SENDMSG( combo ? CB_DIR32 : LB_DIR32, attrib,
-                         (LPARAM)spec ) == LB_ERR)
-                return FALSE;
-        }
-    }
+        *translate = TRUE;
+        break; /* case WM_KEYDOWN */
 
-    if (idStatic && ((hwnd = GetDlgItem32( hDlg, idStatic )) != 0))
-    {
-        char temp[512];
-        int drive = DRIVE_GetCurrentDrive();
-        strcpy( temp, "A:\\" );
-        temp[0] += drive;
-        lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
-        CharLower32A( temp );
-        /* Can't use PostMessage() here, because the string is on the stack */
-        SetDlgItemText32A( hDlg, idStatic, temp );
-    }
+    case WM_CHAR:
+        if (dlgCode & DLGC_WANTCHARS) break;
+        /* drop through */
 
-    if (orig_spec && (spec != orig_spec))
-    {
-        /* Update the original file spec */
-        char *p = spec;
-        while ((*orig_spec++ = *p++));
+    case WM_SYSCHAR:
+        if (DIALOG_IsAccelerator( hwnd, hwndDlg, wParam ))
+        {
+            /* don't translate or dispatch */
+            return TRUE;
+        }
+        break;
     }
 
+    /* If we get here, the message has not been treated specially */
+    /* and can be sent to its destination window. */
+    *dispatch = TRUE;
     return TRUE;
-#undef SENDMSG
 }
 
 
-/**********************************************************************
- *         DIALOG_DlgDirListW
- *
- * Helper function for DlgDirList*32W
- */
-static INT32 DIALOG_DlgDirListW( HWND32 hDlg, LPWSTR spec, INT32 idLBox,
-                                 INT32 idStatic, UINT32 attrib, WINBOOL combo )
-{
-    if (spec)
-    {
-        LPSTR specA = HEAP_strdupWtoA( GetProcessHeap(), 0, spec );
-        INT32 ret = DIALOG_DlgDirList( hDlg, specA, idLBox, idStatic,
-                                       attrib, combo );
-        lstrcpyAtoW( spec, specA );
-        HeapFree( GetProcessHeap(), 0, specA );
-        return ret;
-    }
-    return DIALOG_DlgDirList( hDlg, NULL, idLBox, idStatic, attrib, combo );
-}
-
 
index 9f0bf6c..86838c2 100644 (file)
@@ -72,6 +72,7 @@ int lpstrncpyA( LPSTR ptr1,LPSTR ptr2, int n)
                if ( ptr1[i] == 0 )
                        break;
        }
+       return i;
 }
 int lpstrncpyW( LPWSTR ptr1,LPWSTR ptr2, int n)
 {
@@ -81,6 +82,7 @@ int lpstrncpyW( LPWSTR ptr1,LPWSTR ptr2, int n)
                if ( ptr1[i] == 0 )
                        break;
        }
+       return i;
 }
 
 LPSTR HEAP_strdupA(HANDLE  hHeap,DWORD  dwFlags,LPCSTR ptr)
@@ -100,4 +102,14 @@ LPWSTR HEAP_strdupW(HANDLE  hHeap,DWORD  dwFlags,LPCWSTR ptr)
                lstrcpyW(lpszString,ptr);
         
         return lpszString;
+}
+
+int HEAP_memset( void *d,int c ,int count)
+{
+       return memset(d,c,count);
+}
+
+int HEAP_memcpy( void *d,void *s,int c)
+{
+       return memcpy(d,s,c);
 }
\ No newline at end of file
index 8c6c51c..ab0aefd 100644 (file)
@@ -1,15 +1,16 @@
-#undef WIN32_LEAN_AND_MEAN
+
 #include <windows.h>
 #include <user32/win.h>
-//#include <user32/debug.h>
+#include <user32/debug.h>
 #include <user32/resource.h>
 #include <user32/sysmetr.h>
+#include <user32/syscolor.h>
 #include <user32/menu.h>
 #include <user32/nc.h>
-#include <stdlib.h>
+#include <user32/heapdup.h>
 
 #include <wchar.h>
-#include <stdlib.h>
+//#include <stdlib.h>
 
 typedef struct tagMDINEXTMENU 
 {
@@ -48,9 +49,6 @@ UINT uSubPWndLevel = 0;
 WINBOOL fEndMenu = FALSE;
 
 
-#include<stdio.h>
-#define DPRINT printf
-
 
 /***********************************************************************
  *           debug_print_menuitem
@@ -684,7 +682,7 @@ void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
  *
  * Calculate the size of the menu bar.
  */
-static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
+void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
                                   LPPOPUPMENU lppop, HWND hwndOwner )
 {
     MENUITEM *lpitem;
@@ -1451,7 +1449,7 @@ WINBOOL MENU_PatchResidentPopup( HQUEUE checkQueue, WND* checkWnd )
     }
     menu->items = newItems;
     menu->nItems++;
-    memset( &newItems[pos], 0, sizeof(*newItems) );
+    HEAP_memset( &newItems[pos], 0, sizeof(*newItems) );
     return &newItems[pos];
 }
 
index bcb977a..31c0b36 100644 (file)
@@ -4,10 +4,10 @@
  * Copyright 1993, 1994 Alexandre Julliard
  */
 
-#include <stdlib.h>
+
 #include <string.h>
 #include <ctype.h>
-#include <sys/time.h>
+//#include <sys/time.h>
 #include <sys/types.h>
 #include <windows.h>
 #include <user32/msg.h>
@@ -16,6 +16,7 @@
 #include <user32/debug.h>
 #include <user32/winpos.h>
 #include <user32/queue.h>
+#include <user32/heapdup.h>
 
 
 
@@ -158,16 +159,16 @@ DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD filter,
 
     if (HOOK_IsHooked( WH_MOUSE ))
     { 
-       MOUSEHOOKSTRUCT *hook = malloc(sizeof(MOUSEHOOKSTRUCT));
+       MOUSEHOOKSTRUCT *hook = HeapAlloc(GetProcessHeap(),0,sizeof(MOUSEHOOKSTRUCT));
        if( hook )
        {
            hook->pt           = screen_pt;
            hook->hwnd         = hWnd;
            hook->wHitTestCode = hittest;
            hook->dwExtraInfo  = 0;
-           ret = HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
-                                   message, (LPARAM)(hook) );
-           free(hook);
+           ret = HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
+                                   message, (LPARAM)(hook), pWnd->class->bUnicode );
+           HeapFree(GetProcessHeap(),0,hook);
        }
        if( ret ) return MAKELONG((INT)SYSQ_MSG_SKIP, hittest);
     }
@@ -523,24 +524,47 @@ WINBOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, DWORD filter,
     return FALSE;
 }
 
+
 /***********************************************************************
  *           MSG_SendMessage
  *
  * Implementation of an inter-task SendMessage.
  */
-LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
-                                WPARAM wParam, LPARAM lParam, WORD flags )
+LRESULT MSG_SendMessageInterTask( HWND hwnd, UINT msg,
+                                WPARAM wParam, LPARAM lParam, WINBOOL bUnicode)
 {
+
+    WND *wndPtr;
+    WND **list, **ppWnd;
     INT          prevSMRL = debugSMRL;
     QSMCTRL      qCtrl = { 0, 1};
     MESSAGEQUEUE *queue, *destQ;
 
+    if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
+    {
+       if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
+               return TRUE;
+        for (ppWnd = list; *ppWnd; ppWnd++)
+        {
+            wndPtr = *ppWnd;
+            //if (!WIN_IsWindow(wndPtr)) 
+               //continue;
+            if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) 
+                MSG_SendMessageInterTask( wndPtr->hwndSelf, msg, wParam, lParam, bUnicode );
+        }
+       HeapFree( GetProcessHeap(), 0, list );
+        return TRUE;
+    }
+
+
+// should turn queue and destQ around
+    
     if (!(queue = (MESSAGEQUEUE*)GlobalLock( GetFastQueue() ))) return 0;
-    if (!(destQ = (MESSAGEQUEUE*)GlobalLock( hDestQueue ))) return 0;
+    if (!(destQ = (MESSAGEQUEUE*)GlobalLock( wndPtr->hmemTaskQ ))) return 0;
 
-    if (
+    //if (
        //IsTaskLocked() || 
-       !IsWindow(hwnd)) return 0;
+       //!IsWindow(hwnd)) return 0;
 
     debugSMRL+=4;
     DPRINT("%*sSM: %s [%04x] (%04x -> %04x)\n", 
@@ -552,6 +576,9 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
       QUEUE_WaitBits( QS_SMPARAMSFREE );
     }
 
+
+
+
     /* resume sending */ 
 
     queue->hWnd       = hwnd;
@@ -563,7 +590,7 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
     destQ->hSendingTask = GetFastQueue();
 
     QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE );
-    queue->flags = (queue->flags & ~(QUEUE_SM_ASCII|QUEUE_SM_UNICODE)) | flags;
+//    queue->flags = (queue->flags & ~(QUEUE_SM_ASCII|QUEUE_SM_UNICODE)) | flags;
 
     DPRINT("%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
 
@@ -610,6 +637,52 @@ LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
 WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
                                WORD flags, WINBOOL peek )
 {
+#if 0
+                       case MOUSE_EVENT:
+                               MouseEvent = &Buffer.Event;
+                               if ( MouseEvent->dwEventFlags == MOUSE_MOVED ) {
+                                       msg->hwnd    = hwnd;
+                                       msg->message = WM_MOUSEMOVE;
+                                       msg->wParam = MouseEvent->dwControlKeyState;
+                                       msg->lParam  = 
+                                       MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y);  
+                               }
+                               else if ( MouseEvent->dwEventFlags == DOUBLE_CLICK ) {
+                                       msg->hwnd    = hwnd;
+                                       msg->message = WM_MBUTTONDBLCLK;
+                                       msg->wParam = MouseEvent->dwControlKeyState;
+                                       msg->lParam  = 
+                                       MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y);
+
+                               }
+                               else {
+                                if (MouseEvent->dwButtonState ==  FROM_LEFT_1ST_BUTTON_PRESSED ) {
+                                       msg->hwnd    = hwnd;
+                                       msg->message = WM_MBUTTONDOWN ;
+                                       msg->wParam = MouseEvent->dwControlKeyState;
+                                       msg->lParam  = 
+                                       MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y);
+                                }
+                                else {
+                                       msg->hwnd    = hwnd;
+                                       msg->message = WM_MBUTTONUP ;
+                                       msg->wParam = MouseEvent->dwControlKeyState;
+                                       msg->lParam  = 
+                                       MAKELONG(MouseEvent->dwMousePosition.X,MouseEvent->dwMousePosition.Y);
+                                }
+                               }
+                               break;                          
+       #endif  
+
+
+msg->hwnd    = hwnd;
+msg->message = WM_MBUTTONDBLCLK;
+msg->wParam = 0;
+msg->lParam  = MAKELONG(200,200);                      
+
+return TRUE;
+
+#if 0  
     int pos, mask;
     MESSAGEQUEUE *msgQueue;
     HQUEUE hQueue;
@@ -769,6 +842,9 @@ WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
     }
     if (peek) return TRUE;
     else return (msg->message != WM_QUIT);
+
+ #endif
+
 }
 
 /***********************************************************************
@@ -1040,6 +1116,29 @@ WINBOOL MSG_DoTranslateMessage( UINT message, HWND hwnd,
 }
 
 
+LRESULT MSG_SendMessage(  WND *wndPtr, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    
+    LRESULT ret;   
+
+    if ( wndPtr == NULL )
+       return 0;
+
+  //  if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
+  //      return 0;  /* Don't send anything if the task is dying */
+
+    
+    
+    if ( wndPtr->class->bUnicode )
+       ret = CallWindowProcW( (WNDPROC)wndPtr->winproc,
+                                 wndPtr->hwndSelf, msg, wParam, lParam );
+    else
+       ret = CallWindowProcA( (WNDPROC)wndPtr->winproc,
+                                wndPtr->hwndSelf, msg, wParam, lParam );
+
+    return ret;
+}
+
 HTASK GetCurrentTask(void)
 {
     return (HTASK)-2;
@@ -1054,7 +1153,7 @@ HQUEUE  GetThreadQueue( DWORD thread )
 {
        if ( init == 0 ) {
                init = 1;
-               memset(&Queue,0,sizeof(MESSAGEQUEUE));
+               HEAP_memset(&Queue,0,sizeof(MESSAGEQUEUE));
        }
        return hThreadQ;
 }
index 25bda93..d63c977 100644 (file)
@@ -1,8 +1,11 @@
 #include <windows.h>
 #include <stdlib.h>
 #include <user32/nc.h>
+#include <user32/syscolor.h>
 #include <user32/debug.h>
 
+// GetBitmapDimensionEx in NC_DrawMaxButton95 returns TRUE on invalid bitmap
+
 static HBITMAP hbitmapClose = 0;
 static HBITMAP hbitmapCloseD = 0;
 static HBITMAP hbitmapMinimize = 0;
@@ -126,6 +129,7 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle)
 
     /* Decide if the window will be managed (see CreateWindowEx) */
     // Options.managed &&
+
     if (!( !(style & WS_CHILD) &&
           ((style & (WS_DLGFRAME | WS_THICKFRAME)) ||
            (exStyle & WS_EX_DLGMODALFRAME))))
@@ -136,10 +140,10 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle)
         {
             if (HAS_SIZEFRAME(style))
                 InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME );
-#if 0
+
             if (style & WS_BORDER)
                 InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER);
-#endif
+
         }
 
         if ((style & WS_CAPTION) == WS_CAPTION)
@@ -151,10 +155,12 @@ NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle)
         }
     } else {
 
-
+       if (HAS_SIZEFRAME(style))
+                InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME );
+#if 0
         if (style & WS_BORDER)
             InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER);
-
+#endif
 
         if ((style & WS_CAPTION) == WS_CAPTION)
         {
@@ -326,13 +332,13 @@ NC_GetInsideRect95 (HWND hwnd, RECT *rect)
           InflateRect( rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER );*/
     }
 
-    if (wndPtr->dwStyle & WS_CHILD) {
+//    if (wndPtr->dwStyle & WS_CHILD) {
        if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
            InflateRect(rect, -SYSMETRICS_CXEDGE, -SYSMETRICS_CYEDGE);
 
        if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
            InflateRect(rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER);
-    }
+  //  }
 
     return;
 }
@@ -827,13 +833,22 @@ static void  NC_DrawMaxButton95(
     WND *wndPtr = WIN_FindWndPtr( hwnd );
     SIZE  bmsz;
     HBITMAP  bm;
+    BITMAP bmp;
     HDC hdcMem;
 
-    if( !(wndPtr->flags & WIN_MANAGED) &&
+
+    if( !(wndPtr->flags & WIN_MANAGED) ) {
        GetBitmapDimensionEx((bm = IsZoomed(hwnd) ?
-                               (down ? hbitmapRestoreD : hbitmapRestore ) :
-                               (down ? hbitmapMaximizeD : hbitmapMaximize)),
-                              &bmsz)) {
+                       (down ? hbitmapRestoreD : hbitmapRestore ) :
+                       (down ? hbitmapMaximizeD : hbitmapMaximize)),
+                        &bmsz);
+
+       if ( bmsz.cx == 0 || bmsz.cy == 0 ) {
+               GetObject(bm, sizeof(BITMAP), &bmp);
+               bmsz.cx = bmp.bmWidth;
+               bmsz.cy = bmp.bmHeight;
+               DPRINT("WARN GetBitmapDimensionEx returned 0 size ");
+       }
 
        NC_GetInsideRect95( hwnd, &rect );
 
@@ -1169,7 +1184,7 @@ static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd,
  *
  *****************************************************************************/
 
-static void  NC_DrawCaption95(
+void  NC_DrawCaption95(
     HDC  hdc,
     RECT *rect,
     HWND hwnd,
@@ -1181,6 +1196,7 @@ static void  NC_DrawCaption95(
     WND     *wndPtr = WIN_FindWndPtr( hwnd );
     char    buffer[256];
     HPEN  hPrevPen;
+    int txt;
 
     if (wndPtr->flags & WIN_MANAGED) return;
 
@@ -1188,7 +1204,7 @@ static void  NC_DrawCaption95(
     MoveToEx( hdc, r.left, r.bottom - 1, NULL );
     LineTo( hdc, r.right, r.bottom - 1 );
     SelectObject( hdc, hPrevPen );
   r.bottom-2;
//   r.bottom - 2;
    
 
     FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
@@ -1221,8 +1237,14 @@ static void  NC_DrawCaption95(
        NC_DrawMinButton95( hwnd, hdc, FALSE );
        r.right -= SYSMETRICS_CXSIZE + 1;
     }
+   
+    if ( wndPtr->class->bUnicode )
+       txt = GetWindowTextW( hwnd, buffer, sizeof(buffer) );
+    else
+       txt = GetWindowTextA( hwnd, buffer, sizeof(buffer) );
+
 
-    if (GetWindowTextA( hwnd, buffer, sizeof(buffer) )) {
+    if (txt) {
        NONCLIENTMETRICS nclm;
        HFONT hFont, hOldFont;
        nclm.cbSize = sizeof(NONCLIENTMETRICS);
@@ -1236,7 +1258,11 @@ static void  NC_DrawCaption95(
        else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
        SetBkMode( hdc, TRANSPARENT );
        r.left += 2;
-       DrawTextA( hdc, buffer, -1, &r,
+       if ( wndPtr->class->bUnicode )
+               DrawTextW( hdc, buffer, -1, &r,
+                    DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
+       else
+               DrawTextA( hdc, buffer, -1, &r,
                     DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
        DeleteObject(SelectObject (hdc, hOldFont));
     }
@@ -1378,10 +1404,10 @@ void  NC_DoNCPaint95(
 
     if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW ))) return;
 
-    if (ExcludeVisRect( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left,
-                       wndPtr->rectClient.top-wndPtr->rectWindow.top,
-                       wndPtr->rectClient.right-wndPtr->rectWindow.left,
-                       wndPtr->rectClient.bottom-wndPtr->rectWindow.top )
+    if (ExcludeVisRect( hdc, wndPtr->rectClient.left -wndPtr->rectWindow.left,
+                       wndPtr->rectClient.top  -wndPtr->rectWindow.top,
+                       wndPtr->rectClient.right  -wndPtr->rectWindow.left,
+                       wndPtr->rectClient.bottom  -wndPtr->rectWindow.top )
        == NULLREGION)
     {
        ReleaseDC( hwnd, hdc );
@@ -1495,10 +1521,10 @@ LONG NC_HandleNCActivate( WND *wndPtr, WPARAM wParam )
 {
     WORD wStateChange;
 
-    if( wParam ) wStateChange = !(wndPtr->flags & WIN_NCACTIVATED);
-    else wStateChange = wndPtr->flags & WIN_NCACTIVATED;
+//    if( wParam ) wStateChange = !(wndPtr->flags & WIN_NCACTIVATED);
+//    else wStateChange = wndPtr->flags & WIN_NCACTIVATED;
 
-    if( wStateChange )
+//    if( wStateChange )
     {
        if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
        else wndPtr->flags &= ~WIN_NCACTIVATED;
index ac3a7d0..2cb97fb 100644 (file)
@@ -15,6 +15,7 @@
   /* Last CTLCOLOR id */
 //#define CTLCOLOR_MAX   CTLCOLOR_STATIC
 
+HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType );
 
 
 /***********************************************************************
@@ -45,28 +46,21 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
 
     if (!hwnd) hwnd = GetDesktopWindow();
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
+
+#ifdef OPTIMIZE
     if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
         return TRUE;  /* No redraw needed */
+#endif
 
     bIcon = (wndPtr->dwStyle & WS_MINIMIZE && wndPtr->class->hIcon);
-    if (rectUpdate)
-    {
-        DPRINT( "%04x %d,%d-%d,%d %04x flags=%04x\n",
-                    hwnd, rectUpdate->left, rectUpdate->top,
-                    rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags );
-    }
-    else
-    {
-        DPRINT( "%04x NULL %04x flags=%04x\n", hwnd, hrgnUpdate, flags);
-    }
-
     GetClientRect( hwnd, &rectClient );
 
     if (flags & RDW_INVALIDATE)  /* Invalidate */
     {
         int rgnNotEmpty = COMPLEXREGION;
 
-        if (wndPtr->hrgnUpdate > 1)  /* Is there already an update region? */
+        if (wndPtr->hrgnUpdate > (HRGN)1)  /* Is there already an update region? */
         {
             if ((hrgn = hrgnUpdate) == 0)
                 hrgn = CreateRectRgnIndirect( rectUpdate ? rectUpdate :
@@ -116,7 +110,7 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
     else if (flags & RDW_VALIDATE)  /* Validate */
     {
           /* We need an update region in order to validate anything */
-        if (wndPtr->hrgnUpdate > 1)
+        if (wndPtr->hrgnUpdate > (HRGN)1)
         {
             if (!hrgnUpdate && !rectUpdate)
             {
@@ -148,13 +142,13 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
 
     if (flags & RDW_INTERNALPAINT)
     {
-       if ( wndPtr->hrgnUpdate <= 1 && !(wndPtr->flags & WIN_INTERNAL_PAINT))
+       if ( wndPtr->hrgnUpdate <= (HRGN)1 && !(wndPtr->flags & WIN_INTERNAL_PAINT))
            QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
        wndPtr->flags |= WIN_INTERNAL_PAINT;        
     }
     else if (flags & RDW_NOINTERNALPAINT)
     {
-       if ( wndPtr->hrgnUpdate <= 1 && (wndPtr->flags & WIN_INTERNAL_PAINT))
+       if ( wndPtr->hrgnUpdate <= (HRGN)1 && (wndPtr->flags & WIN_INTERNAL_PAINT))
            QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
        wndPtr->flags &= ~WIN_INTERNAL_PAINT;
     }
@@ -168,10 +162,10 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
     }
     else if (flags & RDW_ERASENOW)
     {
-        if (wndPtr->flags & WIN_NEEDS_NCPAINT)
+        //if (wndPtr->flags & WIN_NEEDS_NCPAINT)
            WIN_UpdateNCArea( wndPtr, FALSE);
 
-        if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
+        //if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
         {
             HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate,
                                    DCX_INTERSECTRGN | DCX_USESTYLE |
@@ -249,3 +243,36 @@ WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
     return TRUE;
 }
 
+/***********************************************************************
+ *           GetControlBrush   Not A Win32 API
+ */
+HBRUSH GetControlBrush( HWND hwnd, HDC hdc, UINT ctlType )
+{
+    WND* wndPtr = WIN_FindWndPtr( hwnd );
+
+    if((ctlType <= CTLCOLOR_MAX) && wndPtr )
+    {
+       WND* parent;
+       if( wndPtr->dwStyle & WS_POPUP ) parent = wndPtr->owner;
+       else parent = wndPtr->parent;
+       if( !parent ) parent = wndPtr;
+       return (HBRUSH)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
+    }
+    return (HBRUSH)0;
+}
+
+/***********************************************************************
+ *          PAINT_GetControlBrush
+ */
+HBRUSH PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC hDC, UINT ctlType )
+{
+    LOGBRUSH LogBrush;
+    HBRUSH bkgBrush = (HBRUSH)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
+                                                            (WPARAM)hDC, (LPARAM)hWnd );
+    if( !GetObject(bkgBrush,sizeof(LOGBRUSH),&LogBrush) )
+       bkgBrush = DEFWND_ControlColor( hDC, ctlType );
+    return bkgBrush;
+}
+
+
+
index 1535433..a4e660a 100644 (file)
@@ -10,6 +10,7 @@
 #include <user32/scroll.h>
 #include <user32/msg.h>
 #include <user32/win.h>
+#include <user32/caret.h>
 #include <user32/debug.h>
 
 #define MAKEINTRESOURCEA(x) "x"
@@ -1065,4 +1066,33 @@ done:
     /* Return current position */
 
     return infoPtr->CurVal;
+}
+
+/*************************************************************************
+ *             SCROLL_FixCaret
+ */
+WINBOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags)
+{
+   HWND hCaret = CARET_GetHwnd();
+
+   if( hCaret )
+   {
+       RECT    rc;
+       CARET_GetRect( &rc );
+       if( hCaret == hWnd ||
+          (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
+       {
+           POINT     pt;
+
+           pt.x = rc.left; pt.y = rc.top;
+           MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
+           if( IntersectRect(lprc, lprc, &rc) )
+           {
+               HideCaret(0);
+              lprc->left = pt.x; lprc->top = pt.y;
+              return TRUE;
+           }
+       }
+   }
+   return FALSE;
 }
\ No newline at end of file
index ef53f5e..427de6f 100644 (file)
@@ -6,9 +6,9 @@
  */
 
 #include <windows.h>
+#include <user32/syscolor.h>
 #include <user32/debug.h>
 
-HPEN STDCALL GetSysColorPen( INT index );
 
 static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555,
                                        0xaaaa, 0x5555, 0xaaaa, 0x5555 };
@@ -18,11 +18,7 @@ static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555,
  * UITOOLS_DrawRectEdge()
  */
 
-/* DrawEdge() flags */
-#define BDR_RAISEDOUTER    0x0001
-#define BDR_SUNKENOUTER    0x0002
-#define BDR_RAISEDINNER    0x0004
-#define BDR_SUNKENINNER    0x0008
+
 
 #define BDR_OUTER          0x0003
 #define BDR_INNER          0x000c
index 904deba..191ef9d 100644 (file)
@@ -9,6 +9,8 @@
 #include <user32/dce.h>
 #include <user32/caret.h>
 #include <user32/debug.h>
+#include <user32/heapdup.h>
+#include <user32/dialog.h>
 
 WND *rootWnd;
 //////////////////////////////////////////////////////////////////////////////////
@@ -93,7 +95,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
                             ? MENU_GetSysMenu( hWnd, 0 ) : 0;
 
     if (classPtr->cbWndExtra) 
-       memset( wndPtr->wExtra, 0, classPtr->cbWndExtra);
+       HEAP_memset( wndPtr->wExtra, 0, classPtr->cbWndExtra);
 
 
     /* Call the WH_CBT hook */
@@ -107,7 +109,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
 
        cbtc.lpcs = cs;
        cbtc.hwndInsertAfter = hWndLinkAfter;
-        ret = HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hWnd, (LPARAM)&cbtc);
+        ret = HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (INT)hWnd, (LPARAM)&cbtc,  classPtr->bUnicode);
         if (ret)
        {
 
@@ -232,21 +234,14 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
     maxPos.x = wndPtr->rectWindow.left;
     maxPos.y = wndPtr->rectWindow.top;
 
-    if ( classPtr->bUnicode == TRUE ) {
-       if( SendMessageW( hWnd, WM_NCCREATE, 0, (LPARAM)cs) == 0)
-       {
-           /* Abort window creation */
-               WIN_DestroyWindow( wndPtr );
-               return NULL;
-       }
-    } else {
-       if( SendMessageA( hWnd, WM_NCCREATE, 0, (LPARAM)cs) == 0)
-       {
+
+    if( MSG_SendMessage( wndPtr, WM_NCCREATE, 0, (LPARAM)cs) == 0)
+    {
            /* Abort window creation */
-               WIN_DestroyWindow( wndPtr );
-               return NULL;
-       }
+       WIN_DestroyWindow( wndPtr );
+       return NULL;
     }
+   
        
     /* Insert the window in the linked list */
 
@@ -258,7 +253,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
                                           maxPos.y - wndPtr->rectWindow.top);
 
 
-    if( (SendMessageA( hWnd, WM_CREATE, 0, (LPARAM)cs )) == -1 )
+    if( (MSG_SendMessage( wndPtr, WM_CREATE, 0, (LPARAM)cs)) == -1 )
     {
        WIN_UnlinkWindow( hWnd );
        WIN_DestroyWindow( wndPtr );
@@ -272,12 +267,12 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
        if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
                    ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
                 
-         SendMessageA( hWnd, WM_SIZE, SIZE_RESTORED,
+         MSG_SendMessage( wndPtr, WM_SIZE, SIZE_RESTORED,
                                 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
                                          wndPtr->rectClient.bottom-wndPtr->rectClient.top));
-         SendMessageA( hWnd, WM_MOVE, 0,
+         MSG_SendMessage( wndPtr, WM_MOVE, 0,
                                 MAKELONG( wndPtr->rectClient.left,
-                                          wndPtr->rectClient.top ) );
+                                          wndPtr->rectClient.top) );
     }
 
             /* Show the window, maximizing or minimizing if needed */
@@ -299,7 +294,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
     {
                /* Notify the parent window only */
 
-               SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
+               MSG_SendMessage( wndPtr->parent, WM_PARENTNOTIFY,
                                MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hWnd );
                if( !IsWindow(hWnd) ) return 0;
     }
@@ -310,7 +305,7 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
             /* Call WH_SHELL hook */
 
     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
-                HOOK_CallHooksW( WH_SHELL, HSHELL_WINDOWCREATED, hWnd, 0L );
+                HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (INT)hWnd, 0L,  classPtr->bUnicode);
 
             
     return hWnd;
@@ -318,6 +313,12 @@ HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom)
 
 }
 
+WINBOOL WIN_IsWindow(HANDLE hWnd)
+{      
+        if (WIN_FindWndPtr( hWnd ) == NULL) return FALSE;
+       return TRUE;
+}
+
 /***********************************************************************
  *           WIN_FindWinToRepaint
  *
@@ -446,7 +447,7 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval )
         /* Special case for dialog window procedure */
         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
         {
-               retval = ptr;
+               retval = (LONG)ptr;
                *ptr = newval;
                return (LONG)retval;
         }
@@ -454,12 +455,12 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval )
     else switch(offset)
     {
        case GWL_ID:
-               ptr = (DWORD*)&wndPtr->wIDmenu;
+               ptr = (LONG*)&wndPtr->wIDmenu;
                break;
        case GWL_HINSTANCE:
-               return SetWindowWord( hwnd, offset, newval );
+               return (LONG)SetWindowWord( hwnd, offset, newval );
        case GWL_WNDPROC:
-               retval = wndPtr->winproc;
+               retval = (LONG)wndPtr->winproc;
                wndPtr->winproc = (WNDPROC)newval;
                return retval;
        case GWL_STYLE:
@@ -467,24 +468,22 @@ LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval )
                newval &= ~(WS_VISIBLE | WS_CHILD);     /* Some bits can't be changed this way */
                style.styleNew = newval | (style.styleOld & (WS_VISIBLE | WS_CHILD));
 
-               //if (wndPtr->flags & WIN_ISWIN32)
-                       SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
+               
+               MSG_SendMessage(wndPtr,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
                wndPtr->dwStyle = style.styleNew;
-               //if (wndPtr->flags & WIN_ISWIN32)
-                       SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
+               
+               MSG_SendMessage(wndPtr,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
                return style.styleOld;
                    
         case GWL_USERDATA: 
-               ptr = &wndPtr->userdata; 
+               ptr = (LONG *)&wndPtr->userdata; 
                break;
         case GWL_EXSTYLE:  
                style.styleOld = wndPtr->dwExStyle;
                style.styleNew = newval;
-               //if (wndPtr->flags & WIN_ISWIN32)
-                       SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
-               wndPtr->dwExStyle = newval;
-               //if (wndPtr->flags & WIN_ISWIN32)
-                       SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
+               MSG_SendMessage(wndPtr,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
+               wndPtr->dwExStyle = newval;             
+               MSG_SendMessage(wndPtr,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
                return style.styleOld;
 
        default:
@@ -511,19 +510,20 @@ WINBOOL WIN_DestroyWindow( WND* wndPtr )
     HWND hWnd;
     WND *pWnd;
 
+    if ( wndPtr == NULL )
+       return FALSE;
+
     hWnd = wndPtr->hwndSelf;
 
-#ifdef CONFIG_IPC
-    if (main_block)
-       DDE_DestroyWindow(wndPtr->hwndSelf);
-#endif  /* CONFIG_IPC */
+
        
     /* free child windows */
 
     while ((pWnd = wndPtr->child))
-        wndPtr->child = WIN_DestroyWindow( pWnd );
+        if ( !WIN_DestroyWindow( pWnd ) )
+               break;
 
-    SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
+    MSG_SendMessage( wndPtr, WM_NCDESTROY, 0, 0);
 
     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
 
@@ -570,9 +570,9 @@ WINBOOL WIN_DestroyWindow( WND* wndPtr )
     if (!(wndPtr->dwStyle & WS_CHILD))
        if (wndPtr->wIDmenu) DestroyMenu( (HMENU)wndPtr->wIDmenu );
     if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
-    //wndPtr->pDriver->pDestroyWindow( wndPtr );
+   
 
-    //DeleteDC(wndPtr->dc)    /* Always do this to catch orphaned DCs */ 
+  //  DeleteDC(wndPtr->dc)    /* Always do this to catch orphaned DCs */ 
 
     wndPtr->winproc = NULL;
     wndPtr->hwndSelf = NULL;
@@ -779,10 +779,7 @@ WINBOOL WIN_LinkWindow( HWND hWnd, HWND hWndInsertAfter )
 void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
 {
     POINT pt = {0, 0}; 
-    HRGN hClip = 1;
-
-    DPRINT("hwnd %04x, hrgnUpdate %04x\n", 
-                      wnd->hwndSelf, wnd->hrgnUpdate );
+    HRGN hClip = (HRGN)1;
 
     /* desktop window doesn't have nonclient area */
     if(wnd == WIN_GetDesktop()) 
@@ -791,7 +788,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
         return;
     }
 
-    if( wnd->hrgnUpdate > 1 )
+    if( wnd->hrgnUpdate > (HRGN)1 )
     {
        ClientToScreen(wnd->hwndSelf, &pt);
 
@@ -799,7 +796,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
         if (!CombineRgn( hClip, wnd->hrgnUpdate, 0, RGN_COPY ))
         {
             DeleteObject(hClip);
-            hClip = 1;
+            hClip = (HRGN)1;
         }
        else
            OffsetRgn( hClip, pt.x, pt.y );
@@ -815,7 +812,7 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
                                        hrgn, RGN_AND) == NULLREGION))
             {
                 DeleteObject( wnd->hrgnUpdate );
-                wnd->hrgnUpdate = 1;
+                wnd->hrgnUpdate = (HRGN)1;
             }
 
             DeleteObject( hrgn );
@@ -824,17 +821,19 @@ void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
 
     wnd->flags &= ~WIN_NEEDS_NCPAINT;
 
+#ifdef OPTIMIZE
     if ((wnd->hwndSelf == GetActiveWindow()) &&
         !(wnd->flags & WIN_NCACTIVATED))
     {
         wnd->flags |= WIN_NCACTIVATED;
-        if( hClip > 1) DeleteObject( hClip );
-        hClip = 1;
+        if( hClip > (HRGN)1) DeleteObject( hClip );
+        hClip = (HRGN)1;
     }
+#endif
 
-    if (hClip) SendMessage( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
+    if (hClip) MSG_SendMessage( wnd, WM_NCPAINT, (WPARAM)hClip, 0L );
 
-    if (hClip > 1) DeleteObject( hClip );
+    if (hClip > (HRGN)1) DeleteObject( hClip );
 }
 
 /***********************************************************************
@@ -888,9 +887,9 @@ void WIN_SendDestroyMsg( WND* pWnd )
     WIN_CheckFocus(pWnd);
 
     if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
-//    CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE ); 
+
   
-    SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
+    MSG_SendMessage( pWnd, WM_DESTROY, 0, 0);
 
     if( IsWindow(pWnd->hwndSelf) )
     {
@@ -907,6 +906,26 @@ void WIN_SendDestroyMsg( WND* pWnd )
 }
 
 
+/***********************************************************************
+ *           IsDialogMessage   (USER32.90)
+ */
+WINBOOL STDCALL WIN_IsDialogMessage( HWND hwndDlg, LPMSG msg )
+{
+
+    WINBOOL ret, translate, dispatch;
+    INT dlgCode;
+
+    if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd ))
+        return FALSE;
+
+    dlgCode = SendMessage( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
+    ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
+                                  msg->wParam, msg->lParam,
+                                  &translate, &dispatch, dlgCode );
+    if (translate) TranslateMessage( msg );
+    if (dispatch) DispatchMessage( msg );
+    return ret;
+}
 
 
 
index 1bfeeb5..3f0c10f 100644 (file)
@@ -1,25 +1,36 @@
 all: user32.exe
 
 INTERNAL_OBJECTS = internal/property.o internal/menu.o internal/heapdup.o internal/nc.o\
-               internal/scroll.o internal/win.o internal/dce.o internal/msg.o internal/queue.o\
+                internal/win.o internal/dce.o internal/msg.o internal/queue.o\
                internal/signal.o internal/event.o internal/timer.o internal/region.o\
-               internal/text.o internal/defwnd.o internal/paint.o internal/uitools.o
+               internal/text.o internal/defwnd.o internal/paint.o internal/uitools.o\
+               internal/dialog.o
 
 MISC_OBJECTS = misc/sprintf.o  misc/dllmain.o misc/string.o misc/sysmetr.o\
                misc/main.o misc/bitmap.o misc/cursor.o misc/vk.o
 
 
 WINDOWS_OBJECTS = windows/wndproc.o windows/win.o windows/hook.o windows/spy.o\
-               windows/queue.o windows/winpos.o windows/class.o windows/menu.o windows/dc.o\
+               windows/queue.o windows/winpos.o windows/class.o windows/dc.o\
                windows/timer.o windows/rect.o windows/msg.o windows/input.o windows/property.o\
-               windows/focus.o windows/paint.o
+               windows/focus.o windows/paint.o windows/msgbox.o windows/dialog.o\
+               windows/scroll.o windows/defdlg.o
 
 GRAPHICS_OBJECTS = graphics/rect.o graphics/caret.o graphics/text.o graphics/syscol.o graphics/fill.o\
                graphics/draw.o graphics/icon.o
 
-RESOURCE_OBJECTS = resources/sysres.o 
+CONTROLS_OBJECTS = controls/button.o controls/combo.o controls/edit.o controls/icontitle.o controls/listbox.o\
+               controls/widgets.o controls/menu.o controls/scroll.o controls/static.o
 
-OBJECTS = $(MISC_OBJECTS) $(INTERNAL_OBJECTS) $(GRAPHICS_OBJECTS) $(RESOURCE_OBJECTS) $(WINDOWS_OBJECTS)
+RESOURCE_OBJECTS = resources/sysres.o
+
+RESOURCE_OBJECT = user32.coff
+
+OBJECTS = $(MISC_OBJECTS) $(INTERNAL_OBJECTS) $(GRAPHICS_OBJECTS) $(RESOURCE_OBJECTS) $(RESOURCE_OBJECT)\
+       $(CONTROLS_OBJECTS) $(WINDOWS_OBJECTS)
+
+user32.coff: user32.rc ../../include/reactos/resource.h
+       windres user32.rc user32.coff
 
 user32.exe: $(OBJECTS)
        $(LD) $(OBJECTS)  F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/crt1.o ./libgdi32.a ./libkernel32.a ./libcrtdll.a   -o user32.exe
index 99fbed8..1473443 100644 (file)
@@ -84,3 +84,6 @@ HBITMAP BITMAP_LoadBitmapW(HINSTANCE instance,LPCWSTR name,
     return hbitmap;
 #endif
 }
+
+
+
index 33452c2..50b6bc0 100644 (file)
@@ -1,9 +1,12 @@
 #include <windows.h>
+#include <stdio.h>
+
 
 LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM, LPARAM);
 
 char szName[] = "Hallo";
 
+
 int _CRT_fmode = 0;
 int _CRT_glob = 0;
 
@@ -13,24 +16,34 @@ int __main(int argc, char **argv)
 }
 
 
+int i;
+
+
+
 int main(int argc, char **argv)
 {
+       WIDGETS_Init();
+#if 0
        HWND hwnd;
+       HWND User32hWnd;
        HMENU hmenu;
        MSG msg;
        WNDCLASSEX wc1;
        HINSTANCE hInst = 0;
        int nWinMode = SW_SHOW;
+        unsigned short *test;
 
-       RECT rect;
+        
+       HANDLE hMod, hrsrc;
+       RECT rect, cl;
 
        wc1.hInstance = hInst;
        wc1.lpszClassName = szName;
        wc1.lpfnWndProc = WindowFunc;
        wc1.style = 0;
        wc1.cbSize = sizeof(WNDCLASSEX);
-       wc1.hIcon = NULL;
-       wc1.hIconSm = NULL;
+       wc1.hIcon = LoadIcon(NULL,IDI_APPLICATION);
+       wc1.hIconSm = LoadIcon(NULL,IDI_WINLOGO);;
 
        wc1.hCursor = NULL;
        wc1.lpszMenuName = NULL;
@@ -38,21 +51,30 @@ int main(int argc, char **argv)
        wc1.cbClsExtra = 0;
        wc1.cbWndExtra = 0;
 
-       wc1.hbrBackground = NULL;
+       wc1.hbrBackground = GetStockObject(WHITE_BRUSH);
+
 
        if ( !RegisterClassEx(&wc1)) return 0;
 
-       hmenu = CreateMenu();
 
-       hwnd = CreateWindowEx(0, szName, "test", WS_OVERLAPPEDWINDOW,
+       hwnd = CreateWindowEx
+       (0, szName, "test2", WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
-               NULL,hmenu,hInst, NULL);
+               NULL,NULL,hInst, NULL);
+
+
+        MessageBox(NULL,"Hallo","Hallo",MB_OK);
 
-      
        ShowWindow(hwnd,nWinMode);
        UpdateWindow(hwnd);
+#endif
+       MessageBox(NULL,"xxx","yyyy",MB_OK);
+#if 0
+       GetWindowRect(hwnd,&rect);
+       GetClientRect(hwnd,&cl);
 
-       SetWindowText(hwnd,"Hallo");
+       printf("%d\n",(rect.left - rect.right) - (cl.left - cl.right));
+       SetWindowText(hwnd,"Hallo3");
 
        DrawMenuBar(hwnd);      
 //     SendMessage( hwnd, WM_MOVE, 0,MAKELONG(0,0));
@@ -64,10 +86,11 @@ int main(int argc, char **argv)
        }
        Sleep(10000);
        return msg.wParam;
+#endif
 }
 
 
-       //printf("hallo\n");
+       
        
        
 
index de94d60..61db5f3 100644 (file)
@@ -9,5 +9,7 @@
 LPCVOID SYSRES_GetResPtr( int id )
 {
 //    return SYSRES_Resources[Options.language][id]->data;
+
+
        return NULL;
 }
\ No newline at end of file
index 35761f3..d31d64f 100644 (file)
@@ -4,8 +4,8 @@
 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 
 VS_VERSION_INFO VERSIONINFO
-       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
-       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEVERSION     0,0,13,RES_UINT_FILE_VERSION
+       PRODUCTVERSION  0,0,13,0
        FILEFLAGSMASK   0x3fL
 #ifdef _DEBUG
        FILEFLAGS       0x1L
@@ -22,7 +22,7 @@ BEGIN
         BEGIN
             VALUE "CompanyName",       RES_STR_COMPANY_NAME
             VALUE "FileDescription",   "ReactOS User API Client Dll\0"
-            VALUE "FileVersion",       RES_STR_FILE_VERSION
+            VALUE "FileVersion",       "post 0.0.13\0"
             VALUE "InternalName",      "user32\0"
             VALUE "LegalCopyright",    RES_STR_LEGAL_COPYRIGHT
             VALUE "OriginalFilename",  "user32.dll\0"
@@ -36,3 +36,23 @@ BEGIN
     END
 END
 
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+MSGBOX DIALOG DISCARDABLE  100, 80, 216, 168
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_SYSMENU
+FONT 8, "MS Sans Serif"
+BEGIN
+        ICON "", 1088, 9, 20, 16, 16, WS_CHILD | WS_VISIBLE
+        LTEXT "", 100, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP
+        PUSHBUTTON "&OK", 1, 16, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Cancel", 2, 64, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Abort", 3, 112, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Retry", 4, 160, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Ignore", 5, 208, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&Yes", 6, 256, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+        PUSHBUTTON "&No", 7, 304, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
\ No newline at end of file
index d3ceefd..c0fc579 100644 (file)
@@ -1,10 +1,19 @@
-
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        lib/user32/windows/class.c
+ * PURPOSE:     Registers a window class
+ * PROGRAMER:   Boudewijn Dekker
+ * UPDATE HISTORY:
+ *              28/05/99: Created
+ */
 #include <windows.h>
 #include <user32/class.h>
 #include <user32/win.h>
 #include <user32/dce.h>
 #include <user32/heapdup.h>
 
+
 CLASS *rootClass;
 
 ATOM STDCALL RegisterClassA(const WNDCLASS* wc) 
@@ -80,7 +89,7 @@ ATOM STDCALL RegisterClassExA(const WNDCLASSEX* wc)
 
 
     if (classExtra) 
-       memset( classPtr->wExtra, 0, classExtra );
+       HEAP_memset( classPtr->wExtra, 0, classExtra );
 
     if (!classPtr) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -136,7 +145,7 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc )
     CLASS *classPtr;
     INT classExtra, winExtra;
 
-    int i, len;
+    int len;
     if ( wc == NULL || wc->cbSize != sizeof(WNDCLASSEX)) {
        SetLastError(ERROR_INVALID_DATA);
        return FALSE;
@@ -165,7 +174,7 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc )
 
 
     if (classExtra) 
-       memset( classPtr->wExtra, 0, classExtra );
+       HEAP_memset( classPtr->wExtra, 0, classExtra );
 
     if (!classPtr) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -189,13 +198,17 @@ ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc )
     classPtr->dce         = (wc->style & CS_CLASSDC) ?
                                  CreateDC( "DISPLAY", NULL,NULL,NULL ) : NULL;
 
-    len = lstrlenW((LPWSTR)wc->lpszMenuName);
-    classPtr->menuName = HeapAlloc(GetProcessHeap(),0,(len+1)*2);
-    lstrcpyW((LPWSTR)classPtr->menuName, (LPWSTR)wc->lpszMenuName);
+   if ( wc->lpszMenuName != NULL ) {
+       len = lstrlenW(wc->lpszMenuName);
+       classPtr->menuName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1));
+       lstrcpyW(classPtr->menuName,wc->lpszMenuName);
+    }
+    else
+       classPtr->menuName = NULL;
 
 
     len = lstrlenW((LPWSTR)wc->lpszClassName);
-    classPtr->className = HeapAlloc(GetProcessHeap(),0,(len+1)*2);
+    classPtr->className = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
     lstrcpyW((LPWSTR)classPtr->className,(LPWSTR) wc->lpszClassName );
 
     classPtr->next        = rootClass;
@@ -283,7 +296,7 @@ WINBOOL GetClassInfoExW( HINSTANCE  hInstance, LPCWSTR  lpClassName, LPWNDCLASSE
        if ( HIWORD(lpClassName) != 0 )
                a = FindAtomW(lpClassName);
        else
-               a = lpClassName;
+               a = (ATOM)lpClassName;
 
        classPtr = CLASS_FindClassByAtom(  a, hInstance );
        if ( classPtr == NULL )
@@ -408,7 +421,7 @@ WORD STDCALL GetClassWord( HWND hWnd, INT nIndex )
     if (nIndex >= 0)
     {
         if (nIndex <= wndPtr->class->cbClsExtra - sizeof(WORD))
-            return (WORD)((char *)wndPtr->class->wExtra) + nIndex;
+            return (WORD)(wndPtr->class->wExtra + nIndex);
     }
     else switch(nIndex)
     {
diff --git a/reactos/lib/user32/windows/defdlg.c b/reactos/lib/user32/windows/defdlg.c
new file mode 100644 (file)
index 0000000..46cbfe8
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Default dialog procedure
+ *
+ * Copyright 1993, 1996 Alexandre Julliard
+ *
+ */
+
+#include <windows.h>
+#include <user32/widgets.h>
+#include <user32/dialog.h>
+#include <user32/win.h>
+
+
+
+/***********************************************************************
+ *           DEFDLG_SetFocus
+ *
+ * Set the focus to a control of the dialog, selecting the text if
+ * the control is an edit dialog.
+ */
+static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
+{
+    HWND hwndPrev = GetFocus();
+
+    if (IsChild( hwndDlg, hwndPrev ))
+    {
+        if (SendMessage( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
+            SendMessage( hwndPrev, EM_SETSEL, TRUE, MAKELONG( -1, 0 ) );
+    }
+    if (SendMessage( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
+        SendMessage( hwndCtrl, EM_SETSEL, FALSE, MAKELONG( 0, -1 ) );
+    SetFocus( hwndCtrl );
+}
+
+
+/***********************************************************************
+ *           DEFDLG_SaveFocus
+ */
+static BOOL DEFDLG_SaveFocus( HWND hwnd, DIALOGINFO *infoPtr )
+{
+    HWND hwndFocus = GetFocus();
+
+    if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return FALSE;
+    infoPtr->hwndFocus = hwndFocus;
+      /* Remove default button */
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           DEFDLG_RestoreFocus
+ */
+static BOOL DEFDLG_RestoreFocus( HWND hwnd, DIALOGINFO *infoPtr )
+{
+    if (!infoPtr->hwndFocus || IsIconic(hwnd)) return FALSE;
+    if (!IsWindow( infoPtr->hwndFocus )) return FALSE;
+    DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
+    /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
+       sometimes losing focus when receiving WM_SETFOCUS messages. */
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           DEFDLG_FindDefButton
+ *
+ * Find the current default push-button.
+ */
+static HWND DEFDLG_FindDefButton( HWND hwndDlg )
+{
+    HWND hwndChild = GetWindow( hwndDlg, GW_CHILD );
+    while (hwndChild)
+    {
+        if (SendMessage( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
+            break;
+        hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
+    }
+    return hwndChild;
+}
+
+
+/***********************************************************************
+ *           DEFDLG_SetDefButton
+ *
+ * Set the new default button to be hwndNew.
+ */
+static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo,
+                                   HWND hwndNew )
+{
+    if (hwndNew &&
+        !(SendMessage(hwndNew, WM_GETDLGCODE, 0, 0 ) & DLGC_UNDEFPUSHBUTTON))
+        return FALSE;  /* Destination is not a push button */
+    
+    if (dlgInfo->idResult)  /* There's already a default pushbutton */
+    {
+        HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
+        if (SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
+            SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
+    }
+    if (hwndNew)
+    {
+        SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
+        dlgInfo->idResult = GetDlgCtrlID( hwndNew );
+    }
+    else dlgInfo->idResult = 0;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           DEFDLG_Proc
+ *
+ * Implementation of DefDlgProc(). Only handle messages that need special
+ * handling for dialogs.
+ */
+LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
+                            LPARAM lParam, DIALOGINFO *dlgInfo )
+{
+    switch(msg)
+    {
+        case WM_ERASEBKGND:
+           FillWindow( hwnd, hwnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG );
+           return 1;
+
+       case WM_NCDESTROY:
+
+             /* Free dialog heap (if created) */
+           if (dlgInfo->hDialogHeap)
+           {
+               GlobalUnlock(dlgInfo->hDialogHeap);
+               GlobalFree(dlgInfo->hDialogHeap);
+               dlgInfo->hDialogHeap = 0;
+           }
+
+             /* Delete font */
+           if (dlgInfo->hUserFont)
+           {
+               DeleteObject( dlgInfo->hUserFont );
+               dlgInfo->hUserFont = 0;
+           }
+
+             /* Delete menu */
+           if (dlgInfo->hMenu)
+           {           
+               DestroyMenu( dlgInfo->hMenu );
+               dlgInfo->hMenu = 0;
+           }
+
+            /* Delete window procedure */
+            //WINPROC_FreeProc( dlgInfo->dlgProc, WIN_PROC_WINDOW );
+            dlgInfo->dlgProc = NULL;
+            dlgInfo->flags |= DF_END;  /* just in case */
+
+             /* Window clean-up */
+           return DefWindowProcA( hwnd, msg, wParam, lParam );
+
+       case WM_SHOWWINDOW:
+           if (!wParam) DEFDLG_SaveFocus( hwnd, dlgInfo );
+           return DefWindowProcA( hwnd, msg, wParam, lParam );
+
+       case WM_ACTIVATE:
+           if (wParam) DEFDLG_RestoreFocus( hwnd, dlgInfo );
+           else DEFDLG_SaveFocus( hwnd, dlgInfo );
+           return 0;
+
+       case WM_SETFOCUS:
+           DEFDLG_RestoreFocus( hwnd, dlgInfo );
+           return 0;
+
+        case DM_SETDEFID:
+            if (dlgInfo->flags & DF_END) return 1;
+            DEFDLG_SetDefButton( hwnd, dlgInfo,
+                                 wParam ? GetDlgItem( hwnd, wParam ) : 0 );
+            return 1;
+
+        case DM_GETDEFID:
+            {
+                HWND hwndDefId;
+                if (dlgInfo->flags & DF_END) return 0;
+                if (dlgInfo->idResult)
+                    return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
+                if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
+                    return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
+            }
+           return 0;
+
+       case WM_NEXTDLGCTL:
+           {
+                HWND hwndDest = (HWND)wParam;
+                if (!lParam)
+                    hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
+                if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
+                DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
+            }
+            return 0;
+
+        case WM_ENTERMENULOOP:
+        case WM_LBUTTONDOWN:
+        case WM_NCLBUTTONDOWN:
+            {
+                HWND hwndFocus = GetFocus();
+                if (hwndFocus)
+                {
+                    WND *wnd = WIN_FindWndPtr( hwndFocus );
+
+                    if( wnd )
+                    {
+                        /* always make combo box hide its listbox control */
+
+                        if( WIDGETS_IsControl( wnd, BIC_COMBO ) )
+                            SendMessageA( hwndFocus, CB_SHOWDROPDOWN,
+                                            FALSE, 0 );
+                        else if( WIDGETS_IsControl( wnd, BIC_EDIT ) &&
+                                 WIDGETS_IsControl( wnd->parent,
+                                                      BIC_COMBO ))
+                            SendMessageA( wnd->parent->hwndSelf, 
+                                            CB_SHOWDROPDOWN, FALSE, 0 );
+                    }
+                }
+            }
+           return DefWindowProcA( hwnd, msg, wParam, lParam );
+
+       case WM_GETFONT: 
+           return dlgInfo->hUserFont;
+
+        case WM_CLOSE:
+            PostMessageA( hwnd, WM_COMMAND, IDCANCEL,
+                            (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
+            return 0;
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           DEFDLG_Epilog
+ */
+LRESULT DEFDLG_Epilog(DIALOGINFO* dlgInfo, UINT msg, BOOL fResult)
+{
+    /* see SDK 3.1 */
+
+    if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
+        msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
+         msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
+         msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
+        return fResult; 
+
+    return dlgInfo->msgResult;
+}
+
+
+
+
+/***********************************************************************
+ *           DefDlgProcA   (USER.120)
+ */
+LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg,
+                              WPARAM wParam, LPARAM lParam )
+{
+
+    DIALOGINFO * dlgInfo;
+    BOOL result = FALSE;
+    WND * wndPtr = WIN_FindWndPtr( hwnd );
+    
+    if (!wndPtr) return 0;
+    dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
+    dlgInfo->msgResult = 0;
+
+    if (dlgInfo->dlgProc) {      /* Call dialog procedure */
+        result = CallWindowProcA( (WNDPROC)dlgInfo->dlgProc,
+                                            hwnd, msg, wParam, lParam );
+
+        /* Check if window was destroyed by dialog procedure */
+        if (dlgInfo->flags & DF_END && !(dlgInfo->flags & DF_ENDING)) {
+            dlgInfo->flags |= DF_ENDING;
+            DestroyWindow( hwnd );
+        }
+    }
+
+    if (!result && IsWindow(hwnd))
+    {
+        /* callback didn't process this message */
+
+        switch(msg)
+        {
+            case WM_ERASEBKGND:
+            case WM_SHOWWINDOW:
+            case WM_ACTIVATE:
+            case WM_SETFOCUS:
+            case DM_SETDEFID:
+            case DM_GETDEFID:
+            case WM_NEXTDLGCTL:
+            case WM_GETFONT:
+            case WM_CLOSE:
+            case WM_NCDESTROY:
+            case WM_ENTERMENULOOP:
+            case WM_LBUTTONDOWN:
+            case WM_NCLBUTTONDOWN:
+                 return DEFDLG_Proc( (HWND)hwnd, msg,
+                                     (WPARAM)wParam, lParam, dlgInfo );
+            case WM_INITDIALOG:
+            case WM_VKEYTOITEM:
+            case WM_COMPAREITEM:
+            case WM_CHARTOITEM:
+                 break;
+
+            default:
+                 return DefWindowProcA( hwnd, msg, wParam, lParam );
+        }
+    }
+
+    return DEFDLG_Epilog(dlgInfo, msg, result);
+
+    
+}
+
+
+/***********************************************************************
+ *           DefDlgProcW   (USER.121)
+ */
+LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam,
+                              LPARAM lParam )
+{
+    DIALOGINFO * dlgInfo;
+    BOOL result = FALSE;
+    WND * wndPtr = WIN_FindWndPtr( hwnd );
+    
+    if (!wndPtr) return 0;
+    dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
+    dlgInfo->msgResult = 0;
+
+    if (dlgInfo->dlgProc) {      /* Call dialog procedure */
+        result = CallWindowProcW( (WNDPROC)dlgInfo->dlgProc,
+                                            hwnd, msg, wParam, lParam );
+        /* Check if window was destroyed by dialog procedure */
+        if (dlgInfo->flags & DF_END && !(dlgInfo->flags & DF_ENDING)) {
+            dlgInfo->flags |= DF_ENDING;
+            DestroyWindow( hwnd );
+        }
+    }
+
+    if (!result && IsWindow(hwnd))
+    {
+        /* callback didn't process this message */
+
+        switch(msg)
+        {
+            case WM_ERASEBKGND:
+            case WM_SHOWWINDOW:
+            case WM_ACTIVATE:
+            case WM_SETFOCUS:
+            case DM_SETDEFID:
+            case DM_GETDEFID:
+            case WM_NEXTDLGCTL:
+            case WM_GETFONT:
+            case WM_CLOSE:
+            case WM_NCDESTROY:
+            case WM_ENTERMENULOOP:
+            case WM_LBUTTONDOWN:
+            case WM_NCLBUTTONDOWN:
+                 return DEFDLG_Proc( (HWND)hwnd, msg,
+                                     (WPARAM)wParam, lParam, dlgInfo );
+            case WM_INITDIALOG:
+            case WM_VKEYTOITEM:
+            case WM_COMPAREITEM:
+            case WM_CHARTOITEM:
+                 break;
+
+            default:
+                 return DefWindowProcW( hwnd, msg, wParam, lParam );
+        }
+    }
+    return DEFDLG_Epilog(dlgInfo, msg, result);
+}
index 1cd4513..956deb0 100644 (file)
+#include <windows.h>
+#include <user32/win.h>
+#include <user32/dialog.h>
+#include <user32/debug.h>
 /***********************************************************************
- *           CreateDialog16   (USER.89)
+ *           CreateDialog   (USER32.89)
  */
-HWND16 WINAPI CreateDialog16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
-                              HWND16 owner, DLGPROC16 dlgProc )
+#undef CreateDialogA
+HWND STDCALL CreateDialogA( HINSTANCE hInst, LPCSTR dlgTemplate,
+                              HWND owner, DLGPROC dlgProc )
 {
-    return CreateDialogParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
+    return CreateDialogParamA( hInst, dlgTemplate, owner, dlgProc, 0 );
 }
 
-
 /***********************************************************************
- *           CreateDialogParam16   (USER.241)
+ *           CreateDialog   (USER32.89)
  */
-HWND16 WINAPI CreateDialogParam16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
-                                   HWND16 owner, DLGPROC16 dlgProc,
-                                   LPARAM param )
+
+#undef CreateDialogW
+HWND STDCALL CreateDialogW( HINSTANCE hInst, LPCWSTR dlgTemplate,
+                              HWND owner, DLGPROC dlgProc )
 {
-    HWND16 hwnd = 0;
-    HRSRC16 hRsrc;
-    HGLOBAL16 hmem;
-    LPCVOID data;
+    return CreateDialogParamW( hInst, dlgTemplate, owner, dlgProc, 0 );
+}
 
-    TRACE(dialog, "%04x,%08lx,%04x,%08lx,%ld\n",
-                   hInst, (DWORD)dlgTemplate, owner, (DWORD)dlgProc, param );
 
-    if (!(hRsrc = FindResource16( hInst, dlgTemplate, RT_DIALOG16 ))) return 0;
-    if (!(hmem = LoadResource16( hInst, hRsrc ))) return 0;
-    if (!(data = LockResource16( hmem ))) hwnd = 0;
-    else hwnd = CreateDialogIndirectParam16( hInst, data, owner,
-                                             dlgProc, param );
-    FreeResource16( hmem );
-    return hwnd;
-}
 
 /***********************************************************************
- *           CreateDialogParam32A   (USER32.73)
+ *           CreateDialogParamA   (USER32.73)
  */
-HWND32 WINAPI CreateDialogParam32A( HINSTANCE32 hInst, LPCSTR name,
-                                    HWND32 owner, DLGPROC32 dlgProc,
+HWND STDCALL CreateDialogParamA( HINSTANCE hInst, LPCSTR name,
+                                    HWND owner, DLGPROC dlgProc,
                                     LPARAM param )
 {
-    if (HIWORD(name))
-    {
-        LPWSTR str = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
-        HWND32 hwnd = CreateDialogParam32W( hInst, str, owner, dlgProc, param);
-        HeapFree( GetProcessHeap(), 0, str );
-        return hwnd;
-    }
-    return CreateDialogParam32W( hInst, (LPCWSTR)name, owner, dlgProc, param );
+    HANDLE hrsrc = FindResourceA( hInst, name, RT_DIALOG );
+    if (!hrsrc) return 0;
+    return CreateDialogIndirectParamA( hInst,
+                                         (LPVOID)LoadResource(hInst, hrsrc),
+                                         owner, dlgProc, param );
 }
 
 
 /***********************************************************************
- *           CreateDialogParam32W   (USER32.74)
+ *           CreateDialogParamW   (USER32.74)
  */
-HWND32 WINAPI CreateDialogParam32W( HINSTANCE32 hInst, LPCWSTR name,
-                                    HWND32 owner, DLGPROC32 dlgProc,
+HWND STDCALL CreateDialogParamW( HINSTANCE hInst, LPCWSTR name,
+                                    HWND owner, DLGPROC dlgProc,
                                     LPARAM param )
 {
-    HANDLE32 hrsrc = FindResource32W( hInst, name, RT_DIALOG32W );
+    HANDLE hrsrc = FindResourceW( hInst, name, (LPCWSTR)RT_DIALOG );
     if (!hrsrc) return 0;
-    return CreateDialogIndirectParam32W( hInst,
-                                         (LPVOID)LoadResource32(hInst, hrsrc),
+    return CreateDialogIndirectParamW( hInst,
+                                         (LPVOID)LoadResource(hInst, hrsrc),
                                          owner, dlgProc, param );
 }
 
 
 /***********************************************************************
- *           CreateDialogIndirect16   (USER.219)
+ *           CreateDialogIndirect   (USER32.219)
  */
-HWND16 WINAPI CreateDialogIndirect16( HINSTANCE16 hInst, LPCVOID dlgTemplate,
-                                      HWND16 owner, DLGPROC16 dlgProc )
+#undef CreateDialogIndirectA
+HWND STDCALL CreateDialogIndirectA( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate,
+                                      HWND owner, DLGPROC dlgProc )
 {
-    return CreateDialogIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0);
+    return CreateDialogIndirectParamA( hInst, dlgTemplate, owner, dlgProc, 0);
 }
 
-
 /***********************************************************************
- *           CreateDialogIndirectParam16   (USER.242)
+ *           CreateDialogIndirect   (USER32.219)
  */
-HWND16 WINAPI CreateDialogIndirectParam16( HINSTANCE16 hInst,
-                                           LPCVOID dlgTemplate,
-                                           HWND16 owner, DLGPROC16 dlgProc,
-                                           LPARAM param )
+#undef CreateDialogIndirectW
+HWND STDCALL CreateDialogIndirectW( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate,
+                                      HWND owner, DLGPROC dlgProc )
 {
-    return DIALOG_CreateIndirect( hInst, dlgTemplate, FALSE, owner,
-                                  dlgProc, param, WIN_PROC_16 );
+    return CreateDialogIndirectParamW( hInst, dlgTemplate, owner, dlgProc, 0);
 }
 
 
 /***********************************************************************
- *           CreateDialogIndirectParam32A   (USER32.69)
+ *           CreateDialogIndirectParamA   (USER32.69)
  */
-HWND32 WINAPI CreateDialogIndirectParam32A( HINSTANCE32 hInst,
-                                            LPCVOID dlgTemplate,
-                                            HWND32 owner, DLGPROC32 dlgProc,
+HWND STDCALL CreateDialogIndirectParamA( HINSTANCE hInst,
+                                            LPCDLGTEMPLATE dlgTemplate,
+                                            HWND owner, DLGPROC dlgProc,
                                             LPARAM param )
 {
-    return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
-                                  (DLGPROC16)dlgProc, param, WIN_PROC_32A );
+    return DIALOG_CreateIndirect( hInst, dlgTemplate,  owner,
+                                  (DLGPROC)dlgProc, param, FALSE );
 }
 
-/***********************************************************************
- *           CreateDialogIndirectParam32AorW   (USER32.71)
- */
-HWND32 WINAPI CreateDialogIndirectParam32AorW( HINSTANCE32 hInst,
-                                            LPCVOID dlgTemplate,
-                                            HWND32 owner, DLGPROC32 dlgProc,
-                                            LPARAM param )
-{   FIXME(dialog,"assume WIN_PROC_32W\n");
-    return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
-                                  (DLGPROC16)dlgProc, param, WIN_PROC_32W );
-}
 
 /***********************************************************************
- *           CreateDialogIndirectParam32W   (USER32.72)
+ *           CreateDialogIndirectParamW   (USER32.72)
  */
-HWND32 WINAPI CreateDialogIndirectParam32W( HINSTANCE32 hInst,
-                                            LPCVOID dlgTemplate,
-                                            HWND32 owner, DLGPROC32 dlgProc,
+HWND STDCALL CreateDialogIndirectParamW( HINSTANCE hInst,
+                                            LPCDLGTEMPLATE dlgTemplate,
+                                            HWND owner, DLGPROC dlgProc,
                                             LPARAM param )
 {
-    return DIALOG_CreateIndirect( hInst, dlgTemplate, TRUE, owner,
-                                  (DLGPROC16)dlgProc, param, WIN_PROC_32W );
+    return DIALOG_CreateIndirect( hInst, dlgTemplate, owner,
+                                  (DLGPROC)dlgProc, param, TRUE );
 }
 
 
 /***********************************************************************
- *           DIALOG_DoDialogBox
+ *           DialogBox   (USER32.87)
  */
-INT32 DIALOG_DoDialogBox( HWND32 hwnd, HWND32 owner )
-{
-    WND * wndPtr;
-    DIALOGINFO * dlgInfo;
-    MSG16 msg;
-    INT32 retval;
-
-      /* Owner must be a top-level window */
-    owner = WIN_GetTopParent( owner );
-    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
-    dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
-    EnableWindow32( owner, FALSE );
-    ShowWindow32( hwnd, SW_SHOW );
 
-    while (MSG_InternalGetMessage(&msg, hwnd, owner, MSGF_DIALOGBOX, PM_REMOVE,
-                                  !(wndPtr->dwStyle & DS_NOIDLEMSG) ))
-    {
-       if (!IsDialogMessage16( hwnd, &msg))
-       {
-           TranslateMessage16( &msg );
-           DispatchMessage16( &msg );
-       }
-       if (dlgInfo->flags & DF_END) break;
-    }
-    retval = dlgInfo->idResult;
-    EnableWindow32( owner, TRUE );
-    dlgInfo->flags |= DF_ENDING;   /* try to stop it being destroyed twice */
-    DestroyWindow32( hwnd );
-    return retval;
+#undef DialogBoxA
+INT STDCALL DialogBoxA( HINSTANCE hInst, LPCSTR dlgTemplate,
+                          HWND owner, DLGPROC dlgProc )
+{
+    return DialogBoxParamA( hInst, dlgTemplate, owner, dlgProc, 0 );
 }
 
-
 /***********************************************************************
- *           DialogBox16   (USER.87)
+ *           DialogBox   (USER32.87)
  */
-INT16 WINAPI DialogBox16( HINSTANCE16 hInst, SEGPTR dlgTemplate,
-                          HWND16 owner, DLGPROC16 dlgProc )
+#undef DialogBoxW
+INT STDCALL DialogBoxW( HINSTANCE hInst, LPCWSTR dlgTemplate,
+                          HWND owner, DLGPROC dlgProc )
 {
-    return DialogBoxParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
+    return DialogBoxParamW( hInst, dlgTemplate, owner, dlgProc, 0 );
 }
 
 
-/***********************************************************************
- *           DialogBoxParam16   (USER.239)
- */
-INT16 WINAPI DialogBoxParam16( HINSTANCE16 hInst, SEGPTR template,
-                               HWND16 owner, DLGPROC16 dlgProc, LPARAM param )
-{
-    HWND16 hwnd = CreateDialogParam16( hInst, template, owner, dlgProc, param);
-    if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
-    return -1;
-}
 
 
 /***********************************************************************
- *           DialogBoxParam32A   (USER32.139)
+ *           DialogBoxParamA   (USER32.139)
  */
-INT32 WINAPI DialogBoxParam32A( HINSTANCE32 hInst, LPCSTR name,
-                                HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
+INT STDCALL DialogBoxParamA( HINSTANCE hInst, LPCSTR name,
+                                HWND owner, DLGPROC dlgProc, LPARAM param )
 {
-    HWND32 hwnd = CreateDialogParam32A( hInst, name, owner, dlgProc, param );
+    HWND hwnd = CreateDialogParamA( hInst, name, owner, dlgProc, param );
     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
     return -1;
 }
 
 
 /***********************************************************************
- *           DialogBoxParam32W   (USER32.140)
+ *           DialogBoxParamW   (USER32.140)
  */
-INT32 WINAPI DialogBoxParam32W( HINSTANCE32 hInst, LPCWSTR name,
-                                HWND32 owner, DLGPROC32 dlgProc, LPARAM param )
+INT STDCALL DialogBoxParamW( HINSTANCE hInst, LPCWSTR name,
+                                HWND owner, DLGPROC dlgProc, LPARAM param )
 {
-    HWND32 hwnd = CreateDialogParam32W( hInst, name, owner, dlgProc, param );
+    HWND hwnd = CreateDialogParamW( hInst, name, owner, dlgProc, param );
     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
     return -1;
 }
 
 
 /***********************************************************************
- *           DialogBoxIndirect16   (USER.218)
+ *           DialogBoxIndirect   (USER32.218)
  */
-INT16 WINAPI DialogBoxIndirect16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
-                                  HWND16 owner, DLGPROC16 dlgProc )
+#undef DialogBoxIndirectA
+INT STDCALL DialogBoxIndirectA( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate,
+                                  HWND owner, DLGPROC dlgProc )
 {
-    return DialogBoxIndirectParam16( hInst, dlgTemplate, owner, dlgProc, 0 );
+    return DialogBoxIndirectParamA( hInst, dlgTemplate, owner, dlgProc, 0 );
 }
 
-
 /***********************************************************************
- *           DialogBoxIndirectParam16   (USER.240)
+ *           DialogBoxIndirect   (USER32.218)
  */
-INT16 WINAPI DialogBoxIndirectParam16( HINSTANCE16 hInst, HANDLE16 dlgTemplate,
-                                       HWND16 owner, DLGPROC16 dlgProc,
-                                       LPARAM param )
+#undef DialogBoxIndirectW
+INT STDCALL DialogBoxIndirectW( HINSTANCE hInst, LPCDLGTEMPLATE dlgTemplate,
+                                  HWND owner, DLGPROC dlgProc )
 {
-    HWND16 hwnd;
-    LPCVOID ptr;
-
-    if (!(ptr = GlobalLock16( dlgTemplate ))) return -1;
-    hwnd = CreateDialogIndirectParam16( hInst, ptr, owner, dlgProc, param );
-    GlobalUnlock16( dlgTemplate );
-    if (hwnd) return (INT16)DIALOG_DoDialogBox( hwnd, owner );
-    return -1;
+    return DialogBoxIndirectParam( hInst, dlgTemplate, owner, dlgProc, 0 );
 }
 
 
 /***********************************************************************
- *           DialogBoxIndirectParam32A   (USER32.136)
+ *           DialogBoxIndirectParamA   (USER32.136)
  */
-INT32 WINAPI DialogBoxIndirectParam32A(HINSTANCE32 hInstance, LPCVOID template,
-                                       HWND32 owner, DLGPROC32 dlgProc,
+INT STDCALL DialogBoxIndirectParamA(HINSTANCE hInstance, LPCDLGTEMPLATE template,
+                                       HWND owner, DLGPROC dlgProc,
                                        LPARAM param )
 {
-    HWND32 hwnd = CreateDialogIndirectParam32A( hInstance, template,
+    HWND hwnd = CreateDialogIndirectParamA( hInstance, template,
                                                 owner, dlgProc, param );
     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
     return -1;
@@ -249,13 +186,13 @@ INT32 WINAPI DialogBoxIndirectParam32A(HINSTANCE32 hInstance, LPCVOID template,
 
 
 /***********************************************************************
- *           DialogBoxIndirectParam32W   (USER32.138)
+ *           DialogBoxIndirectParamW   (USER32.138)
  */
-INT32 WINAPI DialogBoxIndirectParam32W(HINSTANCE32 hInstance, LPCVOID template,
-                                       HWND32 owner, DLGPROC32 dlgProc,
+INT STDCALL DialogBoxIndirectParamW(HINSTANCE hInstance, LPCDLGTEMPLATE template,
+                                       HWND owner, DLGPROC dlgProc,
                                        LPARAM param )
 {
-    HWND32 hwnd = CreateDialogIndirectParam32W( hInstance, template,
+    HWND hwnd = CreateDialogIndirectParamW( hInstance, template,
                                                 owner, dlgProc, param );
     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
     return -1;
@@ -263,23 +200,14 @@ INT32 WINAPI DialogBoxIndirectParam32W(HINSTANCE32 hInstance, LPCVOID template,
 
 
 /***********************************************************************
- *           EndDialog16   (USER32.173)
- */
-BOOL16 WINAPI EndDialog16( HWND16 hwnd, INT16 retval )
-{
-    return EndDialog32( hwnd, retval );
-}
-
-
-/***********************************************************************
- *           EndDialog32   (USER.88)
+ *           EndDialog   (USER32.88)
  */
-WINBOOL WINAPI EndDialog32( HWND32 hwnd, INT32 retval )
+WINBOOL STDCALL EndDialog( HWND hwnd, INT retval )
 {
     WND * wndPtr = WIN_FindWndPtr( hwnd );
     DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
 
-    TRACE(dialog, "%04x %d\n", hwnd, retval );
+    DPRINT( "%04x %d\n", hwnd, retval );
 
     if( dlgInfo )
     {
@@ -291,475 +219,153 @@ WINBOOL WINAPI EndDialog32( HWND32 hwnd, INT32 retval )
 
 
 /***********************************************************************
- *           DIALOG_IsAccelerator
- */
-static WINBOOL DIALOG_IsAccelerator( HWND32 hwnd, HWND32 hwndDlg, WPARAM32 vKey )
-{
-    HWND32 hwndControl = hwnd;
-    HWND32 hwndNext;
-    WND *wndPtr;
-    WINBOOL RetVal = FALSE;
-    INT32 dlgCode;
-
-    if (vKey == VK_SPACE)
-    {
-        dlgCode = SendMessage32A( hwndControl, WM_GETDLGCODE, 0, 0 );
-        if (dlgCode & DLGC_BUTTON)
-        {
-            SendMessage32A( hwndControl, WM_LBUTTONDOWN, 0, 0);
-            SendMessage32A( hwndControl, WM_LBUTTONUP, 0, 0);
-            RetVal = TRUE;
-        }
-    }
-    else
-    {
-        do
-        {
-            wndPtr = WIN_FindWndPtr( hwndControl );
-            if (wndPtr != NULL && wndPtr->text != NULL && 
-                    (wndPtr->dwStyle & (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)
-            {
-                dlgCode = SendMessage32A( hwndControl, WM_GETDLGCODE, 0, 0 );
-                if (dlgCode & (DLGC_BUTTON | DLGC_STATIC))
-                {
-                    /* find the accelerator key */
-                    LPSTR p = wndPtr->text - 2;
-                    do
-                    {
-                        p = strchr( p + 2, '&' );
-                    }
-                    while (p != NULL && p[1] == '&');
-
-                    /* and check if it's the one we're looking for */
-                    if (p != NULL && toupper( p[1] ) == toupper( vKey ) )
-                    {
-                        if ((dlgCode & DLGC_STATIC) || 
-                            (wndPtr->dwStyle & 0x0f) == BS_GROUPBOX )
-                        {
-                            /* set focus to the control */
-                            SendMessage32A( hwndDlg, WM_NEXTDLGCTL,
-                                    hwndControl, 1);
-                            /* and bump it on to next */
-                            SendMessage32A( hwndDlg, WM_NEXTDLGCTL, 0, 0);
-                        }
-                        else if (dlgCode & 
-                           (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))
-                        {
-                            /* send command message as from the control */
-                            SendMessage32A( hwndDlg, WM_COMMAND, 
-                                MAKEWPARAM( LOWORD(wndPtr->wIDmenu), 
-                                    BN_CLICKED ),
-                                (LPARAM)hwndControl );
-                        }
-                        else
-                        {
-                            /* click the control */
-                            SendMessage32A( hwndControl, WM_LBUTTONDOWN, 0, 0);
-                            SendMessage32A( hwndControl, WM_LBUTTONUP, 0, 0);
-                        }
-                        RetVal = TRUE;
-                        break;
-                    }
-                }
-            }
-           hwndNext = GetWindow32( hwndControl, GW_CHILD );
-           if (!hwndNext)
-           {
-               hwndNext = GetWindow32( hwndControl, GW_HWNDNEXT );
-           }
-           while (!hwndNext)
-           {
-               hwndControl = GetParent32( hwndControl );
-               if (hwndControl == hwndDlg)
-               {
-                   hwndNext = GetWindow32( hwndDlg, GW_CHILD );
-               }
-               else
-               {
-                   hwndNext = GetWindow32( hwndControl, GW_HWNDNEXT );
-               }
-           }
-            hwndControl = hwndNext;
-        }
-        while (hwndControl != hwnd);
-    }
-    return RetVal;
-}
-
-/***********************************************************************
- *           DIALOG_IsDialogMessage
- */
-static WINBOOL DIALOG_IsDialogMessage( HWND32 hwnd, HWND32 hwndDlg,
-                                      UINT32 message, WPARAM32 wParam,
-                                      LPARAM lParam, WINBOOL *translate,
-                                      WINBOOL *dispatch, INT32 dlgCode )
-{
-    *translate = *dispatch = FALSE;
-
-    if (message == WM_PAINT)
-    {
-        /* Apparently, we have to handle this one as well */
-        *dispatch = TRUE;
-        return TRUE;
-    }
-
-      /* Only the key messages get special processing */
-    if ((message != WM_KEYDOWN) &&
-        (message != WM_SYSCHAR) &&
-       (message != WM_CHAR))
-        return FALSE;
-
-    if (dlgCode & DLGC_WANTMESSAGE)
-    {
-        *translate = *dispatch = TRUE;
-        return TRUE;
-    }
-
-    switch(message)
-    {
-    case WM_KEYDOWN:
-        switch(wParam)
-        {
-        case VK_TAB:
-            if (!(dlgCode & DLGC_WANTTAB))
-            {
-                SendMessage32A( hwndDlg, WM_NEXTDLGCTL,
-                                (GetKeyState32(VK_SHIFT) & 0x8000), 0 );
-                return TRUE;
-            }
-            break;
-            
-        case VK_RIGHT:
-        case VK_DOWN:
-        case VK_LEFT:
-        case VK_UP:
-            if (!(dlgCode & DLGC_WANTARROWS))
-            {
-                WINBOOL fPrevious = (wParam == VK_LEFT || wParam == VK_UP);
-                HWND32 hwndNext = 
-                    GetNextDlgGroupItem32 (hwndDlg, GetFocus32(), fPrevious );
-                SendMessage32A( hwndDlg, WM_NEXTDLGCTL, hwndNext, 1 );
-                return TRUE;
-            }
-            break;
-
-        case VK_ESCAPE:
-            SendMessage32A( hwndDlg, WM_COMMAND, IDCANCEL,
-                            (LPARAM)GetDlgItem32( hwndDlg, IDCANCEL ) );
-            return TRUE;
-
-        case VK_RETURN:
-            {
-                DWORD dw = SendMessage16( hwndDlg, DM_GETDEFID, 0, 0 );
-                if (HIWORD(dw) == DC_HASDEFID)
-                {
-                    SendMessage32A( hwndDlg, WM_COMMAND, 
-                                    MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
-                                    (LPARAM)GetDlgItem32(hwndDlg, LOWORD(dw)));
-                }
-                else
-                {
-                    SendMessage32A( hwndDlg, WM_COMMAND, IDOK,
-                                    (LPARAM)GetDlgItem32( hwndDlg, IDOK ) );
-    
-                }
-            }
-            return TRUE;
-        }
-        *translate = TRUE;
-        break; /* case WM_KEYDOWN */
-
-    case WM_CHAR:
-        if (dlgCode & DLGC_WANTCHARS) break;
-        /* drop through */
-
-    case WM_SYSCHAR:
-        if (DIALOG_IsAccelerator( hwnd, hwndDlg, wParam ))
-        {
-            /* don't translate or dispatch */
-            return TRUE;
-        }
-        break;
-    }
-
-    /* If we get here, the message has not been treated specially */
-    /* and can be sent to its destination window. */
-    *dispatch = TRUE;
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           IsDialogMessage16   (USER.90)
+ *           IsDialogMessageA   (USER32.342)
  */
-BOOL16 WINAPI WIN16_IsDialogMessage16( HWND16 hwndDlg, SEGPTR msg16 )
+WINBOOL STDCALL IsDialogMessageA( HWND hwndDlg, LPMSG msg )
 {
-    LPMSG16 msg = PTR_SEG_TO_LIN(msg16);
     WINBOOL ret, translate, dispatch;
-    INT32 dlgCode;
+    INT dlgCode;
 
-    if ((hwndDlg != msg->hwnd) && !IsChild16( hwndDlg, msg->hwnd ))
+    if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd ))
         return FALSE;
 
-    dlgCode = SendMessage16( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg16);
+    dlgCode = SendMessageA( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
     ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
                                   msg->wParam, msg->lParam,
                                   &translate, &dispatch, dlgCode );
-    if (translate) TranslateMessage16( msg );
-    if (dispatch) DispatchMessage16( msg );
+    if (translate) TranslateMessage( msg );
+    if (dispatch) DispatchMessageA( msg );
     return ret;
 }
 
 
-BOOL16 WINAPI IsDialogMessage16( HWND16 hwndDlg, LPMSG16 msg )
-{
-    LPMSG16 msg16 = SEGPTR_NEW(MSG16);
-    WINBOOL ret;
-
-    *msg16 = *msg;
-    ret = WIN16_IsDialogMessage16( hwndDlg, SEGPTR_GET(msg16) );
-    SEGPTR_FREE(msg16);
-    return ret;
-}
-
 /***********************************************************************
- *           IsDialogMessage32A   (USER32.342)
+ *           IsDialogMessageW   (USER32.343)
  */
-WINBOOL WINAPI IsDialogMessage32A( HWND32 hwndDlg, LPMSG32 msg )
+WINBOOL STDCALL IsDialogMessageW( HWND hwndDlg, LPMSG msg )
 {
     WINBOOL ret, translate, dispatch;
-    INT32 dlgCode;
+    INT dlgCode;
 
-    if ((hwndDlg != msg->hwnd) && !IsChild32( hwndDlg, msg->hwnd ))
+    if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd ))
         return FALSE;
 
-    dlgCode = SendMessage32A( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
+    dlgCode = SendMessageW( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
     ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
                                   msg->wParam, msg->lParam,
                                   &translate, &dispatch, dlgCode );
-    if (translate) TranslateMessage32( msg );
-    if (dispatch) DispatchMessage32A( msg );
+    if (translate) TranslateMessage( msg );
+    if (dispatch) DispatchMessageW( msg );
     return ret;
 }
 
 
-/***********************************************************************
- *           IsDialogMessage32W   (USER32.343)
- */
-WINBOOL WINAPI IsDialogMessage32W( HWND32 hwndDlg, LPMSG32 msg )
-{
-    WINBOOL ret, translate, dispatch;
-    INT32 dlgCode;
-
-    if ((hwndDlg != msg->hwnd) && !IsChild32( hwndDlg, msg->hwnd ))
-        return FALSE;
-
-    dlgCode = SendMessage32W( msg->hwnd, WM_GETDLGCODE, 0, (LPARAM)msg);
-    ret = DIALOG_IsDialogMessage( msg->hwnd, hwndDlg, msg->message,
-                                  msg->wParam, msg->lParam,
-                                  &translate, &dispatch, dlgCode );
-    if (translate) TranslateMessage32( msg );
-    if (dispatch) DispatchMessage32W( msg );
-    return ret;
-}
-
-
-/****************************************************************
- *         GetDlgCtrlID16   (USER.277)
- */
-INT16 WINAPI GetDlgCtrlID16( HWND16 hwnd )
-{
-    WND *wndPtr = WIN_FindWndPtr(hwnd);
-    if (wndPtr) return wndPtr->wIDmenu;
-    else return 0;
-}
  
 
 /****************************************************************
- *         GetDlgCtrlID32   (USER32.234)
+ *         GetDlgCtrlID   (USER32.234)
  */
-INT32 WINAPI GetDlgCtrlID32( HWND32 hwnd )
+INT STDCALL GetDlgCtrlID( HWND hwnd )
 {
     WND *wndPtr = WIN_FindWndPtr(hwnd);
     if (wndPtr) return wndPtr->wIDmenu;
     else return 0;
 }
  
-
-/***********************************************************************
- *           GetDlgItem16   (USER.91)
- */
-HWND16 WINAPI GetDlgItem16( HWND16 hwndDlg, INT16 id )
-{
-    WND *pWnd;
-
-    if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
-    for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
-        if (pWnd->wIDmenu == (UINT16)id) return pWnd->hwndSelf;
-    return 0;
-}
-
-
-/***********************************************************************
- *           GetDlgItem32   (USER32.235)
- */
-HWND32 WINAPI GetDlgItem32( HWND32 hwndDlg, INT32 id )
+HWND STDCALL GetDlgItem(HWND  hDlg, int  nIDDlgItem )
 {
-    WND *pWnd;
-
-    if (!(pWnd = WIN_FindWndPtr( hwndDlg ))) return 0;
-    for (pWnd = pWnd->child; pWnd; pWnd = pWnd->next)
-        if (pWnd->wIDmenu == (UINT16)id) return pWnd->hwndSelf;
-    return 0;
 }
 
 
-/*******************************************************************
- *           SendDlgItemMessage16   (USER.101)
- */
-LRESULT WINAPI SendDlgItemMessage16( HWND16 hwnd, INT16 id, UINT16 msg,
-                                     WPARAM16 wParam, LPARAM lParam )
-{
-    HWND16 hwndCtrl = GetDlgItem16( hwnd, id );
-    if (hwndCtrl) return SendMessage16( hwndCtrl, msg, wParam, lParam );
-    else return 0;
-}
 
 
 /*******************************************************************
- *           SendDlgItemMessage32A   (USER32.452)
+ *           SendDlgItemMessageA   (USER32.452)
  */
-LRESULT WINAPI SendDlgItemMessage32A( HWND32 hwnd, INT32 id, UINT32 msg,
-                                      WPARAM32 wParam, LPARAM lParam )
+LRESULT STDCALL SendDlgItemMessageA( HWND hwnd, INT id, UINT msg,
+                                      WPARAM wParam, LPARAM lParam )
 {
-    HWND32 hwndCtrl = GetDlgItem32( hwnd, id );
-    if (hwndCtrl) return SendMessage32A( hwndCtrl, msg, wParam, lParam );
+    HWND hwndCtrl = GetDlgItem( hwnd, id );
+    if (hwndCtrl) return SendMessageA( hwndCtrl, msg, wParam, lParam );
     else return 0;
 }
 
 
 /*******************************************************************
- *           SendDlgItemMessage32W   (USER32.453)
+ *           SendDlgItemMessageW   (USER32.453)
  */
-LRESULT WINAPI SendDlgItemMessage32W( HWND32 hwnd, INT32 id, UINT32 msg,
-                                      WPARAM32 wParam, LPARAM lParam )
+LRESULT STDCALL SendDlgItemMessageW( HWND hwnd, INT id, UINT msg,
+                                      WPARAM wParam, LPARAM lParam )
 {
-    HWND32 hwndCtrl = GetDlgItem32( hwnd, id );
-    if (hwndCtrl) return SendMessage32W( hwndCtrl, msg, wParam, lParam );
+    HWND hwndCtrl = GetDlgItem( hwnd, id );
+    if (hwndCtrl) return SendMessageW( hwndCtrl, msg, wParam, lParam );
     else return 0;
 }
 
 
-/*******************************************************************
- *           SetDlgItemText16   (USER.92)
- */
-void WINAPI SetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR lpString )
-{
-    SendDlgItemMessage16( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
-}
-
 
 /*******************************************************************
- *           SetDlgItemText32A   (USER32.478)
+ *           SetDlgItemTextA   (USER32.478)
  */
-WINBOOL WINAPI SetDlgItemText32A( HWND32 hwnd, INT32 id, LPCSTR lpString )
+WINBOOL STDCALL SetDlgItemTextA( HWND hwnd, INT id, LPCSTR lpString )
 {
-    return SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
+    return SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
 }
 
 
 /*******************************************************************
- *           SetDlgItemText32W   (USER32.479)
+ *           SetDlgItemTextW   (USER32.479)
  */
-WINBOOL WINAPI SetDlgItemText32W( HWND32 hwnd, INT32 id, LPCWSTR lpString )
+WINBOOL STDCALL SetDlgItemTextW( HWND hwnd, INT id, LPCWSTR lpString )
 {
-    return SendDlgItemMessage32W( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
+    return SendDlgItemMessageW( hwnd, id, WM_SETTEXT, 0, (LPARAM)lpString );
 }
 
 
-/***********************************************************************
- *           GetDlgItemText16   (USER.93)
- */
-INT16 WINAPI GetDlgItemText16( HWND16 hwnd, INT16 id, SEGPTR str, UINT16 len )
-{
-    return (INT16)SendDlgItemMessage16( hwnd, id, WM_GETTEXT,
-                                        len, (LPARAM)str );
-}
 
 
 /***********************************************************************
- *           GetDlgItemText32A   (USER32.237)
+ *           GetDlgItemTextA   (USER32.237)
  */
-INT32 WINAPI GetDlgItemText32A( HWND32 hwnd, INT32 id, LPSTR str, UINT32 len )
+UINT STDCALL GetDlgItemTextA( HWND hwnd, INT id, LPSTR str, INT len )
 {
-    return (INT32)SendDlgItemMessage32A( hwnd, id, WM_GETTEXT,
+    return (UINT)SendDlgItemMessageA( hwnd, id, WM_GETTEXT,
                                          len, (LPARAM)str );
 }
 
 
 /***********************************************************************
- *           GetDlgItemText32W   (USER32.238)
+ *           GetDlgItemTextW   (USER32.238)
  */
-INT32 WINAPI GetDlgItemText32W( HWND32 hwnd, INT32 id, LPWSTR str, UINT32 len )
+UINT STDCALL GetDlgItemTextW( HWND hwnd, INT id, LPWSTR str, INT len )
 {
-    return (INT32)SendDlgItemMessage32W( hwnd, id, WM_GETTEXT,
+    return (UINT)SendDlgItemMessageW( hwnd, id, WM_GETTEXT,
                                          len, (LPARAM)str );
 }
 
 
-/*******************************************************************
- *           SetDlgItemInt16   (USER.94)
- */
-void WINAPI SetDlgItemInt16( HWND16 hwnd, INT16 id, UINT16 value, BOOL16 fSigned )
-{
-    return SetDlgItemInt32( hwnd, (UINT32)(UINT16)id, value, fSigned );
-}
 
 
 /*******************************************************************
- *           SetDlgItemInt32   (USER32.477)
+ *           SetDlgItemInt   (USER32.477)
  */
-void WINAPI SetDlgItemInt32( HWND32 hwnd, INT32 id, UINT32 value,
+WINBOOL STDCALL SetDlgItemInt( HWND hwnd, INT id, UINT value,
                              WINBOOL fSigned )
 {
     char str[20];
 
-    if (fSigned) sprintf( str, "%d", (INT32)value );
+    if (fSigned) sprintf( str, "%d", (INT)value );
     else sprintf( str, "%u", value );
-    SendDlgItemMessage32A( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
+    SendDlgItemMessageA( hwnd, id, WM_SETTEXT, 0, (LPARAM)str );
 }
 
 
-/***********************************************************************
- *           GetDlgItemInt16   (USER.95)
- */
-UINT16 WINAPI GetDlgItemInt16( HWND16 hwnd, INT16 id, BOOL16 *translated,
-                               BOOL16 fSigned )
-{
-    UINT32 result;
-    WINBOOL ok;
-
-    if (translated) *translated = FALSE;
-    result = GetDlgItemInt32( hwnd, (UINT32)(UINT16)id, &ok, fSigned );
-    if (!ok) return 0;
-    if (fSigned)
-    {
-        if (((INT32)result < -32767) || ((INT32)result > 32767)) return 0;
-    }
-    else
-    {
-        if (result > 65535) return 0;
-    }
-    if (translated) *translated = TRUE;
-    return (UINT16)result;
-}
 
 
 /***********************************************************************
- *           GetDlgItemInt32   (USER32.236)
+ *           GetDlgItemInt   (USER32.236)
  */
-UINT32 WINAPI GetDlgItemInt32( HWND32 hwnd, INT32 id, WINBOOL *translated,
+UINT STDCALL GetDlgItemInt( HWND hwnd, INT id, WINBOOL *translated,
                                WINBOOL fSigned )
 {
     char str[30];
@@ -767,81 +373,62 @@ UINT32 WINAPI GetDlgItemInt32( HWND32 hwnd, INT32 id, WINBOOL *translated,
     long result = 0;
     
     if (translated) *translated = FALSE;
-    if (!SendDlgItemMessage32A(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str))
+    if (!SendDlgItemMessageA(hwnd, id, WM_GETTEXT, sizeof(str), (LPARAM)str))
         return 0;
     if (fSigned)
     {
         result = strtol( str, &endptr, 10 );
         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
             return 0;
-        if (((result == LONG_MIN) || (result == LONG_MAX)) && (errno==ERANGE))
+        if (((result == LONG_MIN) || (result == LONG_MAX)) ) {
+               // errno == ERANGE
             return 0;
+       }
     }
     else
     {
         result = strtoul( str, &endptr, 10 );
         if (!endptr || (endptr == str))  /* Conversion was unsuccessful */
             return 0;
-        if ((result == ULONG_MAX) && (errno == ERANGE)) return 0;
+        if ((result == ULONG_MAX) ) {
+       //      && (errno == ERANGE)
+               return 0;
+       }
     }
     if (translated) *translated = TRUE;
-    return (UINT32)result;
+    return (UINT)result;
 }
 
 
 /***********************************************************************
- *           CheckDlgButton16   (USER.97)
+ *           CheckDlgButton   (USER32.97)
  */
-BOOL16 WINAPI CheckDlgButton16( HWND16 hwnd, INT16 id, UINT16 check )
+BOOL STDCALL CheckDlgButton( HWND hwnd, INT id, UINT check )
 {
-    SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 );
+    SendDlgItemMessageW( hwnd, id, BM_SETCHECK, check, 0 );
     return TRUE;
 }
 
 
-/***********************************************************************
- *           CheckDlgButton32   (USER32.45)
- */
-WINBOOL WINAPI CheckDlgButton32( HWND32 hwnd, INT32 id, UINT32 check )
-{
-    SendDlgItemMessage32A( hwnd, id, BM_SETCHECK32, check, 0 );
-    return TRUE;
-}
-
 
-/***********************************************************************
- *           IsDlgButtonChecked16   (USER.98)
- */
-UINT16 WINAPI IsDlgButtonChecked16( HWND16 hwnd, UINT16 id )
-{
-    return (UINT16)SendDlgItemMessage32A( hwnd, id, BM_GETCHECK32, 0, 0 );
-}
 
 
 /***********************************************************************
- *           IsDlgButtonChecked32   (USER32.344)
+ *           IsDlgButtonChecked   (USER32.98)
  */
-UINT32 WINAPI IsDlgButtonChecked32( HWND32 hwnd, UINT32 id )
+UINT STDCALL IsDlgButtonChecked( HWND hwnd, INT id )
 {
-    return (UINT32)SendDlgItemMessage32A( hwnd, id, BM_GETCHECK32, 0, 0 );
+    return (UINT)SendDlgItemMessageA( hwnd, id, BM_GETCHECK, 0, 0 );
 }
 
 
-/***********************************************************************
- *           CheckRadioButton16   (USER.96)
- */
-BOOL16 WINAPI CheckRadioButton16( HWND16 hwndDlg, UINT16 firstID,
-                                  UINT16 lastID, UINT16 checkID )
-{
-    return CheckRadioButton32( hwndDlg, firstID, lastID, checkID );
-}
 
 
 /***********************************************************************
- *           CheckRadioButton32   (USER32.48)
+ *           CheckRadioButton   (USER32.48)
  */
-WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID,
-                                  UINT32 lastID, UINT32 checkID )
+WINBOOL STDCALL CheckRadioButton( HWND hwndDlg, INT firstID,
+                                  INT lastID, INT checkID )
 {
     WND *pWnd = WIN_FindWndPtr( hwndDlg );
     if (!pWnd) return FALSE;
@@ -854,7 +441,7 @@ WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID,
         lastID = firstID;  /* Buttons are in reverse order */
     while (pWnd)
     {
-       SendMessage32A( pWnd->hwndSelf, BM_SETCHECK32,
+       SendMessageA( pWnd->hwndSelf, BM_SETCHECK,
                         (pWnd->wIDmenu == checkID), 0 );
         if (pWnd->wIDmenu == lastID) break;
        pWnd = pWnd->next;
@@ -864,60 +451,41 @@ WINBOOL WINAPI CheckRadioButton32( HWND32 hwndDlg, UINT32 firstID,
 
 
 /***********************************************************************
- *           GetDialogBaseUnits   (USER.243) (USER32.233)
+ *           GetDialogBaseUnits   (USER32.243) (USER32.233)
  */
-DWORD WINAPI GetDialogBaseUnits(void)
+LONG STDCALL GetDialogBaseUnits(void)
 {
     return MAKELONG( xBaseUnit, yBaseUnit );
 }
 
 
 /***********************************************************************
- *           MapDialogRect16   (USER.103)
+ *           MapDialogRect   (USER32.103)
  */
-void WINAPI MapDialogRect16( HWND16 hwnd, LPRECT16 rect )
+WINBOOL STDCALL MapDialogRect( HWND hwnd, LPRECT rect )
 {
     DIALOGINFO * dlgInfo;
     WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return;
+    if (!wndPtr) return FALSE;
     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
+    return TRUE;
 }
 
 
-/***********************************************************************
- *           MapDialogRect32   (USER32.382)
- */
-void WINAPI MapDialogRect32( HWND32 hwnd, LPRECT32 rect )
-{
-    DIALOGINFO * dlgInfo;
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return;
-    dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
-    rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
-    rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
-    rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
-    rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
-}
 
 
-/***********************************************************************
- *           GetNextDlgGroupItem16   (USER.227)
- */
-HWND16 WINAPI GetNextDlgGroupItem16( HWND16 hwndDlg, HWND16 hwndCtrl,
-                                     BOOL16 fPrevious )
-{
-    return (HWND16)GetNextDlgGroupItem32( hwndDlg, hwndCtrl, fPrevious );
-}
+
+
 
 
 /***********************************************************************
- *           GetNextDlgGroupItem32   (USER32.275)
+ *           GetNextDlgGroupItem   (USER32.275)
  */
-HWND32 WINAPI GetNextDlgGroupItem32( HWND32 hwndDlg, HWND32 hwndCtrl,
+HWND STDCALL GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl,
                                      WINBOOL fPrevious )
 {
     WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg;
@@ -965,20 +533,13 @@ HWND32 WINAPI GetNextDlgGroupItem32( HWND32 hwndDlg, HWND32 hwndCtrl,
 }
 
 
-/***********************************************************************
- *           GetNextDlgTabItem16   (USER.228)
- */
-HWND16 WINAPI GetNextDlgTabItem16( HWND16 hwndDlg, HWND16 hwndCtrl,
-                                   BOOL16 fPrevious )
-{
-    return (HWND16)GetNextDlgTabItem32( hwndDlg, hwndCtrl, fPrevious );
-}
+
 
 
 /***********************************************************************
- *           GetNextDlgTabItem32   (USER32.276)
+ *           GetNextDlgTabItem   (USER32.276)
  */
-HWND32 WINAPI GetNextDlgTabItem32( HWND32 hwndDlg, HWND32 hwndCtrl,
+HWND STDCALL GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl,
                                    WINBOOL fPrevious )
 {
     WND *pWnd, *pWndLast, *pWndCtrl, *pWndDlg;
index 9606a49..7e22666 100644 (file)
@@ -287,12 +287,12 @@ LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code,
                               WPARAM wParam, LPARAM lParam )
 {
    // MESSAGEQUEUE *queue;
-    HANDLE prevHook;
+    //HANDLE prevHook;
     HOOKDATA *data = (HOOKDATA *)(hook);
     LRESULT ret;
 
-    WPARAM wParamOrig = wParam;
-    LPARAM lParamOrig = lParam;
+    //WPARAM wParamOrig = wParam;
+    //LPARAM lParamOrig = lParam;
    // HOOK_MapFunc MapFunc;
    // HOOK_UnMapFunc UnMapFunc;
 
@@ -337,7 +337,16 @@ WINBOOL HOOK_IsHooked( INT id )
     return HOOK_GetHook( id, GetThreadQueue(0) ) != 0;
 }
 
+LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wParam,
+                           LPARAM lParam ,WINBOOL bUnicode)
+{
+       if ( bUnicode == TRUE )
+               return HOOK_CallHooksW( id, code, wParam,lParam );
+       else
+               return HOOK_CallHooksA( id, code, wParam,lParam );
 
+       return 0;
+}
 
 /***********************************************************************
  *           HOOK_CallHooksA
index 8dd616a..56d52d2 100644 (file)
@@ -251,27 +251,13 @@ WINBOOL STDCALL PostMessageW( HWND hwnd, UINT message, WPARAM wParam,
 LRESULT STDCALL SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
                                LPARAM lParam )
 {
-    WND * wndPtr;
-    WND **list, **ppWnd;
-    LRESULT ret;
+    WND *wndPtr;
 
     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
     {
-        if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
-            return TRUE;
-        for (ppWnd = list; *ppWnd; ppWnd++)
-        {
-            wndPtr = *ppWnd;
-            if (!IsWindow(wndPtr->hwndSelf)) continue;
-            if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
-                SendMessageA( wndPtr->hwndSelf, msg, wParam, lParam );
-        }
-       HeapFree( GetProcessHeap(), 0, list );
-        return TRUE;
+       return MSG_SendMessageInterTask(hwnd,msg,wParam,lParam,FALSE);
     }
 
-    if (HOOK_IsHooked( WH_CALLWNDPROC ))
-       MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
 
     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
     {
@@ -279,73 +265,37 @@ LRESULT STDCALL SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
         return 0;
     }
 
-    if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
-        return 0;  /* Don't send anything if the task is dying */
-
-    SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
-
-    if (wndPtr->hmemTaskQ != GetFastQueue())
-        ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
-                               QUEUE_SM_ASCII );
-    else
-        ret = CallWindowProcA( (WNDPROC)wndPtr->winproc,
-                                 hwnd, msg, wParam, lParam );
+    if (HOOK_IsHooked( WH_CALLWNDPROC ))
+       MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
 
-    SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
-    return ret;
+  
+    return MSG_SendMessage(wndPtr,msg,wParam,lParam,FALSE);
 }
 
 
 
-LRESULT STDCALL SendMessageW( 
-  HWND hwnd,    /* Window to send message to. If HWND_BROADCAST, 
-                 the message will be sent to all top-level windows. */
-
-  UINT msg,      /* message */
-  WPARAM wParam, /* message parameter */
-  LPARAM lParam    /* additional message parameter */
-) {
-    WND * wndPtr;
-    WND **list, **ppWnd;
-    LRESULT ret;
+LRESULT STDCALL SendMessageW(  HWND hwnd,  UINT msg,  WPARAM wParam, 
+       LPARAM lParam   ) 
+{
+    WND *wndPtr;
 
     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
     {
-        if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
-            return TRUE;
-        for (ppWnd = list; *ppWnd; ppWnd++)
-        {
-            wndPtr = *ppWnd;
-            if (!IsWindow(wndPtr->hwndSelf)) continue;
-            if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
-                SendMessageW( wndPtr->hwndSelf, msg, wParam, lParam );
-        }
-       HeapFree( GetProcessHeap(), 0, list );
-        return TRUE;
+       return MSG_SendMessageInterTask(hwnd,msg,wParam,lParam,TRUE);
     }
 
-    if (HOOK_IsHooked( WH_CALLWNDPROC ))
-        MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
 
     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
     {
         DPRINT( "invalid hwnd %08x\n", hwnd );
         return 0;
     }
-    if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
-        return 0;  /* Don't send anything if the task is dying */
-
-    SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
 
-    if (wndPtr->hmemTaskQ != GetFastQueue())
-        ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
-                                QUEUE_SM_ASCII | QUEUE_SM_UNICODE );
-    else
-        ret = CallWindowProcW( (WNDPROC)wndPtr->winproc,
-                                 hwnd, msg, wParam, lParam );
+    if (HOOK_IsHooked( WH_CALLWNDPROC ))
+       MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
 
-    SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
-    return ret;
+  
+    return MSG_SendMessage(wndPtr,msg,wParam,lParam,TRUE);
 }
 
 /***********************************************************************
index 3a752ed..9486541 100644 (file)
@@ -1,6 +1,7 @@
 #define UNICODE
 #include <windows.h>
 #include <user32/win.h>
+#include <user32/nc.h>
 #include <user32/resource.h>
 
 
@@ -9,8 +10,12 @@
 #define MB_DEFMASK             0x00000F00
 
 LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
-                                        WPARAM wParam, LPARAM lParam );
+                                        WPARAM wParam, LPARAM lParam, WINBOOL bUnicode );
 
+LRESULT CALLBACK MSGBOX_DlgProcA( HWND hwnd, UINT message,
+                                        WPARAM wParam, LPARAM lParam );
+LRESULT CALLBACK MSGBOX_DlgProcW( HWND hwnd, UINT message,
+                                        WPARAM wParam, LPARAM lParam );
 
 // FIXME ?????????
     /* Static text */
@@ -47,7 +52,8 @@ INT STDCALL MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title,
                               UINT type, WORD langid )
 {
     MSGBOXPARAMS mbox;
-   
+    HANDLE hrsrc;
+    HANDLE hDlgTemplate;
     if (title == NULL)
        title="Error";
     if (text == NULL)
@@ -56,9 +62,13 @@ INT STDCALL MessageBoxExA( HWND hWnd, LPCSTR text, LPCSTR title,
     mbox.lpszCaption = title;
     mbox.lpszText  = text;
     mbox.dwStyle  = type;
-    return DialogBoxIndirectParamA( WIN_GetWindowInstance(hWnd),
-                                      SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
-                                      hWnd, MSGBOX_DlgProc, (LPARAM)&mbox );
+
+    hrsrc = FindResourceA( NULL, "MSGBOX", RT_DIALOG );
+    if (!hrsrc) return 0;
+   
+    hDlgTemplate = LockResource(LoadResource(NULL,hrsrc));
+    return DialogBoxIndirectParamA( NULL, hDlgTemplate,
+                                      hWnd, MSGBOX_DlgProcA, (LPARAM)&mbox );
 }
 
 /**************************************************************************
@@ -68,7 +78,8 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
                               UINT type, WORD langid )
 {
     MSGBOXPARAMS mbox;
-   
+    HANDLE hrsrc;
+    HANDLE hDlgTemplate;   
     if (title == NULL)
        title=L"Error";
     if (text == NULL)
@@ -77,9 +88,14 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
     mbox.lpszCaption = title;
     mbox.lpszText  = text;
     mbox.dwStyle  = type;
-    return DialogBoxIndirectParamW( WIN_GetWindowInstance(hWnd),
-                                      SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
-                                      hWnd, MSGBOX_DlgProc, (LPARAM)&mbox );
+
+    hrsrc = FindResourceW( NULL, L"MSGBOX", RT_DIALOG );
+    if (!hrsrc) return 0;
+
+    hDlgTemplate = LockResource(LoadResource(NULL,hrsrc));
+    return DialogBoxIndirectParamW( NULL,
+                                      hDlgTemplate,
+                                      hWnd, MSGBOX_DlgProcW, (LPARAM)&mbox );
 }
 
 
@@ -89,10 +105,13 @@ INT STDCALL MessageBoxExW( HWND hWnd, LPCWSTR text, LPCWSTR title,
  */
 INT STDCALL MessageBoxIndirectA( LPMSGBOXPARAMS msgbox )
 {
-     
+    HANDLE hrsrc = FindResourceA( NULL, "MSGBOX", RT_DIALOG );
+    HANDLE hDlgTemplate;
+    if (!hrsrc) return 0;
+    hDlgTemplate = LockResource(LoadResource(NULL,hrsrc));
     return DialogBoxIndirectParamA( msgbox->hInstance,
-                                     SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
-                                      msgbox->hwndOwner, MSGBOX_DlgProc,
+                                     hDlgTemplate,
+                                      msgbox->hwndOwner, MSGBOX_DlgProcA,
                                      (LPARAM)msgbox );
 }
 
@@ -102,9 +121,13 @@ INT STDCALL MessageBoxIndirectA( LPMSGBOXPARAMS msgbox )
 INT STDCALL MessageBoxIndirectW( LPMSGBOXPARAMS msgbox )
 {
 
+    HANDLE hrsrc = FindResourceW( NULL, L"MSGBOX", RT_DIALOG );
+    HANDLE hDlgTemplate;
+    if (!hrsrc) return 0;
+    hDlgTemplate = LockResource(LoadResource(NULL,hrsrc));
     return DialogBoxIndirectParamW( msgbox->hInstance,
-                                     SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
-                                      msgbox->hwndOwner, MSGBOX_DlgProc,
+                                     hDlgTemplate,
+                                      msgbox->hwndOwner, MSGBOX_DlgProcW,
                                      (LPARAM)msgbox );
 }
 
@@ -113,8 +136,19 @@ INT STDCALL MessageBoxIndirectW( LPMSGBOXPARAMS msgbox )
  *
  * Dialog procedure for message boxes.
  */
-LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
+LRESULT CALLBACK MSGBOX_DlgProcA( HWND hwnd, UINT message,
                                         WPARAM wParam, LPARAM lParam )
+{
+       return MSGBOX_DlgProc(hwnd,message,wParam,lParam,FALSE); 
+}
+
+LRESULT CALLBACK MSGBOX_DlgProcW( HWND hwnd, UINT message,
+                                        WPARAM wParam, LPARAM lParam )
+{
+       return MSGBOX_DlgProc(hwnd,message,wParam,lParam,TRUE); 
+}
+
+LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam, WINBOOL bUnicode )
 {
   static HFONT hFont = 0;
   LPMSGBOXPARAMS lpmb;
@@ -126,144 +160,162 @@ LRESULT CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message,
   int i, buttons, bwidth, bheight, theight, wwidth, bpos;
   int borheight, iheight, tiheight;
 
-  NONCLIENTMETRICS nclm;
   
   switch(message) {
    case WM_INITDIALOG:
        lpmb = (LPMSGBOXPARAMS)lParam;
  
-       nclm.cbSize = sizeof(NONCLIENTMETRICS);
-       SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
-       hFont = CreateFontIndirect(&nclm.lfMessageFont);
-        /* set button font */
-       for (i=1; i < 8; i++)
-           SendDlgItemMessageW (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
-        /* set text font */
-       SendDlgItemMessageW (hwnd, 100, WM_SETFONT, (WPARAM)hFont, 0);
+        if (TWEAK_WineLook >= WIN95_LOOK) {
+               NONCLIENTMETRICS nclm;
+               INT i;
+               nclm.cbSize = sizeof(NONCLIENTMETRICS);
+               SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
+               hFont = CreateFontIndirect (&nclm.lfMessageFont);
+               /* set button font */
+               for (i=1; i < 8; i++)
+                       SendDlgItemMessage (hwnd, i, WM_SETFONT, (WPARAM)hFont, 0);
+                       /* set text font */
+               SendDlgItemMessage (hwnd, 100, WM_SETFONT, (WPARAM)hFont, 0);
+       }
+
+       
+
  
-       if (lpmb->lpszCaption) 
-               SetWindowTextW(hwnd, lpmb->lpszCaption);
-       SetWindowTextW(GetDlgItem(hwnd, 100), lpmb->lpszText);
+       if ( bUnicode == TRUE ) {
+               if (lpmb->lpszCaption) 
+                       SetWindowTextW(hwnd, (LPCWSTR)lpmb->lpszCaption);       
+               SetWindowTextW(GetDlgItem(hwnd, 100),(LPWSTR) lpmb->lpszText);
+       } else {
+               if (lpmb->lpszCaption) 
+                       SetWindowTextA(hwnd, lpmb->lpszCaption);        
+               SetWindowTextA(GetDlgItem(hwnd, 100), lpmb->lpszText);
+       }
     /* Hide not selected buttons */
        switch(lpmb->dwStyle & MB_TYPEMASK) {
-     case MB_OK:
-        ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
-      /* fall through */
-     case MB_OKCANCEL:
-       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
-      break;
-     case MB_ABORTRETRYIGNORE:
-       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
-      break;
-     case MB_YESNO:
-       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
-      /* fall through */
-     case MB_YESNOCANCEL:
-       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
-       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
-      break;
-    }
-    /* Set the icon */
-    switch(lpmb->dwStyle & MB_ICONMASK) {
-     case MB_ICONEXCLAMATION:
-       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
-                           (WPARAM)LoadIcon(0, IDI_EXCLAMATION), 0);
-      break;
-     case MB_ICONQUESTION:
-       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
+               case MB_OK:
+                       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
+                       /* fall through */
+               case MB_OKCANCEL:
+                       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
+                        break;
+               case MB_ABORTRETRYIGNORE:
+                       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 6), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 7), SW_HIDE);
+                        break;
+                case MB_YESNO:
+                       ShowWindow(GetDlgItem(hwnd, 2), SW_HIDE);
+                 /* fall through */
+                case MB_YESNOCANCEL:
+                       ShowWindow(GetDlgItem(hwnd, 1), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 3), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
+                       ShowWindow(GetDlgItem(hwnd, 5), SW_HIDE);
+                break;
+       }
+       /* Set the icon */
+       switch(lpmb->dwStyle & MB_ICONMASK) {
+               case MB_ICONEXCLAMATION:
+                               SendDlgItemMessage(hwnd, stc1, STM_SETICON,
+                          (WPARAM)LoadIcon(0, IDI_EXCLAMATION), 0);
+                break;
+                case MB_ICONQUESTION:
+                               SendDlgItemMessage(hwnd, stc1, STM_SETICON,
                            (WPARAM)LoadIcon(0, IDI_QUESTION), 0);
-      break;
-     case MB_ICONASTERISK:
-       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
+                break;
+                case MB_ICONASTERISK:
+                       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
                            (WPARAM)LoadIcon(0, IDI_ASTERISK), 0);
-      break;
-     case MB_ICONHAND:
-     default:
-       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
+                break;
+                case MB_ICONHAND:
+                default:
+                       SendDlgItemMessage(hwnd, stc1, STM_SETICON,
                            (WPARAM)LoadIcon(0, IDI_HAND), 0);
-      break;
-    }
+                break;
+       }
     
-    /* Position everything */
-    GetWindowRect(hwnd, &rect);
-    borheight = rect.bottom - rect.top;
-    wwidth = rect.right - rect.left;
-    GetClientRect(hwnd, &rect);
-    borheight -= rect.bottom - rect.top;
-
-    /* Get the icon height */
-    GetWindowRect(GetDlgItem(hwnd, 1088), &rect);
-    iheight = rect.bottom - rect.top;
+       /* Position everything */
+       GetWindowRect(hwnd, &rect);
+       borheight = rect.bottom - rect.top;
+       wwidth = rect.right - rect.left;
+       GetClientRect(hwnd, &rect);
+       borheight -= rect.bottom - rect.top;
+
+       /* Get the icon height */
+       GetWindowRect(GetDlgItem(hwnd, 1088), &rect);
+       iheight = rect.bottom - rect.top;
     
-    /* Get the number of visible buttons and their width */
-    GetWindowRect(GetDlgItem(hwnd, 2), &rect);
-    bheight = rect.bottom - rect.top;
-    bwidth = rect.left;
-    GetWindowRect(GetDlgItem(hwnd, 1), &rect);
-    bwidth -= rect.left;
-    for (buttons = 0, i = 1; i < 8; i++)
-    {
-      hItem = GetDlgItem(hwnd, i);
-      if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE)
-        buttons++;
-    }
+       /* Get the number of visible buttons and their width */
+       GetWindowRect(GetDlgItem(hwnd, 2), &rect);
+       bheight = rect.bottom - rect.top;
+       bwidth = rect.left;
+       GetWindowRect(GetDlgItem(hwnd, 1), &rect);
+       bwidth -= rect.left;
+       for (buttons = 0, i = 1; i < 8; i++)
+       {
+               hItem = GetDlgItem(hwnd, i);
+               if (GetWindowLong(hItem, GWL_STYLE) & WS_VISIBLE)
+                       buttons++;
+       }
     
-    /* Get the text size */
-    hItem = GetDlgItem(hwnd, 100);
-    GetWindowRect(hItem, &textrect);
-    MapWindowPoints(0, hwnd, (LPPOINT)&textrect, 2);
+       /* Get the text size */
+       hItem = GetDlgItem(hwnd, 100);
+       GetWindowRect(hItem, &textrect);
+       MapWindowPoints(0, hwnd, (LPPOINT)&textrect, 2);
     
-    GetClientRect(hItem, &rect);
-    hdc = GetDC(hItem);
-    lRet = DrawTextW( hdc, lpmb->lpszText, -1, &rect,
+       GetClientRect(hItem, &rect);
+       hdc = GetDC(hItem);
+
+
+       if ( bUnicode )
+           lRet = DrawTextW( hdc, (LPCWSTR)lpmb->lpszText, -1, &rect,
                         DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
-    theight = rect.bottom  - rect.top;
-    tiheight = 16 + max(iheight, theight);
-    ReleaseDC(hItem, hdc);
+       else
+           lRet = DrawTextA( hdc, lpmb->lpszText, -1, &rect,
+                        DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
+       theight = rect.bottom  - rect.top;
+       tiheight = 16 + max(iheight, theight);
+       ReleaseDC(hItem, hdc);
     
-    /* Position the text */
-    SetWindowPos(hItem, 0, textrect.left, (tiheight - theight) / 2, 
+       /* Position the text */
+       SetWindowPos(hItem, 0, textrect.left, (tiheight - theight) / 2, 
                   rect.right - rect.left, theight,
                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
     
-    /* Position the icon */
-    hItem = GetDlgItem(hwnd, 1088);
-    GetWindowRect(hItem, &rect);
-    MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
-    SetWindowPos(hItem, 0, rect.left, (tiheight - iheight) / 2, 0, 0,
+       /* Position the icon */
+       hItem = GetDlgItem(hwnd, 1088);
+       GetWindowRect(hItem, &rect);
+       MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
+       SetWindowPos(hItem, 0, rect.left, (tiheight - iheight) / 2, 0, 0,
                   SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
     
     /* Resize the window */
-    SetWindowPos(hwnd, 0, 0, 0, wwidth, 8 + tiheight + bheight + borheight,
+       SetWindowPos(hwnd, 0, 0, 0, wwidth, 8 + tiheight + bheight + borheight,
                   SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
     
     /* Position the buttons */
-    bpos = (wwidth - bwidth * buttons) / 2;
-    GetWindowRect(GetDlgItem(hwnd, 1), &rect);
-    for (buttons = i = 0; i < 7; i++) {
-      /* some arithmetic to get the right order for YesNoCancel windows */
-      hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1);
-      if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) {
-       if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) {
-         SetFocus(hItem);
-         SendMessageW( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
-       }
-       SetWindowPos(hItem, 0, bpos, tiheight, 0, 0,
-                      SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
-       bpos += bwidth;
-      }
-    }
-    return 0;
-    break;
+       bpos = (wwidth - bwidth * buttons) / 2;
+       GetWindowRect(GetDlgItem(hwnd, 1), &rect);
+       for (buttons = i = 0; i < 7; i++) {
+               /* some arithmetic to get the right order for YesNoCancel windows */
+               hItem = GetDlgItem(hwnd, (i + 5) % 7 + 1);
+               if (GetWindowLong(hItem, GWL_STYLE) & WS_VISIBLE) {
+                       if (buttons++ == ((lpmb->dwStyle & MB_DEFMASK) >> 8)) {
+                               SetFocus(hItem);
+                               SendMessage( hItem, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
+                       }
+                       SetWindowPos(hItem, 0, bpos, tiheight, 0, 0,
+                               SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
+                       bpos += bwidth;
+               }
+       }
+       return 0;
+       break;
     
    case WM_COMMAND:
     switch (wParam)
diff --git a/reactos/lib/user32/windows/scroll.c b/reactos/lib/user32/windows/scroll.c
new file mode 100644 (file)
index 0000000..62f2366
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Scroll windows and DCs
+ *
+ * Copyright  David W. Metcalfe, 1993
+ *           Alex Korobka       1995,1996
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <windows.h>
+#include <user32/class.h>
+#include <user32/win.h>
+#include <user32/dce.h>
+#include <user32/sysmetr.h>
+#include <user32/caret.h>
+#include <user32/debug.h>
+
+
+
+/*************************************************************************
+ *             ScrollWindow   (USER.450)
+ *
+ * FIXME: verify clipping region calculations
+ */
+WINBOOL STDCALL ScrollWindow( HWND hwnd, INT dx, INT dy,
+                              const RECT *rect, const RECT *clipRect )
+{
+    HDC        hdc;
+    HRGN       hrgnUpdate,hrgnClip;
+    RECT       rc, cliprc;
+    HWND       hCaretWnd = CARET_GetHwnd();
+    WND*       wndScroll = WIN_FindWndPtr( hwnd );
+
+
+    if ( !wndScroll || !WIN_IsWindowDrawable( wndScroll, TRUE ) ) return TRUE;
+
+    if ( !rect ) /* do not clip children */
+       {
+         GetClientRect(hwnd, &rc);
+         hrgnClip = CreateRectRgnIndirect( &rc );
+
+          if ((hCaretWnd == hwnd) || IsChild(hwnd,hCaretWnd))
+              HideCaret(hCaretWnd);
+          else hCaretWnd = 0;
+         hdc = GetDCEx(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS);
+          DeleteObject( hrgnClip );
+       }
+    else       /* clip children */
+       {
+         CopyRect(&rc, rect);
+
+          if (hCaretWnd == hwnd) HideCaret(hCaretWnd);
+          else hCaretWnd = 0;
+
+         hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
+       }
+
+    if (clipRect == NULL)
+       GetClientRect(hwnd, &cliprc);
+    else
+       CopyRect(&cliprc, clipRect);
+
+    hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
+    ScrollDC( hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL );
+    ReleaseDC(hwnd, hdc);
+
+    if( !rect )                /* move child windows and update region */
+    { 
+      WND*     wndPtr;
+
+      if( wndScroll->hrgnUpdate > 1 )
+       OffsetRgn( wndScroll->hrgnUpdate, dx, dy );
+
+      for (wndPtr = wndScroll->child; wndPtr; wndPtr = wndPtr->next)
+        SetWindowPos(wndPtr->hwndSelf, 0, wndPtr->rectWindow.left + dx,
+                       wndPtr->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
+                       SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
+                       SWP_DEFERERASE );
+    }
+
+    PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_ALLCHILDREN |
+                 RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW, RDW_C_USEHRGN );
+
+    DeleteObject( hrgnUpdate );
+    if( hCaretWnd ) 
+    {
+       POINT   pt;
+       GetCaretPos(&pt);
+       pt.x += dx; pt.y += dy;
+       SetCaretPos(pt.x, pt.y);
+       ShowCaret(hCaretWnd);
+    }
+    return TRUE;
+}
+
+
+
+
+
+/*************************************************************************
+ *             ScrollDC   (USER.449)
+ * 
+ * Both 'rc' and 'prLClip' are in logical units but update info is 
+ * returned in device coordinates.
+ */
+WINBOOL STDCALL ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc,
+                          const RECT *prLClip, HRGN hrgnUpdate,
+                          LPRECT rcUpdate )
+{
+#if 0
+    RECT rClip;
+    POINT src, dest;
+    INT  ldx, ldy;
+    
+
+    if (!hdc ) return FALSE;
+
+
+    /* compute device clipping region */
+
+    if ( rc )
+       rClip = *rc;
+    else /* maybe we should just return FALSE? */
+       GetClipBox( hdc, &rClip );
+
+    if (prLClip)
+       IntersectRect(&rClip,&rClip,prLClip);
+
+    if( rClip.left >= rClip.right || rClip.top >= rClip.bottom )
+    {
+       return FALSE;
+    }
+   
+    SaveVisRgn( hdc );
+    IntersectVisRect( hdc, rClip.left, rClip.top, 
+                           rClip.right, rClip.bottom ); 
+
+
+    /* translate coordinates */
+
+    ldx = dx * dc->wndExtX / dc->vportExtX;
+    ldy = dy * dc->wndExtY / dc->vportExtY;
+
+    if (dx > 0)
+       dest.x = (src.x = rClip.left) + ldx;
+    else
+       src.x = (dest.x = rClip.left) - ldx;
+
+    if (dy > 0)
+       dest.y = (src.y = rClip.top) + ldy;
+    else
+       src.y = (dest.y = rClip.top) - ldy;
+
+    /* copy bits */
+
+    if( rClip.right - rClip.left > ldx &&
+       rClip.bottom - rClip.top > ldy )
+    {
+       ldx = rClip.right - rClip.left - ldx;
+       ldy = rClip.bottom - rClip.top - ldy;
+
+       if (!BitBlt( hdc, dest.x, dest.y, ldx, ldy,
+                      hdc, src.x, src.y, SRCCOPY))
+       {
+           return FALSE;
+       }
+    }
+
+    /* restore clipping region */
+
+    RestoreVisRgn( hdc );
+
+
+    /* compute update areas */
+
+    if ( (hrgnUpdate || rcUpdate) && dc->w.hVisRgn )
+    {
+       HRGN hrgn = (hrgnUpdate) ? hrgnUpdate : CreateRectRgn( 0,0,0,0 );
+        HRGN hrgnClip;
+
+        LPtoDP( hdc, (LPPOINT)&rClip, 2 );
+        OffsetRect( &rClip, dc->w.DCOrgX, dc->w.DCOrgY );
+        hrgnClip = CreateRectRgnIndirect( &rClip );
+        
+        CombineRgn( hrgn, dc->w.hVisRgn, hrgnClip, RGN_AND );
+        OffsetRgn( hrgn, dx, dy );
+        CombineRgn( hrgn, dc->w.hVisRgn, hrgn, RGN_DIFF );
+        CombineRgn( hrgn, hrgn, hrgnClip, RGN_AND );
+        OffsetRgn( hrgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
+
+        if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
+
+       if (!hrgnUpdate) DeleteObject( hrgn );
+        DeleteObject( hrgnClip );     
+    }
+#endif
+    return TRUE;
+}
+
+
+
+
+
+/*************************************************************************
+ *             ScrollWindowEx   (USER.451)
+ *
+ * NOTE: Use this function instead of ScrollWindow
+ */
+INT STDCALL ScrollWindowEx( HWND hwnd, INT dx, INT dy,
+                               const RECT *rect, const RECT *clipRect,
+                               HRGN hrgnUpdate, LPRECT rcUpdate,
+                               UINT flags )
+{
+    INT  retVal = NULLREGION;
+    WINBOOL bCaret = FALSE, bOwnRgn = TRUE;
+    RECT rc, cliprc;
+    WND*   wnd = WIN_FindWndPtr( hwnd );
+
+    if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) return ERROR;
+
+    if (rect == NULL) GetClientRect(hwnd, &rc);
+    else rc = *rect;
+
+    if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
+    else cliprc = rc;
+
+    if (!IsRectEmpty(&cliprc) && (dx || dy))
+    {
+
+       HDC     hDC;
+       WINBOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
+       HRGN  hrgnClip = CreateRectRgnIndirect(&cliprc);
+
+
+       rc = cliprc;
+       bCaret = SCROLL_FixCaret(hwnd, &rc, flags);
+
+       if( hrgnUpdate ) bOwnRgn = FALSE;
+        else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
+
+       hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE | 
+                      ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
+       if( hDC != NULL)
+       {
+
+#if 0
+           if( dc->w.hVisRgn && bUpdate )
+           {
+                OffsetRgn( hrgnClip, dc->w.DCOrgX, dc->w.DCOrgY );
+               CombineRgn( hrgnUpdate, dc->w.hVisRgn, hrgnClip, RGN_AND );
+               OffsetRgn( hrgnUpdate, dx, dy );
+               CombineRgn( hrgnUpdate, dc->w.hVisRgn, hrgnUpdate, RGN_DIFF );
+               CombineRgn( hrgnUpdate, hrgnUpdate, hrgnClip, RGN_AND );
+                OffsetRgn( hrgnUpdate, -dc->w.DCOrgX, -dc->w.DCOrgY );
+
+               if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
+           }
+#endif
+           ReleaseDC(hwnd, hDC);
+
+       }
+
+       if( wnd->hrgnUpdate > 1 )
+       {
+           if( rect || clipRect )
+           {
+               if( (CombineRgn( hrgnClip, hrgnClip, 
+                                  wnd->hrgnUpdate, RGN_AND ) != NULLREGION) )
+               {
+                   CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_DIFF );
+                   OffsetRgn( hrgnClip, dx, dy );
+                   CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_OR );
+               }
+           }
+           else  
+               OffsetRgn( wnd->hrgnUpdate, dx, dy );
+       }
+
+       if( flags & SW_SCROLLCHILDREN )
+       {
+           RECT        r;
+           WND*        w;
+           for( w = wnd->child; w; w = w->next )
+           {
+       
+                if( !clipRect || IntersectRect(&w->rectWindow, &r, &cliprc) )
+                    SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
+                                   w->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
+                                   SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
+                                   SWP_DEFERERASE );
+           }
+       }
+
+       if( flags & (SW_INVALIDATE | SW_ERASE) )
+           PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
+               ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ), 0 );
+
+       if( bCaret )
+       {
+           SetCaretPos( rc.left + dx, rc.top + dy );
+           ShowCaret(0);
+       }
+
+       if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
+       DeleteObject( hrgnClip );
+    }
+    return retVal;
+}
+
+
index 269f366..feb1ffa 100644 (file)
@@ -5,9 +5,11 @@
 #include <user32/winpos.h>
 #include <user32/hook.h>
 #include <user32/property.h>
+#include <user32/paint.h>
 #include <user32/debug.h>
 
 
+// change style on WS_OVERLAPPEDWINDOW
 
 #undef CreateWindowA
 HWND STDCALL CreateWindowA(LPCSTR  lpClassName, LPCSTR  lpWindowName,
@@ -51,17 +53,11 @@ HWND STDCALL CreateWindowExA( DWORD exStyle, LPCSTR lpClassName,
     //if(exStyle & WS_EX_MDICHILD)
     //    return MDI_CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, data);
 
-#if 0
-    while ((*lpWindowName)!=0 && i < MAX_PATH)
-     {
-       WindowNameW[i] = *lpWindowName;
-       lpWindowName++;
-       i++;
-     }
-    WindowNameW[i] = 0;
-#endif
+
 
    
+    if ( style ==  WS_OVERLAPPEDWINDOW )
+       style |= (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |WS_MAXIMIZEBOX  );
 
 
     /* Create the window */
@@ -91,8 +87,6 @@ HWND STDCALL CreateWindowExW( DWORD exStyle, LPCWSTR lpClassName,
                                  HWND parent, HMENU menu,
                                  HINSTANCE hInstance, LPVOID data )
 {
-//    WCHAR WindowNameW[MAX_PATH];
-//    WCHAR ClassNameW[MAX_PATH];
     CLASS *p;
     DWORD status;
     CREATESTRUCTW cs;
@@ -103,7 +97,8 @@ HWND STDCALL CreateWindowExW( DWORD exStyle, LPCWSTR lpClassName,
     if ( p == NULL )
                return NULL;
 
-  
+    if ( style ==  WS_OVERLAPPEDWINDOW )
+       style |= (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |WS_MAXIMIZEBOX  );
 
     /* Create the window */
 
@@ -133,22 +128,25 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd )
 {
     WND * wndPtr;
 
-    DPRINT( "(%04x)\n", hwnd);
-    
       /* Initialization */
 
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
     //if (wndPtr == pWndDesktop) return FALSE; /* Can't destroy desktop */
 
+
+    if ( hwnd == NULL )
+       return FALSE;
+
       /* Call hooks */
        
 
-    if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) )
+    if( HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, hwnd, 0L, wndPtr->class->bUnicode ) )
         return FALSE;
 
     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
     {
-        HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
+        HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L,  wndPtr->class->bUnicode  );
         /* FIXME: clean up palette - see "Internals" p.352 */
     }
 
@@ -156,12 +154,13 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd )
        if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
        {
            /* Notify the parent window only */
-           SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
+           if ( wndPtr->parent  != NULL )
+               SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
                            MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
            if( !IsWindow(hwnd) ) return TRUE;
        }
 
-  //  CLIPBOARD_GetDriver()->pResetOwner( wndPtr, FALSE ); /* before the window is unmapped */
 
       /* Hide the window */
 
@@ -182,7 +181,10 @@ WINBOOL STDCALL DestroyWindow( HWND hwnd )
 
       for (;;)
       {
-        WND *siblingPtr = wndPtr->parent->child;  /* First sibling */
+
+        WND *siblingPtr = NULL;
+        if ( wndPtr->parent != NULL )
+               siblingPtr = wndPtr->parent->child;  /* First sibling */
         while (siblingPtr)
         {
             if (siblingPtr->owner == wndPtr)
@@ -571,20 +573,22 @@ WINBOOL STDCALL IsWindowVisible( HWND hwnd )
 
 
 /***********************************************************************
- *           ShowWindow32   (USER32.534)
+ *           ShowWindow   (USER32.534)
  */
 WINBOOL STDCALL ShowWindow( HWND hwnd, INT cmd ) 
 {    
     WND*       wndPtr = WIN_FindWndPtr( hwnd );
-    WINBOOL    wasVisible, showFlag;
+    WINBOOL    wasVisible = FALSE, showFlag;
     RECT       newPos = {0, 0, 0, 0};
     int        swp = 0;
 
     if (!wndPtr) return FALSE;
 
 //    DPRINT("hwnd=%04x, cmd=%d\n", hwnd, cmd);
+#ifdef OPTIMIZATION
 
     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
+#endif
 
     switch(cmd)
     {
@@ -680,6 +684,51 @@ WINBOOL STDCALL ShowWindow( HWND hwnd, INT cmd )
  //   SendMessage(hwnd, WM_NCACTIVATE,TRUE,0);
  //   SendMessage(hwnd, WM_NCPAINT,CreateRectRgn(100,100,100, 100) ,0);
 
+   
+    
     return wasVisible;
 }
 
+
+/*******************************************************************
+ *            FlashWindow  (USER32.202)
+ */
+WINBOOL STDCALL FlashWindow( HWND hWnd, WINBOOL bInvert )
+{
+    WND *wndPtr = WIN_FindWndPtr(hWnd);
+
+
+    if (!wndPtr) return FALSE;
+
+    if (wndPtr->dwStyle & WS_MINIMIZE)
+    {
+        if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
+        {
+            HDC hDC = GetDC(hWnd);
+            
+            if (!SendMessage( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
+                wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
+            
+            ReleaseDC( hWnd, hDC );
+            wndPtr->flags |= WIN_NCACTIVATED;
+        }
+        else
+        {
+            PAINT_RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE |
+                                         RDW_UPDATENOW | RDW_FRAME, 0 );
+            wndPtr->flags &= ~WIN_NCACTIVATED;
+        }
+        return TRUE;
+    }
+    else
+    {
+        WPARAM wparam;
+        if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
+        else wparam = (hWnd == GetActiveWindow());
+
+        SendMessage( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
+        return wparam;
+    }
+}
+
+
index d76fcde..453dbfc 100644 (file)
@@ -175,15 +175,13 @@ HWND SetActiveWindow(HWND  hWnd )
 WINBOOL
 STDCALL
 SetWindowPos(
-            HWND hWnd,
-            HWND hWndInsertAfter ,
-            int X,
-            int Y,
-            int cx,
-            int cy,
+            HWND hWnd, HWND hWndInsertAfter ,
+            int X, int Y,
+            int cx, int cy,
             UINT flags)
 {
-    WINDOWPOS winpos;
+
+    WINDOWPOS   winpos;
     WND *      wndPtr;
     RECT       newWindowRect, newClientRect, oldWindowRect;
     HRGN       visRgn = 0;
@@ -192,13 +190,22 @@ SetWindowPos(
     UINT       uFlags;
     WINBOOL      resync = FALSE;
 
-    DPRINT("hwnd %04x, (%i,%i)-(%i,%i) flags %08x\n", 
-                                                hWnd, X, Y, X+cx, Y+cy, flags);  
       /* Check window handle */
 
     if (hWnd == GetDesktopWindow()) return FALSE;
+
+    if (hWnd == GetActiveWindow() ) flags |= SWP_NOACTIVATE;   /* Already active */
+
+
+   /* Check dimensions */
+
+    if (cx <= 0) cx = 1;
+    if (cy <= 0) cy = 1;
+
     if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return FALSE;
 
+#if OPTIMIZATION
     if(wndPtr->dwStyle & WS_VISIBLE)
         flags &= ~SWP_SHOWWINDOW;
     else
@@ -208,38 +215,30 @@ SetWindowPos(
        if (!(flags & SWP_SHOWWINDOW)) flags |= SWP_NOREDRAW;
     }
 
-/*     Check for windows that may not be resized 
-       FIXME: this should be done only for Windows 3.0 programs 
-       if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW ) )
-           flags |= SWP_NOSIZE | SWP_NOMOVE;
-*/
-      /* Check dimensions */
 
-    if (cx <= 0) cx = 1;
-    if (cy <= 0) cy = 1;
 
       /* Check flags */
 
-    if (hWnd == hwndActive) flags |= SWP_NOACTIVATE;   /* Already active */
     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == cx) &&
         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == cy))
         flags |= SWP_NOSIZE;    /* Already the right size */
     if ((wndPtr->rectWindow.left == X) && (wndPtr->rectWindow.top == Y))
         flags |= SWP_NOMOVE;    /* Already the right position */
 
+#endif
       /* Check hWndInsertAfter */
 
     if (!(flags & (SWP_NOZORDER | SWP_NOACTIVATE)))
     {
          /* Ignore TOPMOST flags when activating a window */
           /* _and_ moving it in Z order. */
-       if ((hWndInsertAfter == HWND_TOPMOST) ||
-            (hWndInsertAfter == HWND_NOTOPMOST))
+
+       if ((hWndInsertAfter == HWND_TOPMOST) || (hWndInsertAfter == HWND_NOTOPMOST))
            hWndInsertAfter = HWND_TOP; 
     }
       /* TOPMOST not supported yet */
-    if ((hWndInsertAfter == HWND_TOPMOST) ||
-        (hWndInsertAfter == HWND_NOTOPMOST)) hWndInsertAfter = HWND_TOP;
+    if ((hWndInsertAfter == HWND_TOPMOST) || (hWndInsertAfter == HWND_NOTOPMOST)) 
+       hWndInsertAfter = HWND_TOP;
 
       /* hWndInsertAfter must be a sibling of the window */
     if ((hWndInsertAfter != HWND_TOP) && (hWndInsertAfter != HWND_BOTTOM))
@@ -274,7 +273,7 @@ SetWindowPos(
       /* Send WM_WINDOWPOSCHANGING message */
 
     if (!(winpos.flags & SWP_NOSENDCHANGING))
-       SendMessageA( hWnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
+       MSG_SendMessage( wndPtr, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
 
       /* Calculate new position and size */
 
@@ -414,10 +413,11 @@ SetWindowPos(
 
   
        
-         if (!(flags & SWP_NOREDRAW))
+         if (!(flags & SWP_NOREDRAW) && wndPtr->parent != NULL ) 
                 PAINT_RedrawWindow( wndPtr->parent->hwndSelf, &oldWindowRect,
                                     0, RDW_INVALIDATE | RDW_ALLCHILDREN |
                                        RDW_ERASE | RDW_ERASENOW, 0 );
+        
          uFlags |= SMC_NOPARENTERASE;
         
 
@@ -468,6 +468,7 @@ SetWindowPos(
 
 
 
+
 /***********************************************************************
  *           WINPOS_CreateInternalPosAtom
  */
@@ -491,14 +492,14 @@ void WINPOS_CheckInternalPos( HWND hwnd )
     if( hwnd == hwndActive )
     {
        hwndActive = 0; 
-       //WARN(win, "\tattempt to activate destroyed window!\n");
+       DPRINT("\tattempt to activate destroyed window!\n");
     }
 
     if( lpPos )
     {
-       if( IsWindow(lpPos->hwndIconTitle) ) 
-           DestroyWindow( lpPos->hwndIconTitle );
-       HeapFree( GetProcessHeap(), 0, lpPos );
+       //if( IsWindow(lpPos->hwndIconTitle) ) 
+       //    DestroyWindow( lpPos->hwndIconTitle );
+       //HeapFree( GetProcessHeap(), 0, lpPos );
     }
 }
 
@@ -512,7 +513,18 @@ static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
     RECT rectParent;
     short x, y, xspacing, yspacing;
 
-    GetClientRect( wndPtr->parent->hwndSelf, &rectParent );
+    if ( wndPtr->parent != NULL ) {
+       GetClientRect( wndPtr->parent->hwndSelf, &rectParent );
+    }
+    else {
+
+       rectParent.left = 0;
+       rectParent.right = SYSMETRICS_CXFULLSCREEN;
+       
+       rectParent.top = 0;
+       rectParent.right = SYSMETRICS_CYFULLSCREEN;
+    }
+       
     if ((pt.x >= rectParent.left) && (pt.x + SYSMETRICS_CXICON < rectParent.right) &&
         (pt.y >= rectParent.top) && (pt.y + SYSMETRICS_CYICON < rectParent.bottom))
         return pt;  /* The icon already has a suitable position */
@@ -526,7 +538,9 @@ static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
         for (x = rectParent.left; x <= rectParent.right-xspacing; x += xspacing)
         {
               /* Check if another icon already occupies this spot */
-            WND *childPtr = wndPtr->parent->child;
+           WND *childPtr = NULL;
+           if ( wndPtr->parent )
+               childPtr = wndPtr->parent->child;
             while (childPtr)
             {
                 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
@@ -712,6 +726,7 @@ LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt,
        *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF;
     }
 
+
     if( wnd->dwStyle & WS_MINIMIZE ) 
        memcpy( &lpPos->ptIconPos, &pt,sizeof(POINT) );
     else if( wnd->dwStyle & WS_MAXIMIZE ) 
@@ -824,7 +839,7 @@ void WINPOS_GetMinMaxInfo( WND *wndPtr, POINT *maxSize, POINT *maxPos,
         MinMax.ptMaxPosition.y = -yinc;
     }
 
-    SendMessageA( wndPtr->hwndSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
+    MSG_SendMessage( wndPtr, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
 
       /* Some sanity checks */
 
@@ -857,25 +872,19 @@ UINT WINPOS_MinMaximize( WND* wndPtr, UINT cmd, LPRECT lpRect )
     
     //DPRINT("0x%04x %u\n", wndPtr->hwndSelf, cmd );
 
-    if ( wndPtr->class->bUnicode ) {
-       if (HOOK_CallHooksW(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) {
-               swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
-                return swpFlags;
-       }
-    }
-    else {
-       if (HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) {
-               swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
-                return swpFlags;
-       }
+
+    if (HOOK_CallHooks(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd, wndPtr->class->bUnicode )) {
+       swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
+        return swpFlags;
     }
+   
                
 
     if (lpPos)
     {
        if( wndPtr->dwStyle & WS_MINIMIZE )
        {
-           if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
+           if( !MSG_SendMessage( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
                return (SWP_NOSIZE | SWP_NOMOVE);
            swpFlags |= SWP_NOCOPYBITS;
        }
@@ -1000,7 +1009,156 @@ WINBOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl,
  */
 WINBOOL WINPOS_SetActiveWindow( HWND hWnd, WINBOOL fMouse, WINBOOL fChangeFocus)
 {
-       return FALSE;
+    CBTACTIVATESTRUCT* cbtStruct;
+    WND*     wndPtr, *wndTemp;
+    //HQUEUE hOldActiveQueue, hNewActiveQueue;
+    WORD     wIconized = 0;
+
+    /* paranoid checks */
+    if( hWnd == GetDesktopWindow || hWnd == hwndActive ) return 0;
+
+/*  if (wndPtr && (GetFastQueue() != wndPtr->hmemTaskQ))
+ *     return 0;
+ */
+    wndPtr = WIN_FindWndPtr(hWnd);
+    //hOldActiveQueue = (pActiveQueue)?pActiveQueue->self : 0;
+
+    if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
+       wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
+   
+
+#if 0
+    /* call CBT hook chain */
+    if ((cbtStruct = SEGPTR_NEW(CBTACTIVATESTRUCT16)))
+    {
+        LRESULT wRet;
+        cbtStruct->fMouse     = fMouse;
+        cbtStruct->hWndActive = hwndActive;
+        wRet = HOOK_CallHooks16( WH_CBT, HCBT_ACTIVATE, (WPARAM16)hWnd,
+                                 (LPARAM)SEGPTR_GET(cbtStruct) );
+        SEGPTR_FREE(cbtStruct);
+        if (wRet) return wRet;
+    }
+#endif
+
+    /* set prev active wnd to current active wnd and send notification */
+    if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
+    {
+        if (!SendMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 ))
+        {
+           //if (GetSysModalWindow16() != hWnd) return 0;
+           /* disregard refusal if hWnd is sysmodal */
+        }
+
+
+       SendMessageA( hwndPrevActive, WM_ACTIVATE,
+                        MAKEWPARAM( WA_INACTIVE, wIconized ),
+                        (LPARAM)hWnd );
+
+
+       /* check if something happened during message processing */
+       if( hwndPrevActive != hwndActive ) return 0;
+    }
+
+    /* set active wnd */
+    hwndActive = hWnd;
+
+    /* send palette messages */
+    if (hWnd && SendMessage( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
+       SendMessage((HWND)-1, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0L );
+
+    /* if prev wnd is minimized redraw icon title */
+    if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
+
+#if DESKTOP
+    /* managed windows will get ConfigureNotify event */  
+    if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->flags & WIN_MANAGED))
+    {
+       /* check Z-order and bring hWnd to the top */
+       for (wndTemp = WIN_GetDesktop()->child; wndTemp; wndTemp = wndTemp->next)
+           if (wndTemp->dwStyle & WS_VISIBLE) break;
+
+       if( wndTemp != wndPtr )
+           SetWindowPos(hWnd, HWND_TOP, 0,0,0,0, 
+                          SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+        if (!IsWindow(hWnd)) return 0;
+    }
+
+#endif
+
+#if 0
+    hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
+
+    /* send WM_ACTIVATEAPP if necessary */
+    if (hOldActiveQueue != hNewActiveQueue)
+    {
+        WND **list, **ppWnd;
+
+        if ((list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
+        {
+            for (ppWnd = list; *ppWnd; ppWnd++)
+            {
+                if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
+
+                if ((*ppWnd)->hmemTaskQ == hOldActiveQueue)
+                   SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
+                                   0, QUEUE_GetQueueTask(hNewActiveQueue) );
+            }
+            HeapFree( SystemHeap, 0, list );
+        }
+
+       pActiveQueue = (hNewActiveQueue)
+                      ? (MESSAGEQUEUE*) GlobalLock16(hNewActiveQueue) : NULL;
+
+        if ((list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
+        {
+            for (ppWnd = list; *ppWnd; ppWnd++)
+            {
+                if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
+
+                if ((*ppWnd)->hmemTaskQ == hNewActiveQueue)
+                   SendMessage( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
+                                  1, QUEUE_GetQueueTask( hOldActiveQueue ) );
+            }
+            HeapFree( SystemHeap, 0, list );
+        }
+       if (!IsWindow(hWnd)) return 0;
+    }
+
+#endif
+    if (hWnd)
+    {
+        /* walk up to the first unowned window */
+        wndTemp = wndPtr;
+        while (wndTemp->owner) wndTemp = wndTemp->owner;
+        /* and set last active owned popup */
+        wndTemp->hwndLastActive = hWnd;
+
+        wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
+        SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
+
+        SendMessageA( hWnd, WM_ACTIVATE,
+                MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
+                (LPARAM)hwndPrevActive );
+
+
+        if( !IsWindow(hWnd) ) return 0;
+    }
+#if 0
+    /* change focus if possible */
+    if( fChangeFocus && GetFocus() )
+       if( WIN_GetTopParent(GetFocus()) != hwndActive )
+           FOCUS_SwitchFocus( GetFocus(),
+                              (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
+                              0:
+                              hwndActive
+           );
+#endif
+
+    /* if active wnd is minimized redraw icon title */
+    if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
+
+    return (hWnd == hwndActive);
 }
 
 /*******************************************************************
@@ -1060,7 +1218,7 @@ WINBOOL WINPOS_ChangeActiveWindow( HWND hWnd, WINBOOL mouseMsg )
 
     /* child windows get WM_CHILDACTIVATE message */
     if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD )
-       return SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L);
+       return MSG_SendMessage(wndPtr, WM_CHILDACTIVATE, 0, 0L);
 
         /* owned popups imply owner activation - not sure */
     if ((wndPtr->dwStyle & WS_POPUP) && wndPtr->owner &&
@@ -1076,10 +1234,11 @@ WINBOOL WINPOS_ChangeActiveWindow( HWND hWnd, WINBOOL mouseMsg )
     if( !WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE) )
        return FALSE;
 
+#if DESKTOP
     /* switch desktop queue to current active */
     if( wndPtr->parent == WIN_GetDesktop())
         WIN_GetDesktop()->hmemTaskQ = wndPtr->hmemTaskQ;
-
+#endif
     return TRUE;
 }
 
@@ -1397,8 +1556,7 @@ UINT WINPOS_SizeMoveClean( WND* Wnd, HRGN oldVisRgn,
 // REMOVED DCX_KEEPCLIPRGN 
 
          hDC = GetDCEx( Wnd->parent->hwndSelf, oldVisRgn,
-                           DCX_INTERSECTRGN |
-                          DCX_CACHE | DCX_CLIPSIBLINGS);
+                           DCX_INTERSECTRGN | DCX_CACHE | DCX_CLIPSIBLINGS);
          
          BitBlt( hDC, xto, yto, width, height, hDC, xfrom, yfrom, SRCCOPY );
          ReleaseDC( Wnd->parent->hwndSelf, hDC); 
@@ -1422,3 +1580,15 @@ UINT WINPOS_SizeMoveClean( WND* Wnd, HRGN oldVisRgn,
  return uFlags;
 }
 
+/***********************************************************************
+ *           MoveWindow   (USER32.399)
+ */
+WINBOOL STDCALL MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
+                            WINBOOL repaint )
+{    
+    int flags = SWP_NOZORDER | SWP_NOACTIVATE;
+    if (!repaint) flags |= SWP_NOREDRAW;
+   
+    return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
+}
+