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

X>
X>void CBimapsView::OnButton32774() 
X>{
X>    
X>    CRgn rg;    
X>//запомнили первоначальный
X>    AfxGetMainWnd()->GetWindowRgn(oldRegion);
X>    rg.CreateEllipticRgn(10,10,200,200);
X>//установили эллипсовидный
//::SetWindowRgn(AfxGetMainWnd()->>m_hWnd,rg,TRUE);
X>    AfxGetMainWnd()->SetWindowRgn(rg,TRUE);

X>    
X>}

X>void CBimapsView::OnButton32776() 
X>{
X>    //восстановили первоначальный
X>    AfxGetMainWnd()->SetWindowRgn(oldRegion,TRUE);
X>}

X>


X>Смысл — по щелчку одной кнопки окно становится круглым, а по щелчку на другой — восстанавливает свою форму. И не работает. А вот если пользоваться аналогичными функциями API и сохранять состояние не в переменной-члене класса C*View, а C*App то работает. Почему?


Я набросал примерчик, лежит на http://www.alexfedotov.com/samples/winrgn.zip

Вот замечания:

1. У меня сложилось впечатление, что ты пытаешься отлаживать программу в Release-конфигурации. Во всяком случае, ты ничего не говорила про debug assertions, а они должны быть

2. Команды установки и снятия региона относятся к главному окну, так почему бы их туда и не поместить? В моем примере они находятся в классе CMainFrame.

Теперь по существу:

void CMainFrame::OnSetRgn() 
{
    RECT rcWindow;
    GetWindowRect(&rcWindow);
    
    rcWindow.right  -= rcWindow.left;
    rcWindow.bottom -= rcWindow.top;

    CRgn rgn;
    VERIFY(rgn.CreateRoundRectRgn(0, 0, rcWindow.right, rcWindow.bottom, 80, 80));

    m_OldRgn.CreateRectRgn(0, 0, 0, 0);
    if (!GetWindowRgn(m_OldRgn))
        m_OldRgn.DeleteObject();

    VERIFY(SetWindowRgn((HRGN)rgn.Detach(), TRUE));
}


3. Функция GetWindowRgn ожидает на вход действительный HRGN, поэтому прежде чем давать m_OldRgn на вход этой функции, его надо инициализировать. В показанном тобой коде непонятно, где это происходит, и происходит ли вообще.

4. Нормальные прямоугольные окна не имеют региона. Если вызвать GetWindowRgn для такого окна, она просто возвращает FALSE (а ведь в книжках учат — проверяйте возвращаемое значение функций, хотя бы с помощью VERIFY). Поэтому логика такая: a) создаем регион, б) вызываем GetWindowRgn; в) теперь если функция завершилась успешно, мы получили регион окна, в противном случае г) уничтожаем регион. В результате мы имеет m_OldRgn.m_hObject != NULL, если у окна есть регион, и m_OldRgn.m_hObject == NULL, если его нет.

5. Документация на функцию SetWindowRgn гласит:

<!-- msdn -->
After a successful call to SetWindowRgn, the system owns the region specified by the region handle hRgn. The system does not make a copy of the region. Thus, you should not make any further function calls with this region handle. In particular, do not delete this region handle. The system deletes the region handle when it no longer needed.
<!-- /msdn -->

Поэтому ни сохранять этот регион (как я изначально советовал), ни удалять его (что произойдет в деструкторе CRgn, если не предпринять дополнительных действий) нельзя. Чтобы HRGN не удалился в деструкторе CRgn, его нужно отсоединить от объекта с помощью метода Detach(), как показано в примере.

void CMainFrame::OnRestoreRgn() 
{
    SetWindowRgn((HRGN)m_OldRgn.Detach(), TRUE);
}


6. Восстановление региона просто: если у нас есть сохраненный регион, мы отсоединяем его от объекта и назначаем окну. В противном случае мы вызываем SetWindowRgn c HRGN, равным NULL, что приводит к восстановлению нормальной прямоугольной формы окна.
Автор: Alex Fedotov    Оценить