Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > непонятная ошибка с hDC


Автор: serg405 6.8.2009, 18:45
Очень активно рисую на окне через OnPaint. И иногда в непредсказуемые моменты прога вилетает на ассерте в функциях рисовани типу FileSolidRect() на проверке 
Код

ASSERT(m_hDC != NULL);


Может ли это быть связано с тем, что я dc я получаю через GetDC(), а не через 
Код

CPaint dc(this);


Ище перед вылетом прога иногда выводит сообщение как на рисунке
user posted image

И вот что я вижу в Output.

Код

First-chance exception at 0x7c812afb in SSYS Trader.exe: Microsoft C++ exception: CResourceException at memory location 0x0012cc48..
Warning: Uncaught exception in WindowProc (returning 0).


Странно я ище ни в одном примере не видел чтобы тело onPaint - а брали в try

Автор: Earnest 7.8.2009, 07:46
Если ты в рисуешь в OnPaint, то контекст все же нужно получать через CPaintDC, причем один раз на рисование. Дело в том, что не только рисовать нужно, но и некоторые другие действия выполнять; и делает это именно CPaintDC.
Из твоего поста вообще можно понять, что ты получаешь контекст через GetDC КАЖДЫЙ РАЗ.
И вообще, у тебя где-то явная лажа с кодом, раз такая фигня лезет. Что касается ловли исключений в OnPaint, так мало ли что ты не видел. Все зависит от кода рисования. Если он может вызвать исключение, значит, надо ловить. Кстати, CResourseException говорит о том, что ты безбожно разбазариваешь GDI-ресурсы (т.е. на возвращаешь их).

Автор: serg405 7.8.2009, 10:02
Цитата(Earnest @  7.8.2009,  07:46 Найти цитируемый пост)
разбазариваешь GDI-ресурсы (т.е. на возвращаешь их).

Имееш ввиду что не делаю вот так?

Код

CPaintDC dc(this);
// painting
this->ReleaseDC(&dc);


А и кстаит дополнительный вопрос. Зачем седлали GetDC(), если можно во всех функциях кроме OnPaint использовать
Код

CClientDC dc(this);

Кстати здесь тож нужно делать
 
Код

this->ReleaseDC(&dc);

правильно?

Вот ето нашол в MSDN
Цитата

Because only one bitmap can be selected into a device context at a time, you must call ReleaseDC for each call to GetDC.

А если я сделал не так
Код

CDC *pDC = GetDC();
ReleaseDC(pDC);

а вот так
Код

GetDC()->rectangle(....);

что тогода релизать, тут  я так понимаю ненадо? Или всетаки чтото надо.


И дайте ссылку кто может как правильно и грамотно пользоваться CDC CClientDC CPaintDC OnPaint CustomDraw и так далее.  Может есть какаято книга по рисованию в MFC. Потому что MSDN мне чтото мало потогает.

Автор: GavriKos 7.8.2009, 10:28
1) По поводу ресурсов - это касется не только контекста устройства. Не забывай выгружать кисти, ручки и прочее. Выгружай все ))
2) Лучше приведи полный код, а то действительно непонятно что и как ты используешь для рисования

Автор: serg405 7.8.2009, 10:40
1)
Цитата

2) Лучше приведи полный код, а то действительно непонятно что и как ты используешь для рисования

Уменя в проекте немерено кода по рисованию пишут его 3 человека каждий по своему. Тоесть суть не в коде а в том что ево много и мы непривильно спользуем ресурсы.

2)
Цитата(GavriKos @  7.8.2009,  10:28 Найти цитируемый пост)
1) По поводу ресурсов - это касется не только контекста устройства. Не забывай выгружать кисти, ручки и прочее. Выгружай все ))


3)Выгружать кисти это значит запоминать старую и возвращать ее? Или просто делетать поинтреы(ну это я и так знаю)?
или нужно самому делетать созданый обэкт ну от допустим обезательно ли делать вот так
Код

CBrush br;
br.CreateSolidBrush(255);
CClientDC dc(this);//
CBrush *oldBr = dc.SelectObject(&br);
//draw
dc.SelectObject(oldBr);//Если я далльше уже не рисую, и этого не сделать будут проблемы? 
br.DeleteObject();//Нужно ли это делать ведь по идеи пир выходе с функции и так удалится.
this->ReleaseDC(&d);// правильно???


4)Кстати а если сделать вот так
Код

dc.SelectObject(&br);
br.DeleteObject();// будут ли проблемы? Если я дальше не рисую.


5)А  вот ище пример. Так правильно?
Код

void CColorPickerEx::OnPaint()
{
    CPaintDC dc(this);

    DrawPicker(&dc);

    ReleaseDC(&dc);//раньше этого не было это я щас дописал.Раньше в  DrawPicker() я делал так CDC *pDC = GetDC(); и не освобождал
}

В DrawPicker просто рисую квадраты круги и так далее.

6) А если я рисую в OnCtrlColor? там в функцию приходит DC я так думаю там эго релизать ненадо? А что будет если я эго релизну?


Автор: Earnest 7.8.2009, 13:46
Цитата(serg405 @  7.8.2009,  11:02 Найти цитируемый пост)
Имееш ввиду что не делаю вот так?
CPaintDC dc(this);
// painting
this->ReleaseDC(&dc);

Здесь как раз релизить не надо.
И в случае с ClientDC тоже - это делает деструктор.

А вот здесь
Цитата(serg405 @  7.8.2009,  11:02 Найти цитируемый пост)

GetDC()->rectangle(....);

как раз очень даже надо. Вообще так нельзя делать именно потому, что ты не сохраняешь переменную CDC и непонятно что релизить.

Цитата(serg405 @  7.8.2009,  11:40 Найти цитируемый пост)
3)Выгружать кисти это значит запоминать старую и возвращать ее? Или просто делетать поинтреы(ну это я и так знаю)?

Либо так, либо выбирать в контекст стандартную кисть (StockObject). А потом, разумеется удалять саму кисть (после выгрузки ее из контекста). Причем, если ты используешь автоматические переменные, то они сами разрушатся.

Цитата(serg405 @  7.8.2009,  11:40 Найти цитируемый пост)
4)Кстати а если сделать вот так

dc.SelectObject(&br);
br.DeleteObject();// будут ли проблемы? Если я дальше не рисую.

Еще какие! Нельзя разрушать объект, выбранный в контекст.

Цитата(serg405 @  7.8.2009,  11:40 Найти цитируемый пост)
5)А  вот ище пример. Так правильно?


Цитата(serg405 @  7.8.2009,  11:40 Найти цитируемый пост)
6) А если я рисую в OnCtrlColor? там в функцию приходит DC я так думаю там эго релизать ненадо? А что будет если я эго релизну?

Не надо здесь релизить. А будет неизвестно что и неизвестно когда - неопределенное поведение.

Вообще реилизить нужно только то, что сам создал, это общий принцип.
И с основами C++ и MFC разобраться не помешает.

Автор: GavriKos 7.8.2009, 13:57
По поводу литературы... Есть у меня хорошая книга в бумашке, но она харьковского издания, не знаю можно ли нарыть ее в инете. Название до боли простое - Visul c++. В принципе в любой книге именно по вижуалам должно по идее быть рисование. 

На сколько помню из школьных уроков мфс - правило хорошего тона при рисовании - старые объекты для рисования запоминать и потом обратно подключать. Очень спасает такая привычка в ситуации когда в середину рисования надо что то впихнуть свое. 

Автор: serg405 7.8.2009, 14:08
Цитата(GavriKos @  7.8.2009,  13:57 Найти цитируемый пост)
Название до боли простое - Visul c++

А авторов не подсказеш?

Автор: GavriKos 7.8.2009, 14:24
С. В. Глушаков, А.В. Коваль "Visual c++ руководство разработчика"

Автор: serg405 7.8.2009, 17:51
спасибо за втора. Так ище вопрос

Код

try
{
    CPaintDC dc(this);

    DrawPicker(&dc);

    ReleaseDC(&dc);
}
catch(CResourceException &e)
{
  e.ReportError();
}


Не ловит ничево.

Автор: serg405 10.8.2009, 09:37
А кто что скажет на щет такого кода
Код

void CmyWnd::OnPaint()
{
  CWnd::OnPaint();
  return;
}

Автор: Earnest 10.8.2009, 12:53
Такой обработчик имеет смысл только в единственном случае: когда CWnd не является прямым предком CMyWnd, и прямой предок (или кто-то из предков) переопределяет OnPaint. Во всех остальных случаях он нафик не нужен. Как и оператор return.

Автор: serg405 10.8.2009, 18:05
не ну у маня там if и другой код по else просто не будет ли какогото подводоного камня. Я сам понимаю что пользы от этого в чистом виде 0.

Автор: serg405 10.8.2009, 20:22
Так везде где вызывался GetDC()  все выглыдит вот так
Код

CDC *pDC = GetDC();
Draw(pDC);
ReleasDC(pDC);

Ошыбка не пропала. Осталось впринципе только проверить все SelectObject().
Но я уже начинаю сомневаться что проблема в этом.
Я бы показал сурс но у меня ево немерено и я незнаю где именно все вылетает.
Хочу ище попробовать протрейсать все GetDC и поймать момент когда возникает первый CResourceError.

А у когото вообще такое бывало. Если да то скажыте где нашли ошибку.

Автор: Earnest 11.8.2009, 06:40
Цитата(serg405 @  10.8.2009,  19:05 Найти цитируемый пост)
не ну у маня там if и другой код по else просто не будет ли какогото подводоного камня. Я сам понимаю что пользы от этого в чистом виде 0.

Тогда правильно будет примерно так:
Код

void CMyView::OnPaint()
{
   if (...)
   {
      CWnd::OnPaint();
   }
   else
   {
      CPantDC dc (this);
      ...
   }
}

Т.е. создавать CPaintDC нужно только в коде своей прорисовки, но никак не перед вызовом стандартного метода.

Убери нифиг все GetDC из прорисовки. Вся прорисовка, вызываемая из OnPaint должна получать контекст CPaintDC, инициализируемый здесь же. Перепиши свои функции так, чтобы они получали контекст CDC как параметр, по ссылке, и вызывай из OnPaint или если приспичит - из других мест. Если где-то и нужно контекст через GetDC или CClientDC получать - таких мест не должно быть много. Чаще всего - это прорисовка каких-то временных объектов, скажем, при движении мыши. Но для основной прорисовки должен быть единиый контекст CPaintDC.

Автор: serg405 11.8.2009, 10:16
Код

            CBrush *pBkBrush = new CBrush(item.BkColor);
    CPen *pBkPen = new CPen(0,0,item.BkColor);


Забыл удалить. От лох. Давно у меня такого не было хорошо что на лики посмотрел.

Добавлено через 4 минуты
я так уже давно и сдела. Проблема была втом что забил делетнуть динамическую кисть. Посмотрел в аемори лики и все прояснилось. А на щет GetDC внутри пейнта я использовал функцию с параметром, но ету же функцию визивал и не только из онпейнт вот при тех други вызовах я и использовал GetDC

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)