www.pudn.com > Evd.rar > cdib.cpp


// cdib.cpp 
// new version for WIN32 
#include "stdafx.h" 
#include "cdib.h" 
#include  
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
IMPLEMENT_SERIAL(CDib, CObject, 0); 
 
CDib::CDib() 
{ 
	m_hFile = NULL; 
	m_hBitmap = NULL; 
	m_hPalette = NULL; 
	m_nBmihAlloc = m_nImageAlloc = noAlloc; 
	Empty(); 
} 
 
CDib::CDib(CSize size, int nBitCount) 
{ 
	m_hFile = NULL; 
	m_hBitmap = NULL; 
	m_hPalette = NULL; 
	m_nBmihAlloc = m_nImageAlloc = noAlloc; 
	Empty(); 
	ComputePaletteSize(nBitCount); 
	m_lpBMIH = (LPBITMAPINFOHEADER) new  
		char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries]; 
	m_nBmihAlloc = crtAlloc; 
	m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER); 
	m_lpBMIH->biWidth = size.cx; 
	m_lpBMIH->biHeight = size.cy; 
	m_lpBMIH->biPlanes = 1; 
	m_lpBMIH->biBitCount = nBitCount; 
	m_lpBMIH->biCompression = BI_RGB; 
	m_lpBMIH->biSizeImage = 0; 
	m_lpBMIH->biXPelsPerMeter = 0; 
	m_lpBMIH->biYPelsPerMeter = 0; 
	m_lpBMIH->biClrUsed = m_nColorTableEntries; 
	m_lpBMIH->biClrImportant = m_nColorTableEntries; 
	ComputeMetrics(); 
	memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries); 
	m_lpImage = NULL;  // no data yet 
} 
 
CDib::~CDib() 
{ 
	Empty(); 
} 
 
CSize CDib::GetDimensions() 
{	 
	if(m_lpBMIH == NULL) return CSize(0, 0); 
	return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight); 
} 
 
BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading 
{ 
	// if we open the same file twice, Windows treats it as 2 separate files 
	// doesn't work with rare BMP files where # palette entries > biClrUsed 
	HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 
		bShare ? FILE_SHARE_READ : 0, 
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
	ASSERT(hFile != INVALID_HANDLE_VALUE); 
	DWORD dwFileSize = ::GetFileSize(hFile, NULL); 
	HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); 
	DWORD dwErr = ::GetLastError(); 
	if(hMap == NULL) { 
		AfxMessageBox("Empty bitmap file"); 
		return FALSE; 
	} 
	LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file 
	ASSERT(lpvFile != NULL); 
	if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) { 
		AfxMessageBox("Invalid bitmap file"); 
		DetachMapFile(); 
		return FALSE; 
	} 
	AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER)); 
	m_lpvFile = lpvFile; 
	m_hFile = hFile; 
	m_hMap = hMap; 
	return TRUE; 
} 
 
BOOL CDib::CopyToMapFile(const char* strPathname) 
{ 
	// copies DIB to a new file, releases prior pointers 
	// if you previously used CreateSection, the HBITMAP will be NULL (and unusable) 
	BITMAPFILEHEADER bmfh; 
	bmfh.bfType = 0x4d42;  // 'BM' 
	bmfh.bfSize = m_dwSizeImage + sizeof(BITMAPINFOHEADER) + 
			sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER); 
	// meaning of bfSize open to interpretation 
	bmfh.bfReserved1 = bmfh.bfReserved2 = 0; 
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
			sizeof(RGBQUAD) * m_nColorTableEntries;	 
	HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL, 
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
	ASSERT(hFile != INVALID_HANDLE_VALUE); 
	int nSize =  sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
				sizeof(RGBQUAD) * m_nColorTableEntries +  m_dwSizeImage; 
	HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, NULL); 
	DWORD dwErr = ::GetLastError(); 
	ASSERT(hMap != NULL); 
	LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file 
	ASSERT(lpvFile != NULL); 
	LPBYTE lpbCurrent = (LPBYTE) lpvFile; 
	memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER)); // file header 
	lpbCurrent += sizeof(BITMAPFILEHEADER); 
	LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent; 
	memcpy(lpbCurrent, m_lpBMIH, 
		sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries); // info 
	lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; 
	memcpy(lpbCurrent, m_lpImage, m_dwSizeImage); // bit image 
	DWORD dwSizeImage = m_dwSizeImage; 
	Empty(); 
	m_dwSizeImage = dwSizeImage; 
	m_nBmihAlloc = m_nImageAlloc = noAlloc; 
	m_lpBMIH = lpBMIH; 
	m_lpImage = lpbCurrent; 
	m_hFile = hFile; 
	m_hMap = hMap; 
	m_lpvFile = lpvFile; 
	ComputePaletteSize(m_lpBMIH->biBitCount); 
	ComputeMetrics(); 
	MakePalette(); 
	return TRUE; 
} 
 
BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal) 
{ 
	// assumes contiguous BITMAPINFOHEADER, color table, image 
	// color table could be zero length 
	Empty(); 
	m_hGlobal = hGlobal; 
	if(bMustDelete == FALSE) { 
		m_nBmihAlloc = noAlloc; 
	} 
	else { 
		m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc); 
	} 
	try { 
		m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem; 
		ComputeMetrics(); 
		ComputePaletteSize(m_lpBMIH->biBitCount); 
		m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries; 
		MakePalette(); 
	} 
	catch(CException* pe) { 
		AfxMessageBox("AttachMemory error"); 
		pe->Delete(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */) 
{ 
	if(m_hPalette == NULL) return 0; 
	HDC hdc = pDC->GetSafeHdc(); 
	::SelectPalette(hdc, m_hPalette, bBackground); 
	return ::RealizePalette(hdc); 
} 
 
BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size) 
{ 
	if(m_lpBMIH == NULL) return FALSE; 
	if(m_hPalette != NULL) { 
		::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE); 
	} 
	pDC->SetStretchBltMode(COLORONCOLOR); 
	::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy, 
		0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight, 
		m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY); 
	return TRUE; 
} 
 
HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */) 
{ 
	if(m_lpBMIH == NULL) return NULL; 
	if(m_lpImage != NULL) return NULL; // can only do this if image doesn't exist 
	m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH, 
		DIB_RGB_COLORS,	(LPVOID*) &m_lpImage, NULL, 0); 
	ASSERT(m_lpImage != NULL); 
	return m_hBitmap; 
} 
 
BOOL CDib::MakePalette() 
{ 
	// makes a logical palette (m_hPalette) from the DIB's color table 
	// this palette will be selected and realized prior to drawing the DIB 
	if(m_nColorTableEntries == 0) return FALSE; 
	if(m_hPalette != NULL) ::DeleteObject(m_hPalette); 
	TRACE("CDib::MakePalette -- m_nColorTableEntries = %d\n", m_nColorTableEntries); 
	LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + 
		m_nColorTableEntries * sizeof(PALETTEENTRY)]; 
	pLogPal->palVersion = 0x300; 
	pLogPal->palNumEntries = m_nColorTableEntries; 
	LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable; 
	for(int i = 0; i < m_nColorTableEntries; i++) { 
		pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed; 
		pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen; 
		pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue; 
		pLogPal->palPalEntry[i].peFlags = 0; 
		pDibQuad++; 
	} 
	m_hPalette = ::CreatePalette(pLogPal); 
	delete pLogPal; 
	return TRUE; 
}	 
 
BOOL CDib::SetSystemPalette(CDC* pDC) 
{ 
	// if the DIB doesn't have a color table, we can use the system's halftone palette 
	if(m_nColorTableEntries != 0) return FALSE; 
	m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc()); 
	return TRUE; 
} 
 
HBITMAP CDib::CreateBitmap(CDC* pDC) 
{ 
    if (m_dwSizeImage == 0) return NULL; 
    HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH, 
            CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS); 
    ASSERT(hBitmap != NULL); 
    return hBitmap; 
} 
 
BOOL CDib::Compress(CDC* pDC, BOOL bCompress /* = TRUE */) 
{ 
	// 1. makes GDI bitmap from existing DIB 
	// 2. makes a new DIB from GDI bitmap with compression 
	// 3. cleans up the original DIB 
	// 4. puts the new DIB in the object 
	if((m_lpBMIH->biBitCount != 4) && (m_lpBMIH->biBitCount != 8)) return FALSE; 
		// compression supported only for 4 bpp and 8 bpp DIBs 
	if(m_hBitmap) return FALSE; // can't compress a DIB Section! 
	TRACE("Compress: original palette size = %d\n", m_nColorTableEntries);  
	HDC hdc = pDC->GetSafeHdc(); 
	HPALETTE hOldPalette = ::SelectPalette(hdc, m_hPalette, FALSE); 
	HBITMAP hBitmap;  // temporary 
	if((hBitmap = CreateBitmap(pDC)) == NULL) return FALSE; 
	int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; 
	LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]; 
	memcpy(lpBMIH, m_lpBMIH, nSize);  // new header 
	if(bCompress) { 
		switch (lpBMIH->biBitCount) { 
		case 4: 
			lpBMIH->biCompression = BI_RLE4; 
			break; 
		case 8: 
			lpBMIH->biCompression = BI_RLE8; 
			break; 
		default: 
			ASSERT(FALSE); 
		} 
		// calls GetDIBits with null data pointer to get size of compressed DIB 
		if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight, 
						NULL, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)) { 
			AfxMessageBox("Unable to compress this DIB"); 
			// probably a problem with the color table 
	 		::DeleteObject(hBitmap); 
			delete [] lpBMIH; 
			::SelectPalette(hdc, hOldPalette, FALSE); 
			return FALSE;  
		} 
		if (lpBMIH->biSizeImage == 0) { 
			AfxMessageBox("Driver can't do compression"); 
	 		::DeleteObject(hBitmap); 
			delete [] lpBMIH; 
			::SelectPalette(hdc, hOldPalette, FALSE); 
			return FALSE;  
		} 
		else { 
			m_dwSizeImage = lpBMIH->biSizeImage; 
		} 
	} 
	else { 
		lpBMIH->biCompression = BI_RGB; // decompress 
		// figure the image size from the bitmap width and height 
		DWORD dwBytes = ((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) / 32; 
		if(((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) % 32) { 
			dwBytes++; 
		} 
		dwBytes *= 4; 
		m_dwSizeImage = dwBytes * lpBMIH->biHeight; // no compression 
		lpBMIH->biSizeImage = m_dwSizeImage; 
	}  
	// second GetDIBits call to make DIB 
	LPBYTE lpImage = (LPBYTE) new char[m_dwSizeImage]; 
	VERIFY(::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight, 
    		lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)); 
    TRACE("dib successfully created - height = %d\n", lpBMIH->biHeight); 
	::DeleteObject(hBitmap); 
	Empty(); 
	m_nBmihAlloc = m_nImageAlloc = crtAlloc; 
	m_lpBMIH = lpBMIH; 
	m_lpImage = lpImage; 
	ComputeMetrics(); 
	ComputePaletteSize(m_lpBMIH->biBitCount); 
	MakePalette(); 
	::SelectPalette(hdc, hOldPalette, FALSE); 
	TRACE("Compress: new palette size = %d\n", m_nColorTableEntries);  
	return TRUE; 
} 
 
BOOL CDib::Read(CFile* pFile) 
{ 
	// 1. read file header to get size of info hdr + color table 
	// 2. read info hdr (to get image size) and color table 
	// 3. read image 
	// can't use bfSize in file header 
	Empty(); 
	int nCount, nSize; 
	BITMAPFILEHEADER bmfh; 
	try { 
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); 
		if(nCount != sizeof(BITMAPFILEHEADER)) { 
			throw new CUserException; 
		} 
		if(bmfh.bfType != 0x4d42) { 
			throw new CUserException; 
		} 
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER); 
		m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]; 
		m_nBmihAlloc = m_nImageAlloc = crtAlloc; 
		nCount = pFile->Read(m_lpBMIH, nSize); // info hdr & color table 
		ComputeMetrics(); 
		ComputePaletteSize(m_lpBMIH->biBitCount); 
		MakePalette(); 
		m_lpImage = (LPBYTE) new char[m_dwSizeImage]; 
		nCount = pFile->Read(m_lpImage, m_dwSizeImage); // image only 
	} 
	catch(CException* pe) { 
		AfxMessageBox("Read error"); 
		pe->Delete(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */) 
{ 
	// new function reads BMP from disk and creates a DIB section 
	//    allows modification of bitmaps from disk 
	// 1. read file header to get size of info hdr + color table 
	// 2. read info hdr (to get image size) and color table 
	// 3. create DIB section based on header parms 
	// 4. read image into memory that CreateDibSection allocates 
	Empty(); 
	int nCount, nSize; 
	BITMAPFILEHEADER bmfh; 
	try { 
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); 
		if(nCount != sizeof(BITMAPFILEHEADER)) { 
			throw new CUserException; 
		} 
		if(bmfh.bfType != 0x4d42) { 
			throw new CUserException; 
		} 
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER); 
		m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]; 
		m_nBmihAlloc = crtAlloc; 
		m_nImageAlloc = noAlloc; 
		nCount = pFile->Read(m_lpBMIH, nSize); // info hdr & color table 
		if(m_lpBMIH->biCompression != BI_RGB) { 
			throw new CUserException; 
		} 
		ComputeMetrics(); 
		ComputePaletteSize(m_lpBMIH->biBitCount); 
		MakePalette(); 
		UsePalette(pDC); 
		m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH, 
			DIB_RGB_COLORS,	(LPVOID*) &m_lpImage, NULL, 0); 
		ASSERT(m_lpImage != NULL); 
		nCount = pFile->Read(m_lpImage, m_dwSizeImage); // image only 
	} 
	catch(CException* pe) { 
		AfxMessageBox("ReadSection error"); 
		pe->Delete(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
BOOL CDib::Write(CFile* pFile) 
{ 
	BITMAPFILEHEADER bmfh; 
	bmfh.bfType = 0x4d42;  // 'BM' 
	int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; 
	bmfh.bfSize = 0; 
//	bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage; 
	// meaning of bfSize open to interpretation (bytes, words, dwords?) -- we won't use it 
	bmfh.bfReserved1 = bmfh.bfReserved2 = 0; 
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
			sizeof(RGBQUAD) * m_nColorTableEntries;	 
	try { 
		pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); 
		pFile->Write((LPVOID) m_lpBMIH,  nSizeHdr); 
		pFile->Write((LPVOID) m_lpImage, m_dwSizeImage); 
	} 
	catch(CException* pe) { 
		pe->Delete(); 
		AfxMessageBox("write error"); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
void CDib::Serialize(CArchive& ar) 
{ 
	DWORD dwPos; 
	dwPos = ar.GetFile()->GetPosition(); 
	TRACE("CDib::Serialize -- pos = %d\n", dwPos); 
	ar.Flush(); 
	dwPos = ar.GetFile()->GetPosition(); 
	TRACE("CDib::Serialize -- pos = %d\n", dwPos); 
	if(ar.IsStoring()) { 
		Write(ar.GetFile()); 
	} 
	else { 
		Read(ar.GetFile()); 
	} 
} 
 
// helper functions 
void CDib::ComputePaletteSize(int nBitCount) 
{ 
	if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) { 
		switch(nBitCount) { 
			case 1: 
				m_nColorTableEntries = 2; 
				break; 
			case 4: 
				m_nColorTableEntries = 16; 
				break; 
			case 8: 
				m_nColorTableEntries = 256; 
				break; 
			case 16: 
			case 24: 
			case 32: 
				m_nColorTableEntries = 0; 
				break; 
			default: 
				ASSERT(FALSE); 
		} 
	} 
	else { 
		m_nColorTableEntries = m_lpBMIH->biClrUsed; 
	} 
	ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256));  
} 
 
void CDib::ComputeMetrics() 
{ 
	if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) { 
		TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n"); 
		throw new CUserException; 
	} 
	m_dwSizeImage = m_lpBMIH->biSizeImage; 
	if(m_dwSizeImage == 0) { 
		DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32; 
		if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) { 
			dwBytes++; 
		} 
		dwBytes *= 4; 
		m_dwSizeImage = dwBytes * m_lpBMIH->biHeight; // no compression 
	} 
	m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER); 
} 
 
void CDib::Empty() 
{ 
	// this is supposed to clean up whatever is in the DIB 
	DetachMapFile(); 
	if(m_nBmihAlloc == crtAlloc) { 
		delete [] m_lpBMIH; 
	} 
	else if(m_nBmihAlloc == heapAlloc) { 
		::GlobalUnlock(m_hGlobal); 
		::GlobalFree(m_hGlobal); 
	} 
	if(m_nImageAlloc == crtAlloc) delete [] m_lpImage; 
	if(m_hPalette != NULL) ::DeleteObject(m_hPalette); 
	if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap); 
	m_nBmihAlloc = m_nImageAlloc = noAlloc; 
	m_hGlobal = NULL; 
	m_lpBMIH = NULL; 
	m_lpImage = NULL; 
	m_lpvColorTable = NULL; 
	m_nColorTableEntries = 0; 
	m_dwSizeImage = 0; 
	m_lpvFile = NULL; 
	m_hMap = NULL; 
	m_hFile = NULL; 
	m_hBitmap = NULL; 
	m_hPalette = NULL; 
} 
 
void CDib::DetachMapFile() 
{ 
	if(m_hFile == NULL) return; 
	::UnmapViewOfFile(m_lpvFile); 
	::CloseHandle(m_hMap); 
	::CloseHandle(m_hFile); 
	m_hFile = NULL; 
} 
 
BOOL CDib::DrawDib(CDC* pDC, CPoint origin, CSize size) 
{ 
    if (m_lpBMIH == NULL) return FALSE; 
    if (m_hPalette != NULL) { 
        ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE); 
    } 
    HDRAWDIB hdd = ::DrawDibOpen(); 
    CRect rect(origin, size); 
    pDC->LPtoDP(rect); // Convert DIB’s rectangle 
                       //  to MM_TEXT coordinates 
    rect -= pDC->GetViewportOrg(); 
    int nMapModeOld = pDC->SetMapMode(MM_TEXT); 
    ::DrawDibDraw(hdd, pDC->GetSafeHdc(), rect.left, rect.top, 
        rect.Width(), rect.Height(), m_lpBMIH, m_lpImage, 0, 0, 
        m_lpBMIH->biWidth, m_lpBMIH->biHeight, 0); 
    pDC->SetMapMode(nMapModeOld); 
    VERIFY(::DrawDibClose(hdd)); 
    return TRUE; 
}