tag 标签: 窗口函数

相关博文
  • 热度 10
    2012-12-2 22:05
    857 次阅读|
    0 个评论
    http://bbs.csdn.net/topics/380128180  
  • 热度 14
    2012-12-2 22:00
    1437 次阅读|
    0 个评论
    在win32程序的消息循环函数中   while (GetMessage (msg, NULL, 0, 0))   {      TranslateMessage (msg) ;      DispatchMessage (msg) ;      } DispatchMessag()会调用WndProc()窗口过程函数,直到WndProc()处理完后DispatchMessag()才返回,继续消息循环检索下一条消息,在此之前while()消息循环会停顿掉 在WndProc()函数处理过程中如果又产生了另一个消息B,则必须等这个消息B处理完后wndProc()函数才会返回,而这个消息B也是要由WndProc()函数处理的,即在WndProc()调用的过程中系统接受到消息B后嵌套调用了WndProc(),但此时while消息循环已经停顿了 根据试验,在WndProc()处理过程中发出消息B后,系统通过某种方式跳过while()消息循环获取了消息B,并且又调用了一个WndProc()来处理消息B,等消息B处理完后第二个WndProc()才返回,然后第一个WndProc()继续执行,等第一个WndProc()执行完毕后DispatchMessage()才会返回,然后继续下一轮while()循环 那么,系统是怎样接受到这个消息B的呢?系统是怎样绕过while消息循环获取消息B并且调用第二个WndProc()的,这中间具体发生了哪些事情?网上和书上都没找到详细的处理过程…… 请记住这关键的一点: WndProc()是可重入的,就是说: WndProc()函数虽然没结束,但一个 API调用(SendMessage()等)会立即 再次调用WndProc()。 明白这一点对于理解windows的消息循环 很重要 getmessage取完之后就返回,peekmessage会挂着直到结束 SendMessage是直接发送到窗口过程的,借助系统的User32模块,并不进入队列 我不知道你是怎么试的 你可以运行下面的代码 C/C++ code ? ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include  #include  #include #define msgv (WM_USER+123) LRESULT   CALLBACK WindowProc( HWND   hwnd, UINT   uMsg, WPARAM   wParam, LPARAM   lParam) {      switch (uMsg)      {          case   msgv:          puts ( "enter msgv" );          PostMessageW(hwnd,msgv+1,0,0);          //SendMessageW(hwnd,msgv+1,0,0);          puts ( "leave msgv" );          return   0;          case   msgv+1:          puts ( "enter msgv+1" );          puts ( "leave msgv+1" );          return   0;          case   WM_CLOSE:DestroyWindow(hwnd);          return   0; case   WM_DESTROY:PostQuitMessage(0);          return   0;          default : return   DefWindowProcW(hwnd,uMsg,wParam,lParam);      } }   int   main() {        static   WNDCLASS.EXW WindowClass={ sizeof (WNDCLASS.EXW),0,WindowProc,0,0,0,0,0,0,0,L "aa" ,0};MSG msg; HWND   hwnd;      WindowClass.hInstance=GetModuleHandleW(0);      hwnd=CreateWindowExW(0,( wchar_t *)(unsigned  long )RegisterClass.ExW(WindowClass),0,WS_VISIBLE|WS_OVERLAPPEDWINDOW,200,200,200,200,0,0,0,0);      PostMessageW(hwnd,msgv,0,0);      while (GetMessageW(msg,0,0,0))DispatchMessageW(msg);      return   0; } PostMessage时输出是 enter msgv leave msgv enter msgv+1 leave msgv+1 SendMessage时输出是 enter msgv enter msgv+1 leave msgv+1 leave msgv 1、在win32程序的while消息循环中,DispatchMessag()会调用WndProc()窗口过程函数,直到WndProc()处理完后DispatchMessag()才返回,继续消息循环检索下一条消息,在这之前while()消息循环会停顿掉 2、在WndProc()函数处理过程中又产生了另一个消息B,如果消息B是由PostMessage()发送的,则消息B会发送到消息队列中,然后WndProc()继续执行,执行完毕后返回到DispatchMessag()函数,继续消息循环检索下一条消息,检索到消息B后才开始执行消息B, 3、在WndProc()函数处理过程中又产生了另一个消息B,如果消息B是由SendMessage()发送的,则必须等这个消息B处理完后wndProc()函数才会返回,这时SendMessage()会调用 SendMessageWorker(),SendMessageWorker()判断目标窗口的线程是不是当前线程,如果不是就进入内核调用NtUserMessageCall(),否则就在用户模式调用窗口过程函数WndProc() 虽然此时while()消息循环已经停顿了,但在WndProc()调用的过程中通过SendMessageWorker()间接嵌套调用了WndProc() 测试代码如下: #include  #define MSG_A (WM_USER+123) #define MSG_B (WM_USER+321) LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,                     PSTR szCmdLine, int nCmdShow) { static TCHAR szAppName[] = TEXT("Hello Windows");     HWND         hwnd; MSG          msg; WNDCLASS     wndclass; wndclass.style         = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc   = WndProc; wndclass.cbClExtra    = 0; wndclass.cbWndExtra    = 0; wndclass.hInstance     = hInstance; wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName  = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(wndclass)) {         MessageBox(NULL, TEXT("Register Class Failed !"), "Error", MB_ICONERROR);     return 0; }     hwnd = CreateWindow( szAppName, TEXT("Hello Windows"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(msg, NULL, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {     HDC hdc; static int i; switch(message) { case WM_LBUTTONDOWN:  i = 0;  hdc=GetDC(hwnd);  TextOut(hdc,100, 100 + (i++)*20, TEXT("Use SendMessage( )  Result :"),strlen(TEXT("Use PostMessage( )  Result :")));  i++;  TextOut(hdc,100, 100 + (i++)*20, TEXT("LBUTTONDOWN Start"),strlen(TEXT("LBUTTONDOWN Start")));  SendMessage(hwnd, MSG_A, 0, 0);  TextOut(hdc,100, 100 + (i++)*20, TEXT("LBUTTONDOWN Over"),strlen(TEXT("LBUTTONDOWN Over")));    ReleaseDC(hwnd,hdc);    return 0; case MSG_A:  hdc=GetDC(hwnd);  TextOut(hdc,100, 100 + (i++)*20, TEXT("MSG_A Start"),strlen(TEXT("MSG_A Start")));  SendMessage(hwnd, MSG_B, 0, 0);  TextOut(hdc,100, 100 + (i++)*20, TEXT("MSG_A Over"),strlen(TEXT("MSG_A Over")));  ReleaseDC(hwnd,hdc);   return 0; case MSG_B:  hdc=GetDC(hwnd);  TextOut(hdc,100, 100 + (i++)*20, TEXT("MSG_B Start"),strlen(TEXT("MSG_B Start")));  TextOut(hdc,100, 100 + (i++)*20, TEXT("MSG_B Over"),strlen(TEXT("MSG_B Over")));  ReleaseDC(hwnd,hdc);   return 0; case WM_DESTROY:  PostQuitMessage(0);  return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }   测试结果一: Use SendMessage() Result : LBUTTONDOWN Start MSG_A Start MSG_B Start MSG_B Over MSG_A Over LBUTTONDOWN Over 测试结果二: Use PostMessage() Result : LBUTTONDOWN Start LBUTTONDOWN Over MSG_A Over MSG_A Start MSG_B Start MSG_B Over   DispatchMessage只分发队列消息