// 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;
}