父子窗口分属不同消息循环在WinXP和WinCE的差异
2010-04-19 17:07
344 查看
//=====================================================================
//TITLE:
// 父子窗口分属不同消息循环在WinXP和WinCE的差异
//AUTHOR:
// norains
//DATE:
// Monday 19- April-2010
//ENVIRONMENT:
// WINDOWS CE 5.0
// WINDOWS XP SP3
//=====================================================================
老实说,这题目起的有点拗口,读起来不太滑溜;但更有意思的是,本文所说的情况比较特殊,并不一定大家都能碰上。不过,如果碰上了,估计找起来还特别费劲,特别是对于代码是从WinCE迁移到WinXP上的朋友而言。
在开始进行本文的讨论之前,先确定如下特殊条件:
1. 主线程创建父窗口。
2. 创建一个线程,并在该线程中创建子窗口,且该线程有子窗口的消息循环。
3. 进入到父窗口的消息循环。
可能用文字描述有点抽象,我们来看看具体的代码:
我承认,为了突出文章的主题,这代码写得有点峥嵘,实在不好理解。所以,就以流程图说一下流程:
![](http://hi.csdn.net/attachment/201004/19/0_1271668362W0H0.gif)
如果你是WinCE环境下,刚刚的那段代码跑的非常顺畅,一点问题都没有;但如果是在WinXP,那么一切都会改变,你会发现,程序没有响应,被卡死了。仔细追踪,你会发现出问题的是在流程图中的"创建子窗口"这一项,具体来说,是CreateWindowEx函数根本没有返回!
解决方式也非常简单,在调用CreateWindowEx函数的时候,传入一个WinCE所不具备的WS_EX_NOPARENTNOTIFY即可。当你传入该数值时,CreateWindowEx就会如你所愿,顺顺当当返回。
由此我们或多或少可以知道WinXP和WinCE在消息处理上的小小差异:如果没有WS_EX_NOPARENTNOTIFY,那么子窗口创建时,需要等待父窗口的回应。而在我们示例的代码中,父窗口还没有进入消息循环,无法正常响应子窗口的动作,于是便造成了死锁。而WinCE则没有这方面的问题,子窗口根本就不必等待父窗口的回应,相应的创建完毕后,直接返回。从这个意义上来说,我们一刀切地认为(可能实际底层代码并不一定如此),虽然WinCE不具备WS_EX_NOPARENTNOTIFY这个数值,但实际上却默认具备了该数值的属性。
//TITLE:
// 父子窗口分属不同消息循环在WinXP和WinCE的差异
//AUTHOR:
// norains
//DATE:
// Monday 19- April-2010
//ENVIRONMENT:
// WINDOWS CE 5.0
// WINDOWS XP SP3
//=====================================================================
老实说,这题目起的有点拗口,读起来不太滑溜;但更有意思的是,本文所说的情况比较特殊,并不一定大家都能碰上。不过,如果碰上了,估计找起来还特别费劲,特别是对于代码是从WinCE迁移到WinXP上的朋友而言。
在开始进行本文的讨论之前,先确定如下特殊条件:
1. 主线程创建父窗口。
2. 创建一个线程,并在该线程中创建子窗口,且该线程有子窗口的消息循环。
3. 进入到父窗口的消息循环。
可能用文字描述有点抽象,我们来看看具体的代码:
#include <string> #ifdef UNICODE #ifndef TSTRING #define TSTRING std::wstring #endif #else #ifndef TSTRING #define TSTRING std::string #endif #endif //#ifdef UNICODE HWND g_hWndParent = NULL; HANDLE hEventNotify = NULL; LRESULT CALLBACK WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hWnd,wMsg,wParam,lParam); } BOOL MyRegisterClass(const TSTRING &strClassName) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(NULL); wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszMenuName = NULL; wc.lpszClassName = strClassName.c_str(); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); return RegisterClass(&wc); } HWND MyCreateWindow(const TSTRING &strClassName,const TSTRING &strWndName,HWND hWndParent,DWORD dwStyle,DWORD dwExStyle) { RECT rcArea = {0}; SystemParametersInfo(SPI_GETWORKAREA, 0, &rcArea, 0); return CreateWindowEx(dwExStyle, strClassName.c_str(), strWndName.c_str(), dwStyle, rcArea.left, rcArea.top, rcArea.right - rcArea.left, rcArea.bottom - rcArea.top, hWndParent, NULL, GetModuleHandle(NULL), 0); } DWORD WINAPI ThreadCreateWnd(LPVOID pArg) { if(MyRegisterClass(TEXT("CHILD_CLASS")) == FALSE) { return 0x10; } if(MyCreateWindow(TEXT("CHILD_CLASS"),TEXT("CHILD_NAME"),g_hWndParent,WS_CHILD|WS_VISIBLE,0) == NULL) { return 0x20; } OutputDebugString(TEXT("Finish Create child window/r/n")); SetEvent(hEventNotify); //The message loop MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } #ifdef _WIN32_WCE int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) #else int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) #endif //#ifdef _WIN32_WCE { if(MyRegisterClass(TEXT("PARENT_CLASS")) == FALSE) { return 0x10; } g_hWndParent = MyCreateWindow(TEXT("PARENT_CLASS"),TEXT("PARENT_NAME"),NULL,WS_POPUP|WS_VISIBLE,0); if(g_hWndParent == NULL) { return 0x20; } HANDLE hEventNotify = CreateEvent(NULL,FALSE,FALSE,NULL); CreateThread(NULL,NULL,ThreadCreateWnd,FALSE,FALSE,NULL); WaitForSingleObject(hEventNotify,INFINITE); MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
我承认,为了突出文章的主题,这代码写得有点峥嵘,实在不好理解。所以,就以流程图说一下流程:
![](http://hi.csdn.net/attachment/201004/19/0_1271668362W0H0.gif)
如果你是WinCE环境下,刚刚的那段代码跑的非常顺畅,一点问题都没有;但如果是在WinXP,那么一切都会改变,你会发现,程序没有响应,被卡死了。仔细追踪,你会发现出问题的是在流程图中的"创建子窗口"这一项,具体来说,是CreateWindowEx函数根本没有返回!
解决方式也非常简单,在调用CreateWindowEx函数的时候,传入一个WinCE所不具备的WS_EX_NOPARENTNOTIFY即可。当你传入该数值时,CreateWindowEx就会如你所愿,顺顺当当返回。
由此我们或多或少可以知道WinXP和WinCE在消息处理上的小小差异:如果没有WS_EX_NOPARENTNOTIFY,那么子窗口创建时,需要等待父窗口的回应。而在我们示例的代码中,父窗口还没有进入消息循环,无法正常响应子窗口的动作,于是便造成了死锁。而WinCE则没有这方面的问题,子窗口根本就不必等待父窗口的回应,相应的创建完毕后,直接返回。从这个意义上来说,我们一刀切地认为(可能实际底层代码并不一定如此),虽然WinCE不具备WS_EX_NOPARENTNOTIFY这个数值,但实际上却默认具备了该数值的属性。
相关文章推荐
- 父子窗口分属不同消息循环在WinXP和WinCE的差异
- 百度地图InfoWindow循环显示不同的信息窗口
- win32创建窗口及其消息循环
- QT中|Qt::Tool类型窗口自动退出消息循环问题解决
- 窗口破坏过程与Windows消息循环
- QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
- OIS接管了渲染窗口的消息循环
- QT创建窗口程序、消息循环和WinMain函数
- windows编程学习笔记(1)创建窗口与消息循环
- “鼠标拖动游戏窗口,消息循环会卡住,导致游戏不能更新不能渲染”,解决办法在这里
- 百度地图InfoWindow循环显示不同的信息窗口
- 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(二) 理解消息循环和窗口过程
- 通过小练习掌握MFC知识点之起步篇-父子窗口间传值、ListCtrl隔行变色、双缓冲技术解决控件闪烁、自定义消息等
- 非主线程创建窗口也能工作正常,只要我们注意一点:消息循环必须要和创建窗口在同一线程!
- MFC消息循环中几个函数的差异
- 注册 创建 显示 刷新窗口(注建显新),事件,消息循环,消息处理,钩子,dll钩子. (注重理解其中的逻辑关系)
- QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
- 笔记 VC++ Lesson1 句柄 / 窗口 / 消息循环 / 回调函数
- Qt for windows消息循环、libqxt分析和wince快捷键处理
- 2.创建适合游戏的窗口和消息循环