Reputation: 55
I'm trying to take a full page screenshot in windows. function works in first call but after second call won't work at all and it's just getting a black screen image with a stable size. when i use debugger the function works well without giving the black screen.
Here is the code:
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, 0, 0, cx, 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);
}
update:
Okay i find a way to take a screenshot without black screen image
when i use system("pause");
to make program stop and when press enter to make program continue, it's working, I used c++ sleep methods but not works, any idea?
...
HBITMAP holdbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hbitmap));
system("pause");
BitBlt(hMemoryDC, 0, 0, cx, cy, hScreenDC, x, y, SRCCOPY | CAPTUREBLT);
...
sleep methods:
Sleep(1000);
std::this_thread::sleep_for(std::chrono::seconds(1));
update 2:
I was sending screenshot request using curl and I was testing in a server(rdp) and I was logged out when i was sending request, I think sleep mode in server is enabled and when I logged out the server will be sleep and it's like computer screen to go dark and that's why BitBlt() fails and GetLastError() will return 5 which means access denied
Upvotes: 1
Views: 952
Reputation: 23
you can use PrintWindow to replace BitBlt api, the nFlags
of PrintWindow should set to be PW_RENDERFULLCONTENT
, make sure you called this on a windows 8.1 and later os computer, it may be works, just have a try.
Upvotes: -1
Reputation: 283921
The documentation for GdiplusShutdown
says that
You must call
GdiplusStartup
before you create any GDI+ objects, and you must delete all of your GDI+ objects (or have them go out of scope) before you callGdiplusShutdown
.
You are leaking bm = new Gdiplus::Bitmap(...)
which is violating this rule.
Upvotes: 6