我正在使用ATL来构建我的软件。我创建了一个主框架窗口,其中包含serviral childen窗口。其中一个儿童窗户也有一些带有窗户的窗户。
现在,我的应用程序总是会失败断言:
virtual ~CWindowImplRoot()
{
#ifdef _DEBUG
if(m_hWnd != NULL) // should be cleared in WindowProc
{
ATLTRACE(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed\n"));
ATLASSERT(FALSE);
}
#endif //_DEBUG
}
我为任何窗口定义了WM_NCDESTROY处理程序并设置了bHanded = FALSE,代码可以到达那里。
我再添加OnFinalMessage覆盖功能。不幸的是,没有所有的功能都可以调用。实际上,将调用顶级窗口的OnFinalMessage,可能不会调用中级窗口'OnFinalMessage,永远不会调用底层窗口'OnFinalMessage。
我查看了ATL的源代码:
template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
// set a ptr to this message and save the old value
_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
pThis->m_pCurrentMsg = &msg;
// pass to the message map to process
LRESULT lRes = 0;
BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
// restore saved value for the current message
ATLASSERT(pThis->m_pCurrentMsg == &msg);
// do the default processing if message was not handled
if(!bRet)
{
if(uMsg != WM_NCDESTROY)
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
else
{
// unsubclass, if needed
LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
// mark window as destryed
pThis->m_dwState |= WINSTATE_DESTROYED;
}
}
if((pThis->m_dwState & WINSTATE_DESTROYED) && pOldMsg== NULL)
{
// clear out window handle
HWND hWndThis = pThis->m_hWnd;
pThis->m_hWnd = NULL;
pThis->m_dwState &= ~WINSTATE_DESTROYED;
// clean up after window is destroyed
pThis->m_pCurrentMsg = pOldMsg;
pThis->OnFinalMessage(hWndThis);
}else {
pThis->m_pCurrentMsg = pOldMsg;
}
return lRes;
}
在上面的代码中,变量“pOldMsg”的目的是指示调用堆栈级别。如果“pOldMsg”不等于NULL,则表示不返回调用堆栈。当它为NULL时,表示调用堆栈是最外层的,此刻我们现在可以调用OnFinalMessage函数。
就我而言,似乎有时“pOldMsg”永远不会等于NULL。
聊天:
MainFrame V
|----- ViewDevices V
|----- ViewContainer X
|----- ViewBooks X
|----- ViewFiles V
经过多次测试后,我发现,如果我没有向ViewBooks(ListView)窗口添加任何内容,那么每件事都可以。一旦我只添加一行,这个问题就会重现。我不知道通过交叉线程发送消息是否会导致问题。
有人可以给我一些建议吗?