天天看点

利用CWinThread实现跨线程父子MFC窗口

下面是示例代码.

从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 ,如需转载请自行联系原作者