[user32]
[reactos.git] / reactos / dll / win32 / user32 / windows / bitmap.c
index 69c9f15..41486c5 100644 (file)
@@ -31,6 +31,7 @@
 #include <user32.h>
 
 #include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(user32);
 
 #include "pshpack1.h"
 
@@ -55,9 +56,8 @@ typedef struct
 
 #include "poppack.h"
 
-/*forward declerations... actualy in user32\windows\icon.c but usful here****/
-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);
+/* forward declarations... actually in user32\windows\icon.c but useful here */
+HICON CreateCursorIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot, BOOL fIcon);
 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
 
@@ -66,7 +66,7 @@ CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, in
 /*
  * @implemented
  */
-HANDLE STDCALL
+HANDLE WINAPI
 LoadImageA(HINSTANCE hinst,
           LPCSTR lpszName,
           UINT uType,
@@ -246,6 +246,8 @@ LoadCursorIconImage(
          {
             return hIcon;
          }
+         else
+             TRACE("Didn't find the shared icon!!\n");
       }
 
       hResource = LoadResource(hinst, hResInfo);
@@ -263,12 +265,19 @@ LoadCursorIconImage(
       hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
                                        SizeofResource(hinst, hResInfo),
                                        Icon, 0x00030000, width, height,
-                                       fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
+                                       (fuLoad & (LR_DEFAULTSIZE | LR_SHARED)) | LR_DEFAULTCOLOR);
 
       if (hIcon && 0 != (fuLoad & LR_SHARED))
       {
+#if 1
          NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, hResInfo,
                                  (HRSRC)NULL);
+#else
+         ICONINFO iconInfo;
+
+         if(NtUserGetIconInfo(ResIcon, &iconInfo, NULL, NULL, NULL, FALSE))
+            NtUserSetCursorIconData((HICON)hIcon, hinst, NULL, &iconInfo);
+#endif
       }
 
       return hIcon;
@@ -276,7 +285,7 @@ LoadCursorIconImage(
 
    if (fuLoad & LR_SHARED)
    {
-      DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
+      FIXME("Need LR_SHARED support for loading icon images from files\n");
    }
 
    hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
@@ -319,12 +328,6 @@ LoadCursorIconImage(
    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. */
@@ -381,7 +384,7 @@ LoadCursorIconImage(
    /* Make data point to the start of the XOR image data. */
    Data = (PBYTE)SafeIconImage + HeaderSize;
 
-   hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
+   hIcon = CreateCursorIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2, Icon);
    RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
    DeleteDC(hScreenDc);
 
@@ -402,6 +405,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
    ULONG HeaderSize;
    ULONG ColorCount;
    PVOID Data;
+   BOOL Hit = FALSE;
 
    if (!(fuLoad & LR_LOADFROMFILE))
    {
@@ -438,18 +442,26 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
       BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
    }
 
-   if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+   HeaderSize = BitmapInfo->bmiHeader.biSize;
+   if (HeaderSize == sizeof(BITMAPCOREHEADER))
    {
       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
       ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
-      HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
+      HeaderSize += ColorCount * sizeof(RGBTRIPLE);
    }
    else
    {
-      ColorCount = BitmapInfo->bmiHeader.biClrUsed;
-      if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
-         ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
-      HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
+      if (BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
+      {
+         HeaderSize += 3 * sizeof(RGBQUAD);
+      }
+      else
+      {
+         ColorCount = BitmapInfo->bmiHeader.biClrUsed;
+         if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
+            ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
+         HeaderSize += ColorCount * sizeof(RGBQUAD);
+      }
    }
    Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
 
@@ -460,8 +472,26 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
          UnmapViewOfFile(BitmapInfo);
       return NULL;
    }
+
+   _SEH2_TRY
+   {
    memcpy(PrivateInfo, BitmapInfo, HeaderSize);
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      Hit = TRUE;
+   }
+   _SEH2_END;
 
+   if (Hit)
+   {
+      ERR("We have a thread overrun, these are already freed! pi -> %d, bi -> %d\n", PrivateInfo, BitmapInfo);
+      RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
+      if (fuLoad & LR_LOADFROMFILE)
+         UnmapViewOfFile(BitmapInfo);
+      return NULL;
+   }
+   
    /* FIXME: Handle color conversion and transparency. */
 
    hScreenDc = CreateCompatibleDC(NULL);
@@ -497,7 +527,7 @@ LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
    return hBitmap;
 }
 
-HANDLE STDCALL
+HANDLE WINAPI
 LoadImageW(
    IN HINSTANCE hinst,
    IN LPCWSTR lpszName,
@@ -543,7 +573,7 @@ LoadImageW(
 /*
  * @implemented
  */
-HBITMAP STDCALL
+HBITMAP WINAPI
 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
 {
    return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
@@ -553,230 +583,322 @@ LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
 /*
  * @implemented
  */
-HBITMAP STDCALL
+HBITMAP WINAPI
 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
 {
    return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
 }
 
 
-/*
- * @unimplemented
- */
-HANDLE WINAPI
-CopyImage(
-   IN HANDLE hnd,
-   IN UINT type,
-   IN INT desiredx,
-   IN INT desiredy,
-   IN UINT flags)
+static HANDLE
+CopyBmp(HANDLE hnd,
+        UINT type,
+        INT desiredx,
+        INT desiredy,
+        UINT flags)
 {
-/*
- * BUGS
- *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
- *    all other versions (95/2000/XP have been tested) ignore it.
- *
- * NOTES
- *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
- *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
- *    the copy will have the same depth as the screen.
- *    The content of the image will only be copied if the bit depth of the
- *    original image is compatible with the bit depth of the screen, or
- *    if the source is a DIB section.
- *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
- */
-   switch (type)
-   {
-      case IMAGE_BITMAP:
-         {
-            HBITMAP res = NULL;
-            DIBSECTION ds;
-            int objSize;
-            BITMAPINFO * bi;
+    HBITMAP res = NULL;
+    DIBSECTION ds;
+    int objSize;
+    BITMAPINFO * bi;
+
+    objSize = GetObjectW( hnd, sizeof(ds), &ds );
+    if (!objSize) return 0;
+    if ((desiredx < 0) || (desiredy < 0)) return 0;
+
+    if (flags & LR_COPYFROMRESOURCE)
+    {
+        FIXME("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
+    }
+
+    if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
+    if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
+
+    /* Allocate memory for a BITMAPINFOHEADER structure and a
+       color table. The maximum number of colors in a color table
+       is 256 which corresponds to a bitmap with depth 8.
+       Bitmaps with higher depths don't have color tables. */
+    bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    if (!bi) return 0;
+
+    bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
+    bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
+    bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
+    bi->bmiHeader.biCompression = BI_RGB;
+
+    if (flags & LR_CREATEDIBSECTION)
+    {
+        /* Create a DIB section. LR_MONOCHROME is ignored */
+        void * bits;
+        HDC dc = CreateCompatibleDC(NULL);
+
+        if (objSize == sizeof(DIBSECTION))
+        {
+            /* The source bitmap is a DIB.
+               Get its attributes to create an exact copy */
+            memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
+        }
+
+        /* Get the color table or the color masks */
+        GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+
+        bi->bmiHeader.biWidth  = desiredx;
+        bi->bmiHeader.biHeight = desiredy;
+        bi->bmiHeader.biSizeImage = 0;
+
+        res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
+        DeleteDC(dc);
+    }
+    else
+    {
+        /* Create a device-dependent bitmap */
 
-            objSize = GetObjectW( hnd, sizeof(ds), &ds );
-            if (!objSize) return 0;
-            if ((desiredx < 0) || (desiredy < 0)) return 0;
+        BOOL monochrome = (flags & LR_MONOCHROME);
 
-            if (flags & LR_COPYFROMRESOURCE)
+        if (objSize == sizeof(DIBSECTION))
+        {
+            /* The source bitmap is a DIB section.
+               Get its attributes */
+            HDC dc = CreateCompatibleDC(NULL);
+            bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
+            bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
+            GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+            DeleteDC(dc);
+
+            if (!monochrome && ds.dsBm.bmBitsPixel == 1)
             {
-                DPRINT1("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
+                /* Look if the colors of the DIB are black and white */
+
+                monochrome =
+                      (bi->bmiColors[0].rgbRed == 0xff
+                    && bi->bmiColors[0].rgbGreen == 0xff
+                    && bi->bmiColors[0].rgbBlue == 0xff
+                    && bi->bmiColors[0].rgbReserved == 0
+                    && bi->bmiColors[1].rgbRed == 0
+                    && bi->bmiColors[1].rgbGreen == 0
+                    && bi->bmiColors[1].rgbBlue == 0
+                    && bi->bmiColors[1].rgbReserved == 0)
+                    ||
+                      (bi->bmiColors[0].rgbRed == 0
+                    && bi->bmiColors[0].rgbGreen == 0
+                    && bi->bmiColors[0].rgbBlue == 0
+                    && bi->bmiColors[0].rgbReserved == 0
+                    && bi->bmiColors[1].rgbRed == 0xff
+                    && bi->bmiColors[1].rgbGreen == 0xff
+                    && bi->bmiColors[1].rgbBlue == 0xff
+                    && bi->bmiColors[1].rgbReserved == 0);
             }
+        }
+        else if (!monochrome)
+        {
+            monochrome = ds.dsBm.bmBitsPixel == 1;
+        }
+
+        if (monochrome)
+        {
+            res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
+        }
+        else
+        {
+            HDC screenDC = GetDC(NULL);
+            res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
+            ReleaseDC(NULL, screenDC);
+        }
+    }
 
-            if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
-            if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
+    if (res)
+    {
+        /* Only copy the bitmap if it's a DIB section or if it's
+           compatible to the screen */
+        BOOL copyContents;
 
-            /* Allocate memory for a BITMAPINFOHEADER structure and a
-               color table. The maximum number of colors in a color table
-               is 256 which corresponds to a bitmap with depth 8.
-               Bitmaps with higher depths don't have color tables. */
-            bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-            if (!bi) return 0;
+        if (objSize == sizeof(DIBSECTION))
+        {
+            copyContents = TRUE;
+        }
+        else
+        {
+            HDC screenDC = GetDC(NULL);
+            int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
+            ReleaseDC(NULL, screenDC);
 
-            bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
-            bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
-            bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
-            bi->bmiHeader.biCompression = BI_RGB;
+            copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
+        }
 
-            if (flags & LR_CREATEDIBSECTION)
-            {
-                /* Create a DIB section. LR_MONOCHROME is ignored */
-                void * bits;
-                HDC dc = CreateCompatibleDC(NULL);
+        if (copyContents)
+        {
+            /* The source bitmap may already be selected in a device context,
+               use GetDIBits/StretchDIBits and not StretchBlt  */
 
-                if (objSize == sizeof(DIBSECTION))
-                {
-                    /* The source bitmap is a DIB.
-                       Get its attributes to create an exact copy */
-                    memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
-                }
+            HDC dc;
+            void * bits;
 
-                /* Get the color table or the color masks */
-                GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+            dc = CreateCompatibleDC(NULL);
 
-                bi->bmiHeader.biWidth  = desiredx;
-                bi->bmiHeader.biHeight = desiredy;
-                bi->bmiHeader.biSizeImage = 0;
+            bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
+            bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
+            bi->bmiHeader.biSizeImage = 0;
+            bi->bmiHeader.biClrUsed = 0;
+            bi->bmiHeader.biClrImportant = 0;
 
-                res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
-                DeleteDC(dc);
-            }
-            else
+            /* Fill in biSizeImage */
+            GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+            bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
+
+            if (bits)
             {
-                /* Create a device-dependent bitmap */
+                HBITMAP oldBmp;
 
-                BOOL monochrome = (flags & LR_MONOCHROME);
+                /* Get the image bits of the source bitmap */
+                GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
 
-                if (objSize == sizeof(DIBSECTION))
-                {
-                    /* The source bitmap is a DIB section.
-                       Get its attributes */
-                    HDC dc = CreateCompatibleDC(NULL);
-                    bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
-                    bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
-                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
-                    DeleteDC(dc);
-
-                    if (!monochrome && ds.dsBm.bmBitsPixel == 1)
-                    {
-                        /* Look if the colors of the DIB are black and white */
-
-                        monochrome =
-                              (bi->bmiColors[0].rgbRed == 0xff
-                            && bi->bmiColors[0].rgbGreen == 0xff
-                            && bi->bmiColors[0].rgbBlue == 0xff
-                            && bi->bmiColors[0].rgbReserved == 0
-                            && bi->bmiColors[1].rgbRed == 0
-                            && bi->bmiColors[1].rgbGreen == 0
-                            && bi->bmiColors[1].rgbBlue == 0
-                            && bi->bmiColors[1].rgbReserved == 0)
-                            ||
-                              (bi->bmiColors[0].rgbRed == 0
-                            && bi->bmiColors[0].rgbGreen == 0
-                            && bi->bmiColors[0].rgbBlue == 0
-                            && bi->bmiColors[0].rgbReserved == 0
-                            && bi->bmiColors[1].rgbRed == 0xff
-                            && bi->bmiColors[1].rgbGreen == 0xff
-                            && bi->bmiColors[1].rgbBlue == 0xff
-                            && bi->bmiColors[1].rgbReserved == 0);
-                    }
-                }
-                else if (!monochrome)
-                {
-                    monochrome = ds.dsBm.bmBitsPixel == 1;
-                }
+                /* Copy it to the destination bitmap */
+                oldBmp = SelectObject(dc, res);
+                StretchDIBits(dc, 0, 0, desiredx, desiredy,
+                              0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
+                              bits, bi, DIB_RGB_COLORS, SRCCOPY);
+                SelectObject(dc, oldBmp);
 
-                if (monochrome)
-                {
-                    res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
-                }
-                else
-                {
-                    HDC screenDC = GetDC(NULL);
-                    res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
-                    ReleaseDC(NULL, screenDC);
-                }
+                HeapFree(GetProcessHeap(), 0, bits);
             }
 
-            if (res)
-            {
-                /* Only copy the bitmap if it's a DIB section or if it's
-                   compatible to the screen */
-                BOOL copyContents;
+            DeleteDC(dc);
+        }
 
-                if (objSize == sizeof(DIBSECTION))
-                {
-                    copyContents = TRUE;
-                }
-                else
-                {
-                    HDC screenDC = GetDC(NULL);
-                    int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
-                    ReleaseDC(NULL, screenDC);
+        if (flags & LR_COPYDELETEORG)
+        {
+            DeleteObject(hnd);
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, bi);
+    return res;
+}
 
-                    copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
-                }
 
-                if (copyContents)
-                {
-                    /* The source bitmap may already be selected in a device context,
-                       use GetDIBits/StretchDIBits and not StretchBlt  */
+INT
+GetIconCurBpp(PICONINFO pIconInfo)
+{
+    PBITMAPINFO pbi;
+
+    pbi = (PBITMAPINFO)pIconInfo->hbmColor;
+    return pbi->bmiHeader.biBitCount;
+}
 
-                    HDC dc;
-                    void * bits;
+#if 0
+static BOOL
+SetCursorIconData(
+  HANDLE Handle,
+  HINSTANCE hMod,
+  LPWSTR lpResName,
+  PICONINFO pIconInfo)
+{
 
-                    dc = CreateCompatibleDC(NULL);
+    UNICODE_STRING Res;
 
-                    bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
-                    bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
-                    bi->bmiHeader.biSizeImage = 0;
-                    bi->bmiHeader.biClrUsed = 0;
-                    bi->bmiHeader.biClrImportant = 0;
+    if (!Handle || !pIconInfo)
+        return FALSE;
 
-                    /* Fill in biSizeImage */
-                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
-                    bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
+    RtlInitUnicodeString(&Res, lpResName);
 
-                    if (bits)
-                    {
-                        HBITMAP oldBmp;
+    return NtUserSetCursorIconData(Handle, hMod, &Res, pIconInfo);
 
-                        /* Get the image bits of the source bitmap */
-                        GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
+}
 
-                        /* Copy it to the destination bitmap */
-                        oldBmp = SelectObject(dc, res);
-                        StretchDIBits(dc, 0, 0, desiredx, desiredy,
-                                      0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
-                                      bits, bi, DIB_RGB_COLORS, SRCCOPY);
-                        SelectObject(dc, oldBmp);
 
-                        HeapFree(GetProcessHeap(), 0, bits);
-                    }
+/* bare bones icon copy implementation */
+static HANDLE
+CopyIcoCur(HANDLE hIconCur,
+           UINT type,
+           INT desiredx,
+           INT desiredy,
+           UINT flags)
+{
+    HANDLE hNewIcon = NULL;
+    ICONINFO origIconInfo, newIconInfo;
+    SIZE origSize;
+    DWORD origBpp;
 
-                    DeleteDC(dc);
-                }
+    if (!hIconCur)
+        return NULL;
+
+    if (flags & LR_COPYFROMRESOURCE)
+    {
+        TRACE("FIXME: LR_COPYFROMRESOURCE is yet not implemented for icons\n");
+    }
+
+    if (NtUserGetIconSize(hIconCur, 0, &origSize.cx, &origSize.cy))
+    {
+        if (desiredx == 0) desiredx = origSize.cx;
+        if (desiredx == 0) desiredy = origSize.cy;
+
+        if (NtUserGetIconInfo(hIconCur, &origIconInfo, NULL, NULL, &origBpp, TRUE))
+        {
+            hNewIcon = (HANDLE)NtUserCallOneParam(0, ONEPARAM_ROUTINE_CREATECURICONHANDLE);
 
-                if (flags & LR_COPYDELETEORG)
+            if (hNewIcon)
+            {
+                /* the bitmaps returned from the NtUserGetIconInfo are copies of the original,
+                 * so we can use these directly to build up our icon/cursor copy */
+                RtlCopyMemory(&newIconInfo, &origIconInfo, sizeof(ICONINFO));
+
+                if (!SetCursorIconData(hNewIcon, NULL, NULL, &newIconInfo))
                 {
-                    DeleteObject(hnd);
+                    if (newIconInfo.fIcon)
+                        DestroyIcon(hNewIcon);
+                    else
+                        DestroyCursor(hNewIcon);
+
+                    hNewIcon = NULL;
                 }
             }
-            HeapFree(GetProcessHeap(), 0, bi);
-            return (HICON)res;
-         }
+
+            DeleteObject(origIconInfo.hbmMask);
+            DeleteObject(origIconInfo.hbmColor);
+        }
+    }
+
+    if (hNewIcon && (flags & LR_COPYDELETEORG))
+    {
+        DestroyCursor((HCURSOR)hIconCur);
+    }
+
+    return hNewIcon;
+}
+#endif
+
+/*
+ * @unimplemented
+ */
+HANDLE WINAPI
+CopyImage(
+   IN HANDLE hnd,
+   IN UINT type,
+   IN INT desiredx,
+   IN INT desiredy,
+   IN UINT flags)
+{
+/*
+ * BUGS
+ *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
+ *    all other versions (95/2000/XP have been tested) ignore it.
+ *
+ * NOTES
+ *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
+ *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
+ *    the copy will have the same depth as the screen.
+ *    The content of the image will only be copied if the bit depth of the
+ *    original image is compatible with the bit depth of the screen, or
+ *    if the source is a DIB section.
+ *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
+ */
+   switch (type)
+   {
+      case IMAGE_BITMAP:
+        return CopyBmp(hnd, type, desiredx, desiredy, flags);
+
       case IMAGE_ICON:
-         {
-            static BOOL IconMsgDisplayed = FALSE;
-            /* FIXME: support loading the image as shared from an instance */
-            if (!IconMsgDisplayed)
-            {
-               DPRINT("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
-               IconMsgDisplayed = TRUE;
-            }
-            return CopyIcon(hnd);
-//            return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
-         }
+        //return CopyIcoCur(hnd, type, desiredx, desiredy, flags);
+          return CopyIcon(hnd);
 
       case IMAGE_CURSOR:
          {
@@ -784,16 +906,16 @@ CopyImage(
             /* FIXME: support loading the image as shared from an instance */
             if (!IconMsgDisplayed)
             {
-               DPRINT("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
+               FIXME("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
                IconMsgDisplayed = TRUE;
             }
             /* Should call CURSORICON_ExtCopy but more testing
              * needs to be done before we change this
              */
-            if (flags) DPRINT1("FIXME: Flags are ignored\n");
+            if (flags) FIXME("FIXME: Flags are ignored\n");
             return CopyCursor(hnd);
          }
    }
+
    return NULL;
 }
-