Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / MFC

Barry's Screen Capture

Rate me:
Please Sign up or sign in to vote.
3.74/5 (26 votes)
11 Jan 20034 min read 271.7K   14.5K   96  
An article showing methods of screen capture
// CapITView.cpp : implementation of the CCapITView class
//

#include "stdafx.h"
#include "CapIT.h"

#include "CapITDoc.h"
#include "CapITView.h"

#include "MainFrm.h"


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

int FAR PASCAL GetMessageFunc (int nCode, WPARAM wParam, LPARAM lParam );


int hCurMsg = WH_MOUSE; //WH_GETMESSAGE;
HWND ghWnd;
HHOOK ghhk;

int gCurrentX = 0;
int gCurrentY = 0;

BOOL        gbStartUp=TRUE;
CBitmap*    gcBitmap;
HDC         gHDC=NULL;

BOOL bColorCoding = TRUE;
BOOL bCapturingControl = FALSE;
BOOL bScreenCapture = FALSE;
BOOL bCapturingWindow = FALSE; 
BOOL bCapturingClient = FALSE;

BOOL        gbTrackCodes = FALSE;
BOOL        gbTrackPosition = FALSE;

/////////////////////////////////////////////////////////////////////////////
// CCapITView

IMPLEMENT_DYNCREATE(CCapITView, CScrollView)

BEGIN_MESSAGE_MAP(CCapITView, CScrollView)
	//{{AFX_MSG_MAP(CCapITView)
	ON_WM_CAPTURECHANGED()
	ON_WM_DESTROY()
	ON_COMMAND(ID_SAVE_FILE, OnSaveFile)
	ON_UPDATE_COMMAND_UI(ID_SAVE_FILE, OnUpdateSaveFile)
	ON_COMMAND(ID_COLORCODE, OnColorcode)
	ON_UPDATE_COMMAND_UI(ID_COLORCODE, OnUpdateColorcode)
	ON_COMMAND(ID_TRACKPOS, OnTrackpos)
	ON_UPDATE_COMMAND_UI(ID_TRACKPOS, OnUpdateTrackpos)

	ON_COMMAND(ID_CLEAR, OnClear)
	ON_UPDATE_COMMAND_UI(ID_CLEAR, OnUpdateClear)

	ON_COMMAND(ID_HIDE , OnHideWindow)

	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCapITView construction/destruction

CCapITView::CCapITView()
{
	// TODO: add construction code here
	gbDrawImage = 
	gbIsCaptured = 
	gbNewRect = 
	gbIsMarking = 
	gbCaptureMode = FALSE;
	m_bHookSetup = FALSE;
//	gMainWnd = NULL;
}

CCapITView::~CCapITView()
{
}

BOOL CCapITView::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style |= WS_HSCROLL | WS_VSCROLL;
	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CCapITView drawing

void CCapITView::OnDraw(CDC* pDC)
{


	if(gbDrawImage)
	{
		// Fill in src/dest rectangle with width and height
	    // of captured bitmap 

		CRect  rect;
		GetClientRect(&rect);
        // Paint the captured bitmap in the client area 
//		if(!gbStartUp)
			PaintBitmap( pDC->m_hDC , &rect, ghBitmap, &rect, NULL); 
//		gbDrawImage = FALSE;
	}

}

void CCapITView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	sizeTotal.cx = 400;
	sizeTotal.cy = 200;
	SetScrollSizes(MM_TEXT, sizeTotal);

	gMainWnd = AfxGetMainWnd();
}

/////////////////////////////////////////////////////////////////////////////
// CCapITView printing

BOOL CCapITView::OnPreparePrinting(CPrintInfo* pInfo)
{
	return DoPreparePrinting(pInfo);
}

void CCapITView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{

}

void CCapITView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{

}

/////////////////////////////////////////////////////////////////////////////
// CCapITView diagnostics

#ifdef _DEBUG
void CCapITView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CCapITView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CCapITDoc* CCapITView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCapITDoc)));
	return (CCapITDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CCapITView message handlers


void CCapITView::OnDestroy() 
{
	CScrollView::OnDestroy();
	
	if(ghhk)
		::UnhookWindowsHookEx(ghhk);

    if (ghBitmap) 
       DeleteObject(ghBitmap); 
    if (ghPal) 
       DeleteObject(ghPal); 

}

void CCapITView::OnHideWindow()
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();
	frame->ShowWindow(SW_HIDE);
}


void CCapITView::OnClear()
{
	ClearCapture();
}

void CCapITView::OnUpdateClear(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(gbIsCaptured);	
}

void CCapITView::ClearCapture() 
{

	if(ghhk)
		::UnhookWindowsHookEx(ghhk);

	bColorCoding = TRUE;

	gbIsCaptured = FALSE;	
	ghBitmap = NULL;
	CRect rect;
	GetClientRect(&rect);
	InvalidateRect(rect,TRUE);
	gbTrackCodes = FALSE;
	gbTrackPosition = FALSE;
	UpdateStatusbar(0, gbTrackCodes , gbTrackPosition);
	UpdateCaptureStatus(FALSE);
}

void CCapITView::UpdateCaptureStatus(BOOL bCaptured)
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();
	frame->g_mbImageCaptured = bCaptured;
}

void CCapITView::CaptureClient() 
{
	AfxMessageBox("Click on Client Area to be captured");
	bCapturingClient = TRUE;
	gbStartUp = FALSE;
	SetCapture();
}

void CCapITView::CaptureControl() 
{
	AfxMessageBox("Click on CONTROL to be captured");
	bCapturingControl = TRUE;
	SetCapture();
	gbStartUp=FALSE;
}

void CCapITView::CaptureDesktop()
{
	WindowCapture(GetDesktopWindow()->m_hWnd);
	gbIsCaptured = TRUE;
}

void CCapITView::CaptureWindow() 
{
	AfxMessageBox("Click on Window to be captured");
	bCapturingWindow = TRUE;
	SetCapture();
	gbStartUp = FALSE;
}

void CCapITView::WindowCapture(HWND wnd)
{

	HBITMAP hBitmap = CopyWindowToBitmap(this , wnd, 1);

    HPALETTE hPal = NULL;
    if (hBitmap) 
	{
//       hPal = GetSystemPalette(); 
	   ghBitmap = hBitmap;
       gbDrawImage = TRUE;
	   gbIsCaptured = TRUE;
	   CRect rect;
	   GetClientRect(&rect);
	   InvalidateRect(rect);
	   CCapITDoc* pDoc = GetDocument();
	   DoSize(FromHandle(this->m_hWnd) ,hBitmap);

	   UpdateCaptureStatus(TRUE);

    }
    else 
	{	
		gbIsCaptured = FALSE;
		hPal = NULL; 

	   AfxMessageBox("Sorry !!!!");
	}
}

void CCapITView::OnCaptureChanged(CWnd *pWnd) 
{

	if(gbStartUp)
		return;

	CPoint point;
    VERIFY(GetCursorPos(&point));
	ScreenToClient(&point);
	ClientToScreen(&point);
	CWnd* wnd = WindowFromPoint(point);    	

	if(wnd)
	{
		if(IsChild(wnd))
		{
			WindowCapture(wnd->GetParent()->m_hWnd);
		}
		else
		{
			if(!gbIsCaptured)
			{
				if(bCapturingClient)
				{
					CaptureClientArea(wnd);
					bCapturingClient = FALSE;
				}
				if(bCapturingWindow)
				{
					WindowCapture(wnd->GetTopLevelParent()->m_hWnd);
					bCapturingWindow = FALSE;

				}
				if(bCapturingControl)
				{
					WindowCapture(wnd->GetTopLevelOwner()->m_hWnd);
					bCapturingControl = FALSE;
				}
				gbIsCaptured = TRUE;
				UpdateCaptureStatus(TRUE);

			}	
		}
	}

	ReleaseCapture();

	CScrollView::OnCaptureChanged(pWnd);
}

void CCapITView::CaptureClientArea(CWnd* wnd)
{
	WindowCapture(wnd->m_hWnd);
	return;
}

void CCapITView::OnSaveFile() 
{

   BOOL bOpen = FALSE;
   char bigBuff[2048] = "";  // maximum common dialog buffer size
   char szFilter[] =
      "BMP Files (*.BMP)|*.bmp|*.bmp|All Files (*.*)|*.*|||";
   CFileDialog dlg(bOpen, NULL, NULL,
      OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT, szFilter);

   dlg.m_ofn.lpstrFile = bigBuff;
   dlg.m_ofn.nMaxFile = sizeof(bigBuff);

   dlg.DoModal();
   
   if(dlg.m_ofn.lpstrFile != "")
   {
		HPALETTE hPal = NULL;
        hPal = GetSystemPalette(this->m_hWnd); 
		if(!hPal)
		{
			AfxMessageBox("Error getting System Palette");
			return;
		}
		DWORD   dwFlags = NULL;
		DWORD   dCompression = BI_RLE8; // / BI_RLE4 / BI_RGB;

		HANDLE hDIB = ChangeBitmapFormat(ghBitmap, 
			                                   HIWORD(dwFlags),                  
											   dCompression, 
											   hPal , 
											   this->m_hWnd);

		SaveDIB(hDIB, dlg.m_ofn.lpstrFile);
		hPal = NULL;
   }	
}

void CCapITView::OnUpdateSaveFile(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(gbIsCaptured);	
}

void CCapITView::OnColorcode() 
{

	if(!m_bHookSetup)	
		SetupHookProc();

	bColorCoding = FALSE;
	gbTrackCodes = TRUE;
}

void CCapITView::OnUpdateColorcode(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable((gbIsCaptured) && (bColorCoding));
}

int FAR PASCAL GetMessageFunc (int nCode, WPARAM wParam, LPARAM lParam )
{

   LPMOUSEHOOKSTRUCT MouseHookParam;

   if ( nCode >= 0 ) 
   {

	  MouseHookParam = (MOUSEHOOKSTRUCT *) lParam;
	  gCurrentX = MouseHookParam->pt.x;
	  gCurrentY = MouseHookParam->pt.y;

	  CPoint point;
	  HWND wnd;

	  GetCursorPos(&point);
	  wnd = WindowFromPoint(point);
	  HDC hdc = ::GetDC(wnd); 
	  COLORREF cr = GetPixel(hdc, point.x , point.y);
      CCapITView::UpdateStatusbar(cr , gbTrackCodes , gbTrackPosition);

   }
   return CallNextHookEx(ghhk, hCurMsg, wParam , lParam);
}

void CCapITView::UpdateStatusbar(COLORREF cr , BOOL bShowCodes, BOOL bShowPosition)
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();

	frame->m_bShowCodes = bShowCodes;
	frame->m_iBlueCode = GetBValue(cr);
	frame->m_iGreenCode = GetGValue(cr);
	frame->m_iRedCode= GetRValue(cr);

	frame->m_bShowPosition = bShowPosition;
	frame->m_iPosX = gCurrentX;
	frame->m_iPosY = gCurrentY;

}

void CCapITView::OnTrackpos() 
{
	if(!m_bHookSetup)	
		SetupHookProc();

	gbTrackPosition = TRUE;	
}

void CCapITView::OnUpdateTrackpos(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable((gbIsCaptured) && (!gbTrackPosition));	
}

void CCapITView::SetupHookProc()
{
	ghWnd = this->m_hWnd;
    FARPROC lpMsgFilterProc = (FARPROC)MakeProcInstance((FARPROC)GetMessageFunc, hInst);
    ghhk = SetWindowsHookEx(hCurMsg, (HOOKPROC)lpMsgFilterProc, NULL,
            GetCurrentThreadId());
	m_bHookSetup = TRUE;
}




/******************************************************************************
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993-1997 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
******************************************************************************/

HBITMAP CCapITView::CopyWindowToBitmap(CWnd* wnd , HWND hWnd, WORD fPrintArea)
{
	HBITMAP     hBitmap = NULL;  // handle to device-dependent bitmap      
	// check for a valid window handle      
	if (!hWnd)         
	    return NULL; 

    RECT    rectWnd; 
  ::GetWindowRect(hWnd, &rectWnd);  
	

	switch (fPrintArea)     
	{         
		case PW_WINDOW: // copy entire window         
		{             
          // get the window rectangle              
          // get the bitmap of that window by calling             
		  // CopyScreenToBitmap and passing it the window rect                     
//		  GetWindowRect(&rectWnd);
          hBitmap = CopyScreenToBitmap(&rectWnd);             
		  break;         
		}   
       case PW_CLIENT: // copy client area         
	   {             
	     RECT rectClient;             
	     POINT pt1, pt2;              // get client dimensions              
	     wnd->GetClientRect(&rectClient);              // convert client coords to screen coords              
	     pt1.x = rectClient.left;             
	     pt1.y = rectClient.top;             
	     pt2.x = rectClient.right;             
	     pt2.y = rectClient.bottom;             
	     wnd->ClientToScreen(&pt1);             
	     wnd->ClientToScreen(&pt2);             
	     rectClient.left = pt1.x;             
	     rectClient.top = pt1.y;             
	     rectClient.right = pt2.x;             
	     rectClient.bottom = pt2.y;  

         // get the bitmap of the client area by calling             
	     // CopyScreenToBitmap and passing it the client rect                          
	     hBitmap = CopyScreenToBitmap(&rectClient);             
	     break;         
	   }              
	   default:    // invalid print area             
	        return NULL;     
	}      // return handle to the bitmap     
	
	return hBitmap; 
}

HBITMAP CCapITView::CopyScreenToBitmap(LPRECT lpRect)
{
	HDC         hScrDC, hMemDC;         // screen DC and memory DC     
//	HBITMAP     hBitmap; //, 
//	HBITMAP     hBitmap;
//	HBITMAP     hOldBitmap;    // handles to deice-dependent bitmaps     
	int         nX, nY, nX2, nY2;       // coordinates of rectangle to grab     
	int         nWidth, nHeight;        // DIB width and height     
	int         xScrn, yScrn;           // screen resolution      

	HGDIOBJ     hOldBitmap , hBitmap;
		
		// check for an empty rectangle 
    if (IsRectEmpty(lpRect))       
	   return NULL;      
	   // create a DC for the screen and create     
	   // a memory DC compatible to screen DC          

   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);     
   hMemDC = CreateCompatibleDC(hScrDC);      // get points of rectangle to grab  
   
   nX = lpRect->left;     
   nY = lpRect->top;     
   nX2 = lpRect->right;     
   nY2 = lpRect->bottom;      // get screen resolution      
   
   xScrn = GetDeviceCaps(hScrDC, HORZRES);     
   yScrn = GetDeviceCaps(hScrDC, VERTRES);      
   
   //make sure bitmap rectangle is visible      
   
   if (nX < 0)         
	  nX = 0;     
   
   if (nY < 0)         
      nY = 0;     
   
   if (nX2 > xScrn)         
      nX2 = xScrn;     
   
   if (nY2 > yScrn)         
      nY2 = yScrn;      

   nWidth = nX2 - nX;     
   nHeight = nY2 - nY;      
   
   // create a bitmap compatible with the screen DC     
   
   hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);      
   
   // select new bitmap into memory DC     
   
   hOldBitmap =   SelectObject (hMemDC, hBitmap);      
   
   // bitblt screen DC to memory DC     
   
   BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);     
   
   // select old bitmap back into memory DC and get handle to     
   // bitmap of the screen          
   
   hBitmap = SelectObject(hMemDC, hOldBitmap);      
   
   // clean up      
   
   DeleteDC(hScrDC);     
   DeleteDC(hMemDC);      
   
   // return handle to the bitmap      
   
   return (HBITMAP)hBitmap; 

}

BOOL CCapITView::PaintBitmap(HDC hDC, LPRECT lpDCRect, HBITMAP hDDB, LPRECT lpDDBRect, HPALETTE hPal)
{
    HDC         hMemDC;            // Handle to memory DC 
//    HBITMAP     hOldBitmap;        // Handle to previous bitmap 
    HPALETTE    hOldPal1 = NULL;   // Handle to previous palette 
    HPALETTE    hOldPal2 = NULL;   // Handle to previous palette 
    BOOL        bSuccess = FALSE;  // Success/fail flag 
	HGDIOBJ hOldBitmap;
    // Create a memory DC 
 
    hMemDC = CreateCompatibleDC (hDC); 
 
    // If this failed, return FALSE 
 
    if (!hMemDC) 
        return FALSE; 
 
    // If we have a palette, select and realize it 
 
    if (hPal) 
    { 
        hOldPal1 = SelectPalette(hMemDC, hPal, TRUE); 
        hOldPal2 = SelectPalette(hDC, hPal, FALSE); //TRUE); 
        RealizePalette(hDC); 
    } 
 
    // Select bitmap into the memory DC 
 
    hOldBitmap = SelectObject (hMemDC, hDDB); 

    // Make sure to use the stretching mode best for color pictures 
 
    SetStretchBltMode (hDC, COLORONCOLOR); 
	
    // Determine whether to call StretchBlt() or BitBlt() 
    if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDDBRect)) && 
            (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDDBRect))) 
        bSuccess = BitBlt(hDC, lpDCRect->left, lpDCRect->top, 
                lpDCRect->right - lpDCRect->left, 
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left, 
                lpDDBRect->top, SRCCOPY); 
    else 
        bSuccess = StretchBlt(hDC, lpDCRect->left,  lpDCRect->top,  
                lpDCRect->right - lpDCRect->left, 
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left,  
                lpDDBRect->top,  lpDDBRect->right - lpDDBRect->left, 
                lpDDBRect->bottom - lpDDBRect->top, SRCCOPY); 
 
    // Clean up 
 
    SelectObject(hMemDC, hOldBitmap); 
 
    if (hOldPal1) 
        SelectPalette (hMemDC, hOldPal1, FALSE); 
 
    if (hOldPal2) 
        SelectPalette (hDC, hOldPal2, FALSE); 
 
    DeleteDC (hMemDC); 
 
    // Return with success/fail flag 
 
    return bSuccess; 
}


void CCapITView::DoSize(CWnd* wnd , HBITMAP ghBitmap)
{
    BITMAP      bm;                     // Bitmap info structure 
    int         cxBitmap=0, cyBitmap=0; // Bitmap width and height 
    int         cxScroll, cyScroll;     // Scroll positions 
    RECT        rect;                   // Client rectangle 
 
    // repaint if displaying bitmap 
 
    if (ghBitmap) 
    { 
        // Get info about bitmap 
 
        GetObject(ghBitmap, sizeof(BITMAP), (LPSTR)&bm); 
 
        // Get the width and height of the bitmap 

//		CSize sizeTotal;
		// TODO: calculate the total size of this view
//		sizeTotal.cx = bm.bmWidth;
//		sizeTotal.cy = bm.bmHeight;
//		SetScrollSizes(MM_TEXT, sizeTotal);		

        cxBitmap = bm.bmWidth; 
        cyBitmap = bm.bmHeight; 
 
        // Find out the dimensions of the window, and the current thumb 
        // positions 
 
        wnd->GetClientRect(&rect); 
 
        cxScroll = wnd->GetScrollPos (SB_HORZ); 
        cyScroll = wnd->GetScrollPos (SB_VERT); 
 
        // If current thumb positions would cause blank space 
        // at right or bottom of client area, repaint 
 
        if (cxScroll + rect.right > cxBitmap || 
                cyScroll + rect.bottom > cyBitmap) 
            wnd->InvalidateRect(NULL, FALSE); 
 
        // Make sure scroll bars are updated 
 
        SetupScrollBars(wnd , (WORD)cxBitmap, (WORD)cyBitmap); 
    } 
    else //if (bStartup) 
        wnd->InvalidateRect(NULL, TRUE); 
}

void CCapITView::SetupScrollBars(CWnd* wnd , WORD cxBitmap, WORD cyBitmap)
{
    RECT        rect;                       // Client Rectangle 
    BOOL        bNeedScrollBars=FALSE;      // Need Scroll bars? 
    unsigned    cxWindow, cyWindow;         // Width and height of client area 
    int         cxRange=0, cyRange=0;       // Range needed for horz and vert 
 
    // Do some initialization 
 
    ReallyGetClientRect(wnd , &rect); 
 
    cxWindow = rect.right - rect.left; 
    cyWindow = rect.bottom - rect.top; 
 
    // Now determine if we need the scroll bars 
 
    if ((cxWindow < (unsigned)cxBitmap) || (cyWindow < (unsigned)cyBitmap)) 
        bNeedScrollBars = TRUE; 
 
 
    // Setup the scroll bar ranges.  We want to be able to 
    // scroll the window so that all the bitmap can appear 
    // within the client area.  Take into account that 
    // if the opposite scroll bar is activated, it eats 
    // up some client area. 
 
    if (bNeedScrollBars) 
    { 
        cyRange = (unsigned)cyBitmap - cyWindow - 1 + 
                GetSystemMetrics (SM_CYHSCROLL); 
        cxRange = (unsigned)cxBitmap - cxWindow - 1 + 
                GetSystemMetrics (SM_CXVSCROLL); 
    } 
 
    // Set the ranges we've calculated (0 to 0 means invisible scrollbar) 
 
    wnd->SetScrollRange(SB_VERT, 0, cyRange, TRUE); 
    wnd->SetScrollRange(SB_HORZ, 0, cxRange, TRUE); 
}


void CCapITView::ReallyGetClientRect(CWnd* wnd , LPRECT lpRect)
{
    DWORD   dwWinStyle; 
 
    dwWinStyle = GetWindowLong (wnd->m_hWnd, GWL_STYLE); 
 
    wnd->GetClientRect (lpRect); 
 
    if (dwWinStyle & WS_HSCROLL) 
        lpRect->bottom += (GetSystemMetrics (SM_CYHSCROLL) - 1); 
 
    if (dwWinStyle & WS_VSCROLL) 
        lpRect->right  += (GetSystemMetrics (SM_CXVSCROLL) - 1); 
 
}

WORD CCapITView::SaveDIB(HDIB hDib, LPSTR lpFileName)
{
	BITMAPFILEHEADER    bmfHdr;     // Header for Bitmap file     
	LPBITMAPINFOHEADER  lpBI;       // Pointer to DIB info structure     
	HANDLE              fh;         // file handle for opened file     
	DWORD               dwDIBSize;     
	DWORD               dwWritten;      
	if (!hDib)         
		return ERR_INVALIDHANDLE;  
	
   fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);      
   
   if (fh == INVALID_HANDLE_VALUE)         
		return ERR_OPEN;      
   // Get a pointer to the DIB memory, the first of which contains     
   // a BITMAPINFO structure      
   lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);     
   if (!lpBI)     
   {         
		CloseHandle(fh);         
		return ERR_LOCK;     
	}     
	// Check to see if we're dealing with an OS/2 DIB.  If so, don't     
	// save it because our functions aren't written to deal with these     
	// DIBs.  
   if (lpBI->biSize != sizeof(BITMAPINFOHEADER))     
   {         
		GlobalUnlock(hDib);         
		CloseHandle(fh);         
		return ERR_NOT_DIB;     
	}      
	// Fill in the fields of the file header      
	// Fill in file type (first 2 bytes must be "BM" for a bitmap)      
	bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM" 

 dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);        
 // Now calculate the size of the image      
 // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage     
 // field      
 
 if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))         
  dwDIBSize += lpBI->biSizeImage;     
 else     
 {         
  DWORD dwBmBitsSize;  
  // Size of Bitmap Bits only          
  // It's not RLE, so size is Width (DWORD aligned) * Height          
  dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;          
  dwDIBSize += dwBmBitsSize;          
  // Now, since we have calculated the correct size, why don't we         
  // fill in the biSizeImage field (this will fix any .BMP files which          
  // have this field incorrect).          
  lpBI->biSizeImage = dwBmBitsSize;     
 }       
 
  // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)                         
  bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);     
  bmfHdr.bfReserved1 = 0;     
  bmfHdr.bfReserved2 = 0;      
 
  // Now, calculate the offset the actual bitmap bits will be in     
  // the file -- It's the Bitmap file header plus the DIB header,     
  // plus the size of the color table.          
 
 bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +             PaletteSize((LPSTR)lpBI);      
 
 // Write the file header      
 
 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);      
 
 // Write the DIB header and the bits -- use local version of     
  // MyWrite, so we can write more than 32767 bytes of data          
 
 WriteFile(fh, (LPSTR)lpBI, dwDIBSize, &dwWritten, NULL);      
 GlobalUnlock(hDib);     
 CloseHandle(fh);      
 
 if (dwWritten == 0)         
  return ERR_OPEN; 
 
 // oops, something happened in the write     
  else         
  return 0; // Success code 
 
}

WORD CCapITView::PaletteSize (VOID FAR * pv) 
{     
	LPBITMAPINFOHEADER lpbi;     
	WORD NumColors;      
	lpbi      = (LPBITMAPINFOHEADER)pv;     
	NumColors = DibNumColors(lpbi);      
	if (lpbi->biSize == sizeof(BITMAPCOREHEADER))         
		return NumColors * sizeof(RGBTRIPLE);     
	else         
		return NumColors * sizeof(RGBQUAD); 
} 

WORD CCapITView::DibNumColors (VOID FAR * pv)
{     
	int bits;     
	LPBITMAPINFOHEADER lpbi;     
	LPBITMAPCOREHEADER lpbc;      
	lpbi = ((LPBITMAPINFOHEADER)pv);     
	lpbc = ((LPBITMAPCOREHEADER)pv);      
	
	/*  With the BITMAPINFO format headers, the size of the palette      
	*  is in biClrUsed, whereas in the BITMAPCORE - style headers, it      
	*  is dependent on the bits per pixel ( = 2 raised to the power of      
	*  bits/pixel).      
	*/     
	
	if (lpbi->biSize != sizeof(BITMAPCOREHEADER))     
	{         
		if (lpbi->biClrUsed != 0)             
			return (WORD)lpbi->biClrUsed;         
	
		bits = lpbi->biBitCount;     
	}     
	else         
		bits = lpbc->bcBitCount;      
	
	switch (bits)     
	{     
		case 1:         
			return 2;     
		case 4:         

			return 16;     
		case 8:         
			return 256;     
		default:         
			//  A 24 bitcount DIB has no color table          
			return 0;     

	} 

	
} 

HDIB CCapITView::ChangeBitmapFormat(HBITMAP hBitmap, 
								   WORD wBitCount, 
								   DWORD dwCompression, 
                                   HPALETTE hPal,
								   HWND hwnd) 
{ 
    HDC                hDC;          // Screen DC 
    HDIB               hNewDIB=NULL; // Handle to new DIB 
    BITMAP             Bitmap;       // BITMAP data structure 
    BITMAPINFOHEADER   bi;           // Bitmap info. header 
    LPBITMAPINFOHEADER lpbi;         // Pointer to bitmap header 
    HPALETTE           hOldPal=NULL; // Handle to palette 
    WORD               NewBPP;       // New bits per pixel 
    DWORD              NewComp;      // New compression format 
 
    // Check for a valid bitmap handle 
 
    if (!hBitmap) 
        return NULL; 
 
    // Validate wBitCount and dwCompression 
    // They must match correctly (i.e., BI_RLE4 and 4 BPP or 
    // BI_RLE8 and 8BPP, etc.) or we return failure 
     
    if (wBitCount == 0) 
    { 
        NewComp = dwCompression; 
        if (NewComp == BI_RLE4) 
            NewBPP = 4; 
        else if (NewComp == BI_RLE8) 
            NewBPP = 8; 
        else // Not enough info */ 
            return NULL; 
    } 
    else if (wBitCount == 1 && dwCompression == BI_RGB) 
    { 
        NewBPP = wBitCount; 
        NewComp = BI_RGB; 
    } 
    else if (wBitCount == 4) 
    { 
        NewBPP = wBitCount; 
        if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 
            NewComp = dwCompression; 
        else 
            return NULL; 
    } 
    else if (wBitCount == 8) 
    { 
        NewBPP = wBitCount; 
        if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 
            NewComp = dwCompression; 
        else 
            return NULL; 
    } 
    else if (wBitCount == 24 && dwCompression == BI_RGB) 
    { 
        NewBPP = wBitCount; 
        NewComp = BI_RGB; 
    } 
    else 
        return NULL; 
 
    // Get info about the bitmap 
 
    GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 
 
    // Fill in the BITMAPINFOHEADER appropriately 
 
    bi.biSize               = sizeof(BITMAPINFOHEADER); 
    bi.biWidth              = Bitmap.bmWidth; 
    bi.biHeight             = Bitmap.bmHeight; 
    bi.biPlanes             = 1; 
    bi.biBitCount           = NewBPP; 
    bi.biCompression        = NewComp; 
    bi.biSizeImage          = 0; 
    bi.biXPelsPerMeter      = 0; 
    bi.biYPelsPerMeter      = 0; 
    bi.biClrUsed            = 0; 
    bi.biClrImportant       = 0; 
 
    // Go allocate room for the new DIB 
 
    hNewDIB = AllocRoomForDIB(bi, hBitmap , hwnd); 
    if (!hNewDIB) 
        return NULL; 
 
    // Get a pointer to the new DIB 
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 
 
    // If we have a palette, get a DC and select/realize it 
 
    if (hPal) 
    { 
 		hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
        hOldPal = SelectPalette(hDC, hPal, FALSE); 
        RealizePalette(hDC); 
    } 
 
    // Call GetDIBits and get the new DIB bits 
 
    if (!GetDIBits(hDC, hBitmap, 0, (UINT) lpbi->biHeight, (LPSTR)lpbi + 
            (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 
            DIB_RGB_COLORS)) 
    { 
        GlobalUnlock(hNewDIB); 
        GlobalFree(hNewDIB); 
        hNewDIB = NULL; 
    } 
 
    // Clean up and return 
 
    if (hOldPal) 
    { 
        SelectPalette(hDC, hOldPal, TRUE); 
        RealizePalette(hDC); 
		::ReleaseDC(hwnd, hDC);
     } 
 
    // Unlock the new DIB's memory block 
 
    if (hNewDIB) 
        GlobalUnlock(hNewDIB); 
 
    return hNewDIB; 
}
 
HANDLE CCapITView::AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap , HWND hwnd) 
{ 
    DWORD               dwLen; 
    HANDLE              hDIB; 
    HDC                 hDC; 
    LPBITMAPINFOHEADER  lpbi; 
    HANDLE              hTemp; 
 
    // Figure out the size needed to hold the BITMAPINFO structure 
    // (which includes the BITMAPINFOHEADER and the color table). 
 
    dwLen = bi.biSize + PaletteSize((LPSTR) &bi); 
    hDIB  = GlobalAlloc(GHND,dwLen); 
 
    // Check that DIB handle is valid 
 
    if (!hDIB) 
        return NULL; 
 
    // Set up the BITMAPINFOHEADER in the newly allocated global memory, 
    // then call GetDIBits() with lpBits = NULL to have it fill in the 
    // biSizeImage field for us. 
 
    lpbi  = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
    *lpbi = bi; 
 
    hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
 
    GetDIBits(hDC, hBitmap, 0, (UINT) bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 
            DIB_RGB_COLORS); 
 	::ReleaseDC(hwnd, hDC);
 
 
    // If the driver did not fill in the biSizeImage field, 
    // fill it in -- NOTE: this is a bug in the driver! 
     
    if (lpbi->biSizeImage == 0) 
        lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * 
                lpbi->biBitCount) * lpbi->biHeight; 
 
    // Get the size of the memory block we need 
 
    dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage; 
 
    // Unlock the memory block 
 
    GlobalUnlock(hDIB); 
 
    // ReAlloc the buffer big enough to hold all the bits  
 
    if (hTemp = GlobalReAlloc(hDIB,dwLen,0)) 
        return hTemp; 
    else 
    { 
        // Else free memory block and return failure 
 
        GlobalFree(hDIB); 
        return NULL; 
    } 
} 
 
HPALETTE CCapITView::GetSystemPalette(HWND hwnd) 
{ 
    HDC hDC;                // handle to a DC 
    static HPALETTE hPal = NULL;   // handle to a palette 
    HANDLE hLogPal;         // handle to a logical palette 
    LPLOGPALETTE lpLogPal;  // pointer to a logical palette 
    int nColors;            // number of colors 
 
    // Find out how many palette entries we want. 

    hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
 
    if (!hDC) 
        return NULL; 
	 
    nColors = 256; //PalEntriesOnDevice(hDC);   // Number of palette entries 
 
    // Allocate room for the palette and lock it. 
 
    hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * 
            sizeof(PALETTEENTRY)); 
 
    // if we didn't get a logical palette, return NULL 
 
    if (!hLogPal) 
        return NULL; 
 
    // get a pointer to the logical palette 
 
    lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 
 
    // set some important fields 
 
    lpLogPal->palVersion = 0x300; //PALVERSION; 
    lpLogPal->palNumEntries = nColors; 
 
    // Copy the current system palette into our logical palette 
 
    GetSystemPaletteEntries(hDC, 0, nColors, 
            (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 
 
    // Go ahead and create the palette.  Once it's created, 
    // we no longer need the LOGPALETTE, so free it.     
 
    hPal = CreatePalette(lpLogPal); 
 
    // clean up 
 
    GlobalUnlock(hLogPal); 
    GlobalFree(hLogPal); 
	::ReleaseDC(hwnd, hDC);
 
    return hPal; 
} 

int CCapITView::PalEntriesOnDevice(HDC hDC) 
{     
	int nColors;  // number of colors      
	// Find out the number of colors on this device.          
	nColors = (1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)));
	ASSERT(nColors);     
	return nColors; 
}  

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
India India
Nothing to boast about

Comments and Discussions