Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

Диалоговые процедуры в классе CDialogImplBaseT<> реализованы более или менее аналогично оконным процедурам в классе CWindowImplBaseT<>.

template <class TBase>

LRESULT CALLBACK CDialogImplBaseT<TBase>::StartDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

 CDialogImplBaseT<TBase>* pThis = (CDialogImplBaseT<TBase>*)_Module.ExtractCreateWndData;

 ATLASSERT(pThis != NULL);

 pThis->m_hWnd = hWnd;

 pThis->m_thunk.Init(pThis->GetDialogProc, pThis);

 WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk);

 WNDPROC pOldProc = (WNDPROC)::SetWindowLong(hWnd, DWL_DLGPROC, (LONG)pProc);

#ifdef _DEBUG

 // check if somebody has subclassed us already since we discard it

 if (pOldProc != StartDialogProc)

ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));

#else

 pOldProc; // avoid unused warning

#endif

 return pProc(hWnd, uMsg, wParam, lParam);

}

template <class TBase>LRESULT CALLBACK CDialogImplBaseT<TBase>::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

 CDialogImplBaseT<TBase>* pThis = (CDialogImplBaseT<TBase>*)hWnd;

 // set a ptr to this message and save the old value

 MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };

 const MSG* pOldMsg = pThis->m_pCurrentMsg;

 pThis->m_pCurrentMsg = &msg;

 // pass to the message map to process

 LRESULT lRes;

 BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);

 // restore saved value for the current message

 ATLASSERT(pThis->m_pCurrentMsg == &msg);

 pThis->m_pCurrentMsg = pOldMsg;

 // set result if message was handled

 if (bRet) {

switch (uMsg) {

case WM_COMPAREITEM:

case WM_VKEYTOITEM:

case WM_CHARTOITEM:

case WM_INITDIALOG:

case WM_QUERYDRAGICON:

case WM_CTLCOLORMSGBOX:

case WM_CTLCOLOREDIT:

case WM_CTLCOLORLISTBOX:

case WM_CTLCOLORBTN:

case WM_CTLCOLORDLG:

case WM_CTLCOLORSCROLLBAR:

case WM_CTLCOLORSTATIC:

return lRes;

break;

}

::SetWindowLong(pThis->m_hWnd, DWL_MSGRESULT, lRes);

return TRUE;

 }

 if (uMsg == WM_NCDESTROY) {

// clear out window handle

HWND hWnd = pThis->m_hWnd;

pThis->m_hWnd = NULL;

// clean up after dialog is destroyed

pThis->OnFinalMessage(hWnd);

 }

 return FALSE;

}

Статическая

функция StartDialogProc назначается диалогу при его создании. Для этого её адрес передаётся функциям, подобным DialogBox и CreateDialog, или задаётся в качестве хука для стандартных диалогов. Получив управление, эта функция извлекает хэндл диалога из объекта _Module и сохраняет его в переменной m_hWnd, затем инициализирует переходник и передаёт управление штатной диалоговой процедуре DialogProc, которая и выполняет дальнейшее обслуживание диалога. Каждое полученное сообщение она "пропускает" через карту сообщений вызовом ProcessWindowMessage. Возвращаемое после обработки сообщения значение интерпретируется в зависимости от типа сообщения. Тем самым обеспечивается небольшое, но весьма приятное удобство: программист не должен помнить, каким образом нужно передать операционной системе LRESULT из диалоговой процедуры (напрямую или с помощью SetWindowLong). Достаточно вернуть его из функции-обработчика, а об остальном позаботится WTL.

Поскольку диалоги, как и все остальные окна, используют для обработки сообщений функцию ProcessWindowMessage, вы можете использовать для её создания уже знакомые вам макросы карты сообщений.

После уничтожения диалога WTL вызывает виртуальную функцию OnFinalMessage. Вы можете переопределить её в производном классе и возложить на неё "очистительные" работы. Следует только иметь в виду, что во время работы этой функции диалог уже не существует, и даже переменная m_hWnd содержит NULL. Поэтому в функции OnFinalMessage нельзя, к примеру, загружать данные из контролов диалога в переменные.

Класс CDialogImpl<>

Класс CDialogImpl<> – основное средство для работы с диалогами в WTL. Он используется как с модальными, так и с немодальными диалогами. Соответственно, в нём содержатся обёртки для функций DialogBoxParam, EndDialog, CreateDialogParam и DestroyWindow. Механизм обработки сообщений наследуется от класса CDialogImplBaseT<>.

Для создания модального диалога используется метод DoModal. Уничтожить модальный диалог можно, используя метод EndDialog (можно вызывать этот метод из любого обработчика сообщений, в том числе из обработчика сообщения WM_INITDIALOG). Реализация обоих методов более чем прямолинейна:

// modal dialogs

int DoModal(HWND hWndParent = ::GetActiveWindow, LPARAM dwInitParam = NULL) {

 ATLASSERT(m_hWnd == NULL);

 _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT<TBase>*)this);

#ifdef _DEBUG

 m_bModal = true;

#endif //_DEBUG

 return

::DialogBoxParam(_Module.GetResourceInstance, MAKEINTRESOURCE(T::IDD),

hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);

}

BOOL EndDialog(int nRetCode) {

 ATLASSERT(::IsWindow(m_hWnd));

Поделиться с друзьями: