Поскольку отельного раздела С++ нет спрошу здесь.
Есть следующий код (иллюстрирующий пример)
- Код: Выделить всё
#include <windows.h>
HWND hMainWindow = HWND_DESKTOP;
#define OBJECT_COUNT 10
class Object
{
protected:
int x, y; bool bAllowUp; RECT rectBar, inRect;
public:
virtual void UpDate() = 0;
virtual void Render() = 0;
};
class HorObject : public Object
{
public:
HorObject(int _X, int _Y)
{
bAllowUp = true;
x = _X;
inRect.top = rectBar.top = y = _Y;
inRect.bottom = rectBar.bottom = y + 40;
}
void UpDate()
{
if (x < 10)
bAllowUp = true;
else if (x > 750)
bAllowUp = false;
if (bAllowUp)
{
inRect.left = x;
x += 10;
inRect.right = x;
}
else
{
inRect.right = x + 50;
inRect.left = x + 30;
x -= 10;
}
rectBar.left = x;
rectBar.right = x + 40;
};
void Render()
{
InvalidateRect(hMainWindow, &inRect, TRUE);
HDC hDc = GetDC(hMainWindow);
FillRect(hDc, &rectBar, CreateSolidBrush(RGB(0, 0, 255)));
ReleaseDC(hMainWindow, hDc);
hDc = NULL;
};
};
class VertObject : public Object
{
public:
VertObject(int _X, int _Y)
{
bAllowUp = true;
inRect.left = rectBar.left = x = _X;
y = _Y;
inRect.right = rectBar.right = x + 40;
}
void UpDate()
{
if (y < 10)
bAllowUp = true;
else if (y > 530)
bAllowUp = false;
if (bAllowUp)
{
inRect.top = y;
y += 10;
inRect.bottom = y;
}
else
{
inRect.bottom = y + 50;
inRect.top = y + 30;
y -= 10;
}
rectBar.top = y;
rectBar.bottom = y + 40;
};
void Render()
{
InvalidateRect(hMainWindow, &inRect, TRUE);
HDC hDc = GetDC(hMainWindow);
FillRect(hDc, &rectBar, CreateSolidBrush(RGB(255, 0, 0)));
ReleaseDC(hMainWindow, hDc);
hDc = NULL;
};
};
class BoxManager
{
private:
Object *mObjects[OBJECT_COUNT];
public:
BoxManager()
{
for(int i = 0; i < OBJECT_COUNT/2; i++)
if(mObjects[i])
mObjects[i] = new HorObject(i*100, (4 - i)*100 + 65);
for(int i = OBJECT_COUNT/2; i < OBJECT_COUNT; i++)
if(mObjects[i])
mObjects[i] = new VertObject((10 - i)*100 + 65, i*50 + 75);
}
void UpDate()
{
for(int i = 0; i < OBJECT_COUNT; i++)
if(mObjects[i])
mObjects[i] -> UpDate();
}
void Render()
{
for(int i = 0; i < OBJECT_COUNT; i++)
if(mObjects[i])
mObjects[i] -> Render();
}
~BoxManager()
{
for(int i = 0; i < OBJECT_COUNT; i++)
if(mObjects[i])
{
delete mObjects[i];
mObjects[i] = NULL;
}
}
};
BoxManager *manager = NULL;
LRESULT CALLBACK WindowFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TIMER:
manager -> UpDate();
manager -> Render();
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, wchar_t *lpszArgs, int nWinMode)
{
wchar_t ClassName[16] = L"AppClass", WindowName[16] = L"Boxes";
WNDCLASS wcl;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.lpszMenuName = NULL;
wcl.style = CS_HREDRAW | CS_VREDRAW;
wcl.lpfnWndProc = WindowFunc;
wcl.hInstance = hThisInst;
wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcl.lpszClassName = ClassName;
if (!RegisterClass (&wcl))
return -1;
hMainWindow = CreateWindow (
ClassName, WindowName, WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, HWND_DESKTOP,
NULL, hThisInst, NULL);
if (!hMainWindow)
return -1;
manager = new BoxManager();
ShowWindow (hMainWindow, nWinMode);
UpdateWindow (hMainWindow);
SetTimer(hMainWindow, 1, 25, (TIMERPROC) NULL);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
KillTimer(hMainWindow, 1);
delete manager;
manager = NULL;
return (int)msg.wParam;
}
Во-первых, не ясно, почему утечка наблюдается вовсе? Вроде всё как книга пишет: вызвал GetDC() вызови ReleaseDC(). В коде даже более, добавил зануление - hDc = NULL.
Но нет, программа набирает лимит 9999 объектов GDI, и далее, как следствие, по ней двигаются белые объекты. Это в ХР. В Висте же... в общем, кому нужна цветомузыка, это самое оно. При достижении указанного лимита экран монитор начинает мерцать самыми разными цветами. Если предварительно не запущен диспетчер задач, с мониторингом этого процесса (в частности там и наблюдал количество GDI объектов), вернуть управления системой будет крайне затруднительно
На Севен не проверял, но вероятнее всего там будет таже "картина" что и в Висте.
GDIPlus вариант
- Код: Выделить всё
замена строки кода FillRect(hDc, &rectBar, CreateSolidBrush(RGB(0, 0, 255)));
на такие три строки
Graphics g(hDc);
g.SetPageUnit(UnitPixel);
g.FillRectangle(new SolidBrush(Color(255, 0, 0, 255)), Rect (rectBar.left, rectBar.top, rectBar.right - rectBar.left, rectBar.bottom - rectBar.top));
отрабатывает нормально (не зависимо от ОС), без утечек и с корректным отображением.
Где проблема?
Спасибо за уделённое внимание.