Why is DestoryWindow blocked?

勇强 韩 136 Reputation points
2021-05-04T00:33:10.457+00:00

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 - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,413 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Song Zhu - MSFT 906 Reputation points
    2021-05-04T02:11:29.717+00:00

    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.

    0 comments No comments