关于子线程中销毁主线程窗口的问题
通常销毁或者关闭窗口会用如下函数:
[1] CWnd::DestroyWindow()
[2] CFrameWnd::OnClose()
[3] ::SendMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0);
或者::SendMessage(hWnd,WM_CLOSE,NULL,NULL);
之间的关系如下:
After runing the function sendMessage(),thefunction OnClose() will be excuted;
in the function OnClose() , DestroyWindow() will be called in the end
/
// CFrameWnd closing down
void CFrameWnd::OnClose()
{
if (m_lpfnCloseProc != NULL)
{
// if there is a close proc, then defer to it, and return
// after calling it so the frame itself does not close.
(*m_lpfnCloseProc)(this);
return;
}
// Note: only queries the active document
CDocument* pDocument = GetActiveDocument();
if (pDocument != NULL && !pDocument->CanCloseFrame(this))
{
// document can't close right now -- don't close it
return;
}
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
CDataRecoveryHandler *pHandler = pApp->GetDataRecoveryHandler();
if ((pHandler != NULL) && (pHandler->GetShutdownByRestartManager()))
{
// If the application is being shut down by the Restart Manager, do
// a final autosave. This will mark all the documents as not dirty,
// so the SaveAllModified call below won't prompt for save.
pHandler->AutosaveAllDocumentInfo();
pHandler->SaveOpenDocumentList();
}
// attempt to save all documents
if (pDocument == NULL && !pApp->SaveAllModified())
return; // don't close it
if ((pHandler != NULL) && (!pHandler->GetShutdownByRestartManager()))
{
// If the application is not being shut down by the Restart Manager,
// delete any autosaved documents since everything is now fully saved.
pHandler->DeleteAllAutosavedFiles();
}
// hide the application's windows before closing all the documents
pApp->HideApplication();
// close all documents first
pApp->CloseAllDocuments(FALSE);
// don't exit if there are outstanding component objects
if (!AfxOleCanExitApp())
{
// take user out of control of the app
AfxOleSetUserCtrl(FALSE);
// don't destroy the main window and close down just yet
// (there are outstanding component (OLE) objects)
return;
}
// there are cases where destroying the documents may destroy the
// main window of the application.
if (!afxContextIsDLL && pApp->m_pMainWnd == NULL)
{
AfxPostQuitMessage(0);
return;
}
}
// detect the case that this is the last frame on the document and
// shut down with OnCloseDocument instead.
if (pDocument != NULL && pDocument->m_bAutoDelete)
{
BOOL bOtherFrame = FALSE;
POSITION pos = pDocument->GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = pDocument->GetNextView(pos);
ENSURE_VALID(pView);
if (pView->GetParentFrame() != this)
{
bOtherFrame = TRUE;
break;
}
}
if (!bOtherFrame)
{
pDocument->OnCloseDocument();
return;
}
// allow the document to cleanup before the window is destroyed
pDocument->PreCloseFrame(this);
}
// then destroy the window
DestroyWindow();
}
//
BOOL CWnd::DestroyWindow()
{
CWnd* pWnd;
CHandleMap* pMap;
HWND hWndOrig;
BOOL bResult;
if ((m_hWnd == NULL) && (m_pCtrlSite == NULL))
return FALSE;
bResult = FALSE;
pMap = NULL;
pWnd = NULL;
hWndOrig = NULL;
if (m_hWnd != NULL)
{
pMap = afxMapHWND();
ENSURE(pMap != NULL);
pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
#ifdef _DEBUG
hWndOrig = m_hWnd;
#endif
}
#ifdef _AFX_NO_OCC_SUPPORT
if (m_hWnd != NULL)
bResult = ::DestroyWindow(m_hWnd);
#else //_AFX_NO_OCC_SUPPORT
if ((m_hWnd != NULL) || (m_pCtrlSite != NULL))
{
if (m_pCtrlSite == NULL)
bResult = ::DestroyWindow(m_hWnd);
else
bResult = m_pCtrlSite->DestroyControl();
}
#endif //_AFX_NO_OCC_SUPPORT
if (hWndOrig != NULL)
{
// Note that 'this' may have been deleted at this point,
// (but only if pWnd != NULL)
if (pWnd != NULL)
{
// Should have been detached by OnNcDestroy
#ifdef _DEBUG
ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);
#endif
}
else
{
#ifdef _DEBUG
ASSERT(m_hWnd == hWndOrig);
#endif
// Detach after DestroyWindow called just in case
Detach();
}
}
return bResult;
}
在子线程里面想关闭或销毁主窗口,不能用方法[1][2],因为在子线程中调用DestroyWindow()的时候 ,
pMap = afxMapHWND()会出现问题:pMap = 0.而正常情况下要保证ENSURE(pMap != NULL);
而方法[3]会是正确的销毁窗口的方法。