问题描述
我正在尝试在 Windows 中截取整页屏幕截图。函数在第一次调用时工作,但在第二次调用后根本不起作用,它只是得到一个大小稳定的黑屏图像。 当我使用调试器时,该功能运行良好,不会出现黑屏。
代码如下:
void screenshot(std::string imageaPath)
{
ULONG_PTR gdiplustoken;
Gdiplus::GdiplusstartupInput gdistartupinput;
Gdiplus::GdiplusstartupOutput gdistartupoutput;
gdistartupinput.SuppressBackgroundThread = true;
Gdiplusstartup(&gdiplustoken,&gdistartupinput,&gdistartupoutput); //start GDI+
HDC hScreenDC = GetDC(GetDesktopWindow());
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int cx = GetSystemMetrics(SM_cxvIRTUALSCREEN);
int cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
HBITMAP hbitmap = CreateCompatibleBitmap(hScreenDC,cx,cy);
HBITMAP holdbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hbitmap));
BitBlt(hMemoryDC,cy,hScreenDC,x,y,SRCcopY | CAPTUREBLT);
hbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,holdbitmap));
UINT num,size;
Gdiplus::ImageCodecInfo* imagecodecinfo;
Gdiplus::GetimageEncodeRSSize(&num,&size); // get count of codec
imagecodecinfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
GetimageEncoders(num,size,imagecodecinfo);//get codec
CLSID clsidEncoder;
for (int i = 0; i < num; i++)
{
if (wcscmp(imagecodecinfo[i].MimeType,L"image/jpeg") == 0)
clsidEncoder = imagecodecinfo[i].Clsid; // get jpeg codec id
}
free(imagecodecinfo);
Gdiplus::BitmaP* bm = new Gdiplus::Bitmap(hbitmap,NULL);
std::wstring ws;
ws.assign(imageaPath.begin(),imageaPath.end());//sring to wstring
bm->Save(ws.c_str(),&clsidEncoder); //save in jpeg format
SelectObject(hMemoryDC,holdbitmap);//Release Objects
DeleteObject(hMemoryDC);
DeleteObject(hbitmap);
ReleaseDC(GetDesktopWindow(),hScreenDC);
Gdiplus::GdiplusShutdown(gdiplustoken);
}
更新:
好的,我找到了一种没有黑屏图像的截屏方法
当我使用 system("pause");
使程序停止并按 Enter 使程序继续时,它正在工作,我使用了 c++ sleep 方法但不起作用,知道吗?
...
HBITMAP holdbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hbitmap));
system("pause");
BitBlt(hMemoryDC,SRCcopY | CAPTUREBLT);
...
睡眠方法:
Sleep(1000);
std::this_thread::sleep_for(std::chrono::seconds(1));
更新 2:
我正在使用 curl 发送屏幕截图请求,我正在服务器(rdp)中进行测试,但在发送请求时我已注销,我认为服务器中的睡眠模式已启用,当我注销时,服务器将处于睡眠状态并且这就像电脑屏幕变黑一样,这就是为什么 BitBlt() 失败并且 GetLastError() 将返回 5,这意味着访问被拒绝
解决方法
The documentation for GdiplusShutdown
说
您必须在创建任何 GDI+ 对象之前调用 GdiplusStartup
,并且您必须删除所有 GDI+ 对象(或让它们超出范围)在您调用 { 之前{1}}。
您正在泄露违反此规则的 GdiplusShutdown
。