c++ - C ++,Windows(有时)在获取应用程序屏幕截图时出现白屏
问题描述
我有一个应用程序功能,可以触发所述应用程序窗口的屏幕截图。
它是这样的:
void PlatformWindow::captureScreenshot()
{
WIN32Window *window = (WIN32Window*)&g_window;
if (window) {
HWND handle = window->getWindow();
if (handle){
RECT client_rect = { 0 };
GetClientRect(handle, &client_rect);
int width = client_rect.right - client_rect.left;
int height = client_rect.bottom - client_rect.top;
HDC hdcScreen = GetDC(handle);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height);
SelectObject(hdc, hbmp);
BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY);
BITMAPINFO bmp_info = { 0 };
bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
bmp_info.bmiHeader.biWidth = width;
bmp_info.bmiHeader.biHeight = height;
bmp_info.bmiHeader.biPlanes = 1;
bmp_info.bmiHeader.biBitCount = 24;
bmp_info.bmiHeader.biCompression = BI_RGB;
int bmp_padding = (width * 3) % 4;
if (bmp_padding != 0) bmp_padding = 4 - bmp_padding;
BYTE *bmp_pixels = new BYTE[(width * 3 + bmp_padding) * height];;
GetDIBits(hdc, hbmp, 0, height, bmp_pixels, &bmp_info, DIB_RGB_COLORS);
BITMAPFILEHEADER bmfHeader;
//Make screenshot name as a time
time_t currentTime = std::time(NULL);
std::ostringstream oss;
auto tm = *std::localtime(¤tTime);
oss << std::put_time(&tm, "%d-%m-%Y_%H-%M");
auto time_string = oss.str();
uint id = 0;
std::string name = "screens\\" + time_string +"_0.bmp";
//Loop over its indexes
while(true){
name = "screens\\" + time_string + "_" + std::to_string(id) +".bmp";
if (!file_exists(name)){
break;
}
id++;
}
LPSTR fileName = const_cast<char *>(name.c_str());
HANDLE bmp_file_handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = (width * 3 + bmp_padding) * height + 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
DWORD dwBytesWritten = 0;
WriteFile(bmp_file_handle, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(bmp_file_handle, (LPSTR)&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(bmp_file_handle, (LPSTR)bmp_pixels, (width * 3 + bmp_padding) * height, &dwBytesWritten, NULL);
//Close the handle for the file that was created
CloseHandle(bmp_file_handle);
DeleteDC(hdc);
DeleteObject(hbmp);
ReleaseDC(NULL, hdcScreen);
delete[] bmp_pixels;
}
}
}
它在多台机器(Windows 10、XP 等)上运行良好。但是,在 Windows 7 上存在一个罕见的情况(可能还有其他情况,我不知道这是否只是运气不好或其他原因)导致屏幕截图为空白。就是全白。我进行了一些诊断并且很方便,它可以肯定地捕获正确的窗口,但不知何故它不能很好地捕获像素。
我深入挖掘并发现,每当我在 windows -> 性能选项 -> “调整以获得最佳性能”中设置此选项时,它突然开始工作并且肯定会截取屏幕截图(不再有白屏,这很棒)。
我现在想知道的是,如果我能以某种方式让我的代码更好地掩盖这些情况,因为强制用户更改他的窗口选项并不是一个理想的场景。
@EDIT:我发现这是使它起作用的选项,如果我禁用桌面合成,它就可以正常工作。
解决方案
推荐阅读
- python - 如何根据 Dash 回调加载 Pandas DataFrame?
- java - 用于在春季从多个表中获取数据的自定义查询
- php - PHP - MySQL 服务器已经消失 - 总是发生在 1 个函数中?
- mysql - 导入 MySQL 数据库备份
- javascript - 如何隐藏“查找我的位置”按钮?
- c# - 自动调整“ListView”中图像的缩放以适合所有人,即在没有滚动条的情况下最大化它们的大小
- tabulator - 如何在 tabulator.js 中只选择空(或假)值
- reinforced-typings - Export class members as typescript string literal
- json - What's the best way to validate multiple JSON field dependencies?
- python - 我需要使用函数 python 交换矩阵中的元素