gpt4 book ai didi

使用 GDI+ 删除位图和 CLSID 对象时 C++ 内存管理失败

转载 作者:太空宇宙 更新时间:2023-11-04 12:40:29 24 4
gpt4 key购买 nike

我无法管理我在屏幕截图对象类中创建的位图和 CLSID 对象的内存。这两个都来自 GDI+ 库。 header 在 Screenshot.h 中列出了以下私有(private)变量

#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,我假设它来自这里。如何成功删除这些对象?我会将源代码中的任何答案归功于贡献程序员。如果需要,请留下任何改进我的问题的建议。

最佳答案

scaleHeight = Height + (0.1 * Height);

这似乎是为了解决 DPI 缩放问题。如果 DPI 设置为 10%,它将起作用,但通常情况并非如此。您必须通过 list 文件让您的程序了解 DPI。使用 SetProcessDPIAware 进行快速修复。

不要将dcmemdc 等声明为类成员。这些是 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);

关于使用 GDI+ 删除位图和 CLSID 对象时 C++ 内存管理失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54411964/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com