09 августа 2006

Как закрыть форточку?

WinAPI - вещь для посвященных. Если нужно что-то сделать, мало прочитать документацию (хорошо что хоть она легко доступна). Чтобы что-то сделать правильно, нужно либо долго помучаться, либо перелопатить форумы. Либо и то, и другое.

Задача: закрыть MDI-child окно.
Решение "в лоб": казалось бы, чего проще: DestroyWindow(hWnd)
И даже окно закрывается, на первый взгляд. Но фокус на другое MDI-child окно не переходит, а должен бы. Но это еще не беда. Беда начинается тогда, когда это окно (child) максимизировано. Тогда происходят вообще чудеса: окно закрывается, но от окна в строке меню остаются значки maximize-minimize-close и значок системного меню! Красота, да и только. Если так закрыть несколько окон, то будет полнейший сюрреализм:



Hint: У MDI-child-а обработчик WM_CLOSE по умолчанию закрывает окно (причем делает это грамотно).

Простой вызов SendMessage(hWnd, WM_CLOSE) подходит, но не во всех случаях. Представьте себе, вы пишете обработчик WM_CLOSE, в котором пишете такую конструкцию ;) Да мы просто зациклимся.

В результате у меня получилась подобная конструкция:
bool CMDIFormImpl::Destroy()
{
// This is temporary solution!!!
// todo: replace it by something more suitable

HWND hWnd(m_hWnd);
// call default MDI-child WM_CLOSE handler: it does MDI-destroying better than us
DefWindowProc(WM_CLOSE, 0, 0);
return !::IsWindow(hWnd);
}

3 комментария:

Анонимный комментирует...

> SendMessage (hWnd, WM_CLOSE)
а что если использовать PostMessage?

пишите -> пишете

Raider комментирует...

>а что если использовать PostMessage?

Тогда вызов Destroy() не выполнит своей задачи - не уничтожит окно. Он просто поставит сообщение в очередь.

То есть при PostMessage() следующий код выдаст assertion failed:

Window.Destroy();
ASSERT(!Window.IsWindow());

ser комментирует...

Нэ понял, в чем проблема.
1. WM_MDIDESTROY.
2. WM_MDINEXT + WM_CLOSE + WM_MDIACTIVATE
Можно еще варианты поискать, но лень.
В крайнем случае, можно было бы посмотреть, как сделано в MFC. Не, я понимаю, конечно, что проще M$ пнуть, но работу-то делать все равно придется.