以下记录WIN32进行截屏的要点。可截取特定目标窗口,截取结果可显示到自定窗口的控件,或显示在屏幕。本示例为显示在屏幕右上角。
string mp_ws2s(const wstring& ws)
{
std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";
setlocale(LC_ALL, "chs");
const wchar_t* _Source = ws.c_str();
size_t _Dsize = 2 * ws.size() + 1;
char *_Dest = new char[_Dsize];
memset(_Dest,0,_Dsize);
wcstombs(_Dest,_Source,_Dsize);
std::string result = _Dest;
delete []_Dest;
setlocale(LC_ALL, curLocale.c_str());
return result;
}
wstring mp_s2ws(const string& s)
{
setlocale(LC_ALL, "chs");
const char* _Source = s.c_str();
size_t _Dsize = s.size() + 1;
wchar_t *_Dest = new wchar_t[_Dsize];
wmemset(_Dest, 0, _Dsize);
mbstowcs(_Dest,_Source,_Dsize);
std::wstring result = _Dest;
delete []_Dest;
setlocale(LC_ALL, "C");
return result;
}
//参数说明:
// hWndDisplay:截屏图片显示的窗口,可为自己窗口内的一个控件的窗口句柄,若为NULL,则在屏幕上进行显示
// hWndTarget:截屏目标窗口句柄
// iOriginX:截屏区域X坐标
// iOriginY:截屏区域Y坐标
// iWidth:截屏区域宽度
// iHeight:截屏区域高度
// strBmpFileName:截取后图片保存的文件名
// strMsg:错误信息
bool CaptureImage(HWND hWndDisplay,
HWND hWndTarget,
int iOriginX,
int iOriginY,
int iWidth,
int iHeight,
string strBmpFileName,
string& strMsg)
{
RECT rect;
HDC hdcScreen = NULL;
HDC hdcWindow = NULL;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
string strCaptureBmp = strBmpFileName;
wstring wsCaptureBmp = mp_s2ws(strCaptureBmp);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
int capX;
int capY;
bool bRet = false;
strMsg = "";
do
{
//获取屏幕宽度和高度
hdcScreen = GetDC(NULL);
capX = GetDeviceCaps(hdcScreen, HORZRES);
capY = GetDeviceCaps(hdcScreen, VERTRES);
ReleaseDC(NULL,hdcScreen);
if(cMyUtility::mp_isFileExists((char*)strCaptureBmp.c_str()))
{
DeleteFile(wsCaptureBmp.c_str());
}
GetWindowRect(hWndTarget,&rect);
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(hWndTarget);
if(hdcScreen == NULL)
{
strMsg = "GetDC(NULL) fail";
break;
}
//hwndDisplay = GetDlgItem(pTabWndInfo->hDlg,IDC_BUTTON_CAPTURE_IMG);
hWndDisplay = NULL;
hdcWindow = GetDC(hWndDisplay);
if(hdcWindow == NULL)
{
strMsg = "GetDC(hwndDisplay) fail";
break;
}
// Create a compatible DC, which is used in a BitBlt from the window DC.
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC)
{
strMsg = "CreateCompatibleDC fail";
break;
}
// 显示位置为屏幕右上角
RECT rcClient;
rcClient.left = capX-10-iWidth;
rcClient.top = 10;
rcClient.right = capX-10;
rcClient.bottom = iHeight+10;
// This is the best stretch mode.
SetStretchBltMode(hdcWindow, HALFTONE);
if (!StretchBlt(hdcWindow,
rcClient.left,
rcClient.top,
iWidth,
iHeight,
hdcScreen,
iOriginX,
iOriginY,
iWidth,
iHeight,
SRCCOPY))
{
strMsg = "StretchBlt fail";
break;
}
// Create a compatible bitmap from the Window DC.
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
if (!hbmScreen)
{
strMsg = "CreateCompatibleBitmap fail";
break;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC, hbmScreen);
// Bit block transfer into our compatible memory DC.
if (!BitBlt(hdcMemDC,
0,
0,
iWidth,
iHeight,
hdcWindow,
rcClient.left,
rcClient.top,
SRCCOPY))
{
strMsg = "BitBlt fail";
break;
}
// Get the BITMAP from the HBITMAP.
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
// Gets the "bits" from the bitmap, and copies them into a buffer
// that's pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
hFile = CreateFile(wsCaptureBmp.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
// Add the size of the headers to the size of the bitmap to get the total file size.
dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// Size of the file.
bmfHeader.bfSize = dwSizeofDIB;
// bfType must always be BM for Bitmaps.
bmfHeader.bfType = 0x4D42; // BM.
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
}
// Unlock and Free the DIB from the heap.
GlobalUnlock(hDIB);
GlobalFree(hDIB);
bRet = true;
}while(0);
if(hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
// Clean up.
if(hbmScreen)
{
DeleteObject(hbmScreen);
hbmScreen = NULL;
}
if(hdcMemDC)
{
DeleteObject(hdcMemDC);
hdcMemDC = NULL;
}
if(hdcScreen)
{
ReleaseDC(NULL,hdcScreen);
hdcScreen = NULL;
}
if(hdcWindow)
{
ReleaseDC(hWndDisplay,hdcWindow);
hdcWindow = NULL;
}
return bRet;
}