windows7下无法正常使用GetDIBits获取整个屏幕的截图,但XP是可以的,求指点
LPBITMAPINFO ptBmi;
HWND DeskHwnd;
HDC DeskHDC,ComHDC;
HBITMAP hBmp = 0;
int sdwRet;
BITMAPINFO infoHeader;
memset(&infoHeader.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
infoHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
infoHeader.bmiHeader.biWidth = x;
infoHeader.bmiHeader.biHeight = -y;
infoHeader.bmiHeader.biPlanes = 1;
infoHeader.bmiHeader.biBitCount = 32;
infoHeader.bmiHeader.biCompression = BI_RGB;
/* 如果图像没有分配 */
if (pImg->imageData == NULL)
{
char *data = new char[x * y * pImg->nChannels];
cvSetData(pImg, data, pImg->widthStep);
}
//获取桌面窗口句柄
//DeskHwnd = GetDesktopWindow();
//获取桌面窗口DC
//DeskHDC = GetWindowDC(DeskHwnd);
//ComHDC = CreateCompatibleDC(DeskHDC);
DeskHDC = ::GetDC(0);
hBmp = (HBITMAP)GetCurrentObject(DeskHDC, 7);
sdwRet = GetDIBits(DeskHDC, hBmp, 0, y,
pImg->imageData, &infoHeader,
DIB_RGB_COLORS);
上面这段代码在XP上用的时候是可以成功完成对屏幕的截图和显示的,但是在Win7上,也能成功的获取到图像了,但是结果是一个历史的图像,我截图时候是11:13分了,结果我截图得到的图像是10:56分的图像,不知道为什么,截图多少次都是那张图。求指点
工口-SOL
10 years, 4 months ago
Answers
首先,你的代码中有几个小问题:
你的cvSetData函数用途不明,对于截屏这个目的来说应该没有用处。
计算所需内存的表达式x * y * pImg->nChannels,明显是错误的。Bmp格式要求每行扫描线的数据对齐到4个字节,应该不是你这里的计算方式。
infoHeader.bmiHeader.biBitCount = 32;比较浪费空间,建议改成24(实际效果是一样的)。
GetCurrentObject(DeskHDC, 7);为什么不用OBJ_BITMAP?
最后,你的调用方式并不符合MSDN中的规范,XP下刚好能工作,并不等于这就是正确的。给你一个我自己用的截屏函数作为例子吧:
struct BmpHead : public BITMAPINFOHEADER
{
BmpHead(int x, int y, WORD bits = 24);
BITMAPINFO * operator & () {return (BITMAPINFO*)this;}
};
BmpHead::BmpHead(int x, int y, WORD bits)
{
biSize = sizeof(BITMAPINFOHEADER);
biWidth = x;
biHeight = y;
biPlanes = 1;
biBitCount = bits;
biCompression = BI_RGB;
int LineBytes = ((x * biBitCount + 31) & -32) >> 3;
biSizeImage = LineBytes * y;
biXPelsPerMeter = biYPelsPerMeter = 0;
biClrUsed = biClrImportant = 0;
}
void *WINAPI TakeScreenShot(const RECT &rect, HWND hWnd = NULL)
{
HDC hdcWnd = NULL;
HDC hdcCap = NULL;
HBITMAP bmpCap = NULL;
void *pData = NULL;
do
{
int x = rect.right - rect.left;
int y = rect.bottom - rect.top;
BmpHead bmi(x, y);
hdcWnd = ::GetDC(hWnd);
if (hdcWnd == NULL) break;
hdcCap = ::CreateCompatibleDC(hdcWnd);
if (hdcCap == NULL) break;
bmpCap = ::CreateCompatibleBitmap(hdcWnd, x, y);
if (bmpCap == NULL) break;
HGDIOBJ bmOld = ::SelectObject(hdcCap, bmpCap);
if (bmOld == NULL) break;
BOOL bSuccess = ::BitBlt(hdcCap, 0, 0, x, y,
hdcWnd, rect.left, rect.top, SRCCOPY);
::SelectObject(hdcCap, bmOld);
if (!bSuccess) break;
pData = malloc(bmi.biSizeImage);
if (pData == NULL) break;
DWORD dwRet = ::GetDIBits(hdcWnd, bmpCap, 0, y,
pData, &bmi, DIB_RGB_COLORS);
if (dwRet == 0)
{
free(pData);
pData = NULL;
}
}while(false);
if (hdcCap != NULL) ::DeleteDC(hdcCap);
if (bmpCap != NULL) ::DeleteObject(bmpCap);
if (hdcWnd != NULL) ::ReleaseDC(hWnd, hdcWnd);
return pData;
}
堂本刚砸光
answered 10 years, 4 months ago