我无法管理在屏幕快照对象类中创建的Bitmap和CLSID对象的内存。这两个都来自GDI +库。标头列出了Screenshot.h
中的以下私有变量#include <gdiplus.h>
#include <iostream>
#include <fstream>
#include <string>
#include "windows.h"
#pragma once
#pragma comment(lib, "gdiplus.lib")
using namespace std;
using namespace Gdiplus;
class Screenshot
{
private:
HDC dc, memdc, fontdc;
HBITMAP membit;
Bitmap* bmpPtr;
CLSID clsid;
ULONG_PTR gdiplusToken;
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
public:
Screenshot();
~Screenshot();
void TakeScreenshot(string userAction, string winName, long xMousePos, long yMousePos, long long tStamp);
void SaveScreenshot(string filename);
void memoryManagement();
};
然后,当我的主程序拍摄屏幕截图时,这些值将用TakeScreenshot()填充,但尚未保存到磁盘
void Screenshot::TakeScreenshot(//redacted for readibility) {
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hwnd = GetDesktopWindow();
dc = ::GetDC(0);
int scaleHeight, scaleWidth = 0;
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
scaleHeight = Height + (0.1 * Height);
memdc = CreateCompatibleDC(dc);
membit = CreateCompatibleBitmap(dc, Width, scaleHeight);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);
//Other code that adds fonts, etc. Does not invoke bmpPtr
bmpPtr = new Bitmap(membit, NULL);
GetEncoderClsid(L"image/jpeg", &clsid);
如果保存了屏幕截图,则另一个函数SaveScreenshot()使用bmpPtr-> Save()并在其内部调用Gdiplus shutdown。但是,某些屏幕快照会从队列(STL队列)中弹出,并从内存中弹出而不是保存,如下所示:
void ManageQueue(Screenshot& ssObj)
{
//If queue contains 30 screenshots, pop off first element and push new object
//Else just push new object
if (screenshotQueue.size() == MAX_SCREENSHOTS)
{
screenshotQueue.front().memoryManagement();
screenshotQueue.pop();
screenshotQueue.push(ssObj);
}
else
{
screenshotQueue.push(ssObj);
}
}
我写了一个MemoryManagement()函数来执行必要的发布和删除操作,然后弹出屏幕截图。如果屏幕快照已保存,则不会调用此函数:
void Screenshot::memoryManagement()
{
delete bmpPtr;
delete &clsid;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
}
当调用bmpPtr或clsid上的delete时,无论是从此函数还是在解构函数中,程序都将崩溃。我现在正在使用该程序遇到大量内存泄漏,并且没有运行与Valgrind相当的Windows,我假设它是从这里来的。如何成功删除这些对象?我将以贡献程序员的身份相信源代码中的所有答案。如果需要,请留下任何建议以改善我的问题。
答案 0 :(得分:0)
scaleHeight = Height + (0.1 * Height);
这似乎是尝试解决DPI缩放问题。如果DPI设置为10%,它将起作用,但是通常不是这种情况。您必须通过清单文件使程序对DPI有所了解。使用SetProcessDPIAware
快速修复。
请勿将dc
,memdc
等声明为类成员。这些是GDI句柄(不是GDI +),通常在功能执行期间,可以短时间握住它们。您必须尽快释放它们。
也不需要将其他变量clsid
声明为类成员。您可以根据需要将它们声明为班级成员,但是没有任何收获。
如果您有多显示器设置,则还需要SM_XVIRTUALSCREEN/Y
才能获得显示器设置的左上角。
//call this once on start up
SetProcessDPIAware();
HDC dc = ::GetDC(0);
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
HDC memdc = CreateCompatibleDC(dc);
HBITMAP membit = CreateCompatibleBitmap(dc, Width, Height);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, x, y, SRCCOPY);
Bitmap* bmpPtr = new Bitmap(membit, NULL);
// or just Bitmap bmp(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bmpPtr->Save(L"output.jpg", &clsid);
//cleanup:
delete bmpPtr;
SelectObject(memdc, bmpContainer);
DeleteObject(membit);
DeleteDC(memdc);
ReleaseDC(0, dc);
答案 1 :(得分:0)
此问题的解决方案是使用名称空间删除而不是常规删除。切换到该选项可防止在调试过程中触发断点,并已密封了内存泄漏。
aspect='auto'