update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / window.c
index 863e685..e54945f 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 /* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
 #include <include/callback.h>
 #include <include/msgqueue.h>
 #include <include/rect.h>
+#include <include/dce.h>
+#include <include/paint.h>
+#include <include/painting.h>
+#include <include/scroll.h>
+#include <include/vis.h>
+#include <include/menu.h>
 
 #define NDEBUG
 #include <win32k/debug1.h>
 
 #define TAG_WNAM  TAG('W', 'N', 'A', 'M')
 
-/* FUNCTIONS *****************************************************************/
-
-HWND STDCALL
-NtUserGetAncestor(HWND hWnd, UINT Flags)
+typedef struct _REGISTERED_MESSAGE
 {
-  if (W32kIsDesktopWindow(hWnd))
-    {
-      return(NULL);
-    }
-  if (Flags & GA_PARENT)
-    {
-      PWINDOW_OBJECT Window;
-      HWND hParent;
+  LIST_ENTRY ListEntry;
+  WCHAR MessageName[1];
+} REGISTERED_MESSAGE, *PREGISTERED_MESSAGE;
 
-      Window = W32kGetWindowObject(hWnd);
-      if (Window == NULL)
-       {
-         return(NULL);
-       }     
+static LIST_ENTRY RegisteredMessageListHead;
 
-      if (Window->Parent == NULL)
-       {
-         W32kReleaseWindowObject(Window);
-       }
+#define REGISTERED_MESSAGE_MIN 0xc000
+#define REGISTERED_MESSAGE_MAX 0xffff
 
-      hParent = Window->Parent->Self;
 
-      W32kReleaseWindowObject(Window);
+ /* globally stored handles to the shell windows */
+HWND hwndShellWindow = 0;
+HWND hwndShellListView = 0;
+DWORD pidShellWindow = 0;
 
-      return(hParent);
-    }
-  else
-    {
-      UNIMPLEMENTED;
-      return(NULL);
-    }
-}
 
-VOID
-W32kSetFocusWindow(HWND hWnd)
+NTSTATUS FASTCALL
+InitWindowImpl(VOID)
 {
-}
+  InitializeListHead(&RegisteredMessageListHead);
 
-BOOL
-W32kIsChildWindow(HWND Parent, HWND Child)
-{
-  PWINDOW_OBJECT BaseWindow = W32kGetWindowObject(Child);
-  PWINDOW_OBJECT Window = BaseWindow;
-  while (Window != NULL && Window->Style & WS_CHILD)
-    {
-      if (Window->Self == Parent)
-       {
-         W32kReleaseWindowObject(BaseWindow);
-         return(TRUE);
-       }
-      Window = Window->Parent;
-    }
-  W32kReleaseWindowObject(BaseWindow);
-  return(FALSE);  
+  return(STATUS_SUCCESS);
 }
 
-BOOL
-W32kIsWindowVisible(HWND Wnd)
+NTSTATUS FASTCALL
+CleanupWindowImpl(VOID)
 {
-  PWINDOW_OBJECT BaseWindow = W32kGetWindowObject(Wnd);
-  PWINDOW_OBJECT Window = BaseWindow;
-  BOOLEAN Result = FALSE;
-  while (Window != NULL && Window->Style & WS_CHILD)
-    {
-      if (!(Window->Style & WS_VISIBLE))
-       {
-         W32kReleaseWindowObject(BaseWindow);
-         return(FALSE);
-       }
-      Window = Window->Parent;
-    }
-  if (Window != NULL && Window->Style & WS_VISIBLE)
-    {
-      Result = TRUE;
-    }
-  W32kReleaseWindowObject(BaseWindow);
-  return(Result);
+  return(STATUS_SUCCESS);
 }
 
-BOOL
-W32kIsDesktopWindow(HWND hWnd)
-{
-  PWINDOW_OBJECT WindowObject;
-  BOOL IsDesktop;
-  WindowObject = W32kGetWindowObject(hWnd);
-  IsDesktop = WindowObject->Parent == NULL;
-  W32kReleaseWindowObject(WindowObject);
-  return(IsDesktop);
-}
 
-HWND W32kGetDesktopWindow()
-{
-  return W32kGetActiveDesktop()->DesktopWindow;
-}
+/* HELPER FUNCTIONS ***********************************************************/
 
-HWND W32kGetParentWindow(HWND hWnd)
+/* check if hwnd is a broadcast magic handle */
+inline BOOL IntIsBroadcastHwnd( HWND hwnd )
 {
-  return W32kGetWindowObject(hWnd)->ParentHandle;
+    return (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST);
 }
 
-PWINDOW_OBJECT
-W32kGetWindowObject(HWND hWnd)
-{
-  PWINDOW_OBJECT WindowObject;
-  NTSTATUS Status;
-  Status = 
-    ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
-                              HandleTable,
-                              hWnd,
-                              otWindow,
-                              (PVOID*)&WindowObject);
-  if (!NT_SUCCESS(Status))
-    {
-      return(NULL);
-    }
-  return(WindowObject);
-}
 
-VOID
-W32kReleaseWindowObject(PWINDOW_OBJECT Window)
+inline BOOL IntIsDesktopWindow(PWINDOW_OBJECT Wnd)
 {
-  ObmDereferenceObject(Window);
+  return Wnd->Parent == NULL;
 }
 
-/*!
- * Internal function.
- * Returns client window rectangle relative to the upper-left corner of client area.
- *
- * \note Does not check the validity of the parameters
-*/
-VOID
-W32kGetClientRect(PWINDOW_OBJECT WindowObject, PRECT Rect)
-{
-  ASSERT( WindowObject );
-  ASSERT( Rect );
-
-  Rect->left = Rect->top = 0;
-  Rect->right = WindowObject->ClientRect.right - WindowObject->ClientRect.left;
-  Rect->bottom = 
-    WindowObject->ClientRect.bottom - WindowObject->ClientRect.top;
-}
 
-/*!
- * Internal Function.
- * Return the dimension of the window in the screen coordinates.
-*/
-BOOL STDCALL
-W32kGetWindowRect(HWND hWnd, LPRECT Rect)
+static BOOL BuildChildWindowArray(PWINDOW_OBJECT Window, HWND **Children, unsigned *NumChildren)
 {
-  PWINDOW_OBJECT WindowObject;
-
-  ASSERT( Rect );
-
-  WindowObject = W32kGetWindowObject(hWnd);
-  if (WindowObject == NULL)
+  unsigned Index;
+  PWINDOW_OBJECT Child;
+
+  *Children = NULL;
+  *NumChildren = 0;
+
+  ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
+  Child = Window->FirstChild;
+  while (Child)
+  {
+    (*NumChildren)++;
+    Child = Child->NextSibling;
+  }
+  
+  if (0 != *NumChildren)
+  {
+    *Children = ExAllocatePoolWithTag(PagedPool, *NumChildren * sizeof(HWND), TAG_WNAM);
+    if (NULL != *Children)
     {
-      return(FALSE);
+      Child = Window->FirstChild;
+      Index = 0;
+      while (Child)
+      {
+        (*Children)[Index] = Child->Self;
+        Child = Child->NextSibling;
+        Index++;
+      }
+      assert(Index == *NumChildren);
     }
-  *Rect = WindowObject->WindowRect;
-  if (WindowObject->Style & WS_CHILD)
+    else
     {
-      DbgBreakPoint();
+      DPRINT1("Failed to allocate memory for children array\n");
     }
-  W32kReleaseWindowObject(WindowObject);
-  return(TRUE);
-}
+  }
+  ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
 
-/*!
- * Return the dimension of the window in the screen coordinates.
- * \param      hWnd    window handle.
- * \param      Rect    pointer to the buffer where the coordinates are returned.
-*/
-BOOL STDCALL
-NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
-{
-  RECT SafeRect;
-  BOOL bRet;
 
-  bRet = W32kGetWindowRect(hWnd, &SafeRect);
-  if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT)))){
-    return(FALSE);
-  }
-  return( bRet );
+  return 0 == *NumChildren || NULL != *Children;
 }
 
-/*!
- * Returns client window rectangle relative to the upper-left corner of client area.
- *
- * \param      hWnd    window handle.
- * \param      Rect    pointer to the buffer where the coordinates are returned.
+
+/***********************************************************************
+ *           IntDestroyWindow
  *
-*/
-BOOL STDCALL
-NtUserGetClientRect(HWND hWnd, LPRECT Rect)
+ * Destroy storage associated to a window. "Internals" p.358
+ */
+static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
+                                 PW32PROCESS ProcessData,
+                                 PW32THREAD ThreadData,
+                                 BOOLEAN SendMessages)
 {
-  PWINDOW_OBJECT WindowObject;
-  RECT SafeRect;
+  HWND *Children;
+  unsigned NumChildren;
+  unsigned Index;
+  PWINDOW_OBJECT Child;
 
-  WindowObject = W32kGetWindowObject(hWnd);
-  if (WindowObject == NULL)
+  if (! IntWndBelongsToThread(Window, ThreadData))
     {
-      return(FALSE);
+      DPRINT1("Window doesn't belong to current thread\n");
+      return 0;
     }
-  W32kGetClientRect(WindowObject, &SafeRect);
-  if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
+
+  /* free child windows */
+  if (! BuildChildWindowArray(Window, &Children, &NumChildren))
     {
-      return(FALSE);
+      return 0;
     }
-
-  W32kReleaseWindowObject(WindowObject);
-  return(TRUE);
-}
-
-HWND
-W32kGetActiveWindow(VOID)
-{
-  PUSER_MESSAGE_QUEUE Queue;
-  Queue = (PUSER_MESSAGE_QUEUE)W32kGetActiveDesktop()->ActiveMessageQueue;
-  if (Queue == NULL)
+  for (Index = NumChildren; 0 < Index; Index--)
     {
-      return(NULL);
+      Child = IntGetWindowObject(Children[Index - 1]);
+      if (NULL != Child)
+       {
+         if (IntWndBelongsToThread(Child, ThreadData))
+           {
+             IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
+           }
+#if 0 /* FIXME */
+         else
+           {
+             SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
+           }
+#endif
+       }
     }
-  else
+  if (0 != NumChildren)
     {
-      return(Queue->ActiveWindow);
+      ExFreePool(Children);
     }
-}
 
-HWND
-W32kGetFocusWindow(VOID)
-{
-  PUSER_MESSAGE_QUEUE Queue;
-  PDESKTOP_OBJECT pdo = W32kGetActiveDesktop();
+  if (SendMessages)
+    {
+      /*
+       * Clear the update region to make sure no WM_PAINT messages will be
+       * generated for this window while processing the WM_NCDESTROY.
+       */
+      PaintRedrawWindow(Window, NULL, 0,
+                        RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN,
+                        0);
+
+      /*
+       * Send the WM_NCDESTROY to the window being destroyed.
+       */
+      NtUserSendMessage(Window->Self, WM_NCDESTROY, 0, 0);
+    }
 
-  if( !pdo )
-       return NULL;
+  /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
 
-  Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
+#if 0 /* FIXME */
+  WinPosCheckInternalPos(Window->Self);
+  if (Window->Self == GetCapture())
+    {
+      ReleaseCapture();
+    }
 
-  if (Queue == NULL)
-      return(NULL);
-  else
-      return(Queue->FocusWindow);
-}
+  /* free resources associated with the window */
+  TIMER_RemoveWindowTimers(Window->Self);
+#endif
 
+#if 0 /* FIXME */
+  if (0 == (Window->Style & WS_CHILD))
+    {
+      HMENU Menu = (HMENU) NtUserSetWindowLongW(Window->Self, GWL_ID, 0);
+      if (NULL != Menu)
+       {
+         DestroyMenu(Menu);
+       }
+    }
+  if (Window->hSysMenu)
+    {
+      DestroyMenu(Window->hSysMenu);
+      Window->hSysMenu = 0;
+    }
+  DCE_FreeWindowDCE(Window->Self);    /* Always do this to catch orphaned DCs */
+  WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
+  CLASS_RemoveWindow(Window->Class);
+#endif
 
-WNDPROC
-W32kGetWindowProc(HWND Wnd)
-{
-  PWINDOW_OBJECT WindowObject;
-  WNDPROC WndProc;
+  ExAcquireFastMutexUnsafe(&Window->Parent->ChildrenListLock);
+  IntUnlinkWindow(Window);
+  ExReleaseFastMutexUnsafe(&Window->Parent->ChildrenListLock);
 
-  WindowObject = W32kGetWindowObject(Wnd);
-  if( !WindowObject )
-       return NULL;
+  ExAcquireFastMutexUnsafe (&ThreadData->WindowListLock);
+  RemoveEntryList(&Window->ThreadListEntry);
+  ExReleaseFastMutexUnsafe (&ThreadData->WindowListLock);
+  
+  IntDestroyScrollBar(Window, SB_VERT);
+  IntDestroyScrollBar(Window, SB_HORZ);
 
-  WndProc = WindowObject->Class->Class.lpfnWndProc;
-  W32kReleaseWindowObject(Wnd);
-  return(WndProc);
-}
+  Window->Class = NULL;
+  ObmCloseHandle(ProcessData->WindowStation->HandleTable, Window->Self);
 
-NTSTATUS
-InitWindowImpl(VOID)
-{
-  return(STATUS_SUCCESS);
-}
+  IntGraphicsCheck(FALSE);
 
-NTSTATUS
-CleanupWindowImpl(VOID)
-{
-  return(STATUS_SUCCESS);
+  return 0;
 }
 
 
-DWORD STDCALL
-NtUserAlterWindowStyle(DWORD Unknown0,
-                      DWORD Unknown1,
-                      DWORD Unknown2)
-{
-  UNIMPLEMENTED
+/* INTERNAL ******************************************************************/
 
-  return(0);
-}
 
-DWORD STDCALL
-NtUserChildWindowFromPointEx(HWND Parent,
-                            LONG x,
-                            LONG y,
-                            UINT Flags)
+VOID FASTCALL
+DestroyThreadWindows(struct _ETHREAD *Thread)
 {
-  UNIMPLEMENTED
-
-  return(0);
+  PLIST_ENTRY LastHead;
+  PW32PROCESS Win32Process;
+  PW32THREAD Win32Thread;
+  PWINDOW_OBJECT Window;
+
+  Win32Thread = Thread->Win32Thread;
+  Win32Process = Thread->ThreadsProcess->Win32Process;
+  ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
+  LastHead = NULL;
+  while (Win32Thread->WindowListHead.Flink != &(Win32Thread->WindowListHead) &&
+         Win32Thread->WindowListHead.Flink != LastHead)
+    {
+      LastHead = Win32Thread->WindowListHead.Flink;
+      Window = CONTAINING_RECORD(Win32Thread->WindowListHead.Flink, WINDOW_OBJECT, ThreadListEntry);
+      ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
+      IntDestroyWindow(Window, Win32Process, Win32Thread, FALSE);
+      ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
+    }
+  if (Win32Thread->WindowListHead.Flink == LastHead)
+    {
+      /* Window at head of list was not removed, should never happen, infinite loop */
+      KEBUGCHECK(0);
+    }
+  ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
 }
 
+
 HWND STDCALL
-W32kCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
+IntCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
                        PWNDCLASS_OBJECT DesktopClass,
                        ULONG Width, ULONG Height)
 {
@@ -361,7 +325,7 @@ W32kCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
   WindowObject->Height = Height;
   WindowObject->ParentHandle = NULL;
   WindowObject->Parent = NULL;
-  WindowObject->Menu = NULL;
+  WindowObject->IDMenu = 0;
   WindowObject->Instance = NULL;
   WindowObject->Parameters = NULL;
   WindowObject->Self = Handle;
@@ -373,7 +337,17 @@ W32kCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
   WindowObject->WindowRect.right = Width;
   WindowObject->WindowRect.bottom = Height;
   WindowObject->ClientRect = WindowObject->WindowRect;
-  InitializeListHead(&WindowObject->ChildrenListHead);
+  WindowObject->UserData = 0;
+  /*FIXME: figure out what the correct strange value is and what to do with it (and how to set the wndproc values correctly) */
+  WindowObject->WndProcA = DesktopClass->lpfnWndProcA;
+  WindowObject->WndProcW = DesktopClass->lpfnWndProcW;
+  WindowObject->OwnerThread = PsGetCurrentThread();
+  WindowObject->FirstChild = NULL;
+  WindowObject->LastChild = NULL;
+  WindowObject->PrevSibling = NULL;
+  WindowObject->NextSibling = NULL;
+
+  ExInitializeFastMutex(&WindowObject->ChildrenListLock);
 
   WindowName = ExAllocatePool(NonPagedPool, sizeof(L"DESKTOP"));
   wcscpy(WindowName, L"DESKTOP");
@@ -382,64 +356,782 @@ W32kCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
   return(Handle);
 }
 
-HWND STDCALL
-NtUserCreateWindowEx(DWORD dwExStyle,
-                    PUNICODE_STRING lpClassName,
-                    PUNICODE_STRING lpWindowName,
-                    DWORD dwStyle,
-                    LONG x,
-                    LONG y,
-                    LONG nWidth,
-                    LONG nHeight,
-                    HWND hWndParent,
-                    HMENU hMenu,
-                    HINSTANCE hInstance,
-                    LPVOID lpParam,
-                    DWORD dwShowMode)
-{
-  PWINSTATION_OBJECT WinStaObject;
-  PWNDCLASS_OBJECT ClassObject;
-  PWINDOW_OBJECT WindowObject;
-  PWINDOW_OBJECT ParentWindow;
-  UNICODE_STRING WindowName;
-  NTSTATUS Status;
-  HANDLE Handle;
-  POINT MaxSize, MaxPos, MinTrack, MaxTrack;
-  CREATESTRUCTW Cs;
-  LRESULT Result;
-  DPRINT("NtUserCreateWindowEx\n");
-
-  /* Initialize gui state if necessary. */
-  W32kGuiCheck();
-  W32kGraphicsCheck(TRUE);
-
-  if (!RtlCreateUnicodeString(&WindowName, lpWindowName->Buffer))
-    {
-      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-      return((HWND)0);
-    }
 
-  if (hWndParent != NULL)
+HWND FASTCALL
+IntGetActiveWindow(VOID)
+{
+  PUSER_MESSAGE_QUEUE Queue;
+  Queue = (PUSER_MESSAGE_QUEUE)IntGetActiveDesktop()->ActiveMessageQueue;
+  if (Queue == NULL)
     {
-      ParentWindow = W32kGetWindowObject(hWndParent);
+      return(NULL);
     }
   else
     {
-      hWndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
-      ParentWindow = W32kGetWindowObject(hWndParent);
+      return(Queue->ActiveWindow);
     }
+}
 
-  /* Check the class. */
-  Status = ClassReferenceClassByNameOrAtom(&ClassObject, lpClassName->Buffer);
-  if (!NT_SUCCESS(Status))
-    {
-      RtlFreeUnicodeString(&WindowName);
-      return((HWND)0);
-    }
 
-  /* Check the window station. */
-  DPRINT("IoGetCurrentProcess() %X\n", IoGetCurrentProcess());
-  DPRINT("PROCESS_WINDOW_STATION %X\n", PROCESS_WINDOW_STATION());
+PWINDOW_OBJECT FASTCALL
+IntGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
+{
+  if (IntIsDesktopWindow(Wnd)) return NULL;
+
+  switch (Type)
+  {
+    case GA_PARENT:
+      return Wnd->Parent;
+
+    case GA_ROOT:
+      while(!IntIsDesktopWindow(Wnd->Parent))
+      {
+        Wnd = Wnd->Parent;
+      }
+      return Wnd;
+    
+    case GA_ROOTOWNER:
+      while ((Wnd = IntGetParent(Wnd)));
+      return Wnd;
+  }
+
+  return NULL;
+}
+
+
+/*!
+ * Internal function.
+ * Returns client window rectangle relative to the upper-left corner of client area.
+ *
+ * \note Does not check the validity of the parameters
+*/
+VOID FASTCALL
+IntGetClientRect(PWINDOW_OBJECT WindowObject, PRECT Rect)
+{
+  ASSERT( WindowObject );
+  ASSERT( Rect );
+
+  Rect->left = Rect->top = 0;
+  Rect->right = WindowObject->ClientRect.right - WindowObject->ClientRect.left;
+  Rect->bottom = 
+    WindowObject->ClientRect.bottom - WindowObject->ClientRect.top;
+}
+
+
+HWND FASTCALL IntGetDesktopWindow(VOID)
+{
+  return IntGetActiveDesktop()->DesktopWindow;
+}
+
+
+HWND FASTCALL
+IntGetFocusWindow(VOID)
+{
+  PUSER_MESSAGE_QUEUE Queue;
+  PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
+
+  if( !pdo )
+       return NULL;
+
+  Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
+
+  if (Queue == NULL)
+      return(NULL);
+  else
+      return(Queue->FocusWindow);
+}
+
+
+PWINDOW_OBJECT FASTCALL
+IntGetParent(PWINDOW_OBJECT Wnd)
+{
+  if (Wnd->Style & WS_POPUP)
+  {
+    return IntGetWindowObject(Wnd->ParentHandle); /* wine use HWND for owner window (unknown reason) */
+  }
+  else if (Wnd->Style & WS_CHILD) 
+  {
+    return Wnd->Parent;
+  }
+
+  return NULL;
+}
+
+
+HMENU FASTCALL
+IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu)
+{
+  PMENU_OBJECT MenuObject, NewMenuObject;
+  PW32PROCESS W32Process;
+  HMENU NewMenu, ret = (HMENU)0;
+
+  if(bRevert)
+  {
+    W32Process = PsGetWin32Process();
+    
+    if(!W32Process->WindowStation)
+      return (HMENU)0;
+      
+    if(WindowObject->SystemMenu)
+    {
+      MenuObject = IntGetMenuObject(WindowObject->SystemMenu);
+      if(MenuObject)
+      {
+        IntDestroyMenuObject(MenuObject, FALSE, TRUE);
+      }
+    }
+      
+    if(W32Process->WindowStation->SystemMenuTemplate)
+    {
+      /* clone system menu */
+      MenuObject = IntGetMenuObject(W32Process->WindowStation->SystemMenuTemplate);
+      if(!MenuObject)
+        return (HMENU)0;
+
+      NewMenuObject = IntCloneMenu(MenuObject);
+      if(NewMenuObject)
+      {
+        WindowObject->SystemMenu = NewMenuObject->Self;
+        NewMenuObject->IsSystemMenu = TRUE;
+        ret = NewMenuObject->Self;
+        IntReleaseMenuObject(NewMenuObject);
+      }
+      IntReleaseMenuObject(MenuObject);
+    }
+    else
+    {
+      NewMenu = IntLoadSysMenuTemplate();
+      if(!NewMenu)
+        return (HMENU)0;
+      MenuObject = IntGetMenuObject(NewMenu);
+      if(!MenuObject)
+        return (HMENU)0;
+      
+      NewMenuObject = IntCloneMenu(MenuObject);
+      if(NewMenuObject)
+      {
+        WindowObject->SystemMenu = NewMenuObject->Self;
+        NewMenuObject->IsSystemMenu = TRUE;
+        ret = NewMenuObject->Self;
+        IntReleaseMenuObject(NewMenuObject);
+      }
+      IntDestroyMenuObject(MenuObject, FALSE, TRUE);
+    }
+    if(RetMenu)
+      return ret;
+    else
+      return (HMENU)0;
+  }
+  else
+  {
+    return WindowObject->SystemMenu;
+  }
+}
+
+
+PWINDOW_OBJECT FASTCALL
+IntGetWindowObject(HWND hWnd)
+{
+  PWINDOW_OBJECT WindowObject;
+  NTSTATUS Status;
+  Status = 
+    ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
+                              HandleTable,
+                              hWnd,
+                              otWindow,
+                              (PVOID*)&WindowObject);
+  if (!NT_SUCCESS(Status))
+    {
+      return(NULL);
+    }
+  return(WindowObject);
+}
+
+
+DWORD FASTCALL
+IntGetWindowThreadProcessId(PWINDOW_OBJECT Wnd, PDWORD pid)
+{
+   if (pid) *pid = (DWORD) Wnd->OwnerThread->ThreadsProcess->UniqueProcessId;
+   return (DWORD) Wnd->OwnerThread->Cid.UniqueThread;
+}
+
+
+VOID FASTCALL
+IntInitDesktopWindow(ULONG Width, ULONG Height)
+{
+  PWINDOW_OBJECT DesktopWindow;
+  HRGN DesktopRgn;
+  
+  DesktopWindow = IntGetWindowObject(PsGetWin32Thread()->Desktop->DesktopWindow);
+  if (NULL == DesktopWindow)
+    {
+      return;
+    }
+  DesktopWindow->WindowRect.right = Width;
+  DesktopWindow->WindowRect.bottom = Height;
+  DesktopWindow->ClientRect = DesktopWindow->WindowRect;
+
+  DesktopRgn = UnsafeIntCreateRectRgnIndirect(&(DesktopWindow->WindowRect));
+  VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, DesktopWindow, DesktopRgn);
+  NtGdiDeleteObject(DesktopRgn);
+  IntReleaseWindowObject(DesktopWindow);
+}
+
+
+BOOL FASTCALL
+IntIsChildWindow(HWND Parent, HWND Child)
+{
+  PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Child);
+  PWINDOW_OBJECT Window = BaseWindow;
+  while (Window != NULL && Window->Style & WS_CHILD)
+    {
+      if (Window->Self == Parent)
+       {
+         IntReleaseWindowObject(BaseWindow);
+         return(TRUE);
+       }
+      Window = Window->Parent;
+    }
+  IntReleaseWindowObject(BaseWindow);
+  return(FALSE);  
+}
+
+
+BOOL FASTCALL
+IntIsWindowVisible(HWND Wnd)
+{
+  PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Wnd);
+  PWINDOW_OBJECT Window = BaseWindow;
+  BOOLEAN Result = FALSE;
+  while (Window != NULL && Window->Style & WS_CHILD)
+    {
+      if (!(Window->Style & WS_VISIBLE))
+       {
+         IntReleaseWindowObject(BaseWindow);
+         return(FALSE);
+       }
+      Window = Window->Parent;
+    }
+  if (Window != NULL && Window->Style & WS_VISIBLE)
+    {
+      Result = TRUE;
+    }
+  IntReleaseWindowObject(BaseWindow);
+  return(Result);
+}
+
+
+/* link the window into siblings and parent. children are kept in place. */
+VOID FASTCALL
+IntLinkWindow(
+  PWINDOW_OBJECT Wnd, 
+  PWINDOW_OBJECT WndParent,
+  PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
+  )
+{
+  Wnd->Parent = WndParent; 
+
+  if ((Wnd->PrevSibling = WndPrevSibling))
+  {
+    /* link after WndPrevSibling */
+    if ((Wnd->NextSibling = WndPrevSibling->NextSibling)) Wnd->NextSibling->PrevSibling = Wnd;
+    else if (Wnd->Parent->LastChild == WndPrevSibling) Wnd->Parent->LastChild = Wnd;
+    Wnd->PrevSibling->NextSibling = Wnd;
+  }
+  else
+  {
+    /* link at top */
+    if ((Wnd->NextSibling = WndParent->FirstChild)) Wnd->NextSibling->PrevSibling = Wnd;
+    else Wnd->Parent->LastChild = Wnd;
+    WndParent->FirstChild = Wnd;
+  }
+
+}
+
+
+HWND FASTCALL
+IntSetFocusWindow(HWND hWnd)
+{
+  PUSER_MESSAGE_QUEUE OldMessageQueue;
+  PDESKTOP_OBJECT DesktopObject;
+  PWINDOW_OBJECT WindowObject;
+  HWND hWndOldFocus;
+
+  DPRINT("IntSetFocusWindow(hWnd 0x%x)\n", hWnd);
+
+  if (hWnd != (HWND)0)
+    {
+      WindowObject = IntGetWindowObject(hWnd);
+      if (!WindowObject)
+        {
+          DPRINT("Bad window handle 0x%x\n", hWnd);
+          SetLastWin32Error(ERROR_INVALID_HANDLE);
+         return (HWND)0;
+        }
+    }
+  else
+  {
+    WindowObject = NULL;
+  }
+
+  DesktopObject = IntGetActiveDesktop();
+  if (!DesktopObject)
+    {
+      DPRINT("No active desktop\n");
+      if (WindowObject != NULL)
+        {
+           IntReleaseWindowObject(WindowObject);
+        }
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+         return (HWND)0;
+    }
+
+  hWndOldFocus = (HWND)0;
+  OldMessageQueue = (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue;
+  if (OldMessageQueue != NULL)
+    {
+      hWndOldFocus = OldMessageQueue->FocusWindow;
+    }
+
+  if (WindowObject != NULL)
+    {
+      WindowObject->MessageQueue->FocusWindow = hWnd;
+      (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue =
+        WindowObject->MessageQueue;
+      IntReleaseWindowObject(WindowObject);
+    }
+  else
+    {
+      (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue = NULL;
+    }
+
+  DPRINT("hWndOldFocus = 0x%x\n", hWndOldFocus);
+
+  return hWndOldFocus;
+}
+
+
+PWINDOW_OBJECT FASTCALL
+IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
+{
+  PWINDOW_OBJECT WndOldParent;
+  BOOL was_visible;
+  HWND hWnd, hWndNewParent, hWndOldParent;
+
+  if (!WndNewParent) WndNewParent = IntGetWindowObject(IntGetDesktopWindow());
+
+  hWnd = Wnd;
+  hWndNewParent = WndNewParent;
+
+#if 0
+  if (!(full_handle = WIN_IsCurrentThread( hwnd )))
+    return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
+
+  if (USER_Driver.pSetParent)
+    return USER_Driver.pSetParent( hwnd, parent );
+#endif
+
+  /* Windows hides the window first, then shows it again
+   * including the WM_SHOWWINDOW messages and all */
+  was_visible = WinPosShowWindow( hWnd, SW_HIDE );
+
+  /* validate that window and parent still exist */
+  if (!IntGetWindowObject(hWnd) || !IntGetWindowObject(hWndNewParent)) return NULL;
+
+  /* window must belong to current process */
+  if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess()) return NULL;
+
+  WndOldParent = Wnd->Parent;
+  hWndOldParent =  WndOldParent->Self;
+
+  if (WndNewParent != WndOldParent)
+  {
+    IntUnlinkWindow(Wnd);
+    IntLinkWindow(Wnd, WndNewParent, NULL /*prev sibling*/);
+
+    if (WndNewParent->Self != IntGetDesktopWindow()) /* a child window */
+    {
+      if (!(Wnd->Style & WS_CHILD))
+      {
+        //if ( Wnd->Menu ) DestroyMenu ( Wnd->menu );
+        Wnd->IDMenu = 0;
+      }
+    }
+  }
+
+  /* SetParent additionally needs to make hwnd the topmost window
+       in the x-order and send the expected WM_WINDOWPOSCHANGING and
+       WM_WINDOWPOSCHANGED notification messages.
+   */
+  WinPosSetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0,
+                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
+  /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
+   * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
+  
+  /* validate that the old parent still exist, since it migth have been destroyed
+     during the last callbacks to user-mode 
+   */
+  return (IntGetWindowObject(hWndOldParent) ? WndOldParent : NULL);
+}
+
+
+VOID FASTCALL
+IntReleaseWindowObject(PWINDOW_OBJECT Window)
+{
+  ObmDereferenceObject(Window);
+}
+
+
+/***********************************************************************
+ *           IntSendDestroyMsg
+ */
+static void IntSendDestroyMsg(HWND Wnd)
+{
+#if 0 /* FIXME */
+  GUITHREADINFO info;
+
+  if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
+    {
+      if (Wnd == info.hwndCaret)
+       {
+         DestroyCaret();
+       }
+    }
+#endif
+
+  /*
+   * Send the WM_DESTROY to the window.
+   */
+  NtUserSendMessage(Wnd, WM_DESTROY, 0, 0);
+
+  /*
+   * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
+   * make sure that the window still exists when we come back.
+   */
+#if 0 /* FIXME */
+  if (IsWindow(Wnd))
+    {
+      HWND* pWndArray;
+      int i;
+
+      if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
+
+      /* start from the end (FIXME: is this needed?) */
+      for (i = 0; pWndArray[i]; i++) ;
+
+      while (--i >= 0)
+       {
+         if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
+       }
+      HeapFree(GetProcessHeap(), 0, pWndArray);
+    }
+  else
+    {
+      DPRINT("destroyed itself while in WM_DESTROY!\n");
+    }
+#endif
+}
+
+
+BOOL FASTCALL
+IntSetSystemMenu(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject)
+{
+  PMENU_OBJECT OldMenuObject;
+  if(WindowObject->SystemMenu)
+  {
+    OldMenuObject = IntGetMenuObject(WindowObject->SystemMenu);
+    if(OldMenuObject)
+    {
+      OldMenuObject->IsSystemMenu = FALSE;
+      IntReleaseMenuObject(OldMenuObject);
+    }
+  }
+  
+  WindowObject->SystemMenu = MenuObject->Self;
+  if(MenuObject) /* FIXME check window style, propably return FALSE ? */
+    MenuObject->IsSystemMenu = TRUE;
+  
+  return TRUE;
+}
+
+
+/* unlink the window from siblings and parent. children are kept in place. */
+VOID FASTCALL
+IntUnlinkWindow(PWINDOW_OBJECT Wnd)
+{
+  PWINDOW_OBJECT WndParent = Wnd->Parent; 
+  if (Wnd->NextSibling) Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
+  else if (WndParent->LastChild == Wnd) WndParent->LastChild = Wnd->PrevSibling;
+  if (Wnd->PrevSibling) Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
+  else if (WndParent->FirstChild == Wnd) WndParent->FirstChild = Wnd->NextSibling;
+  //else if (parent->first_unlinked == win) parent->first_unlinked = Wnd->NextSibling;
+}
+
+
+BOOLEAN FASTCALL
+IntWndBelongsToThread(PWINDOW_OBJECT Window, PW32THREAD ThreadData)
+{
+  if (Window->OwnerThread && Window->OwnerThread->Win32Thread)
+  {
+    return (Window->OwnerThread->Win32Thread == ThreadData);
+  }
+
+  return FALSE;
+}
+
+
+/* FUNCTIONS *****************************************************************/
+
+
+/*
+ * @unimplemented
+ */
+DWORD STDCALL
+NtUserAlterWindowStyle(DWORD Unknown0,
+                      DWORD Unknown1,
+                      DWORD Unknown2)
+{
+  UNIMPLEMENTED
+
+  return(0);
+}
+
+
+/*
+ * As best as I can figure, this function is used by EnumWindows,
+ * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
+ *
+ * It's supposed to build a list of HWNDs to return to the caller.
+ * We can figure out what kind of list by what parameters are
+ * passed to us.
+ */
+/*
+ * @implemented
+ */
+ULONG
+STDCALL
+NtUserBuildHwndList(
+  HDESK hDesktop,
+  HWND hwndParent,
+  BOOLEAN bChildren,
+  ULONG dwThreadId,
+  ULONG lParam,
+  HWND* pWnd,
+  ULONG nBufSize)
+{
+  ULONG dwCount = 0;
+
+  /* FIXME handle bChildren */
+  if ( hwndParent )
+    {
+      PWINDOW_OBJECT WindowObject = NULL;
+      PWINDOW_OBJECT Child;
+
+      WindowObject = IntGetWindowObject ( hwndParent );
+      if ( !WindowObject )
+       {
+         DPRINT("Bad window handle 0x%x\n", hwndParent);
+         SetLastWin32Error(ERROR_INVALID_HANDLE);
+         return 0;
+       }
+
+      ExAcquireFastMutex ( &WindowObject->ChildrenListLock );
+      Child = WindowObject->FirstChild;
+      while (Child)
+       {
+         if ( pWnd && dwCount < nBufSize )
+           pWnd[dwCount] = Child->Self;
+         dwCount++;
+    Child = Child->NextSibling;
+       }
+      ExReleaseFastMutex ( &WindowObject->ChildrenListLock );
+      IntReleaseWindowObject ( WindowObject );
+    }
+  else if ( dwThreadId )
+    {
+      NTSTATUS Status;
+      struct _ETHREAD* Thread;
+      struct _EPROCESS* ThreadsProcess;
+      struct _W32PROCESS*   Win32Process;
+      struct _WINSTATION_OBJECT* WindowStation;
+      PUSER_HANDLE_TABLE HandleTable;
+      PLIST_ENTRY Current;
+      PUSER_HANDLE_BLOCK Block = NULL;
+      ULONG i;
+
+      Status = PsLookupThreadByThreadId ( (PVOID)dwThreadId, &Thread );
+      if ( !NT_SUCCESS(Status) || !Thread )
+       {
+         DPRINT("Bad ThreadId 0x%x\n", dwThreadId );
+         SetLastWin32Error(ERROR_INVALID_HANDLE);
+         return 0;
+       }
+      ThreadsProcess = Thread->ThreadsProcess;
+      ASSERT(ThreadsProcess);
+      Win32Process = ThreadsProcess->Win32Process;
+      ASSERT(Win32Process);
+      WindowStation = Win32Process->WindowStation;
+      ASSERT(WindowStation);
+      HandleTable = (PUSER_HANDLE_TABLE)(WindowStation->HandleTable);
+      ASSERT(HandleTable);
+
+      ExAcquireFastMutex(&HandleTable->ListLock);
+
+      Current = HandleTable->ListHead.Flink;
+      while ( Current != &HandleTable->ListHead )
+       {
+         Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
+         for ( i = 0; i < HANDLE_BLOCK_ENTRIES; i++ )
+           {
+             PVOID ObjectBody = Block->Handles[i].ObjectBody;
+             if ( ObjectBody )
+             {
+               if ( pWnd && dwCount < nBufSize )
+                 {
+                   pWnd[dwCount] =
+                     (HWND)ObmReferenceObjectByPointer ( ObjectBody, otWindow );
+                 }
+               dwCount++;
+             }
+           }
+         Current = Current->Flink;
+       }
+
+      ExReleaseFastMutex(&HandleTable->ListLock);
+    }
+  else
+    {
+      PDESKTOP_OBJECT DesktopObject = NULL;
+      KIRQL OldIrql;
+      PWINDOW_OBJECT Child, WndDesktop;
+
+      if ( hDesktop )
+       DesktopObject = IntGetDesktopObject ( hDesktop );
+      else
+       DesktopObject = IntGetActiveDesktop();
+      if (!DesktopObject)
+       {
+         DPRINT("Bad desktop handle 0x%x\n", hDesktop );
+         SetLastWin32Error(ERROR_INVALID_HANDLE);
+         return 0;
+       }
+
+      KeAcquireSpinLock ( &DesktopObject->Lock, &OldIrql );
+
+      WndDesktop = IntGetWindowObject(DesktopObject->DesktopWindow);
+      Child = (WndDesktop ? WndDesktop->FirstChild : NULL);
+      while (Child)
+       {
+         if ( pWnd && dwCount < nBufSize )
+           pWnd[dwCount] = Child->Self;
+         dwCount++;
+    Child = Child->NextSibling;
+       }
+      KeReleaseSpinLock ( &DesktopObject->Lock, OldIrql );
+    }
+
+  return dwCount;
+}
+
+
+/*
+ * @unimplemented
+ */
+BOOL
+STDCALL
+NtUserCallHwndLock(
+  HWND hWnd,
+  DWORD Unknown1)
+{
+  UNIMPLEMENTED
+  /* DrawMenuBar() calls it with Unknown1==0x55 */
+  return 0;
+}
+
+
+/*
+ * @unimplemented
+ */
+DWORD STDCALL
+NtUserChildWindowFromPointEx(HWND Parent,
+                            LONG x,
+                            LONG y,
+                            UINT Flags)
+{
+  UNIMPLEMENTED
+
+  return(0);
+}
+
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+NtUserCreateWindowEx(DWORD dwExStyle,
+                    PUNICODE_STRING lpClassName,
+                    PUNICODE_STRING lpWindowName,
+                    DWORD dwStyle,
+                    LONG x,
+                    LONG y,
+                    LONG nWidth,
+                    LONG nHeight,
+                    HWND hWndParent,
+                    HMENU hMenu,
+                    HINSTANCE hInstance,
+                    LPVOID lpParam,
+                    DWORD dwShowMode)
+{
+  PWINSTATION_OBJECT WinStaObject;
+  PWNDCLASS_OBJECT ClassObject;
+  PWINDOW_OBJECT WindowObject;
+  PWINDOW_OBJECT ParentWindow;
+  PMENU_OBJECT SystemMenu;
+  UNICODE_STRING WindowName;
+  NTSTATUS Status;
+  HANDLE Handle;
+  POINT MaxSize, MaxPos, MinTrack, MaxTrack;
+  CREATESTRUCTW Cs;
+  LRESULT Result;
+  DPRINT("NtUserCreateWindowEx\n");
+
+  /* Initialize gui state if necessary. */
+  IntGraphicsCheck(TRUE);
+
+  if (!RtlCreateUnicodeString(&WindowName,
+                              NULL == lpWindowName->Buffer ?
+                              L"" : lpWindowName->Buffer))
+    {
+      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+      return((HWND)0);
+    }
+
+  /* FIXME: parent must belong to the current process */
+
+  if (hWndParent != NULL)
+    {
+      ParentWindow = IntGetWindowObject(hWndParent);
+    }
+  else
+    {
+      hWndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
+      ParentWindow = IntGetWindowObject(hWndParent);
+    }
+
+  /* Check the class. */
+  Status = ClassReferenceClassByNameOrAtom(&ClassObject, lpClassName->Buffer);
+  if (!NT_SUCCESS(Status))
+    {
+      RtlFreeUnicodeString(&WindowName);
+      IntReleaseWindowObject(ParentWindow);
+      return((HWND)0);
+    }
+
+  /* Check the window station. */
+  DPRINT("IoGetCurrentProcess() %X\n", IoGetCurrentProcess());
+  DPRINT("PROCESS_WINDOW_STATION %X\n", PROCESS_WINDOW_STATION());
   Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
                                       KernelMode,
                                       0,
@@ -448,6 +1140,7 @@ NtUserCreateWindowEx(DWORD dwExStyle,
     {
       RtlFreeUnicodeString(&WindowName);
       ObmDereferenceObject(ClassObject);
+      IntReleaseWindowObject(ParentWindow);
       DPRINT("Validation of window station handle (0x%X) failed\n",
             PROCESS_WINDOW_STATION());
       return (HWND)0;
@@ -456,13 +1149,16 @@ NtUserCreateWindowEx(DWORD dwExStyle,
   /* Create the window object. */
   WindowObject = (PWINDOW_OBJECT)
     ObmCreateObject(PsGetWin32Process()->WindowStation->HandleTable, &Handle,
-                   otWindow, sizeof(WINDOW_OBJECT));
+        otWindow, sizeof(WINDOW_OBJECT) + ClassObject->cbWndExtra
+        );
+
   DPRINT("Created object with handle %X\n", Handle);
   if (!WindowObject)
     {
       ObDereferenceObject(WinStaObject);
       ObmDereferenceObject(ClassObject);
       RtlFreeUnicodeString(&WindowName);
+      IntReleaseWindowObject(ParentWindow);
       SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
       return (HWND)0;
     }
@@ -473,33 +1169,43 @@ NtUserCreateWindowEx(DWORD dwExStyle,
    */
   WindowObject->Class = ClassObject;
   WindowObject->ExStyle = dwExStyle;
-  WindowObject->Style = dwStyle | WIN_NCACTIVATED;
+  WindowObject->Style = dwStyle & ~WS_VISIBLE;
+  DPRINT("1: Style is now %d\n", WindowObject->Style);
+  
+  SystemMenu = IntGetSystemMenu(WindowObject, TRUE, TRUE);
+  
   WindowObject->x = x;
   WindowObject->y = y;
   WindowObject->Width = nWidth;
   WindowObject->Height = nHeight;
+  WindowObject->ContextHelpId = 0;
   WindowObject->ParentHandle = hWndParent;
-  WindowObject->Menu = hMenu;
+  WindowObject->IDMenu = (UINT)hMenu;
+  if(SystemMenu)
+    WindowObject->SystemMenu = SystemMenu->Self;
+  else
+    WindowObject->SystemMenu = (HMENU)0;
   WindowObject->Instance = hInstance;
   WindowObject->Parameters = lpParam;
   WindowObject->Self = Handle;
   WindowObject->MessageQueue = PsGetWin32Thread()->MessageQueue;
   WindowObject->Parent = ParentWindow;
-  InsertHeadList(&ParentWindow->ChildrenListHead,
-                &WindowObject->SiblingListEntry);
-  InitializeListHead(&WindowObject->ChildrenListHead);
-  InitializeListHead(&WindowObject->PropListHead);
-  ExInitializeFastMutex(&WindowObject->ChildrenListLock);
-
-  RtlInitUnicodeString(&WindowObject->WindowName, WindowName.Buffer);
-  RtlFreeUnicodeString(&WindowName);
-
-  if (ClassObject->Class.cbWndExtra != 0)
+  WindowObject->UserData = 0;
+  WindowObject->Unicode = ClassObject->Unicode;
+  WindowObject->WndProcA = ClassObject->lpfnWndProcA;
+  WindowObject->WndProcW = ClassObject->lpfnWndProcW;
+  WindowObject->OwnerThread = PsGetCurrentThread();
+  WindowObject->FirstChild = NULL;
+  WindowObject->LastChild = NULL;
+  WindowObject->PrevSibling = NULL;
+  WindowObject->NextSibling = NULL;
+
+  /* extra window data */
+  if (ClassObject->cbWndExtra != 0)
     {
-      WindowObject->ExtraData =
-       ExAllocatePool(PagedPool,
-                      ClassObject->Class.cbWndExtra * sizeof(DWORD));
-      WindowObject->ExtraDataSize = ClassObject->Class.cbWndExtra;
+      WindowObject->ExtraData = (PULONG)(WindowObject + 1);
+      WindowObject->ExtraDataSize = ClassObject->cbWndExtra;
+      RtlZeroMemory(WindowObject->ExtraData, WindowObject->ExtraDataSize);
     }
   else
     {
@@ -507,29 +1213,33 @@ NtUserCreateWindowEx(DWORD dwExStyle,
       WindowObject->ExtraDataSize = 0;
     }
 
+  InitializeListHead(&WindowObject->PropListHead);
+  ExInitializeFastMutex(&WindowObject->ChildrenListLock);
+
+  RtlInitUnicodeString(&WindowObject->WindowName, WindowName.Buffer);
+  RtlFreeUnicodeString(&WindowName);
+
+
   /* Correct the window style. */
   if (!(dwStyle & WS_CHILD))
     {
       WindowObject->Style |= WS_CLIPSIBLINGS;
+      DPRINT("3: Style is now %d\n", WindowObject->Style);
       if (!(dwStyle & WS_POPUP))
        {
          WindowObject->Style |= WS_CAPTION;
+      WindowObject->Flags |= WINDOWOBJECT_NEED_SIZE;
+      DPRINT("4: Style is now %d\n", WindowObject->Style);
          /* FIXME: Note the window needs a size. */ 
        }
     }
 
-  /* Insert the window into the process's window list. */
+  /* Insert the window into the thread's window list. */
   ExAcquireFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
   InsertTailList (&PsGetWin32Thread()->WindowListHead, 
                  &WindowObject->ThreadListEntry);
   ExReleaseFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
 
-  /*
-   * Insert the window into the list of windows associated with the thread's
-   * desktop. 
-   */
-  InsertTailList(&PsGetWin32Thread()->Desktop->WindowListHead,
-                &WindowObject->DesktopListEntry);
   /* Allocate a DCE for this window. */
   if (dwStyle & CS_OWNDC) WindowObject->Dce = DceAllocDCE(WindowObject->Self,DCE_WINDOW_DC);
   /* FIXME:  Handle "CS_CLASSDC" */
@@ -546,6 +1256,7 @@ NtUserCreateWindowEx(DWORD dwExStyle,
    */
   if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
     {
+      /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
       WinPosGetMinMaxInfo(WindowObject, &MaxSize, &MaxPos, &MinTrack,
                          &MaxTrack);
       x = min(MaxSize.x, y);
@@ -564,9 +1275,9 @@ NtUserCreateWindowEx(DWORD dwExStyle,
   
   /* Initialize the window's scrollbars */
   if (dwStyle & WS_VSCROLL)
-      SCROLL_CreateScrollBar(WindowObject, SB_VERT);
+      IntCreateScrollBar(WindowObject, SB_VERT);
   if (dwStyle & WS_HSCROLL)
-      SCROLL_CreateScrollBar(WindowObject, SB_HORZ);
+      IntCreateScrollBar(WindowObject, SB_HORZ);
 
   /* Send a NCCREATE message. */
   Cs.lpCreateParams = lpParam;
@@ -581,55 +1292,97 @@ NtUserCreateWindowEx(DWORD dwExStyle,
   Cs.lpszName = lpWindowName->Buffer;
   Cs.lpszClass = lpClassName->Buffer;
   Cs.dwExStyle = dwExStyle;
+
+    // AG: For some reason these don't get set already. This might need moving
+    // elsewhere... What is actually done with WindowObject anyway, to retain
+    // its data?
+  DPRINT("[win32k.window] NtUserCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
+//  NtUserSetWindowLong(Handle, GWL_STYLE, WindowObject->Style, TRUE);
+//  NtUserSetWindowLong(Handle, GWL_EXSTYLE, WindowObject->ExStyle, TRUE);
+  // Any more?
+
   DPRINT("NtUserCreateWindowEx(): About to send NCCREATE message.\n");
-  Result = W32kSendNCCREATEMessage(WindowObject->Self, &Cs);
+  Result = IntSendNCCREATEMessage(WindowObject->Self, &Cs);
   if (!Result)
     {
       /* FIXME: Cleanup. */
+      IntReleaseWindowObject(ParentWindow);
       DPRINT("NtUserCreateWindowEx(): NCCREATE message failed.\n");
-      return(NULL);
+      return((HWND)0);
     }
  
   /* Calculate the non-client size. */
   MaxPos.x = WindowObject->WindowRect.left;
   MaxPos.y = WindowObject->WindowRect.top;
   DPRINT("NtUserCreateWindowEx(): About to get non-client size.\n");
+  /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
   Result = WinPosGetNonClientSize(WindowObject->Self, 
                                  &WindowObject->WindowRect,
                                  &WindowObject->ClientRect);
-  W32kOffsetRect(&WindowObject->WindowRect, 
+  NtGdiOffsetRect(&WindowObject->WindowRect, 
                 MaxPos.x - WindowObject->WindowRect.left,
                 MaxPos.y - WindowObject->WindowRect.top);
 
-  /* Send the CREATE message. */
+
+  /* link the window into the parent's child list */
+  ExAcquireFastMutexUnsafe(&ParentWindow->ChildrenListLock);
+  if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
+  {
+    /* link window as bottom sibling */
+    IntLinkWindow(WindowObject, ParentWindow, ParentWindow->LastChild /*prev sibling*/);
+  }
+  else
+  {
+    /* link window as top sibling */
+    IntLinkWindow(WindowObject, ParentWindow, NULL /*prev sibling*/);
+  }
+  ExReleaseFastMutexUnsafe(&ParentWindow->ChildrenListLock);
+
+  /* Send the WM_CREATE message. */
   DPRINT("NtUserCreateWindowEx(): about to send CREATE message.\n");
-  Result = W32kSendCREATEMessage(WindowObject->Self, &Cs);
+  Result = IntSendCREATEMessage(WindowObject->Self, &Cs);
   if (Result == (LRESULT)-1)
     {
       /* FIXME: Cleanup. */
+      IntReleaseWindowObject(ParentWindow);
       DPRINT("NtUserCreateWindowEx(): send CREATE message failed.\n");
-      return(NULL);
+      return((HWND)0);
     } 
-
+  
   /* Send move and size messages. */
   if (!(WindowObject->Flags & WINDOWOBJECT_NEED_SIZE))
     {
       LONG lParam;
+
+      DPRINT("NtUserCreateWindow(): About to send WM_SIZE\n");
+
+      if ((WindowObject->ClientRect.right - WindowObject->ClientRect.left) < 0 ||
+          (WindowObject->ClientRect.bottom - WindowObject->ClientRect.top) < 0)
+         DPRINT("Sending bogus WM_SIZE\n");
       
-      lParam = 
-       MAKE_LONG(WindowObject->ClientRect.right - 
+      lParam = MAKE_LONG(WindowObject->ClientRect.right - 
                  WindowObject->ClientRect.left,
                  WindowObject->ClientRect.bottom - 
                  WindowObject->ClientRect.top);
-      DPRINT("NtUserCreateWindow(): About to send WM_SIZE\n");
-      W32kCallWindowProc(NULL, WindowObject->Self, WM_SIZE, SIZE_RESTORED, 
-                        lParam);
-      lParam = 
-       MAKE_LONG(WindowObject->ClientRect.left,
-                 WindowObject->ClientRect.top);
+      IntCallWindowProc(NULL, WindowObject->Self, WM_SIZE, SIZE_RESTORED, 
+          lParam);
+
       DPRINT("NtUserCreateWindow(): About to send WM_MOVE\n");
-      W32kCallWindowProc(NULL, WindowObject->Self, WM_MOVE, 0, lParam);
+
+      lParam = MAKE_LONG(WindowObject->ClientRect.left,
+          WindowObject->ClientRect.top);
+      IntCallWindowProc(NULL, WindowObject->Self, WM_MOVE, 0, lParam);
+    }
+
+  /* Move from parent-client to screen coordinates */
+  if (0 != (WindowObject->Style & WS_CHILD))
+    {
+    NtGdiOffsetRect(&WindowObject->WindowRect,
+                  ParentWindow->ClientRect.left,
+                  ParentWindow->ClientRect.top);
+    NtGdiOffsetRect(&WindowObject->ClientRect,
+                  ParentWindow->ClientRect.left,
+                  ParentWindow->ClientRect.top);
     }
 
   /* Show or maybe minimize or maximize the window. */
@@ -642,7 +1395,7 @@ NtUserCreateWindowEx(DWORD dwExStyle,
        SW_MAXIMIZE;
       WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
       SwFlag = 
-       ((WindowObject->Style & WS_CHILD) || W32kGetActiveWindow()) ?
+       ((WindowObject->Style & WS_CHILD) || IntGetActiveWindow()) ?
        SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
        SWP_NOZORDER | SWP_FRAMECHANGED;
       DPRINT("NtUserCreateWindow(): About to minimize/maximize\n");
@@ -650,50 +1403,214 @@ NtUserCreateWindowEx(DWORD dwExStyle,
                         NewPos.right, NewPos.bottom, SwFlag);
     }
 
-  /* Notify the parent window of a new child. */
-  if ((WindowObject->Style & WS_CHILD) ||
-      (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)))
+  /* Notify the parent window of a new child. */
+  if ((WindowObject->Style & WS_CHILD) ||
+      (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)))
+    {
+      DPRINT("NtUserCreateWindow(): About to notify parent\n");
+      IntCallWindowProc(NULL, WindowObject->Parent->Self,
+                        WM_PARENTNOTIFY, 
+                        MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
+                        (LPARAM)WindowObject->Self);
+    }
+
+  if (dwStyle & WS_VISIBLE)
+    {
+      DPRINT("NtUserCreateWindow(): About to show window\n");
+      WinPosShowWindow(WindowObject->Self, dwShowMode);
+    }
+  /* FIXME:  Should code be reworked to accomodate the following line? */
+       DPRINT("Setting Active Window to %d\n\n\n",WindowObject->Self);
+  NtUserSetActiveWindow(WindowObject->Self);
+  DPRINT("NtUserCreateWindow(): = %X\n", Handle);
+  DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
+  return((HWND)Handle);
+}
+
+
+/*
+ * @unimplemented
+ */
+HDWP STDCALL
+NtUserDeferWindowPos(HDWP WinPosInfo,
+                    HWND Wnd,
+                    HWND WndInsertAfter,
+                    int x,
+         int y,
+         int cx,
+         int cy,
+                    UINT Flags)
+{
+  UNIMPLEMENTED
+
+  return 0;
+}
+
+
+/*
+ * @implemented
+ */
+BOOLEAN STDCALL
+NtUserDestroyWindow(HWND Wnd)
+{
+  PWINDOW_OBJECT Window;
+  BOOLEAN isChild;
+  HWND hWndFocus;
+
+  Window = IntGetWindowObject(Wnd);
+  if (Window == NULL)
+    {
+      return FALSE;
+    }
+
+  /* Check for desktop window (has NULL parent) */
+  if (NULL == Window->Parent)
+    {
+      IntReleaseWindowObject(Window);
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      return FALSE;
+    }
+
+  /* Look whether the focus is within the tree of windows we will
+   * be destroying.
+   */
+  hWndFocus = IntGetFocusWindow();
+  if (hWndFocus == Wnd || IntIsChildWindow(Wnd, hWndFocus))
+    {
+      HWND Parent = NtUserGetAncestor(Wnd, GA_PARENT);
+      if (Parent == IntGetDesktopWindow())
+       {
+         Parent = NULL;
+       }
+        IntSetFocusWindow(Parent);
+    }
+
+  /* Call hooks */
+#if 0 /* FIXME */
+  if (HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
+    {
+    return FALSE;
+    }
+#endif
+
+  isChild = (0 != (Window->Style & WS_CHILD));
+
+#if 0 /* FIXME */
+  if (isChild)
+    {
+      if (! USER_IsExitingThread(GetCurrentThreadId()))
+       {
+         send_parent_notify(hwnd, WM_DESTROY);
+       }
+    }
+  else if (NULL != GetWindow(Wnd, GW_OWNER))
+    {
+      HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
+      /* FIXME: clean up palette - see "Internals" p.352 */
+    }
+
+  if (! IsWindow(Wnd))
+    {
+    return TRUE;
+    }
+#endif
+
+  /* Hide the window */
+  if (! WinPosShowWindow(Wnd, SW_HIDE ))
+    {
+#if 0 /* FIXME */
+      if (hwnd == GetActiveWindow())
+       {
+         WINPOS_ActivateOtherWindow( hwnd );
+       }
+#endif
+    }
+
+#if 0 /* FIXME */
+  if (! IsWindow(Wnd))
     {
-      DPRINT("NtUserCreateWindow(): About to notify parent\n");
-      W32kCallWindowProc(NULL, WindowObject->Parent->Self,
-                        WM_PARENTNOTIFY, 
-                        MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
-                        (LPARAM)WindowObject->Self);
+    return TRUE;
     }
+#endif
 
-  if (dwStyle & WS_VISIBLE)
+  /* Recursively destroy owned windows */
+#if 0 /* FIXME */
+  if (! isChild)
     {
-      DPRINT("NtUserCreateWindow(): About to show window\n");
-      WinPosShowWindow(WindowObject->Self, dwShowMode);
+      for (;;)
+       {
+         int i;
+         BOOL GotOne = FALSE;
+         HWND *list = WIN_ListChildren(GetDesktopWindow());
+         if (list)
+           {
+             for (i = 0; list[i]; i++)
+               {
+                 if (GetWindow(list[i], GW_OWNER) != Wnd)
+                   {
+                     continue;
+                   }
+                 if (WIN_IsCurrentThread(list[i]))
+                   {
+                     DestroyWindow(list[i]);
+                     GotOne = TRUE;
+                     continue;
+                   }
+                 WIN_SetOwner(list[i], NULL);
+               }
+             HeapFree(GetProcessHeap(), 0, list);
+           }
+         if (! GotOne)
+           {
+             break;
+           }
+       }
     }
+#endif
 
-  DPRINT("NtUserCreateWindow(): = %X\n", Handle);
-  return((HWND)Handle);
-}
+  /* Send destroy messages */
+  IntSendDestroyMsg(Wnd);
 
-DWORD STDCALL
-NtUserDeferWindowPos(HDWP WinPosInfo,
-                    HWND Wnd,
-                    HWND WndInsertAfter,
-                    LONG x,
-                    LONG y,
-                    LONG cx,
-                    LONG cy,
-                    UINT Flags)
-{
-  UNIMPLEMENTED
+#if 0 /* FIXME */
+  if (!IsWindow(Wnd))
+    {
+      return TRUE;
+    }
+#endif
 
-  return 0;
+  /* Unlink now so we won't bother with the children later on */
+#if 0 /* FIXME */
+  WIN_UnlinkWindow( hwnd );
+#endif
+
+  /* Destroy the window storage */
+  IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
+
+  return TRUE;
 }
 
-BOOLEAN STDCALL
-NtUserDestroyWindow(HWND Wnd)
-{
-  W32kGraphicsCheck(FALSE);
 
+/*
+ * @unimplemented
+ */
+DWORD
+STDCALL
+NtUserDrawMenuBarTemp(
+  HWND hWnd,
+  HDC hDC,
+  PRECT hRect,
+  HMENU hMenu,
+  HFONT hFont)
+{
+  /* we'll use this function just for caching the menu bar */
+  UNIMPLEMENTED
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserEndDeferWindowPosEx(DWORD Unknown0,
                          DWORD Unknown1)
@@ -703,6 +1620,10 @@ NtUserEndDeferWindowPosEx(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserFillWindow(DWORD Unknown0,
                 DWORD Unknown1,
@@ -714,57 +1635,118 @@ NtUserFillWindow(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * FUNCTION:
+ *   Searches a window's children for a window with the specified
+ *   class and name
+ * ARGUMENTS:
+ *   hwndParent            = The window whose childs are to be searched. 
+ *                                       NULL = desktop
+ *
+ *   hwndChildAfter = Search starts after this child window. 
+ *                                       NULL = start from beginning
+ *
+ *   ucClassName    = Class name to search for
+ *                                       Reguired parameter.
+ *
+ *   ucWindowName   = Window name
+ *                                       ->Buffer == NULL = don't care
+ *                       
+ * RETURNS:
+ *   The HWND of the window if it was found, otherwise NULL
+ *
+ * FIXME:
+ *   Should use MmCopyFromCaller, we don't want an access violation in here
+ *      
+ */
+/*
+ * @implemented
+ */
 HWND STDCALL
 NtUserFindWindowEx(HWND hwndParent,
                   HWND hwndChildAfter,
                   PUNICODE_STRING ucClassName,
-                  PUNICODE_STRING ucWindowName,
-                  DWORD Unknown4)
+                  PUNICODE_STRING ucWindowName)
 {
-#if 0
   NTSTATUS status;
   HWND windowHandle;
-  PWINDOW_OBJECT windowObject;
-  PLIST_ENTRY currentEntry;
+  PWINDOW_OBJECT ParentWindow, WndChildAfter, WndChild;
   PWNDCLASS_OBJECT classObject;
   
-  W32kGuiCheck();
-  
+  // Get a pointer to the class
   status = ClassReferenceClassByNameOrAtom(&classObject, ucClassName->Buffer);
   if (!NT_SUCCESS(status))
     {
-      return (HWND)0;
+      return NULL;
     }
+  
+  // If hwndParent==NULL use the desktop window instead
+  if(!hwndParent)
+      hwndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
 
-  ExAcquireFastMutexUnsafe (&PsGetWin32Process()->WindowListLock);
-  currentEntry = PsGetWin32Process()->WindowListHead.Flink;
-  while (currentEntry != &PsGetWin32Process()->WindowListHead)
+  // Get the object
+  ParentWindow = IntGetWindowObject(hwndParent);
+
+  if(!ParentWindow)
     {
-      windowObject = CONTAINING_RECORD (currentEntry, WINDOW_OBJECT, 
-                                       ListEntry);
+      ObmDereferenceObject(classObject);
+      return NULL;      
+    }
 
-      if (classObject == windowObject->Class &&
-         RtlCompareUnicodeString (ucWindowName, &windowObject->WindowName, 
-                                  TRUE) == 0)
-       {
-         ObmCreateHandle(PsGetWin32Process()->HandleTable,
-                         windowObject,
-                         &windowHandle);
-         ExReleaseFastMutexUnsafe (&PsGetWin32Process()->WindowListLock);
-         ObmDereferenceObject (classObject);
+  ExAcquireFastMutexUnsafe (&ParentWindow->ChildrenListLock);
+
+  if(hwndChildAfter)
+  {
+    if (!(WndChildAfter = IntGetWindowObject(hwndChildAfter)))
+    {
+      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+      return NULL;
+    }
+
+    /* must be a direct child (not a decendant child)*/
+    if (WndChildAfter->Parent != ParentWindow)
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return NULL;
+    }
+    
+    WndChild = WndChildAfter->NextSibling;
+  }
+  else
+  {
+    WndChild = ParentWindow->FirstChild;
+  }
+
+  while (WndChild)
+  {
+    if (classObject == WndChild->Class && (ucWindowName->Buffer==NULL || 
+        RtlCompareUnicodeString (ucWindowName, &WndChild->WindowName, TRUE) == 0))
+    {
+      windowHandle = WndChild->Self;
+
+      ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
+      IntReleaseWindowObject(ParentWindow);
+      ObmDereferenceObject (classObject);
       
-         return  windowHandle;
-       }
-      currentEntry = currentEntry->Flink;
+      return windowHandle;
+    }
+    
+    WndChild = WndChild->NextSibling;
   }
-  ExReleaseFastMutexUnsafe (&PsGetWin32Process()->WindowListLock);
-  
+
+  ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
+
+  IntReleaseWindowObject(ParentWindow);
   ObmDereferenceObject (classObject);
 
-  return  (HWND)0;
-#endif
+  return  NULL;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserFlashWindowEx(DWORD Unknown0)
 {
@@ -773,6 +1755,103 @@ NtUserFlashWindowEx(DWORD Unknown0)
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+NtUserGetAncestor(HWND hWnd, UINT Type)
+{
+  PWINDOW_OBJECT Wnd, WndAncestor;
+  HWND hWndAncestor = NULL;
+
+  IntAcquireWinLockShared();
+
+  if (!(Wnd = IntGetWindowObject(hWnd)))
+  {
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return NULL;
+  }
+
+  WndAncestor = IntGetAncestor(Wnd, Type);
+  if (WndAncestor) hWndAncestor = WndAncestor->Self;
+
+  IntReleaseWinLock();
+
+  return hWndAncestor;
+}
+
+
+/*
+ * @implemented
+ */
+HWND
+STDCALL
+NtUserGetCapture(VOID)
+{
+  PWINDOW_OBJECT Window;
+  Window = IntGetCaptureWindow();
+  if (Window != NULL)
+    {
+      return(Window->Self);
+    }
+  else
+    {
+      return(NULL);
+    }
+}
+
+
+/*!
+ * Returns client window rectangle relative to the upper-left corner of client area.
+ *
+ * \param      hWnd    window handle.
+ * \param      Rect    pointer to the buffer where the coordinates are returned.
+ *
+*/
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserGetClientRect(HWND hWnd, LPRECT Rect)
+{
+  PWINDOW_OBJECT WindowObject;
+  RECT SafeRect;
+
+  IntAcquireWinLockShared();
+  if (!(WindowObject = IntGetWindowObject(hWnd)))
+  {
+    IntReleaseWinLock();
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);      
+    return FALSE;
+  }
+
+  IntGetClientRect(WindowObject, &SafeRect);
+  IntReleaseWinLock();
+
+  if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
+  {
+    return(FALSE);
+  }
+
+  return(TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+HWND
+STDCALL
+NtUserGetDesktopWindow()
+{
+  return IntGetDesktopWindow();
+}
+
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserGetForegroundWindow(VOID)
 {
@@ -781,6 +1860,10 @@ NtUserGetForegroundWindow(VOID)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserGetInternalWindowPos(DWORD Unknown0,
                           DWORD Unknown1,
@@ -791,6 +1874,37 @@ NtUserGetInternalWindowPos(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
+HWND
+STDCALL
+NtUserGetLastActivePopup(HWND hWnd)
+{
+  PWINDOW_OBJECT Wnd;
+  HWND hWndLastPopup;
+
+  IntAcquireWinLockShared();
+
+  if (!(Wnd = IntGetWindowObject(hWnd)))
+  {
+    IntReleaseWinLock();
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return NULL;
+  }
+
+  hWndLastPopup = Wnd->hWndLastPopup;
+
+  IntReleaseWinLock();
+
+  return hWndLastPopup;
+}
+
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserGetOpenClipboardWindow(VOID)
 {
@@ -799,31 +1913,341 @@ NtUserGetOpenClipboardWindow(VOID)
   return 0;
 }
 
-DWORD STDCALL
-NtUserGetWindowDC(HWND hWnd)
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+NtUserGetParent(HWND hWnd)
+{
+  PWINDOW_OBJECT Wnd, WndParent;
+  HWND hWndParent = NULL;
+
+  IntAcquireWinLockShared();
+
+  if (!(Wnd = IntGetWindowObject(hWnd)))
+  {
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return NULL;
+  }
+
+  WndParent = IntGetParent(Wnd);
+  if (WndParent) hWndParent = WndParent->Self;
+
+  IntReleaseWinLock();
+
+  return hWndParent;
+}
+
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+NtUserGetShellWindow()
+{
+       return hwndShellWindow;
+}
+
+
+/*
+ * @implemented
+ */
+HMENU
+STDCALL
+NtUserGetSystemMenu(
+  HWND hWnd,
+  BOOL bRevert)
+{
+  HMENU res = (HMENU)0;
+  PWINDOW_OBJECT WindowObject;
+  WindowObject = IntGetWindowObject((HWND)hWnd);
+  if(!WindowObject)
+  {
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return (HMENU)0;
+  }
+  
+  res = IntGetSystemMenu(WindowObject, bRevert, FALSE);
+  
+  IntReleaseWindowObject(WindowObject);
+  return res;
+}
+
+
+/*
+ * @implemented
+ */
+HWND
+STDCALL
+NtUserGetWindow(HWND hWnd, UINT Relationship)
+{
+  PWINDOW_OBJECT Wnd;
+  HWND hWndResult = NULL;
+
+  IntAcquireWinLockShared();
+
+  if (!(Wnd = IntGetWindowObject(hWnd)))
+  {
+    IntReleaseWinLock();
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return NULL;
+  }
+  
+  switch (Relationship)
+  {
+    case GW_HWNDFIRST:
+      if (Wnd->Parent && Wnd->Parent->FirstChild)
+      {
+        hWndResult = Wnd->Parent->FirstChild->Self;
+      }
+      break;
+    case GW_HWNDLAST:
+      if (Wnd->Parent && Wnd->Parent->LastChild)
+      {
+        hWndResult = Wnd->Parent->LastChild->Self;
+      }
+      break;
+    case GW_HWNDNEXT:
+      if (Wnd->Parent && Wnd->NextSibling)
+      {
+        hWndResult = Wnd->NextSibling->Self;
+      }
+      break;
+    case GW_HWNDPREV:
+      if (Wnd->Parent && Wnd->PrevSibling)
+      {
+        hWndResult = Wnd->PrevSibling->Self;
+      }
+      break;
+    case GW_OWNER:
+      if (Wnd->Parent)
+      {
+        hWndResult = Wnd->hWndOwner;
+      }
+      break;
+    case GW_CHILD:
+      if (Wnd->FirstChild)
+      {
+        hWndResult = Wnd->FirstChild->Self;
+      }
+      break;
+  }
+
+  IntReleaseWinLock();
+
+  return hWndResult;
+}
+
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+NtUserGetWindowDC(HWND hWnd)
+{
+  return (DWORD) NtUserGetDCEx( hWnd, 0, DCX_USESTYLE | DCX_WINDOW );
+}
+
+
+/*
+ * @implemented
+ */
+LONG STDCALL
+NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
+{
+  PWINDOW_OBJECT WindowObject;
+  NTSTATUS Status;
+  LONG Result;
+
+  Status = 
+    ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
+                              hWnd,
+                              otWindow,
+                              (PVOID*)&WindowObject);
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return 0;
+    }
+
+  if (0 <= (int) Index)
+    {
+      if (WindowObject->ExtraDataSize - sizeof(LONG) < Index ||
+          0 != Index % sizeof(LONG))
+       {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return 0;
+       }
+      Result = WindowObject->ExtraData[Index / sizeof(LONG)];
+    }
+  else
+    {
+      switch (Index)
+       {
+       case GWL_EXSTYLE:
+         Result = WindowObject->ExStyle;
+         break;
+
+       case GWL_STYLE:
+         Result = WindowObject->Style;
+         break;
+       case GWL_WNDPROC:
+         if (Ansi)
+         {
+               Result = (LONG) WindowObject->WndProcA;
+         }
+         else
+         {
+               Result = (LONG) WindowObject->WndProcW;
+         }
+         break;
+
+       case GWL_HINSTANCE:
+         Result = (LONG) WindowObject->Instance;
+         break;
+
+       case GWL_HWNDPARENT:
+         Result = (LONG) WindowObject->ParentHandle;
+         break;
+
+       case GWL_ID:
+         Result = (LONG) WindowObject->IDMenu;
+         break;
+
+       case GWL_USERDATA:
+         Result = WindowObject->UserData;
+         break;
+    
+       default:
+         DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         Result = 0;
+         break;
+       }
+    }
+
+  ObmDereferenceObject(WindowObject);
+
+  return Result;
+}
+
+
+/*
+ * @unimplemented
+ */
+DWORD STDCALL
+NtUserGetWindowPlacement(DWORD Unknown0,
+                        DWORD Unknown1)
+{
+  UNIMPLEMENTED
+
+  return 0;
+}
+
+
+/*!
+ * Return the dimension of the window in the screen coordinates.
+ * \param      hWnd    window handle.
+ * \param      Rect    pointer to the buffer where the coordinates are returned.
+*/
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
 {
-  return NtUserGetDCEx( hWnd, 0, DCX_USESTYLE | DCX_WINDOW );
+  PWINDOW_OBJECT Wnd;
+  RECT SafeRect;
+
+  IntAcquireWinLockShared();
+  if (!(Wnd = IntGetWindowObject(hWnd)))
+  {
+    IntReleaseWinLock();
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);      
+    return FALSE;
+  }
+  
+  SafeRect = Wnd->WindowRect;
+  IntReleaseWinLock();
+
+  if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
+  {
+    return FALSE;
+  }
+
+  return TRUE;
 }
 
+
+/*
+ * @implemented
+ */
 DWORD STDCALL
-NtUserGetWindowPlacement(DWORD Unknown0,
-                        DWORD Unknown1)
+NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
 {
-  UNIMPLEMENTED
-
-  return 0;
+   PWINDOW_OBJECT Wnd;
+   DWORD tid, pid;
+
+   IntAcquireWinLockShared();
+
+   if (!(Wnd = IntGetWindowObject(hWnd)))
+   {
+      IntReleaseWinLock();
+      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+      return 0;
+   }
+
+   tid = IntGetWindowThreadProcessId(Wnd, &pid);
+   IntReleaseWinLock();
+   
+   if (UnsafePid) MmCopyToCaller(UnsafePid, &pid, sizeof(DWORD));
+   
+   return tid;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
-NtUserInternalGetWindowText(DWORD Unknown0,
-                           DWORD Unknown1,
-                           DWORD Unknown2)
+NtUserInternalGetWindowText(HWND hWnd,
+                           LPWSTR lpString,
+                           int nMaxCount)
 {
-  UNIMPLEMENTED
-
-  return 0;
+  DWORD res = 0;
+  PWINDOW_OBJECT WindowObject;
+  
+  IntAcquireWinLockShared(); /* ??? */
+  WindowObject = IntGetWindowObject(hWnd);
+  if(!WindowObject)
+  {
+    IntReleaseWinLock(); /* ??? */
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return 0;
+  }
+  
+  if(lpString)
+  {
+    /* FIXME - Window text is currently stored
+               in the Atom 'USER32!WindowTextAtomA' */
+    
+  }
+  else
+  {
+    /* FIXME - return length of window text */
+  }
+  
+  IntReleaseWindowObject(WindowObject);
+  
+  IntReleaseWinLock(); /* ??? */
+  return res;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserLockWindowUpdate(DWORD Unknown0)
 {
@@ -832,6 +2256,10 @@ NtUserLockWindowUpdate(DWORD Unknown0)
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
 BOOL STDCALL
 NtUserMoveWindow(      
     HWND hWnd,
@@ -841,81 +2269,56 @@ NtUserMoveWindow(
     int nHeight,
     BOOL bRepaint)
 {
-    PWINDOW_OBJECT Window = W32kGetWindowObject(hWnd);
-    ULONG uStyle, uExStyle;
-    WINDOWPOS pWinPos;
+       UINT    flags = SWP_NOZORDER | SWP_NOACTIVATE;
 
-    if (!Window) return FALSE;
-    
-    uStyle = Window->Style;
-    uExStyle = Window->ExStyle;
-    pWinPos.hwnd = hWnd;
-    
-    pWinPos.x = X;
-    pWinPos.y = Y;
-    if (nWidth > NtUserGetSystemMetrics(SM_CXMIN))
-        pWinPos.cx = pWinPos.x + nWidth;
-    else
-        pWinPos.cx = pWinPos.x + NtUserGetSystemMetrics(SM_CXMIN);
-        
-    if (nHeight > NtUserGetSystemMetrics(SM_CYMIN))
-        pWinPos.cy = pWinPos.x + nHeight;
-    else
-        pWinPos.cy = pWinPos.y + NtUserGetSystemMetrics(SM_CYMIN);
-    NtUserSendMessage(hWnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pWinPos);
-    
-    Window->WindowRect.top = Window->ClientRect.top = pWinPos.y;
-    Window->WindowRect.left = Window->ClientRect.left = pWinPos.x;
-    Window->WindowRect.bottom = Window->ClientRect.bottom = pWinPos.cy;
-    Window->WindowRect.right = Window->ClientRect.right = pWinPos.cx;
-    
-    if (!(uStyle & WS_THICKFRAME))
-    {
-      Window->ClientRect.top += NtUserGetSystemMetrics(SM_CYFIXEDFRAME);
-      Window->ClientRect.bottom -= NtUserGetSystemMetrics(SM_CYFIXEDFRAME);
-      Window->ClientRect.left += NtUserGetSystemMetrics(SM_CXFIXEDFRAME);
-      Window->ClientRect.right -= NtUserGetSystemMetrics(SM_CXFIXEDFRAME);
-    }
-    else
-    {
-        Window->ClientRect.top += NtUserGetSystemMetrics(SM_CYSIZEFRAME);
-        Window->ClientRect.bottom -= NtUserGetSystemMetrics(SM_CYSIZEFRAME);
-        Window->ClientRect.left += NtUserGetSystemMetrics(SM_CXSIZEFRAME);
-        Window->ClientRect.right -= NtUserGetSystemMetrics(SM_CXSIZEFRAME);
-    }
+       if(!bRepaint)
+               flags |= SWP_NOREDRAW;
+       return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight, flags);
+}
 
-    if (uStyle & WS_CAPTION)
-       Window->ClientRect.top += NtUserGetSystemMetrics(SM_CYCAPTION);
-    if ( Window->Class->Class.lpszMenuName)
-    {
-        Window->ClientRect.top += NtUserGetSystemMetrics(SM_CYMENU);
-    }
+/*
+       QueryWindow based on KJK::Hyperion and James Tabor.
 
-    NtUserSendMessage(hWnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pWinPos);
-    
-    NtUserSendMessage(hWnd, WM_MOVE, 0, MAKEWORD(Window->ClientRect.left,
-                                                 Window->ClientRect.top));
-                                                 
-    NtUserSendMessage(hWnd, WM_SIZE, 0, MAKEWORD(Window->ClientRect.right -
-                                                 Window->ClientRect.left,
-                                                 Window->ClientRect.bottom -
-                                                 Window->ClientRect.top));
-
-    /* FIXME:  Send WM_NCCALCSIZE */
-    W32kReleaseWindowObject(Window);
-    if (bRepaint) NtUserSendMessage(hWnd, WM_PAINT, 0, 0);
-    return TRUE;
-}
+       0 = QWUniqueProcessId
+       1 = QWUniqueThreadId
+       4 = QWIsHung            Implements IsHungAppWindow found
+                                by KJK::Hyperion.
 
+        9 = QWKillWindow        When I called this with hWnd ==
+                                DesktopWindow, it shutdown the system
+                                and rebooted.
+*/
+/*
+ * @implemented
+ */
 DWORD STDCALL
-NtUserQueryWindow(DWORD Unknown0,
-                 DWORD Unknown1)
+NtUserQueryWindow(HWND hWnd, DWORD Index)
 {
-  UNIMPLEMENTED
 
-  return 0;
+PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
+
+        if(Window == NULL) return((DWORD)NULL);
+
+        IntReleaseWindowObject(Window);
+
+        switch(Index)
+        {
+        case 0x00:
+                return((DWORD)Window->OwnerThread->ThreadsProcess->UniqueProcessId);
+
+        case 0x01:
+                return((DWORD)Window->OwnerThread->Cid.UniqueThread);
+
+        default:
+                return((DWORD)NULL);
+        }
+
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserRealChildWindowFromPoint(DWORD Unknown0,
                               DWORD Unknown1,
@@ -926,34 +2329,135 @@ NtUserRealChildWindowFromPoint(DWORD Unknown0,
   return 0;
 }
 
-NTSTATUS STDCALL
-NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate, UINT flags)
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+NtUserRedrawWindow
+(
+ HWND hWnd,
+ CONST RECT *lprcUpdate,
+ HRGN hrgnUpdate,
+ UINT flags
+)
+{
+ RECT SafeUpdateRect;
+ NTSTATUS Status;
+ PWINDOW_OBJECT Wnd;
+
+ if (!(Wnd = IntGetWindowObject(hWnd)))
+ {
+   SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+   return FALSE;
+ }
+
+ if(NULL != lprcUpdate)
+ {
+  Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate, sizeof(RECT));
+
+  if(!NT_SUCCESS(Status))
+  {
+   /* FIXME: set last error */
+   return FALSE;
+  }
+ }
+
+
+ Status = PaintRedrawWindow
+ (
+  Wnd,
+  NULL == lprcUpdate ? NULL : &SafeUpdateRect,
+  hrgnUpdate,
+  flags,
+  0
+ );
+
+
+ if(!NT_SUCCESS(Status))
+ {
+  /* FIXME: set last error */
+  return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
 {
-  RECT SafeUpdateRect;
+  PLIST_ENTRY Current;
+  PREGISTERED_MESSAGE NewMsg, RegMsg;
+  UINT Msg = REGISTERED_MESSAGE_MIN;
+  UNICODE_STRING MessageName;
   NTSTATUS Status;
 
-  if (NULL != lprcUpdate)
+  Status = MmCopyFromCaller(&MessageName, MessageNameUnsafe, sizeof(UNICODE_STRING));
+  if (! NT_SUCCESS(Status))
+    {
+      SetLastNtError(Status);
+      return 0;
+    }
+
+  NewMsg = ExAllocatePoolWithTag(PagedPool,
+                                 sizeof(REGISTERED_MESSAGE) +
+                                 MessageName.Length,
+                                 TAG_WNAM);
+  if (NULL == NewMsg)
+    {
+      SetLastNtError(STATUS_NO_MEMORY);
+      return 0;
+    }
+
+  Status = MmCopyFromCaller(NewMsg->MessageName, MessageName.Buffer, MessageName.Length);
+  if (! NT_SUCCESS(Status))
+    {
+      ExFreePool(NewMsg);
+      SetLastNtError(Status);
+      return 0;
+    }
+  NewMsg->MessageName[MessageName.Length / sizeof(WCHAR)] = L'\0';
+  if (wcslen(NewMsg->MessageName) != MessageName.Length / sizeof(WCHAR))
+    {
+      ExFreePool(NewMsg);
+      SetLastNtError(STATUS_INVALID_PARAMETER);
+      return 0;
+    }
+
+  Current = RegisteredMessageListHead.Flink;
+  while (Current != &RegisteredMessageListHead)
     {
-      Status = MmCopyFromCaller(&SafeUpdateRect, lprcUpdate, sizeof(RECT));
-      if (! NT_SUCCESS(Status))
+      RegMsg = CONTAINING_RECORD(Current, REGISTERED_MESSAGE, ListEntry);
+      if (0 == wcscmp(NewMsg->MessageName, RegMsg->MessageName))
        {
-         return Status;
+         ExFreePool(NewMsg);
+         return Msg;
        }
+      Msg++;
+      Current = Current->Flink;
     }
 
-  return PaintRedrawWindow(hWnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect, hrgnUpdate,
-                           flags, 0) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
-;
-}
+  if (REGISTERED_MESSAGE_MAX < Msg)
+    {
+      ExFreePool(NewMsg);
+      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+      return 0;
+    }
 
-UINT STDCALL
-NtUserRegisterWindowMessage(LPCWSTR MessageName)
-{
-  UNIMPLEMENTED
+  InsertTailList(&RegisteredMessageListHead, &(NewMsg->ListEntry));
 
-  return(0);
+  return Msg;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserScrollWindowEx(DWORD Unknown0,
                     DWORD Unknown1,
@@ -969,14 +2473,47 @@ NtUserScrollWindowEx(DWORD Unknown0,
   return 0;
 }
 
-DWORD STDCALL
-NtUserSetActiveWindow(DWORD Unknown0)
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+NtUserSetCapture(HWND Wnd)
 {
-  UNIMPLEMENTED
+  PWINDOW_OBJECT Window;
+  PWINDOW_OBJECT Prev;
 
-  return 0;
+  Prev = IntGetCaptureWindow();
+
+  if (Prev != NULL)
+    {
+      IntSendMessage(Prev->Self, WM_CAPTURECHANGED, 0L, (LPARAM)Wnd, FALSE);
+    }
+
+  if (Wnd == NULL)
+    {
+      IntSetCaptureWindow(NULL);
+    }
+  else  
+    {
+      Window = IntGetWindowObject(Wnd);
+      IntSetCaptureWindow(Window);
+      IntReleaseWindowObject(Window);
+    }
+  if (Prev != NULL)
+    {
+      return(Prev->Self);
+    }
+  else
+    {
+      return(NULL);
+    }
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetImeOwnerWindow(DWORD Unknown0,
                        DWORD Unknown1)
@@ -986,6 +2523,10 @@ NtUserSetImeOwnerWindow(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetInternalWindowPos(DWORD Unknown0,
                           DWORD Unknown1,
@@ -998,6 +2539,10 @@ NtUserSetInternalWindowPos(DWORD Unknown0,
 
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetLayeredWindowAttributes(DWORD Unknown0,
                                 DWORD Unknown1,
@@ -1009,6 +2554,10 @@ NtUserSetLayeredWindowAttributes(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetLogonNotifyWindow(DWORD Unknown0)
 {
@@ -1017,15 +2566,170 @@ NtUserSetLogonNotifyWindow(DWORD Unknown0)
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserSetMenu(
+  HWND hWnd,
+  HMENU hMenu,
+  BOOL bRepaint)
+{
+  PWINDOW_OBJECT WindowObject;
+  PMENU_OBJECT MenuObject;
+  WindowObject = IntGetWindowObject((HWND)hWnd);
+  if(!WindowObject)
+  {
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+  
+  if(hMenu)
+  {
+    /* assign new menu handle */
+    MenuObject = IntGetMenuObject((HWND)hMenu);
+    if(!MenuObject)
+    {
+      IntReleaseWindowObject(WindowObject);
+      SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
+      return FALSE;
+    }
+    
+    WindowObject->IDMenu = (UINT)hMenu;
+    
+    IntReleaseMenuObject(MenuObject);
+  }
+  else
+  {
+    /* remove the menu handle */
+    WindowObject->IDMenu = 0;
+  }
+  
+  IntReleaseWindowObject(WindowObject);
+  
+  /* FIXME (from wine)
+  if(bRepaint)
+  {
+    if (IsWindowVisible(hWnd))
+        SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+                      SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
+  }
+  */
+  
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+HWND
+STDCALL
+NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
+{
+  PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
+  HWND hWndOldParent;
+
+  if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
+  {
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    return NULL;
+  }
+  
+  IntAcquireWinLockExclusive();
+  if (hWndNewParent)
+  {
+    if (!(WndParent = IntGetWindowObject(hWndNewParent)))
+    {
+      IntReleaseWinLock();
+      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+      return NULL;
+    }
+  }
+
+  if (!(Wnd = IntGetWindowObject(hWndNewParent)))
+  {
+    IntReleaseWinLock();
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return NULL;
+  }
+
+  WndOldParent = IntSetParent(Wnd, WndParent);
+  if (WndOldParent) hWndOldParent = WndOldParent->Self;
+
+  IntReleaseWinLock();
+
+  return hWndOldParent;    
+}
+
+
+/*
+ * @implemented
+ */
 DWORD STDCALL
-NtUserSetShellWindowEx(DWORD Unknown0,
-                      DWORD Unknown1)
+NtUserSetShellWindowEx(HWND hwndShell, HWND hwndShellListView)
 {
-  UNIMPLEMENTED
+       PEPROCESS my_current = IoGetCurrentProcess();
 
-  return 0;
+        /* test if we are permitted to change the shell window */
+       if (pidShellWindow && my_current->UniqueProcessId!=pidShellWindow)
+               return FALSE;
+
+       hwndShellWindow = hwndShell;
+       hwndShellListView = hwndShellListView;
+
+       if (hwndShell)
+               pidShellWindow = my_current->UniqueProcessId;   /* request shell window for the calling process */
+       else
+               pidShellWindow = 0;     /* shell window is now free for other processes. */
+
+       return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserSetSystemMenu(
+  HWND hWnd,
+  HMENU hMenu)
+{
+  BOOL res = FALSE;
+  PWINDOW_OBJECT WindowObject;
+  PMENU_OBJECT MenuObject;
+  WindowObject = IntGetWindowObject((HWND)hWnd);
+  if(!WindowObject)
+  {
+    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+    return FALSE;
+  }
+  
+  if(hMenu)
+  {
+    /* assign new menu handle */
+    MenuObject = IntGetMenuObject(hMenu);
+    if(!MenuObject)
+    {
+      IntReleaseWindowObject(WindowObject);
+      SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
+      return FALSE;
+    }
+    
+    res = IntSetSystemMenu(WindowObject, MenuObject);
+    
+    IntReleaseMenuObject(MenuObject);
+  }
+  
+  IntReleaseWindowObject(WindowObject);
+  return res;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetWindowFNID(DWORD Unknown0,
                    DWORD Unknown1)
@@ -1035,14 +2739,17 @@ NtUserSetWindowFNID(DWORD Unknown0,
   return 0;
 }
 
-DWORD STDCALL
-NtUserGetWindowLong(HWND hWnd, DWORD Index)
+
+/*
+ * @implemented
+ */
+LONG STDCALL
+NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
 {
   PWINDOW_OBJECT WindowObject;
   NTSTATUS Status;
-  DWORD Result;
-
-  W32kGuiCheck();
+  LONG OldValue;
+  STYLESTRUCT Style;
 
   Status = 
     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
@@ -1051,54 +2758,99 @@ NtUserGetWindowLong(HWND hWnd, DWORD Index)
                               (PVOID*)&WindowObject);
   if (!NT_SUCCESS(Status))
     {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
       return(0);
     }
 
-  switch (Index)
+  if (0 <= (int) Index)
     {
-    case GWL_EXSTYLE:
-      {
-       Result = (DWORD)WindowObject->ExStyle;
-       break;
-      }
-
-    case GWL_STYLE:
-      {
-       Result = (DWORD)WindowObject->Style;
-       break;
-      }
-
-    case GWL_WNDPROC:
-      {
-       Result = (DWORD)WindowObject->Class->Class.lpfnWndProc; 
-       break;
-      }
-    case GWL_ID:
-    break;
+      if (WindowObject->ExtraDataSize - sizeof(LONG) < Index ||
+          0 != Index % sizeof(LONG))
+       {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return 0;
+       }
+      OldValue = WindowObject->ExtraData[Index / sizeof(LONG)];
+      WindowObject->ExtraData[Index / sizeof(LONG)] = NewValue;
+    }
+  else
+    {
+      switch (Index)
+       {
+       case GWL_EXSTYLE:
+         OldValue = (LONG) WindowObject->ExStyle;
+         Style.styleOld = OldValue;
+         Style.styleNew = NewValue;
+         IntSendSTYLECHANGINGMessage(hWnd, GWL_EXSTYLE, &Style);
+         WindowObject->ExStyle = (DWORD)Style.styleNew;
+         IntSendSTYLECHANGEDMessage(hWnd, GWL_EXSTYLE, &Style);
+         break;
+
+       case GWL_STYLE:
+         OldValue = (LONG) WindowObject->Style;
+         Style.styleOld = OldValue;
+         Style.styleNew = NewValue;
+         IntSendSTYLECHANGINGMessage(hWnd, GWL_STYLE, &Style);
+         WindowObject->Style = (DWORD)Style.styleNew;
+         IntSendSTYLECHANGEDMessage(hWnd, GWL_STYLE, &Style);
+         break;
+
+       case GWL_WNDPROC:
+         /* FIXME: should check if window belongs to current process */
+         if (Ansi)
+         {
+           OldValue = (LONG) WindowObject->WndProcA;
+           WindowObject->WndProcA = (WNDPROC) NewValue;
+               WindowObject->WndProcW = (WNDPROC) NewValue+0x80000000;
+               WindowObject->Unicode = FALSE;
+         }
+         else
+         {
+           OldValue = (LONG) WindowObject->WndProcW;
+           WindowObject->WndProcW = (WNDPROC) NewValue;
+               WindowObject->WndProcA = (WNDPROC) NewValue+0x80000000;
+               WindowObject->Unicode = TRUE;
+         }
+         break;
+
+       case GWL_HINSTANCE:
+         OldValue = (LONG) WindowObject->Instance;
+         WindowObject->Instance = (HINSTANCE) NewValue;
+         break;
+
+       case GWL_HWNDPARENT:
+         OldValue = (LONG) WindowObject->ParentHandle;
+         WindowObject->ParentHandle = (HWND) NewValue;
+         /* FIXME: Need to update window lists of old and new parent */
+         UNIMPLEMENTED;
+         break;
+
+       case GWL_ID:
+         OldValue = (LONG) WindowObject->IDMenu;
+         WindowObject->IDMenu = (UINT) NewValue;
+         break;
+
+       case GWL_USERDATA:
+         OldValue = WindowObject->UserData;
+         WindowObject->UserData = NewValue;
+         break;
     
-    default:
-      {
-       DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
-       Result = 0;
-       break;
-      }
+       default:
+         DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         OldValue = 0;
+         break;
+       }
     }
 
   ObmDereferenceObject(WindowObject);
-  return(Result);
+  return(OldValue);
 }
 
-DWORD STDCALL
-NtUserSetWindowLong(DWORD Unknown0,
-                   DWORD Unknown1,
-                   DWORD Unknown2,
-                   DWORD Unknown3)
-{
-  UNIMPLEMENTED
-
-  return 0;
-}
 
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetWindowPlacement(DWORD Unknown0,
                         DWORD Unknown1)
@@ -1108,8 +2860,12 @@ NtUserSetWindowPlacement(DWORD Unknown0,
   return 0;
 }
 
-BOOL 
-STDCALL NtUserSetWindowPos(      
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserSetWindowPos(      
     HWND hWnd,
     HWND hWndInsertAfter,
     int X,
@@ -1121,6 +2877,10 @@ STDCALL NtUserSetWindowPos(
   return WinPosSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserSetWindowRgn(DWORD Unknown0,
                   DWORD Unknown1,
@@ -1131,25 +2891,32 @@ NtUserSetWindowRgn(DWORD Unknown0,
   return 0;
 }
 
-DWORD STDCALL
-NtUserSetWindowWord(DWORD Unknown0,
-                   DWORD Unknown1,
-                   DWORD Unknown2)
+
+/*
+ * @unimplemented
+ */
+WORD STDCALL
+NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewVal)
 {
   UNIMPLEMENTED
-
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
 BOOL STDCALL
 NtUserShowWindow(HWND hWnd,
                 LONG nCmdShow)
 {
-  W32kGuiCheck();
-
   return(WinPosShowWindow(hWnd, nCmdShow));
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserShowWindowAsync(DWORD Unknown0,
                      DWORD Unknown1)
@@ -1159,18 +2926,27 @@ NtUserShowWindowAsync(DWORD Unknown0,
   return 0;
 }
 
-BOOL STDCALL NtUserUpdateWindow( HWND hWnd )
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+NtUserUpdateWindow(HWND hWnd)
 {
-    PWINDOW_OBJECT pWindow = W32kGetWindowObject( hWnd);
+    PWINDOW_OBJECT pWindow = IntGetWindowObject( hWnd);
 
     if (!pWindow)
         return FALSE;
     if (pWindow->UpdateRegion)
         NtUserSendMessage( hWnd, WM_PAINT,0,0);
-    W32kReleaseWindowObject(pWindow);
+    IntReleaseWindowObject(pWindow);
     return TRUE;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserUpdateLayeredWindow(DWORD Unknown0,
                          DWORD Unknown1,
@@ -1187,6 +2963,20 @@ NtUserUpdateLayeredWindow(DWORD Unknown0,
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+NtUserValidateRect(HWND hWnd, const RECT* Rect)
+{
+  return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
+}
+
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 NtUserWindowFromPoint(DWORD Unknown0,
                      DWORD Unknown1)