www.pudn.com > ImageVidwer.rar > DIBSectionCE.cpp, change:2007-10-10,size:39611b


// CDIBSectionCE.cpp : implementation file 
// 
// General purpose DIBsection wrapper class for Win9x, NT 4.0 
// and WinCE. 
// 
// Author      : Chris Maunder (cmaunder@dundas.com) 
// Date        : 17 May 1999 
// 
// Copyright © Dundas Software Ltd. 1999, All Rights Reserved                       
// 
// This code may be used in compiled form in any way you desire. This 
// file may be redistributed unmodified by any means PROVIDING it is  
// not sold for profit without the authors written consent, and  
// providing that this notice and the authors name is included. If  
// the source code in this file is used in any commercial application  
// then a simple email would be nice. 
// 
// This file is provided "as is" with no expressed or implied warranty. 
// The author accepts no liability for any damage, in any form, caused 
// by this code. Use it at your own risk and as with all code expect bugs! 
// It's been tested but I'm not perfect. 
//  
// Please use and enjoy. Please let me know of any bugs/mods/improvements  
// that you have found/implemented and I will fix/incorporate them into this 
// file. 
 
 
#include "stdafx.h" 
#include "DIBSectionCE.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
// Use C++ exception handling instead of structured on non-CE platforms. 
#ifndef _WIN32_WCE   
#undef TRY 
#undef CATCH 
#undef END_CATCH 
#define TRY try 
#define CATCH(ex_class, ex_object) catch(ex_class* ex_object) 
#define END_CATCH 
#endif  // _WIN32_WCE 
 
// Standard colours 
RGBQUAD CDIBSectionCE::ms_StdColours[] = { 
    { 0x00, 0x00, 0x00, 0 },    // First 2 will be palette for monochrome bitmaps 
    { 0xFF, 0xFF, 0xFF, 0 }, 
 
    { 0x00, 0x00, 0xFF, 0 },    // First 16 will be palette for 16 colour bitmaps 
    { 0x00, 0xFF, 0x00, 0 }, 
    { 0x00, 0xFF, 0xFF, 0 }, 
    { 0xFF, 0x00, 0x00, 0 }, 
    { 0xFF, 0x00, 0xFF, 0 }, 
    { 0xFF, 0xFF, 0x00, 0 }, 
 
    { 0x00, 0x00, 0x80, 0 }, 
    { 0x00, 0x80, 0x00, 0 }, 
    { 0x00, 0x80, 0x80, 0 }, 
    { 0x80, 0x00, 0x00, 0 }, 
    { 0x80, 0x00, 0x80, 0 }, 
    { 0x80, 0x80, 0x00, 0 }, 
    { 0x80, 0x80, 0x80, 0 }, 
 
    { 0xC0, 0xC0, 0xC0, 0 }, 
}; 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CE DIBSection global functions 
 
UINT CEGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries, RGBQUAD *pColors); 
 
///////////////////////////////////////////////////////////////////////////// 
// CDIBSectionCE static functions 
 
//  
// --- In  : nBitsPerPixel - bits per pixel 
// --- Out :  
// --- Returns :The number of colours for this colour depth 
// --- Effect : Returns the number of color table entries given the number 
//              of bits per pixel of a bitmap 
/*static*/ int CDIBSectionCE::NumColorEntries(int nBitsPerPixel)  
{ 
    int nColors = 0; 
 
    switch (nBitsPerPixel)  
    { 
	    case 1:  nColors = 2;   break; 
#ifdef _WIN32_WCE 
        case 2:  nColors = 4;   break;   // winCE only        
#endif 
        case 4:  nColors = 16;  break; 
        case 8:  nColors = 256; break; 
        case 16: 
        case 24: 
        case 32: nColors = 0;   break;   // 16,24 or 32 bpp have no color table 
 
        default: 
           ASSERT(FALSE); 
    } 
 
    return nColors; 
} 
 
//  
// --- In  : nWidth - image width in pixels 
//           nBitsPerPixel - bits per pixel 
// --- Out : 
// --- Returns : Returns the number of storage bytes needed for each scanline  
//               in the bitmap 
// --- Effect :  
/*static*/ int CDIBSectionCE::BytesPerLine(int nWidth, int nBitsPerPixel) 
{ 
    int nBytesPerLine = nWidth * nBitsPerPixel; 
    nBytesPerLine = ( (nBytesPerLine + 31) & (~31) ) / 8; 
 
    return nBytesPerLine; 
} 
 
#ifndef DIBSECTION_NO_PALETTE 
 
//  
// --- In  : palette - reference to a palette object which will be filled 
//           nNumColours - number of colour entries to fill 
// --- Out : 
// --- Returns : TRUE on success, false otherwise 
// --- Effect : Creates a halftone color palette independant of screen color depth. 
//              palette will be filled with the colors, and nNumColours is the No. 
//              of colors to file. If nNumColoursis 0 or > 256, then 256 colors are used. 
/*static*/ BOOL CDIBSectionCE::CreateHalftonePalette(CPalette& palette, int nNumColours) 
{ 
    palette.DeleteObject(); 
 
    int nNumStandardColours = sizeof(ms_StdColours) / sizeof(ms_StdColours[0]); 
    int nIndex = 0; 
    int nNumEntries = nNumColours; 
    if (nNumEntries <= 0 || nNumEntries > 256) 
        nNumEntries = 256; 
 
    PALETTEINFO PalInfo;                    
    PalInfo.palNumEntries = (WORD) nNumEntries; 
 
    // The standard colours (16) 
    for (int i = 0; i < nNumStandardColours; i++) 
    { 
        if (nIndex >= nNumEntries)  
            break; 
 
        PalInfo.palPalEntry[nIndex].peRed   = ms_StdColours[i].rgbRed; 
        PalInfo.palPalEntry[nIndex].peGreen = ms_StdColours[i].rgbGreen; 
        PalInfo.palPalEntry[nIndex].peBlue  = ms_StdColours[i].rgbBlue; 
        PalInfo.palPalEntry[nIndex].peFlags = 0; 
        nIndex++; 
    } 
 
    // A colour cube (6 divisions = 216) 
    for (int blue = 0; blue <= 5; blue++) 
        for (int green = 0; green <= 5; green++) 
            for (int red = 0; red <= 5; red++) 
            { 
                if (nIndex >= nNumEntries) 
                    break; 
 
                PalInfo.palPalEntry[nIndex].peRed   = (BYTE) ((red*255)/5); 
                PalInfo.palPalEntry[nIndex].peGreen = (BYTE) ((green*255)/5); 
                PalInfo.palPalEntry[nIndex].peBlue  = (BYTE) ((blue*255)/5); 
                PalInfo.palPalEntry[nIndex].peFlags = 0; 
                nIndex++; 
            } 
 
    // A grey scale (24 divisions) 
    for (int grey = 0; grey <= 23; grey++) 
    { 
        if (nIndex >= nNumEntries)  
            break; 
 
        PalInfo.palPalEntry[nIndex].peRed   = (BYTE) (grey*255/23); 
        PalInfo.palPalEntry[nIndex].peGreen = (BYTE) (grey*255/23); 
        PalInfo.palPalEntry[nIndex].peBlue  = (BYTE) (grey*255/23); 
        PalInfo.palPalEntry[nIndex].peFlags = 0; 
        nIndex++; 
    } 
 
    return palette.CreatePalette((LPLOGPALETTE) PalInfo); 
} 
#endif // DIBSECTION_NO_PALETTE 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CDIBSectionCE 
 
CDIBSectionCE::CDIBSectionCE() 
{ 
    m_hBitmap     = NULL; 
    m_hOldBitmap  = NULL; 
    m_bReuseMemDC = FALSE; 
 
    DeleteObject(); // This will initialise to a known state - ie. empty 
} 
 
CDIBSectionCE::~CDIBSectionCE() 
{ 
    DeleteObject(); 
} 
 
// --- In  : 
// --- Out : 
// --- Returns : 
// --- Effect : Resets the object to an empty state, and frees all memory used. 
void CDIBSectionCE::DeleteObject() 
{ 
    // Unselect the bitmap out of the memory DC before deleting bitmap 
    ReleaseMemoryDC(TRUE); 
 
    if (m_hBitmap) 
        ::DeleteObject(m_hBitmap); 
    m_hBitmap = NULL; 
    m_ppvBits = NULL; 
 
#ifndef DIBSECTION_NO_PALETTE 
    m_Palette.DeleteObject(); 
#endif 
 
    memset(&m_DIBinfo, 0, sizeof(m_DIBinfo)); 
 
    m_iColorDataType = DIB_RGB_COLORS; 
    m_iColorTableSize = 0; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CDIBSectionCE diagnostics 
 
#ifdef _DEBUG 
void CDIBSectionCE::AssertValid() const 
{ 
    ASSERT(m_hBitmap); 
 
    DIBSECTION ds; 
    DWORD dwSize = GetObject( m_hBitmap, sizeof(DIBSECTION), &ds ); 
    ASSERT(dwSize == sizeof(DIBSECTION)); 
 
    ASSERT(0 <= m_iColorTableSize && m_iColorTableSize <= 256); 
 
	CObject::AssertValid(); 
} 
 
void CDIBSectionCE::Dump(CDumpContext& dc) const 
{ 
	CObject::Dump(dc); 
} 
 
#endif //_DEBUG 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CDIBSectionCE operations 
 
// --- In  : pDC - Pointer to a device context 
//           ptDest - point at which the topleft corner of the image is drawn 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Draws the image 1:1 on the device context 
BOOL CDIBSectionCE::Draw(CDC* pDC, CPoint ptDest, BOOL bForceBackground /*=FALSE*/)  
{  
    if (!m_hBitmap) 
        return FALSE; 
 
    CSize size = GetSize(); 
    CPoint ptOrigin = CPoint(0,0); 
 
    // Create a memory DC compatible with the destination DC 
    CDC* pMemDC = GetMemoryDC(pDC, FALSE); 
    if (!pMemDC) 
        return FALSE; 
         
#ifndef DIBSECTION_NO_PALETTE 
    // Select and realize the palette 
    CPalette* pOldPalette = NULL; 
    if (m_Palette.m_hObject && UsesPalette(pDC)) 
    { 
        pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground); 
        pDC->RealizePalette(); 
    } 
#endif // DIBSECTION_NO_PALETTE 
 
    BOOL bResult = pDC->BitBlt(ptDest.x, ptDest.y, size.cx, size.cy, pMemDC,  
                               ptOrigin.x, ptOrigin.y, SRCCOPY); 
 
#ifndef DIBSECTION_NO_PALETTE 
    if (pOldPalette) 
        pDC->SelectPalette(pOldPalette, FALSE); 
#endif // DIBSECTION_NO_PALETTE 
 
    ReleaseMemoryDC(); 
    return bResult; 
} 
 
// --- In  : pDC - Pointer to a device context 
//           ptDest - point at which the topleft corner of the image is drawn 
//           size - size to stretch the image 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Stretch draws the image to the desired size on the device context 
BOOL CDIBSectionCE::Stretch(CDC* pDC, CPoint ptDest, CSize size, 
                          BOOL bForceBackground /*=FALSE*/)  
{  
    if (!m_hBitmap) 
        return FALSE; 
 
    CPoint ptOrigin = CPoint(0,0); 
    CSize imagesize = GetSize(); 
 
    // Create a memory DC compatible with the destination DC 
    CDC* pMemDC = GetMemoryDC(pDC, FALSE); 
    if (!pMemDC) 
        return FALSE; 
         
#ifndef DIBSECTION_NO_PALETTE 
    // Select and realize the palette 
    CPalette* pOldPalette = NULL; 
    if (m_Palette.m_hObject && UsesPalette(pDC)) 
    { 
        pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground); 
        pDC->RealizePalette(); 
    } 
#endif // DIBSECTION_NO_PALETTE 
 
#ifndef _WIN32_WCE 
    pDC->SetStretchBltMode(COLORONCOLOR); 
#endif // _WIN32_WCE 
 
    BOOL bResult = pDC->StretchBlt(ptDest.x, ptDest.y, size.cx, size.cy,  
                                   pMemDC,  
                                   ptOrigin.x, ptOrigin.y, imagesize.cx, imagesize.cy,  
                                   SRCCOPY); 
 
#ifndef DIBSECTION_NO_PALETTE 
    if (pOldPalette) 
        pDC->SelectPalette(pOldPalette, FALSE); 
#endif // DIBSECTION_NO_PALETTE 
 
    ReleaseMemoryDC(); 
    return bResult; 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// Setting the bitmap... 
 
// --- In  : nIDResource - resource ID 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Initialises the bitmap from a resource. If failure, then object is 
//              initialised back to an empty bitmap. 
BOOL CDIBSectionCE::SetBitmap(UINT nIDResource) 
{ 
    return SetBitmap(MAKEINTRESOURCE(nIDResource)); 
} 
 
// --- In  : lpszResourceName - resource name 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Initialises the bitmap from a resource. If failure, then object is 
//              initialised back to an empty bitmap. 
BOOL CDIBSectionCE::SetBitmap(LPCTSTR lpszResourceName) 
{ 
    HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),  
                                        lpszResourceName, 
                                        IMAGE_BITMAP,  
                                        0,0,  
#ifdef _WIN32_WCE 
                                        0 
#else 
                                        LR_CREATEDIBSECTION 
#endif 
                                        ); 
 
    if (!hBmp)  
    { 
        TRACE0("Unable to LoadImage"); 
        return FALSE; 
    } 
 
    BOOL bResult = SetBitmap(hBmp); 
    ::DeleteObject(hBmp); 
    return bResult; 
} 
 
// --- In  : lpBitmapInfo - pointer to a BITMAPINFO structure 
//           lpBits - pointer to image bits 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Initialises the bitmap using the information in lpBitmapInfo to determine 
//              the dimensions and colours, and the then sets the bits from the bits in 
//              lpBits. If failure, then object is initialised back to an empty bitmap. 
BOOL CDIBSectionCE::SetBitmap(LPBITMAPINFO lpBitmapInfo, LPVOID lpBits) 
{ 
    DeleteObject(); 
 
    if (!lpBitmapInfo || !lpBits) 
        return FALSE; 
 
    HDC hDC = NULL; 
    TRY { 
        BITMAPINFOHEADER& bmih = lpBitmapInfo->bmiHeader; 
 
        // Compute the number of colours in the colour table 
        m_iColorTableSize = NumColorEntries(bmih.biBitCount); 
 
        DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD); 
 
        // Copy over BITMAPINFO contents 
        memcpy(&m_DIBinfo, lpBitmapInfo, dwBitmapInfoSize); 
 
        // Should now have all the info we need to create the sucker. 
        //TRACE(_T("Width %d, Height %d, Bits/pixel %d, Image Size %d\n"), 
        //      bmih.biWidth, bmih.biHeight, bmih.biBitCount, bmih.biSizeImage); 
 
        // Create a DC which will be used to get DIB, then create DIBsection 
        hDC = ::GetDC(NULL); 
        if (!hDC)  
        { 
            TRACE0("Unable to get DC\n"); 
            AfxThrowResourceException(); 
        } 
 
        m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*) m_DIBinfo, 
                                     m_iColorDataType, &m_ppvBits, NULL, 0); 
        ::ReleaseDC(NULL, hDC); 
        if (!m_hBitmap) 
        { 
            TRACE0("CreateDIBSection failed\n"); 
            AfxThrowResourceException(); 
        } 
 
        DWORD dwImageSize = m_DIBinfo.bmiHeader.biSizeImage; 
        if (dwImageSize == 0) 
        { 
            int nBytesPerLine = BytesPerLine(lpBitmapInfo->bmiHeader.biWidth,  
                                             lpBitmapInfo->bmiHeader.biBitCount); 
            dwImageSize = nBytesPerLine * lpBitmapInfo->bmiHeader.biHeight; 
        } 
 
#ifndef _WIN32_WCE 
        // Flush the GDI batch queue  
        GdiFlush(); 
#endif 
 
        memcpy(m_ppvBits, lpBits, dwImageSize); 
 
#ifndef DIBSECTION_NO_PALETTE 
        if (!CreatePalette()) 
        { 
            TRACE0("Unable to create palette\n"); 
            AfxThrowResourceException(); 
        } 
#endif // DIBSECTION_NO_PALETTE 
    } 
    CATCH (CException, e) 
    { 
        e->Delete(); 
        _ShowLastError(); 
        if (hDC)  
            ::ReleaseDC(NULL, hDC); 
        DeleteObject(); 
        return FALSE; 
    } 
    END_CATCH 
 
    return TRUE; 
} 
 
// --- In  : hBitmap - handle to image 
//           pPalette - optional palette to use when setting image 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Initialises the bitmap from the HBITMAP supplied. If failure, then 
//              object is initialised back to an empty bitmap. 
BOOL CDIBSectionCE::SetBitmap(HBITMAP hBitmap, CPalette* pPalette /*= NULL*/) 
{ 
    DeleteObject(); 
 
    if (!hBitmap) 
        return FALSE; 
 
    // Get dimensions of bitmap 
    BITMAP bm; 
    if (!::GetObject(hBitmap, sizeof(bm),(LPVOID)&bm)) 
        return FALSE; 
    bm.bmHeight = abs(bm.bmHeight); 
 
    CWindowDC dc(NULL); 
#ifndef DIBSECTION_NO_PALETTE 
    CPalette* pOldPalette = NULL; 
#endif // DIBSECTION_NO_PALETTE 
 
    TRY { 
        m_iColorTableSize = NumColorEntries(bm.bmBitsPixel); 
 
        // Initialize the BITMAPINFOHEADER in m_DIBinfo 
        BITMAPINFOHEADER& bih = m_DIBinfo.bmiHeader; 
        bih.biSize          = sizeof(BITMAPINFOHEADER); 
        bih.biWidth         = bm.bmWidth; 
        bih.biHeight        = bm.bmHeight; 
        bih.biPlanes        = 1;                // Must always be 1 according to docs 
        bih.biBitCount      = bm.bmBitsPixel; 
        bih.biCompression   = BI_RGB; 
        bih.biSizeImage     = BytesPerLine(bm.bmWidth, bm.bmBitsPixel) * bm.bmHeight; 
        bih.biXPelsPerMeter = 0; 
        bih.biYPelsPerMeter = 0; 
        bih.biClrUsed       = 0; 
        bih.biClrImportant  = 0; 
 
        GetColorTableEntries(dc.GetSafeHdc(), hBitmap); 
 
#ifndef DIBSECTION_NO_PALETTE 
        // If we have a palette supplied, then set the palette (and hance DIB color 
        // table) using this palette 
        if (pPalette) 
            SetPalette(pPalette); 
 
        if (m_Palette.GetSafeHandle()) 
        { 
            pOldPalette = dc.SelectPalette(&m_Palette, FALSE); 
            dc.RealizePalette(); 
        } 
#endif // DIBSECTION_NO_PALETTE 
 
        // Create it! 
        m_hBitmap = CreateDIBSection(dc.m_hDC,  
                                     (const BITMAPINFO*) m_DIBinfo, 
                                     m_iColorDataType, 
                                     &m_ppvBits,  
                                     NULL, 0); 
#ifndef DIBSECTION_NO_PALETTE 
        if (pOldPalette) 
            dc.SelectPalette(pOldPalette, FALSE); 
        pOldPalette = NULL;  
#endif // DIBSECTION_NO_PALETTE 
 
        if (!m_hBitmap) 
        { 
            TRACE0("Unable to CreateDIBSection\n"); 
            AfxThrowResourceException(); 
        } 
 
#ifndef DIBSECTION_NO_PALETTE 
        // If palette was supplied then create a palette using the entries in the DIB 
        // color table. 
        if (!pPalette) 
            CreatePalette(); 
#endif // DIBSECTION_NO_PALETTE 
    
        // Need to copy the supplied bitmap onto the newly created DIBsection 
        CDC memDC, CopyDC; 
        if (!CopyDC.CreateCompatibleDC(&dc) || !memDC.CreateCompatibleDC(&dc))  
        { 
            TRACE0("Unable to create compatible DC's\n"); 
            AfxThrowResourceException(); 
        } 
 
#ifndef DIBSECTION_NO_PALETTE 
        if (m_Palette.GetSafeHandle()) 
        { 
            memDC.SelectPalette(&m_Palette, FALSE);  memDC.RealizePalette(); 
            CopyDC.SelectPalette(&m_Palette, FALSE); CopyDC.RealizePalette(); 
        } 
#endif // DIBSECTION_NO_PALETTE 
 
#ifndef _WIN32_WCE 
        // Flush the GDI batch queue  
        GdiFlush(); 
#endif 
 
        HBITMAP hOldMemBitmap  = (HBITMAP) SelectObject(memDC.m_hDC,  hBitmap); 
        HBITMAP hOldCopyBitmap = (HBITMAP) SelectObject(CopyDC.m_hDC, m_hBitmap); 
 
        CopyDC.BitBlt(0,0, bm.bmWidth, bm.bmHeight, &memDC, 0,0, SRCCOPY); 
 
        SelectObject(memDC.m_hDC, hOldMemBitmap); 
        SelectObject(CopyDC.m_hDC, hOldCopyBitmap); 
 
#ifndef DIBSECTION_NO_PALETTE 
        if (m_Palette.GetSafeHandle()) 
        { 
            memDC.SelectStockObject(DEFAULT_PALETTE); 
            CopyDC.SelectStockObject(DEFAULT_PALETTE); 
        } 
#endif // DIBSECTION_NO_PALETTE 
    } 
    CATCH (CException, e) 
    { 
        e->Delete(); 
        _ShowLastError(); 
#ifndef DIBSECTION_NO_PALETTE 
        if (pOldPalette) 
            dc.SelectPalette(pOldPalette, FALSE); 
 #endif // DIBSECTION_NO_PALETTE 
        DeleteObject(); 
        return FALSE; 
    } 
    END_CATCH 
 
    return TRUE; 
} 
 
 
////////////////////////////////////////////////////////////////////////////// 
// Persistance... 
 
// --- In  : lpszFileName - image filename 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Loads the bitmap from a bitmap file with the name lpszFileName.  
//              If failure, then object is initialised back to an empty bitmap. 
BOOL CDIBSectionCE::Load(LPCTSTR lpszFileName) 
{ 
    CFile file; 
    if (!file.Open(lpszFileName, CFile::modeRead)) 
        return FALSE; 
 
    // Get the current file position.   
    DWORD dwFileStart = file.GetPosition(); 
 
    // The first part of the file contains the file header. 
	// This will tell us if it is a bitmap, how big the header is, and how big  
    // the file is. The header size in the file header includes the color table. 
	BITMAPFILEHEADER BmpFileHdr; 
    int nBytes; 
    nBytes = file.Read(&BmpFileHdr, sizeof(BmpFileHdr)); 
    if (nBytes != sizeof(BmpFileHdr))  
    { 
        TRACE0("Failed to read file header\n"); 
        return FALSE; 
    } 
 
    // Check that we have the magic 'BM' at the start. 
    if (BmpFileHdr.bfType != DS_BITMAP_FILEMARKER) 
    { 
        TRACE0("Not a bitmap file\n"); 
        return FALSE; 
    } 
 
    // Read the header (assuming it's a DIB).  
	DIBINFO	BmpInfo; 
    nBytes = file.Read(&BmpInfo, sizeof(BITMAPINFOHEADER));  
    if (nBytes != sizeof(BITMAPINFOHEADER))  
    { 
        TRACE0("Failed to read BITMAPINFOHEADER\n"); 
        return FALSE; 
    } 
 
    // Check that we have a real Windows DIB file. 
    if (BmpInfo.bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) 
    { 
        TRACE0(" File is not a Windows DIB\n"); 
        return FALSE; 
    } 
 
    // See how big the color table is in the file (if there is one).   
    int nColors = NumColorEntries(BmpInfo.bmiHeader.biBitCount); 
	if (nColors > 0)  
    { 
        // Read the color table from the file. 
        int nColorTableSize = nColors * sizeof(RGBQUAD); 
		nBytes = file.Read(BmpInfo.ColorTable(), nColorTableSize); 
		if (nBytes != nColorTableSize)  
        { 
			TRACE0("Failed to read color table\n"); 
			return FALSE; 
        } 
	} 
 
	// So how big the bitmap surface is. 
    int nBitsSize = BmpFileHdr.bfSize - BmpFileHdr.bfOffBits; 
 
    // Allocate the memory for the bits and read the bits from the file. 
    BYTE* pBits = (BYTE*) malloc(nBitsSize); 
    if (!pBits)  
    { 
        TRACE0("Out of memory for DIB bits\n"); 
        return FALSE; 
    } 
 
    // Seek to the bits in the file. 
    file.Seek(dwFileStart + BmpFileHdr.bfOffBits, CFile::begin); 
 
    // read the bits 
    nBytes = file.Read(pBits, nBitsSize); 
    if (nBytes != nBitsSize)  
    { 
        TRACE0("Failed to read bits\n"); 
        free(pBits); 
		return FALSE; 
    } 
 
	// Everything went OK. 
	BmpInfo.bmiHeader.biSizeImage = nBitsSize; 
 
    if (!SetBitmap((LPBITMAPINFO) BmpInfo, pBits)) 
    { 
        TRACE0("Failed to set bitmap info\n"); 
        free(pBits); 
		return FALSE; 
    } 
 
    free(pBits); 
 
    return TRUE; 
} 
 
// --- In  : lpszFileName - image filename 
// --- Out : 
// --- Returns : Returns TRUE on success, FALSE otherwise 
// --- Effect : Saves the image to file. 
BOOL CDIBSectionCE::Save(LPCTSTR lpszFileName) 
{ 
    BITMAPFILEHEADER   hdr; 
    LPBITMAPINFOHEADER lpbi = GetBitmapInfoHeader(); 
 
    if (!lpbi || !lpszFileName) 
        return FALSE; 
 
    CFile file; 
    if (!file.Open(lpszFileName, CFile::modeWrite|CFile::modeCreate)) 
        return FALSE; 
 
    DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD); 
    DWORD dwFileHeaderSize = dwBitmapInfoSize + sizeof(hdr); 
 
    // Fill in the fields of the file header  
    hdr.bfType       = DS_BITMAP_FILEMARKER; 
    hdr.bfSize       = dwFileHeaderSize + lpbi->biSizeImage; 
    hdr.bfReserved1  = 0; 
    hdr.bfReserved2  = 0; 
    hdr.bfOffBits    = dwFileHeaderSize; 
 
    // Write the file header  
    file.Write(&hdr, sizeof(hdr)); 
 
    // Write the DIB header 
    file.Write(lpbi, dwBitmapInfoSize); 
     
    // Write DIB bits 
    file.Write(GetDIBits(), lpbi->biSizeImage); 
 
    return TRUE; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CDIBSectionCE palette stuff 
 
#ifndef DIBSECTION_NO_PALETTE 
 
// --- In  : 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Creates the palette from the DIBSection's color table. Assumes  
//              m_iColorTableSize has been set and the DIBsection m_hBitmap created 
BOOL CDIBSectionCE::CreatePalette() 
{ 
    m_Palette.DeleteObject(); 
 
    if (!m_hBitmap) 
        return FALSE; 
 
    // Create a 256 color halftone palette if there is no color table in the DIBSection 
    if (m_iColorTableSize == 0) 
        return CreateHalftonePalette(m_Palette, 256); 
 
    // Get space for the colour entries 
    RGBQUAD *pRGB = new RGBQUAD[m_iColorTableSize]; 
    if (!pRGB) 
        return CreateHalftonePalette(m_Palette, m_iColorTableSize); 
 
    HDC hDC = ::GetDC(NULL); 
    if (!hDC) 
    { 
        delete [] pRGB; 
        return FALSE; 
    } 
 
    // Create a memory DC compatible with the current DC 
    CDC MemDC; 
    MemDC.CreateCompatibleDC(CDC::FromHandle(hDC)); 
    if (!MemDC.GetSafeHdc()) 
    { 
        delete [] pRGB; 
        ::ReleaseDC(NULL, hDC); 
        return CreateHalftonePalette(m_Palette, m_iColorTableSize); 
    } 
    ::ReleaseDC(NULL, hDC); 
     
    HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(MemDC.GetSafeHdc(), m_hBitmap); 
    if (!hOldBitmap) 
    { 
        delete [] pRGB; 
        return CreateHalftonePalette(m_Palette, m_iColorTableSize); 
    } 
 
    // Get the colours used. WinCE does not support GetDIBColorTable so if you 
    // are using this on a CE device with palettes, then you need to replace 
    // the call with code that manually gets the color table from the m_DIBinfo structure. 
#ifdef _WIN32_WCE 
    int nColours = ::CEGetDIBColorTable(MemDC.GetSafeHdc(), 0, m_iColorTableSize, pRGB); 
#else 
    int nColours = ::GetDIBColorTable(MemDC.GetSafeHdc(), 0, m_iColorTableSize, pRGB); 
#endif 
 
    // Clean up 
    ::SelectObject(MemDC.GetSafeHdc(), hOldBitmap); 
 
    if (!nColours)   // No colours retrieved => the bitmap in the DC is not a DIB section 
    { 
        delete [] pRGB; 
        return CreateHalftonePalette(m_Palette, m_iColorTableSize); 
    }    
     
    // Create and fill a LOGPALETTE structure with the colours used. 
    PALETTEINFO PaletteInfo; 
    PaletteInfo.palNumEntries = (WORD) m_iColorTableSize; 
                         
    for (int i = 0; i < nColours; i++) 
    { 
        PaletteInfo.palPalEntry[i].peRed   = pRGB[i].rgbRed; 
        PaletteInfo.palPalEntry[i].peGreen = pRGB[i].rgbGreen; 
        PaletteInfo.palPalEntry[i].peBlue  = pRGB[i].rgbBlue; 
        PaletteInfo.palPalEntry[i].peFlags = 0; 
    } 
    for (; i < (int) m_iColorTableSize; i++) 
    { 
        PaletteInfo.palPalEntry[i].peRed   = 0; 
        PaletteInfo.palPalEntry[i].peGreen = 0; 
        PaletteInfo.palPalEntry[i].peBlue  = 0; 
        PaletteInfo.palPalEntry[i].peFlags = 0; 
    } 
 
    delete [] pRGB; 
 
    // Create Palette! 
    return m_Palette.CreatePalette(&PaletteInfo); 
} 
 
// --- In  : pPalette - new palette to use 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Sets the current palette used by the image from the supplied CPalette, 
//              and sets the color table in the DIBSection 
BOOL CDIBSectionCE::SetPalette(CPalette* pPalette) 
{ 
    m_Palette.DeleteObject(); 
 
    if (!pPalette) 
        return FALSE; 
 
    UINT nColours = pPalette->GetEntryCount(); 
    if (nColours <= 0 || nColours > 256) 
        return FALSE; 
 
    // Get palette entries 
    PALETTEINFO pi; 
    pi.palNumEntries = (WORD) pPalette->GetPaletteEntries(0, nColours, (LPPALETTEENTRY) pi); 
                           
    // TODO: If pi.palNumEntries < m_iColorTableSize, then fill in blanks with 0's 
 
    return SetLogPalette(&pi); 
} 
 
// --- In  : pLogPalette - new palette to use 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Sets the current palette used by the image from the supplied LOGPALETTE 
BOOL CDIBSectionCE::SetLogPalette(LOGPALETTE* pLogPalette) 
{ 
    ASSERT(pLogPalette->palVersion == (WORD) 0x300); 
    UINT nColours = pLogPalette->palNumEntries; 
    if (nColours <= 0 || nColours > 256) 
    { 
        CreatePalette(); 
        return FALSE; 
    } 
 
    // Create new palette 
    m_Palette.DeleteObject(); 
    if (!m_Palette.CreatePalette(pLogPalette)) 
    { 
        CreatePalette(); 
        return FALSE; 
    } 
 
    if (m_iColorTableSize == 0) 
        return TRUE; 
 
    // Set the DIB colours 
    RGBQUAD RGBquads[256];  
    for (UINT i = 0; i < nColours; i++) 
    { 
        RGBquads[i].rgbRed   = pLogPalette->palPalEntry[i].peRed; 
        RGBquads[i].rgbGreen = pLogPalette->palPalEntry[i].peGreen; 
        RGBquads[i].rgbBlue  = pLogPalette->palPalEntry[i].peBlue; 
        RGBquads[i].rgbReserved = 0; 
    } 
     
    return FillDIBColorTable(nColours, RGBquads); 
} 
 
// --- In  : nNumColours - number of colours to set 
//           pRGB - colours to fill 
// --- Out : 
// --- Returns : Returns TRUE on success 
// --- Effect : Sets the colours used by the image. Only works if # colours <= 256 
BOOL CDIBSectionCE::FillDIBColorTable(UINT nNumColours, RGBQUAD *pRGB) 
{ 
    if (!pRGB || !nNumColours || !m_iColorTableSize || nNumColours > 256) 
        return FALSE; 
 
    // get the number of colors to return per BITMAPINFOHEADER docs 
    UINT nColors; 
    LPBITMAPINFOHEADER pBmih = GetBitmapInfoHeader(); 
    if (pBmih->biClrUsed) 
        nColors = pBmih->biClrUsed; 
    else 
        nColors = 1 << (pBmih->biBitCount*pBmih->biPlanes); 
 
    // Initialize the loop variables 
    nColors = min(nNumColours, nColors); 
 
    LPRGBQUAD pColorTable = GetColorTable(); 
    for (UINT iColor = 0; iColor < nColors; iColor++) 
    { 
        pColorTable[iColor].rgbReserved = 0; 
        pColorTable[iColor].rgbBlue     = pRGB[iColor].rgbBlue; 
        pColorTable[iColor].rgbRed      = pRGB[iColor].rgbRed; 
        pColorTable[iColor].rgbGreen    = pRGB[iColor].rgbGreen; 
    } 
 
    return TRUE; 
} 
 
#endif // DIBSECTION_NO_PALETTE 
 
 
// --- In  : hdc     - the Device Context in which the DIBSection is selected 
//           hBitmap - the bitmap whose solor entries are to be queried 
//           lpbi    - a pointer to a BITMAPINFO structure that will have it's 
//                     color table filled. 
// --- Out : 
// --- Returns : the number of colors placed in the color table 
// --- Effect : This function is a replacement for GetDIBits, in that it retrieves  
//              (or synthesizes) the color table from the given bitmap, and stores  
//              the values in the BITMAPINFO structure supplied. 
UINT CDIBSectionCE::GetColorTableEntries(HDC hdc, HBITMAP hBitmap) 
{ 
    UINT nColorTableSize = m_iColorTableSize; 
    if (!nColorTableSize) 
        return 0; 
     
    // Fill the color table with the colours from the bitmap's color table 
    LPRGBQUAD pColorTable = GetColorTable(); 
     
    // Get the color table from the HBITMAP and copy them over. 
    UINT nCount; 
    RGBQUAD* pRGB = new RGBQUAD[nColorTableSize]; 
    if (pRGB) 
    { 
        HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdc, hBitmap); 
        nCount = CEGetDIBColorTable(hdc, 0, nColorTableSize, pRGB); 
        SelectObject(hdc, hOldBitmap); 
        if (nCount) 
        { 
            nColorTableSize = nCount; 
            memcpy(pColorTable, pRGB, nCount*sizeof(RGBQUAD)); 
        } 
    } 
    delete [] pRGB; 
 
    // Didn't work - so synthesize one. 
    if (!nCount) 
    {        
        int nNumStandardColours = sizeof(ms_StdColours) / sizeof(ms_StdColours[0]); 
        UINT nIndex = 0; 
         
        // The standard colours (16) 
        for (int i = 0; i < nNumStandardColours; i++) 
        { 
            if (nIndex >= nColorTableSize)  
                break; 
 
            memcpy( &(pColorTable[i]), &(ms_StdColours[i]), sizeof(RGBQUAD) );          
             
            nIndex++; 
        } 
         
        // A colour cube (6 divisions = 216) 
        for (int blue = 0; blue <= 5; blue++) 
            for (int green = 0; green <= 5; green++) 
                for (int red = 0; red <= 5; red++) 
                { 
                    if (nIndex >= nColorTableSize) 
                        break; 
                     
                    pColorTable[i].rgbRed   = (BYTE) ((red*255)/5); 
                    pColorTable[i].rgbGreen = (BYTE) ((green*255)/5); 
                    pColorTable[i].rgbBlue  = (BYTE) ((blue*255)/5); 
                    pColorTable[i].rgbReserved = 0; 
                    nIndex++; 
                } 
                 
        // A grey scale (24 divisions) 
        for (int grey = 0; grey <= 23; grey++) 
        { 
            if (nIndex >= nColorTableSize)  
                break; 
             
            pColorTable[i].rgbRed   = (BYTE) (grey*255/23); 
            pColorTable[i].rgbGreen = (BYTE) (grey*255/23); 
            pColorTable[i].rgbBlue  = (BYTE) (grey*255/23); 
            pColorTable[i].rgbReserved = 0; 
            nIndex++; 
        } 
    } 
 
    return nColorTableSize; 
} 
 
/********************************************************************** 
This function is from the MS KB article "HOWTO: Get the Color Table of  
a DIBSection in Windows CE". 
 
PARAMETERS: 
HDC - the Device Context in which the DIBSection is selected 
UINT - the index of the first color table entry to retrieve 
UINT - the number of color table entries to retrieve 
RGBQUAD - a buffer large enough to hold the number of RGBQUAD 
entries requested 
 
RETURNS: 
UINT - the number of colors placed in the buffer 
 
***********************************************************************/ 
UINT CEGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries, 
                        RGBQUAD *pColors) 
{    
    if (pColors == NULL) 
        return 0;                       // No place to put them, fail 
     
    // Get a description of the DIB Section 
    HBITMAP hDIBSection = (HBITMAP) GetCurrentObject( hdc, OBJ_BITMAP ); 
 
    DIBSECTION ds; 
    DWORD dwSize = GetObject( hDIBSection, sizeof(DIBSECTION), &ds ); 
     
    if (dwSize != sizeof(DIBSECTION)) 
        return 0;                      // Must not be a DIBSection, fail 
     
    if (ds.dsBmih.biBitCount > 8) 
        return 0;                      // Not Palettized, fail 
     
    // get the number of colors to return per BITMAPINFOHEADER docs 
    UINT cColors; 
    if (ds.dsBmih.biClrUsed) 
        cColors = ds.dsBmih.biClrUsed; 
    else 
        cColors = 1 << (ds.dsBmih.biBitCount*ds.dsBmih.biPlanes); 
     
    // Create a mask for the palette index bits for 1, 2, 4, and 8 bpp 
    WORD wIndexMask = (0xFF << (8 - ds.dsBmih.biBitCount)) & 0x00FF; 
     
    // Get the pointer to the image bits 
    LPBYTE pBits = (LPBYTE) ds.dsBm.bmBits; 
     
    // Initialize the loop variables 
    cColors = min( cColors, cEntries ); 
    BYTE OldPalIndex = *pBits; 
  
    UINT TestPixelY; 
    if (ds.dsBmih.biHeight > 0 ) 
        // If button up DIB, pBits points to last row 
        TestPixelY = ds.dsBm.bmHeight-1; 
    else 
        // If top down DIB, pBits points to first row 
        TestPixelY = 0; 
     
    for (UINT iColor = uStartIndex; iColor < cColors; iColor++) 
    { 
        COLORREF    rgbColor; 
         
        // Set the palette index for the test pixel, 
        // modifying only the bits for one pixel 
        *pBits = (iColor << (8 - ds.dsBmih.biBitCount)) | 
            (*pBits & ~wIndexMask); 
         
        // now get the resulting color 
        rgbColor = GetPixel( hdc, 0, TestPixelY ); 
         
        pColors[iColor - uStartIndex].rgbReserved = 0; 
        pColors[iColor - uStartIndex].rgbBlue = GetBValue(rgbColor); 
        pColors[iColor - uStartIndex].rgbRed = GetRValue(rgbColor); 
        pColors[iColor - uStartIndex].rgbGreen = GetGValue(rgbColor); 
    } 
     
    // Restore the test pixel 
    *pBits = OldPalIndex; 
     
    return cColors; 
} 
 
 
// --- In  : pDC - device context to use when calling CreateCompatibleDC 
//           bSelectPalette - if TRUE, the current palette will be preselected 
// --- Out : 
// --- Returns : A pointer to a memory DC 
// --- Effect : Creates a memory DC and selects in the current bitmap so it can be 
//              modified using the GDI functions. Only one memDC can be created for 
//              a given CDIBSectionCE object. If you have a memDC but wish to recreate it 
//              as compatible with a different DC, then call ReleaseMemoryDC first. 
//              If the memory DC has already been created then it will be recycled. 
//              Note that if using this in an environment where the colour depth of 
//              the screen may change, then you will need to set "m_bReuseMemDC" to FALSE 
CDC* CDIBSectionCE::GetMemoryDC(CDC* pDC /*=NULL*/, BOOL bSelectPalette /*=TRUE*/) 
{ 
    if (!m_bReuseMemDC) 
        ReleaseMemoryDC(TRUE); 
    else if (m_MemDC.GetSafeHdc())   // Already created? 
    { 
#ifndef _WIN32_WCE 
        // Flush the GDI batch queue  
        GdiFlush(); 
#endif 
        return &m_MemDC; 
    } 
 
    // Create a memory DC compatible with the given DC 
    if (pDC) 
        m_MemDC.CreateCompatibleDC(pDC); 
    else 
    { 
        HDC hDC = ::GetDC(NULL);    // screen DC 
        if (!hDC) return FALSE; 
        m_MemDC.CreateCompatibleDC(CDC::FromHandle(hDC)); 
        ::ReleaseDC(NULL, hDC); 
    } 
    if (!m_MemDC.GetSafeHdc()) 
        return NULL; 
 
    // Select in the bitmap 
    m_hOldBitmap = (HBITMAP) ::SelectObject(m_MemDC.GetSafeHdc(), m_hBitmap); 
    if (!m_hOldBitmap) 
    { 
        m_MemDC.DeleteDC(); 
        return NULL; 
    } 
 
#ifndef DIBSECTION_NO_PALETTE 
    // Select in the palette 
    if (bSelectPalette && UsesPalette(&m_MemDC)) 
    { 
        // Palette should already have been created - but just in case... 
        if (!m_Palette.GetSafeHandle()) 
            CreatePalette(); 
 
        m_pOldPalette = m_MemDC.SelectPalette(&m_Palette, FALSE); 
        m_MemDC.RealizePalette(); 
    } 
    else 
        m_pOldPalette = NULL; 
#endif // DIBSECTION_NO_PALETTE 
 
#ifndef _WIN32_WCE 
    // Flush the GDI batch queue  
    GdiFlush(); 
#endif // _WIN32_WCE 
 
    return &m_MemDC; 
} 
 
// --- In  : bForceRelease - if TRUE, then the memory DC is forcibly released 
// --- Out : 
// --- Returns : TRUE on success 
// --- Effect : Selects out the current bitmap and deletes the mem dc. If bForceRelease  
//              is FALSE, then the DC release will not actually occur. This is provided  
//              so you can have 
// 
//                 GetMemoryDC(...) 
//                 ... do something 
//                 ReleaseMemoryDC() 
// 
//               bracketed calls. If m_bReuseMemDC is subsequently set to FALSE, then  
//               the same code fragment will still work. 
BOOL CDIBSectionCE::ReleaseMemoryDC(BOOL bForceRelease /*=FALSE*/) 
{ 
    if ( !m_MemDC.GetSafeHdc() || (m_bReuseMemDC && !bForceRelease) ) 
        return TRUE; // Nothing to do 
 
#ifndef _WIN32_WCE 
    // Flush the GDI batch queue  
    GdiFlush(); 
#endif // _WIN32_WCE 
 
    // Select out the current bitmap 
    if (m_hOldBitmap) 
        ::SelectObject(m_MemDC.GetSafeHdc(), m_hOldBitmap); 
    m_hOldBitmap = NULL; 
 
#ifndef DIBSECTION_NO_PALETTE 
    // Select out the current palette 
    if (m_pOldPalette) 
        m_MemDC.SelectPalette(m_pOldPalette, FALSE); 
    m_pOldPalette = NULL; 
#endif // DIBSECTION_NO_PALETTE 
 
    // Delete the memory DC 
    return m_MemDC.DeleteDC(); 
} 
 
 
#ifdef _DEBUG 
// Makes trace windows a little bit more informative... 
void CDIBSectionCE::_ShowLastError() 
{ 
    LPVOID lpMsgBuf; 
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,     
                  NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  
                  (LPTSTR) &lpMsgBuf, 0, NULL); 
    TRACE1("Last error: %s\n", lpMsgBuf); 
    LocalFree(lpMsgBuf); 
} 
#else 
void CDIBSectionCE::_ShowLastError() {} 
#endif