fix bug 838 (Sol.exe is missing it's menubar)
[reactos.git] / reactos / lib / user32 / windows / class.c
index bb7c5d9..935286c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: class.c,v 1.9 2001/06/12 17:50:27 chorns Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
  * UPDATE HISTORY:
  *      09-05-2001  CSH  Created
  */
-#include <windows.h>
-#include <user32.h>
-#include <debug.h>
 
+#include <user32.h>
 
-WINBOOL
-STDCALL
-GetClassInfoA(
-  HINSTANCE hInstance,
-  LPCSTR lpClassName,
-  LPWNDCLASS lpWndClass)
+static BOOL GetClassInfoExCommon(
+    HINSTANCE hInst,
+    LPCWSTR lpszClass,
+    LPWNDCLASSEXW lpwcx,
+    BOOL unicode)
 {
-  return FALSE;
+  LPWSTR str;
+  UNICODE_STRING str2, str3;
+  WNDCLASSEXW w;
+  BOOL retval;
+  NTSTATUS Status;
+
+  if ( !lpszClass || !lpwcx )
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+
+  if(IS_ATOM(lpszClass))
+    str = (LPWSTR)lpszClass;
+  else
+  {
+    extern BOOL ControlsInitialized;
+
+    if (unicode)
+    {
+        str = HEAP_strdupW ( lpszClass, wcslen(lpszClass) );
+
+        if ( !str )
+        {
+          SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+          return FALSE;
+        }
+    }
+
+    else
+    {
+        Status = HEAP_strdupAtoW(&str, (LPCSTR)lpszClass, NULL);
+
+        if (! NT_SUCCESS(Status))
+        {
+            SetLastError(RtlNtStatusToDosError(Status));
+            return FALSE;
+        }
+    }
+
+    /* Register built-in controls if not already done */
+    if ( !ControlsInitialized )
+    {
+      ControlsInitialized = ControlsInit(str);
+    }
+  }
+
+  str2.Length = str3.Length = 0;
+  str2.MaximumLength = str3.MaximumLength = 255;
+  str2.Buffer = (PWSTR)HEAP_alloc ( str2.MaximumLength * sizeof(WCHAR) );
+  if ( !str2.Buffer )
+  {
+    SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+    if ( !IS_ATOM(str) )
+      HEAP_free ( str );
+    return FALSE;
+  }
+
+  str3.Buffer = (PWSTR)HEAP_alloc ( str3.MaximumLength * sizeof(WCHAR) );
+  if ( !str3.Buffer )
+  {
+    SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+    HEAP_free ( str2.Buffer );
+    if ( !IS_ATOM(str) )
+      HEAP_free ( str );
+    return FALSE;
+  }
+
+  w.lpszMenuName = (LPCWSTR)&str2;
+  w.lpszClassName = (LPCWSTR)&str3;
+  
+  /* get info about system classes? */
+  if (!hInst) hInst = User32Instance;
+  
+  retval = (BOOL)NtUserGetClassInfo(hInst, str, &w, TRUE, 0);
+  
+  w.hInstance = (hInst == User32Instance) ? 0 : hInst;
+  
+  if ( !IS_ATOM(str) )
+    HEAP_free(str);
+
+  RtlCopyMemory ( lpwcx, &w, sizeof(WNDCLASSEXW) );
+
+  if ( !IS_INTRESOURCE(w.lpszMenuName) && w.lpszMenuName )
+  {
+    if (unicode)
+        lpwcx->lpszMenuName = heap_string_poolW ( str2.Buffer, str2.Length );
+    else
+        ((LPWNDCLASSEXA) lpwcx)->lpszMenuName = heap_string_poolA ( str2.Buffer, str2.Length );
+  }
+
+  if ( !IS_ATOM(w.lpszClassName) && w.lpszClassName )
+  {
+    if (unicode)
+        lpwcx->lpszClassName = heap_string_poolW ( str3.Buffer, str3.Length );
+    else
+        ((LPWNDCLASSEXA) lpwcx)->lpszClassName = heap_string_poolA ( str3.Buffer, str3.Length );
+  }
+
+  HEAP_free ( str2.Buffer );
+  HEAP_free ( str3.Buffer );
+
+  return retval;
 }
 
-WINBOOL
+
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 GetClassInfoExA(
   HINSTANCE hinst,
   LPCSTR lpszClass,
-  LPWNDCLASSEX lpwcx)
+  LPWNDCLASSEXA lpwcx)
 {
-  return FALSE;
+    return GetClassInfoExCommon(hinst, (LPWSTR)lpszClass, (LPWNDCLASSEXW)lpwcx, FALSE);
 }
 
-WINBOOL
+
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 GetClassInfoExW(
   HINSTANCE hinst,
   LPCWSTR lpszClass,
-  LPWNDCLASSEX lpwcx)
+  LPWNDCLASSEXW lpwcx)
+{
+    return GetClassInfoExCommon(hinst, lpszClass, lpwcx, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+GetClassInfoA(
+  HINSTANCE hInstance,
+  LPCSTR lpClassName,
+  LPWNDCLASSA lpWndClass)
 {
-  return FALSE;
+  WNDCLASSEXA w;
+  BOOL retval;
+
+  if ( !lpClassName || !lpWndClass )
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+
+  retval = GetClassInfoExA(hInstance,lpClassName,&w);
+  if (retval)
+  {
+    RtlCopyMemory ( lpWndClass, &w.style, sizeof(WNDCLASSA) );
+  }
+  return retval;
 }
 
-WINBOOL
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 GetClassInfoW(
   HINSTANCE hInstance,
   LPCWSTR lpClassName,
-  LPWNDCLASS lpWndClass)
+  LPWNDCLASSW lpWndClass)
 {
-  return FALSE;
+  WNDCLASSEXW w;
+  BOOL retval;
+
+  if(!lpClassName || !lpWndClass)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+
+  retval = GetClassInfoExW(hInstance,lpClassName,&w);
+  RtlCopyMemory (lpWndClass,&w.style,sizeof(WNDCLASSW));
+  return retval;
 }
 
-DWORD
-STDCALL
-GetClassLongA(
-  HWND hWnd,
-  int nIndex)
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+GetClassLongA(HWND hWnd, int nIndex)
 {
-  return 0;
+   switch (nIndex)
+   {
+      case GCL_HBRBACKGROUND:
+         {
+            DWORD hBrush = NtUserGetClassLong(hWnd, GCL_HBRBACKGROUND, TRUE);
+            if (hBrush != 0 && hBrush < 0x4000)
+               hBrush = (DWORD)GetSysColorBrush((ULONG)hBrush - 1);
+            return hBrush;
+         }
+
+      case GCL_MENUNAME:
+         {
+            PUNICODE_STRING Name;
+            Name = (PUNICODE_STRING)NtUserGetClassLong(hWnd, nIndex, TRUE);
+            if (IS_INTRESOURCE(Name))
+               return (DWORD)Name;
+            else
+               return (DWORD)heap_string_poolA(Name->Buffer, Name->Length);
+         }
+
+      default:
+         return NtUserGetClassLong(hWnd, nIndex, TRUE);
+   }
 }
 
-DWORD
-STDCALL
-GetClassLongW(
-  HWND hWnd,
-  int nIndex)
+/*
+ * @implemented
+ */
+DWORD STDCALL
+GetClassLongW ( HWND hWnd, int nIndex )
 {
-  return 0;
+   switch (nIndex)
+   {
+      case GCL_HBRBACKGROUND:
+         {
+            DWORD hBrush = NtUserGetClassLong(hWnd, GCL_HBRBACKGROUND, TRUE);
+            if (hBrush != 0 && hBrush < 0x4000)
+               hBrush = (DWORD)GetSysColorBrush((ULONG)hBrush - 1);
+            return hBrush;
+         }
+
+      case GCL_MENUNAME:
+         {
+            PUNICODE_STRING Name;
+            Name = (PUNICODE_STRING)NtUserGetClassLong(hWnd, nIndex, FALSE);
+            if (IS_INTRESOURCE(Name))
+               return (DWORD)Name;
+            else
+               return (DWORD)heap_string_poolW(Name->Buffer, Name->Length);
+         }
+
+      default:
+         return NtUserGetClassLong(hWnd, nIndex, FALSE);
+   }
 }
 
-int
-STDCALL
+
+/*
+ * @implemented
+ */
+int STDCALL
 GetClassNameA(
   HWND hWnd,
   LPSTR lpClassName,
   int nMaxCount)
 {
-  return 0;
+  int result;
+  LPWSTR ClassNameW;
+  NTSTATUS Status;
+
+  if(!lpClassName)
+    return 0;
+
+  ClassNameW = HEAP_alloc ( (nMaxCount+1)*sizeof(WCHAR) );
+
+  result = NtUserGetClassName ( hWnd, ClassNameW, nMaxCount );
+
+  Status = HEAP_strcpyWtoA ( lpClassName, ClassNameW, result );
+
+  HEAP_free ( ClassNameW );
+
+  if ( !NT_SUCCESS(Status) )
+    return 0;
+
+  return result;
 }
 
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 GetClassNameW(
@@ -88,9 +307,13 @@ GetClassNameW(
   LPWSTR lpClassName,
   int nMaxCount)
 {
-  return 0;
+   return NtUserGetClassName(hWnd, lpClassName, nMaxCount);
 }
 
+
+/*
+ * @implemented
+ */
 WORD
 STDCALL
 GetClassWord(
@@ -100,47 +323,57 @@ GetClassWord(
  * NOTE: Obsoleted in 32-bit windows
  */
 {
-  return 0;
+    if ((nIndex < 0) && (nIndex != GCW_ATOM))
+        return 0;
+
+    return (WORD) NtUserGetClassLong ( hWnd, nIndex, TRUE );
 }
 
+
+/*
+ * @implemented
+ */
 LONG
 STDCALL
-GetWindowLongA(
-  HWND hWnd,
-  int nIndex)
+GetWindowLongA ( HWND hWnd, int nIndex )
 {
-  return 0;
+  return NtUserGetWindowLong(hWnd, nIndex, TRUE);
 }
 
+
+/*
+ * @implemented
+ */
 LONG
 STDCALL
-GetWindowLongW(
-  HWND hWnd,
-  int nIndex)
+GetWindowLongW(HWND hWnd, int nIndex)
 {
-  return 0;
+  return NtUserGetWindowLong(hWnd, nIndex, FALSE);
 }
 
-UINT
+/*
+ * @implemented
+ */
+WORD
 STDCALL
-RealGetWindowClass(
-  HWND  hwnd,
-  LPSTR pszType,
-  UINT  cchType)
+GetWindowWord(HWND hWnd, int nIndex)
 {
-  return 0;
+  return (WORD)NtUserGetWindowLong(hWnd, nIndex,  TRUE);
 }
 
-UINT
+/*
+ * @implemented
+ */
+WORD
 STDCALL
-RealGetWindowClassA(
-  HWND  hwnd,
-  LPSTR pszType,
-  UINT  cchType)
+SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
 {
-  return 0;
+  return (WORD)NtUserSetWindowLong ( hWnd, nIndex, (LONG)wNewWord, TRUE );
 }
 
+/*
+ * @implemented
+ */
 UINT
 STDCALL
 RealGetWindowClassW(
@@ -148,105 +381,436 @@ RealGetWindowClassW(
   LPWSTR pszType,
   UINT  cchType)
 {
-  return 0;
+       /* FIXME: Implement correct functionality of RealGetWindowClass */
+       return GetClassNameW(hwnd,pszType,cchType);
 }
 
-ATOM
+
+/*
+ * @implemented
+ */
+UINT
 STDCALL
-RegisterClassA(
-  CONST WNDCLASS *lpWndClass)
+RealGetWindowClassA(
+  HWND  hwnd,
+  LPSTR pszType,
+  UINT  cchType)
 {
-  WNDCLASSEX Class;
-
-  RtlMoveMemory(&Class.style, lpWndClass, sizeof(WNDCLASS));
-  Class.cbSize = sizeof(WNDCLASSEX);
-  Class.hIconSm = INVALID_HANDLE_VALUE;
-  return RegisterClassExA(&Class);
+       /* FIXME: Implement correct functionality of RealGetWindowClass */
+       return GetClassNameA(hwnd,pszType,cchType);
 }
 
-ATOM
-STDCALL
-RegisterClassExA(
-  CONST WNDCLASSEX *lpwcx)
+/*
+ * Create a small icon based on a standard icon
+ */
+static HICON
+CreateSmallIcon(HICON StdIcon)
 {
-  UNICODE_STRING MenuName;
-  UNICODE_STRING ClassName;
-  WNDCLASSEX Class;
-  RTL_ATOM Atom;
-
-  if (!RtlCreateUnicodeStringFromAsciiz(&MenuName, (PCSZ)lpwcx->lpszMenuName))
-  {
-    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    return (ATOM)0;
-  }
+   HICON SmallIcon = NULL;
+   ICONINFO StdInfo;
+   int SmallIconWidth;
+   int SmallIconHeight;
+   BITMAP StdBitmapInfo;
+   HDC hInfoDc = NULL;
+   HDC hSourceDc = NULL;
+   HDC hDestDc = NULL;
+   ICONINFO SmallInfo;
+   HBITMAP OldSourceBitmap = NULL;
+   HBITMAP OldDestBitmap = NULL;
+
+   SmallInfo.hbmColor = NULL;
+   SmallInfo.hbmMask = NULL;
+
+   /* We need something to work with... */
+   if (NULL == StdIcon)
+   {
+      goto cleanup;
+   }
+
+   SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
+   SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
+   if (! GetIconInfo(StdIcon, &StdInfo))
+   {
+      DPRINT1("Failed to get icon info for icon 0x%x\n", StdIcon);
+      goto cleanup;
+   }
+   if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
+   {
+      DPRINT1("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
+              StdIcon, StdInfo.hbmColor);
+      goto cleanup;
+   }
+   if (StdBitmapInfo.bmWidth == SmallIconWidth &&
+       StdBitmapInfo.bmHeight == SmallIconHeight)
+   {
+      /* Icon already has the correct dimensions */
+      return StdIcon;
+   }
+
+   /* Get a handle to a info DC and handles to DCs which can be used to
+      select a bitmap into. This is done to avoid triggering a switch to
+      graphics mode (if we're currently in text/blue screen mode) */
+   hInfoDc = CreateICW(NULL, NULL, NULL, NULL);
+   if (NULL == hInfoDc)
+   {
+      DPRINT1("Failed to create info DC\n");
+      goto cleanup;
+   }
+   hSourceDc = CreateCompatibleDC(NULL);
+   if (NULL == hSourceDc)
+   {
+      DPRINT1("Failed to create source DC\n");
+      goto cleanup;
+   }
+   hDestDc = CreateCompatibleDC(NULL);
+   if (NULL == hDestDc)
+   {
+      DPRINT1("Failed to create dest DC\n");
+      goto cleanup;
+   }
+
+   OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
+   if (NULL == OldSourceBitmap)
+   {
+      DPRINT1("Failed to select source color bitmap\n");
+      goto cleanup;
+   }
+   SmallInfo.hbmColor = CreateCompatibleBitmap(hInfoDc, SmallIconWidth,
+                                              SmallIconHeight);
+   if (NULL == SmallInfo.hbmColor)
+   {
+      DPRINT1("Failed to create color bitmap\n");
+      goto cleanup;
+   }
+   OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
+   if (NULL == OldDestBitmap)
+   {
+      DPRINT1("Failed to select dest color bitmap\n");
+      goto cleanup;
+   }
+   if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
+                    hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
+                    StdBitmapInfo.bmHeight, SRCCOPY))
+   {
+     DPRINT1("Failed to stretch color bitmap\n");
+     goto cleanup;
+   }
+
+   if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
+   {
+      DPRINT1("Failed to select source mask bitmap\n");
+      goto cleanup;
+   }
+   SmallInfo.hbmMask = CreateBitmap(SmallIconWidth, SmallIconHeight, 1, 1,
+                                    NULL);
+   if (NULL == SmallInfo.hbmMask)
+   {
+      DPRINT1("Failed to create mask bitmap\n");
+      goto cleanup;
+   }
+   if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
+   {
+      DPRINT1("Failed to select dest mask bitmap\n");
+      goto cleanup;
+   }
+   if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
+                    hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
+                    StdBitmapInfo.bmHeight, SRCCOPY))
+   {
+      DPRINT1("Failed to stretch mask bitmap\n");
+      goto cleanup;
+   }
+
+   SmallInfo.fIcon = TRUE;
+   SmallInfo.xHotspot = SmallIconWidth / 2;
+   SmallInfo.yHotspot = SmallIconHeight / 2;
+   SmallIcon = CreateIconIndirect(&SmallInfo);
+   if (NULL == SmallIcon)
+   {
+      DPRINT1("Failed to create icon\n");
+      goto cleanup;
+   }
+
+cleanup:
+   if (NULL != SmallInfo.hbmMask)
+   {
+      DeleteObject(SmallInfo.hbmMask);
+   }
+   if (NULL != OldDestBitmap)
+   {
+      SelectObject(hDestDc, OldDestBitmap);
+   }
+   if (NULL != SmallInfo.hbmColor)
+   {
+      DeleteObject(SmallInfo.hbmColor);
+   }
+   if (NULL != hDestDc)
+   {
+      DeleteDC(hDestDc);
+   }
+   if (NULL != OldSourceBitmap)
+   {
+      SelectObject(hSourceDc, OldSourceBitmap);
+   }
+   if (NULL != hSourceDc)
+   {
+      DeleteDC(hSourceDc);
+   }
+   if (NULL != hInfoDc)
+   {
+      DeleteDC(hInfoDc);
+   }
+
+   return SmallIcon;
+}
 
-  if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, (PCSZ)lpwcx->lpszMenuName))
-  {
-    RtlFreeUnicodeString(&MenuName);
-    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    return (ATOM)0;
-  }
+/*
+ * @implemented
+ */
+ATOM STDCALL
+RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
+{
+   RTL_ATOM Atom;
+   WNDCLASSEXA WndClass;
+   UNICODE_STRING ClassName;
+   UNICODE_STRING MenuName;
+   HMENU hMenu;
+
+   if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXA) ||
+       lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
+       lpwcx->lpszClassName == NULL)
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return 0;
+   }
+
+   /*
+    * On real Windows this looks more like:
+    *    if (lpwcx->hInstance == User32Instance &&
+    *        *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
+    * But since I have no idea what the magic field in the
+    * TEB structure means, I rather decided to omit that.
+    * -- Filip Navara
+    */
+   if (lpwcx->hInstance == User32Instance)
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return 0;
+   }
+
+   /* Yes, this is correct. We should modify the passed structure. */
+   if (lpwcx->hInstance == NULL)
+      ((WNDCLASSEXA*)lpwcx)->hInstance = GetModuleHandleW(NULL);
+
+   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
+
+   if (NULL == WndClass.hIconSm)
+   {
+      WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
+   }
+
+   if HIWORD(lpwcx->lpszMenuName)
+   {
+      hMenu = 0;
+      RtlCreateUnicodeStringFromAsciiz(&MenuName, WndClass.lpszMenuName);
+    }
+   else
+   {
+      MenuName.Length =
+      MenuName.MaximumLength = 0;
+      MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
+      hMenu = LoadMenuA(WndClass.hInstance, lpwcx->lpszMenuName);
+   }
+   if (IS_ATOM(WndClass.lpszClassName))
+   {
+      ClassName.Length =
+      ClassName.MaximumLength = 0;
+      ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
+   } else
+   {
+      RtlCreateUnicodeStringFromAsciiz(&ClassName, WndClass.lpszClassName);
+   }
+
+   Atom = NtUserRegisterClassExWOW(
+      (WNDCLASSEXW*)&WndClass,
+      &ClassName,
+      &ClassName,
+      &MenuName,
+      NULL,
+      REGISTERCLASS_ANSI,
+      0,
+      hMenu);
+
+   if (!IS_ATOM(WndClass.lpszMenuName))
+      RtlFreeUnicodeString(&MenuName);
+   if (!IS_ATOM(WndClass.lpszClassName))
+      RtlFreeUnicodeString(&ClassName);
+
+   return (ATOM)Atom;
+}
 
-  RtlMoveMemory(&Class, lpwcx, sizeof(WNDCLASSEX));
-  Class.lpszMenuName = (LPCTSTR)MenuName.Buffer;
-  Class.lpszClassName = (LPCTSTR)ClassName.Buffer;
+/*
+ * @implemented
+ */
+ATOM STDCALL
+RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
+{
+   WNDCLASSEXW WndClass;
+   UNICODE_STRING ClassName;
+   UNICODE_STRING MenuName;
+   HMENU hMenu;
+
+   if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
+       lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
+       lpwcx->lpszClassName == NULL)
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return 0;
+   }
+
+   /*
+    * On real Windows this looks more like:
+    *    if (lpwcx->hInstance == User32Instance &&
+    *        *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
+    * But since I have no idea what the magic field in the
+    * TEB structure means, I rather decided to omit that.
+    * -- Filip Navara
+    */
+   if (lpwcx->hInstance == User32Instance)
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return 0;
+   }
+
+   /* Yes, this is correct. We should modify the passed structure. */
+   if (lpwcx->hInstance == NULL)
+      ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
+
+   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
+
+   if (NULL == WndClass.hIconSm)
+   {
+      WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
+   }
+
+   if HIWORD(lpwcx->lpszMenuName)
+   {
+      hMenu = 0;
+      RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
+    }
+   else
+   {
+      MenuName.Length =
+      MenuName.MaximumLength = 0;
+      MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
+      hMenu = LoadMenuW(WndClass.hInstance, lpwcx->lpszMenuName);
+   }
+
+   if (IS_ATOM(WndClass.lpszClassName))
+   {
+      ClassName.Length =
+      ClassName.MaximumLength = 0;
+      ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
+   } else
+   {
+      RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
+   }
+
+   return (ATOM)NtUserRegisterClassExWOW(
+      &WndClass,
+      &ClassName,
+      &ClassName,
+      &MenuName,
+      NULL,
+      0,
+      0,
+      hMenu);
+}
 
-  Atom = NtUserRegisterClassExWOW(
-    (WNDCLASSEX*)lpwcx,
-    FALSE,
-    0,
-    0,
-    0,
-    0);
+/*
+ * @implemented
+ */
+ATOM STDCALL
+RegisterClassA(CONST WNDCLASSA *lpWndClass)
+{
+   WNDCLASSEXA Class;
 
-  RtlFreeUnicodeString(&ClassName);
+   if (lpWndClass == NULL)
+      return 0;
 
-  RtlFreeUnicodeString(&MenuName);
+   RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
+   Class.cbSize = sizeof(WNDCLASSEXA);
+   Class.hIconSm = NULL;
 
-  return (ATOM)Atom;
+   return RegisterClassExA(&Class);
 }
 
-ATOM
-STDCALL
-RegisterClassExW(
-  CONST WNDCLASSEX *lpwcx)
+/*
+ * @implemented
+ */
+ATOM STDCALL
+RegisterClassW(CONST WNDCLASSW *lpWndClass)
 {
-  RTL_ATOM Atom;
+   WNDCLASSEXW Class;
 
-  Atom = NtUserRegisterClassExWOW(
-    (WNDCLASSEX*)lpwcx,
-    TRUE,
-    0,
-    0,
-    0,
-    0);
+   if (lpWndClass == NULL)
+      return 0;
 
-  return (ATOM)Atom;
-}
-
-ATOM
-STDCALL
-RegisterClassW(
-  CONST WNDCLASS *lpWndClass)
-{
-  WNDCLASSEX Class;
+   RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
+   Class.cbSize = sizeof(WNDCLASSEXW);
+   Class.hIconSm = NULL;
 
-  RtlMoveMemory(&Class.style, lpWndClass, sizeof(WNDCLASS));
-  Class.cbSize = sizeof(WNDCLASSEX);
-  Class.hIconSm = INVALID_HANDLE_VALUE;
-  return RegisterClassExW(&Class);
+   return RegisterClassExW(&Class);
 }
 
+/*
+ * @implemented
+ */
 DWORD
 STDCALL
-SetClassLongA(
+SetClassLongA (
   HWND hWnd,
   int nIndex,
   LONG dwNewLong)
 {
-  return 0;
+  UNICODE_STRING str2buf;
+  PUNICODE_STRING str;
+  PUNICODE_STRING str2 = &str2buf;
+
+  if ( nIndex != GCL_MENUNAME )
+  {
+    return NtUserSetClassLong ( hWnd, nIndex, dwNewLong, TRUE );
+  }
+  if ( IS_INTRESOURCE(dwNewLong) )
+  {
+    str2 = (PUNICODE_STRING)dwNewLong;
+  }
+  else
+  {
+    RtlCreateUnicodeStringFromAsciiz ( &str2buf,(LPSTR)dwNewLong );
+  }
+
+  str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
+
+  if ( !IS_INTRESOURCE(dwNewLong) )
+  {
+    RtlFreeUnicodeString ( str2 );
+  }
+  if ( IS_INTRESOURCE(str) )
+  {
+    return (DWORD)str;
+  }
+  else
+  {
+    return (DWORD)heap_string_poolA ( str->Buffer, str->Length );
+  }
 }
 
+
+/*
+ * @implemented
+ */
 DWORD
 STDCALL
 SetClassLongW(
@@ -254,9 +818,43 @@ SetClassLongW(
   int nIndex,
   LONG dwNewLong)
 {
-  return 0;
+  UNICODE_STRING str2buf;
+  PUNICODE_STRING str;
+  PUNICODE_STRING str2 = &str2buf;
+
+  if (nIndex != GCL_MENUNAME )
+  {
+    return NtUserSetClassLong ( hWnd, nIndex, dwNewLong, FALSE );
+  }
+  if ( IS_INTRESOURCE(dwNewLong) )
+  {
+    str2 = (PUNICODE_STRING)dwNewLong;
+  }
+  else
+  {
+    RtlCreateUnicodeString ( &str2buf, (LPWSTR)dwNewLong );
+  }
+
+  str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
+
+  if ( !IS_INTRESOURCE(dwNewLong) )
+  {
+    RtlFreeUnicodeString(str2);
+  }
+  if ( IS_INTRESOURCE(str) )
+  {
+    return (DWORD)str;
+  }
+  else
+  {
+    return (DWORD)heap_string_poolW ( str->Buffer, str->Length );
+  }
 }
 
+
+/*
+ * @implemented
+ */
 WORD
 STDCALL
 SetClassWord(
@@ -267,9 +865,16 @@ SetClassWord(
  * NOTE: Obsoleted in 32-bit windows
  */
 {
-  return 0;
+    if ((nIndex < 0) && (nIndex != GCW_ATOM))
+        return 0;
+
+    return (WORD) NtUserSetClassLong ( hWnd, nIndex, wNewWord, TRUE );
 }
 
+
+/*
+ * @implemented
+ */
 LONG
 STDCALL
 SetWindowLongA(
@@ -277,9 +882,13 @@ SetWindowLongA(
   int nIndex,
   LONG dwNewLong)
 {
-  return 0;
+  return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
 }
 
+
+/*
+ * @implemented
+ */
 LONG
 STDCALL
 SetWindowLongW(
@@ -287,25 +896,54 @@ SetWindowLongW(
   int nIndex,
   LONG dwNewLong)
 {
-  return 0;
+  return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
 }
 
-WINBOOL
+
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 UnregisterClassA(
   LPCSTR lpClassName,
   HINSTANCE hInstance)
 {
-  return FALSE;
+  LPWSTR ClassName;
+  NTSTATUS Status;
+  BOOL Result;
+
+  if(!IS_ATOM(lpClassName))
+  {
+    Status = HEAP_strdupAtoW(&ClassName, lpClassName, NULL);
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastError(RtlNtStatusToDosError(Status));
+      return FALSE;
+    }
+  }
+  else
+    ClassName = (LPWSTR)lpClassName;
+
+  Result = (BOOL)NtUserUnregisterClass((LPCWSTR)ClassName, hInstance, 0);
+
+  if(ClassName && !IS_ATOM(lpClassName))
+    HEAP_free(ClassName);
+
+  return Result;
 }
 
-WINBOOL
+
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 UnregisterClassW(
   LPCWSTR lpClassName,
   HINSTANCE hInstance)
 {
-  return FALSE;
+  return (BOOL)NtUserUnregisterClass(lpClassName, hInstance, 0);
 }
 
 /* EOF */