fix bug 838 (Sol.exe is missing it's menubar)
[reactos.git] / reactos / subsys / win32k / ntuser / class.c
index bc9e655..94e4cc0 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: class.c,v 1.23 2003/08/06 16:47:35 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  */
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <win32k/win32k.h>
-#include <napi/win32.h>
-#include <include/class.h>
-#include <include/error.h>
-#include <include/winsta.h>
-#include <include/object.h>
-#include <include/guicheck.h>
-#include <include/window.h>
+#include <w32k.h>
 
 #define NDEBUG
 #include <debug.h>
 NTSTATUS FASTCALL
 InitClassImpl(VOID)
 {
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
 }
 
 NTSTATUS FASTCALL
 CleanupClassImpl(VOID)
 {
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
 }
 
 
-NTSTATUS FASTCALL
-ClassReferenceClassByAtom(PWNDCLASS_OBJECT* Class,
-                         RTL_ATOM Atom)
+inline VOID FASTCALL 
+ClassDerefObject(PWNDCLASS_OBJECT Class)
 {
-  PWNDCLASS_OBJECT Current;
-  PLIST_ENTRY CurrentEntry;
-  PW32PROCESS Process = PsGetWin32Process();
-  
-  ExAcquireFastMutexUnsafe (&Process->ClassListLock);
-  CurrentEntry = Process->ClassListHead.Flink;
-  while (CurrentEntry != &Process->ClassListHead)
-    {
-    Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry);
-      
-       if (Current->lpszClassName == (PUNICODE_STRING)(ULONG)Atom)
-       {
-       *Class = Current;
-       ObmReferenceObject(Current);
-       ExReleaseFastMutexUnsafe (&Process->ClassListLock);
-       return(STATUS_SUCCESS);
-       }
-
-       CurrentEntry = CurrentEntry->Flink;
-    }
-  ExReleaseFastMutexUnsafe (&Process->ClassListLock);
-  
-  return(STATUS_NOT_FOUND);
+   ASSERT(Class->refs >= 1);
+   Class->refs--;   
 }
 
-NTSTATUS STDCALL
-ClassReferenceClassByName(PWNDCLASS_OBJECT *Class,
-                         PWSTR ClassName)
+
+inline VOID FASTCALL 
+ClassRefObject(PWNDCLASS_OBJECT Class)
 {
-  PWINSTATION_OBJECT WinStaObject;
-  NTSTATUS Status;
-  RTL_ATOM ClassAtom;
-
-  if (!ClassName)
-    {
-      return(STATUS_INVALID_PARAMETER);
-    }
-
-  Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
-                                      KernelMode,
-                                      0,
-                                      &WinStaObject);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT("Validation of window station handle (0x%X) failed\n",
-            PROCESS_WINDOW_STATION());
-      return(STATUS_UNSUCCESSFUL);
-    }
-
-  Status  = RtlLookupAtomInAtomTable(WinStaObject->AtomTable,
-                                    ClassName,
-                                    &ClassAtom);
-
-  if (!NT_SUCCESS(Status))
-    {
-      ObDereferenceObject(WinStaObject);  
-      return(Status);
-    }
-  Status = ClassReferenceClassByAtom(Class,
-                                    ClassAtom);
-  
-  ObDereferenceObject(WinStaObject);  
-  return(Status);
+   ASSERT(Class->refs >= 0);
+   Class->refs++;
 }
 
-NTSTATUS FASTCALL
-ClassReferenceClassByNameOrAtom(PWNDCLASS_OBJECT *Class,
-                               LPWSTR ClassNameOrAtom)
+
+VOID FASTCALL DestroyClass(PWNDCLASS_OBJECT Class)
 {
-  NTSTATUS Status;
-
-  if (IS_ATOM(ClassNameOrAtom))
-    {
-      Status = ClassReferenceClassByAtom(Class, 
-                                 (RTL_ATOM)((ULONG_PTR)ClassNameOrAtom));
-  }
-  else
-    {
-      Status = ClassReferenceClassByName(Class, 
-                                        ClassNameOrAtom);
-    }
-
-  if (!NT_SUCCESS(Status))
-    {
-      SetLastNtError(Status);
-    }
-  
-  return(Status);
+   ASSERT(Class->refs == 0);
+   
+   RemoveEntryList(&Class->ListEntry);
+   if (Class->hMenu)
+      UserDestroyMenu(Class->hMenu);
+   RtlDeleteAtomFromAtomTable(gAtomTable, Class->Atom);
+   ExFreePool(Class);
 }
 
-DWORD STDCALL
-NtUserGetClassInfo(IN LPWSTR ClassName,
-                  IN ULONG InfoClass,
-                  OUT PVOID Info,
-                  IN ULONG InfoLength,
-                  OUT PULONG ReturnedLength)
+
+/* clean all process classes. all process windows must cleaned first!! */
+void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
 {
-  UNIMPLEMENTED;
-    
-  return(0);
+   PWNDCLASS_OBJECT Class;
+
+   while (!IsListEmpty(&Process->ClassList))
+   {
+      Class = CONTAINING_RECORD(RemoveHeadList(&Process->ClassList), WNDCLASS_OBJECT, ListEntry);
+      DestroyClass(Class);
+   }
 }
 
-ULONG FASTCALL
-W32kGetClassName(struct _WINDOW_OBJECT *WindowObject,
-                  LPWSTR lpClassName,
-                  int nMaxCount)
+
+
+
+PWNDCLASS_OBJECT FASTCALL
+ClassGetClassByAtom(RTL_ATOM Atom, HINSTANCE hInstance)
 {
-       int length;
-       LPCWSTR name;
-       if (IS_ATOM(WindowObject->Class->lpszClassName))
-       {
-               /* FIXME find the string from the atom */
-               name = L"\0";
-               length = wcslen(name);
-       }
-       else
-       {
-               name = WindowObject->Class->lpszClassName->Buffer;
-               length = WindowObject->Class->lpszClassName->Length / sizeof(WCHAR);
-       }
-       if (length > nMaxCount)
-       {
-               length = nMaxCount;
-       }
-       *(lpClassName+length) = 0;
-       wcsncpy(lpClassName,name,length);
-       return length;
+   PWNDCLASS_OBJECT Class;
+   PW32PROCESS Process = PsGetWin32Process();
+
+   LIST_FOR_EACH(Class, &Process->ClassList, WNDCLASS_OBJECT, ListEntry)
+   {
+      if (Class->Atom != Atom) continue;
+
+      if (!hInstance || Class->Global || Class->hInstance == hInstance) return Class;
+   }
+   
+   return NULL;
 }
 
-DWORD STDCALL
-NtUserGetClassName(HWND hWnd,
-                  LPWSTR lpClassName,
-                  int nMaxCount)
+
+PWNDCLASS_OBJECT FASTCALL
+ClassGetClassByName(LPCWSTR ClassName, HINSTANCE hInstance)
+{
+   NTSTATUS Status;
+   RTL_ATOM Atom;
+
+   if (!ClassName || !PsGetWin32Thread()->Desktop)
+      return FALSE;
+
+   Status = RtlLookupAtomInAtomTable(
+               gAtomTable,
+               (LPWSTR)ClassName,
+               &Atom);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("Failed to lookup class atom!\n");
+      return FALSE;
+   }
+
+   return ClassGetClassByAtom(Atom, hInstance);
+}
+
+
+PWNDCLASS_OBJECT FASTCALL
+ClassGetClassByNameOrAtom(LPCWSTR ClassNameOrAtom, HINSTANCE hInstance)
 {
-  PWINDOW_OBJECT WindowObject;
-  LONG Ret;
-
-  WindowObject = W32kGetWindowObject(hWnd);
-  if (WindowObject == NULL)
-    {
-      return(0);
-    }
-  Ret = W32kGetClassName(WindowObject, lpClassName, nMaxCount);
-  W32kReleaseWindowObject(WindowObject);
-  return(Ret);
+   if (!ClassNameOrAtom) return NULL;
+   
+   if (IS_ATOM(ClassNameOrAtom))
+      return ClassGetClassByAtom((RTL_ATOM)((ULONG_PTR)ClassNameOrAtom), hInstance);
+   else
+      return ClassGetClassByName(ClassNameOrAtom, hInstance);
 }
 
-DWORD STDCALL
-NtUserGetWOWClass(DWORD Unknown0,
-                 DWORD Unknown1)
+
+static
+BOOL FASTCALL
+IntRegisterClass(
+   CONST WNDCLASSEXW *lpwcx,
+   DWORD Flags,
+   WNDPROC wpExtra,
+   PUNICODE_STRING MenuName,
+   RTL_ATOM Atom,
+   HMENU hMenu)
 {
-  UNIMPLEMENTED;
-  
-  return(0);
+   PWNDCLASS_OBJECT Class;
+   ULONG  objectSize;
+   BOOL Global;
+
+   ASSERT(lpwcx);
+   ASSERT(Atom);
+   ASSERT(lpwcx->hInstance);
+
+   Global = (Flags & REGISTERCLASS_SYSTEM) || (lpwcx->style & CS_GLOBALCLASS);
+
+   /* Check for double registration of the class. */
+   Class = ClassGetClassByAtom(Atom, lpwcx->hInstance);
+   if (Class && Global == Class->Global)
+   {
+      /* can max have one class of each type (global/local) */
+      SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
+      return(FALSE);
+   }
+
+   objectSize = sizeof(WNDCLASS_OBJECT) + lpwcx->cbClsExtra;
+   
+   //FIXME: allocate in session heap (or possibly desktop heap)
+   Class = ExAllocatePool(PagedPool, objectSize);
+   if (!Class)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return(FALSE);
+   }
+   RtlZeroMemory(Class, objectSize);
+
+   Class->cbSize = lpwcx->cbSize;
+   Class->style = lpwcx->style;
+   Class->cbClsExtra = lpwcx->cbClsExtra;
+   Class->cbWndExtra = lpwcx->cbWndExtra;
+   Class->hInstance = lpwcx->hInstance;
+   Class->hIcon = lpwcx->hIcon;
+   Class->hCursor = lpwcx->hCursor;
+   Class->hMenu = hMenu;
+   Class->hbrBackground = lpwcx->hbrBackground;
+   Class->Unicode = !(Flags & REGISTERCLASS_ANSI);
+   Class->Global = Global;
+   Class->hIconSm = lpwcx->hIconSm;
+   Class->Atom = Atom;
+   
+   if (wpExtra == NULL)
+   {
+      if (Flags & REGISTERCLASS_ANSI)
+      {
+         Class->lpfnWndProcA = lpwcx->lpfnWndProc;
+         Class->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
+      }
+      else
+      {
+         Class->lpfnWndProcW = lpwcx->lpfnWndProc;
+         Class->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
+      }
+   }
+   else
+   {
+      if (Flags & REGISTERCLASS_ANSI)
+      {
+         Class->lpfnWndProcA = lpwcx->lpfnWndProc;
+         Class->lpfnWndProcW = wpExtra;
+      }
+      else
+      {
+         Class->lpfnWndProcW = lpwcx->lpfnWndProc;
+         Class->lpfnWndProcA = wpExtra;
+      }
+   }
+   
+   if (MenuName->Length == 0)
+   {
+      Class->lpszMenuName.Length =
+         Class->lpszMenuName.MaximumLength = 0;
+      Class->lpszMenuName.Buffer = MenuName->Buffer;
+   }
+   else
+   {
+      Class->lpszMenuName.Length =
+         Class->lpszMenuName.MaximumLength = MenuName->MaximumLength;
+      Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Class->lpszMenuName.MaximumLength, TAG_STRING);
+      RtlCopyUnicodeString(&Class->lpszMenuName, MenuName);
+   }
+   
+   /* Extra class data */
+   if (Class->cbClsExtra)
+      Class->ExtraData = (PCHAR)(Class + 1);
+
+   if (Global)
+   {
+      /* global classes go last (incl. system classes) */
+      InsertTailList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
+   }
+   else
+   {
+      /* local classes have priority so we put them first */
+      InsertHeadList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
+   }
+   
+   return TRUE;
 }
 
-PWNDCLASS_OBJECT FASTCALL
-W32kCreateClass(CONST WNDCLASSEXW *lpwcx,
-                BOOL bUnicodeClass,
-                RTL_ATOM Atom)
+
+ULONG FASTCALL
+IntGetClassLong(PWINDOW_OBJECT Window, ULONG Offset, BOOL Ansi)
 {
-       PWNDCLASS_OBJECT ClassObject;
-       WORD  objectSize;
-       objectSize = sizeof(WNDCLASS_OBJECT);
-       ClassObject = ObmCreateObject(NULL, NULL, otClass, objectSize);
-       if (ClassObject == 0)
-       {          
-               return(NULL);
-       }
-
-       ClassObject->cbSize = lpwcx->cbSize;
-       ClassObject->style = lpwcx->style;
-       ClassObject->cbClsExtra = lpwcx->cbClsExtra;
-       ClassObject->cbWndExtra = lpwcx->cbWndExtra;
-       ClassObject->hInstance = lpwcx->hInstance;
-       ClassObject->hIcon = lpwcx->hIcon;
-       ClassObject->hCursor = lpwcx->hCursor;
-       ClassObject->hbrBackground = lpwcx->hbrBackground;
-       ClassObject->Unicode = bUnicodeClass;
-       ClassObject->hIconSm = lpwcx->hIconSm;
-       ClassObject->lpszClassName = (PUNICODE_STRING)(ULONG)Atom;
-       if (bUnicodeClass)
-       {
-               ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
-               ClassObject->lpfnWndProcA = (WNDPROC)0xCCCCCCCC;
-       }
-       else
-       {
-               ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
-               ClassObject->lpfnWndProcW = (WNDPROC)0xCCCCCCCC;
-       }
-       if (HIWORD(lpwcx->lpszMenuName) == 0)
-       {
-               ClassObject->lpszMenuName = (PUNICODE_STRING)lpwcx->lpszMenuName;
-       }
-       else
-       {
-               RtlCreateUnicodeString(ClassObject->lpszMenuName,(LPWSTR)lpwcx->lpszMenuName);
-       }
-       return(ClassObject);
+   LONG Ret;
+
+   if ((int)Offset >= 0)
+   {
+      DPRINT("GetClassLong(%x, %d)\n", Window->hSelf, Offset);
+      if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return 0;
+      }
+      Ret = *((LONG *)(Window->Class->ExtraData + Offset));
+      DPRINT("Result: %x\n", Ret);
+      return Ret;
+   }
+
+   switch (Offset)
+   {
+      case GCL_CBWNDEXTRA:
+         Ret = Window->Class->cbWndExtra;
+         break;
+      case GCL_CBCLSEXTRA:
+         Ret = Window->Class->cbClsExtra;
+         break;
+      case GCL_HBRBACKGROUND:
+         Ret = (ULONG)Window->Class->hbrBackground;
+         break;
+      case GCL_HCURSOR:
+         Ret = (ULONG)Window->Class->hCursor;
+         break;
+      case GCL_HICON:
+         Ret = (ULONG)Window->Class->hIcon;
+         break;
+      case GCL_HICONSM:
+         Ret = (ULONG)Window->Class->hIconSm;
+         break;
+      case GCL_HMODULE:
+         Ret = (ULONG)Window->Class->hInstance;
+         break;
+      case GCL_MENUNAME:
+         Ret = (ULONG)Window->Class->lpszMenuName.Buffer;
+         break;
+      case GCL_STYLE:
+         Ret = Window->Class->style;
+         break;
+      case GCL_WNDPROC:
+         if (Ansi)
+         {
+            Ret = (ULONG)Window->Class->lpfnWndProcA;
+         }
+         else
+         {
+            Ret = (ULONG)Window->Class->lpfnWndProcW;
+         }
+         break;
+      case GCW_ATOM:
+         Ret = Window->Class->Atom;
+         break;
+      default:
+         Ret = 0;
+         break;
+   }
+   return(Ret);
 }
 
+static
+void FASTCALL
+co_IntSetClassLong(PWINDOW_OBJECT Window, ULONG Offset, LONG dwNewLong, BOOL Ansi)
+{
+   ASSERT_REFS_CO(Window);
+
+   if ((int)Offset >= 0)
+   {
+      DPRINT("SetClassLong(%x, %d, %x)\n", Window->hSelf, Offset, dwNewLong);
+      if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return;
+      }
+      *((LONG *)(Window->Class->ExtraData + Offset)) = dwNewLong;
+      return;
+   }
+
+   switch (Offset)
+   {
+      case GCL_CBWNDEXTRA:
+         Window->Class->cbWndExtra = dwNewLong;
+         break;
+      case GCL_CBCLSEXTRA:
+         Window->Class->cbClsExtra = dwNewLong;
+         break;
+      case GCL_HBRBACKGROUND:
+         Window->Class->hbrBackground = (HBRUSH)dwNewLong;
+         break;
+      case GCL_HCURSOR:
+         Window->Class->hCursor = (HCURSOR)dwNewLong;
+         break;
+      case GCL_HICON:
+         Window->Class->hIcon = (HICON)dwNewLong;
+
+         if (!IntGetOwner(Window) && !IntGetParent(Window))
+         {
+            co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) Window->hSelf);
+         }
+         break;
+      case GCL_HICONSM:
+         Window->Class->hIconSm = (HICON)dwNewLong;
+         break;
+      case GCL_HMODULE:
+         Window->Class->hInstance = (HINSTANCE)dwNewLong;
+         break;
+      case GCL_MENUNAME:
+         if (Window->Class->lpszMenuName.MaximumLength)
+            RtlFreeUnicodeString(&Window->Class->lpszMenuName);
+         if (!IS_INTRESOURCE(dwNewLong))
+         {
+            Window->Class->lpszMenuName.Length =
+               Window->Class->lpszMenuName.MaximumLength = ((PUNICODE_STRING)dwNewLong)->MaximumLength;
+            Window->Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Window->Class->lpszMenuName.MaximumLength, TAG_STRING);
+            RtlCopyUnicodeString(&Window->Class->lpszMenuName, (PUNICODE_STRING)dwNewLong);
+         }
+         else
+         {
+            Window->Class->lpszMenuName.Length =
+               Window->Class->lpszMenuName.MaximumLength = 0;
+            Window->Class->lpszMenuName.Buffer = (LPWSTR)dwNewLong;
+         }
+         break;
+      case GCL_STYLE:
+         Window->Class->style = dwNewLong;
+         break;
+      case GCL_WNDPROC:
+         if (Ansi)
+         {
+            Window->Class->lpfnWndProcA = (WNDPROC)dwNewLong;
+            Window->Class->lpfnWndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,FALSE);
+            Window->Class->Unicode = FALSE;
+         }
+         else
+         {
+            Window->Class->lpfnWndProcW = (WNDPROC)dwNewLong;
+            Window->Class->lpfnWndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,TRUE);
+            Window->Class->Unicode = TRUE;
+         }
+         break;
+   }
+}
+/* SYSCALLS *****************************************************************/
+
+
 RTL_ATOM STDCALL
-NtUserRegisterClassExWOW(CONST WNDCLASSEXW *lpwcx,
-                        BOOL bUnicodeClass,
-                        DWORD Unknown3,
-                        DWORD Unknown4,
-                        DWORD Unknown5)
+NtUserRegisterClassExWOW(
+   CONST WNDCLASSEXW* lpwcx,
+   PUNICODE_STRING ClassName,
+   PUNICODE_STRING ClassNameCopy,//huhuhuhu???
+   PUNICODE_STRING MenuName,
+   WNDPROC wpExtra,
+   DWORD Flags,
+   DWORD Unknown7,
+   HMENU hMenu)
+
 /*
  * FUNCTION:
  *   Registers a new class with the window manager
  * ARGUMENTS:
- *   lpcxw          = Win32 extended window class structure (unicode)
- *   bUnicodeClass = Wether to send ANSI or unicode strings
+ *   lpwcx          = Win32 extended window class structure
+ *   bUnicodeClass = Whether to send ANSI or unicode strings
  *                   to window procedures
+ *   wpExtra       = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
  * RETURNS:
  *   Atom identifying the new class
  */
 {
-       PWINSTATION_OBJECT WinStaObject;
-       PWNDCLASS_OBJECT ClassObject;
-       NTSTATUS Status;
-       RTL_ATOM Atom;
-       DPRINT("About to open window station handle (0x%X)\n", 
-       PROCESS_WINDOW_STATION());
-       Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
-                                               KernelMode,
-                                               0,
-                                               &WinStaObject);
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("Validation of window station handle (0x%X) failed\n",
-               PROCESS_WINDOW_STATION());
-               return((RTL_ATOM)0);
-       }
-       if (!IS_ATOM(lpwcx->lpszClassName))
-    {
-               Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable,
-                                       (LPWSTR)lpwcx->lpszClassName,
-                                       &Atom);
-               if (!NT_SUCCESS(Status))
-               {
-                       ObDereferenceObject(WinStaObject);
-                       DPRINT("Failed adding class name (%wS) to atom table\n",
-                               lpwcx->lpszClassName);
-                       SetLastNtError(Status);      
-                       return((RTL_ATOM)0);
-               }
-       }
-       else
-       {
-               Atom = (RTL_ATOM)(ULONG)lpwcx->lpszClassName;
-       }
-       ClassObject = W32kCreateClass(lpwcx, bUnicodeClass, Atom);
-       if (ClassObject == NULL)
-    {
-               if (!IS_ATOM(lpwcx->lpszClassName))
-               {
-                       RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Atom);
-               }
-               ObDereferenceObject(WinStaObject);
-               DPRINT("Failed creating window class object\n");
-               SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-               return((RTL_ATOM)0);
-       }
-       ExAcquireFastMutex(&PsGetWin32Process()->ClassListLock);
-       InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry);
-       ExReleaseFastMutex(&PsGetWin32Process()->ClassListLock);
-       ObDereferenceObject(WinStaObject);
-       return(Atom);
+   WNDCLASSEXW SafeClass;
+   NTSTATUS Status;
+   RTL_ATOM Atom;
+   DECLARE_RETURN(RTL_ATOM);
+
+   DPRINT("Enter NtUserRegisterClassExWOW\n");
+   UserEnterExclusive();
+
+   if (!lpwcx)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN( (RTL_ATOM)0);
+   }
+
+   if (Flags & ~REGISTERCLASS_ALL)
+   {
+      SetLastWin32Error(ERROR_INVALID_FLAGS);
+      RETURN( (RTL_ATOM)0);
+   }
+
+   Status = MmCopyFromCaller(&SafeClass, lpwcx, sizeof(WNDCLASSEXW));
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN( (RTL_ATOM)0);
+   }
+
+   /* Deny negative sizes */
+   if (lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN( (RTL_ATOM)0);
+   }
+
+   if (!lpwcx->hInstance)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN( (RTL_ATOM)0);
+   }
+
+   //FIXME: make ClassName ptr the atom, not buffer
+   if (ClassName->Length > 0)
+   {
+      DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer);
+      /* FIXME - Safely copy/verify the buffer first!!! */
+      Status = RtlAddAtomToAtomTable(gAtomTable,
+                                     ClassName->Buffer,
+                                     &Atom);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT1("Failed adding class name (%S) to atom table\n",
+                 ClassName->Buffer);
+         SetLastNtError(Status);
+         RETURN((RTL_ATOM)0);
+      }
+   }
+   else
+   {
+      Atom = (RTL_ATOM)(ULONG)ClassName->Buffer;
+   }
+
+   if (!Atom)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN(0);
+   }
+
+   if (!IntRegisterClass(&SafeClass, Flags, wpExtra, MenuName, Atom, hMenu))
+   {
+      if (ClassName->Length)
+      {
+         RtlDeleteAtomFromAtomTable(gAtomTable, Atom);
+      }
+      DPRINT("Failed creating window class object\n");
+      RETURN((RTL_ATOM)0);
+   }
+
+   RETURN(Atom);
+
+CLEANUP:
+   DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
-ULONG FASTCALL
-W32kGetClassLong(struct _WINDOW_OBJECT *WindowObject, ULONG Offset, BOOL Ansi)
-{
-  LONG Ret;
-  switch (Offset)
-    {
-    case GCL_CBWNDEXTRA:
-      Ret = WindowObject->Class->cbWndExtra;
-      break;
-    case GCL_CBCLSEXTRA:
-      Ret = WindowObject->Class->cbClsExtra;
-      break;
-    case GCL_HBRBACKGROUND:
-      Ret = (ULONG)WindowObject->Class->hbrBackground;
-      break;
-    case GCL_HCURSOR:
-      Ret = (ULONG)WindowObject->Class->hCursor;
-      break;
-    case GCL_HICON:
-      Ret = (ULONG)WindowObject->Class->hIcon;
-      break;
-    case GCL_HICONSM:
-      Ret = (ULONG)WindowObject->Class->hIconSm;
-      break;
-    case GCL_HMODULE:
-      Ret = (ULONG)WindowObject->Class->hInstance;
-      break;
-    /*case GCL_MENUNAME:
-         if (Ansi)
-         {
-               Ret = (ULONG)WindowObject->Class->ClassA.lpszMenuName;
-         }
-         else
-         {
-               Ret = (ULONG)WindowObject->Class->ClassW.lpszMenuName;
-         }
-      break;*/
-    case GCL_STYLE:
-      Ret = WindowObject->Class->style;
-      break;
-    case GCL_WNDPROC:
-         if (WindowObject->Unicode)
-         {
-               Ret = (ULONG)WindowObject->Class->lpfnWndProcW;
-         }
-         else
-         {
-               Ret = (ULONG)WindowObject->Class->lpfnWndProcA;
-         }
-      break;
-    default:
-      Ret = 0;
-      break;
-    }
-  return(Ret);
-}
+
 
 DWORD STDCALL
 NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
 {
-  PWINDOW_OBJECT WindowObject;
-  LONG Ret;
-
-  WindowObject = W32kGetWindowObject(hWnd);
-  if (WindowObject == NULL)
-    {
-      return(0);
-    }
-  Ret = W32kGetClassLong(WindowObject, Offset, Ansi);
-  W32kReleaseWindowObject(WindowObject);
-  return(Ret);
-}
+   PWINDOW_OBJECT Window;
+   DECLARE_RETURN(DWORD);
 
-void FASTCALL
-W32kSetClassLong(PWINDOW_OBJECT WindowObject, ULONG Offset, LONG dwNewLong, BOOL Ansi)
-{
-  switch (Offset)
-    {
-    case GCL_CBWNDEXTRA:
-      WindowObject->Class->cbWndExtra = dwNewLong;
-      break;
-    case GCL_CBCLSEXTRA:
-      WindowObject->Class->cbClsExtra = dwNewLong;
-      break;
-    case GCL_HBRBACKGROUND:
-      WindowObject->Class->hbrBackground = (HBRUSH)dwNewLong;
-      break;
-    case GCL_HCURSOR:
-      WindowObject->Class->hCursor = (HCURSOR)dwNewLong;
-      break;
-    case GCL_HICON:
-      WindowObject->Class->hIcon = (HICON)dwNewLong;
-      break;
-    case GCL_HICONSM:
-      WindowObject->Class->hIconSm = (HICON)dwNewLong;
-      break;
-    case GCL_HMODULE:
-      WindowObject->Class->hInstance = (HINSTANCE)dwNewLong;
-      break;
-    /*case GCL_MENUNAME:
-      WindowObject->Class->Class.lpszMenuName = (LPCWSTR)dwNewLong;
-      break;*/
-    case GCL_STYLE:
-      WindowObject->Class->style = dwNewLong;
-      break;
-    /*case GCL_WNDPROC:
-      WindowObject->Class->Class.lpfnWndProc = (WNDPROC)dwNewLong;
-      break;*/
-    }
+   DPRINT("Enter NtUserGetClassLong\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(0);
+   }
+
+   RETURN(IntGetClassLong(Window, Offset, Ansi));
+
+CLEANUP:
+   DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
+
+
 DWORD STDCALL
 NtUserSetClassLong(HWND hWnd,
-                  DWORD Offset,
-                  LONG dwNewLong,
-                  BOOL Ansi)
+                   DWORD Offset,
+                   LONG dwNewLong,
+                   BOOL Ansi)
 {
-  PWINDOW_OBJECT WindowObject;
-  LONG Ret;
-
-  WindowObject = W32kGetWindowObject(hWnd);
-  if (WindowObject == NULL)
-    {
-      return(0);
-    }
-  Ret = W32kGetClassLong(WindowObject, Offset, Ansi);
-  W32kSetClassLong(WindowObject, Offset, dwNewLong, Ansi);
-  W32kReleaseWindowObject(WindowObject);
-  return(Ret);
+   PWINDOW_OBJECT Window;
+   LONG Ret;
+   USER_REFERENCE_ENTRY Ref;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter NtUserSetClassLong\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(0);
+   }
+
+   UserRefObjectCo(Window, &Ref);
+
+   Ret = IntGetClassLong(Window, Offset, Ansi);
+   co_IntSetClassLong(Window, Offset, dwNewLong, Ansi);
+
+   UserDerefObjectCo(Window);
+
+   RETURN(Ret);
+
+CLEANUP:
+   DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 DWORD STDCALL
 NtUserSetClassWord(DWORD Unknown0,
-                  DWORD Unknown1,
-                  DWORD Unknown2)
+                   DWORD Unknown1,
+                   DWORD Unknown2)
 {
-  UNIMPLEMENTED;
+   UNIMPLEMENTED;
+   return(0);
+}
 
-  return(0);
+BOOL STDCALL
+NtUserUnregisterClass(
+   LPCWSTR ClassNameOrAtom,
+   HINSTANCE hInstance, /* can be 0 */
+   DWORD Unknown)
+{
+   PWNDCLASS_OBJECT Class;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom);
+   UserEnterExclusive();
+
+   if (!ClassNameOrAtom)
+   {
+      SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
+      RETURN(FALSE);
+   }
+
+   if (!(Class = ClassGetClassByNameOrAtom(ClassNameOrAtom, hInstance)))
+   {
+      SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
+      RETURN(FALSE);
+   }
+
+   if (Class->refs)
+   {
+      /* NOTE: the class will not be freed when its refs become 0 ie. no more
+       * windows are using it. I dunno why that is but its how Windows does it (and Wine).
+       * The class will hang around until the process exit. -Gunnar
+       */
+      SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
+      RETURN(FALSE);
+   }
+
+   DestroyClass(Class);
+   
+   RETURN(TRUE);
+
+CLEANUP:
+   DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
+/* NOTE: for system classes hInstance is not NULL here, but User32Instance */
+DWORD STDCALL
+NtUserGetClassInfo(
+   HINSTANCE hInstance,
+   LPCWSTR lpClassName,
+   LPWNDCLASSEXW lpWndClassEx,
+   BOOL Ansi,
+   DWORD unknown3)
+{
+   PWNDCLASS_OBJECT Class;
+   RTL_ATOM Atom;
+   DECLARE_RETURN(DWORD);
+
+   if (IS_ATOM(lpClassName))
+      DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName, hInstance);
+   else
+      DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName, hInstance);
+
+   UserEnterExclusive();
+
+   if (!hInstance)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN(0);
+   }
+
+   if (!(Class = ClassGetClassByNameOrAtom(lpClassName, hInstance)))
+   {
+      SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
+      RETURN(0);
+   }
+
+   lpWndClassEx->cbSize = sizeof(WNDCLASSEXW);
+   lpWndClassEx->style = Class->style;
+   if (Ansi)
+      lpWndClassEx->lpfnWndProc = Class->lpfnWndProcA;
+   else
+      lpWndClassEx->lpfnWndProc = Class->lpfnWndProcW;
+   lpWndClassEx->cbClsExtra = Class->cbClsExtra;
+   lpWndClassEx->cbWndExtra = Class->cbWndExtra;
+   /* This is not typo, we're really not going to use Class->hInstance here. */
+   /* Well, i think its wrong so i changed it -Gunnar */
+   lpWndClassEx->hInstance = Class->hInstance;
+   lpWndClassEx->hIcon = Class->hIcon;
+   lpWndClassEx->hCursor = Class->hCursor;
+   lpWndClassEx->hbrBackground = Class->hbrBackground;
+   if (Class->lpszMenuName.MaximumLength)
+      RtlCopyUnicodeString((PUNICODE_STRING)lpWndClassEx->lpszMenuName, &Class->lpszMenuName);
+   else
+      lpWndClassEx->lpszMenuName = Class->lpszMenuName.Buffer;
+   lpWndClassEx->lpszClassName = lpClassName;
+   lpWndClassEx->hIconSm = Class->hIconSm;
+   Atom = Class->Atom;
+
+   RETURN(Atom);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+
 DWORD STDCALL
-NtUserUnregisterClass(DWORD Unknown0,
-                     DWORD Unknown1,
-                     DWORD Unknown2)
+NtUserGetClassName (
+   HWND hWnd,
+   LPWSTR lpClassName,
+   ULONG nMaxCount /* in TCHARS */
+   )
 {
-  UNIMPLEMENTED;
+   PWINDOW_OBJECT Window;
+   DECLARE_RETURN(DWORD);
+   NTSTATUS Status;
+
+   UserEnterShared();
+   DPRINT("Enter NtUserGetClassName\n");   
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(0);
+   }
+
+   nMaxCount *= sizeof(WCHAR);
+   
+   //FIXME: wrap in SEH to protect lpClassName access
+   Status = RtlQueryAtomInAtomTable(gAtomTable,
+                                    Window->Class->Atom, NULL, NULL,
+                                    lpClassName, &nMaxCount);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN(0);
+   }
+
+   RETURN(nMaxCount / sizeof(WCHAR));
 
-  return(0);
+CLEANUP:
+   DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
+DWORD STDCALL
+NtUserGetWOWClass(DWORD Unknown0,
+                  DWORD Unknown1)
+{
+   UNIMPLEMENTED;
+   return(0);
+}
+
+
 /* EOF */