fix bug 838 (Sol.exe is missing it's menubar)
[reactos.git] / reactos / lib / user32 / windows / class.c
index 9922089..935286c 100644 (file)
@@ -400,6 +400,170 @@ RealGetWindowClassA(
        return GetClassNameA(hwnd,pszType,cchType);
 }
 
+/*
+ * Create a small icon based on a standard icon
+ */
+static HICON
+CreateSmallIcon(HICON StdIcon)
+{
+   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;
+}
+
 /*
  * @implemented
  */
@@ -410,8 +574,9 @@ RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
    WNDCLASSEXA WndClass;
    UNICODE_STRING ClassName;
    UNICODE_STRING MenuName;
+   HMENU hMenu;
 
-   if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
+   if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXA) ||
        lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
        lpwcx->lpszClassName == NULL)
    {
@@ -437,26 +602,34 @@ RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
    if (lpwcx->hInstance == NULL)
       ((WNDCLASSEXA*)lpwcx)->hInstance = GetModuleHandleW(NULL);
 
-   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
+   RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
+
+   if (NULL == WndClass.hIconSm)
+   {
+      WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
+   }
 
-   if (IS_ATOM(lpwcx->lpszMenuName) || lpwcx->lpszMenuName == 0)
+   if HIWORD(lpwcx->lpszMenuName)
+   {
+      hMenu = 0;
+      RtlCreateUnicodeStringFromAsciiz(&MenuName, WndClass.lpszMenuName);
+    }
+   else
    {
       MenuName.Length =
       MenuName.MaximumLength = 0;
-      MenuName.Buffer = (LPWSTR)lpwcx->lpszMenuName;
-   } else
-   {
-      RtlCreateUnicodeStringFromAsciiz(&MenuName, lpwcx->lpszMenuName);
+      MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
+      hMenu = LoadMenuA(WndClass.hInstance, lpwcx->lpszMenuName);
    }
-
-   if (IS_ATOM(lpwcx->lpszClassName))
+   if (IS_ATOM(WndClass.lpszClassName))
    {
       ClassName.Length =
       ClassName.MaximumLength = 0;
-      ClassName.Buffer = (LPWSTR)lpwcx->lpszClassName;
+      ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
    } else
    {
-      RtlCreateUnicodeStringFromAsciiz(&ClassName, lpwcx->lpszClassName);
+      RtlCreateUnicodeStringFromAsciiz(&ClassName, WndClass.lpszClassName);
    }
 
    Atom = NtUserRegisterClassExWOW(
@@ -466,11 +639,12 @@ RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
       &MenuName,
       NULL,
       REGISTERCLASS_ANSI,
-      0);
+      0,
+      hMenu);
 
-   if (!IS_ATOM(lpwcx->lpszMenuName))
+   if (!IS_ATOM(WndClass.lpszMenuName))
       RtlFreeUnicodeString(&MenuName);
-   if (!IS_ATOM(lpwcx->lpszClassName))
+   if (!IS_ATOM(WndClass.lpszClassName))
       RtlFreeUnicodeString(&ClassName);
 
    return (ATOM)Atom;
@@ -485,6 +659,7 @@ 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 ||
@@ -514,24 +689,32 @@ RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
 
    RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
 
-   if (IS_ATOM(lpwcx->lpszMenuName))
+   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)lpwcx->lpszMenuName;
-   } else
-   {
-      RtlInitUnicodeString(&MenuName, lpwcx->lpszMenuName);
+      MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
+      hMenu = LoadMenuW(WndClass.hInstance, lpwcx->lpszMenuName);
    }
 
-   if (IS_ATOM(lpwcx->lpszClassName))
+   if (IS_ATOM(WndClass.lpszClassName))
    {
       ClassName.Length =
       ClassName.MaximumLength = 0;
-      ClassName.Buffer = (LPWSTR)lpwcx->lpszClassName;
+      ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
    } else
    {
-      RtlInitUnicodeString(&ClassName, lpwcx->lpszClassName);
+      RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
    }
 
    return (ATOM)NtUserRegisterClassExWOW(
@@ -541,7 +724,8 @@ RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
       &MenuName,
       NULL,
       0,
-      0);
+      0,
+      hMenu);
 }
 
 /*