Index: include/reactos/undocuser.h
===================================================================
--- include/reactos/undocuser.h	(revision 68654)
+++ include/reactos/undocuser.h	(working copy)
@@ -60,6 +60,9 @@
 #define DCX_KEEPLAYOUT   0x40000000
 #define DCX_PROCESSOWNED 0x80000000
 
+/* Non SDK TPM types.*/
+#define TPM_SYSTEM_MENU  0x00000200
+
 /* NtUserCreateWindowEx dwFlags bits. */
 #define NUCWE_ANSI       0x00000001
 #define NUCWE_SIDEBYSIDE 0x40000000
@@ -132,8 +135,17 @@
 //
 // Undocumented flags for DrawCaptionTemp
 //
+#define DC_NOVISIBLE 0x0800
 #define DC_NOSENDMSG 0x2000
+#define DC_FRAME     0x8000  // Missing from WinUser.H!
 
+//
+// Undocumented states for DrawFrameControl
+//
+#define DFCS_MENUARROWUP   0x0008
+#define DFCS_MENUARROWDOWN 0x0010
+
+
 #define STARTF_SCRNSAVER 0x80000000
 
 #define MOD_WINLOGON_SAS 0x8000
Index: win32ss/CMakeLists.txt
===================================================================
--- win32ss/CMakeLists.txt	(revision 68654)
+++ win32ss/CMakeLists.txt	(working copy)
@@ -149,6 +149,7 @@
     user/ntuser/winpos.c
     user/ntuser/winsta.c
     user/ntuser/object.c
+    user/rtl/text.c
     gdi/ntgdi/arc.c
     gdi/ntgdi/bezier.c
     gdi/ntgdi/bitblt.c
Index: win32ss/user/ntuser/callback.c
===================================================================
--- win32ss/user/ntuser/callback.c	(revision 68654)
+++ win32ss/user/ntuser/callback.c	(working copy)
@@ -393,6 +393,7 @@
           case WM_WINDOWPOSCHANGING:
           case WM_SIZING:
           case WM_MOVING:
+          case WM_MEASUREITEM:
             TRACE("Copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
             if (InSendMessage)
                // Copy into kernel space.
Index: win32ss/user/ntuser/defwnd.c
===================================================================
--- win32ss/user/ntuser/defwnd.c	(revision 68654)
+++ win32ss/user/ntuser/defwnd.c	(working copy)
@@ -11,7 +11,24 @@
 
 DBG_DEFAULT_CHANNEL(UserDefwnd);
 
+INT WINAPI DrawTextExWorker( HDC hdc, LPWSTR str, INT i_count,
+                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp );
 
+INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
+{
+    DRAWTEXTPARAMS dtp;
+
+    memset (&dtp, 0, sizeof(dtp));
+    dtp.cbSize = sizeof(dtp);
+    if (flags & DT_TABSTOP)
+    {
+        dtp.iTabLength = (flags >> 8) & 0xff;
+        flags &= 0xffff00ff;
+    }
+    return DrawTextExWorker(hdc, (LPWSTR)str, count, rect, flags, &dtp);
+}
+
+
 HBRUSH FASTCALL
 DefWndControlColor(HDC hDC, UINT ctlType)
 {
@@ -362,7 +379,43 @@
     co_IntSendMessage(UserHMGetHandle(pwnd), WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
 }
 
+BOOL
+UserPaintCaption(PWND pWnd, INT Flags)
+{
+  BOOL Ret = FALSE;
 
+  if ( pWnd->style & WS_VISIBLE && (pWnd->style & WS_CAPTION) == WS_CAPTION )
+  {
+    /* 
+     * When themes are not enabled we can go on and paint the non client area.
+     * However if we do that with themes enabled we will draw a classic frame.
+     * This is sovled by sending a themes specific message to notify the themes
+     * engine that the caption needs to be redrawn 
+     */
+      if (gpsi->dwSRVIFlags & SRVINFO_APIHOOK)
+      {
+        /* 
+         * This will cause uxtheme to either paint the themed caption or call
+         * RealUserDrawCaption in order to draw the classic caption when themes
+         * are disabled but the themes service is enabled
+         */
+         co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCUAHDRAWCAPTION, Flags, 0);
+      }
+      else
+      {
+         HDC hDC = UserGetDCEx(pWnd, NULL, DCX_WINDOW|DCX_USESTYLE);
+         UserDrawCaptionBar(pWnd, hDC, Flags);
+         UserReleaseDC(pWnd, hDC, FALSE);
+      }
+      Ret = TRUE;
+   }
+   // Support window tray
+   return Ret;
+}
+
+INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen);
+DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd );
+
 /*
    Win32k counterpart of User DefWindowProc
  */
@@ -424,6 +477,28 @@
          UserDerefObjectCo(Wnd->spwndParent);
          break;
 
+      case WM_KEYF1:
+      {
+         HELPINFO hi;
+         PMENU pMenu = UlongToHandle(Wnd->IDMenu);
+         hi.cbSize = sizeof(HELPINFO);
+         hi.MousePos = gpsi->ptCursor;
+         hi.iContextType = HELPINFO_MENUITEM;
+         hi.hItemHandle = UserHMGetHandle(Wnd);
+         hi.iCtrlId = (Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD ? IntMenuItemFromPoint(Wnd, UserHMGetHandle(pMenu), hi.MousePos) : 0;
+         hi.dwContextId = IntGetWindowContextHelpId(Wnd);
+
+         co_IntSendMessage( UserHMGetHandle(Wnd), WM_HELP, 0, (LPARAM)&hi );
+         break;
+      }
+
+      case WM_HELP:
+      {
+         PWND Parent = IntGetParent(Wnd);
+         co_IntSendMessage(UserHMGetHandle(Parent), Msg, wParam, lParam);
+         break;
+      }
+
       case WM_CLOSE:
          co_UserDestroyWindow(Wnd);
          break;
@@ -548,7 +623,9 @@
                  IntGetClientRect(Wnd, &ClientRect);
                  x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
                  y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
+                 UserReferenceObject(Wnd->pcls->spicn);
                  UserDrawIconEx(hDC, x, y, Wnd->pcls->spicn, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
+                 UserDereferenceObject(Wnd->pcls->spicn);
              }
 
              IntEndPaint(Wnd, &Ps);
@@ -607,6 +684,53 @@
           return (DefWndHandleWindowPosChanged(Wnd, (WINDOWPOS*)lParam));
       }
 
+      case WM_NCCALCSIZE:
+      {
+         return NC_HandleNCCalcSize( Wnd, wParam, (RECTL *)lParam );
+      }
+
+      case WM_NCACTIVATE:
+      {
+          return NC_HandleNCActivate( Wnd, wParam, lParam );
+      }
+
+      //
+      // NC Paint mode.
+      //
+      case WM_NCPAINT:
+      {
+          HDC hDC = UserGetDCEx(Wnd, (HRGN)wParam, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
+          Wnd->state |= WNDS_FORCEMENUDRAW;
+          NC_DoNCPaint(Wnd, hDC, -1);
+          Wnd->state &= ~WNDS_FORCEMENUDRAW;
+          UserReleaseDC(Wnd, hDC, FALSE);
+          return 0;
+      }
+      //
+      //  Draw Caption mode.
+      //
+      //  wParam is DC_* flags.
+      //
+      case WM_NCUAHDRAWCAPTION:
+      {
+          HDC hDC = UserGetDCEx(Wnd, NULL, DCX_WINDOW|DCX_USESTYLE);
+          TRACE("WM_NCUAHDRAWCAPTION: wParam DC_ flags %d\n");
+          UserDrawCaptionBar(Wnd, hDC, wParam);
+          UserReleaseDC(Wnd, hDC, FALSE);
+          return 0;
+      }
+      //
+      //  Draw Frame mode.
+      //
+      //  wParam is HDC, lParam is DC_ACTIVE and or DCF_REDRAWHUNGWND.
+      //
+      case WM_NCUAHDRAWFRAME:
+      {
+          TRACE("WM_NCUAHDRAWFRAME: wParam hDC %p lParam DC_ flags %d\n",wParam,lParam);
+          NC_DoNCPaint(Wnd, (HDC)wParam, lParam|DC_NC);
+          return 0;
+      }
+
       /* ReactOS only. */
       case WM_CBT:
       {
Index: win32ss/user/ntuser/draw.c
===================================================================
--- win32ss/user/ntuser/draw.c	(revision 68654)
+++ win32ss/user/ntuser/draw.c	(working copy)
@@ -948,6 +948,14 @@
     WCHAR Symbol;
     switch(uFlags & 0xff)
     {
+        case DFCS_MENUARROWUP:
+            Symbol = '5';
+            break;
+
+        case DFCS_MENUARROWDOWN:
+            Symbol = '6';
+            break;
+
         case DFCS_MENUARROW:
             Symbol = '8';
             break;
@@ -980,8 +988,6 @@
     hFont = GreCreateFontIndirectW(&lf);
     /* save font */
     hOldFont = NtGdiSelectFont(dc, hFont);
-    // FIXME selecting color doesn't work
-#if 0
     if(uFlags & DFCS_INACTIVE)
     {
         /* draw shadow */
@@ -989,7 +995,6 @@
         GreTextOutW(dc, r->left + 1, r->top + 1, &Symbol, 1);
     }
     IntGdiSetTextColor(dc, IntGetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
-#endif
     /* draw selected symbol */
     GreTextOutW(dc, r->left, r->top, &Symbol, 1);
     /* restore previous settings */
@@ -1006,6 +1011,25 @@
 
 
 INT WINAPI
+FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
+{
+    HBRUSH oldbrush;
+    RECT r = *lprc;
+
+    if ((r.right <= r.left) || (r.bottom <= r.top)) return 0;
+    if (!(oldbrush = NtGdiSelectBrush(hDC, hbr))) return 0;
+
+    NtGdiPatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
+    NtGdiPatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
+    NtGdiPatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
+    NtGdiPatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
+
+    NtGdiSelectBrush(hDC, oldbrush);
+    return TRUE;
+}
+
+
+INT WINAPI
 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
 {
     BOOL Ret;
Index: win32ss/user/ntuser/main.c
===================================================================
--- win32ss/user/ntuser/main.c	(revision 68654)
+++ win32ss/user/ntuser/main.c	(working copy)
@@ -461,6 +461,7 @@
     PTEB pTeb;
     LARGE_INTEGER LargeTickCount;
     PRTL_USER_PROCESS_PARAMETERS ProcessParams;
+    PMENUSTATE pms;
 
     Process = Thread->ThreadsProcess;
 
@@ -478,6 +479,15 @@
         return Status;
     }
 
+    /* Allocate Menu State structure */
+    pms = ExAllocatePoolWithTag(NonPagedPool, sizeof(*pms), USERTAG_MENUSTATE);
+    if ( pms == NULL)
+    {
+        ERR_CH(UserThread, "Failed to allocate thread menu state\n");
+        return STATUS_NO_MEMORY;
+    }
+    ptiCurrent->pMenuState = pms;
+
     /* Initialize the THREADINFO */
     ptiCurrent->pEThread = Thread;
     ptiCurrent->ppi = PsGetProcessWin32Process(Process);
Index: win32ss/user/ntuser/menu.c
===================================================================
--- win32ss/user/ntuser/menu.c	(revision 68654)
+++ win32ss/user/ntuser/menu.c	(working copy)
@@ -11,13 +11,26 @@
 
 /* INTERNAL ******************************************************************/
 
+HFONT ghMenuFont = NULL;
+HFONT ghMenuFontBold = NULL;
+static SIZE MenuCharSize;
+
 BOOL FASTCALL IntSetMenuItemInfo(PMENU, PITEM, PROSMENUITEMINFO, PUNICODE_STRING);
 
+/* internal popup menu window messages */
+
+#define MM_SETMENUHANDLE        (WM_USER + 0)
+#define MM_GETMENUHANDLE        (WM_USER + 1)
+
 /* maximum allowed depth of any branch in the menu tree.
  * This value is slightly larger than in windows (25) to
  * stay on the safe side. */
 #define MAXMENUDEPTH 30
 
+#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
+
+//#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
+
 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
 
 #define MENUITEMINFO_TYPE_MASK \
@@ -33,10 +46,38 @@
 
 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
 
+#define IS_SYSTEM_MENU(MenuInfo)  \
+	(0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_SYSTEM_POPUP(MenuInfo) \
+	(0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
+
+#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
+#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
+
 /* Maximum number of menu items a menu can contain */
 #define MAX_MENU_ITEMS (0x4000)
 #define MAX_GOINTOSUBMENU (0x10)
 
+/*  top and bottom margins for popup menus */
+#define MENU_TOP_MARGIN 2 //3
+#define MENU_BOTTOM_MARGIN 2
+
+#define MENU_ITEM_HBMP_SPACE (5)
+#define MENU_BAR_ITEMS_SPACE (12)
+#define SEPARATOR_HEIGHT (5)
+#define MENU_TAB_SPACE (8)
+
+/* Internal MenuTrackMenu() flags */
+#define TPM_INTERNAL            0xF0000000
+#define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
+#define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
+
+#define ITEM_PREV               -1
+#define ITEM_NEXT                1
+
 #define UpdateMenuItemState(state, change) \
 {\
   if((change) & MF_GRAYED) { \
@@ -133,6 +174,26 @@
   } \
 }
 
+PWND FASTCALL
+IntGetMSWND(PMENUSTATE pms)
+{
+   PWND pWnd = NULL;
+   if (pms)
+   {
+       if (pms->pGlobalPopupMenu->fIsTrackPopup)
+       {
+          pWnd = pms->pGlobalPopupMenu->spwndPopupMenu;
+       }
+       else if (pms->pGlobalPopupMenu->spwndNextPopup)
+       {
+          pWnd = pms->pGlobalPopupMenu->spwndNextPopup;
+       }
+       else
+          pWnd = pms->pGlobalPopupMenu->spwndActivePopup;
+   }
+   return pWnd;
+}
+
 PMENU FASTCALL
 IntGetMenuObject(HMENU hMenu)
 {
@@ -269,6 +330,47 @@
    return FALSE;
 }
 
+BOOL
+MenuInit(VOID)
+{
+  NONCLIENTMETRICSW ncm;
+
+  /* get the menu font */
+  if (!ghMenuFont || !ghMenuFontBold)
+  {
+    ncm.cbSize = sizeof(ncm);
+    if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+    {
+      ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
+      return FALSE;
+    }
+
+    ghMenuFont = GreCreateFontIndirectW(&ncm.lfMenuFont);
+    if (ghMenuFont == NULL)
+    {
+      ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
+      return FALSE;
+    }
+    ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+    ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont);
+    if (ghMenuFontBold == NULL)
+    {
+      ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
+      GreDeleteObject(ghMenuFont);
+      ghMenuFont = NULL;
+      return FALSE;
+    }
+    
+    GreSetObjectOwner(ghMenuFont, GDI_OBJ_HMGR_PUBLIC);
+    GreSetObjectOwner(ghMenuFontBold, GDI_OBJ_HMGR_PUBLIC);
+
+    co_IntSetupOBM();
+  }
+
+  return TRUE;
+}
+
+
 /**********************************************************************
  *		MENU_depth
  *
@@ -355,6 +457,45 @@
     return fallback;
 }
 
+/***********************************************************************
+ *           MenuFindSubMenu
+ *
+ * Find a Sub menu. Return the position of the submenu, and modifies
+ * *hmenu in case it is found in another sub-menu.
+ * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
+ */
+static UINT FASTCALL MENU_FindSubMenu(PMENU *menu, PMENU SubTarget )
+{
+    UINT i;
+    PITEM item;
+
+    item = ((PMENU)*menu)->rgItems;
+    for (i = 0; i < ((PMENU)*menu)->cItems; i++, item++)
+    {
+        if (!item->spSubMenu)
+           continue;
+        else
+        {
+           if (item->spSubMenu == SubTarget)
+           {
+              return i;
+           }
+           else 
+           {
+              PMENU pSubMenu = item->spSubMenu;
+              UINT pos = MENU_FindSubMenu( &pSubMenu, SubTarget );
+              if (pos != NO_SELECTED_ITEM)
+              {
+                  *menu = pSubMenu;
+                  return pos;
+              }
+           }
+        }
+    }
+    return NO_SELECTED_ITEM;
+}
+
+
 BOOL FASTCALL
 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
 {
@@ -1019,29 +1160,8 @@
    return res;
 }
 
-BOOL FASTCALL
-IntHiliteMenuItem(PWND WindowObject,
-                  PMENU MenuObject,
-                  UINT uItemHilite,
-                  UINT uHilite)
-{
-   PITEM MenuItem;
 
-   if (!(MenuItem = MENU_FindItem( &MenuObject, &uItemHilite, uHilite ))) return FALSE;
 
-   if (uHilite & MF_HILITE)
-   {
-      MenuItem->fState |= MF_HILITE;
-   }
-   else
-   {
-      MenuItem->fState &= ~MF_HILITE;
-   }
-   /* FIXME: Update the window's menu */
-
-   return TRUE; // Always returns true!!!!
-}
-
 BOOL FASTCALL
 UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos)
 {
@@ -1116,7 +1236,1957 @@
    return ( fByPos ) ? i : MenuItem->wID;
 }
 
+PMENU
+FASTCALL
+co_IntGetSubMenu(
+  PMENU pMenu,
+  int nPos)
+{
+  PITEM pItem;
+  if (!(pItem = MENU_FindItem( &pMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
+
+  if (pItem->spSubMenu)
+  {
+     return pItem->spSubMenu;
+  }
+  return NULL;
+}
+
+/***********************************************************************
+ *           MenuInitSysMenuPopup
+ *
+ * Grey the appropriate items in System menu.
+ */
+void FASTCALL MENU_InitSysMenuPopup(PMENU menu, DWORD style, DWORD clsStyle, LONG HitTest )
+{
+    BOOL gray;
+    UINT DefItem;
+
+    gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
+    IntEnableMenuItem( menu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = ((style & WS_MAXIMIZE) != 0);
+    IntEnableMenuItem( menu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
+    IntEnableMenuItem( menu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
+    IntEnableMenuItem( menu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
+    IntEnableMenuItem( menu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = (clsStyle & CS_NOCLOSE) != 0;
+
+    /* The menu item must keep its state if it's disabled */
+    if(gray)
+        IntEnableMenuItem( menu, SC_CLOSE, MF_GRAYED);
+
+    /* Set default menu item */
+    if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
+    else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
+    else DefItem = SC_CLOSE;
+
+    UserSetMenuDefaultItem(menu, DefItem, MF_BYCOMMAND);
+}
+
+
+/***********************************************************************
+ *           MenuDrawPopupGlyph
+ *
+ * Draws popup magic glyphs (can be found in system menu).
+ */
+static void FASTCALL
+MENU_DrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
+{
+  LOGFONTW lf;
+  HFONT hFont, hOldFont;
+  COLORREF clrsave;
+  INT bkmode;
+  WCHAR symbol;
+  switch (popupMagic)
+  {
+  case (INT_PTR) HBMMENU_POPUP_RESTORE:
+    symbol = '2';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+    symbol = '0';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+    symbol = '1';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_CLOSE:
+    symbol = 'r';
+    break;
+  default:
+    ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
+    return;
+  }
+  RtlZeroMemory(&lf, sizeof(LOGFONTW));
+  RECTL_vInflateRect(r, -2, -2);
+  lf.lfHeight = r->bottom - r->top;
+  lf.lfWidth = 0;
+  lf.lfWeight = FW_NORMAL;
+  lf.lfCharSet = DEFAULT_CHARSET;
+  RtlCopyMemory(lf.lfFaceName, L"Marlett", sizeof(L"Marlett"));
+  hFont = GreCreateFontIndirectW(&lf);
+  /* save font and text color */
+  hOldFont = NtGdiSelectFont(dc, hFont);
+  clrsave = GreGetTextColor(dc);
+  bkmode = GreGetBkMode(dc);
+  /* set color and drawing mode */
+  IntGdiSetBkMode(dc, TRANSPARENT);
+  if (inactive)
+  {
+    /* draw shadow */
+    if (!hilite)
+    {
+      IntGdiSetTextColor(dc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
+      GreTextOutW(dc, r->left + 1, r->top + 1, &symbol, 1);
+    }
+  }
+  IntGdiSetTextColor(dc, IntGetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
+  /* draw selected symbol */
+  GreTextOutW(dc, r->left, r->top, &symbol, 1);
+  /* restore previous settings */
+  IntGdiSetTextColor(dc, clrsave);
+  NtGdiSelectFont(dc, hOldFont);
+  IntGdiSetBkMode(dc, bkmode);
+  GreDeleteObject(hFont);
+}
+
+/***********************************************************************
+ *           MENU_AdjustMenuItemRect
+ *
+ * Adjust menu item rectangle according to scrolling state.
+ */
 VOID FASTCALL
+MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
+{
+    if (menu->dwArrowsOn)
+    {
+        UINT arrow_bitmap_height;
+        arrow_bitmap_height = gpsi->oembmi[OBI_UPARROW].cy; ///// Menu up arrow! OBM_UPARROW
+        rect->top += arrow_bitmap_height - menu->iTop;
+        rect->bottom += arrow_bitmap_height - menu->iTop;
+    }
+}
+
+/***********************************************************************
+ *           MENU_FindItemByCoords
+ *
+ * Find the item at the specified coordinates (screen coords). Does
+ * not work for child windows and therefore should not be called for
+ * an arbitrary system menu.
+ */
+//static
+ITEM *MENU_FindItemByCoords( MENU *menu, POINT pt, UINT *pos )
+{
+    ITEM *item;
+    UINT i;
+    RECT rect;
+    PWND pWnd = ValidateHwndNoErr(menu->hWnd);
+
+    if (!IntGetWindowRect(pWnd, &rect)) return NULL;
+    if (pWnd->ExStyle & WS_EX_LAYOUTRTL)
+       pt.x = rect.right - 1 - pt.x;
+    else
+       pt.x -= rect.left;
+    pt.y -= rect.top;
+    item = menu->rgItems;
+    for (i = 0; i < menu->cItems; i++, item++)
+    {
+        //rect = item->rect;
+        rect.left   = item->xItem;
+        rect.top    = item->yItem; 
+        rect.right  = item->cxItem; // Do this for now......
+        rect.bottom = item->cyItem;
+
+        MENU_AdjustMenuItemRect(menu, &rect);
+	if (RECTL_bPointInRect(&rect, pt.x, pt.y))
+	{
+	    if (pos) *pos = i;
+	    return item;
+	}
+    }
+    return NULL;
+}
+
+INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen)
+{
+    MENU *menu = UserGetMenuObject(hMenu);
+    UINT pos;
+
+    /*FIXME: Do we have to handle hWnd here? */
+    if (!menu) return -1;
+    if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
+    return pos;
+}
+
+/***********************************************************************
+ *           MenuFindItemByKey
+ *
+ * Find the menu item selected by a key press.
+ * Return item id, -1 if none, -2 if we should close the menu.
+ */
+//static
+UINT FASTCALL MENU_FindItemByKey(PWND WndOwner, PMENU menu,
+                  WCHAR Key, BOOL ForceMenuChar)
+{
+  LRESULT MenuChar;
+  WORD Flags = 0;
+
+  TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, menu );
+
+  if (!menu || !VerifyMenu(menu))
+     menu = co_IntGetSubMenu( UserGetMenuObject(WndOwner->SystemMenu), 0 );
+  if (menu)
+  {
+     ITEM *item = menu->rgItems;
+
+     if ( !ForceMenuChar )
+     {
+        UINT i;
+        BOOL cjk = UserGetSystemMetrics( SM_DBCSENABLED );
+
+        for (i = 0; i < menu->cItems; i++, item++)
+        {
+           LPWSTR text = item->Xlpstr;
+           if( text)
+           {
+              const WCHAR *p = text - 2;
+              do
+              {
+                 const WCHAR *q = p + 2;
+                 p = wcschr (q, '&');
+                 if (!p && cjk) p = wcschr (q, '\036'); /* Japanese Win16 */
+              }
+              while (p != NULL && p [1] == '&');
+              if (p && (towupper(p[1]) == towupper(Key))) return i;
+           }
+        }
+     }
+
+     Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
+     Flags |= menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0;
+
+     MenuChar = co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MENUCHAR,
+                              MAKEWPARAM(Key, Flags), (LPARAM) UserHMGetHandle(menu));
+     if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+     if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
+  }
+  return (UINT)(-1);
+}
+
+/***********************************************************************
+ *           MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
+ */
+static void FASTCALL MENU_GetBitmapItemSize(PITEM lpitem, SIZE *size, PWND WndOwner)
+{
+    BITMAP bm;
+    HBITMAP bmp = lpitem->hbmp;
+
+    size->cx = size->cy = 0;
+
+    /* check if there is a magic menu item associated with this item */
+    if (IS_MAGIC_BITMAP(bmp))
+    {
+      switch((INT_PTR) bmp)
+        {
+            case (INT_PTR)HBMMENU_CALLBACK:
+            {
+                MEASUREITEMSTRUCT measItem;
+                measItem.CtlType = ODT_MENU;
+                measItem.CtlID = 0;
+                measItem.itemID = lpitem->wID;
+                measItem.itemWidth = lpitem->cxItem - lpitem->xItem; //lpitem->Rect.right - lpitem->Rect.left;
+                measItem.itemHeight = lpitem->cyItem - lpitem->yItem;//lpitem->Rect.bottom - lpitem->Rect.top;
+                measItem.itemData = lpitem->dwItemData;
+                co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
+                size->cx = measItem.itemWidth;
+                size->cy = measItem.itemHeight;
+                return;
+            }
+            break;
+
+          case (INT_PTR) HBMMENU_SYSTEM:
+            if (lpitem->dwItemData)
+              {
+                bmp = (HBITMAP) lpitem->dwItemData;
+                break;
+              }
+            /* fall through */
+          case (INT_PTR) HBMMENU_MBAR_RESTORE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+            /* FIXME: Why we need to subtract these magic values? */
+            /* to make them smaller than the menu bar? */
+            size->cx = UserGetSystemMetrics(SM_CXSIZE) - 2;
+            size->cy = UserGetSystemMetrics(SM_CYSIZE) - 4;
+            return;
+        }
+    }
+
+    if (GreGetObject(bmp, sizeof(BITMAP), &bm))
+    {
+        size->cx = bm.bmWidth;
+        size->cy = bm.bmHeight;
+    }
+}
+
+/***********************************************************************
+ *           MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
+ */
+static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect,
+                    PMENU Menu, PWND WndOwner, UINT odaction, BOOL MenuBar)
+{
+    BITMAP bm;
+    DWORD rop;
+    HDC hdcMem;
+    HBITMAP bmp;
+    int w = rect->right - rect->left;
+    int h = rect->bottom - rect->top;
+    int bmp_xoffset = 0;
+    int left, top;
+    HBITMAP hbmToDraw = lpitem->hbmp;
+    bmp = hbmToDraw;
+
+    /* Check if there is a magic menu item associated with this item */
+    if (IS_MAGIC_BITMAP(hbmToDraw))
+    {
+        UINT flags = 0;
+        RECT r;
+
+      r = *rect;
+      switch ((INT_PTR)hbmToDraw)
+      {
+        case (INT_PTR)HBMMENU_SYSTEM:
+            if (lpitem->dwItemData)
+            {
+                bmp = (HBITMAP)lpitem->dwItemData;
+                if (!GreGetObject( bmp, sizeof(bm), &bm )) return;
+            }
+            else
+            {
+                PCURICON_OBJECT pIcon = NULL;
+                //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+                //bmp = BmpSysMenu;
+                //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
+                /* only use right half of the bitmap */
+                //bmp_xoffset = bm.bmWidth / 2;
+                //bm.bmWidth -= bmp_xoffset;
+                if (WndOwner)
+                {
+                    pIcon = NC_IconForWindow(WndOwner);
+                    // FIXME: NC_IconForWindow should reference it for us */
+                    if (pIcon) UserReferenceObject(pIcon);
+                }
+
+                if (pIcon)
+                {
+                   LONG cx = UserGetSystemMetrics(SM_CXSMICON);
+                   LONG cy = UserGetSystemMetrics(SM_CYSMICON);
+                   LONG x = rect->left - cx/2 + 1 + (rect->bottom - rect->top)/2; // this is really what Window does
+                   LONG y = (rect->top + rect->bottom)/2 - cy/2; // center
+                   UserDrawIconEx(hdc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
+                   UserDereferenceObject(pIcon);
+                 }
+                 return;
+            }
+            goto got_bitmap;
+        case (INT_PTR)HBMMENU_MBAR_RESTORE:
+            flags = DFCS_CAPTIONRESTORE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
+            r.right += 1;
+            flags = DFCS_CAPTIONMIN;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
+            r.right += 1;
+            flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_CLOSE:
+            flags = DFCS_CAPTIONCLOSE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
+            flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+            break;
+        case (INT_PTR)HBMMENU_CALLBACK:
+            {
+                DRAWITEMSTRUCT drawItem;
+                POINT origorg;
+                drawItem.CtlType = ODT_MENU;
+                drawItem.CtlID = 0;
+                drawItem.itemID = lpitem->wID;
+                drawItem.itemAction = odaction;
+                drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
+                drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
+                drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
+                drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
+                drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
+                drawItem.itemState |= (!(Menu->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
+                drawItem.itemState |= (Menu->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
+                drawItem.hwndItem = (HWND)UserHMGetHandle(Menu);
+                drawItem.hDC = hdc;
+                drawItem.rcItem = *rect;
+                drawItem.itemData = lpitem->dwItemData;
+                /* some applications make this assumption on the DC's origin */
+                GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg);
+                RECTL_vOffsetRect( &drawItem.rcItem, - lpitem->xItem, - lpitem->yItem);
+                co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem);
+                GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+                return;
+            }
+            break;
+
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+            MENU_DrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
+            return;
+      }
+      RECTL_vInflateRect(&r, -1, -1);
+      if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
+      DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
+      return;
+    }
+
+    if (!bmp || !GreGetObject( bmp, sizeof(bm), &bm )) return;
+
+ got_bitmap:
+    hdcMem = NtGdiCreateCompatibleDC( hdc );
+    NtGdiSelectBitmap( hdcMem, bmp );
+
+    /* handle fontsize > bitmap_height */
+    top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
+    left=rect->left;
+    rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
+    if ((lpitem->fState & MF_HILITE) && lpitem->hbmp)
+        IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
+    NtGdiBitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop , 0, 0);
+    IntGdiDeleteDC( hdcMem, FALSE );
+}
+
+DWORD FASTCALL IntGetCharDimensions(HDC hdc, PTEXTMETRICW ptm, PDWORD height);
+
+LONG
+IntGetDialogBaseUnits(VOID)
+{
+    static DWORD units;
+
+    if (!units)
+    {
+        HDC hdc;
+        SIZE size;
+
+        if ((hdc = UserGetDCEx(NULL, NULL, DCX_CACHE)))
+        {
+            size.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&size.cy );
+            if (size.cx) units = MAKELONG( size.cx, size.cy );
+            UserReleaseDC( 0, hdc, FALSE);
+        }
+    }
+    return units;
+}
+
+
+/***********************************************************************
+ *           MenuCalcItemSize
+ *
+ * Calculate the size of the menu item and store it in lpitem->rect.
+ */
+static void FASTCALL MENU_CalcItemSize( HDC hdc, PITEM lpitem, PMENU Menu, PWND pwndOwner,
+                 INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
+{
+    WCHAR *p;
+    UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
+    UINT arrow_bitmap_width;
+    RECT Rect;
+    INT itemheight = 0;
+
+    TRACE("dc=%x owner=%x (%d,%d)\n", hdc, pwndOwner, orgX, orgY);
+
+    arrow_bitmap_width = gpsi->oembmi[OBI_MNARROW].cx;
+
+    MenuCharSize.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&MenuCharSize.cy );
+
+    RECTL_vSetRect( &Rect, orgX, orgY, orgX, orgY );
+
+    if (lpitem->fType & MF_OWNERDRAW)
+    {
+        MEASUREITEMSTRUCT mis;
+        mis.CtlType    = ODT_MENU;
+        mis.CtlID      = 0;
+        mis.itemID     = lpitem->wID;
+        mis.itemData   = lpitem->dwItemData;
+        mis.itemHeight = HIWORD( IntGetDialogBaseUnits());
+        mis.itemWidth  = 0;
+        co_IntSendMessage( UserHMGetHandle(pwndOwner), WM_MEASUREITEM, 0, (LPARAM)&mis );
+        /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
+         * width of a menufont character to the width of an owner-drawn menu. 
+         */
+        Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
+        if (menuBar) {
+            /* under at least win95 you seem to be given a standard
+               height for the menu and the height value is ignored */
+            Rect.bottom += UserGetSystemMetrics(SM_CYMENUSIZE);
+        } else
+            Rect.bottom += mis.itemHeight;
+        // Or this,
+        lpitem->cxBmp = mis.itemWidth;
+        lpitem->cyBmp = mis.itemHeight;
+        ERR("id=%04lx size=%dx%d cx %d cy %d\n",
+                lpitem->wID, Rect.right-Rect.left,
+                 Rect.bottom-Rect.top, MenuCharSize.cx, MenuCharSize.cy);
+/*
+        lpitem->xItem = Rect.left;
+        lpitem->yItem = Rect.top;
+        lpitem->cxItem = Rect.right;
+        lpitem->cyItem = Rect.bottom;
+ */
+        return;
+    }
+
+    lpitem->xItem  = orgX;
+    lpitem->yItem  = orgY; 
+    lpitem->cxItem = orgX;
+    lpitem->cyItem = orgY;
+
+    if (lpitem->fType & MF_SEPARATOR)
+    {
+        lpitem->cyItem += UserGetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
+        if( !menuBar)
+            lpitem->cxItem += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx;
+        return;
+    }
+
+    lpitem->dxTab = 0;
+
+    if (lpitem->hbmp)
+    {
+        SIZE size;
+
+        if (!menuBar) {
+            MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
+            /* Keep the size of the bitmap in callback mode to be able
+             * to draw it correctly */
+            lpitem->cxBmp = size.cx;
+            lpitem->cyBmp = size.cy;
+            Menu->cxTextAlign = max(Menu->cxTextAlign, size.cx);
+
+            lpitem->cxItem += size.cx + 2;
+            itemheight = size.cy + 2;
+
+            if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+                lpitem->cxItem += 2 * check_bitmap_width;
+            lpitem->cxItem += 4 + MenuCharSize.cx;
+            lpitem->dxTab = lpitem->cxItem;
+            lpitem->cxItem += arrow_bitmap_width;//check_bitmap_width;
+        } else /* hbmpItem & MenuBar */ {
+            MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
+            lpitem->cxItem  += size.cx;
+            if( lpitem->Xlpstr) lpitem->cxItem  += 2;
+            itemheight = size.cy;
+
+            /* Special case: Minimize button doesn't have a space behind it. */
+            if (lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+                lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+            lpitem->cxItem -= 1;
+        }
+    }
+    else if (!menuBar) {
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+             lpitem->cxItem += check_bitmap_width;
+        lpitem->cxItem += 4 + MenuCharSize.cx;
+        lpitem->dxTab = lpitem->cxItem;
+        lpitem->cxItem += check_bitmap_width;
+    }
+
+    /* it must be a text item - unless it's the system menu */
+    if (!(lpitem->fType & MF_SYSMENU) && lpitem->Xlpstr) {
+        HFONT hfontOld = NULL;
+        RECT rc;// = lpitem->Rect;
+        LONG txtheight, txtwidth;
+
+        rc.left   = lpitem->xItem;
+        rc.top    = lpitem->yItem; 
+        rc.right  = lpitem->cxItem; // Do this for now......
+        rc.bottom = lpitem->cyItem;
+
+        if ( lpitem->fState & MFS_DEFAULT ) {
+            hfontOld = NtGdiSelectFont( hdc, ghMenuFontBold );
+        }
+        if (menuBar) {
+            txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc, DT_SINGLELINE|DT_CALCRECT); 
+
+            lpitem->cxItem  += rc.right - rc.left;
+            itemheight = max( max( itemheight, txtheight), UserGetSystemMetrics( SM_CYMENU) - 1);
+
+            lpitem->cxItem +=  2 * MenuCharSize.cx;
+        } else {
+            if ((p = wcschr( lpitem->Xlpstr, '\t' )) != NULL) {
+                RECT tmprc = rc;
+                LONG tmpheight;
+                int n = (int)( p - lpitem->Xlpstr);
+                /* Item contains a tab (only meaningful in popup menus) */
+                /* get text size before the tab */
+                txtheight = DrawTextW( hdc, lpitem->Xlpstr, n, &rc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                txtwidth = rc.right - rc.left;
+                p += 1; /* advance past the Tab */
+                /* get text size after the tab */
+                tmpheight = DrawTextW( hdc, p, -1, &tmprc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                lpitem->dxTab += txtwidth;
+                txtheight = max( txtheight, tmpheight);
+                txtwidth += MenuCharSize.cx + /* space for the tab */
+                    tmprc.right - tmprc.left; /* space for the short cut */
+            } else {
+                txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                txtwidth = rc.right - rc.left;
+                lpitem->dxTab += txtwidth;
+            }
+            lpitem->cxItem  += 2 + txtwidth;
+            itemheight = max( itemheight,
+				    max( txtheight + 2, MenuCharSize.cy + 4));
+        }
+        if (hfontOld) NtGdiSelectFont (hdc, hfontOld);
+    } else if( menuBar) {
+        itemheight = max( itemheight, UserGetSystemMetrics(SM_CYMENU)-1);
+    }
+    lpitem->cyItem += itemheight;
+    TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->xItem, lpitem->yItem, lpitem->cxItem, lpitem->cyItem);
+}
+
+/***********************************************************************
+ *           MENU_GetMaxPopupHeight
+ */
+static UINT
+MENU_GetMaxPopupHeight(PMENU lppop)
+{
+    if (lppop->cyMax)
+    {
+       //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
+       return lppop->cyMax;
+    }
+    //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
+    return UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER);
+}
+
+/***********************************************************************
+ *           MenuPopupMenuCalcSize
+ *
+ * Calculate the size of a popup menu.
+ */
+//static
+void FASTCALL MENU_PopupMenuCalcSize(PMENU Menu, PWND WndOwner)
+{
+    PITEM lpitem;
+    HDC hdc;
+    int start, i;
+    int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
+    BOOL textandbmp = FALSE;
+
+    Menu->cxMenu = Menu->cyMenu = 0;
+    if (Menu->cItems == 0) return;
+
+    hdc = UserGetDCEx(NULL, NULL, DCX_CACHE);
+    NtGdiSelectFont( hdc, ghMenuFont );
+
+    start = 0;
+    maxX = 2 + 1;
+
+    Menu->cxTextAlign = 0;
+
+    while (start < Menu->cItems)
+    {
+      lpitem = &Menu->rgItems[start];
+      orgX = maxX;
+      //if( lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+      //    orgX += MENU_COL_SPACE;
+      orgY = MENU_TOP_MARGIN;
+
+      maxTab = maxTabWidth = 0;
+      /* Parse items until column break or end of menu */
+      for (i = start; i < Menu->cItems; i++)//, lpitem++)
+      {
+          if (i != start &&
+               (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+          MENU_CalcItemSize(hdc, lpitem, Menu, WndOwner, orgX, orgY, FALSE, textandbmp);
+          maxX = max(maxX, lpitem->cxItem);
+          orgY = lpitem->cyItem;
+          if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab )
+          {
+              maxTab = max( maxTab, lpitem->dxTab );
+              maxTabWidth = max(maxTabWidth, lpitem->cxItem - lpitem->dxTab);
+          }
+          if( lpitem->Xlpstr && lpitem->hbmp) textandbmp = TRUE;
+      }
+
+        /* Finish the column (set all items to the largest width found) */
+      maxX = max( maxX, maxTab + maxTabWidth );
+      for (lpitem = &Menu->rgItems[start]; start < i; start++, lpitem++)
+      {
+          lpitem->cxItem = maxX;
+           if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab)
+               lpitem->dxTab = maxTab;
+      }
+      Menu->cyMenu = max(Menu->cyMenu, orgY);
+    }
+
+    Menu->cxMenu  = maxX;
+    /* if none of the items have both text and bitmap then
+     * the text and bitmaps are all aligned on the left. If there is at
+     * least one item with both text and bitmap then bitmaps are
+     * on the left and texts left aligned with the right hand side
+     * of the bitmaps */
+    if( !textandbmp) Menu->cxTextAlign = 0;
+
+    /* space for 3d border */
+    Menu->cyMenu += MENU_BOTTOM_MARGIN;
+    Menu->cxMenu += 2;
+
+    /* Adjust popup height if it exceeds maximum */
+    maxHeight = MENU_GetMaxPopupHeight(Menu);
+    Menu->iMaxTop = Menu->cyMenu - MENU_TOP_MARGIN;
+    if (Menu->cyMenu >= maxHeight)
+    {
+       Menu->cyMenu = maxHeight;
+       Menu->dwArrowsOn = 1;
+    }
+    else
+    {   
+       Menu->dwArrowsOn = 0;
+    }
+
+    UserReleaseDC( 0, hdc, FALSE );
+}
+
+/***********************************************************************
+ *           MENU_MenuBarCalcSize
+ *
+ * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
+ * Calculate the size of the menu bar.
+ */
+static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwndOwner )
+{
+    ITEM *lpitem;
+    UINT start, i, helpPos;
+    int orgX, orgY, maxY;
+
+    if ((lprect == NULL) || (lppop == NULL)) return;
+    if (lppop->cItems == 0) return;
+    //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
+    lppop->cxMenu  = lprect->right - lprect->left;
+    lppop->cyMenu = 0;
+    maxY = lprect->top+1;
+    start = 0;
+    helpPos = ~0U;
+    lppop->cxTextAlign = 0;
+    while (start < lppop->cItems)
+    {
+	lpitem = &lppop->rgItems[start];
+	orgX = lprect->left;
+	orgY = maxY;
+
+	  /* Parse items until line break or end of menu */
+	for (i = start; i < lppop->cItems; i++, lpitem++)
+	{
+	    if ((helpPos == ~0U) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
+	    if ((i != start) &&
+		(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+	    TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY );
+	    //debug_print_menuitem ("  item: ", lpitem, "");
+	    //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
+            MENU_CalcItemSize(hdc, lpitem, lppop, pwndOwner, orgX, orgY, TRUE, FALSE);
+
+	    if (lpitem->cxItem > lprect->right)
+	    {
+		if (i != start) break;
+		else lpitem->cxItem = lprect->right;
+	    }
+	    maxY = max( maxY, lpitem->cyItem );
+	    orgX = lpitem->cxItem;
+	}
+
+	  /* Finish the line (set all items to the largest height found) */
+	while (start < i) lppop->rgItems[start++].cyItem = maxY;
+    }
+
+    lprect->bottom = maxY;
+    lppop->cyMenu = lprect->bottom - lprect->top;
+
+    /* Flush right all items between the MF_RIGHTJUSTIFY and */
+    /* the last item (if several lines, only move the last line) */
+    if (helpPos == ~0U) return;
+    lpitem = &lppop->rgItems[lppop->cItems-1];
+    orgY = lpitem->yItem;
+    orgX = lprect->right;
+    for (i = lppop->cItems - 1; i >= helpPos; i--, lpitem--) {
+        if (lpitem->yItem != orgY) break;	/* Other line */
+        if (lpitem->cxItem >= orgX) break;	/* Too far right already */
+        lpitem->xItem += orgX - lpitem->cxItem;
+        lpitem->cxItem = orgX;
+        orgX = lpitem->xItem;
+    }
+}
+
+/***********************************************************************
+ *           MENU_DrawScrollArrows
+ *
+ * Draw scroll arrows.
+ */
+static void
+MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
+{
+    //HDC hdcMem = NtGdiCreateCompatibleDC(hdc);
+    //HBITMAP hOrigBitmap;
+    UINT arrow_bitmap_width, arrow_bitmap_height;
+    //BITMAP bmp;
+    RECT rect, dfcrc;
+
+    //GreGetObject(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
+    arrow_bitmap_width  = gpsi->oembmi[OBI_DNARROW].cx;
+    arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
+
+/*    if (lppop->iTop)
+        hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
+    else
+        hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
+*/
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = lppop->cxMenu;
+    rect.bottom = arrow_bitmap_height;
+    FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
+/*
+    NtGdiBitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
+           arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY, 0,0);
+ */
+    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
+    dfcrc.top = 0;
+    dfcrc.right = arrow_bitmap_width;
+    dfcrc.bottom = arrow_bitmap_height;
+    DrawFrameControl(hdc, &dfcrc, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
+
+    rect.top = lppop->cyMenu - arrow_bitmap_height;
+    rect.bottom = lppop->cyMenu;
+
+    FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
+/*
+    if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
+        SelectObject(hdcMem, get_down_arrow_bitmap());
+    else
+        SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
+    NtGdiBitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
+           lppop->cyMenu - arrow_bitmap_height,
+           arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY, 0,0);
+ */
+    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
+    dfcrc.top = lppop->cyMenu - arrow_bitmap_height;
+    dfcrc.right = arrow_bitmap_width;
+    dfcrc.bottom = arrow_bitmap_height;
+    DrawFrameControl(hdc, &dfcrc, DFC_MENU,
+       ((lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)) ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWDOWN);
+
+    //SelectObject(hdcMem, hOrigBitmap);
+    //IntGdiDeleteDC(hdcMem, FALSE);
+}
+
+/***********************************************************************
+ *           draw_popup_arrow
+ *
+ * Draws the popup-menu arrow.
+ */
+static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
+        UINT arrow_bitmap_height)
+{
+    RECT dfcrc;
+    /*HDC hdcMem = NtGdiCreateCompatibleDC( hdc );
+    HBITMAP hOrigBitmap;
+
+    //hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
+    NtGdiBitBlt( hdc, rect.right - arrow_bitmap_width - 1,
+            (rect.top + rect.bottom - arrow_bitmap_height) / 2,
+            arrow_bitmap_width, arrow_bitmap_height,
+            hdcMem, 0, 0, SRCCOPY, 0,0 );
+    SelectObject( hdcMem, hOrigBitmap );*/
+
+    dfcrc.left = rect.right - arrow_bitmap_width - 1;
+    dfcrc.top = (rect.top + rect.bottom - arrow_bitmap_height) / 2;
+    dfcrc.right = arrow_bitmap_width;
+    dfcrc.bottom = arrow_bitmap_height;    
+    DrawFrameControl(hdc, &dfcrc, DFC_MENU, DFCS_MENUARROW);
+    //IntGdiDeleteDC( hdcMem, FALSE );
+}
+
+/***********************************************************************
+ *           MenuDrawMenuItem
+ *
+ * Draw a single menu item.
+ */
+static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC hdc,
+                 PITEM lpitem, UINT Height, BOOL menuBar, UINT odaction)
+{
+    RECT rect;
+    PWCHAR Text;
+    BOOL flat_menu = FALSE;
+    int bkgnd;
+    UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
+
+    if (!menuBar) {
+        arrow_bitmap_width  = gpsi->oembmi[OBI_MNARROW].cx; 
+        arrow_bitmap_height = gpsi->oembmi[OBI_MNARROW].cy;
+    }
+
+    if (lpitem->fType & MF_SYSMENU)
+    {
+        if ( (Wnd->style & WS_MINIMIZE))
+        {
+          UserGetInsideRectNC(Wnd, &rect);
+          UserDrawSysMenuButton(Wnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
+	}
+        return;
+    }
+
+    UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0);
+    bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
+  
+    /* Setup colors */
+
+    if (lpitem->fState & MF_HILITE)
+    {
+        if(menuBar && !flat_menu) {
+            IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_MENUTEXT));
+            IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_MENU));
+        } else {
+            if (lpitem->fState & MF_GRAYED)
+                IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_GRAYTEXT));
+            else
+                IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
+            IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
+        }
+    }
+    else
+    {
+        if (lpitem->fState & MF_GRAYED)
+            IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_GRAYTEXT ) );
+        else
+            IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_MENUTEXT ) );
+        IntGdiSetBkColor( hdc, IntGetSysColor( bkgnd ) );
+    }
+
+    //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
+    //rect = lpitem->Rect;
+    rect.left   = lpitem->xItem;
+    rect.top    = lpitem->yItem; 
+    rect.right  = lpitem->cxItem; // Do this for now......
+    rect.bottom = lpitem->cyItem;
+
+    MENU_AdjustMenuItemRect(Menu, &rect);
+
+    if (lpitem->fType & MF_OWNERDRAW)
+    {
+        /*
+        ** Experimentation under Windows reveals that an owner-drawn
+        ** menu is given the rectangle which includes the space it requested
+        ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
+        ** and a popup-menu arrow.  This is the value of lpitem->rect.
+        ** Windows will leave all drawing to the application except for
+        ** the popup-menu arrow.  Windows always draws that itself, after
+        ** the menu owner has finished drawing.
+        */
+        DRAWITEMSTRUCT dis;
+
+        dis.CtlType   = ODT_MENU;
+        dis.CtlID     = 0;
+        dis.itemID    = lpitem->wID;
+        dis.itemData  = (DWORD)lpitem->dwItemData;
+        dis.itemState = 0;
+        if (lpitem->fState & MF_CHECKED)  dis.itemState |= ODS_CHECKED;
+        if (lpitem->fState & MF_DEFAULT)  dis.itemState |= ODS_DEFAULT;
+        if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
+        if (lpitem->fState & MF_GRAYED)   dis.itemState |= ODS_GRAYED | ODS_DISABLED;
+        if (lpitem->fState & MF_HILITE)   dis.itemState |= ODS_SELECTED;
+        if (!(Menu->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
+        if (Menu->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
+        dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
+        dis.hwndItem   = (HWND) UserHMGetHandle(Menu);
+        dis.hDC        = hdc;
+        dis.rcItem     = rect;
+        TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
+	        "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd,
+	        dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
+	        dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
+	        dis.rcItem.bottom);
+        co_IntSendMessage(UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM) &dis);
+        /* Draw the popup-menu arrow */
+        if (lpitem->spSubMenu)
+        {
+           /* RECT rectTemp;
+            CopyRect(&rectTemp, &rect);
+            rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK);
+            DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+            */
+            draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
+        }
+        return;
+    }
+
+    if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
+
+    if (lpitem->fState & MF_HILITE)
+    {
+        if (flat_menu)
+        {
+            RECTL_vInflateRect (&rect, -1, -1);
+            FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENUHILIGHT));
+            RECTL_vInflateRect (&rect, 1, 1);
+            FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
+        }
+        else
+        {
+            if(menuBar)
+                DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
+            else
+                FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
+        }
+    }
+    else
+        FillRect( hdc, &rect, IntGetSysColorBrush(bkgnd) );
+
+    IntGdiSetBkMode( hdc, TRANSPARENT );
+
+    /* vertical separator */
+    if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
+    {
+        HPEN oldPen;
+        RECT rc = rect;
+
+        rc.left -= 3;//MENU_COL_SPACE / 2 + 1;
+        rc.top = 3;
+        rc.bottom = Height - 3;
+        if (flat_menu)
+        {
+            oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
+            IntSetDCPenColor(hdc, IntGetSysColor(COLOR_BTNSHADOW));
+            GreMoveTo( hdc, rc.left, rc.top, NULL );
+            NtGdiLineTo( hdc, rc.left, rc.bottom );
+            NtGdiSelectPen( hdc, oldPen );
+        }
+        else
+            DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
+    }
+
+    /* horizontal separator */
+    if (lpitem->fType & MF_SEPARATOR)
+    {
+        HPEN oldPen;
+        RECT rc = rect;
+
+        rc.left++;
+        rc.right--;
+        rc.top += SEPARATOR_HEIGHT / 2;
+        if (flat_menu)
+        {
+            oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
+            IntSetDCPenColor( hdc, IntGetSysColor(COLOR_BTNSHADOW));
+            GreMoveTo( hdc, rc.left, rc.top, NULL );
+            NtGdiLineTo( hdc, rc.right, rc.top );
+            NtGdiSelectPen( hdc, oldPen );
+        }
+        else
+            DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
+        return;
+    }
+
+#if 0
+    /* helper lines for debugging */
+    /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
+    FrameRect(hdc, &rect, NtGdiGetStockObject(BLACK_BRUSH));
+    NtGdiSelectPen(hdc, NtGdiGetStockObject(DC_PEN));
+    IntSetDCPenColor(hdc, IntGetSysColor(COLOR_WINDOWFRAME));
+    GreMoveTo(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
+    NtGdiLineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
+#endif
+
+    if (!menuBar)
+    {
+        HBITMAP bm;
+        INT y = rect.top + rect.bottom;
+        RECT rc = rect;
+        BOOL checked = FALSE;
+        UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
+        UINT check_bitmap_height = UserGetSystemMetrics( SM_CYMENUCHECK );
+        /* Draw the check mark
+         *
+         * FIXME:
+         * Custom checkmark bitmaps are monochrome but not always 1bpp.
+         */
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) {
+            bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : 
+                lpitem->hbmpUnchecked;
+            if (bm)  /* we have a custom bitmap */
+            {
+                HDC hdcMem = NtGdiCreateCompatibleDC( hdc );
+
+                NtGdiSelectBitmap( hdcMem, bm );
+                NtGdiBitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
+                        check_bitmap_width, check_bitmap_height,
+                        hdcMem, 0, 0, SRCCOPY, 0,0);
+                IntGdiDeleteDC( hdcMem, FALSE );
+                checked = TRUE;
+            }
+            else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
+            {
+                RECT r;
+                //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
+                //HDC hdcMem = NtGdiCreateCompatibleDC( hdc );
+                //SelectObject( hdcMem, bm );
+                //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
+                //CopyRect(&r, &rect);
+                r = rect;
+                r.right = r.left + UserGetSystemMetrics(SM_CXMENUCHECK);
+                DrawFrameControl( hdc, &r, DFC_MENU,
+                                 (lpitem->fType & MFT_RADIOCHECK) ?
+                                 DFCS_MENUBULLET : DFCS_MENUCHECK);
+                //NtGdiBitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY, 0,0 );
+                //IntGdiDeleteDC( hdcMem, FALSE );
+                //DeleteObject( bm );
+                checked = TRUE;
+            }
+        }
+        if ( lpitem->hbmp )//&& !( checked && (Menu->dwStyle & MNS_CHECKORBMP)))
+        {
+            RECT bmpRect;
+            //CopyRect(&bmpRect, &rect);
+            bmpRect = rect;
+            if (!((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP) && !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+                bmpRect.left += check_bitmap_width + 2;
+            if (!(checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
+            {
+                //POINT origorg;
+                bmpRect.right = bmpRect.left + lpitem->cxBmp;
+                /* some applications make this assumption on the DC's origin */
+                //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+                MENU_DrawBitmapItem(hdc, lpitem, &bmpRect, Menu, WndOwner, odaction, menuBar);
+                //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+            }
+        }
+        /* Draw the popup-menu arrow */
+        if (lpitem->spSubMenu)
+        {
+           /* RECT rectTemp;
+            CopyRect(&rectTemp, &rect);
+            rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK);
+            DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+            */
+            draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
+        }
+        rect.left += 4;
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+            rect.left += check_bitmap_width;
+        rect.right -= arrow_bitmap_width;//check_bitmap_width;
+    }
+    else if( lpitem->hbmp)
+    { /* Draw the bitmap */
+        //POINT origorg;
+
+        //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+        MENU_DrawBitmapItem(hdc, lpitem, &rect, Menu, WndOwner, odaction, menuBar);
+        //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+    }
+
+    /* process text if present */
+    if (lpitem->Xlpstr)
+    {
+        int i = 0;
+        HFONT hfontOld = 0;
+
+        UINT uFormat = menuBar ?
+                       DT_CENTER | DT_VCENTER | DT_SINGLELINE :
+                       DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+
+        if (((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP))
+             rect.left += max(0, (int)(Menu->cxTextAlign - UserGetSystemMetrics(SM_CXMENUCHECK)));
+        else
+             rect.left += Menu->cxTextAlign;
+
+        if ( lpitem->fState & MFS_DEFAULT )
+        {
+            hfontOld = NtGdiSelectFont(hdc, ghMenuFontBold);
+        }
+
+        if (menuBar) {
+            if( lpitem->hbmp)
+              rect.left += lpitem->cxBmp;
+            if( !(lpitem->hbmp == HBMMENU_CALLBACK)) 
+              rect.left += MenuCharSize.cx;
+            rect.right -= MenuCharSize.cx;
+            //rect.left += MENU_BAR_ITEMS_SPACE / 2;
+            //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+        }
+
+        Text = lpitem->Xlpstr;
+        if(Text)
+        {
+            for (i = 0; L'\0' != Text[i]; i++)
+                if (Text[i] == L'\t' || Text[i] == L'\b')
+                    break;
+        }
+
+        if(lpitem->fState & MF_GRAYED)
+        {
+            if (!(lpitem->fState & MF_HILITE) )
+            {
+                ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+                IntGdiSetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+                DrawTextW( hdc, Text, i, &rect, uFormat );
+                --rect.left; --rect.top; --rect.right; --rect.bottom;
+	        }
+            IntGdiSetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+        }
+        DrawTextW( hdc, Text, i, &rect, uFormat);
+
+        /* paint the shortcut text */
+        if (!menuBar && L'\0' != Text[i])  /* There's a tab or flush-right char */
+        {
+            if (L'\t' == Text[i])
+            {
+                rect.left = lpitem->dxTab;
+                uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+            }
+            else
+            {
+                rect.right = lpitem->dxTab;
+                uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
+            }
+
+            if (lpitem->fState & MF_GRAYED)
+            {
+                if (!(lpitem->fState & MF_HILITE) )
+                {
+                    ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+                    IntGdiSetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+                    DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
+                    --rect.left; --rect.top; --rect.right; --rect.bottom;
+                }
+                IntGdiSetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+            }
+            DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
+        }
+
+        if (hfontOld)
+          NtGdiSelectFont (hdc, hfontOld);
+    }
+}
+
+/***********************************************************************
+ *           MenuDrawPopupMenu
+ *
+ * Paint a popup menu.
+ */
+static void FASTCALL MENU_DrawPopupMenu(PWND wnd, HDC hdc, PMENU menu )
+{
+    HBRUSH hPrevBrush = 0, brush = IntGetSysColorBrush(COLOR_MENU);
+    RECT rect;
+
+    TRACE("wnd=%p dc=%p menu=%p\n", wnd, hdc, menu);
+
+    IntGetClientRect( wnd, &rect );
+
+    if (menu && menu->hbrBack) brush = menu->hbrBack;
+    if((hPrevBrush = NtGdiSelectBrush( hdc, brush ))
+        && (NtGdiSelectFont( hdc, ghMenuFont)))
+    {
+        HPEN hPrevPen;
+
+        NtGdiRectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
+
+        hPrevPen = NtGdiSelectPen( hdc, NtGdiGetStockObject( NULL_PEN ) );
+        if ( hPrevPen )
+        {
+            BOOL flat_menu = FALSE;
+
+            UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0);
+            if (flat_menu)
+               FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_BTNSHADOW));
+            else
+               DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
+
+            //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
+            /* draw menu items */
+            if (menu && menu->cItems)
+            {
+                ITEM *item;
+                UINT u;
+
+                item = menu->rgItems;
+                for (u = menu->cItems; u > 0; u--, item++)
+                {
+                    MENU_DrawMenuItem(wnd, menu, menu->spwndNotify, hdc, item,
+                                         menu->cyMenu, FALSE, ODA_DRAWENTIRE);
+                }
+                /* draw scroll arrows */
+                if (menu->dwArrowsOn)
+                {
+                   MENU_DrawScrollArrows(menu, hdc);
+                }
+
+            }
+         } else
+         {
+             NtGdiSelectBrush( hdc, hPrevBrush );
+         }
+    }
+}
+
+/**********************************************************************
+ *         MENU_IsMenuActive
+ */
+PWND MENU_IsMenuActive(VOID)
+{
+   PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+   if (pti->pMenuState->pGlobalPopupMenu)
+   {
+      return IntGetMSWND(pti->pMenuState);
+   }
+   return NULL; // top_popup
+}
+
+/**********************************************************************
+ *         MENU_EndMenu
+ *
+ * Calls EndMenu() if the hwnd parameter belongs to the menu owner
+ *
+ * Does the (menu stuff) of the default window handling of WM_CANCELMODE
+ */
+void MENU_EndMenu( PWND pwnd )
+{
+    PPOPUPMENU top_popup_menu;
+    PMENUSTATE pms = pwnd->head.pti->pMenuState;
+    
+    top_popup_menu = pms->pGlobalPopupMenu;
+    if (top_popup_menu)
+    {
+    }
+/*
+    MENU *menu;
+    menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL;
+    if (menu && ( hwnd == menu->hWnd ||  hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) )
+       EndMenu();
+*/
+}
+
+DWORD WINAPI
+IntDrawMenuBarTemp(PWND pWnd, HDC hDC, LPRECT Rect, PMENU pMenu, HFONT Font)
+{
+  UINT i;
+  HFONT FontOld = NULL;
+  BOOL flat_menu = FALSE;
+
+  UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0);
+
+  if (!pMenu)
+  {
+      pMenu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+  }
+
+  if (!Font)
+  {
+      Font = ghMenuFont;
+  }
+
+  if (Rect == NULL || !pMenu)
+  {
+      return UserGetSystemMetrics(SM_CYMENU);
+  }
+
+  TRACE("(%x, %x, %p, %x, %x)\n", pWnd, hDC, Rect, pMenu, Font);
+
+  FontOld = NtGdiSelectFont(hDC, Font);
+
+  if (pMenu->cyMenu == 0)
+  {
+      MENU_MenuBarCalcSize(hDC, Rect, pMenu, pWnd);
+  }
+
+  Rect->bottom = Rect->top + pMenu->cyMenu;
+
+  FillRect(hDC, Rect, IntGetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+
+  NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+  IntSetDCPenColor(hDC, IntGetSysColor(COLOR_3DFACE));
+  GreMoveTo(hDC, Rect->left, Rect->bottom - 1, NULL);
+  NtGdiLineTo(hDC, Rect->right, Rect->bottom - 1);
+
+  if (pMenu->cItems == 0)
+  {
+      NtGdiSelectFont(hDC, FontOld);
+      return UserGetSystemMetrics(SM_CYMENU);
+  }
+
+  for (i = 0; i < pMenu->cItems; i++)
+  {
+      MENU_DrawMenuItem(pWnd, pMenu, pWnd, hDC, &pMenu->rgItems[i], pMenu->cyMenu, TRUE, ODA_DRAWENTIRE);
+  }
+
+  NtGdiSelectFont(hDC, FontOld);
+
+  return pMenu->cyMenu;
+}
+
+
+UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw )
+{
+    HFONT hfontOld = 0;
+    PMENU lppop = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+
+    if (lppop == NULL || lprect == NULL)
+    {
+        return UserGetSystemMetrics(SM_CYMENU);
+    }
+
+    if (suppress_draw)
+    {
+       hfontOld = NtGdiSelectFont(hDC, ghMenuFont);
+
+       MENU_MenuBarCalcSize(hDC, lprect, lppop, pWnd);
+
+       lprect->bottom = lprect->top + lppop->cyMenu;
+
+       if (hfontOld) NtGdiSelectFont( hDC, hfontOld);
+       return lppop->cyMenu;
+    }   
+    else
+    {
+       return IntDrawMenuBarTemp(pWnd, hDC, lprect, lppop, NULL);
+    }
+}
+
+/***********************************************************************
+ *           MENU_InitPopup
+ *   
+ * Popup menu initialization before WM_ENTERMENULOOP.
+ */
+static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags )
+{
+    PWND pWndCreated;
+    PPOPUPMENU pPopupMenu;
+    CREATESTRUCTW Cs;
+    LARGE_STRING WindowName;
+    UNICODE_STRING ClassName;
+    PCLS pcls;
+    DWORD ex_style = WS_EX_TOOLWINDOW;
+
+    TRACE("owner=%p hmenu=%p\n", pWndOwner, menu);
+
+    menu->spwndNotify = pWndOwner;
+
+    if (flags & TPM_LAYOUTRTL || pWndOwner->ExStyle & WS_EX_LAYOUTRTL)
+       ex_style = WS_EX_LAYOUTRTL;
+
+    ClassName.Buffer = WC_MENU;
+    ClassName.Length = 0;
+    pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
+    if (pcls == NULL)
+    {
+       ASSERT(FALSE);
+       return FALSE;
+    }
+
+    RtlZeroMemory(&WindowName, sizeof(WindowName));
+    RtlZeroMemory(&Cs, sizeof(Cs));
+    Cs.style = WS_POPUP;
+    Cs.dwExStyle = ex_style;
+    Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
+    Cs.lpszName = (LPCWSTR) &WindowName;
+    Cs.lpszClass = (LPCWSTR) &ClassName;
+    Cs.lpCreateParams = UserHMGetHandle(menu);
+
+    /* NOTE: In Windows, top menu popup is not owned. */
+    pWndCreated = IntCreateWindow(&Cs, &WindowName, pcls, pWndOwner, NULL, NULL, pWndOwner->head.rpdesk);
+
+    if( !pWndCreated ) return FALSE;
+
+    //
+    //  Setup pop up menu structure.
+    //
+    menu->hWnd = UserHMGetHandle(pWndCreated);
+
+    pPopupMenu = ((PMENUWND)pWndCreated)->ppopupmenu;
+    pPopupMenu->spwndActivePopup = pWndCreated; // top_popup = MenuInfo.Wnd or menu->hWnd
+    pPopupMenu->spwndNotify = pWndOwner;        // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
+    pPopupMenu->spmenu = menu;                  // top_popup_hmenu = hMenu
+
+    pPopupMenu->fIsTrackPopup = !!(flags & TPM_POPUPMENU);  // if TRUE, spwndPopupMenu should be set?
+    pPopupMenu->fIsSysMenu    = !!(flags & TPM_SYSTEM_MENU);
+    pPopupMenu->fNoNotify     = !!(flags & TPM_NONOTIFY);
+    pPopupMenu->fRightButton  = !!(flags & TPM_RIGHTBUTTON);
+    pPopupMenu->fSynchronous  = !!(flags & TPM_RETURNCMD);
+
+    if (pPopupMenu->fRightButton)
+       pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_RBUTTON) & 0x8000);
+    else
+       pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_LBUTTON) & 0x8000);
+
+    if (gpsi->aiSysMet[SM_MENUDROPALIGNMENT] ||
+        menu->fFlags & MNF_RTOL)
+    {
+       pPopupMenu->fDroppedLeft = TRUE;
+    }
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MenuShowPopup
+ *
+ * Display a popup menu.
+ */
+static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
+                              INT x, INT y, INT xanchor, INT yanchor )
+{
+    UINT width, height;
+    POINT pt;
+    PMONITOR monitor;
+    PWND pWnd;
+
+    TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
+          pwndOwner, menu, id, x, y, xanchor, yanchor);
+
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+        menu->iItem = NO_SELECTED_ITEM;
+    }
+
+    menu->dwArrowsOn = 0;
+    MENU_PopupMenuCalcSize(menu, pwndOwner);
+
+    /* adjust popup menu pos so that it fits within the desktop */
+
+    width = menu->cxMenu + UserGetSystemMetrics(SM_CXBORDER);
+    height = menu->cyMenu + UserGetSystemMetrics(SM_CYBORDER);
+
+    /* FIXME: should use item rect */
+    pt.x = x;
+    pt.y = y;
+    monitor = UserMonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
+
+    if (flags & TPM_LAYOUTRTL) 
+        flags ^= TPM_RIGHTALIGN;
+
+    if( flags & TPM_RIGHTALIGN ) x -= width;
+    if( flags & TPM_CENTERALIGN ) x -= width / 2;
+
+    if( flags & TPM_BOTTOMALIGN ) y -= height;
+    if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+
+    if( x + width > monitor->rcMonitor.right)
+    {
+        if( xanchor && x >= width - xanchor )
+            x -= width - xanchor;
+
+        if( x + width > monitor->rcMonitor.right)
+            x = monitor->rcMonitor.right - width;
+    }
+    if( x < monitor->rcMonitor.left ) x = monitor->rcMonitor.left;
+
+    if( y + height > monitor->rcMonitor.bottom)
+    {
+        if( yanchor && y >= height + yanchor )
+            y -= height + yanchor;
+
+        if( y + height > monitor->rcMonitor.bottom)
+            y = monitor->rcMonitor.bottom - height;
+    }
+    if( y < monitor->rcMonitor.top ) y = monitor->rcMonitor.top;
+
+    pWnd = ValidateHwndNoErr( menu->hWnd );
+/*
+    if (!top_popup) {
+        top_popup = menu->hWnd;
+        top_popup_hmenu = hmenu;
+    }
+ */
+    /* Display the window */
+
+    co_WinPosSetWindowPos( pWnd, HWND_TOPMOST, x, y, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
+
+    co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
+
+    IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MENU_EnsureMenuItemVisible
+ */
+void
+MENU_EnsureMenuItemVisible(PMENU lppop, UINT wIndex, HDC hdc)
+{
+    if (lppop->dwArrowsOn)
+    {
+        ITEM *item = &lppop->rgItems[wIndex];
+        UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
+        UINT nOldPos = lppop->iTop;
+        RECT rc;
+        UINT arrow_bitmap_height;
+        PWND pWnd = ValidateHwndNoErr(lppop->hWnd);
+
+        IntGetClientRect(pWnd, &rc);
+
+        arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
+
+        rc.top += arrow_bitmap_height;
+        rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
+
+        nMaxHeight -= UserGetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
+        if (item->cyItem > lppop->iTop + nMaxHeight)
+        {
+            lppop->iTop = item->cyItem - nMaxHeight;
+            IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+            MENU_DrawScrollArrows(lppop, hdc);
+            //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
+        }
+        else if (item->yItem - MENU_TOP_MARGIN < lppop->iTop)
+        {
+            lppop->iTop = item->yItem - MENU_TOP_MARGIN;
+            IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+            MENU_DrawScrollArrows(lppop, hdc);
+            //ERR("Scroll Up   iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
+        }
+    }
+}
+
+/***********************************************************************
+ *           MenuSelectItem
+ */
+static
+void FASTCALL MENU_SelectItem(PWND pwndOwner, PMENU menu, UINT wIndex,
+                                    BOOL sendMenuSelect, PMENU topmenu)
+{
+    HDC hdc;
+    PWND pWnd = ValidateHwndNoErr(menu->hWnd);
+
+    TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner, menu, wIndex, sendMenuSelect);
+
+    if (!menu || !menu->cItems || !pWnd) return;
+    if (menu->iItem == wIndex) return;
+
+    if (menu->fFlags & MNF_POPUP)
+       hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE);
+    else
+       hdc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
+   /*
+    if (!top_popup) { 
+        top_popup = lppop->hWnd; pPopupMenu->spwndActivePopup or
+                                 pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
+        top_popup_hmenu = hmenu; pPopupMenu->spmenu
+    }
+    */
+    NtGdiSelectFont( hdc, ghMenuFont );
+
+     /* Clear previous highlighted item */
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+        MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, &menu->rgItems[menu->iItem],
+                       menu->cyMenu, !(menu->fFlags & MNF_POPUP),
+                       ODA_SELECT);
+    }
+
+    /* Highlight new item (if any) */
+    menu->iItem = wIndex;
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        if (!(menu->rgItems[wIndex].fType & MF_SEPARATOR))
+        {
+             menu->rgItems[wIndex].fState |= MF_HILITE;
+             MENU_EnsureMenuItemVisible(menu, wIndex, hdc);
+             MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc,
+                               &menu->rgItems[wIndex], menu->cyMenu, !(menu->fFlags & MNF_POPUP), ODA_SELECT);
+        }
+        if (sendMenuSelect)
+        {
+           ITEM *ip = &menu->rgItems[menu->iItem];
+           WPARAM wParam = MAKEWPARAM( ip->spSubMenu ? wIndex : ip->wID, 
+                                       ip->fType | ip->fState |
+                                      (ip->spSubMenu ? MF_POPUP : 0) |
+                                      (menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+           co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(menu));
+        }
+    }
+    else if (sendMenuSelect) 
+    {
+        if (topmenu) 
+        {
+            int pos;
+            pos = MENU_FindSubMenu(&topmenu, menu);
+            if (pos != NO_SELECTED_ITEM)
+            {
+               ITEM *ip = &topmenu->rgItems[pos];
+               WPARAM wParam = MAKEWPARAM( Pos, ip->fType | ip->fState |
+                                           (ip->spSubMenu ? MF_POPUP : 0) |
+                                           (topmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+               co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(topmenu));
+            }
+        }
+    }
+    UserReleaseDC(pWnd, hdc, FALSE);
+}
+
+/***********************************************************************
+ *           MenuMoveSelection
+ *
+ * Moves currently selected item according to the Offset parameter.
+ * If there is no selection then it should select the last item if
+ * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
+ */
+static void FASTCALL
+MENU_MoveSelection(PWND WndOwner, PMENU Menu, INT Offset)
+{
+  INT i;
+  INT OrigPos;
+
+  TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, Menu, Offset);
+
+  /* Prevent looping */
+  if (0 == Menu->cItems || 0 == Offset)
+    return;
+  else if (Offset < -1)
+    Offset = -1;
+  else if (Offset > 1)
+    Offset = 1;
+
+  OrigPos = Menu->iItem;
+  if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
+  {
+       OrigPos = 0;
+       i = -1;
+  }
+  else
+  {
+      i = Menu->iItem;
+  }
+
+  do
+  {   /* Step */
+      i += Offset;
+      /* Clip and wrap around */
+      if (i < 0)
+      {
+          i = Menu->cItems - 1;
+      }
+      else if (i >= Menu->cItems)
+      {
+          i = 0;
+      }
+      /* If this is a good candidate; */
+      if (!(Menu->rgItems[i].fType & MF_SEPARATOR))
+      {
+          MENU_SelectItem(WndOwner, Menu, i, TRUE, NULL);
+          return;
+      }
+  } while (i != OrigPos);
+
+  /* Not found */
+}
+
+/***********************************************************************
+ *           MenuHideSubPopups
+ *
+ * Hide the sub-popup menus of this menu.
+ */
+static void FASTCALL
+MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
+                               BOOL SendMenuSelect, UINT wFlags)
+{
+  HWND top_popup = Menu->hWnd; // HAX for now just to get hilite to work.
+
+  TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner, Menu, SendMenuSelect);
+
+  if (Menu && top_popup)
+  {
+      PITEM Item;
+
+      if (Menu->iItem != NO_SELECTED_ITEM)
+      {
+         Item = &Menu->rgItems[Menu->iItem];
+         if (!(Item->spSubMenu) ||
+             !(Item->fState & MF_MOUSESELECT)) return;
+         Item->fState &= ~MF_MOUSESELECT;
+      }
+      else
+         return;
+
+      if (Item->spSubMenu)
+      {
+          PWND pWnd = ValidateHwndNoErr(Item->spSubMenu->hWnd);
+          MENU_HideSubPopups(pWndOwner, Item->spSubMenu, FALSE, wFlags);
+          MENU_SelectItem(pWndOwner, Item->spSubMenu, NO_SELECTED_ITEM, SendMenuSelect, NULL);
+
+          co_UserDestroyWindow(pWnd);
+
+          /* Native returns handle to destroyed window */
+          if (!(wFlags & TPM_NONOTIFY))
+             co_IntSendMessage( UserHMGetHandle(pWndOwner), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(Item->spSubMenu),
+                                 MAKELPARAM(0, IS_SYSTEM_MENU(Item->spSubMenu)) );
+          ////
+          // Call WM_UNINITMENUPOPUP FIRST before destroy!!
+          // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
+          //
+          Item->spSubMenu->hWnd = NULL;
+          ////
+      }
+  }
+}
+
+/***********************************************************************
+ *           MenuShowSubPopup
+ *
+ * Display the sub-menu of the selected item of this menu.
+ * Return the handle of the submenu, or menu if no submenu to display.
+ */
+//static
+PMENU FASTCALL
+MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
+{
+  RECT Rect;
+  ITEM *Item;
+  HDC Dc;
+  PWND pWnd;
+
+  TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, Menu, SelectFirst);
+
+  if (Menu->iItem == NO_SELECTED_ITEM) return Menu;
+  
+  Item = &Menu->rgItems[Menu->iItem];
+  if (!(Item->spSubMenu) || (Item->fState & (MF_GRAYED | MF_DISABLED)))
+      return Menu;
+
+  /* message must be sent before using item,
+     because nearly everything may be changed by the application ! */
+
+  /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+  if (!(Flags & TPM_NONOTIFY))
+  {
+      co_IntSendMessage(UserHMGetHandle(WndOwner), WM_INITMENUPOPUP,
+                        (WPARAM) UserHMGetHandle(Item->spSubMenu),
+                         MAKELPARAM(Menu->iItem, IS_SYSTEM_MENU(Menu)));
+  }
+
+  Item = &Menu->rgItems[Menu->iItem];
+  //Rect = ItemInfo.Rect;
+  Rect.left   = Item->xItem;
+  Rect.top    = Item->yItem;
+  Rect.right  = Item->cxItem; // Do this for now......
+  Rect.bottom = Item->cyItem;
+
+  pWnd = ValidateHwndNoErr(Menu->hWnd);
+
+  /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
+  if (!(Item->fState & MF_HILITE))
+  {
+      if (Menu->fFlags & MNF_POPUP) Dc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
+      else Dc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
+
+      NtGdiSelectFont(Dc, ghMenuFont);
+
+      Item->fState |= MF_HILITE;
+      MENU_DrawMenuItem(pWnd, Menu, WndOwner, Dc, Item, Menu->cyMenu,
+                       !(Menu->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
+      UserReleaseDC(pWnd, Dc, FALSE);
+  }
+
+  if (!Item->yItem && !Item->xItem && !Item->cyItem && !Item->cxItem)
+  {
+      Item->xItem  = Rect.left; 
+      Item->yItem  = Rect.top;  
+      Item->cxItem = Rect.right; // Do this for now...... 
+      Item->cyItem = Rect.bottom;
+  }
+  Item->fState |= MF_MOUSESELECT;
+
+  if (IS_SYSTEM_MENU(Menu))
+  {
+      MENU_InitSysMenuPopup(Item->spSubMenu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
+
+      NC_GetSysPopupPos(pWnd, &Rect);
+      if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
+      Rect.top = Rect.bottom;
+      Rect.right = UserGetSystemMetrics(SM_CXSIZE);
+      Rect.bottom = UserGetSystemMetrics(SM_CYSIZE);
+  }
+  else
+  {
+      IntGetWindowRect(pWnd, &Rect);
+      if (Menu->fFlags & MNF_POPUP)
+      {
+          RECT rc;
+          rc.left   = Item->xItem;
+          rc.top    = Item->yItem;
+          rc.right  = Item->cxItem; // Do this for now......
+          rc.bottom = Item->cyItem;
+
+          MENU_AdjustMenuItemRect(Menu, &rc);
+
+          /* The first item in the popup menu has to be at the
+             same y position as the focused menu item */
+          if(Flags & TPM_LAYOUTRTL)
+             Rect.left += UserGetSystemMetrics(SM_CXBORDER);
+          else
+             Rect.left += rc.right /*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER);
+          Rect.top += rc.top - MENU_TOP_MARGIN;//3;
+          Rect.right = rc.left - rc.right + UserGetSystemMetrics(SM_CXBORDER);
+          Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
+                                                     - UserGetSystemMetrics(SM_CYBORDER);
+      }
+      else
+      {
+          if(Flags & TPM_LAYOUTRTL)
+              Rect.left += Rect.right - Item->xItem; //ItemInfo.Rect.left;
+          else
+              Rect.left += Item->xItem; //ItemInfo.Rect.left;
+          Rect.top += Item->cyItem; //ItemInfo.Rect.bottom;
+          Rect.right  = Item->cxItem - Item->xItem; //ItemInfo.Rect.right - ItemInfo.Rect.left;
+          Rect.bottom = Item->cyItem - Item->yItem; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
+      }
+  }
+
+  /* use default alignment for submenus */
+  Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
+
+  MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
+
+  MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
+                Rect.left, Rect.top, Rect.right, Rect.bottom );
+  if (SelectFirst)
+  {
+      MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
+  }
+  return Item->spSubMenu;
+}
+
+
+VOID FASTCALL
 co_IntInitTracking(PWND Window, PMENU Menu, BOOL Popup,
                    UINT Flags)
 {
@@ -1158,6 +3228,141 @@
    return FALSE;
 }
 
+LRESULT WINAPI
+IntPopupMenuWndProc(
+   PWND Wnd,
+   UINT Message,
+   WPARAM wParam,
+   LPARAM lParam,
+   BOOL Ansi)
+{
+  PPOPUPMENU pPopupMenu;
+
+  if (Wnd)
+  {
+     if (!Wnd->fnid)
+     {
+        if (Message != WM_NCCREATE)
+        {
+           return IntDefWindowProc(Wnd, Message, wParam, lParam, Ansi);
+        }
+        Wnd->fnid = FNID_MENU;
+        pPopupMenu = DesktopHeapAlloc( Wnd->head.rpdesk, sizeof(POPUPMENU) );
+        pPopupMenu->posSelectedItem = NO_SELECTED_ITEM;
+        pPopupMenu->spwndPopupMenu = Wnd;
+        ((PMENUWND)Wnd)->ppopupmenu = pPopupMenu;
+        ERR("Pop Up Menu is Setup! Msg %d\n",Message);
+     }
+     else
+     {
+        if (Wnd->fnid != FNID_MENU)
+        {
+           ERR("Wrong window class for Menu!\n");
+           return 0;
+        }
+        pPopupMenu = ((PMENUWND)Wnd)->ppopupmenu;
+     }
+  }
+
+  TRACE("pwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+  switch(Message)
+    {
+    case WM_CREATE:
+      {
+        CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+        pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
+        return 0;
+      }
+
+    case WM_MOUSEACTIVATE:  /* We don't want to be activated */
+      return MA_NOACTIVATE;
+
+    case WM_PAINT:
+      {
+        PAINTSTRUCT ps;
+        IntBeginPaint(Wnd, &ps);
+        MENU_DrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
+        IntEndPaint(Wnd, &ps);
+        return 0;
+      }
+
+    case WM_PRINTCLIENT:
+      {
+         MENU_DrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
+         return 0;
+      }
+
+    case WM_ERASEBKGND:
+      return 1;
+
+    case WM_DESTROY:
+      /* zero out global pointer in case resident popup window was destroyed. */
+      /*if (Wnd == top_popup)
+        {
+          top_popup = NULL;
+          top_popup_hmenu = NULL;
+        }*/
+      break;
+
+    case WM_NCDESTROY:
+      {
+      DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
+      ((PMENUWND)Wnd)->ppopupmenu = 0;
+      Wnd->fnid = FNID_DESTROY;
+      break;
+      }
+
+    case MM_SETMENUHANDLE:
+      {
+        PMENU pmenu = UserGetMenuObject((HMENU)wParam);
+        if (!pmenu)
+        {
+           ERR("Bad Menu Handle\n");
+           break;
+        }
+        pPopupMenu->spmenu = pmenu;
+        break;
+      }
+
+    case MM_GETMENUHANDLE:
+    case MN_GETHMENU:
+         return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
+
+    default:
+      return IntDefWindowProc(Wnd, Message, wParam, lParam, Ansi);
+    }
+
+  return 0;
+}
+
+
+BOOL FASTCALL
+IntHiliteMenuItem(PWND WindowObject,
+                  PMENU MenuObject,
+                  UINT uItemHilite,
+                  UINT uHilite)
+{
+   PITEM MenuItem;
+   UINT uItem = uItemHilite;
+
+   if (!(MenuItem = MENU_FindItem( &MenuObject, &uItem, uHilite ))) return TRUE;
+
+   if (uHilite & MF_HILITE)
+   {
+      MenuItem->fState |= MF_HILITE;
+   }
+   else
+   {
+      MenuItem->fState &= ~MF_HILITE;
+   }
+   if (MenuObject->iItem == uItemHilite) return TRUE;
+   MENU_HideSubPopups( WindowObject, MenuObject, FALSE, 0 );
+   MENU_SelectItem( WindowObject, MenuObject, uItemHilite, TRUE, 0 );
+
+   return TRUE; // Always returns true!!!!
+}
+
 BOOLEAN APIENTRY
 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
 {
@@ -1372,39 +3577,18 @@
 
 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
 {
-    PMENU menu;
-    HMENU hSubMenu;
-    UINT i;
-    PITEM item;
-
+    PMENU menu, pSubTarget;
+    UINT Pos;
     if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
         return NO_SELECTED_ITEM;
 
-    item = menu->rgItems;
-    for (i = 0; i < menu->cItems; i++, item++)
-    {
-        if (!item->spSubMenu)
-           continue;
-        else
-        {
-           hSubMenu = UserHMGetHandle(item->spSubMenu);
-           if (hSubMenu == hSubTarget)
-           {
-              return i;
-           }
-           else
-           {
-              HMENU hsubmenu = hSubMenu;
-              UINT pos = IntFindSubMenu( &hsubmenu, hSubTarget );
-              if (pos != NO_SELECTED_ITEM)
-              {
-                  *hMenu = hsubmenu;
-                  return pos;
-              }
-           }
-        }
-    }
-    return NO_SELECTED_ITEM;
+    pSubTarget = UserGetMenuObject(hSubTarget);
+
+    Pos = MENU_FindSubMenu(&menu, pSubTarget );
+
+    *hMenu = (menu ? UserHMGetHandle(menu) : NULL);
+
+    return Pos;
 }
 
 
@@ -1601,21 +3785,6 @@
    return( Res);
 }
 
-VOID FASTCALL
-MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
-{
-    if (menu->dwArrowsOn)
-    {
-        UINT arrow_bitmap_height;
-        //BITMAP bmp;
-        //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
-        arrow_bitmap_height = gpsi->oembmi[65].cy; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
-        //arrow_bitmap_height = bmp.bmHeight;
-        rect->top += arrow_bitmap_height - menu->iTop;
-        rect->bottom += arrow_bitmap_height - menu->iTop;
-    }
-}
-
 BOOL FASTCALL
 IntGetMenuItemRect(
    PWND pWnd,
@@ -1855,7 +4024,7 @@
       return FALSE;
    }
 
-   *Changed = (Wnd->IDMenu != (UINT) Menu);
+   *Changed = (UlongToHandle(Wnd->IDMenu) != Menu);
    if (! *Changed)
    {
       return TRUE;
@@ -1863,8 +4032,8 @@
 
    if (Wnd->IDMenu)
    {
-      OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
-      ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
+      OldMenu = IntGetMenuObject(UlongToHandle(Wnd->IDMenu));
+      ASSERT(NULL == OldMenu || OldMenu->hWnd == UserHMGetHandle(Wnd));
    }
    else
    {
@@ -1899,7 +4068,7 @@
    Wnd->IDMenu = (UINT) Menu;
    if (NULL != NewMenu)
    {
-      NewMenu->hWnd = Wnd->head.h;
+      NewMenu->hWnd = UserHMGetHandle(Wnd);
       IntReleaseMenuObject(NewMenu);
    }
    if (NULL != OldMenu)
@@ -1912,6 +4081,7 @@
 }
 
 
+
 /* FUNCTIONS *****************************************************************/
 
 /*
@@ -2221,6 +4391,30 @@
  * @implemented
  */
 BOOL APIENTRY
+NtUserEndMenu(VOID)
+{
+   PWND pWnd;
+   TRACE("Enter NtUserEndMenu\n");
+   UserEnterExclusive();
+   if ( gptiCurrent->pMenuState->pGlobalPopupMenu )
+   {
+       pWnd = IntGetMSWND(gptiCurrent->pMenuState);
+       if (pWnd)
+       {
+          UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
+       }
+       else
+          gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
+   }
+   UserLeave();
+   TRACE("Leave NtUserEndMenu\n");
+   return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
 NtUserGetMenuBarInfo(
    HWND hwnd,
    LONG idObject,
@@ -2492,7 +4686,7 @@
    PWND Window;
    DECLARE_RETURN(BOOLEAN);
 
-   TRACE("Enter NtUserHiliteMenuItem\n");
+   ERR("Enter NtUserHiliteMenuItem\n");
    UserEnterExclusive();
 
    if(!(Window = UserGetWindowObject(hWnd)))
@@ -2519,6 +4713,64 @@
 /*
  * @implemented
  */
+DWORD
+APIENTRY
+NtUserDrawMenuBarTemp(
+   HWND hWnd,
+   HDC hDC,
+   PRECT pRect,
+   HMENU hMenu,
+   HFONT hFont)
+{
+   PMENU Menu;
+   PWND Window;
+   RECT Rect;
+   NTSTATUS Status = STATUS_SUCCESS;
+   DECLARE_RETURN(DWORD);
+
+   TRACE("Enter NtUserDrawMenuBarTemp\n");
+   UserEnterExclusive();
+
+   if(!(Window = UserGetWindowObject(hWnd)))
+   {
+      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+      RETURN(0);
+   }
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+      RETURN(0);
+   }
+
+   _SEH2_TRY
+   {
+      ProbeForRead(pRect, sizeof(RECT), sizeof(ULONG));
+      RtlCopyMemory(&Rect, pRect, sizeof(RECT));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      Status = _SEH2_GetExceptionCode();
+   }
+   _SEH2_END;
+
+   if (Status != STATUS_SUCCESS)
+   {
+      SetLastNtError(Status);
+      RETURN(0);
+   }
+
+   RETURN( IntDrawMenuBarTemp(Window, hDC, &Rect, Menu, hFont));
+
+CLEANUP:
+   TRACE("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
 int APIENTRY
 NtUserMenuItemFromPoint(
    HWND hWnd,
@@ -2552,11 +4804,14 @@
    for (i = 0; i < Menu->cItems; i++, mi++)
    {
       RECTL Rect;
+
       Rect.left   = mi->xItem;
       Rect.top    = mi->yItem;
-      Rect.right  = mi->cxItem; // Do this for now......
+      Rect.right  = mi->cxItem;
       Rect.bottom = mi->cyItem;
-      //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
+
+      MENU_AdjustMenuItemRect(Menu, &Rect);
+
       if (RECTL_bPointInRect(&Rect, X, Y))
       {
          break;
@@ -2807,4 +5062,21 @@
    END_CLEANUP;
 }
 
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserTrackPopupMenuEx(
+   HMENU hMenu,
+   UINT fuFlags,
+   int x,
+   int y,
+   HWND hWnd,
+   LPTPMPARAMS lptpm)
+{
+   STUB
+
+   return FALSE;
+}
+
 /* EOF */
Index: win32ss/user/ntuser/menu.h
===================================================================
--- win32ss/user/ntuser/menu.h	(revision 68654)
+++ win32ss/user/ntuser/menu.h	(working copy)
@@ -101,3 +101,5 @@
 PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags );
 BOOL FASTCALL IntMenuItemInfo(PMENU Menu, UINT Item, BOOL ByPosition, PROSMENUITEMINFO UnsafeItemInfo, BOOL SetOrGet, PUNICODE_STRING lpstr);
 BOOL FASTCALL IntSetMenu(PWND Wnd,HMENU Menu,BOOL *Changed);
+UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw );
+BOOL MenuInit(VOID);
Index: win32ss/user/ntuser/message.c
===================================================================
--- win32ss/user/ntuser/message.c	(revision 68654)
+++ win32ss/user/ntuser/message.c	(working copy)
@@ -136,6 +136,9 @@
     { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
     { WM_SIZING, sizeof(RECT), MMS_FLAG_READWRITE },
     { WM_MOVING, sizeof(RECT), MMS_FLAG_READWRITE },
+    { WM_MEASUREITEM, sizeof(MEASUREITEMSTRUCT), MMS_FLAG_READWRITE },
+    { WM_DRAWITEM, sizeof(DRAWITEMSTRUCT), MMS_FLAG_READWRITE },
+    { WM_HELP, sizeof(HELPINFO), MMS_FLAG_READWRITE },
 };
 
 static PMSGMEMORY FASTCALL
Index: win32ss/user/ntuser/nonclient.c
===================================================================
--- win32ss/user/ntuser/nonclient.c	(revision 68654)
+++ win32ss/user/ntuser/nonclient.c	(working copy)
@@ -31,7 +31,13 @@
 #define ON_BOTTOM_BORDER(hit) \
  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
 
+#define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
+            ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE))  || \
+             ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
+             (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
+             (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
 
+
 VOID FASTCALL
 UserDrawWindowFrame(HDC hdc,
                     RECTL *rect,
@@ -109,6 +115,32 @@
     }
 }
 
+/***********************************************************************
+ *           NC_GetSysPopupPos
+ */
+void FASTCALL
+NC_GetSysPopupPos(PWND Wnd, RECT *Rect)
+{
+  RECT WindowRect;
+
+  if ((Wnd->style & WS_MINIMIZE) != 0)
+  {
+      IntGetWindowRect(Wnd, Rect);
+  }
+  else
+    {
+      NC_GetInsideRect(Wnd, Rect);
+      IntGetWindowRect(Wnd, &WindowRect);
+      RECTL_vOffsetRect(Rect, WindowRect.left, WindowRect.top);
+      if (Wnd->style & WS_CHILD)
+      {
+          IntClientToScreen(IntGetParent(Wnd), (POINT *) Rect);
+      }
+      Rect->right = Rect->left + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+      Rect->bottom = Rect->top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+    }
+}
+
 LONG FASTCALL
 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
 {
@@ -598,6 +630,806 @@
    return pIcon;
 }
 
+BOOL
+UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down)
+{
+   PCURICON_OBJECT WindowIcon;
+   BOOL Ret = FALSE;
+
+   if ((WindowIcon = NC_IconForWindow(pWnd)))
+   {
+      UserReferenceObject(WindowIcon);
+
+      Ret = UserDrawIconEx( hDC,
+                            Rect->left + 2,
+                            Rect->top + 2,
+                            WindowIcon,
+                            UserGetSystemMetrics(SM_CXSMICON),
+                            UserGetSystemMetrics(SM_CYSMICON),
+                            0, NULL, DI_NORMAL);
+
+      UserDereferenceObject(WindowIcon);
+   }
+   return Ret;
+}
+
+void
+UserGetInsideRectNC(PWND Wnd, RECT *rect)
+{
+    ULONG Style;
+    ULONG ExStyle;
+
+    Style = Wnd->style;
+    ExStyle = Wnd->ExStyle;
+
+    rect->top    = rect->left = 0;
+    rect->right  = Wnd->rcWindow.right - Wnd->rcWindow.left;
+    rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top;
+
+    if (Style & WS_ICONIC)
+    {
+        return;
+    }
+
+    /* Remove frame from rectangle */
+    if (UserHasThickFrameStyle(Style, ExStyle ))
+    {
+        RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME));
+    }
+    else
+    {
+        if (UserHasDlgFrameStyle(Style, ExStyle ))
+        {
+            RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
+            /* FIXME: this isn't in NC_AdjustRect? why not? */
+            if (ExStyle & WS_EX_DLGMODALFRAME)
+	            RECTL_vInflateRect( rect, -1, 0 );
+        }
+        else
+        {
+            if (UserHasThinFrameStyle(Style, ExStyle))
+            {
+                RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
+            }
+        }
+    }
+    /* We have additional border information if the window
+     * is a child (but not an MDI child) */
+    if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD))
+    {
+       if (ExStyle & WS_EX_CLIENTEDGE)
+          RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
+       if (ExStyle & WS_EX_STATICEDGE)
+          RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
+    }
+}
+
+BOOL
+IntIsScrollBarVisible(PWND pWnd, INT hBar)
+{
+  SCROLLBARINFO sbi;
+  sbi.cbSize = sizeof(SCROLLBARINFO);
+
+  if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi))
+    return FALSE;
+
+  return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
+}
+
+BOOL
+UserHasMenu(PWND pWnd, ULONG Style)
+{
+   return (!(Style & WS_CHILD) && UlongToHandle(pWnd->IDMenu) != 0);
+}
+
+/*
+ * FIXME:
+ * - Cache bitmaps, then just bitblt instead of calling DFC() (and
+ *   wasting precious CPU cycles) every time
+ * - Center the buttons verticaly in the rect
+ */
+VOID
+UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
+{
+   RECT TempRect;
+
+   if (!(Style & WS_SYSMENU))
+   {
+      return;
+   }
+
+   TempRect = *Rect;
+
+   switch (Type)
+   {
+      case DFCS_CAPTIONMIN:
+      {
+         if (ExStyle & WS_EX_TOOLWINDOW)
+            return; /* ToolWindows don't have min/max buttons */
+
+         if (Style & WS_SYSMENU)
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+
+         if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2;
+
+         TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         TempRect.top += 2;
+         TempRect.right -= 1;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
+                          (bDown ? DFCS_PUSHED : 0) |
+                          ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
+         break;
+      }
+      case DFCS_CAPTIONMAX:
+      {
+         if (ExStyle & WS_EX_TOOLWINDOW)
+             return; /* ToolWindows don't have min/max buttons */
+
+         if (Style & WS_SYSMENU)
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+
+         TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         TempRect.top += 2;
+         TempRect.right -= 1;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
+                          (bDown ? DFCS_PUSHED : 0) |
+                          ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
+         break;
+      }
+      case DFCS_CAPTIONCLOSE:
+      {
+          PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE);
+          UINT MenuState = IntGetMenuState(UserHMGetHandle(pSysMenu), SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
+
+         /* FIXME: A tool window has a smaller Close button */
+
+         if (ExStyle & WS_EX_TOOLWINDOW)
+         {
+            TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE);
+            TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2;
+         }
+         else
+         {
+            TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE);
+            TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         }
+         TempRect.top += 2;
+         TempRect.right -= 2;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
+                          ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
+         break;
+      }
+   }
+}
+
+VOID
+UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type)
+{
+   RECT WindowRect;
+   SIZE WindowBorder;
+
+   IntGetWindowRect(pWnd, &WindowRect);
+
+   WindowRect.right -= WindowRect.left;
+   WindowRect.bottom -= WindowRect.top;
+   WindowRect.left = WindowRect.top = 0;
+
+   UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE);
+
+   RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
+
+   UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type);
+}
+
+VOID
+NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle)
+{
+   /* Firstly the "thick" frame */
+   if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
+   {
+      LONG Width =
+         (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) *
+         UserGetSystemMetrics(SM_CXBORDER);
+
+      LONG Height =
+         (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) *
+         UserGetSystemMetrics(SM_CYBORDER);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
+
+      /* Draw frame */
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+
+      RECTL_vInflateRect(CurrentRect, -Width, -Height);
+   }
+
+   /* Now the other bit of the frame */
+   if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
+   {
+      DWORD Width = UserGetSystemMetrics(SM_CXBORDER);
+      DWORD Height = UserGetSystemMetrics(SM_CYBORDER);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(
+         (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
+         (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
+         (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
+         COLOR_WINDOWFRAME));
+
+      /* Draw frame */
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+
+      RECTL_vInflateRect(CurrentRect, -Width, -Height);
+   }
+}
+
+VOID UserDrawCaptionBar(
+   PWND pWnd,
+   HDC hDC,
+   INT Flags)
+{
+   RECT ClientRect, WindowRect, CurrentRect, TempRect;
+   HPEN PreviousPen;
+   BOOL Gradient = FALSE;
+
+   if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return;
+
+   IntGetWindowRect(pWnd, &WindowRect);
+   IntGetClientRect(pWnd, &ClientRect);
+
+   CurrentRect.top = CurrentRect.left = 0;
+   CurrentRect.right = WindowRect.right - WindowRect.left;
+   CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
+
+   /* Draw outer edge */
+   if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
+   {
+      DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
+   }
+   else if (pWnd->ExStyle & WS_EX_STATICEDGE)
+   {
+#if 0
+      DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
+#else
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      RECTL_vInflateRect(&CurrentRect, -1, -1);
+#endif
+   }
+
+   if (Flags & DC_FRAME)
+      NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), pWnd->style, pWnd->ExStyle);
+
+   /* Draw caption */
+   if ((pWnd->style & WS_CAPTION) == WS_CAPTION)
+   {
+
+      TempRect = CurrentRect;
+
+      if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
+      {
+         Flags |= DC_GRADIENT;
+      }
+
+      if (pWnd->ExStyle & WS_EX_TOOLWINDOW)
+      {
+         Flags |= DC_SMALLCAP;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
+      }
+      else
+      {
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags);
+
+      /* Draw buttons */
+      if (pWnd->style & WS_SYSMENU)
+      {
+         UserDrawCaptionButton(pWnd, &TempRect, pWnd->style, pWnd->ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
+         if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW))
+         {
+            UserDrawCaptionButton(pWnd, &TempRect, pWnd->style, pWnd->ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
+            UserDrawCaptionButton(pWnd, &TempRect, pWnd->style, pWnd->ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
+         }
+      }
+
+      if (!(pWnd->style & WS_MINIMIZE))
+      {
+         /* Line under caption */
+         PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+
+         IntSetDCPenColor( hDC, IntGetSysColor(((pWnd->ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
+                                             COLOR_WINDOWFRAME : COLOR_3DFACE));
+
+         GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
+
+         NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
+
+         NtGdiSelectPen(hDC, PreviousPen);
+      }
+   }
+
+   if (!(pWnd->style & WS_MINIMIZE))
+   {
+      if (pWnd->ExStyle & WS_EX_CLIENTEDGE)
+      {
+          DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+      }
+   }
+}
+
+// Note from Wine:
+/* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
+   the call to GetDCEx implying that it is allowed not to use it either.
+   However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
+   will cause clipRgn to be deleted after ReleaseDC().
+   Now, how is the "system" supposed to tell what happened?
+ */
+/*
+ * FIXME:
+ * - Drawing of WS_BORDER after scrollbars
+ * - Correct drawing of size-box
+ */
+LRESULT
+NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags)
+{
+   DWORD Style, ExStyle;
+   PWND Parent;
+   RECT ClientRect, WindowRect, CurrentRect, TempRect;
+   BOOL Active = FALSE;
+
+   if (!IntIsWindowVisible(pWnd) ||
+       (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
+        IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
+      return 0;
+
+   Style = pWnd->style;
+
+   TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Active ? "TRUE" : "FALSE");
+
+   Parent = IntGetParent(pWnd);
+   ExStyle = pWnd->ExStyle;
+
+   if (Flags == -1) // NC paint mode.
+   {
+      if (ExStyle & WS_EX_MDICHILD)
+      {
+         Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd);
+
+         if (Active)
+            Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0));
+      }
+      else
+      {
+         Active = (gpqForeground->spwndActive == pWnd);
+      }
+      Flags = DC_NC;
+   }
+
+   IntGetWindowRect(pWnd, &WindowRect);
+   IntGetClientRect(pWnd, &ClientRect);
+
+   CurrentRect.top = CurrentRect.left = 0;
+   CurrentRect.right = WindowRect.right - WindowRect.left;
+   CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
+
+   /* Draw outer edge */
+   if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
+   {
+      DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
+   }
+   else if (pWnd->ExStyle & WS_EX_STATICEDGE)
+   {
+#if 0
+      DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
+#else
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      RECTL_vInflateRect(&CurrentRect, -1, -1);
+#endif
+   }
+
+   if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active, Style, ExStyle);
+
+   /* Draw caption */
+   if ((Style & WS_CAPTION) == WS_CAPTION)
+   {
+      HPEN PreviousPen;
+      BOOL Gradient = FALSE;
+
+      if (Flags & DCF_REDRAWHUNGWND)
+      {
+         Flags &= ~DCF_REDRAWHUNGWND;
+         Flags |= DC_NOSENDMSG;
+      }
+
+      if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
+      {
+         Flags |= DC_GRADIENT;
+      }
+
+      if (Active)
+      {
+         if (!(pWnd->state & WNDS_ACTIVEFRAME))
+         {
+            ERR("Wnd is active and not set active!\n");
+         }
+         Flags |= DC_ACTIVE;
+      }
+
+      TempRect = CurrentRect;
+
+      if (ExStyle & WS_EX_TOOLWINDOW)
+      {
+         Flags |= DC_SMALLCAP;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
+      }
+      else
+      {
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags);
+
+      /* Draw buttons */
+      if (Style & WS_SYSMENU)
+      {
+         UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
+         if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
+         {
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
+         }
+      }
+      if (!(Style & WS_MINIMIZE))
+      {
+        /* Line under caption */
+         PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+
+         IntSetDCPenColor( hDC, IntGetSysColor(
+                         ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
+                          COLOR_WINDOWFRAME : COLOR_3DFACE));
+
+         GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
+
+         NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
+
+         NtGdiSelectPen(hDC, PreviousPen);
+      }
+   }
+
+   if (!(Style & WS_MINIMIZE))
+   {
+     PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+     /* Draw menu bar */
+     if (menu && !(Style & WS_CHILD))
+     {
+         TempRect = CurrentRect;
+         TempRect.bottom = TempRect.top + menu->cyMenu;
+         CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
+     }
+
+     if (ExStyle & WS_EX_CLIENTEDGE)
+     {
+         DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+     }
+
+     /* Draw the scrollbars */
+     if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
+         IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
+     {
+        RECT ParentClientRect;
+
+        TempRect = CurrentRect;
+
+        if (ExStyle & WS_EX_LEFTSCROLLBAR)
+           TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL);
+        else
+           TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL);
+
+        TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL);
+
+        FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE));
+
+        if (Parent)
+           IntGetClientRect(Parent, &ParentClientRect);
+
+        if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect))
+        {
+           DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
+        }
+
+        IntDrawScrollBar(pWnd, hDC, SB_VERT);
+        IntDrawScrollBar(pWnd, hDC, SB_HORZ);
+     }
+     else
+     {
+        if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL))
+        {
+           IntDrawScrollBar(pWnd, hDC, SB_VERT);
+        }
+        else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
+        {
+           IntDrawScrollBar(pWnd, hDC, SB_HORZ);
+        }
+     }
+   }
+   return 0; // For WM_NCPAINT message, return 0.
+}
+
+LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect )
+{
+   LRESULT Result = 0;
+   SIZE WindowBorders;
+   RECT OrigRect;
+   DWORD Style = Wnd->style;
+
+   if (Rect == NULL)
+   {
+      return Result;
+   }
+   OrigRect = *Rect;
+
+   Wnd->state &= ~WNDS_HASCAPTION;
+
+   if (wparam)
+   {
+      if (Wnd->pcls->style & CS_VREDRAW)
+      {
+         Result |= WVR_VREDRAW;
+      }
+      if (Wnd->pcls->style & CS_HREDRAW)
+      {
+         Result |= WVR_HREDRAW;
+      }
+      Result |= WVR_VALIDRECTS;
+   }
+
+   if (!(Wnd->style & WS_MINIMIZE))
+   {
+      if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle))
+      {
+         UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE);
+         RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
+      }
+      else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER))
+      {
+         RECTL_vInflateRect(Rect, -1, -1);
+      }
+
+      if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
+      {
+         Wnd->state |= WNDS_HASCAPTION;
+
+         if (Wnd->ExStyle & WS_EX_TOOLWINDOW)
+            Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION);
+         else
+            Rect->top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      if (Wnd->IDMenu && ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD))
+      {
+         HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
+
+         Wnd->state |= WNDS_HASMENU;
+
+         if (hDC)
+         {
+           RECT CliRect = *Rect;
+           CliRect.bottom -= OrigRect.top;
+           CliRect.right -= OrigRect.left;
+           CliRect.left -= OrigRect.left;
+           CliRect.top -= OrigRect.top;
+           Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE);
+           UserReleaseDC(Wnd, hDC, FALSE);
+         }
+      }
+
+      if (Wnd->ExStyle & WS_EX_CLIENTEDGE)
+      {
+         RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER));
+      }
+
+      if (Wnd->style & (WS_VSCROLL | WS_HSCROLL))
+      {
+        SCROLLBARINFO sbi;
+        SETSCROLLBARINFO ssbi;
+
+        sbi.cbSize = sizeof(SCROLLBARINFO);
+        if ((Style & WS_VSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_VSCROLL, &sbi))
+        {
+          int i;
+          LONG sx = Rect->right;
+
+          Wnd->state |= WNDS_HASVERTICALSCROOLLBAR;
+
+          sx -= UserGetSystemMetrics(SM_CXVSCROLL);
+
+          for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
+              ssbi.rgstate[i] = sbi.rgstate[i];
+
+          if (sx <= Rect->left)
+             ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
+          else
+             ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
+
+          co_IntSetScrollBarInfo(Wnd, OBJID_VSCROLL, &ssbi);
+
+          if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
+             Style &= ~WS_VSCROLL;
+        }
+        else
+          Style &= ~WS_VSCROLL;
+
+        if ((Style & WS_HSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_HSCROLL, &sbi))
+        {
+          int i;
+          LONG sy = Rect->bottom;
+
+          Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR;
+
+          sy -= UserGetSystemMetrics(SM_CYHSCROLL);
+
+          for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
+              ssbi.rgstate[i] = sbi.rgstate[i];
+
+          if (sy <= Rect->top)
+             ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
+          else
+             ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
+
+          co_IntSetScrollBarInfo(Wnd, OBJID_HSCROLL, &ssbi);
+
+          if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
+             Style &= ~WS_HSCROLL;
+        }
+        else
+          Style &= ~WS_HSCROLL;
+      }
+
+      if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
+      {
+         if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+            Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
+         else
+            Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
+
+         Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
+      }
+      else
+      {
+         if (Style & WS_VSCROLL)
+         {
+            if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+               Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
+            else
+               Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
+         }
+         else if (Style & WS_HSCROLL)
+            Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
+      }
+
+      if (Rect->top > Rect->bottom)
+         Rect->bottom = Rect->top;
+
+      if (Rect->left > Rect->right)
+         Rect->right = Rect->left;
+   }
+   else
+   {
+      Rect->right = Rect->left;
+      Rect->bottom = Rect->top;
+   }
+
+   return Result;
+}
+
+static
+INT NC_DoNCActive(PWND Wnd)
+{
+   INT Ret = 0;
+
+   if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) ||
+        IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) )
+       Ret = DC_CAPTION;
+
+   if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle))
+   {
+      //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same?
+      {
+          Ret = DC_FRAME;
+      }
+   }
+   return Ret;
+}
+
+LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam )
+{
+   INT Flags;
+  /* Lotus Notes draws menu descriptions in the caption of its main
+   * window. When it wants to restore original "system" view, it just
+   * sends WM_NCACTIVATE message to itself. Any optimizations here in
+   * attempt to minimize redrawings lead to a not restored caption.
+   */
+   if (wParam & DC_ACTIVE)
+   {
+      Wnd->state |= WNDS_ACTIVEFRAME;
+      wParam = DC_CAPTION|DC_ACTIVE;
+   }
+   else
+   {
+      Wnd->state &= ~WNDS_ACTIVEFRAME;
+      wParam = DC_CAPTION;
+   }
+
+   if (Wnd->state & WNDS_NONCPAINT || !(Wnd->style & WS_VISIBLE))
+      return 0;
+
+   /* This isn't documented but is reproducible in at least XP SP2 and
+    * Outlook 2007 depends on it
+    */
+   // MSDN:
+   // If this parameter is set to -1, DefWindowProc does not repaint the
+   // nonclient area to reflect the state change.
+   if ( lParam != -1 &&
+        ( Flags = NC_DoNCActive(Wnd)) != 0 )
+   {
+      HDC hDC;
+      HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam;
+
+      if (GreIsHandleValid(hRgn))
+      {
+         hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+         if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR)
+         {
+            GreDeleteObject(hRgnTemp);
+            hRgnTemp = NULL;
+         }
+      }
+
+      if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE)))
+      {
+         NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs.
+         UserReleaseDC(Wnd, hDC, FALSE);
+      }
+      else
+         GreDeleteObject(hRgnTemp);
+   }
+
+   return TRUE;
+}
+
 DWORD FASTCALL
 GetNCHitEx(PWND pWnd, POINT pt)
 {
Index: win32ss/user/ntuser/ntstubs.c
===================================================================
--- win32ss/user/ntuser/ntstubs.c	(revision 68654)
+++ win32ss/user/ntuser/ntstubs.c	(working copy)
@@ -922,23 +922,6 @@
 }
 
 /*
- * @unimplemented
- */
-DWORD
-APIENTRY
-NtUserDrawMenuBarTemp(
-   HWND hWnd,
-   HDC hDC,
-   PRECT hRect,
-   HMENU hMenu,
-   HFONT hFont)
-{
-   /* We'll use this function just for caching the menu bar */
-   STUB
-   return 0;
-}
-
-/*
  * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
  */
 /*
@@ -1013,35 +996,6 @@
    return 0;
 }
 
-/*
- * @unimplemented
- */
-BOOL APIENTRY
-NtUserEndMenu(VOID)
-{
-   STUB
-
-   return 0;
-}
-
-/*
- * @implemented
- */
-/* NOTE: unused function */
-BOOL APIENTRY
-NtUserTrackPopupMenuEx(
-   HMENU hMenu,
-   UINT fuFlags,
-   int x,
-   int y,
-   HWND hWnd,
-   LPTPMPARAMS lptpm)
-{
-   STUB
-
-   return FALSE;
-}
-
 DWORD APIENTRY
 NtUserQuerySendMessage(DWORD Unknown0)
 {
Index: win32ss/user/ntuser/painting.h
===================================================================
--- win32ss/user/ntuser/painting.h	(revision 68654)
+++ win32ss/user/ntuser/painting.h	(working copy)
@@ -33,4 +33,6 @@
 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND );
 BOOL FASTCALL IntFlashWindowEx(PWND,PFLASHWINFO);
 BOOL FASTCALL IntIntersectWithParents(PWND, RECTL *);
-BOOL FASTCALL IntIsWindowDrawable(PWND);
\ No newline at end of file
+BOOL FASTCALL IntIsWindowDrawable(PWND);
+BOOL UserDrawCaption(PWND,HDC,RECTL*,HFONT,HICON,const PUNICODE_STRING,UINT);
+
Index: win32ss/user/ntuser/scroll.h
===================================================================
--- win32ss/user/ntuser/scroll.h	(revision 68654)
+++ win32ss/user/ntuser/scroll.h	(working copy)
@@ -39,5 +39,12 @@
 #define SBOBJ_TO_SBID(Obj)	((Obj) - OBJID_HSCROLL)
 #define SBID_IS_VALID(id)	(id == SB_HORZ || id == SB_VERT || id == SB_CTL)
 
-BOOL FASTCALL co_IntCreateScrollBars(PWND Window);
-BOOL FASTCALL IntDestroyScrollBars(PWND Window);
+BOOL FASTCALL co_IntCreateScrollBars(PWND);
+BOOL FASTCALL IntDestroyScrollBars(PWND);
+DWORD FASTCALL co_UserShowScrollBar(PWND,int,BOOL,BOOL);
+BOOL FASTCALL co_IntGetScrollBarInfo(PWND,LONG,PSCROLLBARINFO);
+BOOL FASTCALL co_IntSetScrollBarInfo(PWND,LONG,PSETSCROLLBARINFO);
+void IntDrawScrollBar(PWND,HDC,INT);
+BOOL FASTCALL
+IntScrollWindow(PWND,int,int,CONST RECT*,CONST RECT*);
+DWORD FASTCALL IntScrollWindowEx(PWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
Index: win32ss/user/ntuser/scrollbar.c
===================================================================
--- win32ss/user/ntuser/scrollbar.c	(revision 68654)
+++ win32ss/user/ntuser/scrollbar.c	(working copy)
@@ -10,6 +10,32 @@
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserScrollbar);
 
+/* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
+#define SCROLL_NOWHERE		0x00    /* Outside the scroll bar */
+#define SCROLL_TOP_ARROW	0x01    /* Top or left arrow */
+#define SCROLL_TOP_RECT		0x02    /* Rectangle between the top arrow and the thumb */
+#define SCROLL_THUMB		0x03    /* Thumb rectangle */
+#define SCROLL_BOTTOM_RECT	0x04    /* Rectangle between the thumb and the bottom arrow */
+#define SCROLL_BOTTOM_ARROW	0x05    /* Bottom or right arrow */
+
+#define SCROLL_FIRST_DELAY   200        /* Delay (in ms) before first repetition when
+                                           holding the button down */
+#define SCROLL_REPEAT_DELAY  50         /* Delay (in ms) between scroll repetitions */
+
+#define SCROLL_TIMER   0                /* Scroll timer id */
+
+  /* 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 0
+
+//
+//
+//
 #define MINTRACKTHUMB    8               /* Minimum size of the rectangle between the arrows */
 
  /* What to do after SetScrollInfo() */
@@ -555,6 +581,39 @@
 }
 
 BOOL FASTCALL
+co_IntSetScrollBarInfo(PWND Window, LONG idObject, PSETSCROLLBARINFO psbi)
+{
+   INT Bar;
+   PSCROLLBARINFO sbi;
+   LPSCROLLINFO psi;
+   ASSERT_REFS_CO(Window);
+
+   Bar = SBOBJ_TO_SBID(idObject);
+
+   if(!SBID_IS_VALID(Bar))
+   {
+      EngSetLastError(ERROR_INVALID_PARAMETER);
+      ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
+      return FALSE;
+   }
+
+   if(!co_IntCreateScrollBars(Window))
+   {
+      ERR("Failed to create scrollbars for window.\n");
+      return FALSE;
+   }
+
+   sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
+   psi = IntGetScrollInfoFromWindow(Window, Bar);
+
+   psi->nTrackPos = psbi->nTrackPos;
+   sbi->reserved  = psbi->reserved;
+   RtlCopyMemory(&sbi->rgstate, &psbi->rgstate, sizeof(psbi->rgstate));
+
+   return TRUE;
+}
+
+BOOL FASTCALL
 co_IntCreateScrollBars(PWND Window)
 {
    PSCROLLBARINFO psbi;
@@ -709,6 +768,248 @@
    return FALSE;
 }
 
+static void
+IntDrawScrollInterior(PWND pWnd, HDC hDC, INT nBar, BOOL Vertical, PSCROLLBARINFO ScrollBarInfo)
+{
+   INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
+   INT ThumbTop = ScrollBarInfo->xyThumbTop;
+   RECT Rect;
+   HBRUSH hSaveBrush, hBrush;
+   BOOL TopSelected = FALSE, BottomSelected = FALSE;
+
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
+      TopSelected = TRUE;
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
+      BottomSelected = TRUE;
+
+   /*
+    * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
+    * The window-owned scrollbars need to call DefWndControlColor
+    * to correctly setup default scrollbar colors
+    */
+   if (nBar == SB_CTL)
+   {
+      hBrush = GetControlBrush( pWnd, hDC, WM_CTLCOLORSCROLLBAR);
+      if (!hBrush)
+         hBrush = IntGetSysColorBrush(COLOR_SCROLLBAR);
+   }
+   else
+   {
+      hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
+   }
+
+   hSaveBrush = NtGdiSelectBrush(hDC, hBrush);
+
+   /* Calculate the scroll rectangle */
+   if (Vertical)
+   {
+      Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
+      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
+      Rect.left = ScrollBarInfo->rcScrollBar.left;
+      Rect.right = ScrollBarInfo->rcScrollBar.right;
+   }
+   else
+   {
+      Rect.top = ScrollBarInfo->rcScrollBar.top;
+      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
+      Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
+      Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
+   }
+
+   /* Draw the scroll rectangles and thumb */
+   if (!ScrollBarInfo->xyThumbBottom)
+   {
+      NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
+         Rect.bottom - Rect.top, PATCOPY);
+
+      /* Cleanup and return */
+      NtGdiSelectBrush(hDC, hSaveBrush);
+      return;
+   }
+
+   ThumbTop -= ScrollBarInfo->dxyLineButton;
+
+   if (ScrollBarInfo->dxyLineButton)
+   {
+      if (Vertical)
+      {
+         if (ThumbSize)
+         {
+            NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
+                   ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
+            Rect.top += ThumbTop;
+            NtGdiPatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
+               Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
+            Rect.bottom = Rect.top + ThumbSize;
+         }
+         else
+         {
+            if (ThumbTop)
+            {
+               NtGdiPatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
+                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
+            }
+         }
+      }
+      else
+      {
+         if (ThumbSize)
+         {
+            NtGdiPatBlt(hDC, Rect.left, Rect.top, ThumbTop,
+               Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
+            Rect.left += ThumbTop;
+            NtGdiPatBlt(hDC, Rect.left + ThumbSize, Rect.top,
+               Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
+               BottomSelected ? BLACKNESS : PATCOPY);
+            Rect.right = Rect.left + ThumbSize;
+         }
+         else
+         {
+            if (ThumbTop)
+            {
+               NtGdiPatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
+                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
+            }
+         }
+      }
+   }
+
+   /* Draw the thumb */
+   if (ThumbSize)
+      DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+
+   /* Cleanup */
+   NtGdiSelectBrush(hDC, hSaveBrush);
+}
+
+
+static VOID FASTCALL
+IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
+{
+   RECT RectLT, RectRB;
+   INT ScrollDirFlagLT, ScrollDirFlagRB;
+
+   RectLT = RectRB = ScrollBarInfo->rcScrollBar;
+   if (Vertical)
+   {
+      ScrollDirFlagLT = DFCS_SCROLLUP;
+      ScrollDirFlagRB = DFCS_SCROLLDOWN;
+      RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
+      RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
+   }
+   else
+   {
+      ScrollDirFlagLT = DFCS_SCROLLLEFT;
+      ScrollDirFlagRB = DFCS_SCROLLRIGHT;
+      RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
+      RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
+   }
+
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
+   {
+      ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
+   {
+      ScrollDirFlagLT |= DFCS_INACTIVE;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
+   {
+      ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
+   {
+      ScrollDirFlagRB |= DFCS_INACTIVE;
+   }
+
+   DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
+   DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
+}
+
+static LONG FASTCALL
+IntScrollGetObjectId(INT SBType)
+{
+   if (SBType == SB_VERT)
+       return OBJID_VSCROLL;
+   if (SBType == SB_HORZ)
+       return OBJID_HSCROLL;
+   return OBJID_CLIENT;
+}
+
+void
+IntDrawScrollBar(PWND Wnd, HDC DC, INT Bar)
+{
+   //PSBWND pSBWnd;
+   //INT ThumbSize;
+   PTHREADINFO pti;
+   SCROLLBARINFO Info;
+   BOOL Vertical;
+
+   pti = PsGetCurrentThreadWin32Thread();
+
+  /*
+   * Get scroll bar info.
+   */
+   switch (Bar)
+   {
+      case SB_HORZ:
+        Vertical = FALSE;
+        break;
+
+      case SB_VERT:
+        Vertical = TRUE;
+        break;
+
+      case SB_CTL:
+        Vertical = (Wnd->style & SBS_VERT) != 0;
+        break;
+
+      default:
+        return;
+   }
+
+   if (!co_IntGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), &Info))
+   {
+      return;
+   }
+
+   if (RECTL_bIsEmptyRect(&Info.rcScrollBar))
+   {
+      return;
+   }
+
+  //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
+
+  /*
+   * Draw the arrows.
+   */
+   if (Info.dxyLineButton)
+   {
+      IntDrawScrollArrows(DC, &Info, Vertical);
+   }
+
+  /*
+   * Draw the interior.
+   */
+   IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
+
+  /*
+   * If scroll bar has focus, reposition the caret.
+   */
+   if ( Wnd == pti->MessageQueue->spwndFocus && Bar == SB_CTL )
+   {
+      if (Vertical)
+      {
+          co_IntSetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
+      }
+      else
+      {
+          co_IntSetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
+      }
+   }
+}
+
+
 LRESULT APIENTRY
 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
Index: win32ss/user/ntuser/scrollex.c
===================================================================
--- win32ss/user/ntuser/scrollex.c	(revision 68654)
+++ win32ss/user/ntuser/scrollex.c	(working copy)
@@ -226,6 +226,244 @@
    return Result;
 }
 
+DWORD
+FASTCALL
+IntScrollWindowEx(
+   PWND pWnd,
+   INT dx,
+   INT dy,
+   const RECT *prcScroll,
+   const RECT *prcClip,
+   HRGN hrgnUpdate,
+   LPRECT prcUpdate,
+   UINT flags)
+{
+   RECTL rcScroll, rcClip, rcCaret;
+   INT Result;
+   PWND Window = NULL, CaretWnd;
+   HDC hDC;
+   PREGION RgnUpdate = NULL, RgnTemp, RgnWinupd = NULL;
+   HWND hwndCaret;
+   DWORD dcxflags = 0;
+   int rdw_flags;
+   USER_REFERENCE_ENTRY CaretRef;
+
+   IntGetClientRect(Window, &rcClip);
+
+   if (prcScroll)
+   {
+      RECTL_bIntersectRect(&rcScroll, &rcClip, prcScroll);
+   }
+   else
+      rcScroll = rcClip;
+
+   if (prcClip)
+   {
+      RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
+   }
+
+   if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
+         (dx == 0 && dy == 0))
+   {
+      return NULLREGION;
+   }
+
+   /* We must use a copy of the region, as we can't hold an exclusive lock
+    * on it while doing callouts to user-mode */
+   RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if(!RgnUpdate)
+   {
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return ERROR;
+   }
+
+   if (hrgnUpdate)
+   {
+       RgnTemp = REGION_LockRgn(hrgnUpdate);
+       if (!RgnTemp)
+       {
+           EngSetLastError(ERROR_INVALID_HANDLE);
+           return ERROR;
+       }
+       IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
+       REGION_UnlockRgn(RgnTemp);
+   }
+
+   /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
+   if (flags & SW_SCROLLWNDDCE)
+   {
+      dcxflags = DCX_USESTYLE;
+
+      if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
+         dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
+
+      if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
+         dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
+   }
+   else
+   {
+       /* So in this case ScrollWindowEx uses Cache DC. */
+       dcxflags = DCX_CACHE|DCX_USESTYLE;
+       if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
+   }
+
+   hDC = UserGetDCEx(Window, 0, dcxflags);
+   if (!hDC)
+   {
+      /* FIXME: SetLastError? */
+      return ERROR;
+   }
+
+   rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
+
+   rcCaret = rcScroll;
+   hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
+
+   Result = UserScrollDC( hDC,
+                          dx,
+                          dy,
+                          &rcScroll,
+                          &rcClip,
+                          NULL,
+                          RgnUpdate,
+                          prcUpdate);
+
+   UserReleaseDC(Window, hDC, FALSE);
+
+   /*
+    * Take into account the fact that some damage may have occurred during
+    * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
+    */
+
+   RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if (!RgnTemp)
+   {
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return ERROR;
+   }
+
+   if (co_IntGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION)
+   {
+      PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip);
+      if (RgnClip)
+      {
+          if (hrgnUpdate)
+          {
+             RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0);
+             IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY);
+          }
+
+          REGION_bOffsetRgn(RgnTemp, dx, dy);
+
+          IntGdiCombineRgn(RgnTemp, RgnTemp, RgnClip, RGN_AND);
+
+          if (hrgnUpdate)
+              IntGdiCombineRgn( RgnWinupd, RgnWinupd, RgnTemp, RGN_OR );
+
+          co_UserRedrawWindow(Window, NULL, RgnTemp, rdw_flags );
+
+          REGION_Delete(RgnClip);
+      }
+   }
+   REGION_Delete(RgnTemp);
+
+   if (flags & SW_SCROLLCHILDREN)
+   {
+      PWND Child;
+      RECTL rcChild;
+      POINT ClientOrigin;
+      USER_REFERENCE_ENTRY WndRef;
+      RECTL rcDummy;
+      LPARAM lParam;
+
+      IntGetClientOrigin(Window, &ClientOrigin);
+
+      for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+      {
+         rcChild = Child->rcWindow;
+         rcChild.left -= ClientOrigin.x;
+         rcChild.top -= ClientOrigin.y;
+         rcChild.right -= ClientOrigin.x;
+         rcChild.bottom -= ClientOrigin.y;
+
+         if (!prcScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
+         {
+            UserRefObjectCo(Child, &WndRef);
+
+            if (Window->spwndParent == UserGetDesktopWindow()) // Window->spwndParent->fnid == FNID_DESKTOP )
+               lParam = MAKELONG(Child->rcClient.left, Child->rcClient.top);
+            else
+               lParam = MAKELONG(rcChild.left + dx, rcChild.top + dy);
+
+            /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
+            /* windows sometimes a WM_MOVE */                  
+            co_IntSendMessage(UserHMGetHandle(Child), WM_MOVE, 0, lParam);
+            
+            UserDerefObjectCo(Child);
+         }
+      }
+   }
+
+   if (flags & (SW_INVALIDATE | SW_ERASE))
+   {
+      co_UserRedrawWindow( Window,
+                           NULL,
+                           RgnUpdate,
+                           rdw_flags |                                    /*    HACK    */
+                          ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : RDW_NOCHILDREN) );
+   }
+
+   if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
+   {
+      UserRefObjectCo(CaretWnd, &CaretRef);
+
+      co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
+      co_UserShowCaret(CaretWnd);
+
+      UserDerefObjectCo(CaretWnd);
+   }
+
+   if (hrgnUpdate && (Result != ERROR))
+   {
+       /* Give everything back to the caller */
+       RgnTemp = REGION_LockRgn(hrgnUpdate);
+       /* The handle should still be valid */
+       ASSERT(RgnTemp);
+       if (RgnWinupd)
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, RgnWinupd, RGN_OR);
+       else
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, NULL, RGN_COPY);
+       REGION_UnlockRgn(RgnTemp);
+   }
+
+   if (RgnWinupd)
+   {
+       REGION_Delete(RgnWinupd);
+   }
+
+   if (RgnUpdate)
+   {
+      REGION_Delete(RgnUpdate);
+   }
+
+   if (Window)
+      UserDerefObjectCo(Window);
+
+   return Result;
+}
+
+
+BOOL FASTCALL
+IntScrollWindow(PWND pWnd,
+                int dx,
+                int dy,
+                CONST RECT *lpRect,
+                CONST RECT *prcClip)
+{
+   return IntScrollWindowEx( pWnd, dx, dy, lpRect, prcClip, 0, NULL,
+                            (lpRect ? 0 : SW_SCROLLCHILDREN) | (SW_ERASE|SW_INVALIDATE|SW_SCROLLWNDDCE)) != ERROR;
+}
+
 /*
  * NtUserScrollDC
  *
Index: win32ss/user/ntuser/userfuncs.h
===================================================================
--- win32ss/user/ntuser/userfuncs.h	(revision 68654)
+++ win32ss/user/ntuser/userfuncs.h	(working copy)
@@ -97,14 +97,11 @@
 VOID FASTCALL IntSetWindowState(PWND, UINT);
 VOID FASTCALL IntClearWindowState(PWND, UINT);
 PTHREADINFO FASTCALL IntTID2PTI(HANDLE);
+HBRUSH FASTCALL GetControlBrush(PWND pwnd,HDC  hdc,UINT ctlType);
 
 /*************** MESSAGE.C ***************/
 
-BOOL FASTCALL
-UserPostMessage(HWND Wnd,
-        UINT Msg,
-        WPARAM wParam,
-        LPARAM lParam);
+BOOL FASTCALL UserPostMessage(HWND Wnd,UINT Msg, WPARAM wParam, LPARAM lParam);
 
 /*************** WINDOW.C ***************/
 
@@ -121,12 +118,22 @@
 BOOL FASTCALL UserSetMenuDefaultItem(PMENU Menu, UINT uItem, UINT fByPos);
 BOOL FASTCALL UserDestroyMenu(HMENU hMenu);
 
-/*************** SCROLLBAR.C ***************/
-
-DWORD FASTCALL co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV);
-
 /************** NONCLIENT **************/
 
 VOID FASTCALL DefWndDoSizeMove(PWND pwnd, WORD wParam);
+LRESULT NC_DoNCPaint(PWND,HDC,INT);
+void FASTCALL NC_GetSysPopupPos(PWND, RECT *);
 
+/************** DEFWND **************/
+
+#define DCF_REDRAWHUNGWND 0x20000000
+
+HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType);
+LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam );
+LRESULT NC_HandleNCCalcSize( PWND wnd, WPARAM wparam, RECTL *winRect );
+VOID NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle);
+VOID UserDrawCaptionBar( PWND pWnd, HDC hDC, INT Flags);
+void UserGetInsideRectNC(PWND Wnd, RECT *rect);
+BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down);
+
 /* EOF */
Index: win32ss/user/ntuser/win32.h
===================================================================
--- win32ss/user/ntuser/win32.h	(revision 68654)
+++ win32ss/user/ntuser/win32.h	(working copy)
@@ -52,8 +52,6 @@
 extern struct _CLS *SystemClassList;
 extern BOOL RegisteredSysClasses;
 
-typedef struct tagMENUSTATE MENUSTATE, *PMENUSTATE;
-
 #include <pshpack1.h>
 // FIXME: Move to ntuser.h
 typedef struct _TL
@@ -110,7 +108,7 @@
     HDESK               hdesk;
     UINT                cPaintsReady; /* Count of paints pending. */
     UINT                cTimersReady; /* Count of timers pending. */
-    PMENUSTATE          pMenuState;
+    struct tagMENUSTATE* pMenuState;
     DWORD               dwExpWinVer;
     DWORD               dwCompatFlags;
     DWORD               dwCompatFlags2;
@@ -173,6 +171,7 @@
     if (InterlockedDecrement(&(pti)->RefCount) == 0) \
     { \
         ASSERT(((pti)->TIF_flags & (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)) == (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)); \
+        ExFreePoolWithTag(pti->pMenuState, USERTAG_MENUSTATE); \
         UserDeleteW32Thread(pti); \
     } \
 } while(0)
Index: win32ss/user/ntuser/window.c
===================================================================
--- win32ss/user/ntuser/window.c	(revision 68654)
+++ win32ss/user/ntuser/window.c	(working copy)
@@ -362,6 +362,20 @@
     return Ret;
 }
 
+DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd )
+{
+   PPROPERTY HelpId;
+
+   do
+   {
+      HelpId = IntGetProp(pWnd, gpsi->atomContextHelpIdProp);
+      if (!HelpId) break;
+      pWnd = IntGetParent(pWnd);
+   }
+   while (pWnd && pWnd->fnid != FNID_DESKTOP);
+   return (DWORD) (HelpId ? HelpId->Data : 0 );
+}
+
 /***********************************************************************
  *           IntSendDestroyMsg
  */
Index: win32ss/user/ntuser/winpos.h
===================================================================
--- win32ss/user/ntuser/winpos.h	(revision 68654)
+++ win32ss/user/ntuser/winpos.h	(working copy)
@@ -69,3 +69,5 @@
 BOOL FASTCALL IntScreenToClient(PWND,LPPOINT);
 BOOL FASTCALL IntClientToScreen(PWND,LPPOINT);
 BOOL FASTCALL IntGetWindowRect(PWND,RECTL*);
+BOOL UserHasWindowEdge(DWORD,DWORD);
+VOID UserGetWindowBorders(DWORD,DWORD,SIZE*,BOOL);
Index: win32ss/user/ntuser/winsta.c
===================================================================
--- win32ss/user/ntuser/winsta.c	(revision 68654)
+++ win32ss/user/ntuser/winsta.c	(working copy)
@@ -297,6 +297,9 @@
    /* Setup the icons */
    co_IntSetWndIcons();
 
+   /* Setup Menu */
+   MenuInit();
+
    /* Show the desktop */
    pdesk = IntGetActiveDesktop();
    ASSERT(pdesk);
Index: win32ss/user/rtl/text.c
===================================================================
--- win32ss/user/rtl/text.c	(revision 68599)
+++ win32ss/user/rtl/text.c	(working copy)
@@ -18,8 +18,8 @@
  */
 /*
  * PROJECT:         ReactOS user32.dll
- * FILE:            lib/user32/windows/input.c
- * PURPOSE:         Input
+ * FILE:            win32ss/user/rtl/text.c
+ * PURPOSE:         Draw Text
  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
  * UPDATE HISTORY:
  *      09-05-2001  CSH  Created
@@ -27,15 +27,15 @@
 
 /* INCLUDES ******************************************************************/
 
+#ifdef _WIN32K_
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserMenu);
+#else
 #include <user32.h>
-
 #include <wine/debug.h>
-
 WINE_DEFAULT_DEBUG_CHANNEL(text);
+#endif
 
-DWORD WINAPI GdiGetCodePage(HDC hdc);
-
-
 /* FUNCTIONS *****************************************************************/
 
 #ifndef NDEBUG
@@ -47,7 +47,7 @@
 #define assert(e) ((e) ? (void)0 : _font_assert(#e, __FILE__, __LINE__))
 
 #else
-#include <assert.h> 
+#include <assert.h>
 
 #endif
 
@@ -55,41 +55,14 @@
 {
   /* Assertion failed at foo.c line 45: x<y */
   DbgPrint("Assertion failed at %s line %d: %s\n", file, line, msg);
-  ExitProcess(3);
+#ifdef _WIN32K_
+  ASSERT(FALSE);
+#else
+  ExitProcess(3);  
   for(;;); /* eliminate warning by mingw */
+#endif
 }
 
-/*
- * @implemented
- */
-LONG
-WINAPI
-TabbedTextOutA(
-  HDC hDC,
-  int X,
-  int Y,
-  LPCSTR lpString,
-  int nCount,
-  int nTabPositions,
-  CONST INT *lpnTabStopPositions,
-  int nTabOrigin)
-{
-  LONG ret;
-  DWORD len;
-  LPWSTR strW;
-  UINT cp = GdiGetCodePage( hDC ); // CP_ACP
-
-  len = MultiByteToWideChar(cp, 0, lpString, nCount, NULL, 0);
-  if (!len) return 0;
-  strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-  if (!strW) return 0;
-  MultiByteToWideChar(cp, 0, lpString, nCount, strW, len);
-  ret = TabbedTextOutW(hDC, X, Y, strW, len, nTabPositions, lpnTabStopPositions, nTabOrigin);
-  HeapFree(GetProcessHeap(), 0, strW);
-  return ret;
-}
-
-
 /***********************************************************************
  *           TEXT_TabbedTextOut
  *
@@ -98,9 +71,15 @@
  *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
  */
 /* WINE synced 22-May-2006 */
-static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr,
-                                INT count, INT cTabStops, const INT *lpTabPos, INT nTabOrg,
-                                BOOL fDisplayText )
+LONG TEXT_TabbedTextOut( HDC hdc,
+                         INT x,
+                         INT y,
+                         LPCWSTR lpstr,
+                         INT count,
+                         INT cTabStops,
+                         const INT *lpTabPos,
+                         INT nTabOrg,
+                         BOOL fDisplayText )
 {
     INT defWidth;
     SIZE extent;
@@ -117,8 +96,13 @@
     }
     else
     {
+#ifdef _WIN32K_
+        TEXTMETRICW tm;
+        GreGetTextMetricsW( hdc, &tm );
+#else
         TEXTMETRICA tm;
         GetTextMetricsA( hdc, &tm );
+#endif
         defWidth = 8 * tm.tmAveCharWidth;
     }
 
@@ -135,7 +119,11 @@
         for (j = i; j < count; j++)
             if (lpstr[j] == '\t') break;
         /* get the extent of the normal character part */
+#ifdef _WIN32K_
+        GreGetTextExtentW( hdc, (LPWSTR)lpstr + i, j - i , &extent, 0 );
+#else
         GetTextExtentPointW( hdc, lpstr + i, j - i , &extent );
+#endif
         /* and if there is a <tab>, calculate its position */
         if( i) {
             /* get x coordinate for the drawing of this string */
@@ -179,8 +167,13 @@
             r.top    = y;
             r.right  = x;
             r.bottom = y + extent.cy;
+#ifdef _WIN32K_
+            GreExtTextOutW( hdc, x0, y, GreGetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
+                         &r, (LPWSTR)lpstr + i, j - i, NULL, 0 );
+#else
             ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
                          &r, lpstr + i, j - i, NULL );
+#endif
         }
         count -= j;
         lpstr += j;
@@ -188,67 +181,6 @@
     return MAKELONG(x - start, extent.cy);
 }
 
-/*
- * @implemented
- */
-LONG
-WINAPI
-TabbedTextOutW(
-  HDC hDC,
-  int X,
-  int Y,
-  LPCWSTR lpString,
-  int nCount,
-  int nTabPositions,
-  CONST INT *lpnTabStopPositions,
-  int nTabOrigin)
-{
-  return TEXT_TabbedTextOut(hDC, X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin, TRUE);
-}
-
-/* WINE synced 22-May-2006 */
-/*
- * @implemented
- */
-DWORD
-WINAPI
-GetTabbedTextExtentA(
-  HDC hDC,
-  LPCSTR lpString,
-  int nCount,
-  int nTabPositions,
-  CONST INT *lpnTabStopPositions)
-{
-    LONG ret;
-    UINT cp = GdiGetCodePage( hDC ); // CP_ACP
-    DWORD len;
-    LPWSTR strW;
-
-    len = MultiByteToWideChar(cp, 0, lpString, nCount, NULL, 0);
-    if (!len) return 0;
-    strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-    if (!strW) return 0;
-    MultiByteToWideChar(cp, 0, lpString, nCount, strW, len);
-    ret = GetTabbedTextExtentW(hDC, strW, len, nTabPositions, lpnTabStopPositions);
-    HeapFree(GetProcessHeap(), 0, strW);
-    return ret;
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-GetTabbedTextExtentW(
-  HDC hDC,
-  LPCWSTR lpString,
-  int nCount,
-  int nTabPositions,
-  CONST INT *lpnTabStopPositions)
-{
-   return TEXT_TabbedTextOut(hDC, 0, 0, lpString, nCount, nTabPositions, lpnTabStopPositions, 0, FALSE);
-}
-
 /*********************************************************************
  *
  *            DrawText functions
@@ -349,8 +281,11 @@
 {
     unsigned int len_ellipsis;
     unsigned int lo, mid, hi;
-
+#ifdef _WIN32K_
+    len_ellipsis = wcslen (ELLIPSISW);
+#else
     len_ellipsis = strlenW (ELLIPSISW);
+#endif
     if (len_ellipsis > max_len) len_ellipsis = max_len;
     if (*len_str > max_len - len_ellipsis)
         *len_str = max_len - len_ellipsis;
@@ -357,13 +292,21 @@
 
     /* First do a quick binary search to get an upper bound for *len_str. */
     if (*len_str > 0 &&
+#ifdef _WIN32K_
+        GreGetTextExtentExW(hdc, str, *len_str, width, NULL, NULL, size, 0) &&
+#else
         GetTextExtentExPointW(hdc, str, *len_str, width, NULL, NULL, size) &&
+#endif
         size->cx > width)
     {
         for (lo = 0, hi = *len_str; lo < hi; )
         {
             mid = (lo + hi) / 2;
+#ifdef _WIN32K_
+            if (!GreGetTextExtentExW(hdc, str, mid, width, NULL, NULL, size, 0))
+#else
             if (!GetTextExtentExPointW(hdc, str, mid, width, NULL, NULL, size))
+#endif
                 break;
             if (size->cx > width)
                 hi = mid;
@@ -376,10 +319,13 @@
     for ( ; ; )
     {
         memcpy(str + *len_str, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
-
+#ifdef _WIN32K_
+        if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size, 0)) break;
+#else
         if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
                                     NULL, NULL, size)) break;
-
+#endif
         if (!*len_str || size->cx <= width) break;
 
         (*len_str)--;
@@ -446,8 +392,11 @@
     int len_trailing;
     int len_under;
     WCHAR *lastBkSlash, *lastFwdSlash, *lastSlash;
-
+#ifdef _WIN32K_
+    len_ellipsis = wcslen (ELLIPSISW);
+#else
     len_ellipsis = strlenW (ELLIPSISW);
+#endif
     if (!max_len) return;
     if (len_ellipsis >= max_len) len_ellipsis = max_len - 1;
     if (*len_str + len_ellipsis >= max_len)
@@ -456,9 +405,13 @@
          * the wrong character
          */
     str[*len_str] = '\0'; /* to simplify things */
-
+#ifdef _WIN32K_
+    lastBkSlash  = wcsrchr (str, BACK_SLASH);
+    lastFwdSlash = wcsrchr (str, FORWARD_SLASH);
+#else
     lastBkSlash  = strrchrW (str, BACK_SLASH);
     lastFwdSlash = strrchrW (str, FORWARD_SLASH);
+#endif
     lastSlash = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
     if (!lastSlash) lastSlash = str;
     len_trailing = *len_str - (lastSlash - str);
@@ -474,9 +427,13 @@
     len_under = 0;
     for ( ; ; )
     {
+#ifdef _WIN32K_
+        if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size, 0)) break;
+#else
         if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
                                     NULL, NULL, size)) break;
-
+#endif
         if (lastSlash == str || size->cx <= width) break;
 
         /* overlap-safe movement to the left */
@@ -670,7 +627,11 @@
         }
     }
     /* Remeasure the string */
+#ifdef _WIN32K_
+    GreGetTextExtentExW (hdc, str, *len_str, 0, NULL, NULL, size, 0);
+#else
     GetTextExtentExPointW (hdc, str, *len_str, 0, NULL, NULL, size);
+#endif
 }
 
 /*********************************************************************
@@ -918,7 +879,11 @@
 
         j_in_seg = j - seg_j;
         max_seg_width = width - plen;
+#ifdef _WIN32K_
+        GreGetTextExtentExW (hdc, dest + seg_j, j_in_seg, max_seg_width, (PULONG)&num_fit, NULL, &size, 0);
+#else
         GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size);
+#endif
 
         /* The Microsoft handling of various combinations of formats is weird.
          * The following may very easily be incorrect if several formats are
@@ -1059,10 +1024,17 @@
     SIZE size;
     HPEN hpen;
     HPEN oldPen;
-
+#ifdef _WIN32K_
+    GreGetTextExtentW (hdc, (LPWSTR)str, offset, &size, 0);
+#else
     GetTextExtentPointW (hdc, str, offset, &size);
+#endif
     prefix_x = x + size.cx;
+#ifdef _WIN32K_
+    GreGetTextExtentW (hdc, (LPWSTR)str, offset+1, &size, 0);
+#else
     GetTextExtentPointW (hdc, str, offset+1, &size);
+#endif
     prefix_end = x + size.cx - 1;
     /* The above method may eventually be slightly wrong due to kerning etc. */
 
@@ -1076,7 +1048,14 @@
         if (prefix_x   < rect->left ) prefix_x   = rect->left;
         if (prefix_end > rect->right) prefix_end = rect->right;
     }
-
+#ifdef _WIN32K_
+    hpen = NtGdiCreatePen (PS_SOLID, 1, GreGetTextColor (hdc), NULL);
+    oldPen = NtGdiSelectPen (hdc, hpen);
+    GreMoveTo (hdc, prefix_x, y, NULL);
+    NtGdiLineTo (hdc, prefix_end, y);
+    NtGdiSelectPen (hdc, oldPen);
+    GreDeleteObject (hpen);
+#else
     hpen = CreatePen (PS_SOLID, 1, GetTextColor (hdc));
     oldPen = SelectObject (hdc, hpen);
     MoveToEx (hdc, prefix_x, y, NULL);
@@ -1083,6 +1062,7 @@
     LineTo (hdc, prefix_end, y);
     SelectObject (hdc, oldPen);
     DeleteObject (hpen);
+#endif
 }
 
 /***********************************************************************
@@ -1097,12 +1077,16 @@
  */
 #define MAX_BUFFER 1024
 /* 
- * @implemented
+ * DrawTextExW
  *
  * Synced with Wine Staging 1.7.37
  */
-INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
-                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
+INT WINAPI DrawTextExWorker( HDC hdc,
+                             LPWSTR str,
+                             INT i_count,
+                             LPRECT rect,
+                             UINT flags,
+                             LPDRAWTEXTPARAMS dtp )
 {
     SIZE size;
     const WCHAR *strPtr;
@@ -1120,10 +1104,12 @@
     int prefix_offset;
     ellipsis_data ellip;
     BOOL invert_y=FALSE;
-
+#ifdef _WIN32K_
+    TRACE("%S, %d, %08x\n", str, count, flags);
+#else
     TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str, count), count,
         wine_dbgstr_rect(rect), flags);
-
+#endif
     if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
           dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
 
@@ -1133,8 +1119,11 @@
 
     if (flags & DT_SINGLELINE)
         flags &= ~DT_WORDBREAK;
-
+#ifdef _WIN32K_
+    GreGetTextMetricsW(hdc, &tm);
+#else
     GetTextMetricsW(hdc, &tm);
+#endif
     if (flags & DT_EXTERNALLEADING)
 	lh = tm.tmHeight + tm.tmExternalLeading;
     else
@@ -1145,7 +1134,16 @@
 
     if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
         return 0;
-
+#ifdef _WIN32K_
+    if (GreGetGraphicsMode(hdc) == GM_COMPATIBLE)
+    {
+        SIZE window_ext, viewport_ext;
+        GreGetWindowExtEx(hdc, &window_ext);
+        GreGetViewportExtEx(hdc, &viewport_ext);
+        if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
+            invert_y = TRUE;
+    }
+#else
     if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
     {
         SIZE window_ext, viewport_ext;
@@ -1154,10 +1152,14 @@
         if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
             invert_y = TRUE;
     }
-
+#endif
     if (count == -1)
     {
+#ifdef _WIN32K_
+        count = wcslen(str);
+#else
         count = strlenW(str);
+#endif
         if (count == 0)
         {
             if( flags & DT_CALCRECT)
@@ -1192,7 +1194,11 @@
     if (flags & DT_MODIFYSTRING)
     {
         size_retstr = (count + 4) * sizeof (WCHAR);
+#ifdef _WIN32K_
+        retstr = ExAllocatePoolWithTag(PagedPool, size_retstr, USERTAG_RTL);
+#else
         retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
+#endif
         if (!retstr) return 0;
         memcpy (retstr, str, size_retstr);
     }
@@ -1264,21 +1270,40 @@
                     const WCHAR *p;
                     p = str; while (p < str+len && *p != TAB) p++;
                     len_seg = p - str;
-                    if (len_seg != len && !GetTextExtentPointW(hdc, str, len_seg, &size))
+                    if (len_seg != len &&
+#ifdef _WIN32K_
+                        !GreGetTextExtentW(hdc, (LPWSTR)str, len_seg, &size, 0))
+#else
+                        !GetTextExtentPointW(hdc, str, len_seg, &size))
+#endif
                     {
+#ifdef _WIN32K_
+                        ExFreePoolWithTag(retstr, USERTAG_RTL);
+#else
                         HeapFree (GetProcessHeap(), 0, retstr);
+#endif
                         return 0;
                     }
                 }
                 else
                     len_seg = len;
-
+#ifdef _WIN32K_
+                if (!GreExtTextOutW( hdc, xseg, y,
+                                    ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
+                                    ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
+                                    rect, (LPWSTR)str, len_seg, NULL, 0 ))
+#else
                 if (!ExtTextOutW( hdc, xseg, y,
                                  ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
                                  ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
                                  rect, str, len_seg, NULL ))
+#endif
                 {
+#ifdef _WIN32K_
+                    ExFreePoolWithTag(retstr, USERTAG_RTL);
+#else
                     HeapFree (GetProcessHeap(), 0, retstr);
+#endif
                     return 0;
                 }
                 if (prefix_offset != -1 && prefix_offset < len_seg)
@@ -1329,129 +1354,12 @@
     if (retstr)
     {
         memcpy (str, retstr, size_retstr);
+#ifdef _WIN32K_
+        ExFreePoolWithTag(retstr, USERTAG_RTL);
+#else
         HeapFree (GetProcessHeap(), 0, retstr);
+#endif
     }
     return y - rect->top;
 }
 
-/***********************************************************************
- *           DrawTextExA    (USER32.@)
- *
- * If DT_MODIFYSTRING is specified then there must be room for up to
- * 4 extra characters.  We take great care about just how much modified
- * string we return.
- *
- * @implemented
- *
- * Synced with Wine Staging 1.7.37
- */
-INT WINAPI DrawTextExA( HDC hdc, LPSTR str, INT count,
-                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
-{
-   WCHAR *wstr;
-   WCHAR *p;
-   INT ret = 0;
-   int i;
-   DWORD wcount;
-   DWORD wmax;
-   DWORD amax;
-   UINT cp;
-
-   if (!count) return 0;
-   if (!str && count > 0) return 0;
-   if( !str || ((count == -1) && !(count = strlen(str))))
-   {
-        int lh;
-        TEXTMETRICA tm;
-
-        if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
-            return 0;
-
-        GetTextMetricsA(hdc, &tm);
-        if (flags & DT_EXTERNALLEADING)
-            lh = tm.tmHeight + tm.tmExternalLeading;
-        else
-            lh = tm.tmHeight;
-
-        if( flags & DT_CALCRECT)
-        {
-            rect->right = rect->left;
-            if( flags & DT_SINGLELINE)
-                rect->bottom = rect->top + lh;
-            else
-                rect->bottom = rect->top;
-        }
-        return lh;
-   }
-   cp = GdiGetCodePage( hdc );
-   wcount = MultiByteToWideChar( cp, 0, str, count, NULL, 0 );
-   wmax = wcount;
-   amax = count;
-   if (flags & DT_MODIFYSTRING)
-   {
-        wmax += 4;
-        amax += 4;
-   }
-   wstr = HeapAlloc(GetProcessHeap(), 0, wmax * sizeof(WCHAR));
-   if (wstr)
-   {
-       MultiByteToWideChar( cp, 0, str, count, wstr, wcount );
-       if (flags & DT_MODIFYSTRING)
-           for (i=4, p=wstr+wcount; i--; p++) *p=0xFFFE;
-           /* Initialise the extra characters so that we can see which ones
-            * change.  U+FFFE is guaranteed to be not a unicode character and
-            * so will not be generated by DrawTextEx itself.
-            */
-       ret = DrawTextExW( hdc, wstr, wcount, rect, flags, dtp );
-       if (flags & DT_MODIFYSTRING)
-       {
-            /* Unfortunately the returned string may contain multiple \0s
-             * and so we need to measure it ourselves.
-             */
-            for (i=4, p=wstr+wcount; i-- && *p != 0xFFFE; p++) wcount++;
-            WideCharToMultiByte( cp, 0, wstr, wcount, str, amax, NULL, NULL );
-       }
-       HeapFree(GetProcessHeap(), 0, wstr);
-   }
-   return ret;
-}
-
-/***********************************************************************
- *           DrawTextW    (USER32.@)
- *
- * @implemented
- * Synced with Wine Staging 1.7.37
- */
-INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
-{
-    DRAWTEXTPARAMS dtp;
-
-    memset (&dtp, 0, sizeof(dtp));
-    dtp.cbSize = sizeof(dtp);
-    if (flags & DT_TABSTOP)
-    {
-        dtp.iTabLength = (flags >> 8) & 0xff;
-        flags &= 0xffff00ff;
-    }
-    return DrawTextExW(hdc, (LPWSTR)str, count, rect, flags, &dtp);
-}
-
-/***********************************************************************
- *           DrawTextA    (USER32.@)
- *
- * @implemented
- * Synced with Wine Staging 1.7.37
- */
-INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count, LPRECT rect, UINT flags )
-{
-    DRAWTEXTPARAMS dtp;
-
-    memset (&dtp, 0, sizeof(dtp));
-    dtp.cbSize = sizeof(dtp);
-    if (flags & DT_TABSTOP)
-    {
-        dtp.iTabLength = (flags >> 8) & 0xff;
-        flags &= 0xffff00ff;
-    }
-    return DrawTextExA( hdc, (LPSTR)str, count, rect, flags, &dtp );
-}
Index: win32ss/user/user32/CMakeLists.txt
===================================================================
--- win32ss/user/user32/CMakeLists.txt	(revision 68654)
+++ win32ss/user/user32/CMakeLists.txt	(working copy)
@@ -60,6 +60,7 @@
     windows/text.c
     windows/window.c
     windows/winpos.c
+    ${REACTOS_SOURCE_DIR}/win32ss/user/rtl/text.c
     ${CMAKE_CURRENT_BINARY_DIR}/user32_stubs.c
     include/user32.h)
 
Index: win32ss/user/user32/windows/defwnd.c
===================================================================
--- win32ss/user/user32/windows/defwnd.c	(revision 68654)
+++ win32ss/user/user32/windows/defwnd.c	(working copy)
@@ -549,9 +549,12 @@
 
     switch (Msg)
     {
-	case WM_NCPAINT:
+/*	case WM_NCPAINT:
 	{
-            return DefWndNCPaint(hWnd, (HRGN)wParam, -1);
+	    NtUserxSetWindowState(pWnd, 16);
+            DefWndNCPaint(hWnd, (HRGN)wParam, -1);
+            NtUserxClearWindowState(pWnd, 16);
+            return 0;
         }
 
         case WM_NCCALCSIZE:
@@ -558,7 +561,7 @@
         {
             return DefWndNCCalcSize(hWnd, (BOOL)wParam, (RECT*)lParam);
         }
-
+*/
         case WM_POPUPSYSTEMMENU:
         {
             /* This is an undocumented message used by the windows taskbar to
@@ -570,12 +573,12 @@
                                LOWORD(lParam), HIWORD(lParam), 0, hWnd, NULL);
             return 0;
         }
-
+/*
         case WM_NCACTIVATE:
         {
             return DefWndNCActivate(hWnd, wParam, lParam);
         }
-
+*/
         case WM_NCHITTEST:
         {
             POINT Point;
@@ -704,7 +707,7 @@
             InvalidateRect(hWnd,NULL,TRUE);
             return (0);
         }
-
+#if 0
         case WM_PAINTICON:
         case WM_PAINT:
         {
@@ -738,7 +741,7 @@
             }
             return (0);
         }
-
+#endif
         case WM_CLOSE:
             DestroyWindow(hWnd);
             return (0);
@@ -1201,6 +1204,13 @@
 /* Move to Win32k !*/
         case WM_SHOWWINDOW:
             if (!lParam) break; // Call when it is necessary.
+        case WM_PAINTICON:
+        case WM_PAINT:
+        case WM_NCUAHDRAWCAPTION:
+        case WM_NCUAHDRAWFRAME:
+        case WM_NCPAINT:
+        case WM_NCACTIVATE:
+        case WM_NCCALCSIZE:
         case WM_SYNCPAINT:
         case WM_SETREDRAW:
         case WM_CLIENTSHUTDOWN:
Index: win32ss/user/user32/windows/draw.c
===================================================================
--- win32ss/user/user32/windows/draw.c	(revision 68654)
+++ win32ss/user/user32/windows/draw.c	(working copy)
@@ -979,6 +979,14 @@
     TCHAR Symbol;
     switch(uFlags & 0xff)
     {
+        case DFCS_MENUARROWUP:
+            Symbol = '5';
+            break;
+
+        case DFCS_MENUARROWDOWN:
+            Symbol = '6';
+            break;
+
         case DFCS_MENUARROW:
             Symbol = '8';
             break;
Index: win32ss/user/user32/windows/font.c
===================================================================
--- win32ss/user/user32/windows/font.c	(revision 68654)
+++ win32ss/user/user32/windows/font.c	(working copy)
@@ -18,8 +18,8 @@
  */
 /*
  * PROJECT:         ReactOS user32.dll
- * FILE:            lib/user32/windows/input.c
- * PURPOSE:         Input
+ * FILE:            win32ss/user/user32/windows/font.c
+ * PURPOSE:         Draw Text
  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
  * UPDATE HISTORY:
  *      09-05-2001  CSH  Created
@@ -35,30 +35,15 @@
 
 DWORD WINAPI GdiGetCodePage(HDC hdc);
 
+INT WINAPI DrawTextExWorker( HDC hdc, LPWSTR str, INT i_count,
+                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp );
 
+LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr,
+                                INT count, INT cTabStops, const INT *lpTabPos, INT nTabOrg,
+                                                                BOOL fDisplayText );
+
 /* FUNCTIONS *****************************************************************/
 
-#ifndef NDEBUG
-
-#ifdef assert
-#undef assert
-#endif
-
-#define assert(e) ((e) ? (void)0 : _font_assert(#e, __FILE__, __LINE__))
-
-#else
-#include <assert.h> 
-
-#endif
-
-void _font_assert(const char *msg, const char *file, int line)
-{
-  /* Assertion failed at foo.c line 45: x<y */
-  DbgPrint("Assertion failed at %s line %d: %s\n", file, line, msg);
-  ExitProcess(3);
-  for(;;); /* eliminate warning by mingw */
-}
-
 /*
  * @implemented
  */
@@ -89,105 +74,6 @@
   return ret;
 }
 
-
-/***********************************************************************
- *           TEXT_TabbedTextOut
- *
- * Helper function for TabbedTextOut() and GetTabbedTextExtent().
- * Note: this doesn't work too well for text-alignment modes other
- *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
- */
-/* WINE synced 22-May-2006 */
-static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr,
-                                INT count, INT cTabStops, const INT *lpTabPos, INT nTabOrg,
-                                BOOL fDisplayText )
-{
-    INT defWidth;
-    SIZE extent;
-    int i, j;
-    int start = x;
-
-    if (!lpTabPos)
-        cTabStops=0;
-
-    if (cTabStops == 1)
-    {
-        defWidth = *lpTabPos;
-        cTabStops = 0;
-    }
-    else
-    {
-        TEXTMETRICA tm;
-        GetTextMetricsA( hdc, &tm );
-        defWidth = 8 * tm.tmAveCharWidth;
-    }
-
-    while (count > 0)
-    {
-        RECT r;
-        INT x0;
-        x0 = x;
-        r.left = x0;
-        /* chop the string into substrings of 0 or more <tabs>
-         * possibly followed by 1 or more normal characters */
-        for (i = 0; i < count; i++)
-            if (lpstr[i] != '\t') break;
-        for (j = i; j < count; j++)
-            if (lpstr[j] == '\t') break;
-        /* get the extent of the normal character part */
-        GetTextExtentPointW( hdc, lpstr + i, j - i , &extent );
-        /* and if there is a <tab>, calculate its position */
-        if( i) {
-            /* get x coordinate for the drawing of this string */
-            for (; cTabStops > i; lpTabPos++, cTabStops--)
-            {
-                if( nTabOrg + abs( *lpTabPos) > x) {
-                    if( lpTabPos[ i - 1] >= 0) {
-                        /* a left aligned tab */
-                        x = nTabOrg + lpTabPos[ i-1] + extent.cx;
-                        break;
-                    }
-                    else
-                    {
-                        /* if tab pos is negative then text is right-aligned
-                         * to tab stop meaning that the string extends to the
-                         * left, so we must subtract the width of the string */
-                        if (nTabOrg - lpTabPos[ i - 1] - extent.cx > x)
-                        {
-                            x = nTabOrg - lpTabPos[ i - 1];
-                            x0 = x - extent.cx;
-                            break;
-                        }
-                    }
-                }
-            }
-            /* if we have run out of tab stops and we have a valid default tab
-             * stop width then round x up to that width */
-            if ((cTabStops <= i) && (defWidth > 0)) {
-                x0 = nTabOrg + ((x - nTabOrg) / defWidth + i) * defWidth;
-                x = x0 + extent.cx;
-            } else if ((cTabStops <= i) && (defWidth < 0)) {
-                x = nTabOrg + ((x - nTabOrg + extent.cx) / -defWidth + i)
-                    * -defWidth;
-                x0 = x - extent.cx;
-            }
-        } else
-            x += extent.cx;
-
-        if (fDisplayText)
-        {
-            r.top    = y;
-            r.right  = x;
-            r.bottom = y + extent.cy;
-            ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
-                         &r, lpstr + i, j - i, NULL );
-        }
-        count -= j;
-        lpstr += j;
-    }
-    return MAKELONG(x - start, extent.cy);
-}
-
 /*
  * @implemented
  */
@@ -249,843 +135,8 @@
    return TEXT_TabbedTextOut(hDC, 0, 0, lpString, nCount, nTabPositions, lpnTabStopPositions, 0, FALSE);
 }
 
-/*********************************************************************
- *
- *            DrawText functions
- *
- * Copied from Wine.
- *   Copyright 1993, 1994 Alexandre Julliard
- *   Copyright 2002 Bill Medland
- *
- * Design issues
- *   How many buffers to use
- *     While processing in DrawText there are potentially three different forms
- *     of the text that need to be held.  How are they best held?
- *     1. The original text is needed, of course, to see what to display.
- *     2. The text that will be returned to the user if the DT_MODIFYSTRING is
- *        in effect.
- *     3. The buffered text that is about to be displayed e.g. the current line.
- *        Typically this will exclude the ampersands used for prefixing etc.
- *
- *     Complications.
- *     a. If the buffered text to be displayed includes the ampersands then
- *        we will need special measurement and draw functions that will ignore
- *        the ampersands (e.g. by copying to a buffer without the prefix and
- *        then using the normal forms).  This may involve less space but may
- *        require more processing.  e.g. since a line containing tabs may
- *        contain several underlined characters either we need to carry around
- *        a list of prefix locations or we may need to locate them several
- *        times.
- *     b. If we actually directly modify the "original text" as we go then we
- *        will need some special "caching" to handle the fact that when we
- *        ellipsify the text the ellipsis may modify the next line of text,
- *        which we have not yet processed.  (e.g. ellipsification of a W at the
- *        end of a line will overwrite the W, the \n and the first character of
- *        the next line, and a \0 will overwrite the second.  Try it!!)
- *
- *     Option 1.  Three separate storages. (To be implemented)
- *       If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold
- *       the edited string in some form, either as the string itself or as some
- *       sort of "edit list" to be applied just before returning.
- *       Use a buffer that holds the ellipsified current line sans ampersands
- *       and accept the need occasionally to recalculate the prefixes (if
- *       DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX)
- */
 
-#define TAB     9
-#define LF     10
-#define CR     13
-#define SPACE  32
-#define PREFIX 38
-#define ALPHA_PREFIX 30 /* Win16: Alphabet prefix */
-#define KANA_PREFIX  31 /* Win16: Katakana prefix */
-
-#define FORWARD_SLASH '/'
-#define BACK_SLASH '\\'
-
-static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
-
-typedef struct tag_ellipsis_data
-{
-    int before;
-    int len;
-    int under;
-    int after;
-} ellipsis_data;
-
-/*********************************************************************
- *                      TEXT_Ellipsify (static)
- *
- *  Add an ellipsis to the end of the given string whilst ensuring it fits.
- *
- * If the ellipsis alone doesn't fit then it will be returned anyway.
- *
- * See Also TEXT_PathEllipsify
- *
- * Arguments
- *   hdc        [in] The handle to the DC that defines the font.
- *   str        [in/out] The string that needs to be modified.
- *   max_str    [in] The dimension of str (number of WCHAR).
- *   len_str    [in/out] The number of characters in str
- *   width      [in] The maximum width permitted (in logical coordinates)
- *   size       [out] The dimensions of the text
- *   modstr     [out] The modified form of the string, to be returned to the
- *                    calling program.  It is assumed that the caller has
- *                    made sufficient space available so we don't need to
- *                    know the size of the space.  This pointer may be NULL if
- *                    the modified string is not required.
- *   len_before [out] The number of characters before the ellipsis.
- *   len_ellip  [out] The number of characters in the ellipsis.
- *
- * See for example Microsoft article Q249678.
- *
- * For now we will simply use three dots rather than worrying about whether
- * the font contains an explicit ellipsis character.
- */
-static void TEXT_Ellipsify (HDC hdc, WCHAR *str, unsigned int max_len,
-                            unsigned int *len_str, int width, SIZE *size,
-                            WCHAR *modstr,
-                            int *len_before, int *len_ellip)
-{
-    unsigned int len_ellipsis;
-    unsigned int lo, mid, hi;
-
-    len_ellipsis = strlenW (ELLIPSISW);
-    if (len_ellipsis > max_len) len_ellipsis = max_len;
-    if (*len_str > max_len - len_ellipsis)
-        *len_str = max_len - len_ellipsis;
-
-    /* First do a quick binary search to get an upper bound for *len_str. */
-    if (*len_str > 0 &&
-        GetTextExtentExPointW(hdc, str, *len_str, width, NULL, NULL, size) &&
-        size->cx > width)
-    {
-        for (lo = 0, hi = *len_str; lo < hi; )
-        {
-            mid = (lo + hi) / 2;
-            if (!GetTextExtentExPointW(hdc, str, mid, width, NULL, NULL, size))
-                break;
-            if (size->cx > width)
-                hi = mid;
-            else
-                lo = mid + 1;
-        }
-        *len_str = hi;
-    }
-    /* Now this should take only a couple iterations at most. */
-    for ( ; ; )
-    {
-        memcpy(str + *len_str, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
-
-        if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
-                                    NULL, NULL, size)) break;
-
-        if (!*len_str || size->cx <= width) break;
-
-        (*len_str)--;
-    }
-    *len_ellip = len_ellipsis;
-    *len_before = *len_str;
-    *len_str += len_ellipsis;
-
-    if (modstr)
-    {
-        memcpy (modstr, str, *len_str * sizeof(WCHAR));
-        modstr[*len_str] = '\0';
-    }
-}
-
-/*********************************************************************
- *                      TEXT_PathEllipsify (static)
- *
- * Add an ellipsis to the provided string in order to make it fit within
- * the width.  The ellipsis is added as specified for the DT_PATH_ELLIPSIS
- * flag.
- *
- * See Also TEXT_Ellipsify
- *
- * Arguments
- *   hdc        [in] The handle to the DC that defines the font.
- *   str        [in/out] The string that needs to be modified
- *   max_str    [in] The dimension of str (number of WCHAR).
- *   len_str    [in/out] The number of characters in str
- *   width      [in] The maximum width permitted (in logical coordinates)
- *   size       [out] The dimensions of the text
- *   modstr     [out] The modified form of the string, to be returned to the
- *                    calling program.  It is assumed that the caller has
- *                    made sufficient space available so we don't need to
- *                    know the size of the space.  This pointer may be NULL if
- *                    the modified string is not required.
- *   pellip     [out] The ellipsification results
- *
- * For now we will simply use three dots rather than worrying about whether
- * the font contains an explicit ellipsis character.
- *
- * The following applies, I think to Win95.  We will need to extend it for
- * Win98 which can have both path and end ellipsis at the same time (e.g.
- *  C:\MyLongFileName.Txt becomes ...\MyLongFileN...)
- *
- * The resulting string consists of as much as possible of the following:
- * 1. The ellipsis itself
- * 2. The last \ or / of the string (if any)
- * 3. Everything after the last \ or / of the string (if any) or the whole
- *    string if there is no / or \.  I believe that under Win95 this would
- *    include everything even though some might be clipped off the end whereas
- *    under Win98 that might be ellipsified too.
- *    Yet to be investigated is whether this would include wordbreaking if the
- *    filename is more than 1 word and splitting if DT_EDITCONTROL was in
- *    effect.  (If DT_EDITCONTROL is in effect then on occasions text will be
- *    broken within words).
- * 4. All the stuff before the / or \, which is placed before the ellipsis.
- */
-static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len,
-                                unsigned int *len_str, int width, SIZE *size,
-                                WCHAR *modstr, ellipsis_data *pellip)
-{
-    int len_ellipsis;
-    int len_trailing;
-    int len_under;
-    WCHAR *lastBkSlash, *lastFwdSlash, *lastSlash;
-
-    len_ellipsis = strlenW (ELLIPSISW);
-    if (!max_len) return;
-    if (len_ellipsis >= max_len) len_ellipsis = max_len - 1;
-    if (*len_str + len_ellipsis >= max_len)
-        *len_str = max_len - len_ellipsis-1;
-        /* Hopefully this will never happen, otherwise it would probably lose
-         * the wrong character
-         */
-    str[*len_str] = '\0'; /* to simplify things */
-
-    lastBkSlash  = strrchrW (str, BACK_SLASH);
-    lastFwdSlash = strrchrW (str, FORWARD_SLASH);
-    lastSlash = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
-    if (!lastSlash) lastSlash = str;
-    len_trailing = *len_str - (lastSlash - str);
-
-    /* overlap-safe movement to the right */
-    memmove (lastSlash+len_ellipsis, lastSlash, len_trailing * sizeof(WCHAR));
-    memcpy (lastSlash, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
-    len_trailing += len_ellipsis;
-    /* From this point on lastSlash actually points to the ellipsis in front
-     * of the last slash and len_trailing includes the ellipsis
-     */
-
-    len_under = 0;
-    for ( ; ; )
-    {
-        if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
-                                    NULL, NULL, size)) break;
-
-        if (lastSlash == str || size->cx <= width) break;
-
-        /* overlap-safe movement to the left */
-        memmove (lastSlash-1, lastSlash, len_trailing * sizeof(WCHAR));
-        lastSlash--;
-        len_under++;
-
-        assert (*len_str);
-        (*len_str)--;
-    }
-    pellip->before = lastSlash-str;
-    pellip->len = len_ellipsis;
-    pellip->under = len_under;
-    pellip->after = len_trailing - len_ellipsis;
-    *len_str += len_ellipsis;
-
-    if (modstr)
-    {
-        memcpy(modstr, str, *len_str * sizeof(WCHAR));
-        modstr[*len_str] = '\0';
-    }
-}
-
-/* Check the character is Chinese, Japanese, Korean and/or Thai */
-inline BOOL IsCJKT(WCHAR wch)
-{
-    if (0x0E00 <= wch && wch <= 0x0E7F)
-        return TRUE;    /* Thai */
-
-    if (0x3000 <= wch && wch <= 0x9FFF)
-        return TRUE;    /* CJK */
-
-    if (0xAC00 <= wch && wch <= 0xD7FF)
-        return TRUE;    /* Korean */
-
-    if (0xFF00 <= wch && wch <= 0xFFEF)
-        return TRUE;    /* CJK */
-
-    return FALSE;
-}
-
-/* See http://en.wikipedia.org/wiki/Kinsoku_shori */
-static const WCHAR KinsokuClassA[] =
-{
-    0x2010, 0x2013, 0x2019, 0x201D, 0x203C, 0x2047, 0x2048, 0x2049, 0x3001, 
-    0x3002, 0x3005, 0x3009, 0x300B, 0x300D, 0x300F, 0x3011, 0x3015, 0x3017, 
-    0x3019, 0x301C, 0x301F, 0x303B, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049, 
-    0x3063, 0x3083, 0x3085, 0x3087, 0x308E, 0x3095, 0x3096, 0x30A0, 0x30A1, 
-    0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30C3, 0x30E3, 0x30E5, 0x30E7, 0x30EE, 
-    0x30F5, 0x30F6, 0x30FB, 0x30FC, 0x30FD, 0x30FE, 0x31F0, 0x31F1, 0x31F2, 
-    0x31F3, 0x31F4, 0x31F5, 0x31F6, 0x31F7, 0x31F8, 0x31F9, 0x31FA, 0x31FB, 
-    0x31FC, 0x31FD, 0x31FE, 0x31FF, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A, 
-    0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0
-};
-
-/*********************************************************************
- *                      TEXT_WordBreak (static)
- *
- *  Perform wordbreak processing on the given string
- *
- * Assumes that DT_WORDBREAK has been specified and not all the characters
- * fit.  Note that this function should even be called when the first character
- * that doesn't fit is known to be a space or tab, so that it can swallow them.
- *
- * Note that the Windows processing has some strange properties.
- * 1. If the text is left-justified and there is room for some of the spaces
- *    that follow the last word on the line then those that fit are included on
- *    the line.
- * 2. If the text is centred or right-justified and there is room for some of
- *    the spaces that follow the last word on the line then all but one of those
- *    that fit are included on the line.
- * 3. (Reasonable behaviour) If the word breaking causes a space to be the first
- *    character of a new line it will be skipped.
- *
- * Arguments
- *   hdc        [in] The handle to the DC that defines the font.
- *   str        [in/out] The string that needs to be broken.
- *   max_str    [in] The dimension of str (number of WCHAR).
- *   len_str    [in/out] The number of characters in str
- *   width      [in] The maximum width permitted
- *   format     [in] The format flags in effect
- *   chars_fit  [in] The maximum number of characters of str that are already
- *              known to fit; chars_fit+1 is known not to fit.
- *   chars_used [out] The number of characters of str that have been "used" and
- *              do not need to be included in later text.  For example this will
- *              include any spaces that have been discarded from the start of
- *              the next line.
- *   size       [out] The size of the returned text in logical coordinates
- *
- * Pedantic assumption - Assumes that the text length is monotonically
- * increasing with number of characters (i.e. no weird kernings)
- *
- * Algorithm
- *
- * Work back from the last character that did fit to either a space or the last
- * character of a word, whichever is met first.
- * If there was one or the first character didn't fit then
- *     If the text is centred or right justified and that one character was a
- *     space then break the line before that character
- *     Otherwise break the line after that character
- *     and if the next character is a space then discard it.
- * Suppose there was none (and the first character did fit).
- *     If Break Within Word is permitted
- *         break the word after the last character that fits (there must be
- *         at least one; none is caught earlier).
- *     Otherwise
- *         discard any trailing space.
- *         include the whole word; it may be ellipsified later
- *
- * Break Within Word is permitted under a set of circumstances that are not
- * totally clear yet.  Currently our best guess is:
- *     If DT_EDITCONTROL is in effect and neither DT_WORD_ELLIPSIS nor
- *     DT_PATH_ELLIPSIS is
- */
-
-static void TEXT_WordBreak (HDC hdc, WCHAR *str, unsigned int max_str,
-                            unsigned int *len_str,
-                            int width, int format, unsigned int chars_fit,
-                            unsigned int *chars_used, SIZE *size)
-{
-    WCHAR *p;
-    int word_fits;
-    assert (format & DT_WORDBREAK);
-    assert (chars_fit < *len_str);
-
-    /* Work back from the last character that did fit to either a space or the
-     * last character of a word, whichever is met first.
-     */
-    p = str + chars_fit; /* The character that doesn't fit */
-    word_fits = TRUE;
-    if (!chars_fit)
-        word_fits = FALSE;
-    else if (*p == SPACE) /* chars_fit < *len_str so this is valid */
-        p--; /* the word just fitted */
-    else
-    {
-        while (p > str && *(--p) != SPACE && (!IsCJKT(p[1]) || 
-                p[1] == L'\0' || wcschr(KinsokuClassA, p[1]) != NULL))
-            ;
-        word_fits = (p != str || *p == SPACE || IsCJKT(p[1]));
-    }
-    /* If there was one. */
-    if (word_fits)
-    {
-        int next_is_space;
-        /* break the line before/after that character */
-        if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE)
-            p++;
-        next_is_space = (unsigned int) (p - str) < *len_str && *p == SPACE;
-        *len_str = p - str;
-        /* and if the next character is a space then discard it. */
-        *chars_used = *len_str;
-        if (next_is_space)
-            (*chars_used)++;
-    }
-    /* Suppose there was none. */
-    else
-    {
-        if ((format & (DT_EDITCONTROL | DT_WORD_ELLIPSIS | DT_PATH_ELLIPSIS)) ==
-            DT_EDITCONTROL)
-        {
-            /* break the word after the last character that fits (there must be
-             * at least one). */
-            if (!chars_fit)
-                ++chars_fit;
-            *len_str = chars_fit;
-            *chars_used = chars_fit;
-
-            /* FIXME - possible error.  Since the next character is now removed
-             * this could make the text longer so that it no longer fits, and
-             * so we need a loop to test and shrink.
-             */
-        }
-        /* Otherwise */
-        else
-        {
-            /* discard any trailing space. */
-            const WCHAR *e = str + *len_str;
-            p = str + chars_fit;
-            while (p < e && *p != SPACE)
-                p++;
-            *chars_used = p - str;
-            if (p < e) /* i.e. loop failed because *p == SPACE */
-                (*chars_used)++;
-
-            /* include the whole word; it may be ellipsified later */
-            *len_str = p - str;
-            /* Possible optimisation; if DT_WORD_ELLIPSIS only use chars_fit+1
-             * so that it will be too long
-             */
-        }
-    }
-    /* Remeasure the string */
-    GetTextExtentExPointW (hdc, str, *len_str, 0, NULL, NULL, size);
-}
-
-/*********************************************************************
- *                      TEXT_SkipChars
- *
- *  Skip over the given number of characters, bearing in mind prefix
- *  substitution and the fact that a character may take more than one
- *  WCHAR (Unicode surrogates are two words long) (and there may have been
- *  a trailing &)
- *
- * Parameters
- *   new_count  [out] The updated count
- *   new_str    [out] The updated pointer
- *   start_count [in] The count of remaining characters corresponding to the
- *                    start of the string
- *   start_str  [in] The starting point of the string
- *   max        [in] The number of characters actually in this segment of the
- *                   string (the & counts)
- *   n          [in] The number of characters to skip (if prefix then
- *                   &c counts as one)
- *   prefix     [in] Apply prefix substitution
- *
- * Return Values
- *   none
- *
- * Remarks
- *   There must be at least n characters in the string
- *   We need max because the "line" may have ended with a & followed by a tab
- *   or newline etc. which we don't want to swallow
- */
-
-static void TEXT_SkipChars (int *new_count, const WCHAR **new_str,
-                            int start_count, const WCHAR *start_str,
-                            int max, int n, int prefix)
-{
-    /* This is specific to wide characters, MSDN doesn't say anything much
-     * about Unicode surrogates yet and it isn't clear if _wcsinc will
-     * correctly handle them so we'll just do this the easy way for now
-     */
-
-    if (prefix)
-    {
-        const WCHAR *str_on_entry = start_str;
-        assert (max >= n);
-        max -= n;
-        while (n--)
-        {
-            if ((*start_str == PREFIX || *start_str == ALPHA_PREFIX) && max--)
-                start_str++;
-            start_str++;
-        }
-        start_count -= (start_str - str_on_entry);
-    }
-    else
-    {
-        start_str += n;
-        start_count -= n;
-    }
-    *new_str = start_str;
-    *new_count = start_count;
-}
-
-/*********************************************************************
- *                      TEXT_Reprefix
- *
- *  Reanalyse the text to find the prefixed character.  This is called when
- *  wordbreaking or ellipsification has shortened the string such that the
- *  previously noted prefixed character is no longer visible.
- *
- * Parameters
- *   str        [in] The original string segment (including all characters)
- *   ns         [in] The number of characters in str (including prefixes)
- *   pe         [in] The ellipsification data
- *
- * Return Values
- *   The prefix offset within the new string segment (the one that contains the
- *   ellipses and does not contain the prefix characters) (-1 if none)
- */
-
-static int TEXT_Reprefix (const WCHAR *str, unsigned int ns,
-                          const ellipsis_data *pe)
-{
-    int result = -1;
-    unsigned int i;
-    unsigned int n = pe->before + pe->under + pe->after;
-    assert (n <= ns);
-    for (i = 0; i < n; i++, str++)
-    {
-        if (i == (unsigned int) pe->before)
-        {
-            /* Reached the path ellipsis; jump over it */
-            if (ns < (unsigned int) pe->under) break;
-            str += pe->under;
-            ns -= pe->under;
-            i += pe->under;
-            if (!pe->after) break; /* Nothing after the path ellipsis */
-        }
-        if (!ns) break;
-        ns--;
-        if (*str++ == PREFIX || *str == ALPHA_PREFIX)
-        {
-            str++;
-            if (!ns) break;
-            if (*str != PREFIX)
-                result = (i < (unsigned int) pe->before || pe->under == 0) ? i : i - pe->under + pe->len;
-                /* pe->len may be non-zero while pe_under is zero */
-            ns--;
-        }
-    }
-    return result;
-}
-
-/*********************************************************************
- *  Returns true if and only if the remainder of the line is a single
- *  newline representation or nothing
- */
-
-static int remainder_is_none_or_newline (int num_chars, const WCHAR *str)
-{
-    if (!num_chars) return TRUE;
-    if (*str != LF && *str != CR) return FALSE;
-    if (!--num_chars) return TRUE;
-    if (*str == *(str+1)) return FALSE;
-    str++;
-    if (*str != CR && *str != LF) return FALSE;
-    if (--num_chars) return FALSE;
-    return TRUE;
-}
-
-/*********************************************************************
- *  Return next line of text from a string.
- *
- * hdc - handle to DC.
- * str - string to parse into lines.
- * count - length of str.
- * dest - destination in which to return line.
- * len - dest buffer size in chars on input, copied length into dest on output.
- * width - maximum width of line in pixels.
- * format - format type passed to DrawText.
- * retsize - returned size of the line in pixels.
- * last_line - TRUE if is the last line that will be processed
- * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which
- *            the return string is built.
- * tabwidth - The width of a tab in logical coordinates
- * pprefix_offset - Here is where we return the offset within dest of the first
- *                  prefixed (underlined) character.  -1 is returned if there
- *                  are none.  Note that there may be more; the calling code
- *                  will need to use TEXT_Reprefix to find any later ones.
- * pellip - Here is where we return the information about any ellipsification
- *          that was carried out.  Note that if tabs are being expanded then
- *          this data will correspond to the last text segment actually
- *          returned in dest; by definition there would not have been any
- *          ellipsification in earlier text segments of the line.
- *
- * Returns pointer to next char in str after end of the line
- * or NULL if end of str reached.
- */
-static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count,
-                                 WCHAR *dest, int *len, int width, DWORD format,
-                                 SIZE *retsize, int last_line, WCHAR **p_retstr,
-                                 int tabwidth, int *pprefix_offset,
-                                 ellipsis_data *pellip)
-{
-    int i = 0, j = 0;
-    int plen = 0;
-    SIZE size = {0, 0};
-    int maxl = *len;
-    int seg_i, seg_count, seg_j;
-    int max_seg_width;
-    int num_fit;
-    int word_broken;
-    int line_fits;
-    unsigned int j_in_seg;
-    int ellipsified;
-    *pprefix_offset = -1;
-
-    /* For each text segment in the line */
-
-    retsize->cy = 0;
-    while (*count)
-    {
-
-        /* Skip any leading tabs */
-
-        if (str[i] == TAB && (format & DT_EXPANDTABS))
-        {
-            plen = ((plen/tabwidth)+1)*tabwidth;
-            (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
-            while (*count && str[i] == TAB)
-            {
-                plen += tabwidth;
-                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
-            }
-        }
-
-
-        /* Now copy as far as the next tab or cr/lf or eos */
-
-        seg_i = i;
-        seg_count = *count;
-        seg_j = j;
-
-        while (*count &&
-               (str[i] != TAB || !(format & DT_EXPANDTABS)) &&
-               ((str[i] != CR && str[i] != LF) || (format & DT_SINGLELINE)))
-        {
-            if ((format & DT_NOPREFIX) || *count <= 1)
-            {
-                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
-                continue;
-            }
-
-	    if (str[i] == PREFIX || str[i] == ALPHA_PREFIX) {
-                (*count)--, i++; /* Throw away the prefix itself */
-                if (str[i] == PREFIX)
-                {
-                    /* Swallow it before we see it again */
-		    (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
-                }
-		else if (*pprefix_offset == -1 || *pprefix_offset >= seg_j)
-                {
-                    *pprefix_offset = j;
-                }
-                /* else the previous prefix was in an earlier segment of the
-                 * line; we will leave it to the drawing code to catch this
-                 * one.
-                 */
-	    }
-	    else if (str[i] == KANA_PREFIX)
-            {
-                /* Throw away katakana access keys */
-                (*count)--, i++; /* skip the prefix */
-                (*count)--, i++; /* skip the letter */
-            }
-            else
-            {
-                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
-            }
-        }
-
-
-        /* Measure the whole text segment and possibly WordBreak and
-         * ellipsify it
-         */
-
-        j_in_seg = j - seg_j;
-        max_seg_width = width - plen;
-        GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size);
-
-        /* The Microsoft handling of various combinations of formats is weird.
-         * The following may very easily be incorrect if several formats are
-         * combined, and may differ between versions (to say nothing of the
-         * several bugs in the Microsoft versions).
-         */
-        word_broken = 0;
-        line_fits = (num_fit >= j_in_seg);
-        if (!line_fits && (format & DT_WORDBREAK))
-        {
-            const WCHAR *s;
-            unsigned int chars_used;
-            TEXT_WordBreak (hdc, dest+seg_j, maxl-seg_j, &j_in_seg,
-                            max_seg_width, format, num_fit, &chars_used, &size);
-            line_fits = (size.cx <= max_seg_width);
-            /* and correct the counts */
-            TEXT_SkipChars (count, &s, seg_count, str+seg_i, i-seg_i,
-                            chars_used, !(format & DT_NOPREFIX));
-            i = s - str;
-            word_broken = 1;
-        }
-        pellip->before = j_in_seg;
-        pellip->under = 0;
-        pellip->after = 0;
-        pellip->len = 0;
-        ellipsified = 0;
-        if (!line_fits && (format & DT_PATH_ELLIPSIS))
-        {
-            TEXT_PathEllipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
-                                max_seg_width, &size, *p_retstr, pellip);
-            line_fits = (size.cx <= max_seg_width);
-            ellipsified = 1;
-        }
-        /* NB we may end up ellipsifying a word-broken or path_ellipsified
-         * string */
-        if ((!line_fits && (format & DT_WORD_ELLIPSIS)) ||
-            ((format & DT_END_ELLIPSIS) &&
-              ((last_line && *count) ||
-               (remainder_is_none_or_newline (*count, &str[i]) && !line_fits))))
-        {
-            int before, len_ellipsis;
-            TEXT_Ellipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
-                            max_seg_width, &size, *p_retstr, &before, &len_ellipsis);
-            if (before > pellip->before)
-            {
-                /* We must have done a path ellipsis too */
-                pellip->after = before - pellip->before - pellip->len;
-                /* Leave the len as the length of the first ellipsis */
-            }
-            else
-            {
-                /* If we are here after a path ellipsification it must be
-                 * because even the ellipsis itself didn't fit.
-                 */
-                assert (pellip->under == 0 && pellip->after == 0);
-                pellip->before = before;
-                pellip->len = len_ellipsis;
-                /* pellip->after remains as zero as does
-                 * pellip->under
-                 */
-            }
-            line_fits = (size.cx <= max_seg_width);
-            ellipsified = 1;
-        }
-        /* As an optimisation if we have ellipsified and we are expanding
-         * tabs and we haven't reached the end of the line we can skip to it
-         * now rather than going around the loop again.
-         */
-        if ((format & DT_EXPANDTABS) && ellipsified)
-        {
-            if (format & DT_SINGLELINE)
-                *count = 0;
-            else
-            {
-                while ((*count) && str[i] != CR && str[i] != LF)
-                {
-                    (*count)--, i++;
-                }
-            }
-        }
-
-        j = seg_j + j_in_seg;
-        if (*pprefix_offset >= seg_j + pellip->before)
-        {
-            *pprefix_offset = TEXT_Reprefix (str + seg_i, i - seg_i, pellip);
-            if (*pprefix_offset != -1)
-                *pprefix_offset += seg_j;
-        }
-
-        plen += size.cx;
-        if (size.cy > retsize->cy)
-            retsize->cy = size.cy;
-
-        if (word_broken)
-            break;
-        else if (!*count)
-            break;
-        else if (str[i] == CR || str[i] == LF)
-        {
-            (*count)--, i++;
-            if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1])
-            {
-                (*count)--, i++;
-            }
-            break;
-        }
-        /* else it was a Tab and we go around again */
-    }
-
-    retsize->cx = plen;
-    *len = j;
-    if (*count)
-        return (&str[i]);
-    else
-        return NULL;
-}
-
-
 /***********************************************************************
- *                      TEXT_DrawUnderscore
- *
- *  Draw the underline under the prefixed character
- *
- * Parameters
- *   hdc        [in] The handle of the DC for drawing
- *   x          [in] The x location of the line segment (logical coordinates)
- *   y          [in] The y location of where the underscore should appear
- *                   (logical coordinates)
- *   str        [in] The text of the line segment
- *   offset     [in] The offset of the underscored character within str
- *   rect       [in] Clipping rectangle (if not NULL)
- */
-/* Synced with wine 1.1.32 */
-static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int offset, const RECT *rect)
-{
-    int prefix_x;
-    int prefix_end;
-    SIZE size;
-    HPEN hpen;
-    HPEN oldPen;
-
-    GetTextExtentPointW (hdc, str, offset, &size);
-    prefix_x = x + size.cx;
-    GetTextExtentPointW (hdc, str, offset+1, &size);
-    prefix_end = x + size.cx - 1;
-    /* The above method may eventually be slightly wrong due to kerning etc. */
-
-    /* Check for clipping */
-    if (rect)
-    {
-        if (prefix_x > rect->right || prefix_end < rect->left ||
-            y < rect->top || y > rect->bottom)
-            return; /* Completely outside */
-        /* Partially outside */
-        if (prefix_x   < rect->left ) prefix_x   = rect->left;
-        if (prefix_end > rect->right) prefix_end = rect->right;
-    }
-
-    hpen = CreatePen (PS_SOLID, 1, GetTextColor (hdc));
-    oldPen = SelectObject (hdc, hpen);
-    MoveToEx (hdc, prefix_x, y, NULL);
-    LineTo (hdc, prefix_end, y);
-    SelectObject (hdc, oldPen);
-    DeleteObject (hpen);
-}
-
-/***********************************************************************
  *           DrawTextExW    (USER32.@)
  *
  * The documentation on the extra space required for DT_MODIFYSTRING at MSDN
@@ -1104,234 +155,7 @@
 INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
                         LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
 {
-    SIZE size;
-    const WCHAR *strPtr;
-    WCHAR *retstr, *p_retstr;
-    size_t size_retstr;
-    WCHAR line[MAX_BUFFER];
-    int len, lh, count=i_count;
-    TEXTMETRICW tm;
-    int lmargin = 0, rmargin = 0;
-    int x = rect->left, y = rect->top;
-    int width = rect->right - rect->left;
-    int max_width = 0;
-    int last_line;
-    int tabwidth /* to keep gcc happy */ = 0;
-    int prefix_offset;
-    ellipsis_data ellip;
-    BOOL invert_y=FALSE;
-
-    TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str, count), count,
-        wine_dbgstr_rect(rect), flags);
-
-    if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
-          dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
-
-    if (!str) return 0;
-
-    strPtr = str;
-
-    if (flags & DT_SINGLELINE)
-        flags &= ~DT_WORDBREAK;
-
-    GetTextMetricsW(hdc, &tm);
-    if (flags & DT_EXTERNALLEADING)
-	lh = tm.tmHeight + tm.tmExternalLeading;
-    else
-	lh = tm.tmHeight;
-
-    if (str[0] && count == 0)
-        return lh;
-
-    if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
-        return 0;
-
-    if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
-    {
-        SIZE window_ext, viewport_ext;
-        GetWindowExtEx(hdc, &window_ext);
-        GetViewportExtEx(hdc, &viewport_ext);
-        if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
-            invert_y = TRUE;
-    }
-
-    if (count == -1)
-    {
-        count = strlenW(str);
-        if (count == 0)
-        {
-            if( flags & DT_CALCRECT)
-            {
-                rect->right = rect->left;
-                if( flags & DT_SINGLELINE)
-                    rect->bottom = rect->top + (invert_y ? -lh : lh);
-                else
-                    rect->bottom = rect->top;
-            }
-            return lh;
-        }
-    }
-
-    if (dtp)
-    {
-        lmargin = dtp->iLeftMargin;
-        rmargin = dtp->iRightMargin;
-        if (!(flags & (DT_CENTER | DT_RIGHT)))
-            x += lmargin;
-        dtp->uiLengthDrawn = 0;     /* This param RECEIVES number of chars processed */
-    }
-
-    if (flags & DT_EXPANDTABS)
-    {
-        int tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8;
-	tabwidth = tm.tmAveCharWidth * tabstop;
-    }
-
-    if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
-
-    if (flags & DT_MODIFYSTRING)
-    {
-        size_retstr = (count + 4) * sizeof (WCHAR);
-        retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
-        if (!retstr) return 0;
-        memcpy (retstr, str, size_retstr);
-    }
-    else
-    {
-        size_retstr = 0;
-        retstr = NULL;
-    }
-    p_retstr = retstr;
-
-    do
-    {
-	len = sizeof(line)/sizeof(line[0]);
-	if (invert_y)
-            last_line = !(flags & DT_NOCLIP) && y - ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) < rect->bottom;
-	else
-            last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom;
-	strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip);
-
-#ifdef __REACTOS__
-    if (flags & DT_CENTER)
-    {
-        if (((rect->right - rect->left) < size.cx) && (flags & DT_CALCRECT))
-        {
-            x = rect->left + size.cx;
-        }
-        else
-        {
-            x = (rect->left + rect->right - size.cx) / 2;
-        }
-    }
-#else
-	if (flags & DT_CENTER) x = (rect->left + rect->right -
-				    size.cx) / 2;
-#endif
-	else if (flags & DT_RIGHT) x = rect->right - size.cx;
-
-	if (flags & DT_SINGLELINE)
-	{
-            if (flags & DT_VCENTER)
-#ifdef __REACTOS__
-            {
-                if (((rect->bottom - rect->top) < (invert_y ? -size.cy : size.cy)) && (flags & DT_CALCRECT))
-                {
-                    y = rect->top + (invert_y ? -size.cy : size.cy);
-                }
-                else
-                {
-#endif
-                    y = rect->top + (rect->bottom - rect->top) / 2 + (invert_y ? (size.cy / 2) : (-size.cy / 2));
-#ifdef __REACTOS__
-                }
-            }
-#endif
-            else if (flags & DT_BOTTOM)
-                y = rect->bottom + (invert_y ? 0 : -size.cy);
-        }
-
-	if (!(flags & DT_CALCRECT))
-	{
-            const WCHAR *str = line;
-            int xseg = x;
-            while (len)
-            {
-                int len_seg;
-                SIZE size;
-                if ((flags & DT_EXPANDTABS))
-                {
-                    const WCHAR *p;
-                    p = str; while (p < str+len && *p != TAB) p++;
-                    len_seg = p - str;
-                    if (len_seg != len && !GetTextExtentPointW(hdc, str, len_seg, &size))
-                    {
-                        HeapFree (GetProcessHeap(), 0, retstr);
-                        return 0;
-                    }
-                }
-                else
-                    len_seg = len;
-
-                if (!ExtTextOutW( hdc, xseg, y,
-                                 ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
-                                 ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
-                                 rect, str, len_seg, NULL ))
-                {
-                    HeapFree (GetProcessHeap(), 0, retstr);
-                    return 0;
-                }
-                if (prefix_offset != -1 && prefix_offset < len_seg)
-                {
-                    TEXT_DrawUnderscore (hdc, xseg, y + tm.tmAscent + 1, str, prefix_offset, (flags & DT_NOCLIP) ? NULL : rect);
-                }
-                len -= len_seg;
-                str += len_seg;
-                if (len)
-                {
-                    assert ((flags & DT_EXPANDTABS) && *str == TAB);
-                    len--; str++;
-                    xseg += ((size.cx/tabwidth)+1)*tabwidth;
-                    if (prefix_offset != -1)
-                    {
-                        if (prefix_offset < len_seg)
-                        {
-                            /* We have just drawn an underscore; we ought to
-                             * figure out where the next one is.  I am going
-                             * to leave it for now until I have a better model
-                             * for the line, which will make reprefixing easier.
-                             * This is where ellip would be used.
-                             */
-                            prefix_offset = -1;
-                        }
-                        else
-                            prefix_offset -= len_seg;
-                    }
-                }
-            }
-	}
-	else if (size.cx > max_width)
-	    max_width = size.cx;
-
-        y += invert_y ? -lh : lh;
-        if (dtp)
-            dtp->uiLengthDrawn += len;
-    }
-    while (strPtr && !last_line);
-
-    if (flags & DT_CALCRECT)
-    {
-	rect->right = rect->left + max_width;
-	rect->bottom = y;
-        if (dtp)
-            rect->right += lmargin + rmargin;
-    }
-    if (retstr)
-    {
-        memcpy (str, retstr, size_retstr);
-        HeapFree (GetProcessHeap(), 0, retstr);
-    }
-    return y - rect->top;
+   return DrawTextExWorker( hdc, str, i_count, rect, flags, dtp );
 }
 
 /***********************************************************************
Index: win32ss/user/user32/windows/menu.c
===================================================================
--- win32ss/user/user32/windows/menu.c	(revision 68654)
+++ win32ss/user/user32/windows/menu.c	(working copy)
@@ -1143,9 +1143,9 @@
         // Or this,
         //Item->cxBmp = mis.itemWidth;
         //Item->cyBmp = mis.itemHeight;
-        TRACE("id=%04lx size=%dx%d\n",
+        TRACE("id=%04lx size=%dx%d cx %d cy %d\n",
                 lpitem->wID, lpitem->Rect.right-lpitem->Rect.left,
-                 lpitem->Rect.bottom-lpitem->Rect.top);
+                 lpitem->Rect.bottom-lpitem->Rect.top, MenuCharSize.cx, MenuCharSize.cy);
         return;
     }
 
@@ -3746,7 +3746,7 @@
     /* owner may not be visible when tracking a popup, so use the menu itself */
     capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd;
     NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1
-    SetCapture(capture_win);                                          // 2
+    SetCapture(capture_win);                                     // 2
 
     while (!fEndMenu)
     {
@@ -4753,19 +4753,19 @@
 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
                                 UINT wHilite )
 {
-    ROSMENUINFO MenuInfo;
-    TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
+    //ROSMENUINFO MenuInfo;
+    ERR("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
     // Force bits to be set call server side....
     // This alone works and passes all the menu test_menu_hilitemenuitem tests.
     if (!NtUserHiliteMenuItem(hWnd, hMenu, wItemID, wHilite)) return FALSE;
     // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
     // Now redraw menu.
-    if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
+/*    if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
     {
        if (MenuInfo.iItem == wItemID) return TRUE;
        MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 );
        MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 );
-    }
+    }*/
     return TRUE; // Always returns TRUE!
 }
 
Index: win32ss/user/user32/windows/nonclient.c
===================================================================
--- win32ss/user/user32/windows/nonclient.c	(revision 68654)
+++ win32ss/user/user32/windows/nonclient.c	(working copy)
@@ -275,8 +275,13 @@
    DWORD Style, ExStyle;
    HWND Parent;
    RECT ClientRect, WindowRect, CurrentRect, TempRect;
+   PWND pWnd;
 
-   if (!IsWindowVisible(hWnd))
+   pWnd = ValidateHwnd(hWnd);
+
+   if (!IsWindowVisible(hWnd) ||
+       (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
+        EqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
       return 0;
 
    Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
