question

yoestar avatar image
0 Votes"
yoestar asked SongZhu-MSFT edited

Why is DestoryWindow blocked?

I create a window and message loop in the child thread.
When I sent a custom message through PostMessage, when I called DestroyWindow in the thread, DestroyWindow blocked and did not trigger WM_DESTORY, so the message loop thread cannot exit normally.

Destory window:

 #define WM_QUIT_MSG_LOOP (WM_USER+8600)
 mfxStatus CD3D11Device::DeleteRenderChildWindow()
 {
     LOG(LS_INFO) << "Intel D3D11Render, Enter DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
    
     //SetParent(m_hChildHwnd, NULL);
     if (m_hChildHwnd){
         LOG(LS_WARNING) << "Intel D3D11Render, DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
         PostMessage(m_hChildHwnd, WM_QUIT_MSG_LOOP, NULL, NULL);
     }
        
     if(m_pChildWindowMsgThread)
         m_pChildWindowMsgThread->Wait();
    
     MSDK_SAFE_DELETE(m_pChildWindowMsgThread);
     MSDK_SAFE_DELETE(m_pCreateFinishEvent);
     LOG(LS_INFO) << "Intel D3D11Render, Leave DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
    
     return MFX_ERR_NONE;
 }

Create window:

 LRESULT CALLBACK CD3D11Device::ChildRenderMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
         LRESULT lResult = 0;
         switch (uMsg) {
         case WM_DESTROY: {
             LOG(LS_WARNING) << "Intel D3D11Render ChildRenderMsgProc, PostQuitMessage, HWND:" << hwnd;
             PostQuitMessage(0);
             break;
         }
         case WM_SETCURSOR: {
             break;
         }
         default:
             lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
             break;
         }
        
         return lResult;
     }
        
     HWND CD3D11Device::ThreadCreateChildWindow(){
         HMODULE hInstance = nullptr;
         BOOL result =
             GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                 reinterpret_cast<char*>(&DefWindowProc), &hInstance);
        
         if (!result) {
             LOG(LS_ERROR) << "[ThreadCreateChildWindow]GetModuleHandleExA failed.";
             return 0;
         }
        
         // Register the host window class. See the MSDN documentation of the
         WNDCLASSEXW wcex = {};
         wcex.cbSize = sizeof(WNDCLASSEX);
         wcex.lpfnWndProc = &ChildRenderMsgProc;
         wcex.hInstance = hInstance;
         wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
         wcex.lpszClassName = _T("Render Window Class");
         //wcex.style |= CS_HREDRAW | CS_VREDRAW &~WS_CAPTION &~WS_SYSMENU;
        
         // Ignore the error which may happen when the class is already registered.
         RegisterClassExW(&wcex);
        
         RECT rcClient = { 0 };
         GetWindowRect(m_HandleWindow, &rcClient);
         // Create the host window.
         HWND hChildWindow =
             CreateWindowW(_T("Render Window Class"), _T("MiniRender"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0,
                 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, m_HandleWindow, nullptr, hInstance, nullptr);
         if (!hChildWindow) {
             LOG(LS_ERROR) << "[ThreadCreateChildWindow]Create child window failed.";
             return 0;
         }
        
         ShowWindow(hChildWindow, SW_SHOW);
         SetRenderChildHwnd(hChildWindow);
         m_pCreateFinishEvent->Signal();
         LOG(LS_WARNING) << "Intel D3D11Render, ThreadCreateChildWindow, HWND:" << hChildWindow;
        
         return hChildWindow;
     }

Message loop thread:

 unsigned int CD3D11Device::ChildWindowMsgThread(void* ctx){
         CD3D11Device* pD3D11Device = static_cast<CD3D11Device*>(ctx);
        
         HWND hChildWindow = NULL;
         if (pD3D11Device) {
             hChildWindow = pD3D11Device->ThreadCreateChildWindow();
         }
        
         if (hChildWindow == NULL){
             return 0;
         }
            
         MSG msg;
         BOOL result;
         while ((result = GetMessage(&msg, NULL, 0, 0)) != 0) {
             if (result == -1) {
                 LOG(LS_ERROR) << "Intel D3D11Render, ChildWindowMsgThread, GetMessage failed, HWND:" << hChildWindow;
                 continue;
             }
        
             if (msg.message == WM_QUIT_MSG_LOOP) {
                 LOG(LS_WARNING) << "Intel D3D11Render, ChildWindowMsgThread, recv WM_QUIT_MSG_LOOP, HWND:" << hChildWindow;

//It's blocking up here

                 DestroyWindow(hChildWindow);
             }
             else {
                 PostMessage(pD3D11Device->GetParentHwnd(), msg.message, msg.wParam, msg.lParam);
             }
        
             LOG(LS_WARNING) << "Intel D3D11Render, ChildWindowMsgThread, GetMessageing, HWND:" << hChildWindow;
             TranslateMessage(&msg);
             DispatchMessage(&msg);
         }
        
         return 0;
     }
windows-api
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Did you try to handle WM_QUIT_MSG_LOOP inside the ChildRenderMsgProc as usually, not in the message loop?


0 Votes 0 ·

1 Answer

SongZhu-MSFT avatar image
0 Votes"
SongZhu-MSFT answered SongZhu-MSFT edited

I think the reason you are trying to destroy the window through an external thread.

According to the MSDN:

A thread cannot use DestroyWindow to destroy a window created by a different thread.


More references: A window transparent overlay stops working after a few seconds, How to provoke “Application not responding”


If the answer is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.