浅谈MFC多进程编程,ui卡死问题
2015-04-16 11:34
1201 查看
由于工作需求,最近需要把公司游戏登陆器改成用多进程实现,把主窗口和游戏窗口各自独立一个进程,目的是为了以后实现多开后界面不至于太卡且一个窗口崩掉后不至于影响其他游戏窗口。
以前从来没写过多进程,完全不懂怎么着手,只好拿着总监给的例子先认真研究了下,一边看例子一边问身边有过这方面经验的人。基本思路是,程序一启动在OnInitDialog函数调用CreateProcess创建子进程,并把父窗口的窗口句柄和url通过命令行传给子进程。在app实例InitInstance接口处添加命令行参数的解析,通过解析出来的启动参数就知道是否是子进程启动。子进程启动后把子进程的窗口和父进程的窗口设成父子关系(SetParent),这样父窗口移动子窗口就自然跟着移动了,而进程间的通信则可以通过发送消息的方式来传递。以下是关键代码(项目是居于对话框的):
一切时候都那么的顺利,而且子窗口里只有一个IE控件用于打开url。
写好后,运行起来,发现这里有两个问题,1、登陆器窗口非顶层窗口,如别的窗口在登陆器窗口上面时鼠标点击游戏窗口(即子进程的子窗口)整个登陆器窗口不会置顶。2、点击主窗口上的关闭/最小化等按钮时,整个登陆器卡死(只能用任务管理器关掉进程了)。
第一个问题我找我哥(同行)帮忙解决了,第二个问题,一直没找到解决方案,也不理解为什么会卡死,网上也搜到了很多这样的帖子,有人说要用钩子或子类化的方法拦截消息,也有人说用sdk和多文档就不存在这个问题,但都没找到解决方案。经过了两个多星期的纠结,几乎要绝望了,难道我要基于sdk重写吗?根本没时间了。
我已经放弃了,直接跟总监说我搞不定,但心里还是很不舒服(我想是程序员都能理解这个感受)。后来不经意间我想到了我的大学老师,于是我打电话给他满聊聊,听听他的看法。过了两天,他发q跟我说解决了,内心由衷的高兴啊,感激涕零。
把子窗口的Style属性改成Child,Visible属性改成True,创建子窗口的时候改成非模式的方式创建子窗口,所有的问题就这么迎刃而解了。
虽然为什么这么改就解决了,且第一个问题也都自然解决了,我不知道是为什么,但一定跟DoModal机制有很大的关系,欢迎高手指教!
ps:
1、 窗口句柄跨进程传送是可行的,因为窗口句柄是全局的,所以跨进程传送也是安全的
2、在父窗口中最好不要直接通过子窗口句柄操作子窗口,比如MoveWindow改变子窗口大小,应该发消息到子窗口移动,因为窗口对象不是多线程安全的,多个线程同时访问可能会导致数据被误读或破坏
源码下载例子:
http://download.csdn.net/detail/huasonl88/8600603
以前从来没写过多进程,完全不懂怎么着手,只好拿着总监给的例子先认真研究了下,一边看例子一边问身边有过这方面经验的人。基本思路是,程序一启动在OnInitDialog函数调用CreateProcess创建子进程,并把父窗口的窗口句柄和url通过命令行传给子进程。在app实例InitInstance接口处添加命令行参数的解析,通过解析出来的启动参数就知道是否是子进程启动。子进程启动后把子进程的窗口和父进程的窗口设成父子关系(SetParent),这样父窗口移动子窗口就自然跟着移动了,而进程间的通信则可以通过发送消息的方式来传递。以下是关键代码(项目是居于对话框的):
//InitInstance解析命令行参数 BOOL CMultiProcTest2App::InitInstance() { HWND frameWnd = NULL; CString gameUrl; CString cmd = GetCommandLine();; int pos = cmd.Find(_T("-frameWnd=")); if (pos != -1) { cmd = cmd.Mid(pos+10); pos = cmd.Find(_T(" ")); if (pos != -1) { CString temp(cmd); temp = temp.Left(pos); frameWnd = (HWND) _ttol(temp.GetBuffer()); } cmd = cmd.Mid(pos); } pos = cmd.Find(_T("-gameurl=")); if (pos != -1) { gameUrl = cmd.Mid(pos + 9); } if (frameWnd) { CGameWndDlg dlgGame(frameWnd); m_pMainWnd = &dlgGame; dlgGame.DoModal(); } else { CLander_G2Dlg dlg; m_pMainWnd = &dlg; dlg.DoModal(); } return FALSE; } //创建子进程 void CreateChildProcess(HWND parentHwnd, CString gameUrl) { TCHAR path[1024] = {0}; TCHAR cmd[1024] = {0}; GetModuleFileName(NULL, path, sizeof(path)); wsprintf(cmd, _T("\"%s\" -frameWnd=%ld -gameurl=%s"), path, (long)parentHwnd, gameUrl); STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = TRUE; BOOL f = CreateProcess( NULL, cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS/*CREATE_NO_WINDOW*/, NULL, NULL, &si, &pi ); if (!f){ return ; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); }
一切时候都那么的顺利,而且子窗口里只有一个IE控件用于打开url。
写好后,运行起来,发现这里有两个问题,1、登陆器窗口非顶层窗口,如别的窗口在登陆器窗口上面时鼠标点击游戏窗口(即子进程的子窗口)整个登陆器窗口不会置顶。2、点击主窗口上的关闭/最小化等按钮时,整个登陆器卡死(只能用任务管理器关掉进程了)。
第一个问题我找我哥(同行)帮忙解决了,第二个问题,一直没找到解决方案,也不理解为什么会卡死,网上也搜到了很多这样的帖子,有人说要用钩子或子类化的方法拦截消息,也有人说用sdk和多文档就不存在这个问题,但都没找到解决方案。经过了两个多星期的纠结,几乎要绝望了,难道我要基于sdk重写吗?根本没时间了。
我已经放弃了,直接跟总监说我搞不定,但心里还是很不舒服(我想是程序员都能理解这个感受)。后来不经意间我想到了我的大学老师,于是我打电话给他满聊聊,听听他的看法。过了两天,他发q跟我说解决了,内心由衷的高兴啊,感激涕零。
把子窗口的Style属性改成Child,Visible属性改成True,创建子窗口的时候改成非模式的方式创建子窗口,所有的问题就这么迎刃而解了。
虽然为什么这么改就解决了,且第一个问题也都自然解决了,我不知道是为什么,但一定跟DoModal机制有很大的关系,欢迎高手指教!
HWND frameWnd = NULL; CString gameUrl; CString cmd(str); int pos = cmd.Find(_T("-frameWnd=")); if (pos != -1) { cmd = cmd.Mid(pos+10); pos = cmd.Find(_T(" ")); if (pos != -1) { CString temp(cmd); temp = temp.Left(pos); frameWnd = (HWND) _ttol(temp.GetBuffer()); } cmd = cmd.Mid(pos); } pos = cmd.Find(_T("-gameurl=")); if (pos != -1) { gameUrl = cmd.Mid(pos + 9); } if (frameWnd) { CGameWndDlg* dlgGame = new CGameWndDlg(frameWnd, gameUrl); dlgGame->Create(IDD_DLG_GAME_WND,CWnd::FromHandle(frameWnd)); dlgGame->ShowWindow(SW_SHOW); m_pMainWnd = dlgGame; } else { CLander_G2Dlg dlg; m_pMainWnd = &dlg; dlg.DoModal(); } if(frameWnd) return TRUE; else return FALSE;
ps:
1、 窗口句柄跨进程传送是可行的,因为窗口句柄是全局的,所以跨进程传送也是安全的
2、在父窗口中最好不要直接通过子窗口句柄操作子窗口,比如MoveWindow改变子窗口大小,应该发消息到子窗口移动,因为窗口对象不是多线程安全的,多个线程同时访问可能会导致数据被误读或破坏
源码下载例子:
http://download.csdn.net/detail/huasonl88/8600603
相关文章推荐
- 在VS2010进行MFC编程设置字符集的问题(使用多字节字符集引起错误)
- VC++6.0&&VS2008&MFC&API学习问题总结(四)(编程内容技巧)
- MFC编程小技巧——强制杀死进程
- 面向概念编程浅谈:最大限度的UI代码共用
- MFC socket编程(浅出+深度:服务端和客户端端口问题)
- 多线程编程-线程安全问题浅谈(附懒汉式单例)
- MFC中发一些CDockablePane 关闭等编程问题。强烈推荐!!!!
- No MFC 编程05 - 进程 > 线程 > 消息队列,三者的包含关系
- 解决 “VC++ 多线程编程,win32,MFC 例子(转)”在高版本上运行有错误的问题
- MFC编程中的小问题
- socket编程中父子进程、兄弟进程的端口问题
- 关于Windows编程(MFC、API等 自己明白就可)向窗口写内容不能立即显示的问题
- 网络编程三---多线程/进程解决并发问题
- MFC 在编程当中遇到的小问题
- MFC编程小技巧——强制杀死进程
- (转)iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等
- 浅谈 upstart 和 孤儿进程问题!!!
- Linux编程:进程同步问题之哲学家就餐问题
- MFC 在编程中需要获取具体的出错信息的问题
- MFC 启动外部进程的问题