September 29, 2005

MFC WinCE и WM_NCDESTROY

Как известно нам из MSDN, "The DestroyWindow function does not support the WM_NCDESTROY or the WM_PARENTNOTIFY message." Т.е. если мы хотим получить управление после того, как был вызван CWnd::Detach() и перед тем, как его виндовая процедура вообще прекратит принимать сообщения какие-либо - то глубоко обламываемся.

Но, на самом деле, не все тут так печально. Ибо MFC все-таки посылает WM_NCDESTROY, несмотря на то, что определение константы сообщения отсутствует в winuser.h:

LRESULT CALLBACK
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	// special message which identifies the window as using AfxWndProc
	if (nMsg == WM_QUERYAFXWNDPROC)
		return 1;

	// all other messages route through message map
	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
	// ...
	// Post-processs WM_DESTROY so we can fake a WM_NCDESTROY.
	// Also route any additional messages to an empty window procedure.
	LRESULT lResult = AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
	if(nMsg == WM_DESTROY) // pseudo-test for "last message"
	{
		pWnd->SendMessage(WM_NCDESTROY); // Вот оно =)
		::SetWindowLong(hWnd,GWL_WNDPROC,(LONG)wce_NullWndProc);
	}
	return lResult;
}

В принципе, кроме определения самой константы сообщения, в MFC для этого все есть: и метод CWnd::OnNcDestroy(), и ON_WM_NCDESTROY() тоже задефайнен.

#define WM_NCDESTROY              (WM_APP-1)

Зачем вообще это нужно? Не знаю =) Например для того, чтобы убить CWnd из самого себя по delete, ибо после WM_NCDESTROY уже никакие сообщения к окну не придут, и оно detached от хендла:

void CMyPage::OnNcDestroy() 
{
	CMyPage::OnNcDestroy();
	delete this; // Где бы мы не убивали окно, оно само себя освободит
}