@mardokvk
Я junior-программист, мой профиль С#, изучаю С++.

Утечка памяти gdiplus?

Не пойму какая часть кода вызывает утечку памяти, что я должен удалять или очищать и как я должен это делать?
Вот мой код
Вызываю функцию:
clock_t start = clock();

	if (SearchToRegion(TemplateExitonDock, winEVEOnline_ClassName, pt_center, ButtonExitStationS, 237, 40))
		cout << "true" << endl;
	else
		cout << "false" << endl;

	clock_t end = clock();
	double seconds = (double)(end - start) / CLOCKS_PER_SEC;
	printf("The time: %f seconds\n", seconds);
	system("pause");
	return 0;

Это собственно функция:
bool SearchToRegion(wchar_t* templateName, wchar_t nameClassWindow[100], Point& pt_center, Point startP, int Widht, int Height)
{
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	Color clr, clr_main;

	int countpxMax = 0, countpx = 0;
	Bitmap bmpTemplate(LoadHbitmapFromFile(templateName), NULL);
	countpxMax = bmpTemplate.GetHeight() * bmpTemplate.GetWidth();
	bmpTemplate.GetPixel(0, 0, &clr);
	GDI_SearchToTrinity GDI(nameClassWindow, startP, Widht, Height);
	Bitmap bmpLauncher(GDI.hBitmap, NULL);
	bmpLauncher.Save(L"D:\\test.bmp", &bmp);

	for (int y = 0; y < bmpLauncher.GetHeight() && countpx != countpxMax; y++) //int x = 0; x < bmpLauncher.GetWidth(); x++
		for (int x = 0; x < bmpLauncher.GetWidth() && countpx != countpxMax; x++) //int y = 0; y < bmpLauncher.GetHeight(); y++
		{
			bmpLauncher.GetPixel(x, y, &clr_main);
			if (clr.GetValue() == clr_main.GetValue() && countpx != countpxMax)
			{
				countpx = Comparison_two_bmp(templateName, GDI.hBitmap, x, y);
			}
		}
	if (countpx == countpxMax)
	{
		RECT rc;
		GetWindowRect(FindWindow(nameClassWindow, NULL), &rc);
		SetForegroundWindow(FindWindow(nameClassWindow, NULL));
		SetCursorPos(rc.left + pt_center.X, rc.top + pt_center.Y);		
		return true;
	}
	else
		return false;
}

Эта функция вызывается внутри предыдущей
int Comparison_two_bmp(wchar_t* templateName, HBITMAP hBmp, int x, int y)
{
	Color clr_t, clr_main;
	int CountPx = 0;

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	Bitmap bmpTemplate(LoadHbitmapFromFile(templateName), NULL);
	Bitmap bmp(hBmp, NULL);
	for (int y_t = 0; y_t < bmpTemplate.GetHeight(); y_t++)
		for (int x_t = 0; x_t < bmpTemplate.GetWidth(); x_t++)
		{
			bmp.GetPixel(x + x_t, y + y_t, &clr_main);
			bmpTemplate.GetPixel(x_t, y_t, &clr_t);
			if (clr_t.GetValue() == clr_main.GetValue())
			{
				CountPx++;
			}
			else
				return CountPx;
		}
	return CountPx;
}


Вот класс через который я делаю скрин экрана, точнее HBITMAP
Но с его утечкой памяти я вроде разобрался, хотя он вызывается в цикле, может я что-то тут забыл удалить.

class GDI_SearchToTrinity
{
public:
	HBITMAP hBitmap;
	RECT rc;
	GDI_SearchToTrinity(wchar_t nameWindow[100], Point start_P, int Width, int Height)
	{
		HWND hwnd = FindWindow(nameWindow, 0);

		while (hwnd == NULL)
			hwnd = FindWindow(nameWindow, 0);


		SetForegroundWindow(hwnd);
		SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE);
		GetWindowRect(hwnd, &rc);

		GdiplusStartupInput gdiplusStartupInput;
		ULONG_PTR gdiplusToken;
		GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

		scrdc = GetDC(0);

		memdc = CreateCompatibleDC(scrdc);
		membit = CreateCompatibleBitmap(scrdc, Width, Height);
		SelectObject(memdc, membit);
		BitBlt(memdc, 0, 0, Width, Height, scrdc, rc.left + start_P.X, rc.top + start_P.Y, SRCCOPY);
		hBitmap = (HBITMAP)SelectObject(memdc, membit);
	}
	~GDI_SearchToTrinity()
	{
		DeleteObject(scrdc);
		DeleteObject(memdc);
		DeleteObject(membit);
		DeleteObject(hBitmap);
	}
private:
	HDC scrdc, memdc;
	HBITMAP membit;
};


Собственно вот что выдает VIsual Studio 2022

64f59059123af108015540.png
  • Вопрос задан
  • 103 просмотра
Пригласить эксперта
Ответы на вопрос 2
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
что я должен удалять или очищать и как я должен это делать?

MSDN говорит, что у каждого GdiplusStartup должен быть парный вызов GdiplusShutdown.
Ответ написан
@mardokvk Автор вопроса
Я junior-программист, мой профиль С#, изучаю С++.
Я подозреваю что утечка идет в этой функции
int Comparison_two_bmp(wchar_t* templateName, HBITMAP hBmp, int x, int y)
{
	Color clr_t, clr_main;
	int CountPx = 0;

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	Bitmap bmpTemplate(LoadHbitmapFromFile(templateName), NULL);
	Bitmap bmp(hBmp, NULL);
	for (int y_t = 0; y_t < bmpTemplate.GetHeight(); y_t++)
		for (int x_t = 0; x_t < bmpTemplate.GetWidth(); x_t++)
		{
			bmp.GetPixel(x + x_t, y + y_t, &clr_main);
			bmpTemplate.GetPixel(x_t, y_t, &clr_t);
			if (clr_t.GetValue() == clr_main.GetValue())
				CountPx++;
			else
				return CountPx;
			//cout << "CountPX(" << CountPx << ") - " << "xt(" << x + x_t << ") - " << "yt(" << y + y_t << ") - " << "x_t(" << x_t << ") - " << "y_t(" << y_t << ")" << endl;
		}


	//bmp.Save(L"bmp_test.bmp", &png);
	
	return CountPx;
}


я предполагаю что постоянное создание Bitmap и отсутствие адекватной его очистки может приводить к утечке.
Bitmap bmpTemplate(LoadHbitmapFromFile(templateName), NULL);
Bitmap bmp(hBmp, NULL);

Вот эти две функции по факту вызываются каждый раз когда вызывается функция, а функция вызывается часто из-за того что она в цикле.
Соответственно эти Bitmap не удаляются и не очищаются после создания, скорее всего она и создают утечку.
Вопрос в том как этого избежать?
Тут у меня две проблемы, вопрос в том как передать Bitmap в функцию, чтобы не приходилось его создавать снова и снова?
Второй вопрос, как удалять Bitmap?
Если бы я смог удалять Bitmap тогда не будет утечки, а если просто буду передавать его в функцию, то не придется создавать его множество раз.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы