Original Post
I'm trying to set up a quick app that will take a screenshot of each monitor, saving each one to a new file. I've tried it and while debugging, it saves the primary monitor's display fine, but the second monitor turns up the right size, but all grey. This is my first attempt at using EnumDisplayMonitors, and I was wondering if any of you could point me to where I was going wrong.
[source lang=cpp]
#include <windows.h>
#include <tchar.h>
#include <atlimage.h>
#include <string>
using namespace std;
void SaveBitmap(char *szFilename,HBITMAP hBitmap) {
HDC hdc=NULL;
FILE* fp=NULL;
LPVOID pBuf=NULL;
BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
do {
hdc=GetDC(NULL);
ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
if(bmpInfo.bmiHeader.biSizeImage<=0)
bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL){
MessageBox( NULL, "Unable to Allocate Bitmap Memory", "Error", MB_OK|MB_ICONERROR);
break;
}
bmpInfo.bmiHeader.biCompression=BI_RGB;
GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS);
if((fp = fopen(szFilename,"wb"))==NULL){
MessageBox( NULL, "Unable to Create Bitmap File", "Error", MB_OK|MB_ICONERROR);
break;
}
bmpFileHeader.bfReserved1=0;
bmpFileHeader.bfReserved2=0;
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType='MB';
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
}while(false);
if(hdc) ReleaseDC(NULL,hdc);
if(pBuf) free(pBuf);
if(fp) fclose(fp);
}
BOOL CALLBACK MyGrabEnumProc(
HMONITOR hMonitor, // handle to display monitor
HDC hdc1, // handle to monitor DC
LPRECT lprcMonitor, // monitor intersection rectangle
LPARAM data // data
) {
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;
HDC hMemDC = CreateCompatibleDC(hdc1);
nX = lprcMonitor->left;
nY = lprcMonitor->top;
nX2 = lprcMonitor->right;
nY2 = lprcMonitor->bottom; // get screen resolution
xScrn = GetDeviceCaps(hdc1, HORZRES);
yScrn = GetDeviceCaps(hdc1, VERTRES);
nWidth = nX2 - nX;
nHeight = nY2 - nY;
// create a bitmap compatible with the screen DC
hBitmap = CreateCompatibleBitmap(hdc1, nWidth, nHeight);
// select new bitmap into memory DC
hOldBitmap = SelectObject (hMemDC, hBitmap);
// bitblt screen DC to memory DC
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hdc1, 0, 0, SRCCOPY);
// Note: I also tried this as
//BitBlt(hMemDC, 0, 0, nWidth, nHeight, hdc1, nX, nY, SRCCOPY);
// as lprcMonitor is twice as wide the second time as it is the first time
// select old bitmap back into memory DC and get handle to
// bitmap of the screen
hBitmap = SelectObject(hMemDC, hOldBitmap);
// clean up
DeleteDC(hMemDC);
// save the bitmap
SaveBitmap("c:/file.bmp", (HBITMAP)hBitmap);
// Todo: save each monitor to new filename
return 1;
}
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR, int)
{
HDC hdc = GetDC(NULL);
EnumDisplayMonitors(hdc, NULL, (MONITORENUMPROC)MyGrabEnumProc, NULL);
ReleaseDC(NULL, hdc);
return 0;
}