Win32: модальное диалоговое окно не возвращает фокус - PullRequest
0 голосов
/ 29 мая 2009

Я пишу классы-оболочки для win32, в основном, чтобы больше узнать о программировании на win32. Чтобы обойти проблему обратных вызовов в стиле c, следующий метод сохраняет / извлекает указатель с помощью SetWindowLong / GetWindowLong и передает его фактическому winproc.

LRESULT CALLBACK WinClass::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // On window creation, WindowProc receives lParam as a LPCREATESTRUCT 
    // Store *this* pointer as long in GWL_USERDATA
    if (msg == WM_NCCREATE)
        ::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams));

    // Retrieve the pointer
    WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLongPtr(hwnd, GWL_USERDATA));

    // Call the actual winproc function
    if (wnd)
        return wnd->WndProc(hwnd, msg, wParam, lParam);
    // Default to DefWindowProc message handler function
    return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

Winclass - это класс, обертывающий главное окно, созданное CreateWindowEx. Та же самая функция WindowProc является частью MDlgClass, заключающего модальное диалоговое окно. Я вызываю диалог, как это

DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(id), hwnd, DialogProc);

Если я передаю NULL как hWndParent, диалоговое окно нормально работает как немодальное диалоговое окно, но если я передаю hwnd, дескриптор главного окна как hWndParent, диалоговое окно работает правильно как модальное диалоговое окно. Однако, когда я закрываю диалог, он не передает управление обратно в главное родительское окно? Отладка в Visual Studio показывает зависание в насосе сообщений в WinMain.

Я думал об использовании хэш-карты для отображения указателей, но я бы предпочел сделать это с помощью GetWindowLong и т. Д. Возможно ли это? Я пытался сохранить указатель диалога в DWL_USER, но это не помогает.

Буду признателен за любую помощь, я все еще думаю о Win32.

РЕДАКТИРОВАТЬ: я уничтожаю диалог с помощью EndDialog

РЕДАКТИРОВАТЬ: я храню указатель в области GWL_USERDATA главного окна, которая не используется окнами, и я изменяю его только в WinClass :: WindowProc, когда окно создается впервые. Если я не создаю экземпляр класса диалога, я знаю, что к указателю обращаются правильно, поскольку приложение отвечает на команды меню, обработанные с помощью WindowProc и WM_COMMAND.

Ответы [ 4 ]

5 голосов
/ 29 мая 2009

Вы не можете использовать WindowProc в качестве DialogProc. Оконные процедуры вызывают DefWindowProc, когда они не обрабатывают сообщение, и возвращают значимый результат, когда они это делают. Диалоговые процедуры возвращают FALSE, когда они не обрабатывают сообщение, возвращают TRUE, когда они ДЕЛАЮТ (кроме случаев, когда они обрабатывают WM_INITDIALOG), и, если они имеют значимый результат, который им необходимо вернуть из процедуры внешнего окна, это помещается в DWL_MSGRESULT.

Когда вы вызываете функцию модального диалогового окна, DialogBox, он входит в цикл прокачки сообщений - который отправляет сообщения всем окнам в потоке, поэтому все окна продолжают рисовать и обрабатывать ввод - когда диалоговое окно закрыто (используя EndDialog) , процедура DialogBox должна вернуться.

При создании класса для переноса диалоговых окон обычным методом является передача указателя 'this' одной из функций DialogBoxParam, которую можно непосредственно извлечь из сообщения WM_INITDIALOG.

0 голосов
/ 31 мая 2009
//static method
BOOL CALLBACK WinClass::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Store *this* pointer as long in GWL_USERDATA
  if (msg == WM_INITDIALOG)
  {
        ::SetWindowLongPtr(hwnd, DWLP_USER, reinterpret_cast(lParam));
        m_hWnd = hWnd; // I assume you really don't want to keep passing the hwnd around
  }

   WinClass* wnd = reinterpret_cast(::GetWindowLongPtr(hwnd, GWL_USERDATA));
   if (wnd)
       return wnd->DlgProcImpl(umsg, wParam, lParam);
   return FALSE;
}

BOOL WinClass::DlgProcImpl(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // your code goes here

            return FALSE;
    }

    return FALSE;
}

INT_PTR WinClass:DoModalDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR template)
{
    return ::DialogBoxParam(hInst, template, hwndParent, WinClass::DlgProc, this);
}

0 голосов
/ 29 мая 2009

Вы сохраняете указатель на lpCreateParams. Возможно ли, что связанный блок памяти освобождается или иным образом уничтожается?

0 голосов
/ 29 мая 2009

Как вы закрываете окно? Вы используете DestroyWindow? Пока дочернее окно активно, родительское окно будет отключено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...