MFC(7) 利用CWinThread实现跨线程父子MFC窗口
2017-11-30 16:49
519 查看
http://jetyi.blog.51cto.com/1460128/1074315/
原则上,MFC对象只能由创建该对象的线程访问,而不能由其它线程访问.这是因为MFC窗口中有一个Windows handle maps, 这个maps同线程相关,也就是说该线程一定会访问该maps,而且该线程创建的MFC窗口对象一定会放到该maps中,如果没有就会报错.但是如果其它线程将一个窗口对象传到该线程,因为这个窗口没有在该线程maps中,所以就会报错.但是MFC也给出了跨线程访问MFC窗口对象的办法,一种办法就是就是不传递窗口对象,而是传递窗口句柄;另外一种办法就是在接收窗口句柄的线程中使用FromHandle构造一个新的窗口对象并加入maps中.详细信息参考 Multithreading:
Programming Tips.
下面是示例代码.
从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();
protected:
DECLARE_MESSAGE_MAP()
public:
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();
return TRUE;
}
退出函数实现.
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();
}
等待函数是必须的,这是为了等待子窗口线程退出后父窗口线程再退出.
在测试中发现,关闭主窗口之前只能保证先关闭子窗口,但退出主线程之前并不能保证子窗口线程一定会退出,这可能会导致某些资源不能正确释放,所以这里要调用等待函数,从而保证子窗口线程能够正常退出.
跨线程父子窗口的好处是创建子窗口阻塞时不会影响父窗口的运行.例如启动程序时,创建子窗口过程中由于加载太多内容而阻塞,导致父窗口无法操作,分属不同线程后,父窗口运行不受影响,它仍然可以正常启动,最大最小化,移动,响应鼠标消息等等.
但也不完全是这样,程序运行起来之后,子窗口也会使用父窗口所在的线程消息循环,如果子窗口阻塞,同样会导致父窗口阻塞.
对于跨线程MFC对象使用问题,MSDN已经介绍过来,可以参考Multithreading
with C++ and MFC.
有一位网友介绍的更详细,参考如何在工作线程中创建窗口?.只不过他使用的是工作线程,而不是MFC提供的UI线程.
原则上,MFC对象只能由创建该对象的线程访问,而不能由其它线程访问.这是因为MFC窗口中有一个Windows handle maps, 这个maps同线程相关,也就是说该线程一定会访问该maps,而且该线程创建的MFC窗口对象一定会放到该maps中,如果没有就会报错.但是如果其它线程将一个窗口对象传到该线程,因为这个窗口没有在该线程maps中,所以就会报错.但是MFC也给出了跨线程访问MFC窗口对象的办法,一种办法就是就是不传递窗口对象,而是传递窗口句柄;另外一种办法就是在接收窗口句柄的线程中使用FromHandle构造一个新的窗口对象并加入maps中.详细信息参考 Multithreading:
Programming Tips.
下面是示例代码.
从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();
protected:
DECLARE_MESSAGE_MAP()
public:
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();
return TRUE;
}
退出函数实现.
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();
}
等待函数是必须的,这是为了等待子窗口线程退出后父窗口线程再退出.
在测试中发现,关闭主窗口之前只能保证先关闭子窗口,但退出主线程之前并不能保证子窗口线程一定会退出,这可能会导致某些资源不能正确释放,所以这里要调用等待函数,从而保证子窗口线程能够正常退出.
跨线程父子窗口的好处是创建子窗口阻塞时不会影响父窗口的运行.例如启动程序时,创建子窗口过程中由于加载太多内容而阻塞,导致父窗口无法操作,分属不同线程后,父窗口运行不受影响,它仍然可以正常启动,最大最小化,移动,响应鼠标消息等等.
但也不完全是这样,程序运行起来之后,子窗口也会使用父窗口所在的线程消息循环,如果子窗口阻塞,同样会导致父窗口阻塞.
对于跨线程MFC对象使用问题,MSDN已经介绍过来,可以参考Multithreading
with C++ and MFC.
有一位网友介绍的更详细,参考如何在工作线程中创建窗口?.只不过他使用的是工作线程,而不是MFC提供的UI线程.
相关文章推荐
- 利用CWinThread实现跨线程父子MFC窗口
- MFC(7) 利用CWinThread实现跨线程父子MFC窗口
- 利用CWinThread实现跨线程父子MFC窗口
- 利用CWinThread实现跨线程父子MFC窗口
- MFC中利用多线程实现opencv视频窗口多画面
- 通过继承CWinThread实现MFC多线程
- 新手使用MFC基于CWinThread实现线程通信
- ACE利用ACE_Thread_Mutex实现线程间互斥访问临界区
- python之win32下,枚举进程,线程和线程对应的窗口的利用ctypes实现
- 利用主线程与子线程间的消息通讯,实现任务处理队列.子线程中创建不会阻塞执行的窗口
- 利用Java线程Thread实现接口Runnable接口使图片动起来
- 用 MFC 类库编程实现工作者线程
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Java_利用多线程实现窗口组件背景图大小按比例变化
- MFC消息三部曲(2)——线程中控制窗口内容
- (转)从头开始如何利用MFC分割窗口
- winPcap+MFC实现网络嗅探器
- MFC中利用MSComm控件实现串口通信的例子
- 第01天多线程网络:(11):NSThread实现线程间通信
- 在mfc中利用opencv打开摄像头并显示在窗口上