update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / window.c
index a95151b..2e9f63f 100644 (file)
 #include <windows.h>
 #include <user32.h>
 #include <window.h>
-#include <debug.h>
+#include <string.h>
 #include <user32/callback.h>
+#include <user32/regcontrol.h>
+
+#define NDEBUG
+#include <debug.h>
+
+static BOOL ControlsInitCalled = FALSE;
 
 /* FUNCTIONS *****************************************************************/
 ULONG
-   WinHasThickFrameStyle(ULONG Style, ULONG ExStyle)
+WinHasThickFrameStyle(ULONG Style, ULONG ExStyle)
 {
   return((Style & WS_THICKFRAME) &&
         (!((Style & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)));
 }
 
+
 NTSTATUS STDCALL
 User32SendNCCALCSIZEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
 {
@@ -32,15 +39,15 @@ User32SendNCCALCSIZEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
   SENDNCCALCSIZEMESSAGE_CALLBACK_RESULT Result;
   WNDPROC Proc;
 
-  DbgPrint("User32SendNCCALCSIZEMessageForKernel.\n");
+  DPRINT("User32SendNCCALCSIZEMessageForKernel.\n");
   CallbackArgs = (PSENDNCCALCSIZEMESSAGE_CALLBACK_ARGUMENTS)Arguments;
   if (ArgumentLength != sizeof(SENDNCCALCSIZEMESSAGE_CALLBACK_ARGUMENTS))
     {
-      DbgPrint("Wrong length.\n");
+      DPRINT("Wrong length.\n");
       return(STATUS_INFO_LENGTH_MISMATCH);
     }
-  Proc = (WNDPROC)GetWindowLongW(CallbackArgs->Wnd, GWL_WNDPROC);
-  DbgPrint("Proc %X\n", Proc);
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
   /* Call the window procedure; notice kernel messages are always unicode. */
   if (CallbackArgs->Validate)
     {
@@ -55,10 +62,11 @@ User32SendNCCALCSIZEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
                                      FALSE, (LPARAM)&CallbackArgs->Rect);
       Result.Rect = CallbackArgs->Rect;
     }
-  DbgPrint("Returning result %d.\n", Result);
+  DPRINT("Returning result %d.\n", Result);
   return(ZwCallbackReturn(&Result, sizeof(Result), STATUS_SUCCESS));
 }
 
+
 NTSTATUS STDCALL
 User32SendGETMINMAXINFOMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
 {
@@ -66,23 +74,24 @@ User32SendGETMINMAXINFOMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
   SENDGETMINMAXINFO_CALLBACK_RESULT Result;
   WNDPROC Proc;
 
-  DbgPrint("User32SendGETMINAXINFOMessageForKernel.\n");
+  DPRINT("User32SendGETMINAXINFOMessageForKernel.\n");
   CallbackArgs = (PSENDGETMINMAXINFO_CALLBACK_ARGUMENTS)Arguments;
   if (ArgumentLength != sizeof(SENDGETMINMAXINFO_CALLBACK_ARGUMENTS))
     {
-      DbgPrint("Wrong length.\n");
+      DPRINT("Wrong length.\n");
       return(STATUS_INFO_LENGTH_MISMATCH);
     }
-  Proc = (WNDPROC)GetWindowLongW(CallbackArgs->Wnd, GWL_WNDPROC);
-  DbgPrint("Proc %X\n", Proc);
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
   /* Call the window procedure; notice kernel messages are always unicode. */
   Result.Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_GETMINMAXINFO, 
                                  0, (LPARAM)&CallbackArgs->MinMaxInfo);
   Result.MinMaxInfo = CallbackArgs->MinMaxInfo;
-  DbgPrint("Returning result %d.\n", Result);
+  DPRINT("Returning result %d.\n", Result);
   return(ZwCallbackReturn(&Result, sizeof(Result), STATUS_SUCCESS));
 }
 
+
 NTSTATUS STDCALL
 User32SendCREATEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
 {
@@ -90,22 +99,23 @@ User32SendCREATEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
   WNDPROC Proc;
   LRESULT Result;
 
-  DbgPrint("User32SendCREATEMessageForKernel.\n");
+  DPRINT("User32SendCREATEMessageForKernel.\n");
   CallbackArgs = (PSENDCREATEMESSAGE_CALLBACK_ARGUMENTS)Arguments;
   if (ArgumentLength != sizeof(SENDCREATEMESSAGE_CALLBACK_ARGUMENTS))
     {
-      DbgPrint("Wrong length.\n");
+      DPRINT("Wrong length.\n");
       return(STATUS_INFO_LENGTH_MISMATCH);
     }
-  Proc = (WNDPROC)GetWindowLongW(CallbackArgs->Wnd, GWL_WNDPROC);
-  DbgPrint("Proc %X\n", Proc);
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
   /* Call the window procedure; notice kernel messages are always unicode. */
   Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_CREATE, 0, 
                           (LPARAM)&CallbackArgs->CreateStruct);
-  DbgPrint("Returning result %d.\n", Result);
+  DPRINT("Returning result %d.\n", Result);
   return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
 }
 
+
 NTSTATUS STDCALL
 User32SendNCCREATEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
 {
@@ -113,28 +123,125 @@ User32SendNCCREATEMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
   WNDPROC Proc;
   LRESULT Result;
 
-  DbgPrint("User32SendNCCREATEMessageForKernel.\n");
+  DPRINT("User32SendNCCREATEMessageForKernel.\n");
   CallbackArgs = (PSENDNCCREATEMESSAGE_CALLBACK_ARGUMENTS)Arguments;
   if (ArgumentLength != sizeof(SENDNCCREATEMESSAGE_CALLBACK_ARGUMENTS))
     {
-      DbgPrint("Wrong length.\n");
+      DPRINT("Wrong length.\n");
       return(STATUS_INFO_LENGTH_MISMATCH);
     }
-  Proc = (WNDPROC)GetWindowLongW(CallbackArgs->Wnd, GWL_WNDPROC);
-  DbgPrint("Proc %X\n", Proc);
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
   /* Call the window procedure; notice kernel messages are always unicode. */
   Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_NCCREATE, 0, 
                           (LPARAM)&CallbackArgs->CreateStruct);
-  DbgPrint("Returning result %d.\n", Result);
+  DPRINT("Returning result %d.\n", Result);
+  return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
+}
+
+
+NTSTATUS STDCALL
+User32SendWINDOWPOSCHANGINGMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+  PSENDWINDOWPOSCHANGING_CALLBACK_ARGUMENTS CallbackArgs;
+  WNDPROC Proc;
+  LRESULT Result;
+
+  DPRINT("User32SendWINDOWPOSCHANGINGMessageForKernel.\n");
+  CallbackArgs = (PSENDWINDOWPOSCHANGING_CALLBACK_ARGUMENTS)Arguments;
+  if (ArgumentLength != sizeof(SENDWINDOWPOSCHANGING_CALLBACK_ARGUMENTS))
+    {
+      DPRINT("Wrong length.\n");
+      return(STATUS_INFO_LENGTH_MISMATCH);
+    }
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
+  /* Call the window procedure; notice kernel messages are always unicode. */
+  Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_WINDOWPOSCHANGING, 0, 
+                          (LPARAM)&CallbackArgs->WindowPos);
+  DPRINT("Returning result %d.\n", Result);
+  return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
+}
+
+
+NTSTATUS STDCALL
+User32SendWINDOWPOSCHANGEDMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+  PSENDWINDOWPOSCHANGED_CALLBACK_ARGUMENTS CallbackArgs;
+  WNDPROC Proc;
+  LRESULT Result;
+
+  DPRINT("User32SendWINDOWPOSCHANGEDMessageForKernel.\n");
+  CallbackArgs = (PSENDWINDOWPOSCHANGED_CALLBACK_ARGUMENTS)Arguments;
+  if (ArgumentLength != sizeof(SENDWINDOWPOSCHANGED_CALLBACK_ARGUMENTS))
+    {
+      DPRINT("Wrong length.\n");
+      return(STATUS_INFO_LENGTH_MISMATCH);
+    }
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
+  /* Call the window procedure; notice kernel messages are always unicode. */
+  Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_WINDOWPOSCHANGED, 0, 
+                          (LPARAM)&CallbackArgs->WindowPos);
+  DPRINT("Returning result %d.\n", Result);
+  return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
+}
+
+
+NTSTATUS STDCALL
+User32SendSTYLECHANGINGMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+  PSENDSTYLECHANGING_CALLBACK_ARGUMENTS CallbackArgs;
+  WNDPROC Proc;
+  LRESULT Result;
+
+  DPRINT("User32SendSTYLECHANGINGMessageForKernel.\n");
+  CallbackArgs = (PSENDSTYLECHANGING_CALLBACK_ARGUMENTS)Arguments;
+  if (ArgumentLength != sizeof(SENDSTYLECHANGING_CALLBACK_ARGUMENTS))
+    {
+      DPRINT("Wrong length.\n");
+      return(STATUS_INFO_LENGTH_MISMATCH);
+    }
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
+  /* Call the window procedure; notice kernel messages are always unicode. */
+  Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_STYLECHANGING, CallbackArgs->WhichStyle,
+                          (LPARAM)&CallbackArgs->Style);
+  DPRINT("Returning result %d.\n", Result);
+  return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
+}
+
+
+NTSTATUS STDCALL
+User32SendSTYLECHANGEDMessageForKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+  PSENDSTYLECHANGED_CALLBACK_ARGUMENTS CallbackArgs;
+  WNDPROC Proc;
+  LRESULT Result;
+
+  DPRINT("User32SendSTYLECHANGEDGMessageForKernel.\n");
+  CallbackArgs = (PSENDSTYLECHANGED_CALLBACK_ARGUMENTS)Arguments;
+  if (ArgumentLength != sizeof(SENDSTYLECHANGED_CALLBACK_ARGUMENTS))
+    {
+      DPRINT("Wrong length.\n");
+      return(STATUS_INFO_LENGTH_MISMATCH);
+    }
+  Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
+  DPRINT("Proc %X\n", Proc);
+  /* Call the window procedure; notice kernel messages are always unicode. */
+  Result = CallWindowProcW(Proc, CallbackArgs->Wnd, WM_STYLECHANGED, CallbackArgs->WhichStyle,
+                          (LPARAM)&CallbackArgs->Style);
+  DPRINT("Returning result %d.\n", Result);
   return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
 }
 
+
 NTSTATUS STDCALL
 User32CallSendAsyncProcForKernel(PVOID Arguments, ULONG ArgumentLength)
 {
   PSENDASYNCPROC_CALLBACK_ARGUMENTS CallbackArgs;
 
-  DbgPrint("User32CallSendAsyncProcKernel()\n");
+  DPRINT("User32CallSendAsyncProcKernel()\n");
   CallbackArgs = (PSENDASYNCPROC_CALLBACK_ARGUMENTS)Arguments;
   if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
     {
@@ -145,6 +252,7 @@ User32CallSendAsyncProcForKernel(PVOID Arguments, ULONG ArgumentLength)
   return(STATUS_SUCCESS);
 }
 
+
 NTSTATUS STDCALL
 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
 {
@@ -158,8 +266,7 @@ User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
     }
   if (CallbackArgs->Proc == NULL)
     {
-      CallbackArgs->Proc = (WNDPROC)GetWindowLong(CallbackArgs->Wnd, 
-                                                 GWL_WNDPROC);
+      CallbackArgs->Proc = (WNDPROC)NtUserGetWindowLong(CallbackArgs->Wnd, GWL_WNDPROC, FALSE);
     }
   Result = CallWindowProcW(CallbackArgs->Proc, CallbackArgs->Wnd, 
                           CallbackArgs->Msg, CallbackArgs->wParam, 
@@ -167,6 +274,7 @@ User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
   return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
 }
 
+
 static void NC_AdjustRectOuter95 (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
 {
     int adjust;
@@ -202,6 +310,7 @@ static void NC_AdjustRectOuter95 (LPRECT rect, DWORD style, BOOL menu, DWORD exS
     if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
 }
 
+
 static void
 NC_AdjustRectInner95 (LPRECT rect, DWORD style, DWORD exStyle)
 {
@@ -220,14 +329,10 @@ NC_AdjustRectInner95 (LPRECT rect, DWORD style, DWORD exStyle)
     if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
 }
 
-WINBOOL STDCALL
-AdjustWindowRect(LPRECT lpRect,
-                DWORD dwStyle,
-                WINBOOL bMenu)
-{
-  return(AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0));
-}
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 AdjustWindowRectEx(LPRECT lpRect, 
                   DWORD dwStyle, 
@@ -246,38 +351,66 @@ AdjustWindowRectEx(LPRECT lpRect,
     return TRUE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
-AllowSetForegroundWindow(DWORD dwProcessId)
+AdjustWindowRect(LPRECT lpRect,
+                DWORD dwStyle,
+                WINBOOL bMenu)
 {
-  return(FALSE);
+  return(AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0));
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
-AnimateWindow(HWND hwnd,
-             DWORD dwTime,
-             DWORD dwFlags)
+AllowSetForegroundWindow(DWORD dwProcessId)
 {
-  return FALSE;
+  UNIMPLEMENTED;
+  return(FALSE);
 }
 
+
+/*
+ * @unimplemented
+ */
 UINT STDCALL
 ArrangeIconicWindows(HWND hWnd)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 HDWP STDCALL
 BeginDeferWindowPos(int nNumWindows)
 {
+  UNIMPLEMENTED;
   return (HDWP)0;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 BringWindowToTop(HWND hWnd)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WORD STDCALL
 CascadeWindows(HWND hwndParent,
               UINT wHow,
@@ -285,33 +418,50 @@ CascadeWindows(HWND hwndParent,
               UINT cKids,
               const HWND *lpKids)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 ChildWindowFromPoint(HWND hWndParent,
                     POINT Point)
 {
+  UNIMPLEMENTED;
   return (HWND)0;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 ChildWindowFromPointEx(HWND hwndParent,
                       POINT pt,
                       UINT uFlags)
 {
+  UNIMPLEMENTED;
   return (HWND)0;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 CloseWindow(HWND hWnd)
 {
-    SendMessageA(hWnd, WM_CLOSE, 0, 0);
     SendMessageA(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
-    
+
     return (WINBOOL)(hWnd);
 }
 
+/*
+ * @implemented
+ */
 HWND STDCALL
 CreateWindowExA(DWORD dwExStyle,
                LPCSTR lpClassName,
@@ -328,26 +478,38 @@ CreateWindowExA(DWORD dwExStyle,
 {
   UNICODE_STRING WindowName;
   UNICODE_STRING ClassName;
+  WNDCLASSEXA wce;
   HWND Handle;
   INT sw;
-  
-  if (IS_ATOM(lpClassName)) 
+
+#if 0
+  DbgPrint("[window] CreateWindowExA style %d, exstyle %d, parent %d\n", dwStyle, dwExStyle, hWndParent);
+#endif
+
+  /* Register built-in controls if not already done */
+  if (! ControlsInitCalled)
+    {
+      ControlsInit();
+      ControlsInitCalled = TRUE;
+    }
+
+  if (IS_ATOM(lpClassName))
     {
       RtlInitUnicodeString(&ClassName, NULL);
       ClassName.Buffer = (LPWSTR)lpClassName;
-    } 
-  else 
+    }
+  else
     {
-      if (!RtlCreateUnicodeStringFromAsciiz(&(ClassName), (PCSZ)lpClassName)) 
+      if (!RtlCreateUnicodeStringFromAsciiz(&(ClassName), (PCSZ)lpClassName))
        {
          SetLastError(ERROR_OUTOFMEMORY);
          return (HWND)0;
        }
     }
 
-  if (!RtlCreateUnicodeStringFromAsciiz(&WindowName, (PCSZ)lpWindowName)) 
+  if (!RtlCreateUnicodeStringFromAsciiz(&WindowName, (PCSZ)lpWindowName))
     {
-      if (!IS_ATOM(lpClassName)) 
+      if (!IS_ATOM(lpClassName))
        {
          RtlFreeUnicodeString(&ClassName);
        }
@@ -404,6 +566,15 @@ CreateWindowExA(DWORD dwExStyle,
            }
        }
     }
+    
+  if(!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))
+  {
+    wce.cbSize = sizeof(WNDCLASSEXA);
+    if(GetClassInfoExA(hInstance, lpClassName, &wce) && wce.lpszMenuName)
+    {
+      hMenu = LoadMenuA(hInstance, wce.lpszMenuName);
+    }
+  }
 
   Handle = NtUserCreateWindowEx(dwExStyle,
                                &ClassName,
@@ -419,6 +590,10 @@ CreateWindowExA(DWORD dwExStyle,
                                lpParam,
                                sw);
 
+#if 0
+  DbgPrint("[window] NtUserCreateWindowEx() == %d\n", Handle);
+#endif
+
   RtlFreeUnicodeString(&WindowName);
 
   if (!IS_ATOM(lpClassName)) 
@@ -429,6 +604,10 @@ CreateWindowExA(DWORD dwExStyle,
   return Handle;
 }
 
+
+/*
+ * @implemented
+ */
 HWND STDCALL
 CreateWindowExW(DWORD dwExStyle,
                LPCWSTR lpClassName,
@@ -445,9 +624,17 @@ CreateWindowExW(DWORD dwExStyle,
 {
   UNICODE_STRING WindowName;
   UNICODE_STRING ClassName;
+  WNDCLASSEXW wce;
   HANDLE Handle;
   UINT sw;
 
+  /* Register built-in controls if not already done */
+  if (! ControlsInitCalled)
+    {
+      ControlsInit();
+      ControlsInitCalled = TRUE;
+    }
+
   if (IS_ATOM(lpClassName)) 
     {
       RtlInitUnicodeString(&ClassName, NULL);
@@ -510,6 +697,15 @@ CreateWindowExW(DWORD dwExStyle,
        }
     }
 
+  if(!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))
+  {
+    wce.cbSize = sizeof(WNDCLASSEXW);
+    if(GetClassInfoExW(hInstance, lpClassName, &wce) && wce.lpszMenuName)
+    {
+      hMenu = LoadMenuW(hInstance, wce.lpszMenuName);
+    }
+  }
+
   Handle = NtUserCreateWindowEx(dwExStyle,
                                &ClassName,
                                &WindowName,
@@ -522,11 +718,15 @@ CreateWindowExW(DWORD dwExStyle,
                                hMenu,
                                hInstance,
                                lpParam,
-                               0);
+                               sw);
 
   return (HWND)Handle;
 }
 
+
+/*
+ * @unimplemented
+ */
 HDWP STDCALL
 DeferWindowPos(HDWP hWinPosInfo,
               HWND hWnd,
@@ -537,91 +737,260 @@ DeferWindowPos(HDWP hWinPosInfo,
               int cy,
               UINT uFlags)
 {
-  return (HDWP)0;
+  return NtUserDeferWindowPos(hWinPosInfo, hWnd, hWndInsertAfter, x, y, cx, cy, uFlags);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 DestroyWindow(HWND hWnd)
 {
-  SendMessageW(hWnd, WM_DESTROY, 0, 0);
-  SendMessageW(hWnd, WM_NCDESTROY, 0, 0);
-
   return NtUserDestroyWindow(hWnd);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 EndDeferWindowPos(HDWP hWinPosInfo)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
-WINBOOL STDCALL
-EnumChildWindows(HWND hWndParent,
-                ENUMWINDOWSPROC lpEnumFunc,
-                LPARAM lParam)
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+GetDesktopWindow(VOID)
 {
-  return FALSE;
+       return NtUserGetDesktopWindow();
 }
 
-WINBOOL STDCALL
+
+/*
+ * @unimplemented
+ */
+HWND STDCALL
+GetForegroundWindow(VOID)
+{
+  UNIMPLEMENTED;
+  return (HWND)0;
+}
+
+
+WINBOOL
+STATIC
+User32EnumWindows (
+       HDESK hDesktop,
+       HWND hWndparent,
+       ENUMWINDOWSPROC lpfn,
+       LPARAM lParam,
+       DWORD dwThreadId,
+       BOOL bChildren )
+{
+  DWORD i, dwCount = 0;
+  HWND* pHwnd = NULL;
+  HANDLE hHeap;
+
+  if ( !lpfn )
+    {
+      SetLastError ( ERROR_INVALID_PARAMETER );
+      return FALSE;
+    }
+
+  /* FIXME instead of always making two calls, should we use some
+     sort of persistent buffer and only grow it ( requiring a 2nd
+     call ) when the buffer wasn't already big enough? */
+  /* first get how many window entries there are */
+  SetLastError(0);
+  dwCount = NtUserBuildHwndList (
+    hDesktop, hWndparent, bChildren, dwThreadId, lParam, NULL, 0 );
+  if ( !dwCount || GetLastError() )
+    return FALSE;
+
+  /* allocate buffer to receive HWND handles */
+  hHeap = GetProcessHeap();
+  pHwnd = HeapAlloc ( hHeap, 0, sizeof(HWND)*(dwCount+1) );
+  if ( !pHwnd )
+    {
+      SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+      return FALSE;
+    }
+
+  /* now call kernel again to fill the buffer this time */
+  dwCount = NtUserBuildHwndList (
+    hDesktop, hWndparent, bChildren, dwThreadId, lParam, pHwnd, dwCount );
+  if ( !dwCount || GetLastError() )
+    {
+      if ( pHwnd )
+       HeapFree ( hHeap, 0, pHwnd );
+      return FALSE;
+    }
+
+  /* call the user's callback function until we're done or
+     they tell us to quit */
+  for ( i = 0; i < dwCount; i++ )
+  {
+    /* FIXME I'm only getting NULLs from Thread Enumeration, and it's
+     * probably because I'm not doing it right in NtUserBuildHwndList.
+     * Once that's fixed, we shouldn't have to check for a NULL HWND
+     * here
+     */
+    if ( !(ULONG)pHwnd[i] ) /* don't enumerate a NULL HWND */
+      continue;
+    if ( !(*lpfn)( pHwnd[i], lParam ) )
+      break;
+  }
+  if ( pHwnd )
+    HeapFree ( hHeap, 0, pHwnd );
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+EnumChildWindows(
+       HWND hWndParent,
+       ENUMWINDOWSPROC lpEnumFunc,
+       LPARAM lParam)
+{
+  if ( !hWndParent )
+    hWndParent = GetDesktopWindow();
+  return User32EnumWindows ( NULL, hWndParent, lpEnumFunc, lParam, 0, FALSE );
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
 EnumThreadWindows(DWORD dwThreadId,
                  ENUMWINDOWSPROC lpfn,
                  LPARAM lParam)
 {
-  return FALSE;
+  if ( !dwThreadId )
+    dwThreadId = GetCurrentThreadId();
+  return User32EnumWindows ( NULL, NULL, lpfn, lParam, dwThreadId, FALSE );
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 EnumWindows(ENUMWINDOWSPROC lpEnumFunc,
            LPARAM lParam)
 {
-  return FALSE;
+  return User32EnumWindows ( NULL, NULL, lpEnumFunc, lParam, 0, FALSE );
 }
 
-HWND STDCALL
-FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+EnumDesktopWindows(
+       HDESK hDesktop,
+       ENUMWINDOWSPROC lpfn,
+       LPARAM lParam)
 {
-  //FIXME: FindWindow does not search children, but FindWindowEx does.
-  //       what should we do about this?
-  return FindWindowExA (NULL, NULL, lpClassName, lpWindowName);
+  return User32EnumWindows ( hDesktop, NULL, lpfn, lParam, 0, FALSE );
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 FindWindowExA(HWND hwndParent,
              HWND hwndChildAfter,
              LPCSTR lpszClass,
              LPCSTR lpszWindow)
 {
+  UNIMPLEMENTED;
   return (HWND)0;
 }
 
-HWND STDCALL
-FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName)
-{
-  //FIXME: FindWindow does not search children, but FindWindowEx does.
-  //       what should we do about this?
-  return FindWindowExW (NULL, NULL, lpClassName, lpWindowName);
-}
 
+/*
+ * @implemented
+ */
 HWND STDCALL
 FindWindowExW(HWND hwndParent,
              HWND hwndChildAfter,
              LPCWSTR lpszClass,
              LPCWSTR lpszWindow)
 {
-  return (HWND)0;
+       UNICODE_STRING ucClassName;
+       UNICODE_STRING ucWindowName;
+
+       if (IS_ATOM(lpszClass)) 
+       {
+               RtlInitUnicodeString(&ucClassName, NULL);
+               ucClassName.Buffer = (LPWSTR)lpszClass;
+    } 
+       else 
+    {
+               RtlInitUnicodeString(&ucClassName, lpszClass);
+    }
+
+       // Window names can't be atoms, and if lpszWindow = NULL,
+       // RtlInitUnicodeString will clear it
+       
+       RtlInitUnicodeString(&ucWindowName, lpszWindow);
+
+
+       return NtUserFindWindowEx(hwndParent, hwndChildAfter, &ucClassName, &ucWindowName);
 }
 
-WINBOOL STDCALL
-GetAltTabInfo(HWND hwnd,
-             int iItem,
-             PALTTABINFO pati,
-             LPTSTR pszItemText,
-             UINT cchItemText)
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
 {
-  return FALSE;
+  //FIXME: FindWindow does not search children, but FindWindowEx does.
+  //       what should we do about this?
+  return FindWindowExA (NULL, NULL, lpClassName, lpWindowName);
+}
+
+
+/*
+ * @implemented
+ */
+HWND STDCALL
+FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName)
+{
+  /* 
+  
+  There was a FIXME here earlier, but I think it is just a documentation unclarity.
+
+  FindWindow only searches top level windows. What they mean is that child 
+  windows of other windows than the desktop can be searched. 
+  FindWindowExW never does a recursive search.
+  
+       / Joakim
+  */
+
+  return FindWindowExW (NULL, NULL, lpClassName, lpWindowName);
 }
 
+
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetAltTabInfoA(HWND hwnd,
               int iItem,
@@ -629,9 +998,14 @@ GetAltTabInfoA(HWND hwnd,
               LPSTR pszItemText,
               UINT cchItemText)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetAltTabInfoW(HWND hwnd,
               int iItem,
@@ -639,116 +1013,174 @@ GetAltTabInfoW(HWND hwnd,
               LPWSTR pszItemText,
               UINT cchItemText)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 HWND STDCALL
 GetAncestor(HWND hwnd, UINT gaFlags)
 {
   return(NtUserGetAncestor(hwnd, gaFlags));
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetClientRect(HWND hWnd, LPRECT lpRect)
 {
   return(NtUserGetClientRect(hWnd, lpRect));
 }
 
-HWND STDCALL
-GetDesktopWindow(VOID)
-{
-  return (HWND)0;
-}
-
-HWND STDCALL
-GetForegroundWindow(VOID)
-{
-  return (HWND)0;
-}
 
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetGUIThreadInfo(DWORD idThread,
                 LPGUITHREADINFO lpgui)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 GetLastActivePopup(HWND hWnd)
 {
-  return (HWND)0;
+  return NtUserGetLastActivePopup(hWnd);
 }
 
+
+/*
+ * @implemented
+ */
 HWND STDCALL
 GetParent(HWND hWnd)
 {
-  return NtUserGetAncestor(hWnd, GA_PARENT);
+  return NtUserGetParent(hWnd);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetProcessDefaultLayout(DWORD *pdwDefaultLayout)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetTitleBarInfo(HWND hwnd,
                PTITLEBARINFO pti)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 HWND STDCALL
-GetTopWindow(HWND hWnd)
+GetWindow(HWND hWnd,
+         UINT uCmd)
 {
-  return (HWND)0;
+  return NtUserGetWindow(hWnd, uCmd);
 }
 
+
+/*
+ * @implemented
+ */
 HWND STDCALL
-GetWindow(HWND hWnd,
-         UINT uCmd)
+GetTopWindow(HWND hWnd)
 {
-  return (HWND)0;
+  if (!hWnd) hWnd = GetDesktopWindow();
+  return GetWindow( hWnd, GW_CHILD );
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetWindowInfo(HWND hwnd,
              PWINDOWINFO pwi)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 UINT STDCALL
 GetWindowModuleFileName(HWND hwnd,
                        LPSTR lpszFileName,
                        UINT cchFileNameMax)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 UINT STDCALL
 GetWindowModuleFileNameA(HWND hwnd,
                         LPSTR lpszFileName,
                         UINT cchFileNameMax)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 UINT STDCALL
 GetWindowModuleFileNameW(HWND hwnd,
                         LPWSTR lpszFileName,
                         UINT cchFileNameMax)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 GetWindowPlacement(HWND hWnd,
                   WINDOWPLACEMENT *lpwndpl)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetWindowRect(HWND hWnd,
              LPRECT lpRect)
@@ -756,92 +1188,158 @@ GetWindowRect(HWND hWnd,
   return(NtUserGetWindowRect(hWnd, lpRect));
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
 {
   return(SendMessageA(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString));
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 GetWindowTextLengthA(HWND hWnd)
 {
   return(SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0));
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 GetWindowTextLengthW(HWND hWnd)
 {
-  return 0;
+  return(SendMessageW(hWnd, WM_GETTEXTLENGTH, 0, 0));
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
-GetWindowTextW(HWND hWnd,
-              LPWSTR lpString,
-              int nMaxCount)
+GetWindowTextW(
+       HWND hWnd,
+       LPWSTR lpString,
+       int nMaxCount)
 {
-  return 0;
+  return(SendMessageW(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString));
 }
 
 DWORD STDCALL
 GetWindowThreadProcessId(HWND hWnd,
                         LPDWORD lpdwProcessId)
 {
-  return 0;
+   return NtUserGetWindowThreadProcessId(hWnd, lpdwProcessId);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsChild(HWND hWndParent,
        HWND hWnd)
 {
-  return FALSE;
+    // Untested
+    return ((HWND)NtUserGetWindowLong(hWnd, GWL_HWNDPARENT, FALSE)) == hWndParent;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsIconic(HWND hWnd)
 {
-  return FALSE;
+  return (NtUserGetWindowLong( hWnd, GWL_STYLE, FALSE) & WS_MINIMIZE) != 0;  
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsWindow(HWND hWnd)
 {
-  return FALSE;
+  DWORD WndProc = NtUserGetWindowLong(hWnd, GWL_WNDPROC, FALSE);
+  return (0 != WndProc || ERROR_INVALID_HANDLE != GetLastError());
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsWindowUnicode(HWND hWnd)
 {
-  return FALSE;
+       return (WINBOOL)NtUserCallOneParam((DWORD)hWnd,ONEPARAM_ROUTINE_ISWINDOWUNICODE);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsWindowVisible(HWND hWnd)
 {
-  while (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)
+  while (NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_CHILD)
     {
-      if (!(GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE))
+      if (!(NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_VISIBLE))
        {
          return(FALSE);
        }
       hWnd = GetAncestor(hWnd, GA_PARENT);
     }
-  return(GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE);
+  return(NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_VISIBLE);
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+IsWindowEnabled(
+  HWND hWnd)
+{
+    // AG: I don't know if child windows are affected if the parent is
+    // disabled. I think they stop processing messages but stay appearing
+    // as enabled.
+    
+    return (! (NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_DISABLED));
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 IsZoomed(HWND hWnd)
 {
-  ULONG uStyle = GetWindowLong(hWnd, GWL_STYLE);
-  
-  return (uStyle & WS_MAXIMIZE);
+  return NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_MAXIMIZE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 LockSetForegroundWindow(UINT uLockCode)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 MoveWindow(HWND hWnd,
           int X,
@@ -850,65 +1348,139 @@ MoveWindow(HWND hWnd,
           int nHeight,
           WINBOOL bRepaint)
 {
-    return NtUserMoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
+  return NtUserMoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+AnimateWindow(HWND hwnd,
+             DWORD dwTime,
+             DWORD dwFlags)
+{
+  /* FIXME Add animation code */
+
+  /* If trying to show/hide and it's already   *
+   * shown/hidden or invalid window, fail with *
+   * invalid parameter                         */
+   
+  BOOL visible;
+  visible = IsWindowVisible(hwnd);
+//  if(!IsWindow(hwnd) ||
+//    (visible && !(dwFlags & AW_HIDE)) ||
+//    (!visible && (dwFlags & AW_HIDE)))
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+
+//  ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
+
+  return TRUE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 OpenIcon(HWND hWnd)
 {
-  return FALSE;
+    if (! NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_MINIMIZE)
+    {
+        // Not minimized - error?
+        return FALSE;
+    }
+    
+    if (! SendMessageA(hWnd, WM_QUERYOPEN, 0, 0))
+    {
+        // Window doesn't want to be opened - error?
+        return FALSE;
+    }
+    
+    // Now we need to do the actual opening of the window, which is something
+    // I'll leave to someone more capable :)
+
+    UNIMPLEMENTED;
+    return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 RealChildWindowFromPoint(HWND hwndParent,
                         POINT ptParentClientCoords)
 {
+  UNIMPLEMENTED;
   return (HWND)0;
 }
 
-UINT
-RealGetWindowClass(HWND  hwnd,
-                  LPTSTR pszType,
-                  UINT  cchType)
-{
-  return 0;
-}
-
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetForegroundWindow(HWND hWnd)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetLayeredWindowAttributes(HWND hwnd,
                           COLORREF crKey,
                           BYTE bAlpha,
                           DWORD dwFlags)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 SetParent(HWND hWndChild,
          HWND hWndNewParent)
 {
-  return (HWND)0;
+  return NtUserSetParent(hWndChild, hWndNewParent);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetProcessDefaultLayout(DWORD dwDefaultLayout)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetWindowPlacement(HWND hWnd,
                   CONST WINDOWPLACEMENT *lpwndpl)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetWindowPos(HWND hWnd,
             HWND hWndInsertAfter,
@@ -918,30 +1490,47 @@ SetWindowPos(HWND hWnd,
             int cy,
             UINT uFlags)
 {
-  return FALSE;
+  return NtUserSetWindowPos(hWnd,hWndInsertAfter, X, Y, cx, cy, uFlags);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetWindowTextA(HWND hWnd,
               LPCSTR lpString)
 {
-  return FALSE;
+  return SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)lpString);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetWindowTextW(HWND hWnd,
               LPCWSTR lpString)
 {
-  return FALSE;
+  return SendMessageW(hWnd, WM_SETTEXT, 0, (LPARAM)lpString);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 ShowOwnedPopups(HWND hWnd,
                WINBOOL fShow)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 ShowWindow(HWND hWnd,
           int nCmdShow)
@@ -949,13 +1538,22 @@ ShowWindow(HWND hWnd,
   return NtUserShowWindow(hWnd, nCmdShow);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 ShowWindowAsync(HWND hWnd,
                int nCmdShow)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WORD STDCALL
 TileWindows(HWND hwndParent,
            UINT wHow,
@@ -963,9 +1561,14 @@ TileWindows(HWND hwndParent,
            UINT cKids,
            const HWND *lpKids)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 UpdateLayeredWindow(HWND hwnd,
                    HDC hdcDst,
@@ -977,15 +1580,25 @@ UpdateLayeredWindow(HWND hwnd,
                    BLENDFUNCTION *pblend,
                    DWORD dwFlags)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 HWND STDCALL
 WindowFromPoint(POINT Point)
 {
+  UNIMPLEMENTED;
   return (HWND)0;
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints)
 {
@@ -1003,14 +1616,143 @@ MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints)
       lpPoints[i].x += XMove;
       lpPoints[i].y += YMove;
     }
-  return(MAKELONG(LOWORD(XMove), LOWORD(YMove))); 
+  return(MAKELONG(LOWORD(XMove), LOWORD(YMove)));
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL 
 ScreenToClient(HWND hWnd, LPPOINT lpPoint)
 {
   return(MapWindowPoints(NULL, hWnd, lpPoint, 1));
 }
 
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+ClientToScreen(HWND hWnd, LPPOINT lpPoint)
+{
+    return (MapWindowPoints( hWnd, NULL, lpPoint, 1 ));
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+SetWindowContextHelpId(HWND hwnd,
+          DWORD dwContextHelpId)
+{
+  return (WINBOOL)NtUserCallTwoParam((DWORD)hwnd, (DWORD)dwContextHelpId, 
+                                     TWOPARAM_ROUTINE_SETWNDCONTEXTHLPID);
+}
+
+
+/*
+ * @implemented
+ */
+DWORD
+STDCALL
+GetWindowContextHelpId(HWND hwnd)
+{
+  return NtUserCallOneParam((DWORD)hwnd, ONEPARAM_ROUTINE_GETWNDCONTEXTHLPID);
+}
+
+/*
+ * @implemented
+ */
+DWORD
+STDCALL
+InternalGetWindowText(HWND hWnd, LPWSTR lpString, int nMaxCount)
+{
+  DWORD res = 0;
+  LPWSTR lps = NULL;
+  if(lpString && (nMaxCount > 0))
+  {
+    lps = RtlAllocateHeap(RtlGetProcessHeap(), 0, nMaxCount * sizeof(WCHAR));
+    if(!lps)
+    {
+      SetLastError(ERROR_OUTOFMEMORY);
+      return 0;
+    }
+  }
+  
+  res = NtUserInternalGetWindowText(hWnd, lps, nMaxCount);
+  
+  if(lps)
+  {
+    RtlCopyMemory(lpString, lps, res * sizeof(WCHAR));
+    lpString[res] = (WCHAR)"\0";  /* null-terminate the string */
+    
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lps);
+  }
+  
+  return res;
+}
+
+/*
+ * @unimplemented
+ */
+WINBOOL
+STDCALL
+IsHungAppWindow(HWND hwnd)
+{
+  /* FIXME: ReactOS doesnt identify hung app windows yet */
+  return FALSE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+SetLastErrorEx(DWORD dwErrCode, DWORD dwType)
+{
+  SetLastError(dwErrCode);
+}
+
+/*
+ * @implemented
+ */
+WINBOOL
+STDCALL
+SetSystemMenu (
+  HWND hwnd, 
+  HMENU hMenu)
+{
+  if(!hwnd)
+  {
+    SetLastError(ERROR_INVALID_WINDOW_HANDLE);
+    return FALSE;
+  }
+  if(!hMenu)
+  {
+    SetLastError(ERROR_INVALID_MENU_HANDLE);
+    return FALSE;
+  }
+  return NtUserSetSystemMenu(hwnd, hMenu);
+}
+
+/*
+ * @implemented
+ */
+HMENU
+STDCALL
+GetSystemMenu(
+  HWND hWnd,
+  WINBOOL bRevert)
+{
+  if(!hWnd)
+  {
+    SetLastError(ERROR_INVALID_WINDOW_HANDLE);
+    return (HMENU)0;
+  }
+  return NtUserGetSystemMenu(hWnd, bRevert);
+}
+
 /* EOF */