分享

父子窗口分属不同消息循环在WinXP和WinCE的差异

 lhzstudio 2012-05-15

//=====================================================================
//TITLE:
//    父子窗口分属不同消息循环在WinXP和WinCE的差异
//AUTHOR:
//    norains
//DATE:
//    Monday 19- April-2010
//ENVIRONMENT:
//    WINDOWS CE 5.0
//    WINDOWS XP SP3
//=====================================================================

    老实说,这题目起的有点拗口,读起来不太滑溜;但更有意思的是,本文所说的情况比较特殊,并不一定大家都能碰上。不过,如果碰上了,估计找起来还特别费劲,特别是对于代码是从WinCE迁移到WinXP上的朋友而言。

 

    在开始进行本文的讨论之前,先确定如下特殊条件:

     1. 主线程创建父窗口。
     2. 创建一个线程,并在该线程中创建子窗口,且该线程有子窗口的消息循环。
     3. 进入到父窗口的消息循环。

 

    可能用文字描述有点抽象,我们来看看具体的代码:

  1. #include <string>   
  2.   
  3. #ifdef UNICODE   
  4.  #ifndef TSTRING   
  5.   #define TSTRING std::wstring   
  6.  #endif   
  7. #else   
  8.  #ifndef TSTRING   
  9.   #define TSTRING std::string   
  10.  #endif   
  11. #endif //#ifdef UNICODE   
  12.   
  13. HWND g_hWndParent = NULL;  
  14. HANDLE hEventNotify = NULL;  
  15. LRESULT CALLBACK WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)  
  16. {  
  17.  return DefWindowProc(hWnd,wMsg,wParam,lParam);  
  18. }  
  19. BOOL MyRegisterClass(const TSTRING &strClassName)  
  20. {  
  21.  WNDCLASS wc;  
  22.  wc.style         = 0;  
  23.     wc.lpfnWndProc   = WndProc;  
  24.     wc.cbClsExtra    = 0;  
  25.     wc.cbWndExtra    = 0;  
  26.     wc.hInstance     = GetModuleHandle(NULL);  
  27.     wc.hIcon         = NULL;   
  28.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);   
  29.     wc.lpszMenuName  = NULL;  
  30.  wc.lpszClassName = strClassName.c_str();   
  31.  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  32.  return RegisterClass(&wc);  
  33. }  
  34. HWND MyCreateWindow(const TSTRING &strClassName,const TSTRING &strWndName,HWND hWndParent,DWORD dwStyle,DWORD dwExStyle)  
  35. {  
  36.  RECT rcArea = {0};  
  37.  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcArea, 0);  
  38.     return CreateWindowEx(dwExStyle,  
  39.     strClassName.c_str(),  
  40.     strWndName.c_str(),  
  41.                 dwStyle,  
  42.                 rcArea.left,  
  43.                 rcArea.top,  
  44.                 rcArea.right - rcArea.left,  
  45.                 rcArea.bottom - rcArea.top,  
  46.                 hWndParent,   
  47.                 NULL,   
  48.                 GetModuleHandle(NULL),   
  49.                 0);  
  50.   
  51. }  
  52. DWORD WINAPI ThreadCreateWnd(LPVOID pArg)  
  53. {  
  54.  if(MyRegisterClass(TEXT("CHILD_CLASS")) == FALSE)  
  55.  {  
  56.   return 0x10;  
  57.  }  
  58.  if(MyCreateWindow(TEXT("CHILD_CLASS"),TEXT("CHILD_NAME"),g_hWndParent,WS_CHILD|WS_VISIBLE,0) == NULL)  
  59.  {  
  60.   return 0x20;  
  61.  }  
  62.   
  63.  OutputDebugString(TEXT("Finish Create child window/r/n"));  
  64.  SetEvent(hEventNotify);  
  65.  //The message loop    
  66.  MSG msg;  
  67.  while(GetMessage(&msg,NULL,0,0))  
  68.  {  
  69.   TranslateMessage(&msg);  
  70.   DispatchMessage(&msg);  
  71.  }  
  72.  return 0;  
  73. }  
  74.   
  75.   
  76. #ifdef _WIN32_WCE   
  77.  int WINAPI WinMain( HINSTANCE hInstance,  
  78.       HINSTANCE hPrevInstance,  
  79.       LPTSTR    lpCmdLine,  
  80.       int       nCmdShow)  
  81. #else   
  82.  int APIENTRY _tWinMain(HINSTANCE hInstance,  
  83.                      HINSTANCE hPrevInstance,  
  84.                      LPTSTR    lpCmdLine,  
  85.                      int       nCmdShow)  
  86. #endif //#ifdef _WIN32_WCE   
  87. {    
  88.    
  89.  if(MyRegisterClass(TEXT("PARENT_CLASS")) == FALSE)  
  90.  {  
  91.   return 0x10;  
  92.  }  
  93.  g_hWndParent = MyCreateWindow(TEXT("PARENT_CLASS"),TEXT("PARENT_NAME"),NULL,WS_POPUP|WS_VISIBLE,0);  
  94.  if(g_hWndParent == NULL)  
  95.  {  
  96.   return 0x20;  
  97.  }  
  98.    
  99.  HANDLE hEventNotify = CreateEvent(NULL,FALSE,FALSE,NULL);  
  100.    
  101.  CreateThread(NULL,NULL,ThreadCreateWnd,FALSE,FALSE,NULL);  
  102.  WaitForSingleObject(hEventNotify,INFINITE);  
  103.   
  104.  MSG msg;   
  105.  while(GetMessage(&msg,NULL,0,0))  
  106.  {  
  107.   TranslateMessage(&msg);  
  108.   DispatchMessage(&msg);  
  109.  }  
  110.   
  111.  return 0;  
  112. }  


    我承认,为了突出文章的主题,这代码写得有点峥嵘,实在不好理解。所以,就以流程图说一下流程:


 
    如果你是WinCE环境下,刚刚的那段代码跑的非常顺畅,一点问题都没有;但如果是在WinXP,那么一切都会改变,你会发现,程序没有响应,被卡死了。仔细追踪,你会发现出问题的是在流程图中的"创建子窗口"这一项,具体来说,是CreateWindowEx函数根本没有返回!

 

    解决方式也非常简单,在调用CreateWindowEx函数的时候,传入一个WinCE所不具备的WS_EX_NOPARENTNOTIFY即可。当你传入该数值时,CreateWindowEx就会如你所愿,顺顺当当返回。

 

    由此我们或多或少可以知道WinXP和WinCE在消息处理上的小小差异:如果没有WS_EX_NOPARENTNOTIFY,那么子窗口创建时,需要等待父窗口的回应。而在我们示例的代码中,父窗口还没有进入消息循环,无法正常响应子窗口的动作,于是便造成了死锁。而WinCE则没有这方面的问题,子窗口根本就不必等待父窗口的回应,相应的创建完毕后,直接返回。从这个意义上来说,我们一刀切地认为(可能实际底层代码并不一定如此),虽然WinCE不具备WS_EX_NOPARENTNOTIFY这个数值,但实际上却默认具备了该数值的属性。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多