Below I provide my code in advance.

The whole problem is the incomplete cleaning of the LPSTREAM memory after using it in GDIplus::Bitmap::Save()

Specifically in this line:

 bmp->Save(stream, &jpegClsid, &encoderParameters); 

After returning from the function, I read the contents of the stream and try to clear it with

 str->Release(); 

but the memory is not cleared; in the screenshot, calls to the TakeScreenshot function are:

(The jumps in memory usage when saving to HBITMAP, a clean screenshot weighs 14mb, as the snapshot of 2 screens)

Screenshot

Maybe I missed the rest of the code?

Spent on this problem the whole day, poke your nose at the error, please.

 void SaveJpeg(HBITMAP hbmpImage, unsigned int Quality, LPSTREAM stream) { Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); Gdiplus::EncoderParameters encoderParameters; encoderParameters.Count = 1; encoderParameters.Parameter[0].Guid = Gdiplus::EncoderQuality; encoderParameters.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; encoderParameters.Parameter[0].NumberOfValues = 1; encoderParameters.Parameter[0].Value = &Quality; CLSID jpegClsid; GetEncoderClsid(L"image/jpeg", &jpegClsid); Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(hbmpImage, (HPALETTE)0); //bmp->Save(L"1.jpg", &jpegClsid, &encoderParameters); bmp->Save(stream, &jpegClsid, &encoderParameters); delete(bmp); } void WINAPI TakeScreenshot(unsigned int quality, LPBYTE* fs, ULONG* written) { HDC hdc = GetDC(NULL); HDC hDest = CreateCompatibleDC(hdc); int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); HBITMAP hbDesktop = CreateCompatibleBitmap(hdc, width, height); SelectObject(hDest, hbDesktop); BitBlt(hDest, 0, 0, width, height, hdc, 0, 0, SRCCOPY); LPSTREAM str; CreateStreamOnHGlobal(NULL, FALSE, &str); SaveJpeg(hbDesktop, quality, str); STATSTG Stat; if (str->Stat(&Stat, STATFLAG_NONAME) == S_OK && Stat.cbSize.HighPart == 0) { LARGE_INTEGER li; li.HighPart = 0; li.LowPart = 0; str->Seek(li, STREAM_SEEK_SET, NULL); LPBYTE buf = (LPBYTE)malloc(sizeof(DWORD) + Stat.cbSize.LowPart); if (buf != NULL) { if (str->Read(buf + sizeof(DWORD), Stat.cbSize.LowPart, &Stat.cbSize.LowPart) == S_OK) { *((LPDWORD)buf) = Stat.cbSize.LowPart; *fs = buf; *written = sizeof(DWORD) + Stat.cbSize.LowPart; } } free(buf); } str->Release(); ReleaseDC(NULL, hdc); DeleteDC(hDest); } 
  • For 'hbDesktop' it seems like the need is 'DeleteObject' - αλεχολυτ
  • Added, thanks. But this of course does not solve the problem of cleaning the stream. - NaNman

1 answer 1

Everything turned out to be quite simple.

It was necessary to replace FALSE in

 CreateStreamOnHGlobal(NULL, FALSE, &str); 

On TRUE.

This parameter determines whether to clear the thread’s memory after the call.

 stream->Release();