Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 20:45
Оценка:
Привет всем.
Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

void CGraphView::OnDraw(CDC* pDC)
{
    //рисуем график
    DrawGraph(pDC);
}

void CGraphView::OnTimer(UINT nIDEvent) 
{
    // TODO: Add your message handler code here and/or call default
    // чего-то тут делаю 
..............................................

    CDC *pDC = this->GetDC();
    DrawGraph(pDC);
}

void CGraphView::DrawGraph(CDC *pDC)
{
        
    CRect clientRect;
    GetClientRect(&clientRect);

    CDC dc;
    try{
        if(!dc.CreateCompatibleDC(pDC)) throw 1;
    }
    catch(int)
    {
        MessageBox("Ошибка создания контекста!");
        return;
    }
    
    CBitmap bmp;
    bmp.CreateCompatibleBitmap(pDC,clientRect.Width(),clientRect.Height());
    CBitmap* oldBitmap = dc.SelectObject(&bmp);
        //çàïîëíÿåì ñíà÷àëà íóæíûì öâåòîì áýêãðàóíä
    CBrush bkgrndBrush(RGB(0,0,0));
    dc.FillRect(&clientRect,&bkgrndBrush);
        
        
    double kX=(double)clientRect.Width()/1000;
    p = Y.begin();
    double y = clientRect.Height()/2-(*(p++)*100);
    
    CPen pen1(PS_SOLID,1,RGB(255,255,255));
    CPen* oldPen = dc.SelectObject(&pen1);
    dc.MoveTo(0,clientRect.Height()/2);
    dc.LineTo(clientRect.Width(),clientRect.Height()/2);
    dc.SelectObject(oldPen);
        
    CPen pen2(PS_SOLID,1,RGB(255,0,0));
    oldPen = dc.SelectObject(&pen2);
    
    dc.MoveTo(0,y);
    for(int i=0;i<Y.size()-1;i++)
    {
        y = clientRect.Height()/2-(*(p++)*clientRect.Height()/2);
        double xx = (double)i*kX;
        dc.LineTo((int)xx,y);
    }
    dc.SelectObject(oldPen);

    pDC->BitBlt( 0,0,clientRect.Width(),clientRect.Height(),
            &dc,0,0,SRCCOPY);

    dc.SelectObject(oldBitmap);

    dc.DeleteDC();
}


Вроде бы возвращаю везде все GDI-объекты, удаляю сам dc....
В чём трабл??

Буду благодаврен за совет,
Роман.
Re: Ошибка при создании CDC, help!
От: Dima2  
Дата: 24.02.02 21:00
Оценка:
Здравствуйте Аноним, Вы писали:

А>Привет всем.

А>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

А>Вроде бы возвращаю везде все GDI-объекты, удаляю сам dc....

А>В чём трабл??

Что-то не увидел у тебя вызова ReleaseDC.
Re: Ошибка при создании CDC, help!
От: _Liss_  
Дата: 24.02.02 21:03
Оценка:
Здравствуйте Аноним, Вы писали:

А>Привет всем.

А>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

Попробуй останавливать таймер в OnTimer при прорисовке, и в OnDraw, а потом снова его запускать.
Re: Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 21:25
Оценка:
Гм, нашёл причину... :super:

void CGraphView::OnTimer(UINT nIDEvent) 
{
    // TODO: Add your message handler code here and/or call default
    // чего-то тут делаю
.............................................

//    CDC *pDC = this->GetDC();
//    DrawGraph(pDC);
    this->Invalidate(FALSE);
}


Иначе пожиралась вся память (увидел в TaskManager).
Но вопрос в силе — ПОЧЕМУ!
:)
Роман.
Re[2]: Ошибка при создании CDC, help!
От: Dima2  
Дата: 24.02.02 21:32
Оценка:
Здравствуйте Аноним, Вы писали:

А>Гм, нашёл причину...


А>
А>void CGraphView::OnTimer(UINT nIDEvent) 
А>{
А>    // TODO: Add your message handler code here and/or call default
А>    // чего-то тут делаю
А>.............................................
А>
А>//    CDC *pDC = this->GetDC();
А>//    DrawGraph(pDC);
А>    this->Invalidate(FALSE);
А>}
А>


А>Иначе пожиралась вся память (увидел в TaskManager).

А>Но вопрос в силе — ПОЧЕМУ!
А>
А>Роман.

Роман ответ выше я тебе уже дал.
Ты не причину нашел, а отрисовываеш с помощью WM_PAINT, а в OnPaint судя по всему у тебя все в порядке.


void CGraphView::OnTimer(UINT nIDEvent) 
{
    CDC *pDC = this->GetDC();
    DrawGraph(pDC);
    ReleaseDC();
}
Re[2]: Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 21:35
Оценка:
Здравствуйте Dima2, Вы писали:

D>Здравствуйте Аноним, Вы писали:


А>>Привет всем.

А>>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

А>>Вроде бы возвращаю везде все GDI-объекты, удаляю сам dc....

А>>В чём трабл??

D>Что-то не увидел у тебя вызова ReleaseDC.


Привет Дима. Спасибо за участие :)
а который из них освобождать и от чего? Временному dc я перед выходом возвращаю старые GDI, сам его убиваю ( dc.DeleteDC() ), хотя мне не совсем понятно, зачем это делать, всё равно он при выходе из DrawGraph подчистится.... а в pDC ничего нового не выбираю, а лишь копирую битмап в него из временного... :???:
Re[3]: Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 21:41
Оценка:
Здравствуйте Dima2, Вы писали:

D>Здравствуйте Аноним, Вы писали:


А>>Гм, нашёл причину... :super:


А>>
А>>void CGraphView::OnTimer(UINT nIDEvent) 
А>>{
А>>    // TODO: Add your message handler code here and/or call default
А>>    // чего-то тут делаю
А>>.............................................
А>>
А>>//    CDC *pDC = this->GetDC();
А>>//    DrawGraph(pDC);
А>>    this->Invalidate(FALSE);
А>>}
А>>


А>>Иначе пожиралась вся память (увидел в TaskManager).

А>>Но вопрос в силе — ПОЧЕМУ!
А>> :)
А>>Роман.

D>Роман ответ выше я тебе уже дал.

D>Ты не причину нашел, а отрисовываеш с помощью WM_PAINT, а в OnPaint судя по всему у тебя все в порядке.


D>
D>void CGraphView::OnTimer(UINT nIDEvent) 
D>{
D>    CDC *pDC = this->GetDC();
D>    DrawGraph(pDC);
D>    ReleaseDC();
D>}
D>


Спасибо, Дима, так тоже работает :)
Я так понимаю, это нужно делать по той причине, что GetDC() возвращает не указатель, а создаёт его копию и возвращает указатель уже на эту копию?
Роман.
Re[3]: Ошибка при создании CDC, help!
От: Dima2  
Дата: 24.02.02 21:44
Оценка:
Здравствуйте Аноним, Вы писали:

А>Здравствуйте Dima2, Вы писали:


D>>Здравствуйте Аноним, Вы писали:


А>>>Привет всем.

А>>>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

А>>>Вроде бы возвращаю везде все GDI-объекты, удаляю сам dc....

А>>>В чём трабл??

D>>Что-то не увидел у тебя вызова ReleaseDC.


А>Привет Дима. Спасибо за участие

А>а который из них освобождать и от чего? Временному dc я перед выходом возвращаю старые GDI, сам его убиваю ( dc.DeleteDC() ), хотя мне не совсем понятно, зачем это делать, всё равно он при выходе из DrawGraph подчистится.... а в pDC ничего нового не выбираю, а лишь копирую битмап в него из временного...

C dc у тебя все в порядке и DeleteDC ему ты естественно можеш не делать (это сделает за тебя деструктор CDC), хотя может быть неплохо привыкнуть это делать самому, т.к. если будеш писать на чистом API, то будеш забывать.
Ф-я CreateCompatibleDC создает новый DC совместимый с твоим pDC, но pDC тебе то нужно освободить почитай описание ф-ии GetDC().
Re[4]: Ошибка при создании CDC, help!
От: Alex Fedotov США  
Дата: 24.02.02 22:08
Оценка:
Здравствуйте Аноним, Вы писали:

D>>
D>>void CGraphView::OnTimer(UINT nIDEvent) 
D>>{
D>>    CDC *pDC = this->GetDC();
D>>    DrawGraph(pDC);
D>>    ReleaseDC();
D>>}
D>>


А>Я так понимаю, это нужно делать по той причине, что GetDC() возвращает не указатель, а создаёт его копию и возвращает указатель уже на эту копию?


CWnd::GetDC — это тонкая оболочка вокруг функции Win32 API с одноименным названием, которая выдает объект контекста устройства из внутреннего кэша системы. ReleaseDC возвращает объект в кэш. Логика предельно простая: взял — положи на место.
-- Alex Fedotov
Re[4]: Ошибка при создании CDC, help!
От: Dima2  
Дата: 24.02.02 22:22
Оценка:
Здравствуйте Аноним, Вы писали:

А>Спасибо, Дима, так тоже работает

А>Я так понимаю, это нужно делать по той причине, что GetDC() возвращает не указатель, а создаёт его копию и возвращает указатель уже на эту копию?

Ох, ты что-то такое сказал, что я не понял. Это уже какой-то двойной указатель получается. Да нет все проще GetDC() возвращает просто указатель на временный объект CDC.

Ты можеш создать окно со стилем CS_OWNDC, тогда ты можеш вызвать GetDC (один раз) для получения так называемого "private device context", в этом случае вызывать ReleaseDC не надо (нельзя) и сохраняются все изменения DC, которые ты сделал все время жизни окна.
Re[5]: Ошибка при создании CDC, help!
От: Dima2  
Дата: 24.02.02 22:27
Оценка:
Здравствуйте Dima2, Вы писали:

D>Ты можеш создать окно со стилем CS_OWNDC, тогда ты можеш вызвать GetDC (один раз) для получения так называемого "private device context", в этом случае вызывать ReleaseDC не надо (нельзя) и сохраняются все изменения DC, которые ты сделал все время жизни окна.


А если у тебя окно не имеет стиля CS_OWNDC, то как правильно сказал Alex Fedotov, твой DC, полученный через GetDC будет являться частью DC кэша системы и в один прекрасный момент ты этот кэш исчерпаеш.
Re[4]: Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 23:06
Оценка:
Здравствуйте Dima2, Вы писали:

D>Здравствуйте Аноним, Вы писали:


А>>Здравствуйте Dima2, Вы писали:


D>>>Здравствуйте Аноним, Вы писали:


А>>>>Привет всем.

А>>>>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:

А>>>>Вроде бы возвращаю везде все GDI-объекты, удаляю сам dc....

А>>>>В чём трабл??

D>>>Что-то не увидел у тебя вызова ReleaseDC.


А>>Привет Дима. Спасибо за участие :)

А>>а который из них освобождать и от чего? Временному dc я перед выходом возвращаю старые GDI, сам его убиваю ( dc.DeleteDC() ), хотя мне не совсем понятно, зачем это делать, всё равно он при выходе из DrawGraph подчистится.... а в pDC ничего нового не выбираю, а лишь копирую битмап в него из временного... :???:

D>C dc у тебя все в порядке и DeleteDC ему ты естественно можеш не делать (это сделает за тебя деструктор CDC), хотя может быть неплохо привыкнуть это делать самому, т.к. если будеш писать на чистом API, то будеш забывать.

D>Ф-я CreateCompatibleDC создает новый DC совместимый с твоим pDC, но pDC тебе то нужно освободить почитай описание ф-ии GetDC().
Re[4]: Ошибка при создании CDC, help!
От: Аноним  
Дата: 24.02.02 23:12
Оценка:
Всё понятно, всем спасибо, прозрел
Роман. :)
Re: Ошибка при создании CDC, help!
От: Nagir  
Дата: 19.12.02 08:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет всем.

А>Такая проблема: в моей функции DrawGraph примерно через 1-2 минуцты работы программы происходит ошибка при очередном создании контекста dc. Функция вызывается на WM_TIMER (он установлен на 10мсек). Привожу код:
А>void CGraphView::OnTimer(UINT nIDEvent)
А>{
А> // TODO: Add your message handler code here and/or call default
А> // чего-то тут делаю
А>..............................................

А> CDC *pDC = this->GetDC();

А> DrawGraph(pDC);
А>}

Answer:

В он OnTimer я не вижу delete pDC (не знаю, может ты освобожбаешь pDC в другом месте — я не смотрел DrawGraph (sorry) ), но я бы сделал так:

void CGraphView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
// чего-то тут делаю
..............................................

CClientDC dc(this);
DrawGraph(&dc);
}
если у тебя в DrawGraph все в порядке, то будет работать.
Re[2]: Ошибка при создании CDC, help!
От: Mozhay Россия www.mozhay.chat.ru
Дата: 21.12.02 22:19
Оценка:
Здравствуйте, Nagir, Вы писали:

N>В он OnTimer я не вижу delete pDC (не знаю, может ты освобожбаешь pDC в другом месте — я не смотрел DrawGraph (sorry) ), но я бы сделал так:


Насчет delete я сильно сомневаюсь Правильнее — pDC->ReleaseDC();

N> CClientDC dc(this);

N> DrawGraph(&dc);

А это — совсем правильно.
... << RSDN@Home 1.0 beta 3 >>
Re: Ошибка при создании CDC, help!
От: Mozhay Россия www.mozhay.chat.ru
Дата: 21.12.02 22:19
Оценка:
Привет!

Вот немного исправленный код:

void CGraphView::OnTimer(UINT nIDEvent) 
{
    CDC *pDC = this->GetDC();
    DrawGraph(pDC);
    pDC->ReleaseDC();
}

void CGraphView::DrawGraph(CDC *pDC)
{
    CRect clientRect;
    GetClientRect(&clientRect);

    CDC dc;
    if (!dc.CreateCompatibleDC(pDC))
    {
        MessageBox("Ошибка создания контекста!");
        return;
    }

    CBitmap bmp;
    bmp.CreateCompatibleBitmap(pDC,clientRect.Width(),clientRect.Height());
    CBitmap* oldBitmap = dc.SelectObject(&bmp);
    CBrush bkgrndBrush(RGB(0,0,0));
    dc.FillRect(&clientRect,&bkgrndBrush);
        
    double kX=(double)clientRect.Width()/1000;
    p = Y.begin();
    double y = clientRect.Height()/2-(*(p++)*100);
    
    CPen pen1(PS_SOLID,1,RGB(255,255,255));
    CPen* oldPen = dc.SelectObject(&pen1);
    dc.MoveTo(0,clientRect.Height()/2);
    dc.LineTo(clientRect.Width(),clientRect.Height()/2);
        
    CPen pen2(PS_SOLID,1,RGB(255,0,0));
    dc.SelectObject(&pen2);
    
    dc.MoveTo(0,y);
    for(int i=0;i<Y.size()-1;i++)
    {
        y = clientRect.Height()/2-(*(p++)*clientRect.Height()/2);
        double xx = (double)i*kX;
        dc.LineTo((int)xx,y);
    }
    dc.SelectObject(oldPen);

    pDC->BitBlt( 0,0,clientRect.Width(),clientRect.Height(),
            &dc,0,0,SRCCOPY);

    dc.SelectObject(oldBitmap);
    dc.DeleteDC();
}


Должно полегчать.

Несколько советов:
... << RSDN@Home 1.0 beta 3 >>
Re[2]: Ошибка при создании CDC, help!
От: Patalog Россия  
Дата: 23.12.02 09:39
Оценка:
Здравствуйте, Mozhay, Вы писали:

M>Вот немного исправленный код:


M>
[]
M>    dc.SelectObject(oldBitmap);
M>    dc.DeleteDC();
      ^^^^^^^^^^^^^^^^
А ето зачем? Деструктор у CDC уже отменили? Или для "надежности"?

M>}
M>
Почетный кавалер ордена Совка.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.