У меня есть диалоговый класс, созданный из шаблона диалога в памяти, который запускает свой собственный вложенный цикл сообщений (в дополнение к основному циклу сообщений приложения).
Для создания диалога я использую CreateDialogIndirectParamW
, который возвращает дескриптордиалоговое окно,
Поскольку диалоговое окно полностью настроено, вся обработка и создание сообщения выполняется вручную.
Я пропустил процедуру диалога, но в основном она вызывает нижеприведенные соответствующие обработчики сообщений, как толькодиалог закрывается.
Обратите внимание, что мы не можем использовать функцию EndDialog
для уничтожения диалога и завершения цикла сообщений, потому что для CreateDialogIndirectParamW
мы должны явно использовать DestroyWindow
.
Я ищу эффективный способ завершения диалогового цикла.
Я пытался реализовать этот цикл , но проблема в том, что этот подход потребляет слишком много ресурсов ЦП, поскольку for
цикл в примере кода будет просто работать глупо, пока не появится сообщение, или если for
опущено, то PeekMessage
немедленно остановит цикл, а это не то, что я не хочу.
Соответствующее объявление класса:
class Dialog :
public ContainerWindow,
public MessageWindow,
public SuperClassWindow
{
// ...
public:
/** Process messages for dialog window */
[[nodiscard]] int RunMessageLoop() override;
protected:
/** Handler for WM_NCDESTROY */
std::uint32_t OnNcDestroy(const UINT& uMsg, const WPARAM& wParam, const LPARAM& lParam) override;
/** Handler for WM_DESTROY */
inline void OnDestroy() const noexcept override;
/** Handler for WM_CLOSE */
inline virtual bool OnClose() noexcept;
// ...
protected:
HWND mhWnd; /** Window handle of derived component */
}
Упрощенное определение класса:
std::uint32_t Dialog::OnNcDestroy(
[[maybe_unused]] const UINT& uMsg,
[[maybe_unused]] const WPARAM& wParam,
[[maybe_unused]] const LPARAM& lParam)
{
// ...
delete this; // note we can't set this pointer to nullptr!
// ...
return count;
}
void Dialog::OnDestroy() const noexcept
{
PostQuitMessage(0);
}
bool Dialog::OnClose() noexcept
{
return DestroyWindow(mhWnd);
}
А вот цикл сообщений для диалога: мне нужно добавить проверочный код в цикл, чтобы проверить, является ли диалог допустимым объектом, то есть как-то остановить цикл, если объект Dialog был удален
После того, какОбработчик OnNcDestroy
вызван, IsDialogMessageW
ниже произойдет сбой, см. Комментарий.
Похоже, GetMessageW
продолжит работать после отправки WM_NCDESTROY
, цикл все еще ожидает WM_QUIT
, отправленный *Обработчик 1045 *, поэтому цикл msg продолжит работать после удаления объекта Dialog, что приведет к сбою IsDialogMessageW(mhWnd, &msg)
ниже. поскольку mhWnd
больше не существует.
int Dialog::RunMessageLoop()
{
EnableWindow(mhWndParent, FALSE);
MSG msg{ };
BOOL result = FALSE;
while ((result = GetMessageW(&msg, nullptr, 0, 0)) != FALSE)
{
if (result == -1)
{
ShowError(ERR_BOILER); // error checking function.
break;
}
// once OnNcDestroy is called "mhWnd" is invalid memory
// and this will off course cause access violation!
if (!IsDialogMessageW(mhWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
EnableWindow(mhWndParent, TRUE);
return static_cast<int>(msg.wParam);
}
обратите внимание, что мы не можем if (this)
, поскольку this
не является nullptr
и не может быть установлено на nullptr
в OnNcDestroy
обработчик.