// XTPImageManager.cpp : implementation of the CXTPImageManager class.
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>

#include "XTPVC80Helpers.h"
#include "XTPColorManager.h"
#include "XTPDrawHelpers.h"
#include "XTPSystemHelpers.h"
#include "XTPMacros.h"
#include "XTPPropExchange.h"
#include "XTPImageManager.h"
#include "XTPResourceManager.h"

#ifdef _XTP_INCLUDE_GRAPHICLIBRARY
#include "GraphicLibrary/XTPGraphicBitmapPng.h"
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define DESTROYICON(hIcon) if (hIcon) { ::DestroyIcon(hIcon); hIcon = 0; }
#define FREE(hHandle) if (hHandle) { free(hHandle); hHandle = 0; }

double CXTPImageManager::m_dDisabledAlphaFactor = 1.0;
double CXTPImageManager::m_dDisabledBrightnessFactor = 0.5;
BOOL CXTPImageManager::m_bAutoResample = FALSE;
CLIPFORMAT CXTPImageManager::m_nImageClipFormat = (CLIPFORMAT)RegisterClipboardFormat(_T("Xtreme ToolBar Image"));
CLIPFORMAT CXTPImageManager::m_nAlphaClipFormat = (CLIPFORMAT)RegisterClipboardFormat(_T("Alpha Bitmap Image"));

#ifndef NOMIRRORBITMAP
#define NOMIRRORBITMAP      (DWORD)0x80000000 /* Do not Mirror the bitmap in this call */
#endif

#define  IMAGE_PLACEHOLDER 0xDEADBEAF

//---------------------------------------------------------------------------
//    Should be a prime number:
// 37, 53, 79 , 101, 127, 199, 503, 1021, 1511, 2003, 3001, 4001, 5003, 6007, 8009, 12007, 16001, 32003, 48017, 64007
#define XTP_IMAGEMAN_HASH_TABLE_SIZE 127

//////////////////////////////////////////////////////////////////////////
// Common

// Based on http://support.microsoft.com/kb/303916/en-us
BOOL CXTPImageManager::BitmapsCompatible(LPBITMAP lpbm1, LPBITMAP lpbm2) const
{
	if (lpbm1->bmBitsPixel != lpbm2->bmBitsPixel)
		return FALSE;

	if (lpbm1->bmPlanes != lpbm2->bmPlanes)
		return FALSE;

	if (lpbm1->bmWidth != lpbm2->bmWidth)
		return FALSE;

	if (lpbm1->bmHeight != lpbm2->bmHeight)
		return FALSE;

	return TRUE;
}

// Based on http://www.rsdn.ru/article/files/Functions/mctranspblt.xml
BOOL CXTPImageManager::McTransparentBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest,
	int nWidthDest, int nHeightDest, HDC hdcSrc,
	int nXOriginSrc, int nYOriginSrc, int nWidthSrc,
	int nHeightSrc, UINT crTransparent)
{

	BOOL bResult = FALSE;

	if (!hdcDest || !hdcSrc)
		return FALSE;

	HDC hdcMask = NULL;
	HDC hdcTmpSrc = NULL;
	HBITMAP hbmTransMask = NULL;
	HBITMAP oldhbmTransMask = NULL;
	HBITMAP hbmTmpSrc = NULL;
	HBITMAP oldhbmTmpSrc = NULL;


	COLORREF OldBkColor = ::SetBkColor(hdcDest, RGB(255, 255, 255));
	COLORREF OldTextColor = ::SetTextColor(hdcDest, RGB(0, 0, 0));

	if ((hdcMask = ::CreateCompatibleDC(hdcDest)) == NULL)
	{
		goto ClearUp;
	}

	if ((hdcTmpSrc = ::CreateCompatibleDC(hdcSrc))==NULL)
	{
		goto ClearUp;
	}

	if ((hbmTmpSrc = ::CreateCompatibleBitmap(hdcDest,nWidthSrc,nHeightSrc))==NULL)
	{
		goto ClearUp;
	}

	oldhbmTmpSrc = (HBITMAP)::SelectObject(hdcTmpSrc,hbmTmpSrc);

	if (!::BitBlt(hdcTmpSrc, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY))
	{
		goto ClearUp;
	}

	if ((hbmTransMask = ::CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL)) == NULL)
	{
		goto ClearUp;
	}

	oldhbmTransMask = (HBITMAP)::SelectObject(hdcMask,hbmTransMask);

	::SetBkColor(hdcTmpSrc,crTransparent);
	if (!::BitBlt(hdcMask, 0, 0, nWidthSrc, nHeightSrc, hdcTmpSrc, 0, 0, SRCCOPY))
	{
		goto ClearUp;
	}

	if (crTransparent != RGB(0, 0, 0))
	{
		::SetBkColor(hdcTmpSrc, RGB(0, 0, 0));
		::SetTextColor(hdcTmpSrc, RGB(255, 255, 255));

		if (!::BitBlt(hdcTmpSrc, 0, 0, nWidthSrc, nHeightSrc, hdcMask, 0, 0, SRCAND))
		{
			goto ClearUp;
		}
	}

	if ((nWidthDest == nWidthSrc) && (nHeightDest == nHeightSrc))
	{
		if (!::BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthSrc, nHeightSrc, hdcMask, 0, 0, SRCAND))
		{
			goto ClearUp;
		}
		if (!::BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthSrc, nHeightSrc, hdcTmpSrc, 0, 0, SRCPAINT))
		{
			goto ClearUp;
		}
	}
	else
	{
		if (!::StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcMask, 0, 0, nWidthSrc, nHeightSrc,SRCAND))
		{
			goto ClearUp;
		}
		if (!::StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcTmpSrc, 0, 0,  nWidthSrc, nHeightSrc,SRCPAINT))
		{
			goto ClearUp;
		}
	}
	bResult = TRUE;

ClearUp:
	if (hdcMask)
	{
		if (oldhbmTransMask)
			::SelectObject(hdcMask,oldhbmTransMask);
		::DeleteDC(hdcMask);
	}

	if (hbmTmpSrc)
	{
		if (oldhbmTmpSrc)
			::SelectObject(hdcTmpSrc,oldhbmTmpSrc);
		::DeleteObject(hbmTmpSrc);
	}

	if (hdcTmpSrc)
		::DeleteDC(hdcTmpSrc);

	if (hbmTransMask)
		::DeleteObject(hbmTransMask);

	::SetBkColor(hdcDest, OldBkColor);
	::SetTextColor(hdcDest,OldTextColor);

	return bResult;
}

BOOL CXTPImageManager::IsWindow2000() const
{
	return XTPSystemVersion()->IsWin2KOrGreater();
}

BOOL CXTPImageManager::TransparentBlt(HDC hdcDest, const CRect& rcDest,HDC hdcSrc,
	const CRect& rcSrc, UINT crTransparent) const
{
	if (IsWindow2000() && XTPDrawHelpers()->m_pfnTransparentBlt)
	{
		return XTPDrawHelpers()->m_pfnTransparentBlt(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
			hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), crTransparent);
	}

	return McTransparentBlt(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
		hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), crTransparent);
}

// Based on http://support.microsoft.com/kb/303916/en-us
BOOL CXTPImageManager::BlendImages(HBITMAP hbmSrc1, BOOL bRTL1, HBITMAP hbmSrc2, BOOL bRTL2, HBITMAP hbmDst) const
{
	BITMAP bmSrc1, bmSrc2, bmDst;
	RGBQUAD *lprgbSrc1, *lprgbSrc2, *lprgbDst;
	DWORD dwWidthBytes;
	int x, y;

	// Get weighting value for second source image.

	// Get information about the surfaces you were passed.
	if (!GetObject(hbmSrc1, sizeof(BITMAP), &bmSrc1)) return FALSE;
	if (!GetObject(hbmSrc2, sizeof(BITMAP), &bmSrc2)) return FALSE;
	if (!GetObject(hbmDst,  sizeof(BITMAP), &bmDst))  return FALSE;

	// Make sure you have data that meets your requirements.
	if (!BitmapsCompatible(&bmSrc1, &bmSrc2)) return FALSE;
	if (!BitmapsCompatible(&bmSrc1, &bmDst))  return FALSE;
	if (bmSrc1.bmBitsPixel != 32) return FALSE;
	if (bmSrc1.bmPlanes != 1) return FALSE;
	if (!bmSrc1.bmBits || !bmSrc2.bmBits || !bmDst.bmBits) return FALSE;

	dwWidthBytes = bmDst.bmWidthBytes;

	// Initialize the surface pointers.
	lprgbSrc1 = (RGBQUAD*)bmSrc1.bmBits;
	lprgbSrc2 = (RGBQUAD*)bmSrc2.bmBits;
	lprgbDst  = (RGBQUAD*)bmDst.bmBits;

	#define F(a)  BYTE(gbSrc1.##a + (255 - gbSrc1.rgbReserved) * gbSrc2.##a / 255)

	for (y = 0; y < bmDst.bmHeight; y++)
	{
		for (x = 0; x < bmDst.bmWidth; x++)
		{
			RGBQUAD& gbSrc1 = bRTL1 ? lprgbSrc1[bmDst.bmWidth - 1 - x] : lprgbSrc1[x];
			RGBQUAD& gbSrc2 = bRTL2 ? lprgbSrc2[bmDst.bmWidth - 1 - x] : lprgbSrc2[x];

			lprgbDst[x].rgbRed   = F(rgbRed);
			lprgbDst[x].rgbGreen = F(rgbGreen);
			lprgbDst[x].rgbBlue  = F(rgbBlue);
		}

		// Move to next scan line.
		lprgbSrc1 = (RGBQUAD *)((LPBYTE)lprgbSrc1 + dwWidthBytes);
		lprgbSrc2 = (RGBQUAD *)((LPBYTE)lprgbSrc2 + dwWidthBytes);
		lprgbDst  = (RGBQUAD *)((LPBYTE)lprgbDst  + dwWidthBytes);
	}

	return TRUE;
}

// Based on http://support.microsoft.com/kb/303916/en-us
HBITMAP AFX_CDECL CXTPImageManager::Create32BPPDIBSection(HDC hDC, int iWidth, int iHeight, LPBYTE* lpBits)
{
	BITMAPINFO bmi;
	HBITMAP hbm;
	LPBYTE pBits;

	// Initialize header to 0s.
	ZeroMemory(&bmi, sizeof(bmi));

	// Fill out the fields you care about.
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = iWidth;
	bmi.bmiHeader.biHeight = iHeight;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;
	bmi.bmiHeader.biCompression = BI_RGB;

	// Create the surface.
	hbm = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);

	if (lpBits)
	{
		*lpBits = pBits;
	}

	return(hbm);
}

// Based on http://support.microsoft.com/kb/303916/en-us
BOOL CXTPImageManager::DoAlphaBlend(HDC hdcDest,                 // Handle to destination DC.
	int nXOriginDest,            // X-coord of upper-left corner.
	int nYOriginDest,            // Y-coord of upper-left corner.
	int nWidthDest,              // Destination width.
	int nHeightDest,             // Destination height.
	HDC hdcSrc,                  // Handle to source DC.
	int nXOriginSrc,             // X-coord of upper-left corner.
	int nYOriginSrc,             // Y-coord of upper-left corner.
	int nWidthSrc,               // Source width.
	int nHeightSrc              // Source height.
) const
{
	HDC      hdcSrc1 = NULL;
	HDC      hdcSrc2 = NULL;
	HBITMAP  hbmSrc1 = NULL, hbmOldSrc1 = NULL;
	HBITMAP  hbmSrc2 = NULL, hbmOldSrc2 = NULL;
	HBITMAP  hbmDst  = NULL;
	BOOL     bReturn = FALSE;
	BOOL     bRTLSrc    = XTPDrawHelpers()->IsContextRTL(hdcSrc);
	BOOL     bRTLDest   = XTPDrawHelpers()->IsContextRTL(hdcDest);

	// Create surfaces for sources and destination images.
	hbmSrc1 = CXTPImageManager::Create32BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
	if (!hbmSrc1) goto HANDLEERROR;

	hbmSrc2 = CXTPImageManager::Create32BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
	if (!hbmSrc2) goto HANDLEERROR;

	hbmDst  = CXTPImageManager::Create32BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
	if (!hbmDst) goto HANDLEERROR;

	// Create HDCs to hold our surfaces.
	hdcSrc1 = CreateCompatibleDC(hdcSrc);
	if (!hdcSrc1) goto HANDLEERROR;

	hdcSrc2 = CreateCompatibleDC(hdcSrc);
	if (!hdcSrc2) goto HANDLEERROR;

	XTPDrawHelpers()->SetContextRTL(hdcSrc2, FALSE);
	XTPDrawHelpers()->SetContextRTL(hdcSrc1, FALSE);

	// Prepare the surfaces for drawing.
	hbmOldSrc1 = (HBITMAP)SelectObject(hdcSrc1, hbmSrc1);
	hbmOldSrc2 = (HBITMAP)SelectObject(hdcSrc2, hbmSrc2);
	SetStretchBltMode(hdcSrc1, COLORONCOLOR);
	SetStretchBltMode(hdcSrc2, COLORONCOLOR);


	// Capture a copy of the source area.
	if (!StretchBlt(hdcSrc1, 0,0,nWidthDest,nHeightDest,
		hdcSrc,  nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
		SRCCOPY))
		goto HANDLEERROR;


	// Capture a copy of the destination area.
	if (!BitBlt(hdcSrc2, 0, 0, nWidthDest, nHeightDest,
		hdcDest, nXOriginDest, nYOriginDest, SRCCOPY))
		goto HANDLEERROR;



	SelectObject(hdcSrc1, hbmOldSrc1); hbmOldSrc1 = NULL;
	SelectObject(hdcSrc2, hbmOldSrc2); hbmOldSrc2 = NULL;

	// Blend the two source areas to create the destination image.
	bReturn = BlendImages(hbmSrc1, bRTLSrc, hbmSrc2, bRTLDest, hbmDst);


	// Display the blended (destination) image to the target HDC.
	if (bReturn)
	{
		hbmOldSrc1 = (HBITMAP)SelectObject(hdcSrc1, hbmDst);

		BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
			hdcSrc1, 0,0, SRCCOPY | (bRTLDest ? NOMIRRORBITMAP : 0));

		SelectObject(hdcSrc1, hbmOldSrc1);
		hbmOldSrc1 = NULL;
	}

	// Clean up the rest of the objects you created.

HANDLEERROR:

	if (hbmOldSrc1) SelectObject(hdcSrc1, hbmOldSrc1);
	if (hbmOldSrc2) SelectObject(hdcSrc2, hbmOldSrc2);
	if (hdcSrc1) DeleteDC(hdcSrc1);
	if (hdcSrc2) DeleteDC(hdcSrc2);
	if (hbmSrc1) DeleteObject(hbmSrc1);
	if (hbmSrc2) DeleteObject(hbmSrc2);
	if (hbmDst) DeleteObject(hbmDst);

	return bReturn;
}


BOOL CXTPImageManager::AlphaBlend(HDC hdcDest, const CRect& rcDest, HDC hdcSrc, const CRect& rcSrc) const
{
	if (XTPDrawHelpers()->IsContextRTL(hdcDest) && XTPSystemVersion()->IsWin9x())
	{
		return DoAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
			hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height());
	}

	if (XTPDrawHelpers()->m_pfnAlphaBlend && (IsWindow2000() || (rcSrc.top == 0 && rcSrc.left == 0 && rcDest.top >= 0)))
	{
		BLENDFUNCTION bf;
		ZeroMemory(&bf, sizeof(BLENDFUNCTION));

		bf.AlphaFormat  = 0x01;
		bf.SourceConstantAlpha = 255;
		bf.BlendOp = AC_SRC_OVER;

		return XTPDrawHelpers()->m_pfnAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
			hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), bf);

	}
	return DoAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
		hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height());
}

BOOL CXTPImageManager::AlphaBlend2(HDC hdcDest, const CRect& rcDest, HDC hdcSrc, const CRect& rcSrc, BYTE Transparency) const
{
	if (XTPDrawHelpers()->IsContextRTL(hdcDest) && XTPSystemVersion()->IsWin9x())
	{
		return DoAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
			hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height());
	}

	if (XTPDrawHelpers()->m_pfnAlphaBlend && (IsWindow2000() || (rcSrc.top == 0 && rcSrc.left == 0)))
	{
		BLENDFUNCTION bf;
		ZeroMemory(&bf, sizeof(BLENDFUNCTION));

		bf.AlphaFormat  = 0;
		bf.SourceConstantAlpha = Transparency;
		bf.BlendOp = AC_SRC_OVER;

		return XTPDrawHelpers()->m_pfnAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
			hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), bf);

	}
	return DoAlphaBlend(hdcDest, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
		hdcSrc, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height());
}



//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerImageList

CXTPImageManagerImageList::CXTPImageManagerImageList()
{
	m_hImageList = NULL;
	m_bDestroyImageList = FALSE;
	m_nBaseCommand = 0;
	m_pImageManager = NULL;
}

CXTPImageManagerImageList::~CXTPImageManagerImageList()
{
	if (m_hImageList && m_bDestroyImageList)
	{
		ImageList_Destroy(m_hImageList);
	}

	RemoveAll();
}

void CXTPImageManagerImageList::RemoveAll()
{
	UINT nCommand;
	CXTPImageManagerIcon* pIcon;

	POSITION pos = m_mapIcons.GetStartPosition();
	while (pos)
	{
		m_mapIcons.GetNextAssoc(pos, nCommand, pIcon);
		pIcon->InternalRelease();
	}

	m_mapIcons.RemoveAll();
}

BOOL CXTPImageManagerImageList::Lookup(UINT nCommand)
{
	return ((nCommand >= m_nBaseCommand) &&
		(nCommand < m_nBaseCommand + ImageList_GetImageCount(m_hImageList)));
}

CSize CXTPImageManagerImageList::GetIconSize() const
{
	int nWidth = 0, nHeight = 0;
	VERIFY(ImageList_GetIconSize(m_hImageList, &nWidth, &nHeight));

	return CSize(nWidth, nHeight);
}

CXTPImageManagerIcon* CXTPImageManagerImageList::GetIcon(UINT nCommand)
{
	CXTPImageManagerIcon* pImage = NULL;

	if (m_mapIcons.Lookup(nCommand, pImage))
	{
		return pImage;
	}

	CSize sz = GetIconSize();

	pImage = new CXTPImageManagerIcon(nCommand, sz.cx, sz.cy, this);
	m_mapIcons.SetAt(nCommand, pImage);

	return pImage;
}

void CXTPImageManagerImageList::Draw(CDC* pDC, CPoint pt, CXTPImageManagerIcon* pIcon, CSize szIcon, COLORREF clrBK, COLORREF clrFG, UINT uiFlags)
{
	ImageList_DrawEx(m_hImageList, pIcon->GetID() - m_nBaseCommand, pDC->GetSafeHdc(),
		pt.x, pt.y, szIcon.cx, szIcon.cy, clrBK, clrFG, ILD_TRANSPARENT | ILD_NORMAL | uiFlags);
}

//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerIcon


struct CXTPImageManagerIcon::ICONIMAGE
{
	BITMAPINFOHEADER    icHeader;   // DIB header
	RGBQUAD             icColors[1];// Color table
	BYTE                icXOR[1];   // DIB bits for XOR mask
	BYTE                icAND[1];   // DIB bits for AND mask
};

#pragma pack(push, 2)
// resources are WORD-aligned

struct CXTPImageManagerIcon::ICONDIRENTRY
{
	BYTE        bWidth;             // Width, in pixels, of the image
	BYTE        bHeight;            // Height, in pixels, of the image
	BYTE        bColorCount;        // Number of colors in image (0 if >= 8bpp)
	BYTE        bReserved;          // Reserved (must be 0)
	WORD        wPlanes;            // Color Planes
	WORD        wBitCount;          // Bits per pixel
	DWORD       dwBytesInRes;       // How many bytes in this resource ?
	DWORD       dwImageOffset;      // Where in the file is this image ?
};

struct CXTPImageManagerIcon::ICONDIRHEADER
{
	WORD            idReserved;     // Reserved (must be 0)
	WORD            idType;         // Resource Type (1 for icons)
	WORD            idCount;        // How many images ?
};

struct CXTPImageManagerIcon::GRPICONDIRENTRY
{
	BYTE   bWidth;                  // Width, in pixels, of the image
	BYTE   bHeight;                 // Height, in pixels, of the image
	BYTE   bColorCount;             // Number of colors in image (0 if >= 8bpp)
	BYTE   bReserved;               // Reserved
	WORD   wPlanes;                 // Color Planes
	WORD   wBitCount;               // Bits per pixel
	DWORD  dwBytesInRes;            // how many bytes in this resource ?
	WORD   nID;                     // the ID
};

struct CXTPImageManagerIcon::GRPICONDIR
{
	WORD              idReserved;   // Reserved (must be 0)
	WORD              idType;       // Resource type (1 for icons)
	WORD              idCount;      // How many images ?
	GRPICONDIRENTRY   idEntries[1]; // The entries for each image
};

#pragma pack(pop)

BOOL CXTPImageManagerIcon::IsAlphaBitmapFile(LPCTSTR pszFileName)
{
	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	DWORD dwBytesRead;

	BITMAPFILEHEADER fileHeader;

	if (!ReadFile(hFile, &fileHeader, sizeof(BITMAPFILEHEADER), &dwBytesRead, 0) || dwBytesRead != sizeof(BITMAPFILEHEADER))
	{
		CloseHandle(hFile);
		return FALSE;
	}

	BITMAPINFOHEADER infoHeader;

	if (!ReadFile(hFile, &infoHeader, sizeof(BITMAPINFOHEADER), &dwBytesRead, 0) || dwBytesRead != sizeof(BITMAPINFOHEADER))
	{
		CloseHandle(hFile);
		return FALSE;
	}

	BOOL bResult = infoHeader.biBitCount == 32;

	CloseHandle(hFile);

	return bResult;
}

BOOL CXTPImageManagerIcon::IsPngBitmapFile(LPCTSTR pszFileName)
{
	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	DWORD dwBytesRead;

	BYTE fileHeader[4];
	BYTE png_signature[4] = {137, 80, 78, 71};

	if (!ReadFile(hFile, &fileHeader, sizeof(fileHeader), &dwBytesRead, 0) || dwBytesRead != sizeof(fileHeader))
	{
		CloseHandle(hFile);
		return FALSE;
	}

	BOOL bResult = memcmp(&fileHeader, &png_signature, 4) == 0;

	CloseHandle(hFile);

	return bResult;
}


HBITMAP AFX_CDECL CXTPImageManagerIcon::LoadBitmapFromFile(LPCTSTR lpszFileName, BOOL* lbAlphaBitmap)
{
#ifdef _XTP_INCLUDE_GRAPHICLIBRARY
	BOOL bPngBitmap = CXTPImageManagerIcon::IsPngBitmapFile(lpszFileName);

	if (bPngBitmap)
	{
		CXTPGraphicBitmapPng bmp;
		if (!bmp.LoadFromFile(lpszFileName))
			return NULL;

		if (lbAlphaBitmap)
		{
			*lbAlphaBitmap = bmp.IsAlpha();
		}
		return (HBITMAP)bmp.Detach();
	}
#endif
	BOOL bAlphaBitmap = CXTPImageManagerIcon::IsAlphaBitmapFile(lpszFileName);

	HBITMAP hBmp = (HBITMAP)LoadImage(0, lpszFileName,
		IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | (bAlphaBitmap ? LR_CREATEDIBSECTION : 0) | LR_LOADFROMFILE);

	if (hBmp)
	{
		if (lbAlphaBitmap)
		{
			*lbAlphaBitmap = bAlphaBitmap;
		}
		return hBmp;
	}

	LPPICTURE pPict = NULL;

	if (OleLoadPicturePath((LPOLESTR)XTP_CT2CW(lpszFileName), NULL, 0, 0, IID_IPicture, (LPVOID*)&pPict) == S_OK)
	{
		CDC dc;
		dc.CreateCompatibleDC(NULL);

		long hmWidth;
		long hmHeight;

		pPict->get_Width(&hmWidth);
		pPict->get_Height(&hmHeight);

		int cx = MulDiv(dc.GetDeviceCaps(LOGPIXELSX), (int)hmWidth, 2540);
		int cy = MulDiv(dc.GetDeviceCaps(LOGPIXELSY), (int)hmHeight, 2540);

		HBITMAP hbmpImage = CXTPImageManager::Create32BPPDIBSection(NULL, cx, cy);

		HGDIOBJ hOldBitmap = ::SelectObject(dc, hbmpImage);
		dc.FillSolidRect(0, 0, cx, cy, GetSysColor(COLOR_3DFACE));

		pPict->Render(dc, 0, 0, cx, cy, 0, hmHeight-1, hmWidth, -hmHeight, 0);

		::SelectObject(dc, hOldBitmap);

		pPict->Release();

		return hbmpImage;
	}

	return NULL;
}


BOOL AFX_CDECL CXTPImageManagerIcon::IsPngBitmapResource(HMODULE hModule, LPCTSTR lpBitmapName)
{
	BYTE png_signature[4] = {137, 80, 78, 71};

	HRSRC hResource = ::FindResource(hModule, lpBitmapName, _T("PNG"));

	if (hResource == NULL)
		return FALSE;

	HGLOBAL hGlobal = LoadResource(hModule, hResource);
	if (hGlobal == NULL)
		return FALSE;

	LPBYTE pBitmapInfoHeader = (LPBYTE)::LockResource(hGlobal);
	BOOL bPngBitmap = memcmp(pBitmapInfoHeader, &png_signature, 4) == 0;

	UnlockResource(hGlobal);
	FreeResource(hGlobal);

	return (bPngBitmap);
}

BOOL AFX_CDECL CXTPImageManagerIcon::IsAlphaBitmapResource(HMODULE hModule, LPCTSTR lpBitmapName)
{
	HRSRC hResource = ::FindResource(hModule, lpBitmapName, RT_BITMAP);

	if (hResource == NULL)
		return FALSE;

	HGLOBAL hGlobal = LoadResource(hModule, hResource);
	if (hGlobal == NULL)
		return FALSE;

	LPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal);
	ASSERT(pBitmapInfoHeader != NULL);
	if (!pBitmapInfoHeader)
		return FALSE;

	BOOL bAlpahBitmap = pBitmapInfoHeader->biBitCount == 32;
	UnlockResource(hGlobal);
	FreeResource(hGlobal);

	return (bAlpahBitmap);
}

HBITMAP AFX_CDECL CXTPImageManagerIcon::LoadBitmapFromResource(LPCTSTR lpszResource, BOOL* lbAlphaBitmap)
{
	HMODULE hModule;

#ifdef _XTP_INCLUDE_GRAPHICLIBRARY
	hModule = AfxFindResourceHandle(lpszResource, _T("PNG"));

	BOOL bPngBitmap = IsPngBitmapResource(hModule, lpszResource);
	if (bPngBitmap)
	{
		CXTPGraphicBitmapPng bmpIcons;

		HRSRC hResource = ::FindResource(hModule, lpszResource, _T("PNG"));

		if (!bmpIcons.LoadFromResource(hModule, hResource))
			return NULL;

		if (lbAlphaBitmap)
		{
			*lbAlphaBitmap = bmpIcons.IsAlpha();
		}

		return (HBITMAP)bmpIcons.Detach();
	}
#endif

	hModule = AfxFindResourceHandle(lpszResource, RT_BITMAP);

	CBitmap bmpIcons;
	BOOL bAlphaBitmap = IsAlphaBitmapResource(hModule, lpszResource);

	if (lbAlphaBitmap)
	{
		*lbAlphaBitmap = bAlphaBitmap;
	}

	if (bAlphaBitmap)
	{
		return LoadAlphaBitmap(hModule, lpszResource);
	}

	return (HBITMAP)LoadImage(hModule, lpszResource, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
}

HBITMAP AFX_CDECL CXTPImageManagerIcon::LoadBitmapFromResource(HMODULE hModule, LPCTSTR lpszResource, BOOL* lbAlphaBitmap)
{
#ifdef _XTP_INCLUDE_GRAPHICLIBRARY

	BOOL bPngBitmap = IsPngBitmapResource(hModule, lpszResource);
	if (bPngBitmap)
	{
		CXTPGraphicBitmapPng bmpIcons;

		HRSRC hResource = ::FindResource(hModule, lpszResource, _T("PNG"));

		if (!bmpIcons.LoadFromResource(hModule, hResource))
			return NULL;

		if (lbAlphaBitmap)
		{
			*lbAlphaBitmap = bmpIcons.IsAlpha();
		}

		return (HBITMAP)bmpIcons.Detach();
	}
#endif

	CBitmap bmpIcons;
	BOOL bAlphaBitmap = IsAlphaBitmapResource(hModule, lpszResource);

	if (lbAlphaBitmap)
	{
		*lbAlphaBitmap = bAlphaBitmap;
	}

	if (bAlphaBitmap)
	{
		return LoadAlphaBitmap(hModule, lpszResource);
	}

	return (HBITMAP)LoadImage(hModule, lpszResource, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
}

HBITMAP CXTPImageManagerIcon::LoadAlphaBitmap(UINT nIDResource)
{
	return LoadAlphaBitmap(AfxFindResourceHandle(MAKEINTRESOURCE(nIDResource), RT_BITMAP),
		MAKEINTRESOURCE(nIDResource));
}

HBITMAP CXTPImageManagerIcon::LoadAlphaBitmap(HMODULE hModule, LPCTSTR lpszResource)
{
	HRSRC hResource = ::FindResource(hModule, lpszResource, RT_BITMAP);
	if (hResource == NULL)
		return NULL;

	HGLOBAL hGlobal = LoadResource(hModule, hResource);
	if (hGlobal == NULL)
		return NULL;

	LPBITMAPINFO pResourceInfo = (LPBITMAPINFO)::LockResource(hGlobal);
	ASSERT(pResourceInfo != NULL);
	if (!pResourceInfo)
		return NULL;

	int biSizeImage = pResourceInfo->bmiHeader.biHeight * pResourceInfo->bmiHeader.biWidth * 4;

	HBITMAP hbmResult = NULL;

	if (pResourceInfo->bmiHeader.biBitCount == 32 &&
		SizeofResource(hModule, hResource) >= int(biSizeImage + sizeof(BITMAPINFOHEADER)))
	{
		CDC dcSrc;
		dcSrc.CreateCompatibleDC(NULL);

		PBITMAPINFO pBitmapInfo = (PBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + sizeof(COLORREF) * 3);
		ASSERT(pBitmapInfo != NULL);
		if (!pBitmapInfo)
			return NULL;

		MEMCPY_S(pBitmapInfo, &pResourceInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
		pBitmapInfo->bmiHeader.biSizeImage = biSizeImage;

		BYTE* pDestBits = NULL;
		HBITMAP hBmp = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pDestBits, NULL, 0);

		if (hBmp && pDestBits)
		{
			MEMCPY_S(pDestBits, &pResourceInfo->bmiColors, biSizeImage);
			hbmResult = hBmp;
		}
		FREE(pBitmapInfo);
	}

	UnlockResource(hGlobal);
	FreeResource(hGlobal);

	return hbmResult;

}



HBITMAP CXTPImageManagerIcon::LoadAlphaIcon(LPCTSTR pszFileName, int nWidth)
{

	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		return NULL;
	}

	ICONDIRHEADER idh;

	DWORD dwBytesRead = 0;
	if (!ReadFile(hFile, &idh, sizeof(ICONDIRHEADER) , &dwBytesRead, NULL) || dwBytesRead != sizeof(ICONDIRHEADER))
	{
		CloseHandle(hFile);
		return FALSE;
	}

	if (idh.idType != 1 || idh.idCount == 0)
	{
		CloseHandle(hFile);
		return FALSE;
	}


	ICONDIRENTRY* pEntries = (ICONDIRENTRY*)malloc(sizeof(ICONDIRENTRY) * idh.idCount);

	if (pEntries == NULL)
	{
		CloseHandle(hFile);
		return FALSE;
	}

	if (!ReadFile(hFile, pEntries, idh.idCount * sizeof(ICONDIRENTRY), &dwBytesRead, NULL)
		|| dwBytesRead != idh.idCount * sizeof(ICONDIRENTRY))
	{
		free(pEntries);
		CloseHandle(hFile);
		return FALSE;
	}

	HBITMAP hBitmap = 0;

	for (int i = 0; i < idh.idCount; i++)
	{
		if (pEntries[i].wBitCount == 32 && (((int)pEntries[i].bWidth == nWidth) || (nWidth == 0)))
		{
			if (!SetFilePointer(hFile, pEntries[i].dwImageOffset,
				NULL, FILE_BEGIN))
				continue;

			ICONIMAGE* pIconImage = (ICONIMAGE*)malloc(pEntries[i].dwBytesInRes);
			if (pIconImage == NULL)
				continue;

			dwBytesRead = 0;
			BOOL bResult = ReadFile(hFile, pIconImage, pEntries[i].dwBytesInRes,
				&dwBytesRead, NULL);

			if (!bResult || (dwBytesRead != pEntries[i].dwBytesInRes) || (pIconImage->icHeader.biBitCount != 32))
			{
				free(pIconImage);
				continue;
			}

			CDC dcSrc;
			dcSrc.CreateCompatibleDC(NULL);

			pIconImage->icHeader.biHeight /= 2;
			pIconImage->icHeader.biSizeImage = pIconImage->icHeader.biHeight * pIconImage->icHeader.biWidth * 4;

			BYTE* pDest = NULL;
			HBITMAP hBmp = CreateDIBSection(dcSrc, (BITMAPINFO*)&pIconImage->icHeader, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);

			if (pDest != NULL && hBmp != NULL)
			{
				MEMCPY_S(pDest, &pIconImage->icColors, pIconImage->icHeader.biSizeImage);
				hBitmap = hBmp;

				free(pIconImage);
				break;
			}

			free(pIconImage);
		}
	}
	free(pEntries);
	CloseHandle(hFile);

	return hBitmap;

}

BOOL CXTPImageManager::SetIconFromIcoFile(LPCTSTR pszFileName, UINT nIDCommand, CSize szIcon, XTPImageState imageState)
{
	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	CXTPImageManagerIcon::ICONDIRHEADER idh;

	DWORD dwBytesRead = 0;
	if (!ReadFile(hFile, &idh, sizeof(CXTPImageManagerIcon::ICONDIRHEADER) , &dwBytesRead, NULL) || dwBytesRead != sizeof(CXTPImageManagerIcon::ICONDIRHEADER))
	{
		CloseHandle(hFile);
		return FALSE;
	}

	if (idh.idType != 1 || idh.idCount == 0)
	{
		CloseHandle(hFile);
		return FALSE;
	}


	CXTPImageManagerIcon::ICONDIRENTRY* pEntries = (CXTPImageManagerIcon::ICONDIRENTRY*)malloc(sizeof(CXTPImageManagerIcon::ICONDIRENTRY) * idh.idCount);

	if (pEntries == NULL)
	{
		CloseHandle(hFile);
		return FALSE;
	}

	if (!ReadFile(hFile, pEntries, idh.idCount * sizeof(CXTPImageManagerIcon::ICONDIRENTRY), &dwBytesRead, NULL)
		|| dwBytesRead != idh.idCount * sizeof(CXTPImageManagerIcon::ICONDIRENTRY))
	{
		free(pEntries);
		CloseHandle(hFile);
		return FALSE;
	}

	BOOL bResult = FALSE;

	for (int i = 0; i < idh.idCount; i++)
	{
		CSize szResourceIcon((int)pEntries[i].bWidth, (int)pEntries[i].bHeight);
		CXTPImageManagerIconHandle hIcon;

		if ((szIcon == szResourceIcon) || (szIcon == CSize(0, 0)))
		{
			if (!SetFilePointer(hFile, pEntries[i].dwImageOffset,
				NULL, FILE_BEGIN))
				continue;

			CXTPImageManagerIcon::ICONIMAGE* pIconImage = (CXTPImageManagerIcon::ICONIMAGE*)malloc(pEntries[i].dwBytesInRes);
			if (pIconImage == NULL)
				continue;

			dwBytesRead = 0;
			BOOL bReadFile = ReadFile(hFile, pIconImage, pEntries[i].dwBytesInRes,
				&dwBytesRead, NULL);

			if (!bReadFile || (dwBytesRead != pEntries[i].dwBytesInRes))
			{
				free(pIconImage);
				continue;
			}

			if (pIconImage->icHeader.biBitCount == 32)
			{

				CDC dcSrc;
				dcSrc.CreateCompatibleDC(NULL);

				pIconImage->icHeader.biHeight /= 2;
				pIconImage->icHeader.biSizeImage = pIconImage->icHeader.biHeight * pIconImage->icHeader.biWidth * 4;

				BYTE* pDest = NULL;
				HBITMAP hBitmap = CreateDIBSection(dcSrc, (BITMAPINFO*)&pIconImage->icHeader, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);

				if (pDest != NULL && hBitmap != NULL)
				{
					MEMCPY_S(pDest, &pIconImage->icColors, pIconImage->icHeader.biSizeImage);

					hIcon = hBitmap;
				}
			}
			else
			{
				hIcon = CreateIconFromResourceEx((PBYTE)pIconImage, pEntries[i].dwBytesInRes, TRUE,
					0x00030000, szResourceIcon.cx, szResourceIcon.cy, LR_DEFAULTCOLOR);
			}

			if (!hIcon.IsEmpty())
			{
				SetIcon(hIcon, nIDCommand, szResourceIcon, imageState);
				bResult = TRUE;
			}

			free(pIconImage);
		}
	}
	free(pEntries);
	CloseHandle(hFile);

	return bResult;
}

//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerResource

CXTPImageManagerResource::CXTPImageManagerResource(CXTPImageManager* pImageManager, CSize szIcon)
{
	m_pImageManager = pImageManager;
	m_szIcon = szIcon;
	m_pBits = NULL;
	m_nAllocWidth = 0;

	m_hbmpImage = 0;
	m_hbmpMask = 0;

	HDC hdcScreen = ::GetDC(HWND_DESKTOP);
	m_dc.Attach(::CreateCompatibleDC(hdcScreen));
	ReleaseDC(HWND_DESKTOP, hdcScreen);

	::InitializeCriticalSection(&m_cs);
}

CXTPImageManagerResource::~CXTPImageManagerResource()
{
	RemoveAll();

	::DeleteCriticalSection(&m_cs);
}

void CXTPImageManagerResource::RemoveAll()
{
	int i;
	for (i = 0; i < (int)m_arrIcons.GetSize(); i++)
	{
		delete m_arrIcons[i];
	}
	m_arrIcons.RemoveAll();

	for (i = 0; i < (int)m_arrAlloc.GetSize(); i++)
	{
		delete m_arrAlloc[i];
	}
	m_arrAlloc.RemoveAll();


	if (m_hbmpImage)
	{
		DeleteObject(m_hbmpImage);
		m_hbmpImage = NULL;
	}
	if (m_hbmpMask)
	{
		DeleteObject(m_hbmpMask);
		m_hbmpMask = NULL;
	}

	m_nAllocWidth = 0;
	m_pBits = NULL;
}


CXTPImageManagerResource* CXTPImageManager::GetResource(CSize szIcon)
{
	DWORD dwSize = MAKELONG(szIcon.cx, szIcon.cy);

	CXTPImageManagerResource* pResource = NULL;
	if (m_mapResources.Lookup(dwSize, pResource))
		return pResource;

	pResource = new CXTPImageManagerResource(this, szIcon);
	m_mapResources.SetAt(dwSize, pResource);

	return pResource;
}

XTP_IMAGERESOURCE_INFO* CXTPImageManagerResource::AllocBitmap()
{
	if (m_arrAlloc.GetSize() > 0)
	{
		XTP_IMAGERESOURCE_INFO* pRInfo = m_arrAlloc[m_arrAlloc.GetSize() - 1];
		m_arrAlloc.RemoveAt(m_arrAlloc.GetSize() - 1);
		m_arrIcons.Add(pRInfo);
		return pRInfo;
	}

	if (!m_hbmpImage && !m_hbmpMask)
	{
		m_hbmpImage = CXTPImageManager::Create32BPPDIBSection(NULL, m_szIcon.cx, m_szIcon.cy, &m_pBits);
		m_hbmpMask = CreateBitmap(m_szIcon.cx, m_szIcon.cy, 1, 1, NULL);

		m_nAllocWidth = m_szIcon.cx;

		if (!m_hbmpImage || !m_hbmpMask)
			return NULL;

		XTP_IMAGERESOURCE_INFO* pRInfo = new XTP_IMAGERESOURCE_INFO();
		pRInfo->pResource = this;
		pRInfo->bAlpha = FALSE;
		pRInfo->rc = CRect(0, 0, m_szIcon.cx, m_szIcon.cy);

		m_arrIcons.Add(pRInfo);
		return pRInfo;
	}

	LPBYTE pBits = NULL;
	HBITMAP hbmpImage = CXTPImageManager::Create32BPPDIBSection(NULL, m_szIcon.cx + m_nAllocWidth, m_szIcon.cy, &pBits);
	HBITMAP hbmpMask = CreateBitmap(m_szIcon.cx + m_nAllocWidth, m_szIcon.cy, 1, 1, NULL);

	if (hbmpImage && pBits)
	{
		LPBYTE pBitsI = pBits;

		for (int y = 0; y < m_szIcon.cy; y++)
		{
			memcpy(pBitsI, m_pBits, m_nAllocWidth * 4);
			m_pBits += m_nAllocWidth * 4;
			pBitsI += (m_szIcon.cx + m_nAllocWidth) * 4;
		}
	}
	else
	{
		return NULL;
	}

	if (hbmpMask)
	{
		m_dc.SetBitmap(hbmpMask);
		m_dc.DrawState(CPoint(0, 0), CSize(0, 0), m_hbmpMask, 0, 0);
		m_dc.SetBitmap(NULL);
	}
	else
	{
		return NULL;
	}

	DeleteObject(m_hbmpImage);
	DeleteObject(m_hbmpMask);

	m_hbmpImage = hbmpImage;
	m_hbmpMask = hbmpMask;
	m_pBits = pBits;

	XTP_IMAGERESOURCE_INFO* pRInfo = new XTP_IMAGERESOURCE_INFO();
	pRInfo->pResource = this;
	pRInfo->bAlpha = FALSE;
	pRInfo->rc = CRect(m_nAllocWidth, 0, m_nAllocWidth + m_szIcon.cx, m_szIcon.cy);
	m_arrIcons.Add(pRInfo);

	m_nAllocWidth += m_szIcon.cx;

	return pRInfo;
}

void CXTPImageManagerResource::Clear(XTP_IMAGERESOURCE_INFO* pRInfo)
{
	CXTPLockGuard lock(m_cs);

	for (int i = 0; i < (int)m_arrIcons.GetSize(); i++)
	{
		if (m_arrIcons[i] == pRInfo)
		{
			m_arrIcons.RemoveAt(i);
			m_arrAlloc.Add(pRInfo);

			if (m_arrAlloc.GetSize() * m_szIcon.cx == m_nAllocWidth)
			{
				ASSERT(m_arrIcons.GetSize() == 0);
				RemoveAll();
			}
			return;
		}
	}
}

BOOL AFX_CDECL CXTPImageManagerIcon::IsAlphaIconHandle(HICON hIcon)
{
	if (!hIcon)
		return FALSE;

	ICONINFO iconInfo;
	if ((CXTPImageManager::IsAlphaIconsImageListSupported() || XTPSystemVersion()->IsWinXPOrGreater())
		&& GetIconInfo(hIcon, &iconInfo))
	{
		LPBYTE pBitsI = NULL;
		BOOL bAlpha = -1;
		HBITMAP hBitmap = CXTPImageManagerIcon::PreMultiplyAlphaBitmap(iconInfo.hbmColor, &bAlpha, &pBitsI);

		DeleteObject(iconInfo.hbmColor);
		DeleteObject(iconInfo.hbmMask);

		if (bAlpha == TRUE && pBitsI)
		{
			DeleteObject(hBitmap);
			return TRUE;
		}

		if (hBitmap) DeleteObject(hBitmap);
	}

	return FALSE;
}

XTP_IMAGERESOURCE_INFO* CXTPImageManagerResource::Add(const CXTPImageManagerIconHandle& hHandle)
{
	CXTPLockGuard lock(m_cs);

	ASSERT(hHandle.m_pRInfo == NULL);
	ASSERT(!hHandle.IsEmpty());
	if (hHandle.IsEmpty())
		return NULL;

	if (hHandle.GetExtent() != GetExtent())
		return NULL;

	if (!hHandle.m_hIcon && !hHandle.m_hBitmap)
		return NULL;

	XTP_IMAGERESOURCE_INFO* pRInfo = AllocBitmap();
	if (pRInfo == NULL)
		return NULL;

	if (hHandle.m_hIcon)
	{
		ICONINFO iconInfo;
		if (CXTPImageManager::IsAlphaIconsImageListSupported() && GetIconInfo(hHandle.m_hIcon, &iconInfo))
		{
			LPBYTE pBitsI = NULL;
			BOOL bAlpha = -1;
			HBITMAP hBitmap = CXTPImageManagerIcon::PreMultiplyAlphaBitmap(iconInfo.hbmColor, &bAlpha, &pBitsI);

			DeleteObject(iconInfo.hbmColor);
			DeleteObject(iconInfo.hbmMask);

			if (bAlpha == TRUE && pBitsI)
			{
				for (int y = 0; y < m_szIcon.cy; y++)
				{
					LPBYTE pBitsRow = m_pBits + ((y * m_nAllocWidth + pRInfo->rc.left) * 4);
					memcpy(pBitsRow, pBitsI, m_szIcon.cx * 4);
					pBitsI += m_szIcon.cx * 4;
				}

				pRInfo->bAlpha = TRUE;

				DeleteObject(hBitmap);
				return pRInfo;
			}

			if (hBitmap) DeleteObject(hBitmap);
		}

		if (m_hbmpImage)
		{
			m_dc.SetBitmap(m_hbmpImage);
			m_dc.FillSolidRect(pRInfo->rc, 0);
			DrawIconEx(m_dc, pRInfo->rc.left, pRInfo->rc.top, hHandle.m_hIcon, 0, 0, 0, NULL, DI_NORMAL);
			m_dc.SetBitmap(NULL);
		}

		if (m_hbmpMask)
		{
			m_dc.SetBitmap(m_hbmpMask);
			m_dc.FillSolidRect(pRInfo->rc, 0);
			DrawIconEx(m_dc, pRInfo->rc.left, pRInfo->rc.top, hHandle.m_hIcon, 0, 0, 0, NULL, DI_MASK);
			m_dc.SetBitmap(NULL);
		}

		pRInfo->bAlpha = FALSE;
	}
	else
	{
		LPBYTE pBitsI = ((CXTPImageManagerIconHandle&)hHandle).PreMultiply();
		if (!pBitsI)
			return NULL;

		for (int y = 0; y < m_szIcon.cy; y++)
		{
			LPBYTE pBitsRow = m_pBits + ((y * m_nAllocWidth + pRInfo->rc.left) * 4);
			memcpy(pBitsRow, pBitsI, m_szIcon.cx * 4);
			pBitsI += m_szIcon.cx * 4;
		}

		pRInfo->bAlpha = TRUE;
	}

	return pRInfo;
}

BOOL CXTPImageManager::IsDrawReverted(CDC* pDC) const
{
	if (m_bDrawReverted == 1)
		return TRUE;
	if (m_bDrawReverted == 2)
		return CXTPDrawHelpers::IsContextRTL(pDC);
	return FALSE;
}

void CXTPImageManagerResource::CreateIcon(CXTPImageManagerIconHandle& hHandle, XTP_IMAGERESOURCE_INFO* pRInfo)
{
	CXTPLockGuard lock(m_cs);

	hHandle.Clear();

	HBITMAP hBitmap = 0;
	LPBYTE pBits = 0;


	{
		hBitmap = CXTPImageManager::Create32BPPDIBSection(NULL, m_szIcon.cx, m_szIcon.cy, &pBits);
		if (!hBitmap || !pBits)
			return;

		LPBYTE pBitsI = pBits;

		for (int y = 0; y < m_szIcon.cy; y++)
		{
			LPBYTE pBitsRow = m_pBits + ((y * m_nAllocWidth + pRInfo->rc.left) * 4);
			memcpy(pBitsI, pBitsRow, m_szIcon.cx * 4);
			pBitsI += m_szIcon.cx * 4;
		}
	}

	if (pRInfo->bAlpha)
	{
		hHandle.m_hBitmap = hBitmap;
		hHandle.m_pBits = pBits;
	}
	else
	{
		HBITMAP hbmpMask = CreateBitmap(m_szIcon.cx, m_szIcon.cy, 1, 1, NULL);
		{
			CXTPCompatibleDC dc(0, hbmpMask);
			m_dc.SetBitmap(m_hbmpMask);
			dc.BitBlt(0, 0, m_szIcon.cx, m_szIcon.cy, &m_dc, pRInfo->rc.left, 0, SRCCOPY);
			m_dc.SetBitmap(NULL);
		}

		ICONINFO ii;
		ii.fIcon    = TRUE;
		ii.xHotspot = 0;
		ii.yHotspot = 0;
		ii.hbmColor = hBitmap;
		ii.hbmMask  = hbmpMask;
		hHandle.m_hIcon = CreateIconIndirect(&ii);

		DeleteObject(hBitmap);
		DeleteObject(hbmpMask);
	}

	hHandle.m_bClearHandles = TRUE;
}


void CXTPImageManagerResource::DrawIconComposited(CDC* pDC, XTP_IMAGERESOURCE_INFO* pRInfo, CPoint pt, CSize szIcon)
{
	CBitmap bmp;
	LPDWORD lpBits = 0;
	bmp.Attach(CXTPImageManager::Create32BPPDIBSection(pDC->GetSafeHdc(), szIcon.cx, szIcon.cy, (LPBYTE*)&lpBits));
	if (!lpBits)
		return;

	CXTPCompatibleDC dc(&m_dc, &bmp);

	dc.SetBkColor(0xFFFFFF);
	dc.SetTextColor(0);

	if (m_hbmpMask)
	{
		m_dc.SetBitmap(m_hbmpMask);
		StretchBlt(dc, 0, 0, szIcon.cx, szIcon.cy, m_dc, pRInfo->rc.left, 0, m_szIcon.cx, m_szIcon.cy, SRCCOPY);
		m_dc.SetBitmap(NULL);
	}

	for (int i = 0; i < szIcon.cx * szIcon.cy; i++)
	{
		*lpBits =  (*lpBits == 0) ? 0xFF000000 : 0;
		lpBits++;
	}

	if (m_hbmpImage)
	{
		m_dc.SetBitmap(m_hbmpImage);
		StretchBlt(dc, 0, 0, szIcon.cx, szIcon.cy, m_dc, pRInfo->rc.left, 0, m_szIcon.cx, m_szIcon.cy, SRCINVERT);
		m_dc.SetBitmap(NULL);
	}

	XTPImageManager()->AlphaBlend(*pDC, CRect(pt, szIcon), dc, CRect(0, 0, szIcon.cx, szIcon.cy));
}


void CXTPImageManagerResource::Draw(CDC* pDC, XTP_IMAGERESOURCE_INFO* pRInfo, CPoint pt, CSize szIcon, BOOL bDrawComposited)
{
	CXTPLockGuard lock(m_cs);

	if (!pRInfo->bAlpha)
	{
		pDC->SetStretchBltMode(COLORONCOLOR);

		if (bDrawComposited)
		{
			DrawIconComposited(pDC, pRInfo, pt, szIcon);
			return;
		}

		if (m_pImageManager->IsDrawReverted(pDC))
		{
			pt.x += szIcon.cx;
			szIcon.cx = -szIcon.cx;
		}

		if (m_hbmpMask)
		{
			m_dc.SetBitmap(m_hbmpMask);
			m_dc.SetTextColor(0);
			m_dc.SetBkColor(0xFFFFFF);

			COLORREF clrOldText = pDC->SetTextColor(0);
			COLORREF clrOldBk = pDC->SetBkColor(0xFFFFFF);

			StretchBlt(pDC->GetSafeHdc(), pt.x, pt.y, szIcon.cx, szIcon.cy, m_dc, pRInfo->rc.left,  0,  m_szIcon.cx, m_szIcon.cy, SRCAND);

			pDC->SetBkColor(clrOldBk);
			pDC->SetTextColor(clrOldText);
			m_dc.SetBitmap(NULL);
		}

		if (m_hbmpImage)
		{
			m_dc.SetBitmap(m_hbmpImage);
			StretchBlt(pDC->GetSafeHdc(), pt.x, pt.y, szIcon.cx, szIcon.cy, m_dc, pRInfo->rc.left,  0,  m_szIcon.cx, m_szIcon.cy, SRCINVERT);
			m_dc.SetBitmap(NULL);
		}
	}
	else
	{
		m_dc.SetBitmap(m_hbmpImage);
		XTPImageManager()->AlphaBlend(pDC->GetSafeHdc(), CRect(pt, szIcon),
			m_dc, CRect(pRInfo->rc.TopLeft(), m_szIcon));
		m_dc.SetBitmap(NULL);
	}
}

CSize CXTPImageManagerResource::GetExtent() const
{
	return m_szIcon;
}


//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerIconHandle

void CXTPImageManagerIconHandle::Init()
{
	m_hIcon = NULL;
	m_hBitmap = NULL;
	m_pBits = NULL;
	m_bClearHandles = FALSE;
	m_pImageManager = NULL;
	m_pRInfo = NULL;
	m_szIcon = CSize(0, 0);
	m_bUseResources = TRUE;
}

CXTPImageManagerIconHandle::CXTPImageManagerIconHandle()
{
	Init();
}

CXTPImageManagerIconHandle::CXTPImageManagerIconHandle(HICON hIcon, BOOL bUseResources)
{
	Init();

	m_hIcon = hIcon;
	m_bClearHandles = FALSE;
	m_szIcon = _GetExtent();
	m_bUseResources = bUseResources;
}

CXTPImageManagerIconHandle::CXTPImageManagerIconHandle(HBITMAP hBitmap)
{
	Init();

	m_hBitmap = hBitmap;
	m_bClearHandles = FALSE;
	m_szIcon = _GetExtent();
}

CXTPImageManagerIconHandle::CXTPImageManagerIconHandle(const CXTPImageManagerIconHandle& hHandle)
{
	Init();

	m_hIcon = hHandle.m_hIcon;
	m_hBitmap = hHandle.m_hBitmap;
	m_pBits = hHandle.m_pBits;
	m_pRInfo = hHandle.m_pRInfo;
	m_pImageManager = hHandle.m_pImageManager;
	m_bUseResources = hHandle.m_bUseResources;

	m_bClearHandles = FALSE;
	m_szIcon = hHandle.GetExtent();
}


void CXTPImageManagerIconHandle::CopyHandle(HBITMAP hBitmap)
{
	Clear();
	m_hBitmap = CXTPImageManagerIcon::CopyAlphaBitmap(hBitmap);

	m_szIcon = _GetExtent();
	m_bClearHandles = TRUE;
}

void CXTPImageManagerIconHandle::CopyHandle(const CXTPImageManagerIconHandle& hHandle)
{
	Clear();

	if (m_pImageManager && !hHandle.IsEmpty() && m_pImageManager->m_bUseResources && hHandle.m_bUseResources)
	{
		CXTPImageManagerResource* pResource = m_pImageManager->GetResource(hHandle.GetExtent());

		if (hHandle.m_pRInfo == NULL)
		{
			m_pRInfo = pResource->Add(hHandle);
		}
		else
		{
			CXTPImageManagerIconHandle iconClear;
			iconClear.CopyHandle(hHandle);
			m_pRInfo = pResource->Add(iconClear);
		}
	}
	else
	{
		if (hHandle.m_hIcon) m_hIcon = CopyIcon(hHandle.m_hIcon);
		if (hHandle.m_hBitmap) m_hBitmap = CXTPImageManagerIcon::CopyAlphaBitmap(hHandle.m_hBitmap, hHandle.m_pBits ? &m_pBits : NULL);
		if (hHandle.m_pRInfo)
		{
			hHandle.m_pRInfo->pResource->CreateIcon(*this, hHandle.m_pRInfo);
		}
	}
	m_bUseResources = hHandle.m_bUseResources;

	m_bClearHandles = TRUE;
	m_szIcon = hHandle.GetExtent();
}

const CXTPImageManagerIconHandle& CXTPImageManagerIconHandle::operator=(const HICON hIcon)
{
	Clear();
	m_hIcon = hIcon;
	m_bClearHandles = TRUE;
	m_szIcon = _GetExtent();

	return *this;
}
const CXTPImageManagerIconHandle& CXTPImageManagerIconHandle::operator=(const HBITMAP hBitmap)
{
	Clear();

	m_hBitmap = hBitmap;
	m_bClearHandles = TRUE;
	m_szIcon = _GetExtent();

	return *this;
}

CXTPImageManagerIconHandle::~CXTPImageManagerIconHandle()
{
	Clear();
}

BOOL CXTPImageManagerIconHandle::IsEmpty() const
{
	return (m_hIcon == 0 && m_hBitmap == 0 && m_pRInfo == NULL) || (m_szIcon == CSize(0, 0));
}

BOOL CXTPImageManagerIconHandle::IsAlpha() const
{
	return m_hBitmap != 0 || (m_pRInfo && m_pRInfo->bAlpha);
}

HBITMAP CXTPImageManagerIconHandle::GetBitmap() const
{
	ASSERT(IsAlpha());

	if (m_hBitmap)
		return m_hBitmap;

	if (m_pRInfo && m_pRInfo->pResource && m_pRInfo->pResource->m_hbmpImage)
		return m_pRInfo->pResource->m_hbmpImage;

	ASSERT(FALSE);
	return NULL;
}

HICON CXTPImageManagerIconHandle::GetIcon() const
{
	return m_hIcon;
}

void CXTPImageManagerIconHandle::Detach()
{
	m_bClearHandles = FALSE;
	Clear();
}

void CXTPImageManagerIconHandle::Clear()
{
	if (m_bClearHandles)
	{
		if (m_hIcon)
		{
			DestroyIcon(m_hIcon);
		}

		if (m_hBitmap)
		{
			DeleteObject(m_hBitmap);
		}

		if (m_pRInfo)
		{
			m_pRInfo->pResource->Clear(m_pRInfo);
			m_pRInfo = NULL;
		}
	}

	m_hIcon = 0;
	m_hBitmap = 0;
	m_pBits = 0;
	m_pRInfo = NULL;
	m_bClearHandles = FALSE;
}

CSize CXTPImageManagerIconHandle::GetExtent() const
{
	return m_szIcon;
}

CSize CXTPImageManagerIconHandle::_GetExtent() const
{
	if (m_pRInfo != NULL)
		return m_pRInfo->pResource->GetExtent();

	if (m_hIcon)
		return CXTPImageManagerIcon::GetExtent(m_hIcon);

	if (m_hBitmap)
	{
		BITMAP bmpinfo;
		if (::GetObject(m_hBitmap, sizeof(bmpinfo), &bmpinfo))
		{
			return CSize((int)bmpinfo.bmWidth, (int)bmpinfo.bmHeight);
		}
	}
	return 0;
}



void CXTPImageManagerIconHandle::Draw(CDC* pDC, CPoint pt, CSize szIcon, BOOL bDrawComposited)
{
	if (IsEmpty())
		return;

	if (m_pRInfo)
	{
		m_pRInfo->pResource->Draw(pDC, m_pRInfo, pt, szIcon, bDrawComposited);
	}
	else if (!IsAlpha())
	{
		CXTPImageManager* pImageManager = m_pImageManager ? m_pImageManager : XTPImageManager();

		if (pImageManager->IsDrawReverted(pDC))
		{
			pt.x += szIcon.cx;
			szIcon.cx = -szIcon.cx;
		}

		if (!bDrawComposited)
		{
			DrawIconEx(pDC->GetSafeHdc(), pt.x, pt.y, GetIcon(), szIcon.cx, szIcon.cy, 0, 0, DI_NORMAL);
		}
		else
		{
			CXTPImageManagerIcon::DrawIconComposited(pDC, pt, szIcon, GetIcon());
		}
	}
	else if (PreMultiply())
	{
		if (pt.y < 0 && (szIcon.cy == (int)m_szIcon.cy))
		{
			if (pt.y + m_szIcon.cy > 0)
			{
				CXTPImageManagerIcon::DrawAlphaBitmap(pDC, m_hBitmap, CPoint(pt.x, 0),
					CSize(szIcon.cx, m_szIcon.cy + pt.y), CPoint(0, -pt.y), CSize(m_szIcon.cx, m_szIcon.cy + pt.y));
			}
		}
		else
		{
			CXTPImageManagerIcon::DrawAlphaBitmap(pDC, m_hBitmap, pt, szIcon, CPoint(0, 0), m_szIcon);
		}
	}
}

BOOL CXTPImageManagerIconHandle::CreateIconFromResource(LPCTSTR lpszResourceName, CSize szIcon, BOOL bGroupResource)
{
	if (bGroupResource)
	{
		HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_GROUP_ICON);
		if (hInst)
			return CreateIconFromResource(hInst, lpszResourceName, szIcon, TRUE);
	}

	HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ICON);
	if (hInst)
		return CreateIconFromResource(hInst, lpszResourceName, szIcon, FALSE);

	return FALSE;

}

BOOL CXTPImageManagerIconHandle::CreateIconFromResource(HINSTANCE hInst, LPCTSTR lpszResourceName, CSize szIcon, BOOL bGroupResource)
{
	HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_GROUP_ICON);

	if (hRsrc != NULL && bGroupResource)
	{
		// Load and Lock to get a pointer to a GRPICONDIR
		HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
		if (!hGlobal)
			return FALSE;

		CXTPImageManagerIcon::GRPICONDIR* lpGrpIconDir = (CXTPImageManagerIcon::GRPICONDIR*)LockResource(hGlobal);
		if (!lpGrpIconDir)
			return FALSE;

		for (int i = (int)lpGrpIconDir->idCount - 1; i >= 0; i--)
		{
			if (lpGrpIconDir->idEntries[i].bWidth == szIcon.cx && lpGrpIconDir->idEntries[i].bHeight == szIcon.cy)
			{
				if (CreateIconFromResource(hInst, MAKEINTRESOURCE(lpGrpIconDir->idEntries[i].nID), szIcon, FALSE))
					return TRUE;
			}
		}

		return FALSE;
	}

	hRsrc = ::FindResource(hInst, lpszResourceName, RT_ICON);

	if (hRsrc == NULL)
		return FALSE;

	HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
	if (!hGlobal)
		return FALSE;
	CXTPImageManagerIcon::ICONIMAGE* lpIconImage = (CXTPImageManagerIcon::ICONIMAGE*)LockResource(hGlobal);

	if (lpIconImage == NULL)
		return FALSE;

	DWORD dwResourceSize = SizeofResource(hInst, hRsrc);

	if (lpIconImage->icHeader.biBitCount == 32)
	{
		CDC dcSrc;
		dcSrc.CreateCompatibleDC(0);

		BITMAPINFOHEADER* pBitmapInfo = (BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER) + sizeof(COLORREF) * 3);
		if (!pBitmapInfo)
			return FALSE;

		*pBitmapInfo = lpIconImage->icHeader;

		pBitmapInfo->biHeight /= 2;
		pBitmapInfo->biSizeImage = pBitmapInfo->biHeight * pBitmapInfo->biWidth * 4;

		BYTE* pDest = NULL;
		HBITMAP hBitmap = CreateDIBSection(dcSrc, (BITMAPINFO*)pBitmapInfo, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);

		if (pDest == NULL || hBitmap == NULL)
		{
			free(pBitmapInfo);
			return FALSE;
		}

		ASSERT(pBitmapInfo->biSizeImage <= dwResourceSize - sizeof(BITMAPINFOHEADER));

		MEMCPY_S(pDest, &lpIconImage->icColors, pBitmapInfo->biSizeImage);

		*this = hBitmap; // NOTE: it call DeleteObejct in destructor
		free(pBitmapInfo);
	}
	else
	{
		*this = CreateIconFromResourceEx((PBYTE)lpIconImage, dwResourceSize, TRUE,
			0x00030000, szIcon.cx, szIcon.cy, LR_DEFAULTCOLOR);
	}

	return !IsEmpty();
}


LPBYTE CXTPImageManagerIconHandle::PreMultiply()
{
	if (m_pBits != NULL)
		return m_pBits;

	if (m_hBitmap == 0)
		return NULL;

	LPBYTE pBits = NULL;

	HBITMAP hBitmapAlpha =  CXTPImageManagerIcon::PreMultiplyAlphaBitmap(m_hBitmap, NULL, &pBits);
	if (!hBitmapAlpha || (pBits == NULL))
		return NULL;

	Clear();

	m_hBitmap = hBitmapAlpha;
	m_pBits = pBits;
	m_bClearHandles = TRUE;
	m_szIcon = _GetExtent();

	return m_pBits;
}

BOOL CXTPImageManagerIcon::IsAlpha() const
{
	return m_hIcon.IsAlpha();
}

HBITMAP CXTPImageManagerIcon::InvertAlphaBitmap(HBITMAP hBitmap)
{

	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	DWORD* pBits = 0;
	PBITMAPINFO pBitmapInfo = 0;

	HBITMAP hBitmapAlpha = 0;

	TRY
	{
		UINT nSize;
		if (!GetBitmapBits(dcSrc, hBitmap, pBitmapInfo, (LPVOID&)pBits, nSize))
			return 0;

		DWORD* pDest = NULL;

		hBitmapAlpha = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);
		if (pDest == NULL || hBitmapAlpha == NULL)
			AfxThrowMemoryException();

		int cy = pBitmapInfo->bmiHeader.biHeight;
		int cx = pBitmapInfo->bmiHeader.biWidth;

		for (int y = 0; y < cy; y++)
		{
			DWORD* pBitsRow = &pBits[y * cx + cx - 1];

			for (int x = 0; x < cx; x++)
			{
				*pDest++ = *pBitsRow--;
			}
		}
	}
	CATCH (CMemoryException, e)
	{
		TRACE(_T("Failed -- Memory exception thrown."));
	}
	END_CATCH

	FREE(pBits);
	FREE(pBitmapInfo);

	return hBitmapAlpha;
}

HBITMAP CXTPImageManagerIcon::PreMultiplyAlphaBitmap(HBITMAP hBitmap, BOOL* pbAlpha, LPBYTE* lpBits)
{
	if (lpBits) *lpBits = NULL;

	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	PBYTE pBitsSrc = 0;
	PBITMAPINFO pBitmapInfo = 0;

	HBITMAP hBitmapAlpha = 0;

	TRY
	{
		UINT nSize;
		if (!GetBitmapBits(dcSrc, hBitmap, pBitmapInfo, (LPVOID&)pBitsSrc, nSize))
			return 0;

		BYTE* pBitsDest = NULL;

		hBitmapAlpha = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pBitsDest, NULL, 0);
		if (pBitsDest == NULL || hBitmapAlpha == NULL)
			AfxThrowMemoryException();

		MEMCPY_S(pBitsDest, pBitsSrc, nSize);

		BOOL bAlpha0Found = FALSE;

		BYTE* pBitsI = pBitsDest;
		UINT nCount = nSize / 4;

		for (UINT i = 0; i < nCount; i++)
		{
			int nAlpha = pBitsI[3];
			pBitsI[0] = BYTE(pBitsI[0] * nAlpha / 255);
			pBitsI[1] = BYTE(pBitsI[1] * nAlpha / 255);
			pBitsI[2] = BYTE(pBitsI[2] * nAlpha / 255);

			if (pbAlpha)
			{
				if (nAlpha == 0)
					bAlpha0Found = TRUE;

				if ((nAlpha != 255 && nAlpha != 0) || (nAlpha == 255 && bAlpha0Found) || (nAlpha == 255 && *pbAlpha == -1))
					*pbAlpha = TRUE;
			}
			pBitsI += 4;
		}

		if (pbAlpha && (*pbAlpha == FALSE))
		{
			MEMCPY_S(pBitsDest, pBitsSrc, nSize);
		}

		if (lpBits)
		{
			*lpBits = pBitsDest;
		}

	}
	CATCH (CMemoryException, e)
	{
		TRACE(_T("Failed -- Memory exception thrown."));
	}
	END_CATCH

	FREE(pBitsSrc);
	FREE(pBitmapInfo);

	return hBitmapAlpha;
}

BOOL CXTPImageManagerIcon::GetBitmapBits(CDC& dcSrc, HBITMAP hBitmap, PBITMAPINFO& pBitmapInfo, LPVOID& pBits, UINT& nSize)
{
	if (hBitmap == 0)
		return FALSE;

	BITMAPINFO  bmi;
	memset(&bmi, 0, sizeof(bmi));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);


	if (GetDIBits(dcSrc, hBitmap, 0, 0, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS) == 0)
		return FALSE;

	if (bmi.bmiHeader.biBitCount != 32)
		return FALSE;

	nSize = bmi.bmiHeader.biHeight * bmi.bmiHeader.biWidth * 4;
	pBits = (PBYTE)malloc(nSize);
	if (pBits == NULL)
		return FALSE;

	if ((pBitmapInfo = (PBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + 3 * sizeof(COLORREF))) == NULL)
	{
		FREE(pBits);
		return FALSE;
	}

	MEMCPY_S(pBitmapInfo, &bmi, sizeof(BITMAPINFOHEADER));

	if (GetDIBits(dcSrc, hBitmap, 0, bmi.bmiHeader.biHeight, pBits, pBitmapInfo, DIB_RGB_COLORS) == NULL)
	{
		FREE(pBits);
		FREE(pBitmapInfo);
		return FALSE;
	}
	return TRUE;
}

HBITMAP CXTPImageManagerIcon::CopyAlphaBitmap(HBITMAP hBitmap, LPBYTE* lpBits)
{
	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	PBYTE pBitsSrc = 0;
	PBITMAPINFO pBitmapInfo = 0;
	UINT nSize;

	if (!GetBitmapBits(dcSrc, hBitmap, pBitmapInfo, (LPVOID&)pBitsSrc, nSize))
		return 0;

	BYTE* pBitsDest = NULL;
	HBITMAP hBmp = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pBitsDest, NULL, 0);

	if (pBitsDest != NULL && hBmp != NULL)
	{
		MEMCPY_S(pBitsDest, pBitsSrc, nSize);
	}

	FREE(pBitsSrc);
	FREE(pBitmapInfo);

	if (lpBits)
	{
		*lpBits = pBitsDest;
	}

	return hBmp;

}




//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerIcon
CXTPImageManagerIcon::CXTPImageManagerIcon(UINT nID, int nWidth, int nHeight, CXTPImageManagerIconSet* pIconSet)
	: m_nID(nID)
	, m_nWidth(nWidth)
	, m_nHeight(nHeight)
	, m_pIconSet(pIconSet)
	, m_pImageList(NULL)
{
	m_bDrawComposited = FALSE;

	if (m_pIconSet)
	{
		m_hIcon.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hFaded.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hShadow.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hHot.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hChecked.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hPressed.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hDisabled.m_pImageManager = m_pIconSet->m_pImageManager;
		m_hDisabledAuto.m_pImageManager = m_pIconSet->m_pImageManager;
	}

}

CXTPImageManagerIcon::CXTPImageManagerIcon(UINT nID, int nWidth, int nHeight, CXTPImageManagerImageList* pImageList)
	: m_nID(nID)
	, m_nWidth(nWidth)
	, m_nHeight(nHeight)
	, m_pIconSet(NULL)
	, m_pImageList(pImageList)
{
}


CXTPImageManagerIcon::~CXTPImageManagerIcon()
{
	Clear(TRUE);
}

UINT CXTPImageManagerIcon::GetID() const
{
	return m_nID;
}

int CXTPImageManagerIcon::GetHeight() const
{
	return m_nHeight;
}

int CXTPImageManagerIcon::GetWidth() const
{
	return m_nWidth;
}

void CXTPImageManagerIcon::Clear(BOOL bIcon /* = FALSE */)
{
	if (bIcon)
	{
		m_hIcon.Clear();
	}
	m_hFaded.Clear();
	m_hShadow.Clear();
	m_hHot.Clear();
	m_hChecked.Clear();
	m_hPressed.Clear();
	m_hDisabled.Clear();
	m_hDisabledAuto.Clear();
}

void CXTPImageManagerIcon::Refresh()
{
	m_hFaded.Clear();
	m_hShadow.Clear();
	m_hDisabledAuto.Clear();
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetIcon()
{
	return m_hIcon;
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetIcon(XTPImageState imageState)
{
	return imageState == xtpImageDisabled ? GetDisabledIcon() : imageState == xtpImageHot? GetHotIcon() :
		imageState == xtpImageChecked? GetCheckedIcon() : imageState == xtpImagePressed? GetPressedIcon() : GetIcon();
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetFadedIcon()
{
	if (m_hFaded.IsEmpty())
	{
		CreateFadedIcon();
	}
	return m_hFaded.IsEmpty() ? m_hIcon : m_hFaded;
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetShadowIcon()
{
	if (m_hShadow.IsEmpty())
	{
		CreateShadowIcon();
	}
	return m_hShadow;
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetHotIcon()
{
	return !m_hHot.IsEmpty() ? m_hHot : m_hIcon;
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetCheckedIcon()
{
	return !m_hChecked.IsEmpty() ? m_hChecked : GetHotIcon();
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetPressedIcon()
{
	return !m_hPressed.IsEmpty() ? m_hPressed : GetHotIcon();
}

BOOL CXTPImageManagerIcon::HasDisabledIcon() const
{
	if (!m_hDisabled.IsEmpty())
		return TRUE;

	if (!m_hDisabledAuto.IsEmpty())
		return TRUE;

	return FALSE;
}

CXTPImageManagerIconHandle& CXTPImageManagerIcon::GetDisabledIcon(BOOL bCreateIfNotExists /*= TRUE*/)
{
	if (!m_hDisabled.IsEmpty())
		return m_hDisabled;

	if (!m_hDisabledAuto.IsEmpty())
		return m_hDisabledAuto;

	if (bCreateIfNotExists)
	{
		CreateDisabledIcon();
	}

	return m_hDisabledAuto;
}

BOOL CXTPImageManagerIcon::SetIcon(const CXTPImageManagerIconHandle& iconHandle, XTPImageState imageState)
{
	switch (imageState)
	{
		case xtpImageNormal:
			SetNormalIcon(iconHandle);
			break;
		case xtpImageHot:
			SetHotIcon(iconHandle);
			break;
		case xtpImageChecked:
			SetCheckedIcon(iconHandle);
			break;
		case xtpImageDisabled:
			SetDisabledIcon(iconHandle);
			break;
		case xtpImagePressed:
			SetPressedIcon(iconHandle);
			break;
		default:
			return FALSE;
	}

	return TRUE;
}


BOOL CXTPImageManagerIcon::SetIcon(const CXTPImageManagerIconHandle& hIcon)
{
	ASSERT(!hIcon.IsEmpty());
	Clear(TRUE);
	m_hIcon.CopyHandle(hIcon);
	CSize sz = GetExtent();

	m_nHeight = sz.cy;
	m_nWidth = sz.cx;

	if (m_pIconSet)
		m_pIconSet->RefreshAll();

	return TRUE;
}

BOOL CXTPImageManagerIcon::SetIcon(UINT nIDResourceIcon, int nWidth, int nHeight)
{
	Clear(TRUE);

	ASSERT(nWidth != 0 && nHeight != 0);

	if (!m_hIcon.CreateIconFromResource(MAKEINTRESOURCE(nIDResourceIcon), CSize(nWidth, nHeight)))
		return FALSE;

	m_nHeight = nHeight;
	m_nWidth = nWidth;

	return TRUE;
}

void CXTPImageManagerIcon::SetNormalIcon(const CXTPImageManagerIconHandle& hIcon)
{
	ASSERT(!hIcon.IsEmpty());

	Refresh();
	m_hIcon.CopyHandle(hIcon);


#ifdef _DEBUG
	CSize sz = GetExtent();

	ASSERT((int)m_nHeight == sz.cy);
	ASSERT((int)m_nWidth == sz.cx);

#endif
}

void CXTPImageManagerIcon::SetHotIcon(const CXTPImageManagerIconHandle& hIcon)
{
	Refresh();
	m_hHot.CopyHandle(hIcon);
}

void CXTPImageManagerIcon::SetCheckedIcon(const CXTPImageManagerIconHandle& hIcon)
{
	Refresh();
	m_hChecked.CopyHandle(hIcon);
}

void CXTPImageManagerIcon::SetPressedIcon(const CXTPImageManagerIconHandle& hIcon)
{
	Refresh();
	m_hPressed.CopyHandle(hIcon);
}

void CXTPImageManagerIcon::SetDisabledIcon(const CXTPImageManagerIconHandle& hIcon)
{
	Refresh();
	m_hDisabled.CopyHandle(hIcon);
}


COLORREF CXTPImageManagerIcon::LightenColor(COLORREF clr, double factor)
{
	return RGB(
		factor * 255 + (1.0 - factor) * GetRValue(clr),
		factor * 255 + (1.0 - factor) * GetGValue(clr),
		factor * 255 + (1.0 - factor) * GetBValue(clr)) ;
}

void CXTPImageManagerIcon::CreateFadedIcon()
{
	ASSERT(m_hFaded.IsEmpty());

	if (!m_hIcon.m_bUseResources)
		return;

	CXTPImageManagerIconHandle hFaded;
	hFaded.CopyHandle(m_hIcon);

	if (!hFaded.IsAlpha())
	{
		ICONINFO info;
		if (GetIconInfo(hFaded.GetIcon(), &info))
		{
			if (!CXTPDrawHelpers::IsLowResolution())
			{
				CXTPCompatibleDC dc(NULL, CBitmap::FromHandle(info.hbmColor));
				CXTPCompatibleDC dcMask(NULL, CBitmap::FromHandle(info.hbmMask));

				BITMAP bmp;
				::GetObject(info.hbmColor, sizeof(BITMAP), &bmp);

				for (int i = 0; i < bmp.bmWidth; i++)
				for (int j = 0; j < bmp.bmHeight; j++)
				{
					COLORREF clr = dc.GetPixel(i, j);
					COLORREF clrMask = dcMask.GetPixel(i, j);
					if (clrMask == 0)
						dc.SetPixel(i, j, LightenColor(clr, .3));
				}
			}

			hFaded = CreateIconIndirect(&info);

			::DeleteObject(info.hbmColor);
			::DeleteObject(info.hbmMask);
		}
	}
	else if (hFaded.PreMultiply())
	{
		PBYTE pBits = hFaded.PreMultiply();
		CSize szIcon = hFaded.GetExtent();

		UINT nCount = szIcon.cx * szIcon.cy;

		for (UINT i = 0; i < nCount; i++)
		{
			int nAlpha = pBits[3];
			if (nAlpha != 0)
			{
				pBits[0] = BYTE(.3 * nAlpha + (1.0 - .3) * pBits[0]);
				pBits[1] = BYTE(.3 * nAlpha + (1.0 - .3) * pBits[1]);
				pBits[2] = BYTE(.3 * nAlpha + (1.0 - .3) * pBits[2]);
			}
			pBits += 4;
		}
	}

	m_hFaded.CopyHandle(hFaded);
}

void CXTPImageManagerIcon::CreateShadowIcon()
{
	ASSERT(m_hShadow.IsEmpty());

	if (!m_hIcon.m_bUseResources)
		return;

	COLORREF clrBackground = GetXtremeColor(XPCOLOR_HIGHLIGHT);
	COLORREF clrShadow = RGB(GetRValue(clrBackground) * .75, GetGValue(clrBackground) * .75, GetBValue(clrBackground) * .75);

	CXTPImageManagerIconHandle hShadow;
	hShadow.CopyHandle(GetHotIcon());

	if (!hShadow.IsAlpha())
	{
		ICONINFO info;
		if (GetIconInfo(hShadow.GetIcon(), &info))
		{
			{
				CXTPCompatibleDC dc(NULL, CBitmap::FromHandle(info.hbmColor));
				CXTPCompatibleDC dcMask(NULL, CBitmap::FromHandle(info.hbmMask));

				BITMAP bmp;
				::GetObject(info.hbmColor, sizeof(BITMAP), &bmp);

				for (int i = 0; i < bmp.bmWidth; i++)
				for (int j = 0; j < bmp.bmHeight; j++)
				{
					COLORREF clrMask = dcMask.GetPixel(i, j);
					if (clrMask == 0)
						dc.SetPixel(i, j, clrShadow);
				}
			}

			hShadow = CreateIconIndirect(&info);

			::DeleteObject(info.hbmMask);
			::DeleteObject(info.hbmColor);
		}
	}
	else if (hShadow.PreMultiply())
	{
		PBYTE pBits = hShadow.PreMultiply();
		CSize szIcon = hShadow.GetExtent();

		UINT nCount = szIcon.cx * szIcon.cy;

		for (UINT i = 0; i < nCount; i++)
		{
			int nAlpha = pBits[3];
			pBits[0] = BYTE(GetRValue(clrShadow) * nAlpha / 255);
			pBits[1] = BYTE(GetGValue(clrShadow) * nAlpha / 255);
			pBits[2] = BYTE(GetBValue(clrShadow) * nAlpha / 255);
			pBits += 4;
		}
	}

	m_hShadow.CopyHandle(hShadow);
}

void CXTPImageManagerIcon::CreateDisabledIcon(COLORREF clrDisabledLight /*= (COLORREF)-1*/, COLORREF clrDisabledDark /*= (COLORREF)-1*/)
{
	if (!m_hDisabledAuto.IsEmpty())
		return;

	BOOL bOfficeDisabledIcons = clrDisabledLight != (COLORREF)-1 && clrDisabledDark != (COLORREF)-1;

	CXTPImageManagerIconHandle hDisabled;
	hDisabled.CopyHandle(m_hIcon);

	if (!hDisabled.IsAlpha())
	{
		ICONINFO info;
		if (GetIconInfo(hDisabled.GetIcon(), &info))
		{
			{
				CXTPCompatibleDC dc(NULL, CBitmap::FromHandle(info.hbmColor));
				CXTPCompatibleDC dcMask(NULL, CBitmap::FromHandle(info.hbmMask));

				BITMAP bmp;
				::GetObject(info.hbmColor, sizeof(BITMAP), &bmp);

				for (int i = 0; i < bmp.bmWidth; i++)
				for (int j = 0; j < bmp.bmHeight; j++)
				{
					COLORREF clrMask = dcMask.GetPixel(i, j);
					COLORREF clr = dc.GetPixel(i, j);

					if (clrMask == 0)
					{
						if (bOfficeDisabledIcons)
						{
							double dGray = (GetRValue(clr) * 0.299 + GetGValue(clr) * 0.587 + GetBValue(clr) * 0.114)/255;
							double dLight = 1.0 - dGray;

							clr = RGB(dLight * GetRValue(clrDisabledDark) + dGray * GetRValue(clrDisabledLight),
								dLight * GetGValue(clrDisabledDark) + dGray * GetGValue(clrDisabledLight),
								dLight * GetBValue(clrDisabledDark) + dGray * GetBValue(clrDisabledLight));

							dc.SetPixel(i, j, clr);
						}
						else
						{
							double dGray = GetRValue(clr) * 0.299 + GetGValue(clr) * 0.587 + GetBValue(clr) * 0.114;
							int nGray = (BYTE)(pow(dGray / 255.0, CXTPImageManager::m_dDisabledBrightnessFactor) * 255.0);

							dc.SetPixel(i, j, RGB(nGray, nGray, nGray));
						}
					}
				}
			}

			hDisabled = CreateIconIndirect(&info);
			::DeleteObject(info.hbmMask);
			::DeleteObject(info.hbmColor);

		}
	}
	else if (hDisabled.PreMultiply())
	{
		PBYTE pBits = hDisabled.PreMultiply();
		CSize szIcon = hDisabled.GetExtent();

		UINT nCount = szIcon.cx * szIcon.cy;

		for (UINT i = 0; i < nCount; i++)
		{
			int nAlpha = pBits[3];
			if (nAlpha != 0)
			{
				int R = pBits[0] * 255 / nAlpha;
				int G = pBits[1] * 255 / nAlpha;
				int B = pBits[2] * 255 / nAlpha;

				if (bOfficeDisabledIcons)
				{
					double dGray = (R * 0.114 + G * 0.587 + B * 0.299)/255.0;
					double dLight = 1.0 - dGray;

					R = BYTE(dLight * GetBValue(clrDisabledDark) + dGray * GetBValue(clrDisabledLight));
					G = BYTE(dLight * GetGValue(clrDisabledDark) + dGray * GetGValue(clrDisabledLight));
					B = BYTE(dLight * GetRValue(clrDisabledDark) + dGray * GetRValue(clrDisabledLight));
				}
				else
				{
					double dGray = R * 0.114 + G * 0.587 + B * 0.299;
					R = G = B = (BYTE)(pow(dGray / 255.0, CXTPImageManager::m_dDisabledBrightnessFactor) * 255.0);
					nAlpha = BYTE(nAlpha / CXTPImageManager::m_dDisabledAlphaFactor);
				}

				pBits[0] = BYTE(R * nAlpha / 255);
				pBits[1] = BYTE(G * nAlpha / 255);
				pBits[2] = BYTE(B * nAlpha / 255);
			}

			pBits += 4;
		}
	}

	m_hDisabledAuto.CopyHandle(hDisabled);
}

CSize CXTPImageManagerIcon::GetExtent() const
{
	return m_hIcon.GetExtent();
}

CSize CXTPImageManagerIcon::GetExtent(HICON hIcon)
{
	ASSERT(hIcon);

	CSize extent(0);
	if (hIcon)
	{
		ICONINFO iconinfo;
		if (::GetIconInfo(hIcon, &iconinfo))
		{
			BITMAP bmpinfo;
			if (::GetObject(iconinfo.hbmMask, sizeof(bmpinfo), &bmpinfo))
			{
				extent.cx = (int)bmpinfo.bmWidth;
				extent.cy = (int)bmpinfo.bmHeight;
				if (!iconinfo.hbmColor)
				{
					// b/w icons have double size for XOR and AND masks
					extent.cy /= 2;
				}
			}
			// cleanup GDI
			if (iconinfo.hbmMask) ::DeleteObject(iconinfo.hbmMask);
			if (iconinfo.hbmColor) ::DeleteObject(iconinfo.hbmColor);
		}
	}
	return extent;
}


HICON CXTPImageManagerIcon::ScaleToFit(HICON hIcon, CSize szExtent, int nWidth)
{
	if (nWidth == 0 || szExtent == CSize(0))
	{
		// invalid arg
		return NULL;
	}
	if (nWidth == szExtent.cx)
		return ::CopyIcon(hIcon);

	CSize szDesiredExtent(nWidth, MulDiv(szExtent.cy, nWidth, szExtent.cx));

	// scale the icon
	CImageList images;
	VERIFY(images.Create(szDesiredExtent.cx, szDesiredExtent.cy, ILC_COLOR32 | ILC_MASK, 1, 1));
	images.Add(hIcon);
	return images.ExtractIcon(0);
}

BOOL CXTPImageManagerIcon::GetDIBBitmap(HBITMAP hBitmap, PBYTE& pBits, UINT& nBitsSize, PBITMAPINFO& pBitmapInfo, UINT& nBitmapInfoSize)
{
	pBits = 0;
	pBitmapInfo = 0;

	BITMAPINFO  bmi;
	memset(&bmi, 0, sizeof(bmi));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	TRY
	{
		if (GetDIBits(dcSrc, hBitmap, 0, 0, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS) == 0)
			AfxThrowMemoryException();

		nBitsSize = bmi.bmiHeader.biSizeImage != 0? bmi.bmiHeader.biSizeImage :
			bmi.bmiHeader.biHeight * bmi.bmiHeader.biWidth * 4;

		pBits = (PBYTE)malloc(nBitsSize);
		if (pBits == NULL)
			AfxThrowMemoryException();

		int nColorTableSize = bmi.bmiHeader.biBitCount == 4 ? 16 : bmi.bmiHeader.biBitCount == 8 ? 256 : 3;

		nBitmapInfoSize = sizeof(BITMAPINFOHEADER) + nColorTableSize * sizeof(COLORREF);
		if ((pBitmapInfo = (PBITMAPINFO)malloc(nBitmapInfoSize)) == NULL)
			AfxThrowMemoryException();

		MEMCPY_S(pBitmapInfo, &bmi, sizeof(BITMAPINFOHEADER));

		if (GetDIBits(dcSrc, hBitmap, 0, bmi.bmiHeader.biHeight, pBits, pBitmapInfo, DIB_RGB_COLORS) == NULL)
			AfxThrowMemoryException();
	}
	CATCH (CMemoryException, e)
	{
		TRACE(_T("Failed -- Memory exception thrown."));
		return FALSE;
	}
	END_CATCH

	return TRUE;
}

HBITMAP CXTPImageManagerIcon::ReadDIBBitmap(CArchive& ar, LPBYTE* lpBits)
{
	PBITMAPINFO pBitmapInfo = 0;
	PBYTE pBitsSrc = 0;

	DWORD dwCount = (DWORD) ar.ReadCount();
	DWORD dwBitsCount = 0;

	if (dwCount > 0)
	{
		pBitmapInfo = (PBITMAPINFO)malloc(dwCount);
		ar.Read(pBitmapInfo, dwCount);

		dwBitsCount = (DWORD) ar.ReadCount();
		pBitsSrc = (PBYTE)malloc(dwBitsCount);
		ar.Read(pBitsSrc, dwBitsCount);
	}
	else
	{
		return NULL;
	}

	if (!pBitmapInfo || dwBitsCount == 0)
	{
		FREE(pBitsSrc);
		FREE(pBitmapInfo);
		return NULL;
	}

	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	if (pBitmapInfo->bmiHeader.biSizeImage == 0)
	{
		pBitmapInfo->bmiHeader.biSizeImage = dwBitsCount;
	}

	BYTE* pBitsDest = NULL;
	HBITMAP hBmp = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pBitsDest, NULL, 0);

	if (!pBitsDest || !hBmp)
	{
		FREE(pBitsSrc);
		FREE(pBitmapInfo);
		return NULL;
	}

	MEMCPY_S(pBitsDest, pBitsSrc, min(dwBitsCount, pBitmapInfo->bmiHeader.biSizeImage));

	FREE(pBitsSrc);
	FREE(pBitmapInfo);

	if (lpBits)
	{
		*lpBits = pBitsDest;
	}

	return hBmp;
}

void CXTPImageManagerIcon::WriteDIBBitmap(CArchive& ar, HBITMAP hBitmap)
{
	PBYTE pBits = 0;
	PBITMAPINFO pBitmapInfo = 0;
	UINT nBitsSize;
	UINT nBitmapInfoSize;

	if (GetDIBBitmap(hBitmap, pBits, nBitsSize, pBitmapInfo, nBitmapInfoSize))
	{
		ar.WriteCount(nBitmapInfoSize);
		ar.Write(pBitmapInfo, nBitmapInfoSize);
		ar.WriteCount(nBitsSize);
		ar.Write(pBits, nBitsSize);
	}
	else
	{
		ar.WriteCount(0);
	}
	FREE(pBits);
	FREE(pBitmapInfo);
}

void CXTPImageManagerIcon::SerializeIcon(CXTPImageManagerIconHandle& hIcon, CArchive& ar, long nSchema)
{
	if (ar.IsStoring())
	{
		CXTPImageManagerIconHandle hHandle;
		hHandle.CopyHandle(hIcon);
		hHandle.PreMultiply();

		ICONINFO info;

		if (!hHandle.IsEmpty())
		{
			if (hHandle.IsAlpha())
			{
				WriteDIBBitmap(ar, hHandle.GetBitmap());
				ar.WriteCount(0);
			}
			else if (GetIconInfo(hHandle.GetIcon(), &info))
			{
				WriteDIBBitmap(ar, info.hbmColor);
				WriteDIBBitmap(ar, info.hbmMask);

				::DeleteObject(info.hbmColor);
				::DeleteObject(info.hbmMask);

			}
			else
			{
				ar.WriteCount(0);
				ar.WriteCount(0);
			}
		}
		else
		{
			ar.WriteCount(0);
			ar.WriteCount(0);
		}
	}
	else
	{
		CXTPImageManagerIconHandle hHandle;

		LPBYTE lpBits = NULL;
		HBITMAP hbmColor = ReadDIBBitmap(ar, &lpBits);
		HBITMAP hbmMask = ReadDIBBitmap(ar, NULL);

		if (hbmColor)
		{
			if (hbmMask == 0)
			{
				hHandle = hbmColor;

				if (nSchema > _XTP_SCHEMA_112)
				{
					hHandle.m_pBits = lpBits;
				}
				hbmColor = 0;
			}
			else
			{
				BITMAP bmp;
				::GetObject(hbmColor, sizeof(BITMAP), &bmp);

				CImageList il;
				il.Create(bmp.bmWidth, bmp.bmHeight, ILC_COLOR24 | ILC_MASK, 0, 1);
				il.Add(CBitmap::FromHandle(hbmColor), hbmMask == 0 ? (CBitmap*)NULL : CBitmap::FromHandle(hbmMask));
				hHandle = il.ExtractIcon(0);
			}

			if (hbmColor) ::DeleteObject(hbmColor);
			if (hbmMask) ::DeleteObject(hbmMask);
		}

		hIcon.CopyHandle(hHandle);
	}

}

void CXTPImageManagerIcon::Serialize(CArchive& ar)
{
	long nSchema = _XTP_SCHEMA_CURRENT;

	if (ar.IsStoring())
	{
		ar << m_nHeight;
		ar << nSchema;

	}
	else
	{
		ar >> m_nHeight;
		ar >> nSchema;
	}
	SerializeIcon(m_hIcon, ar, nSchema);
	SerializeIcon(m_hDisabled, ar, nSchema);
	SerializeIcon(m_hHot, ar, nSchema);

	if (nSchema > _XTP_SCHEMA_875)
	{
		SerializeIcon(m_hChecked, ar, nSchema);
	}
	if (nSchema > _XTP_SCHEMA_98)
	{
		SerializeIcon(m_hPressed, ar, nSchema);
	}
}

void CXTPImageManagerIcon::Copy(CXTPImageManagerIcon* pIcon)
{
	ASSERT(m_nID == pIcon->GetID());
	m_nWidth = pIcon->m_nWidth;
	m_nHeight = pIcon->m_nHeight;

	m_hIcon.CopyHandle(pIcon->m_hIcon);
	m_hDisabled.CopyHandle(pIcon->m_hDisabled);
	m_hHot.CopyHandle(pIcon->m_hHot);
	m_hChecked.CopyHandle(pIcon->m_hChecked);
	m_hPressed.CopyHandle(pIcon->m_hPressed);

	m_hFaded.Clear();
	m_hShadow.Clear();
	m_hDisabledAuto.Clear();
}

void CXTPImageManagerIcon::DrawAlphaBitmap(CDC* pDC, HBITMAP hBitmap, CPoint ptDest, CSize szDest, CPoint ptSrc, CSize szSrc)
{
	if (szSrc == CSize(0))
		szSrc = szDest;

	CXTPCompatibleDC dc(NULL, CBitmap::FromHandle(hBitmap));

	XTPImageManager()->AlphaBlend(pDC->GetSafeHdc(), CRect(ptDest, szDest),
		dc, CRect(ptSrc, szSrc));

}
CXTPImageManager* CXTPImageManagerIcon::GetImageManager() const
{
	if (m_pIconSet)
	{
		ASSERT(m_pIconSet->m_pImageManager);
		return m_pIconSet->m_pImageManager;
	}

	return XTPImageManager();
}

void CXTPImageManagerIcon::DrawMono(CDC* pDC, CPoint pt, CXTPImageManagerIconHandle& hIcon, CSize szIcon, COLORREF clrBrush)
{
	if (hIcon.IsAlpha())
		return;

	if (szIcon.cx == 0)
		szIcon.cx = m_nWidth;

	if (szIcon.cy == 0)
		szIcon.cy = m_nHeight * szIcon.cx / m_nWidth;

	CBitmap bmp;
	bmp.CreateCompatibleBitmap(pDC, szIcon.cx, szIcon.cy);
	{
		CXTPCompatibleDC dc(pDC, &bmp);
		dc.FillSolidRect(0, 0, szIcon.cx, szIcon.cy, 0xFFFFFF);

		Draw(&dc, CPoint(0, 0), hIcon, szIcon);
	}
	pDC->DrawState(pt, szIcon, bmp, (UINT)DSS_MONO, CBrush(clrBrush));
}

void CXTPImageManagerIcon::Draw(CDC* pDC, CPoint pt, CSize szIcon)
{
	Draw(pDC, pt, GetIcon(), szIcon);
}

void CXTPImageManagerIcon::Draw(CDC* pDC, CPoint pt)
{
	Draw(pDC, pt, GetIcon());
}

void CXTPImageManagerIcon::DrawIconComposited(CDC* pDC, CPoint pt, CSize szIcon, HICON hIcon)
{
	CRect rcDest;
	if (szIcon.cx < 0)
	{
		rcDest.SetRect(pt.x + szIcon.cx, pt.y, pt.x, pt.y + szIcon.cy);
	}
	else
	{
		rcDest.SetRect(pt.x, pt.y, pt.x + szIcon.cx, pt.y + szIcon.cy);
	}

	CSize sz(rcDest.Width(), rcDest.Height());
	CBitmap bmp;
	LPDWORD lpBits;
	bmp.Attach(CXTPImageManager::Create32BPPDIBSection(pDC->GetSafeHdc(), sz.cx, sz.cy, (LPBYTE*)&lpBits));

	CXTPCompatibleDC dc(pDC, &bmp);

	CRect rcDestOrig(0, 0, sz.cx, sz.cy);

	dc.FillSolidRect(rcDestOrig, 0xFF00FF);
	DrawIconEx(dc, szIcon.cx > 0 ? 0 : -szIcon.cx, 0, hIcon, szIcon.cx, szIcon.cy, 0, 0, DI_NORMAL);

	for (int i = 0; i < sz.cx * sz.cy; i++)
	{
		if (lpBits[0] == 0xFF00FF)
		{
			lpBits[0] = 0;
		}
		else
		{
			lpBits[0] |= 0xFF000000;
		}
		lpBits++;
	}

	XTPImageManager()->AlphaBlend(*pDC, rcDest, dc, rcDestOrig);
}

void CXTPImageManagerIcon::Draw(CDC* pDC, CPoint pt, CXTPImageManagerIconHandle& hIcon, CSize szIcon /*= 0*/, COLORREF clrBK, COLORREF clrFG, UINT uiFlags)
{
	if (szIcon.cx == 0)
		szIcon.cx = m_nWidth;

	if (szIcon.cy == 0)
		szIcon.cy = m_nHeight * szIcon.cx / m_nWidth;

	if (m_pImageList)
	{
		m_pImageList->Draw(pDC, pt, this, szIcon,clrBK, clrFG, uiFlags);
		return;
	}

	hIcon.Draw(pDC, pt, szIcon, m_bDrawComposited);
}



//////////////////////////////////////////////////////////////////////////
// CXTPImageManagerIconSet

CXTPImageManagerIconSet::CXTPImageManagerIconSet(UINT nID, CXTPImageManager* pImageManager)
	: m_nID(nID)
{
	ASSERT(pImageManager);
	m_pImageManager = pImageManager;


}

CXTPImageManagerIconSet::~CXTPImageManagerIconSet()
{
	RemoveAll();
}

void CXTPImageManagerIconSet::RemoveAll()
{
	UINT nWidth;
	CXTPImageManagerIcon* pIcon;

	POSITION pos = m_mapIcons.GetStartPosition();
	while (pos)
	{
		m_mapIcons.GetNextAssoc(pos, nWidth, pIcon);
		pIcon->Clear(TRUE);
		pIcon->InternalRelease();
	}
	m_mapIcons.RemoveAll();
}

CXTPImageManagerIcon* CXTPImageManagerIconSet::CreateIcon(UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = 0;
	if (m_mapIcons.Lookup(nWidth, pIcon))
	{
		ASSERT(pIcon->m_nID == m_nID);
		ASSERT(pIcon->m_nWidth == nWidth);
	}
	else
	{
		pIcon = new CXTPImageManagerIcon(m_nID, nWidth, 15, this);
		m_mapIcons.SetAt(nWidth, pIcon);
	}

	ASSERT(pIcon);

	return pIcon;
}

void CXTPImageManagerIconSet::SetIcon(const CXTPImageManagerIconHandle& hIcon, UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = CreateIcon(nWidth);
	pIcon->SetIcon(hIcon);
}

void CXTPImageManagerIconSet::SetDisabledIcon(const CXTPImageManagerIconHandle& hIcon, UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = CreateIcon(nWidth);
	pIcon->SetDisabledIcon(hIcon);
}

void CXTPImageManagerIconSet::SetHotIcon(const CXTPImageManagerIconHandle& hIcon, UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = CreateIcon(nWidth);
	pIcon->SetHotIcon(hIcon);
}

void CXTPImageManagerIconSet::SetCheckedIcon(const CXTPImageManagerIconHandle& hIcon, UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = CreateIcon(nWidth);
	pIcon->SetCheckedIcon(hIcon);
}

void CXTPImageManagerIconSet::SetPressedIcon(const CXTPImageManagerIconHandle& hIcon, UINT nWidth)
{
	CXTPImageManagerIcon* pIcon = CreateIcon(nWidth);
	pIcon->SetPressedIcon(hIcon);
}

CXTPImageManagerIcon* CXTPImageManagerIconSet::GetIcon(UINT nWidth, BOOL bScaled)
{
	ASSERT(m_mapIcons.GetCount() > 0);

	CXTPImageManagerIcon* pIcon = NULL;
	BOOL bSpecial = (nWidth == ICON_BIG) || (nWidth == ICON_SMALL);

	if (!bSpecial)
	{
		if (m_mapIcons.Lookup(nWidth, pIcon))
		{
			return pIcon;
		}
		if (!bScaled)
			return NULL;
	}

	UINT nDelta = 0;

	POSITION pos = m_mapIcons.GetStartPosition();
	while (pos)
	{
		UINT nWidthScale;
		CXTPImageManagerIcon* pIconScale;

		m_mapIcons.GetNextAssoc(pos, nWidthScale, pIconScale);

		if (bSpecial)
		{
			if (((nDelta == 0) || ((nWidth == ICON_SMALL && nWidthScale < nDelta)
				|| (nWidth == ICON_BIG && nWidthScale > nDelta))))
			{
				pIcon = pIconScale;
				nDelta = nWidthScale;
			}
		}
		else if (nDelta == 0 || (UINT)abs(int(nWidthScale - nWidth)) < nDelta)
		{
			pIcon = pIconScale;
			nDelta = (UINT)abs(int(nWidthScale - nWidth));
		}
	}

	ASSERT(pIcon != 0);
	if (!pIcon)
		return NULL;

	return pIcon;
}


void CXTPImageManagerIconSet::RefreshAll()
{
	POSITION pos = m_mapIcons.GetStartPosition();
	UINT nWidth;
	CXTPImageManagerIcon* pIcon;

	while (pos)
	{
		m_mapIcons.GetNextAssoc(pos, nWidth, pIcon);

		pIcon->Refresh();
	}
}



//////////////////////////////////////////////////////////////////////////
// CXTPImageManager

CXTPImageManager::CXTPImageManager()
{
	m_clrMask = (COLORREF)-1;

	m_nCustomID = 0x10AAA;

	m_mapImages.InitHashTable(XTP_IMAGEMAN_HASH_TABLE_SIZE, FALSE);

	m_bDrawReverted = 2;

	m_bUseResources = TRUE;


}

CXTPImageManager* AFX_CDECL XTPImageManager()
{
	static CXTPImageManager s_managerInstance;
	return &s_managerInstance;
}

CXTPImageManager::~CXTPImageManager()
{
	RemoveAll();
}

BOOL CXTPImageManager::LoadToolbar(UINT nIDResourceToolBar, UINT*& pItems, int& nCount, CSize& szIcon) const
{
	LPCTSTR lpszResourceName = MAKEINTRESOURCE(nIDResourceToolBar);

	struct CToolBarData
	{
		WORD wVersion;
		WORD wWidth;
		WORD wHeight;
		WORD wItemCount;

		WORD* items()
		{
			return (WORD*)(this + 1);
		}
	};

	ASSERT(lpszResourceName != NULL);
	if (!lpszResourceName)
		return FALSE;

	// determine location of the bitmap in resource fork
	HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
	HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
	if (hRsrc == NULL)
		return FALSE;

	HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
	if (hGlobal == NULL)
		return FALSE;

	CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
	if (pData == NULL)
		return FALSE;

	ASSERT(pData->wVersion == 1);

	pItems = new UINT[pData->wItemCount];

	nCount = 0;
	for (int i = 0; i < pData->wItemCount; i++)
		if (pData->items()[i]) pItems[nCount++] = pData->items()[i];

	szIcon = CSize(pData->wWidth, pData->wHeight);

	UnlockResource(hGlobal);
	FreeResource(hGlobal);
	return TRUE;
}

BOOL CXTPImageManager::SetIcons(UINT nIDResourceToolBar, CBitmap& bmpIcons, XTPImageState imageState)
{
	UINT* pItems = NULL;
	CSize szIcon(0);
	int nCount = 0;
	BOOL bResult = LoadToolbar(nIDResourceToolBar, pItems, nCount, szIcon);

	if (bResult && !SetIcons(bmpIcons, pItems, nCount, szIcon, imageState))
		bResult = FALSE;

	if (pItems)
	{
		delete[] pItems;
	}

	return bResult;
}
BOOL CXTPImageManager::SetIcons(UINT nIDResourceToolBar, UINT nIDResourceBitmap, XTPImageState imageState)
{
	UINT* pItems = NULL;
	CSize szIcon(0);
	int nCount = 0;
	BOOL bResult = LoadToolbar(nIDResourceToolBar, pItems, nCount, szIcon);

	if (bResult && !SetIcons(nIDResourceBitmap, pItems, nCount, CSize(0, 0), imageState))
		bResult = FALSE;

	if (pItems)
	{
		delete[] pItems;
	}

	return bResult;

}


BOOL CXTPImageManager::SetIcons(UINT nIDResourceToolBar, XTPImageState imageState)
{
	return SetIcons(nIDResourceToolBar, nIDResourceToolBar, imageState);
}

BOOL CXTPImageManager::SetIcons(UINT nIDResourceToolBar, CImageList& imlIcons, XTPImageState imageState)
{
	UINT* pItems = NULL;
	CSize szIcon(0);
	int nCount = 0;
	BOOL bResult = LoadToolbar(nIDResourceToolBar, pItems, nCount, szIcon);

	if (bResult && !SetIcons(imlIcons, pItems, nCount, szIcon, imageState))
		bResult = FALSE;

	if (pItems)
	{
		delete[] pItems;
	}

	return bResult;

}

BOOL CXTPImageManager::SetIcon(const CXTPImageManagerIconHandle& hIcon, UINT nIDCommand, CSize szIcon, XTPImageState imageState)
{
	if (hIcon.IsEmpty())
		return FALSE;

	if (szIcon == CSize(0))
	{
		szIcon = hIcon.GetExtent();
	}
	if (szIcon == CSize(0))
		return FALSE;

	CXTPImageManagerIconSet* pIconSet;
	if (m_mapImages.Lookup(nIDCommand, pIconSet))
	{
		if (imageState == xtpImageNormal) pIconSet->SetIcon(hIcon, szIcon.cx);
		if (imageState == xtpImageDisabled) pIconSet->SetDisabledIcon(hIcon, szIcon.cx);
		if (imageState == xtpImageHot) pIconSet->SetHotIcon(hIcon, szIcon.cx);
		if (imageState == xtpImageChecked) pIconSet->SetCheckedIcon(hIcon, szIcon.cx);
		if (imageState == xtpImagePressed) pIconSet->SetPressedIcon(hIcon, szIcon.cx);
	}
	else if (imageState == xtpImageNormal)
	{
		pIconSet = new CXTPImageManagerIconSet(nIDCommand, this);
		pIconSet->SetIcon(hIcon, szIcon.cx);
		m_mapImages.SetAt(nIDCommand, pIconSet);
	}
	else return FALSE;

	return TRUE;
}

BOOL CXTPImageManager::SetIcon(UINT nIDResourceIcon, UINT nIDCommand, CSize szIcon, XTPImageState imageState)
{
	return SetIcon(MAKEINTRESOURCE(nIDResourceIcon), nIDCommand, szIcon, imageState);
}

BOOL CXTPImageManager::SetIconFromResource(HINSTANCE hInst, LPCTSTR lpszResourceName, UINT nIDCommand, CSize szIcon, XTPImageState imageState)
{
	// determine location of the bitmap in resource fork
	HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_GROUP_ICON);
	if (hRsrc != NULL)
	{
		// Load and Lock to get a pointer to a GRPICONDIR
		HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
		if (!hGlobal)
			return FALSE;

		CXTPImageManagerIcon::GRPICONDIR* lpGrpIconDir = (CXTPImageManagerIcon::GRPICONDIR*)
			LockResource(hGlobal);
		if (!lpGrpIconDir)
			return FALSE;

		for (WORD i = 0; i < lpGrpIconDir->idCount; i++)
		{
			CXTPImageManagerIconHandle hIcon;
			CSize szResourceIcon(lpGrpIconDir->idEntries[i].bWidth, lpGrpIconDir->idEntries[i].bHeight);

			if ((szIcon == szResourceIcon) || (szIcon == CSize(0, 0)))
			{
				if (!hIcon.CreateIconFromResource(hInst, MAKEINTRESOURCE(lpGrpIconDir->idEntries[i].nID),
					szResourceIcon, FALSE))
				{
					return FALSE;
				}

				if (!SetIcon(hIcon, nIDCommand, szResourceIcon, imageState))
				{
					return FALSE;
				}
			}
		}
	}
	else
	{
		CXTPImageManagerIconHandle hIcon;

		if (!hIcon.CreateIconFromResource(hInst, lpszResourceName, szIcon, FALSE))
		{
			return FALSE;
		}

		return SetIcon(hIcon, nIDCommand, szIcon, imageState);
	}
	return TRUE;
}


BOOL CXTPImageManager::SetIcon(LPCTSTR lpszResourceName, UINT nIDCommand, CSize szIcon, XTPImageState imageState)
{
	// determine location of the bitmap in resource fork
	HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_GROUP_ICON);
	HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_GROUP_ICON);

	if (hRsrc != NULL)
	{
		SetIconFromResource(hInst, lpszResourceName, nIDCommand, szIcon, imageState);
	}
	else
	{
		CXTPImageManagerIconHandle hIcon;

		if (!hIcon.CreateIconFromResource(lpszResourceName, szIcon, FALSE))
		{
			return FALSE;
		}

		return SetIcon(hIcon, nIDCommand, szIcon, imageState);
	}
	return TRUE;
}


BOOL CXTPImageManager::SetIcons(CImageList& imlIcons, UINT* pCommands, int nCount, CSize szIcon, XTPImageState imageState)
{
	if (!imlIcons.GetSafeHandle())
		return FALSE;

	if ((nCount == 0) && (pCommands == 0))
	{
		nCount = imlIcons.GetImageCount();
	}

	if (szIcon == CSize(0) && nCount > 0)
	{
		IMAGEINFO imageInfo;
		imlIcons.GetImageInfo(0, &imageInfo);
		szIcon = CRect(imageInfo.rcImage).Size();
	}

	BOOL bIncludeAll = imlIcons.GetImageCount() == nCount;
	int j = 0;

	for (int i = 0; i < nCount; i++)
	{
		if ((pCommands == NULL) || bIncludeAll || (pCommands[i] != 0 && pCommands[i] != IMAGE_PLACEHOLDER))
		{
			HICON hIcon = imlIcons.ExtractIcon(j);
			if (hIcon)
			{
				SetIcon(hIcon, pCommands ? pCommands[i]: i, szIcon, imageState);
				DestroyIcon(hIcon);
			}
			else
			{
				return FALSE;
			}
			j++;
		}
	}
	return TRUE;
}


BOOL CXTPImageManager::SplitBitmap(HBITMAP hbmSource, int nCount, HBITMAP* pDest) const
{
	ASSERT(pDest != NULL);
	ASSERT(sizeof(int) == 4);

	if (!pDest)
		return FALSE;

	BITMAPINFO  bmi;
	memset(&bmi, 0, sizeof(bmi));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	PINT pBits = 0;
	PBITMAPINFO pBitmapInfo = 0;

	BOOL bResult = TRUE;
	int i;

	TRY
	{
		if (GetDIBits(dcSrc, hbmSource, 0, 0, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS) == 0)
			AfxThrowMemoryException();

		UINT nSize = bmi.bmiHeader.biHeight * bmi.bmiHeader.biWidth * 4;
		pBits = (PINT)malloc(nSize);
		if (pBits == NULL)
			AfxThrowMemoryException();

		if ((pBitmapInfo = (PBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + 3 * sizeof(COLORREF))) == NULL)
			AfxThrowMemoryException();

		MEMCPY_S(pBitmapInfo, &bmi, sizeof(BITMAPINFOHEADER));

		if (GetDIBits(dcSrc, hbmSource, 0, bmi.bmiHeader.biHeight, pBits, pBitmapInfo, DIB_RGB_COLORS) == NULL)
			AfxThrowMemoryException();

		ASSERT(pBitmapInfo->bmiHeader.biWidth % nCount == 0);

		pBitmapInfo->bmiHeader.biWidth /= nCount;
		pBitmapInfo->bmiHeader.biSizeImage /= nCount;

		PINT* pDestBits = new PINT[nCount];
		for (i = 0; i < nCount; i++)
		{
			pDest[i] = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pDestBits[i], NULL, 0);
			if (!pDest[i])
			{
				for (int j = 0; j < i; j++)
					DeleteObject(pDest[j]);

				delete[] pDestBits;

				AfxThrowMemoryException();
			}
		}

		PINT pBitsIter = pBits;

		for (int y = 0; y < pBitmapInfo->bmiHeader.biHeight; y++)
		{
			for (i = 0; i < nCount; i++)
			{
				for (int x = 0; x < pBitmapInfo->bmiHeader.biWidth; x++)
				{
					*pDestBits[i]++ = *pBitsIter++;
				}
			}
		}
		delete[] pDestBits;

	}
	CATCH (CMemoryException, e)
	{
		TRACE(_T("Failed -- Memory exception thrown."));
		bResult = FALSE;
	}
	END_CATCH

	FREE(pBits);
	FREE(pBitmapInfo);

	return bResult;

}

COLORREF CXTPImageManager::GetBitmapMaskColor(CBitmap& bmpIcons, CPoint pt)
{
	CXTPCompatibleDC dc(NULL, &bmpIcons);
	return dc.GetPixel(pt);
}

COLORREF CXTPImageManager::GetBitmapMaskColor(UINT nIDBitmap, CPoint pt)
{
	CBitmap bmp;
	VERIFY(bmp.LoadBitmap(nIDBitmap));
	return GetBitmapMaskColor(bmp, pt);
}


HBITMAP CXTPImageManager::ResampleAlphaLayer(UINT nIDBitmap, COLORREF clrMask)
{
	HBITMAP hbmAlpha = CXTPImageManagerIcon::LoadAlphaBitmap(nIDBitmap);
	if (!hbmAlpha)
		return 0;

	CBitmap bmp;
	bmp.Attach(hbmAlpha);

	return CXTPImageManager::ResampleAlphaLayer(bmp, clrMask);
}

HBITMAP CXTPImageManager::ResampleAlphaLayer(HBITMAP bmpAlpha, COLORREF clrMask)
{
	CDC dcSrc;
	dcSrc.CreateCompatibleDC(NULL);

	PBYTE pBits = 0;
	PBITMAPINFO pBitmapInfo = 0;
	UINT nSize;

	if (!CXTPImageManagerIcon::GetBitmapBits(dcSrc, bmpAlpha, pBitmapInfo, (LPVOID&)pBits, nSize))
		return 0;

	PBYTE pTarget = NULL;
	PBYTE pSource = pBits;
	pBitmapInfo->bmiHeader.biBitCount = 24;
	pBitmapInfo->bmiHeader.biSizeImage = 0;
	pBitmapInfo->bmiHeader.biCompression = BI_RGB;

	HBITMAP hBitmapResult = CreateDIBSection(dcSrc, pBitmapInfo, DIB_RGB_COLORS, (void**)&pTarget, NULL, 0);

	if (pTarget && pSource && hBitmapResult)
	{
		BYTE byMaskRed = GetRValue(clrMask);
		BYTE byMaskGreen = GetGValue(clrMask);
		BYTE byMaskBlue = GetBValue(clrMask);

		for (int i = 0; i < pBitmapInfo->bmiHeader.biHeight; i ++)
		{
			for (int j = 0; j < pBitmapInfo->bmiHeader.biWidth; j ++)
			{
				int iAlpha = pSource[3];

				if (iAlpha < 120) // Transparent
				{
					pTarget[0] = byMaskRed;
					pTarget[1] = byMaskGreen;
					pTarget[2] = byMaskBlue;
				}
				else if (iAlpha == 255) // Opaque
				{
					pTarget[0] = pSource[0];
					pTarget[1] = pSource[1];
					pTarget[2] = pSource[2];
				}
				else
				{
					pTarget[0] = (BYTE)((pSource[0] * (255 - iAlpha) + pSource[0] * iAlpha) >> 8);
					pTarget[1] = (BYTE)((pSource[1] * (255 - iAlpha) + pSource[1] * iAlpha) >> 8);
					pTarget[2] = (BYTE)((pSource[2] * (255 - iAlpha) + pSource[2] * iAlpha) >> 8);
				}

				pTarget += 3;
				pSource += 4;
			}

			if (pBitmapInfo->bmiHeader.biWidth & 1)
				pTarget++;
		}
	}

	FREE(pBits);
	FREE(pBitmapInfo);

	return hBitmapResult;
}

BOOL CXTPImageManager::SetIcons(CBitmap& bmpIcons, UINT* pCommands, int nCount, CSize szIcon, XTPImageState imageState, BOOL bAlpha)
{
	if (szIcon == CSize(0) && nCount > 0)
	{
		BITMAP bmpInfo;
		bmpIcons.GetBitmap(&bmpInfo);
		szIcon = CSize(bmpInfo.bmWidth / nCount, bmpInfo.bmHeight);
	}

	if (nCount == 0 && szIcon.cx > 0)
	{
		BITMAP bmpInfo;
		bmpIcons.GetBitmap(&bmpInfo);
		nCount = bmpInfo.bmWidth / szIcon.cx;
	}

	if (szIcon.cx == 0)
		return FALSE;

	if (bAlpha && !IsAlphaIconsSupported() && m_bAutoResample)
	{
		HBITMAP hBitmap = ResampleAlphaLayer(bmpIcons, m_clrMask == COLORREF(-1) ? RGB(0, 0xFF, 0) : m_clrMask);
		if (!hBitmap)
			return FALSE;

		CBitmap bmpResample;
		bmpResample.Attach(hBitmap);
		return SetIcons(bmpResample, pCommands, nCount, szIcon, imageState, FALSE);
	}

	if (bAlpha)
	{
		BITMAP bmpInfo;
		bmpIcons.GetBitmap(&bmpInfo);
		if (bmpInfo.bmWidth % szIcon.cx != 0)
			return FALSE;

		int nIconCount = bmpInfo.bmWidth / szIcon.cx;

		HBITMAP* pDestBitmap = new HBITMAP[nIconCount];

		if (!SplitBitmap(bmpIcons, nIconCount, pDestBitmap))
		{
			delete[] pDestBitmap;
			return FALSE;
		}
		BOOL bIgnoreNulls = (nIconCount == nCount);

		int j = 0;

		for (int i = 0; i < nCount; i++)
		{
			if ((!pCommands || bIgnoreNulls || (pCommands[i] != 0 && pCommands[i] != IMAGE_PLACEHOLDER)) && j < nIconCount)
			{

				SetIcon(pDestBitmap[j], pCommands ? pCommands[i]: i, szIcon, imageState);
				j++;
			}
		}

		for (j = 0; j < nIconCount; j++)
		{
			DeleteObject(pDestBitmap[j]);
		}

		delete[] pDestBitmap;


		return TRUE;

	}
	else
	{
		CImageList imgList;


		if (!imgList.Create(szIcon.cx, szIcon.cy, ILC_COLOR24 | ILC_MASK, 0, 1))
			return FALSE;

		COLORREF clrMask = m_clrMask != (COLORREF)-1 ? m_clrMask : GetBitmapMaskColor(bmpIcons);
		imgList.Add(&bmpIcons, clrMask);

		return SetIcons(imgList, pCommands, nCount, szIcon, imageState);
	}

}


BOOL CXTPImageManager::SetIcons(UINT nIDResourceBitmap, UINT* pCommands, int nCount, CSize szIcon, XTPImageState imageState)
{
	return SetIcons(MAKEINTRESOURCE(nIDResourceBitmap), pCommands, nCount, szIcon, imageState);
}

BOOL CXTPImageManager::SetIcons(LPCTSTR lpszResourceBitmap, UINT* pCommands, int nCount, CSize szIcon, XTPImageState imageState)
{
	BOOL bAlphaBitmap = FALSE;
	CBitmap bmpIcons;

	HBITMAP hBmp = CXTPImageManagerIcon::LoadBitmapFromResource(lpszResourceBitmap, &bAlphaBitmap);

	if (!hBmp)
		return FALSE;

	bmpIcons.Attach(hBmp);

	return SetIcons(bmpIcons, pCommands, nCount, szIcon, imageState, bAlphaBitmap);
}


BOOL CXTPImageManager::SetImageList(HIMAGELIST hImageList, int nBaseCommand, BOOL bDestoryImageList)
{
	if (!hImageList)
		return FALSE;

	CXTPImageManagerImageList* pImageList = new CXTPImageManagerImageList;
	pImageList->m_bDestroyImageList = bDestoryImageList;
	pImageList->m_hImageList = hImageList;
	pImageList->m_nBaseCommand = nBaseCommand;
	pImageList->m_pImageManager = this;

	m_arrImageList.Add(pImageList);
	return TRUE;
}

BOOL CXTPImageManager::SetImageList(UINT nBitmap, int cx, int nBaseCommand, COLORREF clrMask)
{
	BOOL bAlpha = FALSE;
	HBITMAP hBitmap = CXTPImageManagerIcon::LoadBitmapFromResource(MAKEINTRESOURCE(nBitmap), &bAlpha);
	if (!hBitmap)
		return FALSE;

	BITMAP bmpInfo;
	if (!::GetObject(hBitmap, sizeof(BITMAP), &bmpInfo))
		return FALSE;

	if (cx == 0) cx = bmpInfo.bmWidth;

	if (((bmpInfo.bmWidth % cx) != 0))
		return FALSE;

	HIMAGELIST hImageList = ImageList_Create(cx, bmpInfo.bmHeight, (bAlpha ? ILC_COLOR32 : ILC_COLOR24) |
		(clrMask == COLORREF_NULL ? 0 : ILC_MASK), 0, 1);

	if (!hImageList)
		return FALSE;

	if (bAlpha || (clrMask == COLORREF_NULL))
	{
		ImageList_Add(hImageList, hBitmap, NULL);
	}
	else
	{
		ImageList_AddMasked(hImageList, hBitmap, clrMask);
	}

	DeleteObject(hBitmap);

	return SetImageList(hImageList, nBaseCommand, TRUE);
}




BOOL CXTPImageManager::IsPngBitmapResource(UINT nIDResourceBitmap)
{
	return CXTPImageManagerIcon::IsPngBitmapResource(AfxFindResourceHandle(MAKEINTRESOURCE(nIDResourceBitmap), _T("PNG")),
		MAKEINTRESOURCE(nIDResourceBitmap));
}



BOOL CXTPImageManager::IsAlphaBitmapResource(UINT nIDResourceBitmap)
{
	return CXTPImageManagerIcon::IsAlphaBitmapResource(AfxFindResourceHandle(MAKEINTRESOURCE(nIDResourceBitmap), RT_BITMAP),
		MAKEINTRESOURCE(nIDResourceBitmap));
}

UINT CXTPImageManager::AddCustomIcon(const CXTPImageManagerIconHandle& hIcon)
{
	CSize szIcon = hIcon.GetExtent();
	m_nCustomID++;

	CXTPImageManagerIconSet* pIconSet = new CXTPImageManagerIconSet(m_nCustomID, this);
	pIconSet->SetIcon(hIcon, szIcon.cx);
	m_mapImages.SetAt(m_nCustomID, pIconSet);

	return m_nCustomID;
}

void CXTPImageManager::CopyImage(UINT nCommand)
{
	CMemFile memFile;
	CArchive ar (&memFile, CArchive::store);

	Serialize(nCommand, ar);
	ar.Flush();

	DWORD dwCount = (DWORD)memFile.GetPosition();
	BYTE* pControls = memFile.Detach();

	HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwCount);
	if (hGlobal != NULL)
	{
		LPVOID lpData = GlobalLock(hGlobal);

		MEMCPY_S(lpData, pControls, dwCount);

		GlobalUnlock(hGlobal);
		SetClipboardData(m_nImageClipFormat, hGlobal);
	}

	ar.Close();
	memFile.Close();
	free(pControls);
}



UINT CXTPImageManager::PasteCustomImage(COleDataObject& data)
{
#ifdef __AFXOLE_H__
	HGLOBAL hGlobal = data.GetGlobalData (m_nImageClipFormat);

	if (hGlobal == NULL) return 0;

	try
	{
		CSharedFile globFile;
		globFile.SetHandle(hGlobal, FALSE);
		CArchive ar (&globFile, CArchive::load);

		m_nCustomID++;
		Serialize(m_nCustomID, ar);

		ar.Close();

	}
	catch (COleException* pEx)
	{
		pEx->Delete ();
		return 0;
	}
	catch (CArchiveException* pEx)
	{
		pEx->Delete ();
		return 0;
	}
	return m_nCustomID;
#else
	return 0;
#endif
}

BOOL CXTPImageManager::IsPrimaryImageExists(UINT nCommand, int nWidth) const
{
	CXTPImageManagerIconSet* pIconSet = GetIconSet(nCommand);

	if (pIconSet)
	{
		CXTPImageManagerIcon* pIcon = pIconSet->GetIcon(nWidth, FALSE);
		if (pIcon)
			return TRUE;
	}

	CXTPImageManagerImageList* pImageList = GetImageList(nCommand);
	if (pImageList)
	{
		return nWidth == 0 || pImageList->GetIconSize().cx == nWidth;
	}

	return FALSE;
}

CXTPImageManagerIcon* CXTPImageManager::GetImage(UINT nCommand, int nWidth) const
{
	CXTPImageManagerIconSet* pIconSet = GetIconSet(nCommand);

	if (pIconSet)
	{
		return pIconSet->GetIcon(nWidth);
	}

	CXTPImageManagerImageList* pImageList = GetImageList(nCommand);
	if (pImageList)
	{
		return pImageList->GetIcon(nCommand);
	}

	return NULL;
}

BOOL CXTPImageManager::Lookup(UINT nCommand) const
{
	return (GetIconSet(nCommand) != NULL) || (GetImageList(nCommand) != NULL);
}

CXTPImageManagerIconSet* CXTPImageManager::GetIconSet(UINT nCommand) const
{
	CXTPImageManagerIconSet* pIconSet;
	if (m_mapImages.Lookup(nCommand, pIconSet))
	{
		return pIconSet;

	}
	return NULL;
}

CXTPImageManagerImageList* CXTPImageManager::GetImageList(UINT nCommand) const
{
	for (int i = 0; i < (int)m_arrImageList.GetSize(); i++)
	{
		CXTPImageManagerImageList* pImageList = m_arrImageList[i];

		if (pImageList->Lookup(nCommand))
			return pImageList;
	}
	return NULL;
}

void CXTPImageManager::RemoveIcon(UINT nIDCommand)
{
	CXTPImageManagerIconSet* pIconSet;
	if (m_mapImages.Lookup(nIDCommand, pIconSet))
	{
		m_mapImages.RemoveKey(nIDCommand);
		pIconSet->RemoveAll();
		pIconSet->InternalRelease();
	}
}

void CXTPImageManager::RemoveAll()
{
	POSITION pos = m_mapImages.GetStartPosition();
	UINT nID;
	CXTPImageManagerIconSet* pIconSet;
	while (pos)
	{
		m_mapImages.GetNextAssoc(pos, nID, pIconSet);
		pIconSet->RemoveAll();
		pIconSet->InternalRelease();
	}
	m_mapImages.RemoveAll();

	pos = m_mapResources.GetStartPosition();
	DWORD dwSize;
	CXTPImageManagerResource* pResource;
	while (pos)
	{
		m_mapResources.GetNextAssoc(pos, dwSize, pResource);
		delete pResource;
	}
	m_mapResources.RemoveAll();


	for (int i = 0; i < (int)m_arrImageList.GetSize(); i++)
	{
		delete m_arrImageList[i];
	}
	m_arrImageList.RemoveAll();

}

void CXTPImageManager::RefreshAll()
{
	POSITION pos = m_mapImages.GetStartPosition();
	UINT nID;
	CXTPImageManagerIconSet* pIconSet;

	while (pos)
	{
		m_mapImages.GetNextAssoc(pos, nID, pIconSet);
		pIconSet->RefreshAll();
	}

	for (int i = 0; i < (int)m_arrImageList.GetSize(); i++)
	{
		m_arrImageList[i]->RemoveAll();
	}
}

COLORREF CXTPImageManager::SetMaskColor(COLORREF clrMask)
{
	COLORREF clrReturn = m_clrMask;
	m_clrMask = clrMask;
	return clrReturn;
}
COLORREF CXTPImageManager::GetMaskColor() const
{
	return m_clrMask;
}

BOOL CXTPImageManager::IsAlphaIconsSupported() const
{
	return TRUE;

}

BOOL CXTPImageManager::IsAlphaIconsImageListSupported()
{
	DWORD dwComCtlVersion = XTPSystemVersion()->GetComCtlVersion();
	return HIWORD(dwComCtlVersion) > 5;
}

void CXTPImageManager::DoPropExchange(UINT nCommand, CXTPPropExchange* pPX)
{
#ifndef _XTP_EXCLUDE_PROPEXCHANGE
	if (nCommand > m_nCustomID)
		m_nCustomID = nCommand;

	const LPCTSTR lpszCheck = _T("CXTPImageManagerIcons");
	CString strCheck = lpszCheck;

	if (pPX->IsStoring())
	{
		PX_String(pPX, _T("CheckSum"), strCheck, lpszCheck);

		ASSERT(nCommand > 0);
//this assertion kill VB6

		CXTPImageManagerIconSet* pIconSet = GetIconSet(nCommand);

		ASSERT(pIconSet);
//this assertion kill VB6

		if (!pIconSet)
		{
			CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Icon")));
			pEnumerator->GetPosition(0);
			return;
		}

		UINT nWidth;
		CXTPImageManagerIcon* pIcon;
		DWORD dwCount =(DWORD)pIconSet->m_mapIcons.GetCount();

		CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Icon")));
		POSITION posEnum = pEnumerator->GetPosition(dwCount);

		POSITION pos = pIconSet->m_mapIcons.GetStartPosition();
		while (pos)
		{
			pIconSet->m_mapIcons.GetNextAssoc(pos, nWidth, pIcon);

			CXTPPropExchangeSection secIcon(pEnumerator->GetNext(posEnum));

			PX_Long(&secIcon, _T("Width"), (long&)nWidth);
			PX_Serialize(&secIcon, _T("Data"), pIcon);
		}
	}
	else
	{
		PX_String(pPX, _T("CheckSum"), strCheck, lpszCheck);

		if (strCheck != lpszCheck)
			AfxThrowArchiveException(CArchiveException::badClass);


		CXTPImageManagerIconSet* pIconSet;
		if (m_mapImages.Lookup(nCommand, pIconSet))
		{
			pIconSet->RemoveAll();
		}
		else
		{
			pIconSet = new CXTPImageManagerIconSet(nCommand, this);
			m_mapImages.SetAt(nCommand, pIconSet);
		}

		CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Icon")));
		POSITION posEnum = pEnumerator->GetPosition();

		while (posEnum)
		{
			CXTPPropExchangeSection secIcon(pEnumerator->GetNext(posEnum));

			UINT nWidth = 16;
			PX_Long(&secIcon, _T("Width"), (long&)nWidth);

			CXTPImageManagerIcon* pIcon = new CXTPImageManagerIcon(nCommand, nWidth, 15, pIconSet);
			PX_Serialize(&secIcon, _T("Data"), pIcon);

			pIconSet->m_mapIcons.SetAt(nWidth, pIcon);
		}
	}
#endif
}

void CXTPImageManager::Serialize(UINT nCommand, CArchive& ar)
{
#ifndef _XTP_EXCLUDE_PROPEXCHANGE
	CXTPPropExchangeArchive px(ar);
	DoPropExchange(nCommand, &px);
#endif
}



void CXTPImageManager::DoPropExchange(CXTPPropExchange* pPX)
{
#ifndef _XTP_EXCLUDE_PROPEXCHANGE
	CMap<UINT, UINT, CXTPImageManagerIconSet*, CXTPImageManagerIconSet*>* pIcons = GetImages();

	CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("IconSet")));
	POSITION posEnum = pEnumerator->GetPosition((DWORD)pIcons->GetCount());

	if (pPX->IsStoring())
	{
		UINT nIDCommand;
		CXTPImageManagerIconSet* pIconSet;

		POSITION pos = pIcons->GetStartPosition();

		while (pos)
		{
			pIcons->GetNextAssoc(pos, nIDCommand, pIconSet);
			CXTPPropExchangeSection secIconSet(pEnumerator->GetNext(posEnum));

			PX_Long(&secIconSet, _T("Id"), (long&)nIDCommand);
			DoPropExchange(nIDCommand, &secIconSet);
		}
	}
	else
	{
		RemoveAll();

		while (posEnum)
		{
			CXTPPropExchangeSection secIconSet(pEnumerator->GetNext(posEnum));

			UINT nIDCommand = 0;
			PX_Long(&secIconSet, _T("Id"), (long&)nIDCommand);

			DoPropExchange(nIDCommand, &secIconSet);
		}
	}
#endif
}
void CXTPImageManager::Serialize(CArchive& ar)
{
#ifndef _XTP_EXCLUDE_PROPEXCHANGE
	CXTPPropExchangeArchive px(ar);
	DoPropExchange(&px);
#endif
}


void CXTPImageManager::AddIcons(CXTPImageManager* pImageManager)
{
	if (pImageManager == 0)
		return;

	POSITION pos = pImageManager->m_mapImages.GetStartPosition();
	UINT nID;
	CXTPImageManagerIconSet* pIconSet;

	while (pos)
	{
		pImageManager->m_mapImages.GetNextAssoc(pos, nID, pIconSet);

		AddIcons(pIconSet);
	}
}

void CXTPImageManager::AddIcons(CXTPImageManagerIconSet* pIconSetAdd)
{
	int nId = pIconSetAdd->GetID();

	CXTPImageManagerIconSet* pIconSet = NULL;

	if (!m_mapImages.Lookup(nId, pIconSet))
	{
		pIconSet = new CXTPImageManagerIconSet(nId, this);

		m_mapImages.SetAt(nId, pIconSet);
	}

	POSITION pos = pIconSetAdd->m_mapIcons.GetStartPosition();
	UINT nWidth;
	CXTPImageManagerIcon* pIconAdd;

	while (pos)
	{
		pIconSetAdd->m_mapIcons.GetNextAssoc(pos, nWidth, pIconAdd);

		CXTPImageManagerIcon* pIcon = NULL;
		if (!pIconSet->m_mapIcons.Lookup(nWidth, pIcon))
		{
			pIcon  = new CXTPImageManagerIcon(nId, nWidth, pIconAdd->GetHeight());
			pIconSet->m_mapIcons.SetAt(nWidth, pIcon);
		}

		pIcon->Copy(pIconAdd);
	}
}

BOOL CXTPImageManager::DoDisableBitmap(HBITMAP hBmp, COLORREF clrDisabledLight, COLORREF clrDisabledDark,
		int nBlackAndWhiteContrast)
{
	ASSERT(nBlackAndWhiteContrast == -1 ||
		(nBlackAndWhiteContrast >= 0 && nBlackAndWhiteContrast <= 255));

	BOOL bOfficeDisabledIcons = clrDisabledLight != (COLORREF)-1 && clrDisabledDark != (COLORREF)-1;

	BITMAP bmBitmap;

	// Get information about the surfaces you were passed.
	if (!GetObject(hBmp,  sizeof(BITMAP), &bmBitmap))  return FALSE;

	// Make sure you have data that meets your requirements.
	if (bmBitmap.bmBitsPixel != 32)
		return FALSE;

	if (bmBitmap.bmPlanes != 1)
		return FALSE;

	if (!bmBitmap.bmBits)
		return FALSE;

	DWORD dwWidthBytes = bmBitmap.bmWidthBytes;

	// Initialize the surface pointers.
	RGBQUAD *lprgbBitmap = (RGBQUAD*)bmBitmap.bmBits;

	//************************************************
	int x, y;
	for (y = 0; y < bmBitmap.bmHeight; y++)
	{
		for (x = 0; x < bmBitmap.bmWidth; x++)
		{
			if (bOfficeDisabledIcons)
			{
				double dGray = (lprgbBitmap[x].rgbBlue * 0.114 + lprgbBitmap[x].rgbGreen * 0.587 + lprgbBitmap[x].rgbRed * 0.299)/255.0;
				double dLight = 1.0 - dGray;

				lprgbBitmap[x].rgbBlue  = BYTE(dLight * GetBValue(clrDisabledDark) + dGray * GetBValue(clrDisabledLight));
				lprgbBitmap[x].rgbGreen = BYTE(dLight * GetGValue(clrDisabledDark) + dGray * GetGValue(clrDisabledLight));
				lprgbBitmap[x].rgbRed   = BYTE(dLight * GetRValue(clrDisabledDark) + dGray * GetRValue(clrDisabledLight));
			}
			else if (nBlackAndWhiteContrast != -1)
			{
				int nGray = (lprgbBitmap[x].rgbBlue * 114 + lprgbBitmap[x].rgbGreen * 587 + lprgbBitmap[x].rgbRed * 299) / 1000;
				nGray = nGray + (255 - nGray) * nBlackAndWhiteContrast / 255;
				nGray = min(nGray, 255);

				lprgbBitmap[x].rgbBlue = BYTE(nGray);
				lprgbBitmap[x].rgbGreen = BYTE(nGray);
				lprgbBitmap[x].rgbRed = BYTE(nGray);

				lprgbBitmap[x].rgbReserved = BYTE(lprgbBitmap[x].rgbReserved / CXTPImageManager::m_dDisabledAlphaFactor);
			}
			else
			{
				double dGray = (lprgbBitmap[x].rgbBlue * 0.114 + lprgbBitmap[x].rgbGreen * 0.587 + lprgbBitmap[x].rgbRed * 0.299)/255.0;

				lprgbBitmap[x].rgbBlue = (BYTE)(pow(dGray, CXTPImageManager::m_dDisabledBrightnessFactor) * 255.0);
				lprgbBitmap[x].rgbGreen = lprgbBitmap[x].rgbBlue;
				lprgbBitmap[x].rgbRed = lprgbBitmap[x].rgbBlue;

				lprgbBitmap[x].rgbReserved = BYTE(lprgbBitmap[x].rgbReserved / CXTPImageManager::m_dDisabledAlphaFactor);
			}
		}

		// Move to next scan line.
		lprgbBitmap = (RGBQUAD *)((LPBYTE)lprgbBitmap + dwWidthBytes);
	}

	return TRUE;
}

BOOL CXTPImageManager::DisableBitmap(HDC hDC, const CRect& rcRect, COLORREF clrDisabledLight, COLORREF clrDisabledDark)
{
	HDC      hdcDst  = NULL;
	HBITMAP  hbmDst  = NULL;
	HBITMAP  hbmpOld = NULL;

	BOOL    bReturn = FALSE;
	// Create surfaces for new image.
	hbmDst  = CXTPImageManager::Create32BPPDIBSection(hDC, rcRect.Width(), rcRect.Height());
	if (!hbmDst) goto HANDLEERROR;

	// Create HDCs to hold our surfaces.
	hdcDst  = CreateCompatibleDC(hDC);
	if (!hdcDst) goto HANDLEERROR;

	// Prepare the surfaces for drawing.
	hbmpOld = (HBITMAP)SelectObject(hdcDst,  hbmDst);

	// Capture a copy of the source area.
	if (!BitBlt(hdcDst, 0, 0, rcRect.Width(), rcRect.Height(),
		hDC, rcRect.left, rcRect.top, SRCCOPY) )
		goto HANDLEERROR;

	// Modify sourcepixels to create the destination image.
	bReturn = DoDisableBitmap(hbmDst, clrDisabledLight, clrDisabledDark);

	// Display the disabled image to the target HDC.
	if (bReturn)
	{
		BitBlt(hDC, rcRect.left, rcRect.top, rcRect.Width(), rcRect.Height(),
			hdcDst, 0,0, SRCCOPY);
	}

HANDLEERROR:

	// Clean up the rest of the objects you created.
	if (hbmpOld) SelectObject(hdcDst, hbmpOld);
	if (hdcDst) DeleteDC(hdcDst);
	if (hbmDst) DeleteObject(hbmDst);

	return bReturn;
}

BOOL CXTPImageManager::BlackWhiteBitmap(HDC hDC, const CRect& rcRect, int nBlackAndWhiteContrast)
{
	HDC      hdcDst  = NULL;
	HBITMAP  hbmDst  = NULL;
	HBITMAP  hbmpOld = NULL;

	BOOL    bReturn = FALSE;
	// Create surfaces for new image.
	hbmDst  = CXTPImageManager::Create32BPPDIBSection(hDC, rcRect.Width(), rcRect.Height());
	if (!hbmDst) goto HANDLEERROR;

	// Create HDCs to hold our surfaces.
	hdcDst  = CreateCompatibleDC(hDC);
	if (!hdcDst) goto HANDLEERROR;

	// Prepare the surfaces for drawing.
	hbmpOld = (HBITMAP)SelectObject(hdcDst,  hbmDst);

	// Capture a copy of the source area.
	if (!BitBlt(hdcDst, 0, 0, rcRect.Width(), rcRect.Height(),
		hDC, rcRect.left, rcRect.top, SRCCOPY) )
		goto HANDLEERROR;

	// Modify sourcepixels to create the destination image.
	bReturn = DoDisableBitmap(hbmDst, (COLORREF)-1, (COLORREF)-1, nBlackAndWhiteContrast);

	// Display the disabled image to the target HDC.
	if (bReturn)
	{
		BitBlt(hDC, rcRect.left, rcRect.top, rcRect.Width(), rcRect.Height(),
			hdcDst, 0,0, SRCCOPY);
	}

HANDLEERROR:

	// Clean up the rest of the objects you created.
	if (hbmpOld) SelectObject(hdcDst, hbmpOld);
	if (hdcDst) DeleteDC(hdcDst);
	if (hbmDst) DeleteObject(hbmDst);

	return bReturn;
}