c++ - 使用 ATL 正确关闭在单独线程上创建的窗口

标签 c++ multithreading winapi com atl

我有一个多线程应用程序,在某些线程上,我正在使用 ATL 的 CWindowImpl<> 创建窗口.我有一个用作线程过程的静态方法。我需要在线程上创建一个窗口,因为我需要与线程进行一些通信以 be synchronous , 和 PostThreadMessage()是明确异步的。当我的窗口收到 WM_DESTROY消息(由 MESSAGE_HANDLER 宏定义的处理程序),它调用 PostQuitMessage() ,如本方法所示:

LRESULT MyATLWindowClass::OnDestroy(UINT uMsg,
                                    WPARAM wParam,
                                    LPARAM lParam,
                                    BOOL& bHandled) {
  ::PostQuitMessage(0);
  return 0;
}

我正在使用 PostThreadMessage() 向线程发送自定义消息向线程表明是时候终止它自己了。处理该自定义消息,我调用 CWindowImpl::DestroyWindow()方法,它似乎确实正确地破坏了窗口,就像我的 OnDestroy正在调用消息处理程序。但是,似乎拥有线程从未收到过 WM_QUIT。消息进行处理。下面包括我的线程过程的简化版本。

unsigned int WINAPI MyATLWindowClass::ThreadProc(LPVOID lpParameter) {
  // Initialize COM on the thread
  ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

  // Create the window using ATL
  MyATLWindowClass new_window;
  HWND session_window_handle = new_window.Create(
      /* HWND hWndParent */ HWND_MESSAGE,
      /* _U_RECT rect */ CWindow::rcDefault,
      /* LPCTSTR szWindowName */ NULL,
      /* DWORD dwStyle */ NULL,
      /* DWORD dwExStyle */ NULL,
      /* _U_MENUorID MenuOrID */ 0U,
      /* LPVOID lpCreateParam */ NULL);

  // Initialize the message pump on the thread.
  MSG msg;
  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

  // Run the message loop
  BOOL get_message_return_value;
  while ((get_message_return_value = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
    if (get_message_return_value == -1) {
      // GetMessage handling logic taken from MSDN documentation
      break;
    } else {
      if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
        // Requested thread shutdown, so destroy the window
        new_window.DestroyWindow();
      } else if (msg.message == WM_QUIT) {
        // Process the quit message and exit the message loop
        // to terminate the thread
        break;
      } else {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
      }
    }
  }

  // Uninitialize COM on the thread before exiting
  ::CoUninitialize();
  return 0;
}

请注意,如果我调用 DestroyWindow() 似乎并不重要或者如果我发送 WM_CLOSE消息到窗口。在这两种情况下,线程的消息泵都没有收到 WM_QUIT。拥有线程的消息泵是否应该接收这样的消息?我对线程的消息泵和窗口的消息泵如何交互的误解在哪里?或者关于 ATL 的窗口类如何创建和管理窗口,我遗漏了什么?

最佳答案

GetMessage() 从不返回 WM_QUIT。该消息强制它返回 0,旨在终止您的消息循环。

当心使用 PostThreadMessage() 的相当大的危险。 永远不要在同时显示窗口的线程上使用它,就像您正在使用的线程一样。问题是它不接受 HWND 参数。所以只有你的消息循环可以看到消息,它不会被传递到任何带有 DispatchMessage() 的窗口。当进入模态消息循环时,这会出错,这是您无法控制的类型。就像使 MessageBox 工作的模态循环一样。或者 Windows 用来允许用户调整窗口大小的那个。或者 DialogBox() 使用的那个。等等。始终使用 PostMessage(),使用您自己的消息编号。

关于c++ - 使用 ATL 正确关闭在单独线程上创建的窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16776506/

相关文章:

c++ - C++程序可以在if/else语句中包含switch语句吗?

Python 异步上下文

android - 异步任务让 UI 卡住

c++ - 将 float 的值打印到小数点后两位

c++ - win32 c++ 在没有子类化的编辑控件中检测到 'enter'?

c++ - boost::asio::steady_timer 在 boost::dll 中不起作用

c++ - 如何停止 QGridLayout 元素的扩展

c++ - 无法使用数据断点 C++,Visual Studio 2013

java - 在 Java 中使用轮询不好吗?

perl - 如何停止使用 Win32::Daemon 启动的 Win32 服务?