【发布时间】:2019-04-22 02:22:46
【问题描述】:
感谢 Nick Nougat 的回答 here 中的代码,我可以使用 BitBlt 和 GetDIBits 成功捕获部分屏幕。
捕获整个屏幕或桌面似乎可行,但是当我提供应用程序的 HDC 时,它会打印出奇怪的数据(bgra 格式)。
HWND dekstopHWND = GetDesktopWindow();
// prints correct desktop pixels
HWND appHWND = FindWindowA(NULL, "Hello World!"); // working handle of an electron app
//prints 0 0 0 0 as pixels
HWND appHWND = FindWindowA(NULL, "Untitled - Notepad"); // Notepad app
//prints 255 255 255 0 as pixels
...
- 函数
GetDeviceCaps表示电子应用支持BitBlt和 设备TECHNOLOGY是raster display。 - 应用 DC 的宽度始终为全屏,与窗口大小无关:
printf("width %d\n", GetDeviceCaps(GetDC(appHWND), HORZRES)); //1920,这是正确的行为吗?
我对 Windows API 非常陌生...steps 或函数中的哪一个可能导致此问题? 谢谢。
....
HBITMAP GetScreenBmp(HDC hdc) {
int nScreenWidth = 100;
int nScreenHeight = 100;
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteDC(hCaptureDC);
return hBitmap;
}
int main() {
HWND appHWND = FindWindowA(NULL, "Hello World!");
HDC hdc = GetDC(appHWND);
HBITMAP hBitmap = GetScreenBmp(hdc);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if (0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)){
cout << "error" << endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;
// get the actual bitmap buffer
if (0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
for (int i = 0; i < 100; i++) {
printf("%d\t", (int)lpPixels[i]);
}
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
return 0;
}
【问题讨论】:
-
请贴出所有相关代码。
-
记事本客户端窗口底行的前 25 个像素全为白色,这并不奇怪。你知道位图是自下而上的,对吧?
-
好的,我刚刚把记事本窗口做得很小,我得到了很多 (0,0,0,0) - 黑色透明和 (255,255,255,0) 白色透明像素...但是,一些正常像素以 255 作为 alpha 显示:(240,240,240,255) - 我怀疑这是滚动条。我想我应该检查一些界限......知道怎么做吗?
-
位图通常会忽略 Alpha 通道。只有一两个 API 调用可以使用它们。我当然不会对您从 DC 获得的值赋予任何意义。如果你想做边界检查,我会使用窗口客户区。
-
我认为你是对的。当我使用记事本句柄进行 1000x1000 屏幕捕获时,它会在没有应用程序顶部菜单的情况下绘制应用程序,其余部分为黑色。我想要的电子应用程序的屏幕截图完全是黑色的。我想我可能需要访问一些子“渲染”窗口...谢谢您的帮助:)