[ATL][ATL_APITEST] Add CImage initial implementation + tests, by Katayama Hirofumi...
authorMark Jansen <mark.jansen@reactos.org>
Thu, 18 Aug 2016 19:27:49 +0000 (19:27 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Thu, 18 Aug 2016 19:27:49 +0000 (19:27 +0000)
- Tests focus mainly on loading + saving images.
- The implementation is not perfect yet, see CImage_WIP.txt for test results.
- The GDI+ functions should be fixed before this test can pass fully, MS' ATL fails in ReactOS, but passes on Windows.

svn path=/trunk/; revision=72332

12 files changed:
reactos/sdk/lib/atl/atlcom.h
reactos/sdk/lib/atl/atlimage.h [new file with mode: 0644]
rostests/apitests/atl/CImage.cpp [new file with mode: 0644]
rostests/apitests/atl/CImage_WIP.txt [new file with mode: 0644]
rostests/apitests/atl/CMakeLists.txt
rostests/apitests/atl/ant.bmp [new file with mode: 0644]
rostests/apitests/atl/atl_apitest.rc
rostests/apitests/atl/cross.bmp [new file with mode: 0644]
rostests/apitests/atl/devenv/CImage.sln [new file with mode: 0644]
rostests/apitests/atl/devenv/CImage.vcxproj [new file with mode: 0644]
rostests/apitests/atl/resource.h
rostests/apitests/atl/testlist.c

index 98d0ca0..57121ff 100644 (file)
@@ -21,6 +21,8 @@
 
 #pragma once
 
+#include <cguid.h>          // for GUID_NULL
+
 namespace ATL
 {
 
diff --git a/reactos/sdk/lib/atl/atlimage.h b/reactos/sdk/lib/atl/atlimage.h
new file mode 100644 (file)
index 0000000..d964805
--- /dev/null
@@ -0,0 +1,1142 @@
+// PROJECT:        ReactOS ATL CImage
+// LICENSE:        Public Domain
+// PURPOSE:        Provides compatibility to Microsoft ATL
+// PROGRAMMERS:    Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
+
+#ifndef __ATLIMAGE_H__
+#define __ATLIMAGE_H__
+
+// !!!!
+// TODO: The backend (gdi+) that this class relies on is not yet complete!
+//       Before that is finished, this class will not be a perfect replacement.
+//       See rostest/apitests/atl/CImage_WIP.txt for test results.
+// !!!!
+
+// TODO: GetImporterFilterString, GetExporterFilterString, Load, Save
+// TODO: make CImage thread-safe
+
+#pragma once
+
+#include <atlcore.h>
+
+#include <wingdi.h>
+#include <cguid.h>          // for GUID_NULL
+#include <gdiplus.h>        // GDI+
+
+namespace ATL
+{
+
+class CImage
+{
+public:
+    // flags for CImage::Create/CreateEx
+    enum
+    {
+        createAlphaChannel = 1      // enable alpha
+    };
+
+    // orientation of DIB
+    enum DIBOrientation
+    {
+        DIBOR_DEFAULT,              // default
+        DIBOR_BOTTOMUP,             // bottom-up DIB
+        DIBOR_TOPDOWN               // top-down DIB
+    };
+
+    CImage() throw()
+    {
+        m_hbm = NULL;
+        m_hbmOld = NULL;
+        m_hDC = NULL;
+
+        m_eOrientation = DIBOR_DEFAULT;
+        m_bHasAlphaCh = false;
+        m_bIsDIBSec = false;
+        m_rgbTransColor = CLR_INVALID;
+        ZeroMemory(&m_ds, sizeof(m_ds));
+
+        if (GetCommon().AddRef() == 1)
+        {
+            GetCommon().LoadLib();
+        }
+    }
+
+    ~CImage()
+    {
+        Destroy();
+        ReleaseGDIPlus();
+    }
+
+    operator HBITMAP()
+    {
+        return m_hbm;
+    }
+
+public:
+    void Attach(HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT)
+    {
+        AttachInternal(hBitmap, eOrientation, -1);
+    }
+
+    HBITMAP Detach() throw()
+    {
+        m_eOrientation = DIBOR_DEFAULT;
+        m_bHasAlphaCh = false;
+        m_rgbTransColor = CLR_INVALID;
+        ZeroMemory(&m_ds, sizeof(m_ds));
+
+        HBITMAP hBitmap = m_hbm;
+        m_hbm = NULL;
+        return hBitmap;
+    }
+
+    HDC GetDC() const throw()
+    {
+        if (m_hDC)
+            return m_hDC;
+
+        m_hDC = ::CreateCompatibleDC(NULL);
+        m_hbmOld = ::SelectObject(m_hDC, m_hbm);
+        return m_hDC;
+    }
+
+    void ReleaseDC() const throw()
+    {
+        ATLASSERT(m_hDC);
+
+        if (m_hDC == NULL)
+            return;
+
+        if (m_hbmOld)
+        {
+            ::SelectObject(m_hDC, m_hbmOld);
+            m_hbmOld = NULL;
+        }
+        ::DeleteDC(m_hDC);
+        m_hDC = NULL;
+    }
+
+public:
+    BOOL AlphaBlend(HDC hDestDC,
+        int xDest, int yDest, int nDestWidth, int nDestHeight,
+        int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
+        BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const
+    {
+        ATLASSERT(IsTransparencySupported());
+
+        BLENDFUNCTION bf;
+        bf.BlendOp = bBlendOp;
+        bf.BlendFlags = 0;
+        bf.SourceConstantAlpha = bSrcAlpha;
+        bf.AlphaFormat = AC_SRC_ALPHA;
+
+        GetDC();
+        BOOL ret = ::AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                                m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL AlphaBlend(HDC hDestDC, int xDest, int yDest,
+                    BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const
+    {
+        int width = GetWidth();
+        int height = GetHeight();
+        return AlphaBlend(hDestDC, xDest, yDest, width, height, 0, 0,
+                          width, height, bSrcAlpha, bBlendOp);
+    }
+    BOOL AlphaBlend(HDC hDestDC, const POINT& pointDest,
+                    BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const
+    {
+        return AlphaBlend(hDestDC, pointDest.x, pointDest.y, bSrcAlpha, bBlendOp);
+    }
+    BOOL AlphaBlend(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc,
+                    BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const
+    {
+        return AlphaBlend(hDestDC, rectDest.left, rectDest.top,
+                          rectDest.right - rectDest.left,
+                          rectDest.bottom - rectDest.top,
+                          rectSrc.left, rectSrc.top,
+                          rectSrc.right - rectSrc.left,
+                          rectSrc.bottom - rectSrc.top,
+                          bSrcAlpha, bBlendOp);
+    }
+
+    BOOL BitBlt(HDC hDestDC, int xDest, int yDest,
+                int nDestWidth, int nDestHeight,
+                int xSrc, int ySrc, DWORD dwROP = SRCCOPY) const throw()
+    {
+        GetDC();
+        BOOL ret = ::BitBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                            m_hDC, xSrc, ySrc, dwROP);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL BitBlt(HDC hDestDC, int xDest, int yDest,
+                DWORD dwROP = SRCCOPY) const throw()
+    {
+        return BitBlt(hDestDC, xDest, yDest,
+                      GetWidth(), GetHeight(), 0, 0, dwROP);
+    }
+    BOOL BitBlt(HDC hDestDC, const POINT& pointDest,
+                DWORD dwROP = SRCCOPY) const throw()
+    {
+        return BitBlt(hDestDC, pointDest.x, pointDest.y, dwROP);
+    }
+    BOOL BitBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc,
+                DWORD dwROP = SRCCOPY) const throw()
+    {
+        return BitBlt(hDestDC, rectDest.left, rectDest.top,
+                      rectDest.right - rectDest.left,
+                      rectDest.bottom - rectDest.top,
+                      pointSrc.x, pointSrc.y, dwROP);
+    }
+
+    BOOL Create(int nWidth, int nHeight, int nBPP, DWORD dwFlags = 0) throw()
+    {
+        return CreateEx(nWidth, nHeight, nBPP, BI_RGB, NULL, dwFlags);
+    }
+
+    BOOL CreateEx(int nWidth, int nHeight, int nBPP, DWORD eCompression,
+                  const DWORD* pdwBitmasks = NULL, DWORD dwFlags = 0) throw()
+    {
+        return CreateInternal(nWidth, nHeight, nBPP, eCompression, pdwBitmasks, dwFlags);
+    }
+
+    void Destroy() throw()
+    {
+        if (m_hbm)
+        {
+            ::DeleteObject(Detach());
+        }
+    }
+
+    BOOL Draw(HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight,
+              int xSrc, int ySrc, int nSrcWidth, int nSrcHeight) const throw()
+    {
+        ATLASSERT(IsTransparencySupported());
+        if (m_bHasAlphaCh)
+        {
+            return AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                              xSrc, ySrc, nSrcWidth, nSrcHeight);
+        }
+        else if (m_rgbTransColor != CLR_INVALID)
+        {
+            COLORREF rgb;
+            if ((m_rgbTransColor & 0xFF000000) == 0x01000000)
+                rgb = RGBFromPaletteIndex(m_rgbTransColor & 0xFF);
+            else
+                rgb = m_rgbTransColor;
+            return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                                  xSrc, ySrc, nSrcWidth, nSrcHeight, rgb);
+        }
+        else
+        {
+            return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                              xSrc, ySrc, nSrcWidth, nSrcHeight);
+        }
+    }
+    BOOL Draw(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc) const throw()
+    {
+        return Draw(hDestDC, rectDest.left, rectDest.top,
+                    rectDest.right - rectDest.left,
+                    rectDest.bottom - rectDest.top,
+                    rectSrc.left, rectSrc.top,
+                    rectSrc.right - rectSrc.left,
+                    rectSrc.bottom - rectSrc.top);
+    }
+    BOOL Draw(HDC hDestDC, int xDest, int yDest) const throw()
+    {
+        return Draw(hDestDC, xDest, yDest, GetWidth(), GetHeight());
+    }
+    BOOL Draw(HDC hDestDC, const POINT& pointDest) const throw()
+    {
+        return Draw(hDestDC, pointDest.x, pointDest.y);
+    }
+    BOOL Draw(HDC hDestDC, int xDest, int yDest,
+              int nDestWidth, int nDestHeight) const throw()
+    {
+        return Draw(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                    0, 0, GetWidth(), GetHeight());
+    }
+    BOOL Draw(HDC hDestDC, const RECT& rectDest) const throw()
+    {
+        return Draw(hDestDC, rectDest.left, rectDest.top,
+                    rectDest.right - rectDest.left,
+                    rectDest.bottom - rectDest.top);
+    }
+
+    void *GetBits() throw()
+    {
+        ATLASSERT(IsDIBSection());
+        BYTE *pb = (BYTE *)m_bm.bmBits;
+        if (m_eOrientation == DIBOR_BOTTOMUP)
+        {
+            pb += m_bm.bmWidthBytes * (m_bm.bmHeight - 1);
+        }
+        return pb;
+    }
+
+    int GetBPP() const throw()
+    {
+        ATLASSERT(m_hbm);
+        return m_bm.bmBitsPixel;
+    }
+
+    void GetColorTable(UINT iFirstColor, UINT nColors,
+                       RGBQUAD* prgbColors) const throw()
+    {
+        ATLASSERT(IsDIBSection());
+        GetDC();
+        ::GetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors);
+        ReleaseDC();
+    }
+
+    int GetHeight() const throw()
+    {
+        ATLASSERT(m_hbm);
+        return m_bm.bmHeight;
+    }
+
+    int GetMaxColorTableEntries() const throw()
+    {
+        ATLASSERT(IsDIBSection());
+        if (m_ds.dsBmih.biClrUsed && m_ds.dsBmih.biBitCount < 16)
+            return m_ds.dsBmih.biClrUsed;
+        switch (m_bm.bmBitsPixel)
+        {
+            case 1:     return 2;
+            case 4:     return 16;
+            case 8:     return 256;
+            case 16: case 32:
+                if (m_ds.dsBmih.biCompression == BI_BITFIELDS)
+                    return 3;
+                return 0;
+            case 24:
+            default:
+                return 0;
+        }
+    }
+
+    int GetPitch() const throw()
+    {
+        ATLASSERT(IsDIBSection());
+        if (m_eOrientation == DIBOR_BOTTOMUP)
+            return -m_bm.bmWidthBytes;
+        else
+            return m_bm.bmWidthBytes;
+    }
+
+    COLORREF GetPixel(int x, int y) const throw()
+    {
+        GetDC();
+        COLORREF ret = ::GetPixel(m_hDC, x, y);
+        ReleaseDC();
+        return ret;
+    }
+
+    void* GetPixelAddress(int x, int y) throw()
+    {
+        ATLASSERT(IsDIBSection());
+        BYTE *pb = (BYTE *)GetBits();
+        pb += GetPitch() * y;
+        pb += (GetBPP() * x) / 8;
+        return pb;
+    }
+
+    COLORREF GetTransparentColor() const throw()
+    {
+        return m_rgbTransColor;
+    }
+
+    int GetWidth() const throw()
+    {
+        ATLASSERT(m_hbm);
+        return m_bm.bmWidth;
+    }
+
+    bool IsDIBSection() const throw()
+    {
+        ATLASSERT(m_hbm);
+        return m_bIsDIBSec;
+    }
+
+    bool IsIndexed() const throw()
+    {
+        ATLASSERT(IsDIBSection());
+        return GetBPP() <= 8;
+    }
+
+    bool IsNull() const throw()
+    {
+        return m_hbm == NULL;
+    }
+
+    HRESULT Load(LPCTSTR pszFileName) throw()
+    {
+        // convert the file name string into Unicode
+        // TODO: use a string class
+#ifdef UNICODE
+        LPCWSTR pszNameW = pszFileName;
+#else
+        WCHAR szPath[MAX_PATH];
+        ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH);
+        LPCWSTR pszNameW = szPath;
+#endif
+
+        // create a GpBitmap object from file
+        using namespace Gdiplus;
+        GpBitmap *pBitmap = NULL;
+        GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap);
+        ATLASSERT(pBitmap);
+
+        // TODO & FIXME: get parameters (m_rgbTransColor etc.)
+
+        // get bitmap handle
+        HBITMAP hbm = NULL;
+        Color color(0xFF, 0xFF, 0xFF);
+        Gdiplus::Status status;
+        status = GetCommon().CreateHBITMAPFromBitmap(
+            pBitmap, &hbm, color.GetValue());
+
+        // delete GpBitmap
+        GetCommon().DisposeImage(pBitmap);
+
+        // attach it
+        if (status == Ok)
+            Attach(hbm);
+        return (status == Ok ? S_OK : E_FAIL);
+    }
+    HRESULT Load(IStream* pStream) throw()
+    {
+        // create GpBitmap from stream
+        using namespace Gdiplus;
+        GpBitmap *pBitmap = NULL;
+        GetCommon().CreateBitmapFromStream(pStream, &pBitmap);
+        ATLASSERT(pBitmap);
+
+        // TODO & FIXME: get parameters (m_rgbTransColor etc.)
+
+        // get bitmap handle
+        HBITMAP hbm = NULL;
+        Color color(0xFF, 0xFF, 0xFF);
+        Gdiplus::Status status;
+        status = GetCommon().CreateHBITMAPFromBitmap(
+            pBitmap, &hbm, color.GetValue());
+
+        // delete Bitmap
+        GetCommon().DisposeImage(pBitmap);
+
+        // attach it
+        if (status == Ok)
+            Attach(hbm);
+        return (status == Ok ? S_OK : E_FAIL);
+    }
+
+    // NOTE: LoadFromResource loads BITMAP resource only
+    void LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName) throw()
+    {
+        HANDLE hHandle = ::LoadImage(hInstance, pszResourceName,
+                                     IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+        Attach(reinterpret_cast<HBITMAP>(hHandle));
+    }
+    void LoadFromResource(HINSTANCE hInstance, UINT nIDResource) throw()
+    {
+        LoadFromResource(hInstance, MAKEINTRESOURCE(nIDResource));
+    }
+
+    BOOL MaskBlt(HDC hDestDC, int xDest, int yDest,
+                 int nDestWidth, int nDestHeight, int xSrc, int ySrc,
+                 HBITMAP hbmMask, int xMask, int yMask,
+                 DWORD dwROP = SRCCOPY) const throw()
+    {
+        ATLASSERT(IsTransparencySupported());
+        GetDC();
+        BOOL ret = ::MaskBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                             m_hDC, xSrc, ySrc,
+                             hbmMask, xMask, yMask, dwROP);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL MaskBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc,
+                 HBITMAP hbmMask, const POINT& pointMask,
+                 DWORD dwROP = SRCCOPY) const throw()
+    {
+        return MaskBlt(hDestDC, rectDest.left, rectDest.top,
+            rectDest.right - rectDest.left, rectDest.bottom - rectDest.top,
+            pointSrc.x, pointSrc.y, hbmMask, pointMask.x, pointMask.y, dwROP);
+    }
+    BOOL MaskBlt(HDC hDestDC, int xDest, int yDest,
+                 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw()
+    {
+        return MaskBlt(hDestDC, xDest, yDest, GetWidth(), GetHeight(),
+                       0, 0, hbmMask, 0, 0, dwROP);
+    }
+    BOOL MaskBlt(HDC hDestDC, const POINT& pointDest,
+                 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw()
+    {
+        return MaskBlt(hDestDC, pointDest.x, pointDest.y, hbmMask, dwROP);
+    }
+
+    BOOL PlgBlt(HDC hDestDC, const POINT* pPoints,
+                int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
+                HBITMAP hbmMask = NULL,
+                int xMask = 0, int yMask = 0) const throw()
+    {
+        ATLASSERT(IsTransparencySupported());
+        GetDC();
+        BOOL ret = ::PlgBlt(hDestDC, pPoints, m_hDC,
+                            xSrc, ySrc, nSrcWidth, nSrcHeight,
+                            hbmMask, xMask, yMask);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL PlgBlt(HDC hDestDC, const POINT* pPoints,
+                HBITMAP hbmMask = NULL) const throw()
+    {
+        return PlgBlt(hDestDC, pPoints, 0, 0, GetWidth(), GetHeight(),
+                      hbmMask);
+    }
+    BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc,
+                HBITMAP hbmMask, const POINT& pointMask) const throw()
+    {
+        return PlgBlt(hDestDC, pPoints, rectSrc.left, rectSrc.top,
+            rectSrc.right - rectSrc.left, rectSrc.bottom - rectSrc.top,
+            hbmMask, pointMask.x, pointMask.y);
+    }
+    BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc,
+                HBITMAP hbmMask = NULL) const throw()
+    {
+        POINT pointMask = {0, 0};
+        return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask);
+    }
+
+    void ReleaseGDIPlus() throw()
+    {
+        COMMON*& pCommon = GetCommonPtr();
+        if (pCommon && pCommon->Release() == 0)
+        {
+            delete pCommon;
+            pCommon = NULL;
+        }
+    }
+
+    HRESULT Save(IStream* pStream, GUID *guidFileType) const throw()
+    {
+        using namespace Gdiplus;
+        ATLASSERT(m_hbm);
+
+        // TODO & FIXME: set parameters (m_rgbTransColor etc.)
+        CLSID clsid;
+        if (!GetClsidFromFileType(&clsid, guidFileType))
+            return E_FAIL;
+
+        // create a GpBitmap from HBITMAP
+        GpBitmap *pBitmap = NULL;
+        GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
+
+        // save to stream
+        Status status;
+        status = GetCommon().SaveImageToStream(pBitmap, pStream, &clsid, NULL);
+
+        // destroy GpBitmap
+        GetCommon().DisposeImage(pBitmap);
+
+        return (status == Ok ? S_OK : E_FAIL);
+    }
+    HRESULT Save(LPCTSTR pszFileName,
+                 REFGUID guidFileType = GUID_NULL) const throw()
+    {
+        using namespace Gdiplus;
+        ATLASSERT(m_hbm);
+
+        // TODO & FIXME: set parameters (m_rgbTransColor etc.)
+
+        // convert the file name string into Unicode
+        // TODO: use a string class
+#ifdef UNICODE
+        LPCWSTR pszNameW = pszFileName;
+#else
+        WCHAR szPath[MAX_PATH];
+        ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH);
+        LPCWSTR pszNameW = szPath;
+#endif
+
+        // if the file type is null, get the file type from extension
+        const GUID *FileType = &guidFileType;
+        if (IsGuidEqual(guidFileType, GUID_NULL))
+        {
+            LPCWSTR pszExt = GetFileExtension(pszNameW);
+            FileType = FileTypeFromExtension(pszExt);
+        }
+
+        // get CLSID from file type
+        CLSID clsid;
+        if (!GetClsidFromFileType(&clsid, FileType))
+            return E_FAIL;
+
+        // create a GpBitmap from HBITMAP
+        GpBitmap *pBitmap = NULL;
+        GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
+
+        // save to file
+        Status status;
+        status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
+
+        // destroy GpBitmap
+        GetCommon().DisposeImage(pBitmap);
+
+        return (status == Ok ? S_OK : E_FAIL);
+    }
+
+    void SetColorTable(UINT iFirstColor, UINT nColors,
+                       const RGBQUAD* prgbColors) throw()
+    {
+        ATLASSERT(IsDIBSection());
+        GetDC();
+        ::SetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors);
+        ReleaseDC();
+    }
+
+    void SetPixel(int x, int y, COLORREF color) throw()
+    {
+        GetDC();
+        ::SetPixelV(m_hDC, x, y, color);
+        ReleaseDC();
+    }
+
+    void SetPixelIndexed(int x, int y, int iIndex) throw()
+    {
+        ATLASSERT(IsIndexed());
+        GetDC();
+        ::SetPixelV(m_hDC, x, y, PALETTEINDEX(iIndex));
+        ReleaseDC();
+    }
+
+    void SetPixelRGB(int x, int y, BYTE r, BYTE g, BYTE b) throw()
+    {
+        SetPixel(x, y, RGB(r, g, b));
+    }
+
+    COLORREF SetTransparentColor(COLORREF rgbTransparent) throw()
+    {
+        ATLASSERT(m_hbm);
+        COLORREF rgbOldColor = m_rgbTransColor;
+        m_rgbTransColor = rgbTransparent;
+        return rgbOldColor;
+    }
+
+    BOOL StretchBlt(HDC hDestDC, int xDest, int yDest,
+                    int nDestWidth, int nDestHeight,
+                    int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
+                    DWORD dwROP = SRCCOPY) const throw()
+    {
+        GetDC();
+        BOOL ret = ::StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                                m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwROP);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL StretchBlt(HDC hDestDC, int xDest, int yDest,
+                    int nDestWidth, int nDestHeight,
+                    DWORD dwROP = SRCCOPY) const throw()
+    {
+        return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                          0, 0, GetWidth(), GetHeight(), dwROP);
+    }
+    BOOL StretchBlt(HDC hDestDC, const RECT& rectDest,
+                    DWORD dwROP = SRCCOPY) const throw()
+    {
+        return StretchBlt(hDestDC, rectDest.left, rectDest.top,
+                          rectDest.right - rectDest.left,
+                          rectDest.bottom - rectDest.top, dwROP);
+    }
+    BOOL StretchBlt(HDC hDestDC, const RECT& rectDest,
+                    const RECT& rectSrc, DWORD dwROP = SRCCOPY) const throw()
+    {
+        return StretchBlt(hDestDC, rectDest.left, rectDest.top,
+                          rectDest.right - rectDest.left,
+                          rectDest.bottom - rectDest.top,
+                          rectSrc.left, rectSrc.top,
+                          rectSrc.right - rectSrc.left,
+                          rectSrc.bottom - rectSrc.top, dwROP);
+    }
+
+    BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest,
+                        int nDestWidth, int nDestHeight,
+                        int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
+                        UINT crTransparent = CLR_INVALID) const throw()
+    {
+        ATLASSERT(IsTransparencySupported());
+        GetDC();
+        BOOL ret = ::TransparentBlt(hDestDC, xDest, yDest,
+                                    nDestWidth, nDestHeight,
+                                    m_hDC, xSrc, ySrc,
+                                    nSrcWidth, nSrcHeight, crTransparent);
+        ReleaseDC();
+        return ret;
+    }
+    BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest,
+                        int nDestWidth, int nDestHeight,
+                        UINT crTransparent = CLR_INVALID) const throw()
+    {
+        return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight,
+                              0, 0, GetWidth(), GetHeight(), crTransparent);
+    }
+    BOOL TransparentBlt(HDC hDestDC, const RECT& rectDest,
+                        UINT crTransparent = CLR_INVALID) const throw()
+    {
+        return TransparentBlt(hDestDC, rectDest.left, rectDest.top,
+                              rectDest.right - rectDest.left,
+                              rectDest.bottom - rectDest.top, crTransparent);
+    }
+    BOOL TransparentBlt(
+       HDC hDestDC, const RECT& rectDest,
+       const RECT& rectSrc, UINT crTransparent = CLR_INVALID) const throw()
+    {
+        return TransparentBlt(hDestDC, rectDest.left, rectDest.top,
+            rectDest.right - rectDest.left, rectDest.bottom - rectDest.left,
+            rectSrc.left, rectSrc.top, rectSrc.right - rectSrc.left,
+            rectSrc.bottom - rectSrc.top, crTransparent);
+    }
+
+public:
+    static BOOL IsTransparencySupported() throw()
+    {
+        return TRUE;
+    }
+
+#if 0
+    // TODO: implement this
+    static HRESULT GetImporterFilterString(
+        CSimpleString& strImporters,
+        CSimpleArray<GUID>& aguidFileTypes,
+        LPCTSTR pszAllFilesDescription = NULL,
+        DWORD dwExclude = excludeDefaultLoad,
+        TCHAR chSeparator = _T('|'))
+    {
+        ATLASSERT(0);
+        return -1;
+    }
+
+    // TODO: implement this
+    static HRESULT GetExporterFilterString(
+        CSimpleString& strExporters,
+        CSimpleArray<GUID>& aguidFileTypes,
+        LPCTSTR pszAllFilesDescription = NULL,
+        DWORD dwExclude = excludeDefaultSave,
+        TCHAR chSeparator = _T('|'))
+    {
+        ATLASSERT(0);
+        return -1;
+    }
+#endif  // 0
+
+protected:
+    // an extension of BITMAPINFO
+    struct MYBITMAPINFOEX
+    {
+        BITMAPINFOHEADER bmiHeader;
+        RGBQUAD bmiColors[256];
+        BITMAPINFO *get()
+        {
+            return reinterpret_cast<BITMAPINFO *>(this);
+        }
+        const BITMAPINFO *get() const
+        {
+            return reinterpret_cast<const BITMAPINFO *>(this);
+        }
+    };
+
+    // The common data of atlimage
+    struct COMMON
+    {
+        // abbreviations of GDI+ basic types
+        typedef Gdiplus::GpStatus St;
+        typedef Gdiplus::ImageCodecInfo ICI;
+        typedef Gdiplus::GpBitmap Bm;
+        typedef Gdiplus::EncoderParameters EncParams;
+        typedef Gdiplus::GpImage Im;
+        typedef Gdiplus::ARGB ARGB;
+        typedef HBITMAP HBM;
+        typedef Gdiplus::GdiplusStartupInput GSI;
+        typedef Gdiplus::GdiplusStartupOutput GSO;
+
+        // GDI+ function types
+#undef API
+#undef CST
+#define API WINGDIPAPI
+#define CST GDIPCONST
+        typedef St (WINAPI *STARTUP)(ULONG_PTR *, const GSI *, GSO *);
+        typedef void (WINAPI *SHUTDOWN)(ULONG_PTR);
+        typedef St (API *GETIMAGEENCODERSSIZE)(UINT *, UINT *);
+        typedef St (API *GETIMAGEENCODERS)(UINT, UINT, ICI *);
+        typedef St (API *CREATEBITMAPFROMFILE)(CST WCHAR*, Bm **);
+        typedef St (API *CREATEHBITMAPFROMBITMAP)(Bm *, HBM *, ARGB);
+        typedef St (API *CREATEBITMAPFROMSTREAM)(IStream *, Bm **);
+        typedef St (API *CREATEBITMAPFROMHBITMAP)(HBM, HPALETTE, Bm **);
+        typedef St (API *SAVEIMAGETOSTREAM)(Im *, IStream *, CST CLSID *,
+                                            CST EncParams *);
+        typedef St (API *SAVEIMAGETOFILE)(Im *, CST WCHAR *, CST CLSID *,
+                                          CST EncParams *);
+        typedef St (API *DISPOSEIMAGE)(Im*);
+#undef API
+#undef CST
+
+        // members
+        int                     count;
+        HINSTANCE               hinstGdiPlus;
+        ULONG_PTR               gdiplusToken;
+
+        // GDI+ functions
+        STARTUP                 Startup;
+        SHUTDOWN                Shutdown;
+        GETIMAGEENCODERSSIZE    GetImageEncodersSize;
+        GETIMAGEENCODERS        GetImageEncoders;
+        CREATEBITMAPFROMFILE    CreateBitmapFromFile;
+        CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap;
+        CREATEBITMAPFROMSTREAM  CreateBitmapFromStream;
+        CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP;
+        SAVEIMAGETOSTREAM       SaveImageToStream;
+        SAVEIMAGETOFILE         SaveImageToFile;
+        DISPOSEIMAGE            DisposeImage;
+
+        COMMON()
+        {
+            count = 0;
+            hinstGdiPlus = NULL;
+            Startup = NULL;
+            Shutdown = NULL;
+            GetImageEncodersSize = NULL;
+            GetImageEncoders = NULL;
+            CreateBitmapFromFile = NULL;
+            CreateHBITMAPFromBitmap = NULL;
+            CreateBitmapFromStream = NULL;
+            CreateBitmapFromHBITMAP = NULL;
+            SaveImageToStream = NULL;
+            SaveImageToFile = NULL;
+            DisposeImage = NULL;
+        }
+        ~COMMON()
+        {
+            FreeLib();
+        }
+
+        ULONG AddRef()
+        {
+            return ++count;
+        }
+        ULONG Release()
+        {
+            return --count;
+        }
+
+        // get procedure address of the DLL
+        template <typename TYPE>
+        TYPE AddrOf(const char *name)
+        {
+            FARPROC proc = ::GetProcAddress(hinstGdiPlus, name);
+            return reinterpret_cast<TYPE>(proc);
+        }
+
+        HINSTANCE LoadLib()
+        {
+            if (hinstGdiPlus)
+                return hinstGdiPlus;
+
+            hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
+
+            // get procedure addresses from the DLL
+            Startup = AddrOf<STARTUP>("GdiplusStartup");
+            Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown");
+            GetImageEncodersSize =
+                AddrOf<GETIMAGEENCODERSSIZE>("GdipGetImageEncodersSize");
+            GetImageEncoders = AddrOf<GETIMAGEENCODERS>("GdipGetImageEncoders");
+            CreateBitmapFromFile =
+                AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile");
+            CreateHBITMAPFromBitmap =
+                AddrOf<CREATEHBITMAPFROMBITMAP>("GdipCreateHBITMAPFromBitmap");
+            CreateBitmapFromStream =
+                AddrOf<CREATEBITMAPFROMSTREAM>("GdipCreateBitmapFromStream");
+            CreateBitmapFromHBITMAP =
+                AddrOf<CREATEBITMAPFROMHBITMAP>("GdipCreateBitmapFromHBITMAP");
+            SaveImageToStream =
+                AddrOf<SAVEIMAGETOSTREAM>("GdipSaveImageToStream");
+            SaveImageToFile = AddrOf<SAVEIMAGETOFILE>("GdipSaveImageToFile");
+            DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage");
+
+            if (hinstGdiPlus && Startup)
+            {
+                Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+                Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
+            }
+
+            return hinstGdiPlus;
+        }
+        void FreeLib()
+        {
+            if (hinstGdiPlus)
+            {
+                Shutdown(gdiplusToken);
+
+                Startup = NULL;
+                Shutdown = NULL;
+                GetImageEncodersSize = NULL;
+                GetImageEncoders = NULL;
+                CreateBitmapFromFile = NULL;
+                CreateHBITMAPFromBitmap = NULL;
+                CreateBitmapFromStream = NULL;
+                CreateBitmapFromHBITMAP = NULL;
+                SaveImageToStream = NULL;
+                SaveImageToFile = NULL;
+                DisposeImage = NULL;
+                ::FreeLibrary(hinstGdiPlus);
+                hinstGdiPlus = NULL;
+            }
+        }
+    }; // struct COMMON
+
+    static COMMON*& GetCommonPtr()
+    {
+        static COMMON *s_pCommon = NULL;
+        return s_pCommon;
+    }
+
+    static COMMON& GetCommon()
+    {
+        COMMON*& pCommon = GetCommonPtr();
+        if (pCommon == NULL)
+            pCommon = new COMMON;
+        return *pCommon;
+    }
+
+protected:
+    HBITMAP             m_hbm;
+    mutable HGDIOBJ     m_hbmOld;
+    mutable HDC         m_hDC;
+    DIBOrientation      m_eOrientation;
+    bool                m_bHasAlphaCh;
+    bool                m_bIsDIBSec;
+    COLORREF            m_rgbTransColor;
+    union
+    {
+        BITMAP          m_bm;
+        DIBSECTION      m_ds;
+    };
+
+    LPCWSTR GetFileExtension(LPCWSTR pszFileName) const
+    {
+        LPCWSTR pch = wcsrchr(pszFileName, L'\\');
+        if (pch == NULL)
+            pch = wcsrchr(pszFileName, L'/');
+        pch = (pch ? wcsrchr(pch, L'.') : wcsrchr(pszFileName, L'.'));
+        return (pch ? pch : (pszFileName + ::lstrlenW(pszFileName)));
+    }
+
+    COLORREF RGBFromPaletteIndex(int iIndex) const
+    {
+        RGBQUAD table[256];
+        GetColorTable(0, 256, table);
+        RGBQUAD& quad =  table[iIndex];
+        return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
+    }
+
+    struct EXTENSION_ENTRY
+    {
+        LPCWSTR pszExt;
+        GUID guid;
+    };
+
+    const GUID *FileTypeFromExtension(LPCWSTR pszExt) const
+    {
+        static const EXTENSION_ENTRY table[] =
+        {
+            {L".jpg", Gdiplus::ImageFormatJPEG},
+            {L".png", Gdiplus::ImageFormatPNG},
+            {L".bmp", Gdiplus::ImageFormatBMP},
+            {L".gif", Gdiplus::ImageFormatGIF},
+            {L".tif", Gdiplus::ImageFormatTIFF},
+            {L".jpeg", Gdiplus::ImageFormatJPEG},
+            {L".jpe", Gdiplus::ImageFormatJPEG},
+            {L".jfif", Gdiplus::ImageFormatJPEG},
+            {L".dib", Gdiplus::ImageFormatBMP},
+            {L".rle", Gdiplus::ImageFormatBMP},
+            {L".tiff", Gdiplus::ImageFormatTIFF}
+        };
+        const size_t count = _countof(table);
+        for (size_t i = 0; i < count; ++i)
+        {
+            if (::lstrcmpiW(table[i].pszExt, pszExt) == 0)
+                return &table[i].guid;
+        }
+        return NULL;
+    }
+
+    struct FORMAT_ENTRY
+    {
+        GUID guid;
+        LPCWSTR mime;
+    };
+
+    bool GetClsidFromFileType(CLSID *clsid, const GUID *guid) const
+    {
+        static const FORMAT_ENTRY table[] =
+        {
+            {Gdiplus::ImageFormatJPEG, L"image/jpeg"},
+            {Gdiplus::ImageFormatPNG, L"image/png"},
+            {Gdiplus::ImageFormatBMP, L"image/bmp"},
+            {Gdiplus::ImageFormatGIF, L"image/gif"},
+            {Gdiplus::ImageFormatTIFF, L"image/tiff"}
+        };
+        const size_t count = _countof(table);
+        for (size_t i = 0; i < count; ++i)
+        {
+            if (IsGuidEqual(table[i].guid, *guid))
+            {
+                int num = GetEncoderClsid(table[i].mime, clsid);
+                if (num >= 0)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    int GetEncoderClsid(LPCWSTR mime, CLSID *clsid) const
+    {
+        UINT count = 0, total_size = 0;
+        GetCommon().GetImageEncodersSize(&count, &total_size);
+        if (total_size == 0)
+            return -1;  // failure
+
+        Gdiplus::ImageCodecInfo *pInfo;
+        BYTE *pb = new BYTE[total_size];
+        ATLASSERT(pb);
+        pInfo = reinterpret_cast<Gdiplus::ImageCodecInfo *>(pb);
+        if (pInfo == NULL)
+            return -1;  // failure
+
+        GetCommon().GetImageEncoders(count, total_size, pInfo);
+
+        for (UINT iInfo = 0; iInfo < count; ++iInfo)
+        {
+            if (::lstrcmpiW(pInfo[iInfo].MimeType, mime) == 0)
+            {
+                *clsid = pInfo[iInfo].Clsid;
+                delete[] pb;
+                return iInfo;  // success
+            }
+        }
+
+        delete[] pb;
+        return -1;  // failure
+    }
+
+    bool IsGuidEqual(const GUID& guid1, const GUID& guid2) const
+    {
+        RPC_STATUS status;
+        if (::UuidEqual(const_cast<GUID *>(&guid1),
+                        const_cast<GUID *>(&guid2), &status))
+        {
+            if (status == RPC_S_OK)
+                return true;
+        }
+        return false;
+    }
+
+    void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation,
+                        LONG iTransColor)
+    {
+        Destroy();
+
+        const int size = sizeof(DIBSECTION);
+        m_bIsDIBSec = (::GetObject(hBitmap, size, &m_ds) == size);
+
+        bool bOK = (::GetObject(hBitmap, sizeof(BITMAP), &m_bm) != 0);
+
+        if (bOK)
+        {
+            m_hbm = hBitmap;
+            m_eOrientation = eOrientation;
+            m_bHasAlphaCh = (m_bm.bmBitsPixel == 32);
+            m_rgbTransColor = CLR_INVALID;
+        }
+    }
+
+    BOOL CreateInternal(int nWidth, int nHeight, int nBPP,
+                        DWORD eCompression, const DWORD* pdwBitmasks = NULL,
+                        DWORD dwFlags = 0) throw()
+    {
+        ATLASSERT(nWidth != 0);
+        ATLASSERT(nHeight != 0);
+
+        // initialize BITMAPINFO extension
+        MYBITMAPINFOEX bi;
+        ZeroMemory(&bi, sizeof(bi));
+        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+        bi.bmiHeader.biWidth = nWidth;
+        bi.bmiHeader.biHeight = nHeight;
+        bi.bmiHeader.biPlanes = 1;
+        bi.bmiHeader.biBitCount = nBPP;
+        bi.bmiHeader.biCompression = eCompression;
+
+        // is there alpha channel?
+        bool bHasAlphaCh;
+        bHasAlphaCh = (nBPP == 32 && (dwFlags & createAlphaChannel));
+
+        // get orientation
+        DIBOrientation eOrientation;
+        eOrientation = ((nHeight > 0) ? DIBOR_BOTTOMUP : DIBOR_TOPDOWN);
+
+        // does it have bit fields?
+        if (eCompression == BI_BITFIELDS)
+        {
+            if (nBPP == 16 || nBPP == 32)
+            {
+                // store the mask data
+                LPDWORD pdwMask = reinterpret_cast<LPDWORD>(bi.bmiColors);
+                pdwMask[0] = pdwBitmasks[0];
+                pdwMask[1] = pdwBitmasks[1];
+                pdwMask[2] = pdwBitmasks[2];
+            }
+            else
+            {
+                return FALSE;
+            }
+        }
+        else
+        {
+            ATLASSERT(pdwBitmasks == NULL);
+            if (pdwBitmasks)
+                return FALSE;
+        }
+
+        // create a DIB section
+        HDC hDC = ::CreateCompatibleDC(NULL);
+        ATLASSERT(hDC);
+        LPVOID pvBits;
+        HBITMAP hbm = ::CreateDIBSection(hDC, bi.get(), DIB_RGB_COLORS,
+                                         &pvBits, NULL, 0);
+        ATLASSERT(hbm);
+        ::DeleteDC(hDC);
+
+        // attach it
+        AttachInternal(hbm, eOrientation, -1);
+        m_bHasAlphaCh = bHasAlphaCh;
+
+        return hbm != NULL;
+    }
+
+private:
+    // NOTE: CImage is not copyable
+    CImage(const CImage&);
+    CImage& operator=(const CImage&);
+};
+
+}
+
+#endif
+
+#ifndef _ATL_NO_AUTOMATIC_NAMESPACE
+using namespace ATL;
+#endif //!_ATL_NO_AUTOMATIC_NAMESPACE
diff --git a/rostests/apitests/atl/CImage.cpp b/rostests/apitests/atl/CImage.cpp
new file mode 100644 (file)
index 0000000..d294aa2
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test for CImage
+ * PROGRAMMER:      Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
+ */
+
+#include <atlimage.h>
+#include "resource.h"
+
+#ifdef __REACTOS__
+    #include <apitest.h>
+#else
+    #include <stdlib.h>
+    #include <stdio.h>
+    #include <stdarg.h>
+    const char *g_file = NULL;
+    int g_line = 0;
+    int g_tests_executed = 0;
+    int g_tests_failed = 0;
+    void ok_func(BOOL value, const char *fmt, ...)
+    {
+        va_list va;
+        va_start(va, fmt);
+        if (!value)
+        {
+            printf("%s (%d): ", g_file, g_line);
+            vprintf(fmt, va);
+            g_tests_failed++;
+        }
+        g_tests_executed++;
+        va_end(va);
+    }
+    #undef ok
+    #define ok              g_file = __FILE__; g_line = __LINE__; ok_func
+    #define START_TEST(x)   int main(void)
+#endif
+
+
+const TCHAR* szFiles[] = {
+    TEXT("ant.png"),
+    TEXT("ant.tif"),
+    TEXT("ant.gif"),
+    TEXT("ant.jpg"),
+    TEXT("ant.bmp"),
+};
+
+static TCHAR szTempPath[MAX_PATH];
+TCHAR* file_name(const TCHAR* file)
+{
+    static TCHAR buffer[MAX_PATH];
+    lstrcpy(buffer, szTempPath);
+    lstrcat(buffer, TEXT("\\"));
+    lstrcat(buffer, file);
+    return buffer;
+}
+
+static void write_bitmap(HINSTANCE hInst, int id, TCHAR* file)
+{
+    HRSRC rsrc;
+
+    rsrc = FindResource(hInst, MAKEINTRESOURCE(id), MAKEINTRESOURCE(RT_BITMAP));
+    ok(rsrc != NULL, "Expected to find an image resource\n");
+    if (rsrc)
+    {
+        void *rsrc_data;
+        HANDLE hfile;
+        BOOL ret;
+        HGLOBAL glob = LoadResource(hInst, rsrc);
+        DWORD rsrc_size = SizeofResource(hInst, rsrc);
+
+        rsrc_data = LockResource(glob);
+
+        hfile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+        ok(hfile != INVALID_HANDLE_VALUE, "Unable to open temp file: %lu\n", GetLastError());
+        if (hfile != INVALID_HANDLE_VALUE)
+        {
+            BITMAPFILEHEADER bfh = { 0 };
+            DWORD dwWritten;
+
+            bfh.bfType = 'MB';
+            bfh.bfSize = rsrc_size + sizeof(BITMAPFILEHEADER);
+            bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+            bfh.bfReserved1 = bfh.bfReserved2 = 0;
+            ret = WriteFile(hfile, &bfh, sizeof(bfh), &dwWritten, NULL);
+            ok(ret, "Unable to write temp file: %lu\n", GetLastError());
+            ret = WriteFile(hfile, rsrc_data, rsrc_size, &dwWritten, NULL);
+            ok(ret, "Unable to write temp file: %lu\n", GetLastError());
+            CloseHandle(hfile);
+        }
+        UnlockResource(rsrc_data);
+    }
+}
+
+typedef Gdiplus::GpStatus (WINAPI *STARTUP)(ULONG_PTR *, const Gdiplus::GdiplusStartupInput *, Gdiplus::GdiplusStartupOutput *);
+typedef void (WINAPI *SHUTDOWN)(ULONG_PTR);
+typedef Gdiplus::GpStatus (WINGDIPAPI *CREATEBITMAPFROMFILE)(GDIPCONST WCHAR*, Gdiplus::GpBitmap **);
+typedef Gdiplus::GpStatus (WINGDIPAPI *GETPIXELFORMAT)(Gdiplus::GpImage *image, Gdiplus::PixelFormat *format);
+typedef Gdiplus::GpStatus (WINGDIPAPI *DISPOSEIMAGE)(Gdiplus::GpImage *);
+
+static HINSTANCE               hinstGdiPlus;
+static ULONG_PTR               gdiplusToken;
+
+static STARTUP                 Startup;
+static SHUTDOWN                Shutdown;
+static CREATEBITMAPFROMFILE    CreateBitmapFromFile;
+static GETPIXELFORMAT          GetImagePixelFormat;
+static DISPOSEIMAGE            DisposeImage;
+
+template <typename TYPE>
+TYPE AddrOf(const char *name)
+{
+    FARPROC proc = ::GetProcAddress(hinstGdiPlus, name);
+    return reinterpret_cast<TYPE>(proc);
+}
+
+static void init_gdip()
+{
+    hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
+    Startup = AddrOf<STARTUP>("GdiplusStartup");
+    Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown");
+    CreateBitmapFromFile = AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile");
+    GetImagePixelFormat = AddrOf<GETPIXELFORMAT>("GdipGetImagePixelFormat");
+    DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage");
+}
+
+
+static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf)
+{
+    using namespace Gdiplus;
+    GpBitmap *pBitmap = NULL;
+
+#ifdef UNICODE
+    WCHAR* file = tfile;
+#else
+    WCHAR file[MAX_PATH];
+    ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH);
+#endif
+
+    if (Startup == NULL)
+        init_gdip();
+
+    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+    Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+
+    Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap);
+    ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status);
+    ok(pBitmap != NULL, "Expected a valid bitmap\n");
+    if (pBitmap)
+    {
+        PixelFormat pf;
+        GetImagePixelFormat(pBitmap, &pf);
+        ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf);
+
+        DisposeImage(pBitmap);
+    }
+    Shutdown(gdiplusToken);
+}
+
+
+START_TEST(CImage)
+{
+    HRESULT hr;
+    TCHAR* file;
+    BOOL bOK;
+    int width, height, bpp;
+    size_t n;
+    CImage image1, image2;
+    COLORREF color;
+    HDC hDC;
+
+#if 0
+    width = image1.GetWidth();
+    height = image1.GetHeight();
+    bpp = image1.GetBPP();
+#endif
+
+    HINSTANCE hInst = GetModuleHandle(NULL);
+    GetTempPath(MAX_PATH, szTempPath);
+
+    image1.LoadFromResource(hInst, IDB_ANT);
+    ok(!image1.IsNull(), "Expected image1 is not null\n");
+
+    width = image1.GetWidth();
+    ok(width == 48, "Expected width to be 48, was: %d\n", width);
+    height = image1.GetHeight();
+    ok(height == 48, "Expected height to be 48, was: %d\n", height);
+    bpp = image1.GetBPP();
+    ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
+
+
+    image2.LoadFromResource(hInst, IDB_CROSS);
+    ok(!image2.IsNull(), "Expected image2 is not null\n");
+    image2.SetTransparentColor(RGB(255, 255, 255));
+
+    width = image2.GetWidth();
+    ok(width == 32, "Expected width to be 32, was: %d\n", width);
+    height = image2.GetHeight();
+    ok(height == 32, "Expected height to be 32, was: %d\n", height);
+    bpp = image2.GetBPP();
+    ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
+
+    color = image1.GetPixel(5, 5);
+    ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
+
+    hDC = image1.GetDC();
+    bOK = image2.Draw(hDC, 0, 0);
+    image1.ReleaseDC();
+    ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK);
+    image2.Destroy();
+
+    color = image1.GetPixel(5, 5);
+    ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
+
+    file = file_name(TEXT("ant.bmp"));
+    write_bitmap(hInst, IDB_ANT, file);
+
+    init_gdip();
+
+    determine_file_bpp(file, PixelFormat8bppIndexed);
+
+    hr = image2.Load(file);
+    ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr);
+    ok(!image2.IsNull(), "Expected image1 is not null\n");
+    bOK = DeleteFile(file);
+    ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK);
+
+    width = image2.GetWidth();
+    ok(width == 48, "Expected width to be 48, was: %d\n", width);
+    height = image2.GetHeight();
+    ok(height == 48, "Expected height to be 48, was: %d\n", height);
+    bpp = image2.GetBPP();
+    ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
+
+    for (n = 0; n < _countof(szFiles); ++n)
+    {
+        file = file_name(szFiles[n]);
+        image2.Destroy();
+
+        if (n == 0)
+            hr = image1.Save(file, Gdiplus::ImageFormatPNG);
+        else
+            hr = image1.Save(file);
+        ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
+
+        bOK = (GetFileAttributes(file) != 0xFFFFFFFF);
+        ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
+
+        hr = image2.Load(file);
+        ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
+
+        width = image2.GetWidth();
+        ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n);
+        height = image2.GetHeight();
+        ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n);
+        bpp = image2.GetBPP();
+        if (n == 3)
+        {
+            ok(bpp == 24, "Expected bpp to be 24, was: %d (for %i)\n", bpp, n);
+            determine_file_bpp(file, PixelFormat24bppRGB);
+        }
+        else
+        {
+            ok(bpp == 8, "Expected bpp to be 8, was: %d (for %i)\n", bpp, n);
+            determine_file_bpp(file, PixelFormat8bppIndexed);
+        }
+        color = image1.GetPixel(5, 5);
+        ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i (for %i)\n", GetRValue(color), GetGValue(color), GetBValue(color), n);
+
+        bOK = DeleteFile(file);
+        ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
+    }
+
+#ifndef __REACTOS__
+    printf("CImage: %i tests executed (0 marked as todo, %i failures), 0 skipped.\n", g_tests_executed, g_tests_failed);
+#endif
+}
diff --git a/rostests/apitests/atl/CImage_WIP.txt b/rostests/apitests/atl/CImage_WIP.txt
new file mode 100644 (file)
index 0000000..ea26712
--- /dev/null
@@ -0,0 +1,86 @@
+Test files:\r
+\r
+atl_apitest: CImage class from reactos\r
+CImage.exe : CImage class from microsoft\r
+\r
+================================================================================================================\r
+Windows Server 2003 SP2:\r
+================================================================================================================\r
+>atl_apitest.exe CImage\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(234): Test failed: Expected bpp to be 8, was: 32\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 0)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 1)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 2)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(260): Test failed: Expected bpp to be 24, was: 32 (for 3)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 4)\r
+\r
+CImage: 79 tests executed (0 marked as todo, 6 failures), 0 skipped.\r
+================================================================================================================\r
+>CImage.exe\r
+CImage: 79 tests executed (0 marked as todo, 0 failures), 0 skipped.\r
+================================================================================================================\r
+================================================================================================================\r
+Windows 10:\r
+================================================================================================================\r
+>atl_apitest.exe CImage\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(234): Test failed: Expected bpp to be 8, was: 32\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 0)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 1)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 2)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(260): Test failed: Expected bpp to be 24, was: 32 (for 3)\r
+R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 4)\r
+\r
+CImage: 79 tests executed (0 marked as todo, 6 failures), 0 skipped.\r
+================================================================================================================\r
+>CImage.exe\r
+CImage: 79 tests executed (0 marked as todo, 0 failures), 0 skipped.\r
+================================================================================================================\r
+================================================================================================================\r
+ReactOS:\r
+================================================================================================================\r
+>atl_apitest.exe CImage\r
+CImage.cpp:234: Test failed: Expected bpp to be 8, was: 32\r
+CImage.cpp:265: Test failed: Expected bpp to be 8, was: 32 (for 0)\r
+CImage.cpp:245: Test failed: Expected hr to be S_OK, was: 80004005 (for 1)\r
+CImage.cpp:251: Test failed: Expected hr to be S_OK, was: 80004005 (for 1)\r
+CImage.cpp:254: Test failed: Expected width to be 48, was: 0 (for 1)\r
+CImage.cpp:256: Test failed: Expected height to be 48, was: 0 (for 1)\r
+CImage.cpp:265: Test failed: Expected bpp to be 8, was: 0 (for 1)\r
+CImage.cpp:148: Test failed: Expected status to be 0, was: 1\r
+CImage.cpp:149: Test failed: Expected a valid bitmap\r
+CImage.cpp:245: Test failed: Expected hr to be S_OK, was: 80004005 (for 2)\r
+CImage.cpp:251: Test failed: Expected hr to be S_OK, was: 80004005 (for 2)\r
+CImage.cpp:254: Test failed: Expected width to be 48, was: 0 (for 2)\r
+CImage.cpp:256: Test failed: Expected height to be 48, was: 0 (for 2)\r
+CImage.cpp:265: Test failed: Expected bpp to be 8, was: 0 (for 2)\r
+CImage.cpp:148: Test failed: Expected status to be 0, was: 1\r
+CImage.cpp:149: Test failed: Expected a valid bitmap\r
+CImage.cpp:260: Test failed: Expected bpp to be 24, was: 32 (for 3)\r
+CImage.cpp:154: Test failed: Expected PixelFormat to be 0x21808, was: 0x30803\r
+CImage.cpp:265: Test failed: Expected bpp to be 8, was: 32 (for 4)\r
+CImage.cpp:154: Test failed: Expected PixelFormat to be 0x30803, was: 0x21808\r
+\r
+CImage: 77 tests executed (0 marked as todo, 20 failures), 0 skipped.\r
+================================================================================================================\r
+>CImage.exe\r
+../CImage.cpp (245): Expected hr to be S_OK, was: 80004005 (for 1)\r
+../CImage.cpp (251): Expected hr to be S_OK, was: 80004005 (for 1)\r
+../CImage.cpp (254): Expected width to be 48, was: 0 (for 1)\r
+../CImage.cpp (256): Expected height to be 48, was: 0 (for 1)\r
+../CImage.cpp (265): Expected bpp to be 8, was: 0 (for 1)\r
+../CImage.cpp (148): Expected status to be 0, was: 1\r
+../CImage.cpp (149): Expected a valid bitmap\r
+../CImage.cpp (245): Expected hr to be S_OK, was: 80004005 (for 2)\r
+../CImage.cpp (251): Expected hr to be S_OK, was: 80004005 (for 2)\r
+../CImage.cpp (254): Expected width to be 48, was: 0 (for 2)\r
+../CImage.cpp (256): Expected height to be 48, was: 0 (for 2)\r
+../CImage.cpp (265): Expected bpp to be 8, was: 0 (for 2)\r
+../CImage.cpp (148): Expected status to be 0, was: 1\r
+../CImage.cpp (149): Expected a valid bitmap\r
+../CImage.cpp (260): Expected bpp to be 24, was: 8 (for 3)\r
+../CImage.cpp (154): Expected PixelFormat to be 0x21808, was: 0x30803\r
+../CImage.cpp (265): Expected bpp to be 8, was: 24 (for 4)\r
+../CImage.cpp (154): Expected PixelFormat to be 0x30803, was: 0x21808\r
+CImage: 77 tests executed (0 marked as todo, 18 failures), 0 skipped.\r
+================================================================================================================\r
+\r
index ddb7229..ada8acd 100644 (file)
@@ -1,4 +1,5 @@
 
+add_definitions(-DINITGUID)
 set_cpp(WITH_RUNTIME WITH_EXCEPTIONS)
 
 include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl)
@@ -7,6 +8,7 @@ add_executable(atl_apitest
     atltypes.cpp
     CComBSTR.cpp
     CComHeapPtr.cpp
+    CImage.cpp
     CRegKey.cpp
     CString.cpp
     testlist.c
@@ -14,5 +16,5 @@ add_executable(atl_apitest
 
 target_link_libraries(atl_apitest wine uuid)
 set_module_type(atl_apitest win32cui)
-add_importlibs(atl_apitest ole32 oleaut32 advapi32 user32 msvcrt kernel32)
+add_importlibs(atl_apitest rpcrt4 ole32 oleaut32 msimg32 gdi32 advapi32 user32 msvcrt kernel32)
 add_cd_file(TARGET atl_apitest DESTINATION reactos/bin FOR all)
diff --git a/rostests/apitests/atl/ant.bmp b/rostests/apitests/atl/ant.bmp
new file mode 100644 (file)
index 0000000..aea13bd
Binary files /dev/null and b/rostests/apitests/atl/ant.bmp differ
index 760690b..a103786 100644 (file)
@@ -9,3 +9,5 @@ BEGIN
     IDS_TEST2 "I am a happy BSTR"
 END
 
+IDB_ANT BITMAP "ant.bmp"
+IDB_CROSS BITMAP "cross.bmp"
diff --git a/rostests/apitests/atl/cross.bmp b/rostests/apitests/atl/cross.bmp
new file mode 100644 (file)
index 0000000..a8ea2fd
Binary files /dev/null and b/rostests/apitests/atl/cross.bmp differ
diff --git a/rostests/apitests/atl/devenv/CImage.sln b/rostests/apitests/atl/devenv/CImage.sln
new file mode 100644 (file)
index 0000000..099c2c3
--- /dev/null
@@ -0,0 +1,28 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.24720.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CImage", "CImage.vcxproj", "{AE520E17-2DAE-40FF-B082-F32A7A935FB2}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|x64 = Debug|x64\r
+               Debug|x86 = Debug|x86\r
+               Release|x64 = Release|x64\r
+               Release|x86 = Release|x86\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x64.ActiveCfg = Debug|x64\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x64.Build.0 = Debug|x64\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x86.ActiveCfg = Debug|Win32\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x86.Build.0 = Debug|Win32\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x64.ActiveCfg = Release|x64\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x64.Build.0 = Release|x64\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x86.ActiveCfg = Release|Win32\r
+               {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x86.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/rostests/apitests/atl/devenv/CImage.vcxproj b/rostests/apitests/atl/devenv/CImage.vcxproj
new file mode 100644 (file)
index 0000000..571f2e3
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{AE520E17-2DAE-40FF-B082-F32A7A935FB2}</ProjectGuid>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+    <Keyword>AtlProj</Keyword>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v120_xp</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="Shared">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <IgnoreImportLibrary>true</IgnoreImportLibrary>\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <Culture>0x0409</Culture>\r
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <RegisterOutput>true</RegisterOutput>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <Culture>0x0409</Culture>\r
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <RegisterOutput>true</RegisterOutput>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <Culture>0x0409</Culture>\r
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <RegisterOutput>true</RegisterOutput>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <Culture>0x0409</Culture>\r
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <RegisterOutput>true</RegisterOutput>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="../CImage.cpp">\r
+      <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MultiThreaded</RuntimeLibrary>\r
+      <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MultiThreaded</RuntimeLibrary>\r
+      <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MultiThreadedDebug</RuntimeLibrary>\r
+      <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MultiThreadedDebug</RuntimeLibrary>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ResourceCompile Include="../atl_apitest.rc" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
index bc0ff64..ca804d8 100644 (file)
@@ -1,3 +1,6 @@
 
 #define IDS_TEST1 2000
 #define IDS_TEST2 2001
+
+#define IDB_ANT   1
+#define IDB_CROSS 2
index 380bb66..535f8bc 100644 (file)
@@ -4,6 +4,7 @@
 extern void func_atltypes(void);
 extern void func_CComBSTR(void);
 extern void func_CComHeapPtr(void);
+extern void func_CImage(void);
 extern void func_CRegKey(void);
 extern void func_CString(void);
 
@@ -12,6 +13,7 @@ const struct test winetest_testlist[] =
     { "atltypes", func_atltypes },
     { "CComBSTR", func_CComBSTR },
     { "CComHeapPtr", func_CComHeapPtr },
+    { "CImage", func_CImage },
     { "CRegKey", func_CRegKey },
     { "CString", func_CString },
     { 0, 0 }