关于WM_QUIT消息的牛刀解释



原文链接:http://www.krnl.info/thread-1844-1-1.html


这是我看到的对windows 进程退出,对WM_QUIT消息讲的最详细的了。


 首先感谢 gz81 对牛刀 ○六八 讲教程的错误提出。

  经管理员确认,牛刀竟然也有送经验送分的权力,哈哈。
  可要注意喽,牛刀不但能送正分,还能送负分哟,呵呵。 9 e( o9 \/ G- p9 D- d9 |
$ J; @+ Y/ h4 j/ R1 j' J
  所以说,请大家以后尽量不要打着牛刀的旗号要分要经验,估计送刀如果送负分的话,其他人也不会送正分给你吧,哼哼!!!

  说句玩笑话,不过既然有这权力,牛刀就要用,以后对牛刀教材中的错误,进行提出并通过牛刀确认的话,牛刀一律给分,当然如下几种情况不给分(甚至可能给负分,哼哼)。
·恶意灌水(注:这一点牛刀不容易出现,牛刀的教程还能够受到绝大多数朋友们的尊重,到目前为止,恶意灌水的寥寥无几。 # v# k/ ^1 Y; G  z
·别字(牛刀的错笔字不属送分范围,当然可以提出,当然其实有时候,牛刀自己都发现笔字,说实话,懒得改,呵呵,大家顺着读吧,呵呵。注:牛刀用的是五笔,属于字型码,所以有些东西真容易打错的,例如有些地方字典打成“字曲”,这些都属于手误,不属送分范围) ! ]* \. u) \, o: Q8 ^; j4 ]
·语句不通(有些语句就是不通,或者说有意不通,也就是说,语法上的东东,不属于送分范围) ! m( H% f( a' t2 O8 @" p+ k
·文字偏差(有些属于前期论坛的代码问题,如果“[i]”,在以前的论坛上就都是斜体,不过牛刀不改了,为什么,因为不改你就不能用“复制/粘贴”大法,呵呵,牛刀的教材是实践教材,所以对于一切文字上的偏差,也不在送分范围)
·未经确认(其他情况,牛刀感觉不值得送分的,牛刀也不会送分,当然,直接要分的,牛刀不但不会送分甚至可能扣分,所以切忌要分)。 5 m# ^- i9 B/ p! s5 ]) L9 }) L( g4 y
8 Y* G' G, c6 ], t6 Q" I: r' C
  说实话,能够发现牛刀教程中的错误,证明你上机了,实践了,否则,是绝对不可能发现一些质的错误的。 * o4 p1 x4 e, h* o

  对了,这位朋友提出的是 牛刀使用了一个系统没有的消息 WM_EXIT 这个消息系统没有,后进管理员确认,牛刀也确认没有,于是,管理员经过查找资料,提出了一个问题 WM_QUIT 是不是属于消息。

  有些资料上对此不认为是一个消息,而这个功能就是设定某些标志位,于是,牛刀就去做了一些程序——

  1. #include <windows.h>

  2. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

  3. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,7 f  w9 b% D' ~0 }
  4.                     PSTR szCmdLine, int iCmdShow)) I: F; g4 N5 k1 h/ [
  5. {
  6.         static TCHAR szAppName[] = TEXT ("TestWin") ;: e4 [. C- [" n* Q( t% X% @  u
  7.         HWND        hwnd ;
  8.         MSG        msg ;
  9.         WNDCLASS        wndclass ;. _4 W2 }5 C  h6 a
  10.         
  11.         wndclass.style                  = CS_HREDRAW | CS_VREDRAW ;
  12.         wndclass.lpfnWndProc  = WndProc ;* c, B% D9 e- c' s4 j9 b
  13.         wndclass.cbClsExtra          = 0 ;
  14.         wndclass.cbWndExtra          = 0 ;
  15.         wndclass.hInstance          = hInstance ;
  16.         wndclass.hIcon                  = LoadIcon (NULL, IDI_APPLICATION) ;
  17.         wndclass.hCursor          = LoadCursor (NULL, IDC_ARROW) ;& z7 m6 x$ j, S, p
  18.         wndclass.hbrBackground        = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  19.         wndclass.lpszMenuName        = NULL;' r% x* K3 Q+ K/ H+ T  D
  20.         wndclass.lpszClassName        = szAppName ;3 p, S5 _9 |5 `! w
  21.         
  22.         if (!RegisterClass (&wndclass))
  23.         {
  24.                 MessageBox (        NULL, TEXT ("This program requires Windows NT!"), 
  25.                         szAppName, MB_ICONERROR) ;
  26.                 return 0 ;7 C4 z, Z. A" v. d
  27.         }2 [9 s; x9 Y6 u( Z3 |1 _: ?' T6 S
  28.         hwnd = CreateWindow( szAppName,TEXT ("牛刀WM_QUIT测试"),WS_OVERLAPPEDWINDOW,& O2 U+ G% S3 ^& s& g4 f
  29.                 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,% o( G3 i1 I! z
  30.                 NULL,NULL,hInstance,NULL) ;
  31.         ' U0 Y/ g/ }5 C3 H- X# C
  32.         ShowWindow (hwnd, iCmdShow) ;  L) [6 W3 N: P8 a: M' s4 C% a
  33.         UpdateWindow (hwnd) ;. Z; t# F2 V% k; |# q
  34.         
  35.         while (GetMessage (&msg, NULL, 0, 0))( }% ~% f( a. J! L
  36.         {7 T3 r/ h% Q2 x; n2 Q
  37.                 TranslateMessage (&msg) ;
  38.                 DispatchMessage (&msg) ;+ j1 D0 Y3 g7 Q
  39.         }/ U% ^3 T! S/ O- V2 t
  40.         return msg.wParam ;
  41. }
  42. # n1 W- L; E8 E! X
  43. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  44. {* c# v; [% \. v6 R" z. b: i" @( z
  45.         switch (message)" R7 h4 B# p# h* [& m: Y
  46.         {
  47.         case        WM_DESTROY:
  48.                 PostQuitMessage (0) ;
  49.                 return 0 ;
  50.         }
  51.         return DefWindowProc (hwnd, message, wParam, lParam) ;  c4 R, s) ^3 \5 L
  52. }
复制代码
上面的程序,我们可以运行了,并且只在 WM_DESTROY 发送了 WM_QUIT 消息,所以说,如果这一个消息不响应的话,那么我们的程序就结束不了,以前我们曾经说过,没有 PostQuitMessage 消息的话,我们的程序是结束不了的。(什么?你的程序结束了?你打开任务管理器看看,真的结束了吗?只不过是窗口被销毁了罢了,呵呵,所以说,当 WM_DESTROY 消息响应时,我们的程序窗口已经被销毁。) . l# _( x  _' D  l6 W6 @  \
  当然 WM_CLOSE 消息被响应时,窗口还没有销毁,当然,那个消息中,是可以执行 DestroyWindow 函数去销毁窗口的,而如果不执行的话,那么窗口就销毁不了,也就是说,我们如果响应一个空消息的话——

  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" ^  I9 o: y. Y! C( a3 K7 ~( B
  2. {0 j+ U2 t0 p  ?9 C
  3.         switch (message)
  4.         {2 R- _( k% l# ?% M/ ~  l
  5.         case WM_CLOSE:
  6.                 return 0;
  7.         default:/ _* h* {+ g0 q9 \# R& j/ m, U
  8.                 return DefWindowProc (hwnd, message, wParam, lParam) ;
  9.         }
  10. }
复制代码
我们的窗口是关不掉的,所以说,系统默认函数在响应 WM_CLOSE 时,是提供销毁窗口的函数的,然而,在销毁窗口时,却没有提供发送 WM_QUIT 消息的函数,所以我们的消息处理中,至少响应如下消息:
  1. ! J) H3 v' _" ~; z3 C
  2. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" G5 G/ F; C: P4 a( }" j
  3. {, r) l1 X  @9 U& x) {. p
  4.         switch (message)
  5.         {: U2 W, E" u% x2 L- T/ g
  6.         case WM_DESTROY:
  7.                 PostQuitMessage (0) ;
  8.                 return 0 ;
  9.         default:/ [3 b( s4 ^7 G7 L# w& M
  10.                 return DefWindowProc (hwnd, message, wParam, lParam);
  11.         }1 K) K( H0 B# @% L; K' ~, r4 L8 j
  12. }! x& d6 g7 D- [7 l* r  J
复制代码
那好,一个问题,我们的函数能够响应WM_QUIT 消息吗?如果按照某些材料上说的,我们就不能响应这个消息了,去做一个程序试试——

  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {
  3.         switch (message)
  4.         {
  5.         case WM_DESTROY:
  6.                 PostQuitMessage (0) ;9 r  x2 p: Z  k5 V) ~
  7.                 break;
  8.         case WM_QUIT:
  9.                 MessageBox(hwnd,"消息测试","WM_QUIT消息测试",MB_OK);
  10.                 break;
  11.         }- k  n# n, B5 b7 X0 N) ?
  12.         return DefWindowProc (hwnd, message, wParam, lParam);
  13. }
复制代码
果然不假,上面的一些理论得到了证实,可是牛刀不服,既然没有用,那么要这个消息干嘛?牛刀不服,换了一个地方打劫——
  1. ) p3 s2 X" v! A! j
  2.         while (GetMessage (&msg, NULL, 0, 0))
  3.         {
  4.                 TranslateMessage (&msg) ;, g( R! t0 I5 G- N
  5.                 DispatchMessage (&msg) ;
  6.         }* }1 ]. p+ E" j' X4 R4 J. |
  7.         if(WM_QUIT==msg.message)MessageBox(NULL,"消息测试","WM_QUIT消息测试",MB_OK);
复制代码
这一次,这个消息被我们打劫到了,并且顺利地执行,那么为什么我们在 WndProc 函数中,得不到消息呢?我们来看看我们消息的执行过程)——
  1. - n9 \, X- R% g% I6 r8 E
  2. while (GetMessage (&msg, NULL, 0, 0))  //得到消息,请注意,如果消息是 WM_QUIT,那么这个函数就返回 0 ,下面的程序就执行不到了。8 L0 q& U4 x- L* i
  3. {1 ?% k, y- t2 ^. T& c2 B, m) o
  4.         TranslateMessage (&msg) ;  //翻译程序,翻译消息# b  u$ h. U/ d) A
  5.         DispatchMessage (&msg) ;   //执行消息,是这一句将消息队列中的消息传递给 WndProc 函数,所以一旦有了 WM_QUIT 消息,这一句就执行不到,于是,我们的消息在 WndProc 函数中就捕捉不到了。
  6. }" f5 N9 C6 q2 u1 q; o% o
复制代码
明白了上面的道理,那么我们如果想在消息处理函数中捕捉到这个消息,那么我们怎么办呢?可以改一下下程序嘛,呵呵,看——
  1. 6 O9 |4 |+ ^3 y
  2.         int MsgRet;. i+ Q2 b" a3 i0 _/ v; y1 w
  3.         do4 g6 o2 P  F' \+ u
  4.         {        MsgRet=GetMessage (&msg, NULL, 0, 0);' V; s9 b2 n9 h' P# O/ j( B
  5.                 TranslateMessage (&msg) ;! U! }$ k* ?* L& v" p2 H
  6.                 DispatchMessage (&msg) ;
  7.         }while(MsgRet);        //我们改了成 do-while 结构,这样上面的消息就每条消息都有机会送到 WinProc 函数喽
复制代码
程序理论讲完了,很可惜的是,我们的程序, WndProc 中的 WM_QUIT 消息仍旧没有被执行,这是什么原因??? : i* O2 x8 _% C; U* q

  很显然,肯定被系统的 DispatchMessage (&msg) ; 函数给过滤掉了,不知牛刀考虑的有没有道理,大家可以各抒己见。
: P, k7 E2 Z: T
  结论:WM_QUIT 是一个消息,但这个消息不能在 WndProc 消息函数中被捕获,如果要响应,也只能在消息循环地位置拦截,但我们一般不需要这样做。


原文:"注意到WM_QUIT消息让消息循环终止归根结底是让GetMessage返回为0,而GetMessage函数是从消息对列里取一条消息,然后再返回,只能当消息为WM_QUIT时才返回0结束消息循环。再仔细看一下SendMessage的注释发现,SendMessage直接发送到窗口,并调用窗口处理程序,完成消息响应,即SendMessage 根本就没有将消息发到消息对列中,因此GetMessage无法从消息对列中收到WM_QUIT的消息。而PostMessage却直接发送消息到消息对列中,然后立即返回,这一点点的区别就解决了我们上面的问题。陆解了这一点,就不难理解上面注释中说的为什么不让直接使用PostMessage来发送WM_QUIT消息来终止程序了。"


 GetMessage 是收到了 WM_QUIT 消息的,但牛刀的结论是:被 DispatchMessage 函数给过滤掉了。( F' P8 F" m8 i: r
  也就是说,WM_QUIT 消息发送给窗口是无效的,所以使用 SendMessage 向窗口发送 WM_QUIT 消息则无效。6 c. T# _+ [/ ]0 Q# q

  为了验证这个想法,牛刀去做了一个测试——


  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {" L. T, v5 @. A% j. w& X
  3.         switch (message). K% }" W. Z5 T" `) q
  4.         {
  5.         case WM_LBUTTONDOWN:6 O* b  Z, C% w0 D
  6.                 SendMessage(hwnd,WM_QUIT,0,0);# c! }$ H% g" f% j  ^5 B. g
  7.                 break;
  8.         case WM_DESTROY:
  9.                 PostQuitMessage (0) ;
  10.                 break;
  11.         case WM_QUIT:
  12.                 MessageBox(hwnd,"消息测试","WM_QUIT消息测试",MB_OK);/ r6 x* ]" h; E+ ^$ W! l6 g
  13.                 break;
  14.         }
  15.         return DefWindowProc (hwnd, message, wParam, lParam);' \4 s! Z4 Y; w6 A5 Q! o0 j
  16. }
复制代码
8 T  H" E- @7 y' @. W
2 C& E+ D5 y3 ]# Q( {( ]- {
  牛刀惊奇地发现,牛刀上面的 SendMessage 发送消息无效的结论是不正确的。窗口函数的确响应的 WM_QUIT 消息,但由于这个消息没有被 GetMessage 捕获,所以程序根本没有退出,也就是说,使用 SendMessage 发送这个消息时,是不经过消息队列的,也就是说是不经过——

  1.         while(GetMessage (&msg, NULL, 0, 0))7 }5 G% t0 i1 r( l# _
  2.         {        
  3.                 TranslateMessage (&msg) ;# B( y/ i1 I. s/ u# Z
  4.                 DispatchMessage (&msg) ;5 ?+ N0 O9 a/ C8 R6 E6 [5 q
  5.         }
复制代码
4 M" b  T, L% q$ @" @' q* N" z

  这个消息循环的,所以不能使得 GetMessage 返回 0 值。

  于是,牛刀又去测试了 PostMessage 消息: : w  C; B2 x% s" g7 @
  1. % K4 _+ q3 ?7 T/ ?4 t6 \3 w! Q2 f
  2. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  3. {
  4.         switch (message)# b' n& m, Z" e( [' H
  5.         {5 h; Y3 f3 J( }" B% e
  6.         case WM_LBUTTONDOWN:
  7.                 PostMessage(hwnd,WM_QUIT,0,0);
  8.                 break;
  9.         case WM_DESTROY:5 R2 w- b2 k- d1 {/ t
  10.                 PostQuitMessage (0) ;  h& H/ c' C) q3 C; U9 b
  11.                 break;
  12.         case WM_QUIT:) B* v4 v1 P1 V) h! Z1 C4 u$ e
  13.                 MessageBox(hwnd,"消息测试","WM_QUIT消息测试",MB_OK);
  14.                 break;
  15.         }
  16.         return DefWindowProc (hwnd, message, wParam, lParam);& C$ |  W8 P2 Q; R/ @0 S# s$ r. t" Q
  17. }
复制代码
& q% Z! H: y5 d

  由于消息这次是发进了消息队列,所以我们在 WndProc 函数中就又不能响应消息了。 8 y. Y) Q( r2 j* y  G' g0 N( U
. L2 A, \$ ~% \- u
  综上所述:
·WM_QUIT 的确是一条消息,并且这个消息是可以发送到消息队列中(使用PostMessage),亦可以发送到窗口(使用SendMessage),但是,我们是不能通过消息队列将消息发送到窗口中的,因为我们的队列中的消息被 DispatchMessage 给过滤掉了。 2 O, ]5 P9 x3 I! z# q" |

  通过上面的一些讨论与测试,我们基本可以估计出 DispatchMessage 的函数应该是这样或近似这样的程序——

  1. void DispatchMessage(MSG msg)
  2. {
  3.         if(WM_QUIT!=msg.message)
  4.         {
  5.                 SendMessage(msg.hwnd,msg.message,msg.wParam,msg.lParam);
  6.         }
  7. }* i0 ]0 p# d  N3 m7 Z6 J
复制代码

, @) s/ s, \( q! j
  附:为什么不建议直接用 PostMessage 来发 WM_QIUT 消息的牛刀解释。 " q6 a/ x0 @  N+ U; A/ _

  首先一点的就是,可以使用 PostMessage 来发送 WM_QUIT 消息,并且一点残留都没有(注:任务管理器中一点残余都没有)。 * J( d" o, {: b% `8 V1 W+ ?
  当然,窗口也没有了,程序结束了,但会有一个问题,那就是,我们的窗口并没有被销毁,因为没有来得及响应 WM_DESTROY 消息,为了验证,牛刀做了以下的程序——

  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {
  3.         switch (message)7 A- O* z* B- H* T0 ~
  4.         {; \2 e( o4 i9 B! Z# m3 I
  5.         case WM_LBUTTONDOWN:* A: H. ]# x' n
  6.                 PostMessage(hwnd,WM_QUIT,0,0);
  7.                 break;1 ?" x" E8 t, D( T3 N9 k
  8.         case WM_DESTROY:
  9.                 MessageBox(hwnd,"消息测试","WM_DESTROY消息测试",MB_OK);2 s" W- o1 p" }1 D) G, O
  10.                 break;8 r9 d2 g2 ?5 y+ G  |( K* r7 L
  11.         case WM_QUIT:
  12.                 MessageBox(hwnd,"消息测试","WM_QUIT消息测试",MB_OK);
  13.                 break;1 x8 A& u% X0 z& C
  14.         }7 Z: N6 L2 C! O
  15.         return DefWindowProc (hwnd, message, wParam, lParam);& M8 }% t5 i- w
  16. }
复制代码


  果然不假,我们的销毁窗口的消息并没有接收到,我们的程序就退出了循环,但是,窗口关闭了吗? 5 \' n( W- m6 H

  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" ^7 Y" I; Z' q- {) E
  2. {
  3.         switch (message)/ @; z+ L- Y! D8 X
  4.         {
  5.         case WM_LBUTTONDOWN:) k- [* o* ?$ X
  6.                 PostMessage(hwnd,WM_QUIT,0,0);2 @3 h: c, n$ r8 F7 F4 B
  7.                 break;
  8.         case WM_CLOSE:( e" B% o( Y: r; F8 |: b8 ~
  9.                 MessageBox(hwnd,"消息测试","WM_CLOSE消息测试",MB_OK);0 Z+ n% J/ `4 |' A" S/ ^# W9 U
  10.                 break;" `4 B( B4 G* S+ }: E
  11.         case WM_DESTROY:
  12.                 MessageBox(hwnd,"消息测试","WM_DESTROY消息测试",MB_OK);( k$ N( E, O4 [
  13.                 break;
  14.         case WM_QUIT:
  15.                 MessageBox(hwnd,"消息测试","WM_QUIT消息测试",MB_OK);
  16.                 break;, [8 `" |( J) U# C/ i1 ]7 N2 k
  17.         }
  18.         return DefWindowProc (hwnd, message, wParam, lParam);; i! w) D4 @' {9 `4 B+ t% Z  L
  19. }
复制代码
# Z+ t' L6 C6 p- }
; o/ y4 ^1 ]5 u  @4 S
  奇怪的是,窗口也没有被关闭。 & Y; H0 A4 y( b
6 Z" R" k3 ?1 V
  那么就有问题了,窗口既没有被销毁,也没有被关闭,那么这个窗口我们也见不到了,那么这个窗口哪儿去了?[我们 C++ 中没有像 Java 那样的垃圾回收机制,所以也不可能消失]

  唯一的解释,我们的窗口还在内存中,当然,牛刀没当过黑客,如果当过黑客的话,应该通过黑客技术可以将这个窗口重新显示出来,但可以想像,那时候的窗口即使显示出来,也是一个死窗口,什么功能也没有,因为这个窗口已经和我们的程序脱节了,当然黑客技术可以通过一些手段去映射我们的窗口消息到其他的函数上,去满足其他程序的一些需求,可能功能已经不是原来的功能了——怎么像是在说《聊斋》故事啊,呵呵,比较恐怖,呵呵,又感觉在讨论黑客技术啊,呵呵。 3 R$ J0 n" j) u8 y" c" e9 W! E
" B0 j" M, X% Z; I2 i+ M
  总之,窗口是有的,在内存中,我们看不见了,为什么上面像在搞黑客,也是这个原因,会出现内存泄漏,所以从建议的角度来说,是不建议用 PostMessage 来发送 WM_QUIT 消息的。 1 K% p4 U  s( u

  但,是可以用 SendMessage 来发送 WM_QUIT 消息了,但此时,这个消息已经没有退出程序的功能了,如果有必要,我们完全可以当自定义的消息来使用,这样一来,我们如果想自定一个消息,又怕麻烦,那么我们就完全可以不用定义,而直接借用 WM_QUIT 消息来响应就好,唯一的缺点就是,那就不能使用 PostMessage 来发送用户自定义消息啦,呵呵,这不能不说是多线程任务的一个遗憾,但如果想将消息当函数用,那一点问题都没有。 6 h4 X* e/ c4 o  r
1 N' q+ [& A* y1 e
  这就是牛刀对 WM_QUIT 消息的一点粗浅的认识,希望对大家有所帮助。


我以为,SendMessage是立即调用窗口的回调函数,PostMessage是把消息排到消息队列里面。 4楼
/ f# }/ o; Z1 o3 F3 a
WM_QUIT就是用来向系统声明此消息队列结束,不用继续维持了。

重要更正:! M( n; T* |, p% E: r
  上面4楼的最后一个程序,窗口是关闭了的,最后打字时,手误了,呵呵,不好意思。

  5楼的说法是正确的,但是 WM_QUIT 的确是可以通过 SendMessage 发送到窗口中去,并且在窗口消息处理中响应的,但程序结束不了,所以正常情况下,我们是不这样用的,也没有必要。


谢谢楼上的回贴,并不是牛刀想复杂了,而是牛刀在讨论 WM_QUIT 消息的发送机理。
1 ^- }2 x% Q) g! \( m
  因为有些材料上说 WM_QUIT 不是一个消息,只是设置一些标志,而事实上在回调函数中也真的不能响应 WM_QUIT 消息,所以牛刀写这篇文章。0 E( o' }2 \0 u* x/ Q: ]# H
% z& \  ?  L& x( ]& D5 r5 k
  试验的结果是—— WM_QUIT 是一个消息,并且在 WndProc 中亦可以响应,但是必须直接向窗口发出一个消息,也就是说使用 SendMessage 发送;而 GetMessage(&msg,NULL,0,0) 是可以捕捉到消息的,并且仅在捕捉到此消息时,返回值是 0 ,至于你说的 WM_QUIT 不为零,不这奇怪,可以想像,必定是在 GetMessage 函数中有如下代码——" o' E8 ?: S7 _' V' I4 V  }7 V3 o


  1. if(WM_QUIT==message)return 0;
复制代码

' \) V% I4 V+ D' U5 R
  并且事实上,WM_QUIT 消息在 DispatchMessage 函数中,也的确被过滤掉了。因为我们上面的代码—— 4 o( N6 G  W3 b) y  f. u' g1 P
  1. " W7 u% O# i9 _7 j
  2. int MsgRet;
  3.         do
  4.         {& U1 k% q) O( n& ^- f
  5.                 MsgRet=GetMessage (&msg, NULL, 0, 0);
  6.                 TranslateMessage (&msg) ;
  7.                 DispatchMessage (&msg) ;, h5 v# A; B, N' s/ w/ Y
  8.         }while(MsgRet);0 H! |% {- O  G9 x
复制代码

( ]; n3 F8 `# F& P0 j& i
  是允许 WM_QUIT 消息通过 DispatchMessage 函数的,然而,并没有发送到窗体,所以这个消息被过滤掉了,当然,有两种可能,一种是被 DispatchMessage 函数给过滤掉了,另一种可能是被 TranslateMessage 给过滤掉了,那么是哪一种情况呢?牛刀做了如下程序,看看效果——
  1. ! i/ d$ z4 {' P2 l2 C9 f
  2.         int MsgRet;
  3.         do
  4.         {        ; U3 a1 g6 K- T3 `, j
  5.                 MsgRet=GetMessage (&msg, NULL, 0, 0);- j2 y. Q: L( Y5 m, b# A# e  }
  6.                 if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在GetMessage函数后被捕获","消息测试",MB_OK);: O4 U2 U) `, f$ f% e% O1 \
  7.                 TranslateMessage (&msg) ;2 C  n4 w- t$ P, V! J* G5 m
  8.                 if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在TranslateMessage函数后被捕获","消息测试",MB_OK);
  9.                 DispatchMessage (&msg) ;0 X; l6 z$ ~+ D9 Y: ^; O
  10.                 if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在DispatchMessage函数后被捕获","消息测试",MB_OK);
  11.         }while(MsgRet);
复制代码
& G; W; T5 x( ~4 `

  三个 Message 都能执行,所以说,TranslateMessage 并没有改变消息, DispatchMessage 也根本没有改变消息,所以消息必然是被 DispatchMessage 函数给过滤掉了。 7 B+ s: Q+ z/ t! e$ z0 ]
2 w4 \8 n5 X- T3 E5 Z- ]+ ~
  注:你的那段函数——

  1. while (GetMessage(&msg,NULL,0,0))2 S9 u+ n1 c3 C" z4 D; l
  2.         {
  3.             TranslateMessage(&msg);    // Translates virtual key codes.
  4.             DispatchMessage(&msg);     // Dispatches message to window.( l0 K4 Q3 _& t
  5.         }
  6.     return (msg.wParam);           // Returns the value from PostQuitMessage.) m' Z( d: E, ~" c9 {0 Q; x
复制代码
$ f0 @0 q$ S3 E+ R% A, D& q2 |

  固然是正确的,但如果去研究这种消息之间的关系的话,特别是 WM_QUIT 消息,你这种常规写法就难以胜任喽。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值