На самом деле существует довольно много способов сохранить контекст для ваших оконных процедур, и диалоги - это просто особый случай окон, поэтому эти методы применимы.
Одним из способов, как вы упомянули, является использование GWLP_USERDATA
/ GetWindowLongPtr()
/ SetWindowLongPtr()
для хранения указателя на контекст диалога. Обратите внимание, что функции имеют префикс Ptr()
. Эти функции будут работать с 32-битным и 64-битным кодом. Функции «не Ptr()
» работают только с 32-битным кодом, поэтому их не следует использовать.
В соответствии с документацией для GetWindowLongPtr()
значение GWLP_USERDATA
изначально установлено на ноль. Таким образом, вы всегда можете рассчитывать на проверку того, вернет ли GetWindowLongPtr()
ноль, и на этом этапе возвращает FALSE
из диалоговой процедуры.
Процедура диалога с использованием этих функций может выглядеть примерно так:
// MyDialogProc is a static function in MyDialogClass. Can also be a global function.
INT_PTR CALLBACK MyDialogClass::MyDialogProc(HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
MyDialogClass* target = 0;
if(uMsg == WM_INITDIALOG)
{
target = reinterpret_cast<MyDialogClass*>(lParam);
::SetWindowLongPtr(hwndDlg, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(target));
}
target = reinterpret_cast<MyDialogClass*>(
::GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
if(target != 0)
{
// Something like this
return target->ProcessMessage(hwndDlg, uMsg, wParam, lParam);
}
return FALSE;
}
И ваш код создания диалога передает указатель на экземпляр MyDialogClass
, используя функцию-член, возможно, такую:
void MyDialogClass::Create()
{
// ....
// Use CreateDialogParam() or friends to create a dialog and pass
// the context pointer.
HWND h = ::CreateDialogParam(hInstance, lpTemplateName, hWndParent,
&MyDialogClass::MyDialogProc, reinterpret_cast<LPARAM>(this));
// ....
}
Если вы предпочитаете другой метод (поскольку вы беспокоитесь, что кто-то другой напишет поверх GWLP_USERDATA
), вы можете использовать GetProp () / SetProp () / RemoveProp () и придумайте уникальное имя для идентификации указателя. GetProp()
возвращает ноль, если не удается найти свойство, поэтому вы снова можете рассчитывать, что оно вернет ноль Это метод, который я использую в своей библиотеке / фреймворке.
Процедура диалога, использующая функции свойств, может выглядеть примерно так:
const wchar_t* myDialogClassContextPtrName = L"MyDlgClsCxtPtr"; // Unicode
// const char* myDialogClassContextPtrName = "MyDlgClsCxtPtr"; // ANSI
// MyDialogProc is a static function in MyDialogClass. Can also be a global function.
INT_PTR CALLBACK MyDialogClass::MyDialogProc(HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
MyDialogClass* target = 0;
if(uMsg == WM_INITDIALOG)
{
target = reinterpret_cast<MyDialogClass*>(lParam);
::SetProp(hwndDlg, myDialogClassContextPtrName,
reinterpret_cast<HANDLE>(target));
}
target = reinterpret_cast<MyDialogClass*>(
::GetProp(hwndDlg, myDialogClassContextPtrName));
if(target != 0)
{
// Something like this
INT_PTR returnValue = target->ProcessMessage(hwndDlg, uMsg, wParam, lParam);
if(uMsg == WM_NCDESTROY)
{
::RemoveProp(hwndDlg, myDialogClassContextPtrName);
}
return returnValue;
}
return FALSE;
}
Как вы уже видели, есть сообщения, которые отправляются до сообщения WM_INITDIALOG
(или сообщения WM_NCCREATE
для не диалоговых окон). По моему опыту, эти сообщения несущественны и никак не повлияют на функциональность вашей процедуры. Вы можете вернуть FALSE
для сообщений, которые вы получили до WM_INITDIALOG
.