Replace RtlNtStatusToDosError(STATUS_NO_MEMORY) with ERROR_OUTOFMEMORY.
[reactos.git] / reactos / lib / user32 / windows / class.c
index c220b4a..423b74c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: class.c,v 1.46 2004/04/09 20:03:14 navaraf Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
@@ -8,18 +8,8 @@
  * UPDATE HISTORY:
  *      09-05-2001  CSH  Created
  */
-#include <windows.h>
-#include <user32.h>
-#include <string.h>
-#include <stdlib.h>
-#include <debug.h>
-#include <window.h>
-#include <strpool.h>
-#include <user32/regcontrol.h>
-#define NTOS_MODE_USER
-#include <ntos.h>
-
 
+#include <user32.h>
 
 static BOOL GetClassInfoExCommon(
     HINSTANCE hInst,
@@ -51,7 +41,7 @@ static BOOL GetClassInfoExCommon(
 
         if ( !str )
         {
-          SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+          SetLastError (ERROR_OUTOFMEMORY);
           return FALSE;
         }
     }
@@ -59,7 +49,7 @@ static BOOL GetClassInfoExCommon(
     else
     {
         Status = HEAP_strdupAtoW(&str, (LPCSTR)lpszClass, NULL);
-        
+
         if (! NT_SUCCESS(Status))
         {
             SetLastError(RtlNtStatusToDosError(Status));
@@ -79,7 +69,7 @@ static BOOL GetClassInfoExCommon(
   str2.Buffer = (PWSTR)HEAP_alloc ( str2.MaximumLength * sizeof(WCHAR) );
   if ( !str2.Buffer )
   {
-    SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+    SetLastError (ERROR_OUTOFMEMORY);
     if ( !IS_ATOM(str) )
       HEAP_free ( str );
     return FALSE;
@@ -88,7 +78,8 @@ static BOOL GetClassInfoExCommon(
   str3.Buffer = (PWSTR)HEAP_alloc ( str3.MaximumLength * sizeof(WCHAR) );
   if ( !str3.Buffer )
   {
-    SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
+    SetLastError (ERROR_OUTOFMEMORY);
+    HEAP_free ( str2.Buffer );
     if ( !IS_ATOM(str) )
       HEAP_free ( str );
     return FALSE;
@@ -96,7 +87,14 @@ static BOOL GetClassInfoExCommon(
 
   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);
 
@@ -107,7 +105,7 @@ static BOOL GetClassInfoExCommon(
     if (unicode)
         lpwcx->lpszMenuName = heap_string_poolW ( str2.Buffer, str2.Length );
     else
-        (LPWNDCLASSEXA) lpwcx->lpszMenuName = heap_string_poolA ( str2.Buffer, str2.Length );
+        ((LPWNDCLASSEXA) lpwcx)->lpszMenuName = heap_string_poolA ( str2.Buffer, str2.Length );
   }
 
   if ( !IS_ATOM(w.lpszClassName) && w.lpszClassName )
@@ -115,7 +113,7 @@ static BOOL GetClassInfoExCommon(
     if (unicode)
         lpwcx->lpszClassName = heap_string_poolW ( str3.Buffer, str3.Length );
     else
-        (LPWNDCLASSEXA) lpwcx->lpszClassName = heap_string_poolA ( str3.Buffer, str3.Length );
+        ((LPWNDCLASSEXA) lpwcx)->lpszClassName = heap_string_poolA ( str3.Buffer, str3.Length );
   }
 
   HEAP_free ( str2.Buffer );
@@ -173,7 +171,10 @@ GetClassInfoA(
   }
 
   retval = GetClassInfoExA(hInstance,lpClassName,&w);
-  RtlCopyMemory ( lpWndClass, &w.style, sizeof(WNDCLASSA) );
+  if (retval)
+  {
+    RtlCopyMemory ( lpWndClass, &w.style, sizeof(WNDCLASSA) );
+  }
   return retval;
 }
 
@@ -277,7 +278,7 @@ GetClassNameA(
   int result;
   LPWSTR ClassNameW;
   NTSTATUS Status;
-  
+
   if(!lpClassName)
     return 0;
 
@@ -400,23 +401,167 @@ RealGetWindowClassA(
 }
 
 /*
- * @implemented
+ * Create a small icon based on a standard icon
  */
-ATOM
-STDCALL
-RegisterClassA(CONST WNDCLASSA *lpWndClass)
+static HICON
+CreateSmallIcon(HICON StdIcon)
 {
-  WNDCLASSEXA Class;
+   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;
+   }
 
-  if ( !lpWndClass )
-    return 0;
+   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;
+   }
 
-  RtlCopyMemory ( &Class.style, lpWndClass, sizeof(WNDCLASSA) );
+   /* 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;
+   }
 
-  Class.cbSize = sizeof(WNDCLASSEXA);
-  Class.hIconSm = NULL;
+   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;
+   }
 
-  return RegisterClassExA ( &Class );
+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;
 }
 
 /*
@@ -425,54 +570,85 @@ RegisterClassA(CONST WNDCLASSA *lpWndClass)
 ATOM STDCALL
 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
 {
-  RTL_ATOM Atom;
-  WNDCLASSEXW wndclass;
-  NTSTATUS Status;
-  LPWSTR ClassName = NULL;
-  LPWSTR MenuName = NULL;
-
-  if ( !lpwcx || (lpwcx->cbSize != sizeof(WNDCLASSEXA)) )
-    return 0;
-
-  if ( !lpwcx->lpszClassName )
-    return 0;
-
-  RtlCopyMemory ( &wndclass, lpwcx, sizeof(WNDCLASSEXW) );
-
-  if ( !IS_ATOM(lpwcx->lpszClassName) )
-  {
-    Status = HEAP_strdupAtoW ( &ClassName, (LPCSTR)lpwcx->lpszClassName, NULL );
-    if ( !NT_SUCCESS (Status) )
-    {
-      SetLastError (RtlNtStatusToDosError(Status));
+   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;
-    }
-    wndclass.lpszClassName = ClassName;
-  }
+   }
 
-  if ( !IS_INTRESOURCE(lpwcx->lpszMenuName) )
-  {
-    Status = HEAP_strdupAtoW ( &MenuName, (LPCSTR)lpwcx->lpszMenuName, NULL );
-    if ( !NT_SUCCESS (Status) )
-    {
-      if ( ClassName )
-       HEAP_free ( ClassName );
-      SetLastError (RtlNtStatusToDosError(Status));
+   /*
+    * 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;
-    }
-    wndclass.lpszMenuName = MenuName;
-  }
+   }
 
-  Atom = NtUserRegisterClassExWOW ( &wndclass, FALSE, (WNDPROC)0, 0, 0 );
+   /* Yes, this is correct. We should modify the passed structure. */
+   if (lpwcx->hInstance == NULL)
+      ((WNDCLASSEXA*)lpwcx)->hInstance = GetModuleHandleW(NULL);
 
-  /* free strings if neccessary */
-  if ( MenuName  ) HEAP_free ( MenuName );
-  if ( ClassName ) HEAP_free ( ClassName );
+   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
 
-  return (ATOM)Atom;
-}
+   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;
+}
 
 /*
  * @implemented
@@ -480,54 +656,94 @@ RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
 ATOM STDCALL
 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
 {
-  RTL_ATOM Atom;
-  HANDLE hHeap;
-  WNDCLASSEXW wndclass;
-  LPWSTR ClassName = NULL;
-  LPWSTR MenuName = NULL;
+   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;
+   }
 
-  if ( !lpwcx || (lpwcx->cbSize != sizeof(WNDCLASSEXA)) )
-    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;
+   }
 
-  if ( !lpwcx->lpszClassName )
-    return 0;
+   /* Yes, this is correct. We should modify the passed structure. */
+   if (lpwcx->hInstance == NULL)
+      ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
 
-  hHeap = GetProcessHeap();
-  RtlCopyMemory ( &wndclass, lpwcx, sizeof(WNDCLASSEXW) );
+   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
 
-  /* copy strings if needed */
+   if (NULL == WndClass.hIconSm)
+   {
+      WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
+   }
 
-  if ( !IS_ATOM(lpwcx->lpszClassName) )
-  {
-    ClassName = HEAP_strdupW ( lpwcx->lpszClassName, lstrlenW(lpwcx->lpszClassName) );
-    if ( !ClassName )
-    {
-      SetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
-      return 0;
+   if HIWORD(lpwcx->lpszMenuName)
+   {
+      hMenu = 0;
+      RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
     }
-    wndclass.lpszClassName = ClassName;
-  }
+   else
+   {
+      MenuName.Length =
+      MenuName.MaximumLength = 0;
+      MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
+      hMenu = LoadMenuW(WndClass.hInstance, lpwcx->lpszMenuName);
+   }
 
-  if ( !IS_INTRESOURCE(lpwcx->lpszMenuName) )
-  {
-    MenuName = HEAP_strdupW ( lpwcx->lpszMenuName, lstrlenW(lpwcx->lpszMenuName) );
-    if ( !MenuName )
-    {
-      if ( ClassName )
-       HEAP_free ( MenuName );
-      SetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
-      return 0;
-    }
-    wndclass.lpszMenuName = MenuName;
-  }
+   if (IS_ATOM(WndClass.lpszClassName))
+   {
+      ClassName.Length =
+      ClassName.MaximumLength = 0;
+      ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
+   } else
+   {
+      RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
+   }
 
-  Atom = NtUserRegisterClassExWOW ( &wndclass, TRUE, (WNDPROC)0, 0, 0 );
+   return (ATOM)NtUserRegisterClassExWOW(
+      &WndClass,
+      &ClassName,
+      &ClassName,
+      &MenuName,
+      NULL,
+      0,
+      0,
+      hMenu);
+}
 
-  /* free strings if neccessary */
-  if ( MenuName  ) HEAP_free ( MenuName  );
-  if ( ClassName ) HEAP_free ( ClassName );
+/*
+ * @implemented
+ */
+ATOM STDCALL
+RegisterClassA(CONST WNDCLASSA *lpWndClass)
+{
+   WNDCLASSEXA Class;
+
+   if (lpWndClass == NULL)
+      return 0;
 
-  return (ATOM)Atom;
+   RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
+   Class.cbSize = sizeof(WNDCLASSEXA);
+   Class.hIconSm = NULL;
+
+   return RegisterClassExA(&Class);
 }
 
 /*
@@ -536,17 +752,16 @@ RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
 ATOM STDCALL
 RegisterClassW(CONST WNDCLASSW *lpWndClass)
 {
-  WNDCLASSEXW Class;
-
-  if ( !lpWndClass )
-    return 0;
+   WNDCLASSEXW Class;
 
-  RtlCopyMemory ( &Class.style, lpWndClass, sizeof(WNDCLASSW) );
+   if (lpWndClass == NULL)
+      return 0;
 
-  Class.cbSize = sizeof(WNDCLASSEXW);
-  Class.hIconSm = NULL;
+   RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
+   Class.cbSize = sizeof(WNDCLASSEXW);
+   Class.hIconSm = NULL;
 
-  return RegisterClassExW ( &Class );
+   return RegisterClassExW(&Class);
 }
 
 /*
@@ -559,8 +774,9 @@ SetClassLongA (
   int nIndex,
   LONG dwNewLong)
 {
+  UNICODE_STRING str2buf;
   PUNICODE_STRING str;
-  PUNICODE_STRING str2;
+  PUNICODE_STRING str2 = &str2buf;
 
   if ( nIndex != GCL_MENUNAME )
   {
@@ -572,7 +788,7 @@ SetClassLongA (
   }
   else
   {
-    RtlCreateUnicodeString ( str2, (LPWSTR)dwNewLong );
+    RtlCreateUnicodeStringFromAsciiz ( &str2buf,(LPSTR)dwNewLong );
   }
 
   str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
@@ -602,8 +818,9 @@ SetClassLongW(
   int nIndex,
   LONG dwNewLong)
 {
+  UNICODE_STRING str2buf;
   PUNICODE_STRING str;
-  PUNICODE_STRING str2;
+  PUNICODE_STRING str2 = &str2buf;
 
   if (nIndex != GCL_MENUNAME )
   {
@@ -615,7 +832,7 @@ SetClassLongW(
   }
   else
   {
-    RtlCreateUnicodeStringFromAsciiz ( str2,(LPSTR)dwNewLong );
+    RtlCreateUnicodeString ( &str2buf, (LPWSTR)dwNewLong );
   }
 
   str = (PUNICODE_STRING)NtUserSetClassLong(hWnd, nIndex, (DWORD)str2, TRUE);
@@ -695,7 +912,7 @@ UnregisterClassA(
   LPWSTR ClassName;
   NTSTATUS Status;
   BOOL Result;
-  
+
   if(!IS_ATOM(lpClassName))
   {
     Status = HEAP_strdupAtoW(&ClassName, lpClassName, NULL);
@@ -707,12 +924,12 @@ UnregisterClassA(
   }
   else
     ClassName = (LPWSTR)lpClassName;
-  
+
   Result = (BOOL)NtUserUnregisterClass((LPCWSTR)ClassName, hInstance, 0);
-  
-  if(ClassName && !IS_ATOM(lpClassName)) 
+
+  if(ClassName && !IS_ATOM(lpClassName))
     HEAP_free(ClassName);
-  
+
   return Result;
 }