Проблема с приложением :\
Всё вроде бы нормально, но через некоторое время (оно варьируется), программа выводит сообщение Out of memory и перестаёт реагировать на нажатия.. Я всё проверил - везде где malloc, всегда юзаю free(), все создаваемые объекты в OnPaint удаляю через DeleteObject и DeleteDC.. Может есть какой нюанс, который я упустил? При каких абстоятельсвах эта ошибка чаще всего всплывает?
У меня есть подозрение. Юзаю структуру:
int ticker;
short id;
short global_id;
byte group;
float x;
float y;
float z;
} DROP;
DROP *drop;
Память под указатель выделяю так:
memset(drop, '\x00', sizeof(DROP)*DROPMAX);
DROPMAX - количество экземпляров структуры.
Так можно с массивом структур работать?
Зарнее спасибо! Уже неделю парюсь с этим багом...
Кстати:
зачем в обработчике сообщения отрисовки(!!!) что то создавать или удалять???
Кстати:
зачем в обработчике сообщения отрисовки(!!!) что то создавать или удалять???
Эм, а так разве нелья?
void CProjectDlg::OnPaint() {
CPaintDC dc(this); // device context for painting
if (IsIconic()) {
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
} else {
CDC mapDc;
CBitmap m_bmp;
mapDc.CreateCompatibleDC(&dc);
m_bmp.CreateCompatibleBitmap(&dc, 100, 100);
mapDc.SelectObject(&m_bmp);
mapDc.SelectObject(brush); // brush инициализирую глобально
mapDc.PatBlt(0, 0, 100, 100, PATCOPY);
mapDc.Rectangle(0, 0, 100, 100);
mapDc.Ellipse(100 / 2 - 4, 100 / 2 - 4, 100 / 2 + 4, 100 / 2 + 4);
dc.BitBlt(0, 0, 100, 100, &mapDc, 0, 0, SRCCOPY);
dc.ReleaseOutputDC();
dc.DeleteDC();
mapDc.DeleteDC();
m_bmp.DeleteObject();
CDialog::OnPaint();
}
}
А затем когда надо обновляю окно:
InvalidateRect(0, true);
UpdateWindow();
dc.DeleteDC();
mapDc.DeleteDC();
m_bmp.DeleteObject();
делать не обязательно, так как все это вызывается автоматически при выходе из OnPaint() для локальных объектов.
Утечки памяти для MFC проекта должны быть по умолчанию быть видны в окне дебагера после завершения программы. Если они не видны, то их либо нет либо они отключены.
Для WinAPI проекта отображение утечек памяти включается строчкой типа (не знаю работает ли это для MFC):
#include <crtdbg.h>
...
//entry point
int WINAPI _tWinMain(HINSTANCE instance, HINSTANCE /*prev_instance*/, LPTSTR /*cmd_line*/, int wnd_show)
{
//DEBUG: show memory leaks at application exit
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_crtDbgFlag);
...
}
Вроде ликов нету. Значит ошибка в другом месте.
mapDc.DeleteDC();
m_bmp.DeleteObject();
Эти 2 строчки здесь действительно нужны. В каком порядке компилятору захочеться уничтожать эти объекты - определяется в левой ноге Б.Г.
А вот вызывать родительский OnPaint - это вы, сударь, зря делаете... Ибо он наверняк может ещё новый контекст попытаться создать, а то что вы сотворили со старым, аннигилировав его тотально, ему при этом явно не на пользу...
Если так подумать - OnPaint чей бы то ни было вообще вызывать нельзя...
И вообще, внеэкранные контексты и битмапы для них лучше делать через указатели и new/delete - тогда ты точно сам определяешь место и время их смерти ;)
dc.DeleteDC();
mapDc.DeleteDC();
m_bmp.DeleteObject();
делать не обязательно, так как все это вызывается автоматически при выходе из OnPaint() для локальных объектов.
Утечки памяти для MFC проекта должны быть по умолчанию быть видны в окне дебагера после завершения программы. Если они не видны, то их либо нет либо они отключены.
Обааа, огромное спасибо за наводку. Попробовал дебаг, программа тут же упала написав:
Cannot Release Output hDC on Attached CDC.
Detected memory leaks!
Dumping objects ->
d:\myprojects\hookdll\prj\prj\prjdlg.cpp(186) : {95} client block at 0x003594B8, subtype c0, 232 bytes long.
a CPage2 object at $003594B8, 232 bytes long
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {91} normal block at 0x00357E50, 29 bytes long.
Data: < >x > EC 97 3E 78 0C 00 00 00 0C 00 00 00 01 00 00 00
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {90} normal block at 0x00357DF8, 24 bytes long.
Data: < >x > EC 97 3E 78 07 00 00 00 07 00 00 00 01 00 00 00
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {89} normal block at 0x00357D50, 105 bytes long.
Data: < >xX X > EC 97 3E 78 58 00 00 00 58 00 00 00 01 00 00 00
d:\myprojects\hookdll\prj\prj\prjdlg.cpp(172) : {87} client block at 0x00357C90, subtype c0, 132 bytes long.
a CPage1 object at $00357C90, 132 bytes long
d:\myprojects\hookdll\prj\prj\prjdlg.cpp(161) : {86} normal block at 0x00357C40, 16 bytes long.
Data: <d h > 64 00 00 00 0D 00 00 00 68 01 00 00 11 01 00 00
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {72} normal block at 0x00357220, 49 bytes long.
Data: < >x > EC 97 3E 78 05 00 00 00 20 00 00 00 01 00 00 00
Object dump complete.
The program '[1148] prj.exe: Native' has exited with code 3 (0x3).
Убрал:
dc.ReleaseOutputDC();
dc.DeleteDC();
Запустил снова дебаг. Программа запустилась, но при нажатии не первую же кнопку снова упала... Ошибка такая же как выше, но предложения "Cannot Release Output hDC on Attached CDC." не было...
Возможно ли как-то по этому дампу отследить где memory leak?
2Ireul а как тогда экран перерисовывать?
Вызов OnPaint() происходит по сообщению, ручные вызовы имелись в виду, когда я говорил что вызывать OnPaint нельзя.
Зачем каждый раз в обработчике перерисовки создавать битмапы, чтото на них рисовать удалять? Он же должен только перерисовывать изменившеюся облать и все.
Ну рисуй там де действительно что то меняется. Рисуй на виртуальном контектсе и битмапе например, в в товем OnPain делай BitBlt оттуда.