0

マルチスレッド アプリケーションがあり、特定のスレッドで、ATL を使用してウィンドウを作成していますCWindowImpl<>。スレッド プロシージャとして使用している静的メソッドがあります。スレッドとの通信の一部をsynchronousにする必要があり、PostThreadMessage()明示的に非同期であるため、スレッドにウィンドウを作成する必要があります。ウィンドウがメッセージ (マクロでWM_DESTROY定義されたハンドラー)を受け取ると、次のメソッドに示すように、 を呼び出します。MESSAGE_HANDLERPostQuitMessage()

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 のウィンドウ クラスがウィンドウを作成および管理する方法について何が欠けているのでしょうか?

4

2 に答える 2

1

GetMessage() が WM_QUIT を返すことはありません。そのメッセージは、代わりに 0 を返すように強制し、メッセージ ループを終了するように設計されています。

PostThreadMessage() の使用にはかなりの危険があることに注意してください。使用しているようなウィンドウも表示するスレッドでは使用しないでください。問題は、HWND 引数を取らないことです。したがって、メッセージループだけがメッセージを見ることができ、DispatchMessage() を使用してウィンドウに配信されることはありません。これは、制御できないようなモーダル メッセージ ループに入るとうまくいきません。MessageBox を機能させるモーダル ループのように。または、ユーザーがウィンドウのサイズを変更できるようにするために Windows が使用するもの。または DialogBox() が使用するもの。など。常に PostMessage() を使用し、独自のメッセージ番号を使用してください。

于 2013-05-27T18:30:57.720 に答える