C++自己的类中存在GDI+内存泄露问题

3
我正在寻找这段代码中的内存泄漏问题。我对GDI+不是很熟悉,不确定我的做法是否正确。在我的主函数中,每次循环迭代时,都会调用下面所见的类,并将另一个向量推入该函数中。除了存在内存泄漏之外,一切正常。我尝试使用cppCheck程序查找泄漏,但它没有发现任何内存泄漏:/ 我最后的解决问题的机会就是询问比我更有GDI+经验的人。非常感谢您的帮助,对于这段冗长的代码,我表示抱歉 :)
#include "helper.h"

Gui::Gui(const TCHAR* fileName) {
    this->fileName = fileName;
}

void Gui::drawGui(Gdiplus::Bitmap* image, std::vector<std::wstring> &vec) {

    // Init graphics
    Gdiplus::Graphics* graphics = Gdiplus::Graphics::FromImage(image);

    Gdiplus::Pen penWhite (Gdiplus::Color::White);
    Gdiplus::Pen penRed   (Gdiplus::Color::Red);
    Gdiplus::SolidBrush redBrush(Gdiplus::Color(255, 255, 0, 0));
    penRed.SetWidth(8);

    unsigned short marginTop = 15;
    unsigned short marginLeft = 5;
    unsigned short horizontalBarsizeStart = marginLeft + 60;


    for (unsigned short iter = 0; iter < 8; iter++) {
        // Draw text
        std::wstring coreLabel = L"Core " + std::to_wstring(iter) + L':';
        Gdiplus::Font myFont(L"Arial", 12);
        Gdiplus::PointF origin(marginLeft, marginTop - 10);
        graphics->DrawString(coreLabel.c_str(), coreLabel.length(), &myFont, origin, &redBrush);

        // Draw CPU lines
        unsigned short horizontalBarsizeEnd = horizontalBarsizeStart + std::stoi(vec.at(iter)); // 100 == Max cpu load
        graphics->DrawLine(&penRed, horizontalBarsizeStart, marginTop, horizontalBarsizeEnd, marginTop);

        // Draw border
        Gdiplus::Rect rect(horizontalBarsizeStart, marginTop - 5, 100, 8);
        graphics->DrawRectangle(&penWhite, rect);

        // Next element
        marginTop += 17;
    }
}


bool Gui::SetColorBackgroundFromFile(std::vector<std::wstring> &vec) {

    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    // Initialize GDI+.
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HDC hdc = GetDC(NULL);

    // Load the image. Any of the following formats are supported: BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
    Gdiplus::Bitmap* image = Gdiplus::Bitmap::FromFile(this->fileName, false);

    if (image == NULL) {
        return false;
    }

    // Draw the gui
    this->drawGui(image, vec);

    // Get the bitmap handle
    HBITMAP hBitmap = NULL;
    Gdiplus::Status status = image->GetHBITMAP(RGB(0, 0, 0), &hBitmap);
    if (status != Gdiplus::Ok) {
        return false;
    }

    BITMAPINFO bitmapInfo = { 0 };
    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    // Check what we got
    int ret = GetDIBits(hdc, hBitmap, 0, 0, NULL, &bitmapInfo, DIB_RGB_COLORS);

    if (LOGI_LCD_COLOR_WIDTH != bitmapInfo.bmiHeader.biWidth || LOGI_LCD_COLOR_HEIGHT != bitmapInfo.bmiHeader.biHeight) {
        std::cout << "Oooops. Make sure to use a 320 by 240 image for color background." << std::endl;
        return false;
    }

    bitmapInfo.bmiHeader.biCompression = BI_RGB;
    bitmapInfo.bmiHeader.biHeight = -bitmapInfo.bmiHeader.biHeight; // this value needs to be inverted, or else image will show up upside/down

    BYTE byteBitmap[LOGI_LCD_COLOR_WIDTH * LOGI_LCD_COLOR_HEIGHT * 4]; // we have 32 bits per pixel, or 4 bytes

    // Gets the "bits" from the bitmap and copies them into a buffer 
    // which is pointed to by byteBitmap.
    ret = GetDIBits(hdc, hBitmap, 0,
    -bitmapInfo.bmiHeader.biHeight, // height here needs to be positive. Since we made it negative previously, let's reverse it again.
    &byteBitmap,
    (BITMAPINFO *)&bitmapInfo, DIB_RGB_COLORS);

    LogiLcdColorSetBackground(byteBitmap); // Send image to LCD

    // delete the image when done 
    if (image) {
        delete image;
        image = NULL;
        Gdiplus::GdiplusShutdown(gdiplusToken); // Shutdown GDI+
    }
return true;
}
1个回答

4
drawGui()函数中,你正在泄漏graphics对象。这一行代码创建了一个新的Gdiplus::Graphics对象:
Gdiplus::Graphics* graphics = Gdiplus::Graphics::FromImage(image);

但是你在任何地方都没有调用delete graphics来删除它,一旦你完成了它的使用。

SetColorBackgroundFromFile中,你正在泄漏DC。

HDC hdc = GetDC(NULL);

这会获取屏幕的DC,但你并没有调用ReleaseDC(NULL, hdc);来释放它。

在同一个函数中,你使用以下调用创建了一个HBITMAP

Gdiplus::Status status = image->GetHBITMAP(RGB(0, 0, 0), &hBitmap);

但你没有任何地方调用 DeleteObject(hBitmap); 来释放内存。

同时,如果出现错误,你的代码可能会在没有进行必要的清理的情况下返回。例如,如果 GetHBITMAP 调用失败,你会立即返回并且会泄漏你在几行之前创建的 image 对象。


目前很完美 :) 但是ReleaseDC(hdc);没有起作用 - The Coder
@TheCoder 抱歉,应该是 ReleaseDC(NULL, hdc); - Jonathan Potter
非常感谢,你救了我们的一天! - The Coder
@TheCoder 值得你使用 RAII 技术来最小化或消除这些错误。你目前的代码有多个返回点--任何代码更改并忘记删除资源,都会造成泄漏。使用 RAII 可以解决这些问题:https://dev59.com/WHE95IYBdhLWcg3watM3 - PaulMcKenzie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接