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.
I tried PostThreadMessage
, In addition, I tried to use closewindow. But the problem is that WM_DESTORY is not triggered after calling DestroyWindow
, not the PostMessage
.
Message loop thread is still running and window handle is valid, why? I worked hard for a few days and couldn't find the reason, thank you very much.
Destroy 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;
}
A window has a thread affinity. Only the thread that created the window can destroy the window (and receive and dispatch messages for the window). This is clearly stated in the documentation: