Check for failed allocations and fix some resource leaks.
[reactos.git] / reactos / lib / user32 / windows / bitmap.c
index c297f22..16b03fb 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: bitmap.c,v 1.11 2003/07/10 21:04:31 chorns Exp $
+/* $Id$
  *
  * PROJECT:         ReactOS user32.dll
  * FILE:            lib/user32/windows/input.c
 
 /* INCLUDES ******************************************************************/
 
-#include <string.h>
-#include <windows.h>
 #include <user32.h>
-#include <debug.h>
-#include <stdlib.h>
 
 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
-HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired);
+HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
+HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
-
+CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -57,7 +54,7 @@ LoadImageA(HINSTANCE hinst,
   UNICODE_STRING NameString;
 
   if (HIWORD(lpszName))
-    {      
+    {
       RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
       lpszWName = NameString.Buffer;
       Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
@@ -73,48 +70,236 @@ LoadImageA(HINSTANCE hinst,
 }
 
 
-HANDLE STATIC
+static HANDLE
 LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
 {
-  DbgPrint("FIXME: Need support for loading cursor images.\n");
-  return(NULL);
+   HANDLE hResource;
+   HANDLE h2Resource;
+   HANDLE hfRes;
+   HANDLE hFile;
+   HANDLE hSection;
+   CURSORICONDIR *IconDIR;
+   HDC hScreenDc;
+   HANDLE hIcon;
+   ULONG HeaderSize;
+   ULONG ColorCount;
+   PVOID Data;
+   CURSORICONDIRENTRY* dirEntry;
+   ICONIMAGE* SafeIconImage;
+   GRPCURSORICONDIR* IconResDir;
+   INT id;
+   ICONIMAGE *ResIcon;
+   UINT ColorBits;
+
+   if (!(fuLoad & LR_LOADFROMFILE))
+   {
+      if (hinst == NULL)
+      {
+         hinst = GetModuleHandleW(L"USER32");
+      }
+      hResource = hfRes = FindResourceW(hinst, lpszName, RT_GROUP_CURSOR);
+      if (hResource == NULL)
+      {
+         return NULL;
+      }
+
+      if (fuLoad & LR_SHARED)
+      {
+         /* FIXME - pass size! */
+         hIcon = (HANDLE)NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, 0, 0);
+         if (hIcon)
+         {
+            return hIcon;
+         }
+      }
+
+      hResource = LoadResource(hinst, hResource);
+      if (hResource == NULL)
+      {
+         return NULL;
+      }
+      IconResDir = LockResource(hResource);
+      if (IconResDir == NULL)
+      {
+         return NULL;
+      }
+
+      /* Find the best fitting in the IconResDir for this resolution. */
+      id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, TRUE,
+         32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
+
+      h2Resource = FindResourceW(hinst, MAKEINTRESOURCEW(id),
+         MAKEINTRESOURCEW(RT_CURSOR));
+
+      hResource = LoadResource(hinst, h2Resource);
+      if (hResource == NULL)
+      {
+         return NULL;
+      }
+
+      ResIcon = LockResource(hResource);
+      if (ResIcon == NULL)
+      {
+         return NULL;
+      }
+
+      hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE)ResIcon,
+         SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
+         32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
+      if (hIcon && 0 != (fuLoad & LR_SHARED))
+      {
+         NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
+                                 (HRSRC)NULL);
+      }
+
+      return hIcon;
+   }
+
+   if (fuLoad & LR_SHARED)
+   {
+      DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
+   }
+
+   hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
+      OPEN_EXISTING, 0, NULL);
+   if (hFile == NULL)
+   {
+      return NULL;
+   }
+
+   hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+   CloseHandle(hFile);
+   if (hSection == NULL)
+   {
+      return NULL;
+   }
+
+   IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
+   CloseHandle(hSection);
+   if (IconDIR == NULL)
+   {
+      return NULL;
+   }
+
+   if (0 != IconDIR->idReserved ||
+       (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
+   {
+      UnmapViewOfFile(IconDIR);
+      return NULL;
+   }
+
+   /*
+    * Get a handle to the screen dc, the icon we create is going to be
+    * compatable with it.
+    */
+   hScreenDc = CreateCompatibleDC(0);
+   if (hScreenDc == NULL)
+   {
+      UnmapViewOfFile(IconDIR);
+      return NULL;
+   }
+
+   if (fuLoad & LR_MONOCHROME)
+   {
+      ColorBits = 1;
+   }
+   else
+   {
+      ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
+      /*
+       * FIXME:
+       * Remove this after proper support for alpha icons will be finished.
+       */
+      if (ColorBits > 8)
+         ColorBits = 8;
+   }
+
+   /* Pick the best size. */
+   dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
+   if (!dirEntry)
+   {
+      UnmapViewOfFile(IconDIR);
+      return NULL;
+   }
+
+   SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
+   if (SafeIconImage == NULL)
+   {
+      UnmapViewOfFile(IconDIR);
+      return NULL;
+   }
+   memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
+   UnmapViewOfFile(IconDIR);
+
+   /* at this point we have a copy of the icon image to play with */
+
+   SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
+
+   if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
+   {
+      BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
+      ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
+      HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
+   }
+   else
+   {
+      ColorCount = SafeIconImage->icHeader.biClrUsed;
+      if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
+       {
+         ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
+       }
+      HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
+   }
+
+   /* make data point to the start of the XOR image data */
+   Data = (PBYTE)SafeIconImage + HeaderSize;
+
+   hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
+   DeleteDC(hScreenDc);
+   RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
+   return hIcon;
 }
 
 
-HANDLE STATIC
+static HANDLE
 LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuLoad)
 {
   HANDLE hResource;
   HANDLE h2Resource;
+  HANDLE hfRes;
   HANDLE hFile;
   HANDLE hSection;
   CURSORICONDIR* IconDIR;
   HDC hScreenDc;
   HANDLE hIcon;
   ULONG HeaderSize;
-  ULONG ColourCount;
+  ULONG ColorCount;
   PVOID Data;
   CURSORICONDIRENTRY* dirEntry;
   ICONIMAGE* SafeIconImage;
-  GRPICONDIR* IconResDir;
+  GRPCURSORICONDIR* IconResDir;
   INT id;
   ICONIMAGE *ResIcon;
 
-  if (fuLoad & LR_SHARED)
-    DbgPrint("FIXME: need LR_SHARED support Loading icon images\n");
-
   if (!(fuLoad & LR_LOADFROMFILE))
   {
       if (hinst == NULL)
          {
-           hinst = GetModuleHandle(L"USER32");         
+           hinst = GetModuleHandleW(L"USER32");
          }
-      hResource = FindResourceW(hinst, lpszName, RT_GROUP_ICON);
+      hResource = hfRes = FindResourceW(hinst, lpszName, RT_GROUP_ICON);
       if (hResource == NULL)
          {
            return(NULL);
          }
 
+      if (fuLoad & LR_SHARED)
+          {
+            hIcon = NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, width, height);
+            if(hIcon)
+              return hIcon;
+          }
+
       hResource = LoadResource(hinst, hResource);
       if (hResource == NULL)
          {
@@ -130,9 +315,9 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
       id = LookupIconIdFromDirectoryEx((PBYTE) IconResDir, TRUE,
                 width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
 
-         h2Resource = FindResource(hinst,
-                     MAKEINTRESOURCE(id),
-                     MAKEINTRESOURCE(RT_ICON));
+         h2Resource = FindResourceW(hinst,
+                     MAKEINTRESOURCEW(id),
+                     MAKEINTRESOURCEW(RT_ICON));
 
       hResource = LoadResource(hinst, h2Resource);
       if (hResource == NULL)
@@ -145,13 +330,32 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
          {
            return(NULL);
          }
-      return CreateIconFromResourceEx((PBYTE) ResIcon,
-                  SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
-                  width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
+      hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE) ResIcon,
+                        SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
+                        width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
+      if (hIcon && 0 != (fuLoad & LR_SHARED))
+      {
+        NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
+                                (HRSRC)NULL);
+      }
+      return hIcon;
   }
   else
   {
-      hFile = CreateFile(lpszName,
+      /*
+       * FIXME: This code is incorrect and is likely to crash in many cases.
+       * In the file the cursor/icon directory records are stored like
+       * CURSORICONFILEDIR, but we treat them like CURSORICONDIR. In Wine
+       * this is solved by creating a fake cursor/icon directory in memory
+       * and passing that to CURSORICON_FindBestIcon.
+       */
+
+      if (fuLoad & LR_SHARED)
+      {
+        DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
+      }
+
+      hFile = CreateFileW(lpszName,
                         GENERIC_READ,
                         FILE_SHARE_READ,
                         NULL,
@@ -159,11 +363,11 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
                         0,
                         NULL);
       if (hFile == NULL)
-         {
-           return(NULL);
-         }
+      {
+          return NULL;
+      }
 
-      hSection = CreateFileMapping(hFile,
+      hSection = CreateFileMappingW(hFile,
                                   NULL,
                                   PAGE_READONLY,
                                   0,
@@ -172,37 +376,40 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
 
       CloseHandle(hFile);
       if (hSection == NULL)
-         {
-           return(NULL);
-         }
+      {
+          return NULL;
+      }
+
       IconDIR = MapViewOfFile(hSection,
                                 FILE_MAP_READ,
                                 0,
                                 0,
                                 0);
-
       CloseHandle(hSection);
       if (IconDIR == NULL)
-         {
-           return(NULL);
-         }
+      {
+          return NULL;
+      }
+      
+      if (0 != IconDIR->idReserved ||
+          (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
+      {
+          UnmapViewOfFile(IconDIR);
+          return NULL;
+      }
 
       //pick the best size.
       dirEntry = (CURSORICONDIRENTRY *)  CURSORICON_FindBestIcon( IconDIR, width, height, 1);
-
-
       if (!dirEntry)
-         {
-         if (fuLoad & LR_LOADFROMFILE)
-                {
-              UnmapViewOfFile(IconDIR);
-                }
-         return(NULL);
-         }
+      {
+          UnmapViewOfFile(IconDIR);
+          return NULL;
+      }
 
-      SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, dirEntry->dwBytesInRes); 
+      SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
 
       memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
+      UnmapViewOfFile(IconDIR);
   }
 
   //at this point we have a copy of the icon image to play with
@@ -212,19 +419,19 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
   if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
     {
       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
-      ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
-      HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
+      ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
+      HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
     }
   else
     {
-      ColourCount = SafeIconImage->icHeader.biClrUsed;
-      if (ColourCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
+      ColorCount = SafeIconImage->icHeader.biClrUsed;
+      if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
        {
-         ColourCount = 1 << SafeIconImage->icHeader.biBitCount;
+         ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
        }
-      HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
+      HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
     }
-  
+
   //make data point to the start of the XOR image data
   Data = (PBYTE)SafeIconImage + HeaderSize;
 
@@ -234,20 +441,19 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
   if (hScreenDc == NULL)
   {
       if (fuLoad & LR_LOADFROMFILE)
-         {
-               RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
-        UnmapViewOfFile(IconDIR);
-         }
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
+      }
       return(NULL);
   }
 
-  hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height);
-  RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
+  hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
+  RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
   return hIcon;
 }
 
 
-HANDLE STATIC
+static HANDLE
 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
 {
   HANDLE hResource;
@@ -258,14 +464,14 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
   HDC hScreenDc;
   HANDLE hBitmap;
   ULONG HeaderSize;
-  ULONG ColourCount;
+  ULONG ColorCount;
   PVOID Data;
 
   if (!(fuLoad & LR_LOADFROMFILE))
     {
       if (hInstance == NULL)
        {
-         hInstance = GetModuleHandle(L"USER32");               
+         hInstance = GetModuleHandleW(L"USER32");
        }
       hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
       if (hResource == NULL)
@@ -285,7 +491,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
     }
   else
     {
-      hFile = CreateFile(lpszName,
+      hFile = CreateFileW(lpszName,
                         GENERIC_READ,
                         FILE_SHARE_READ,
                         NULL,
@@ -296,7 +502,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
        {
          return(NULL);
        }
-      hSection = CreateFileMapping(hFile,
+      hSection = CreateFileMappingW(hFile,
                                   NULL,
                                   PAGE_READONLY,
                                   0,
@@ -304,7 +510,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
                                   NULL);
       CloseHandle(hFile);
       if (hSection == NULL)
-       {               
+       {
          return(NULL);
        }
       BitmapInfo = MapViewOfFile(hSection,
@@ -326,21 +532,21 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
   if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
     {
       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
-      ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
-      HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
+      ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
+      HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
     }
   else
     {
-      ColourCount = BitmapInfo->bmiHeader.biClrUsed;
-      if (ColourCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
+      ColorCount = BitmapInfo->bmiHeader.biClrUsed;
+      if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
        {
-         ColourCount = 1 << BitmapInfo->bmiHeader.biBitCount;
+         ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
        }
-      HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
+      HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
     }
-  Data = (PVOID)BitmapInfo + HeaderSize;
+  Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
 
-  PrivateInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, HeaderSize);
+  PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
   if (PrivateInfo == NULL)
     {
       if (fuLoad & LR_LOADFROMFILE)
@@ -351,11 +557,12 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
     }
   memcpy(PrivateInfo, BitmapInfo, HeaderSize);
 
-  /* FIXME: Handle colour conversion and transparency. */
+  /* FIXME: Handle color conversion and transparency. */
 
-  hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
+  hScreenDc = CreateCompatibleDC(NULL);
   if (hScreenDc == NULL)
     {
+      RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
       if (fuLoad & LR_LOADFROMFILE)
        {
          UnmapViewOfFile(BitmapInfo);
@@ -367,7 +574,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
     {
       DIBSECTION Dib;
 
-      hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL, 
+      hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
                                 0, 0);
       GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
       SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
@@ -379,8 +586,8 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
                               Data, PrivateInfo, DIB_RGB_COLORS);
     }
 
-  RtlFreeHeap(RtlGetProcessHeap(), 0, PrivateInfo);
-  /*DeleteDC(hScreenDc);*/
+  RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
+  DeleteDC(hScreenDc);
   if (fuLoad & LR_LOADFROMFILE)
     {
       UnmapViewOfFile(BitmapInfo);
@@ -395,7 +602,7 @@ LoadImageW(HINSTANCE hinst,
           int cxDesired,
           int cyDesired,
           UINT fuLoad)
-{  
+{
   if (fuLoad & LR_DEFAULTSIZE)
     {
       if (uType == IMAGE_ICON)
@@ -462,3 +669,62 @@ LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
 {
   return(LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
 }
+
+
+/*
+ * @unimplemented
+ */
+HANDLE WINAPI
+CopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
+{
+    HBITMAP res;
+    BITMAP bm;
+
+       switch (type)
+       {
+        case IMAGE_BITMAP:
+                       {
+                               DbgPrint("WARNING:  Incomplete implementation of CopyImage!\n");
+                       /* FIXME:  support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
+                                                                LR_COPYRETURNORG, LR_CREATEDIBSECTION,
+                                                                and LR_MONOCHROME; */
+
+                               if (!GetObjectW(hnd, sizeof(bm), &bm)) return 0;
+                               bm.bmBits = NULL;
+                               if ((res = CreateBitmapIndirect(&bm)))
+                               {
+                    char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
+                                       if (buf == NULL)
+                                       {
+                                               DeleteObject(res);
+                                               return NULL;
+                                       }
+                                       GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
+                                       SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
+                                       HeapFree(GetProcessHeap(), 0, buf);
+                               }
+                return res;
+                       }
+               case IMAGE_ICON:
+                       {
+                               static BOOL IconMsgDisplayed = FALSE;
+                               /* FIXME: support loading the image as shared from an instance */
+                               if (!IconMsgDisplayed) {
+                                       DbgPrint("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
+                                       IconMsgDisplayed = TRUE;
+                               }
+                       return CopyIcon(hnd);
+                       }
+               case IMAGE_CURSOR:
+                       {
+                               static BOOL IconMsgDisplayed = FALSE;
+                               /* FIXME: support loading the image as shared from an instance */
+                               if (!IconMsgDisplayed) {
+                                       DbgPrint("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
+                                       IconMsgDisplayed = TRUE;
+                               }
+                               return CopyCursor(hnd);
+                       }
+       }
+       return 0;
+}