下面是示例代码.
从CWinThread派生一个CUIThread类,可以利用VS向导生成,再添加一个成员:HWND m_hParentWnd.
创建一个对话框类CUIChildDlg,同样用VS向导生成.
子窗口所在的线程.
class CUIThread : public CWinThread
{
DECLARE_DYNCREATE(CUIThread)
protected:
CUIThread(); // protected constructor used by dynamic creation
virtual ~CUIThread();
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
DECLARE_MESSAGE_MAP()
HWND m_hParentWnd; //注意,它是父窗口句柄,不能是CWnd*对象.
};
在线程中创建对话框窗口.
BOOL CUIWinThread::InitInstance()
// TODO: perform and per-thread initialization here
ASSERT(::IsWindow(m_ hParentWnd));
CWnd* pParent = CWnd::FromHandle(m_hParentWnd);//注意这行
CUIChildDlg* pDlg = new CUIChildDlg(pParent);
pDlg->Create(CUIChildDlg::IDD, pParent);
pDlg->ShowWindow(SW_SHOW);
return TRUE;
}
在这个函数中,创建了一个对话框,作为主窗口的子窗口.
注意这个FromHandle的调用,他返回一个CWnd对象.
这样创建的窗口不会报错.如果直接将主窗口对象传递过来,而不是通过调用FromHandle获取,则调用pDlg->Create会报错,在调试版本中会弹出一个窗口,指出错误位置.
CUIChildDlg是利用向导随便写的一个对话框.注意要重载下面这个函数.
void CUIChildDlg::OnNcDestroy()
CDialog::OnNcDestroy();
// TODO: Add your message handler code here
::PostQuitMessage(0);//为了使线程自动退出.
下面代码是CWinApp派生类,主窗口在这个类中创建.
BOOL CMFCSingleDocTestApp::InitInstance()
... …
// The one and only window has been initialized, so show and update it
m_pMainWnd->ShowWindow(SW_SHOW);//主窗口
m_pMainWnd->UpdateWindow();
// call DragAcceptFiles only if there's a suffix
// In an SDI app, this should occur after ProcessShellCommand
m_pUIThread = (CUIWinThread*)AfxBeginThread(RUNTIME_CLASS(CUIWinThread),
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);//创建后先不要启动.
m_pUIThread->m_hParentWnd = m_pMainWnd->m_hWnd;//主窗口句柄.
m_pUIThread->ResumeThread();
退出函数实现.
int CMFCSingleDocTestApp::ExitInstance()
//TODO: handle additional resources you may have added
AfxOleTerm(FALSE);
ASSERT(NULL != m_pUIThread);
::WaitForSingleObject(m_pUIThread->m_hThread, INFINITE);
return CWinAppEx::ExitInstance();
等待函数是必须的,这是为了等待子窗口线程退出后父窗口线程再退出.
在测试中发现,关闭主窗口之前只能保证先关闭子窗口,但退出主线程之前并不能保证子窗口线程一定会退出,这可能会导致某些资源不能正确释放,所以这里要调用等待函数,从而保证子窗口线程能够正常退出.
跨线程父子窗口的好处是创建子窗口阻塞时不会影响父窗口的运行.例如启动程序时,创建子窗口过程中由于加载太多内容而阻塞,导致父窗口无法操作,分属不同线程后,父窗口运行不受影响,它仍然可以正常启动,最大最小化,移动,响应鼠标消息等等.
但也不完全是这样,程序运行起来之后,子窗口也会使用父窗口所在的线程消息循环,如果子窗口阻塞,同样会导致父窗口阻塞.
本文转自jetyi51CTO博客,原文链接:http://blog.51cto.com/jetyi/1074315 ,如需转载请自行联系原作者