Ошибка управления памятью в C ++ при удалении объектов Bitmap и CLSID с помощью GDI + - PullRequest
0 голосов
/ 29 января 2019

Я не могу управлять памятью для объектов 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 (), но еще не сохраняются на диск

* 1005.*

Если скриншот сохранен, другая функция SaveScreenshot () использует bmpPtr-> Save () и внутри него вызывается отключение Gdiplus.Однако некоторые снимки экрана выводятся из очереди (очередь 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, будь то из этой функции или из деконструктора, программа аварийно завершает работу.Я испытываю значительные утечки памяти с программой сейчас и без запуска эквивалента Windows Valgrind, я предполагаю, что это происходит отсюда.Как я могу успешно удалить эти объекты?Я буду отмечать любой ответ в моем исходном коде как программист.Пожалуйста, оставьте любые предложения по улучшению моего вопроса, если это необходимо.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Решением этой проблемы было использование удаления пространства имен вместо обычного удаления.Переключение на это предотвратило срабатывание точки останова во время отладки и устранило утечку памяти.

    void Screenshot::memoryManagement()
{
    ::delete bmpPtr;
    ReleaseDC(NULL, memdc);
    DeleteObject(fontdc);
    DeleteObject(memdc);
    DeleteObject(membit);
    GdiplusShutdown(gdiplusToken);
}
0 голосов
/ 29 января 2019
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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...