關(guān)于WM_QUIT消息的牛刀解釋
yuanhubilie?2013-01-30 12:21:09?
?3201??收藏
原文鏈接:http://www.krnl.info/thread-1844-1-1.html
這是我看到的對(duì)windows 進(jìn)程退出跷叉,對(duì)WM_QUIT消息講的最詳細(xì)的了吨枉。
首先感謝 gz81 對(duì)牛刀 ○六八 講教程的錯(cuò)誤提出调塌。
經(jīng)管理員確認(rèn),牛刀竟然也有送經(jīng)驗(yàn)送分的權(quán)力惩阶,哈哈匈辱。
可要注意嘍寺擂,牛刀不但能送正分,還能送負(fù)分喲砾医,呵呵拿撩。9 e( o9 \/ G- p9 D- d9 |
$ J; @+ Y/ h4 j/ R1 j' J
所以說(shuō),請(qǐng)大家以后盡量不要打著牛刀的旗號(hào)要分要經(jīng)驗(yàn)如蚜,估計(jì)送刀如果送負(fù)分的話绷雏,其他人也不會(huì)送正分給你吧,哼哼2劳ぁO严浴!
說(shuō)句玩笑話兴猩,不過(guò)既然有這權(quán)力期吓,牛刀就要用,以后對(duì)牛刀教材中的錯(cuò)誤倾芝,進(jìn)行提出并通過(guò)牛刀確認(rèn)的話讨勤,牛刀一律給分,當(dāng)然如下幾種情況不給分(甚至可能給負(fù)分晨另,哼哼)潭千。
·惡意灌水(注:這一點(diǎn)牛刀不容易出現(xiàn),牛刀的教程還能夠受到絕大多數(shù)朋友們的尊重借尿,到目前為止刨晴,惡意灌水的寥寥無(wú)幾。# v# k/ ^1 Y; G??z
·別字(牛刀的錯(cuò)筆字不屬送分范圍路翻,當(dāng)然可以提出狈癞,當(dāng)然其實(shí)有時(shí)候,牛刀自己都發(fā)現(xiàn)筆字茂契,說(shuō)實(shí)話蝶桶,懶得改,呵呵掉冶,大家順著讀吧真竖,呵呵。注:牛刀用的是五筆厌小,屬于字型碼恢共,所以有些東西真容易打錯(cuò)的,例如有些地方字典打成“字曲”召锈,這些都屬于手誤旁振,不屬送分范圍)! ]* \. u) \, o: Q8 ^; j4 ]
·語(yǔ)句不通(有些語(yǔ)句就是不通获询,或者說(shuō)有意不通涨岁,也就是說(shuō)拐袜,語(yǔ)法上的東東,不屬于送分范圍)! m( H% f( a' t2 O8 @" p+ k
·文字偏差(有些屬于前期論壇的代碼問(wèn)題梢薪,如果“[i]”蹬铺,在以前的論壇上就都是斜體,不過(guò)牛刀不改了秉撇,為什么甜攀,因?yàn)椴桓哪憔筒荒苡谩皬?fù)制/粘貼”大法,呵呵琐馆,牛刀的教材是實(shí)踐教材规阀,所以對(duì)于一切文字上的偏差,也不在送分范圍)
·未經(jīng)確認(rèn)(其他情況瘦麸,牛刀感覺(jué)不值得送分的谁撼,牛刀也不會(huì)送分,當(dāng)然滋饲,直接要分的厉碟,牛刀不但不會(huì)送分甚至可能扣分,所以切忌要分)屠缭。5 m# ^- i9 B/ p! s5 ]) L9 }) L( g4 y
8 Y* G' G, c6 ], t6 Q" I: r' C
說(shuō)實(shí)話箍鼓,能夠發(fā)現(xiàn)牛刀教程中的錯(cuò)誤,證明你上機(jī)了呵曹,實(shí)踐了款咖,否則,是絕對(duì)不可能發(fā)現(xiàn)一些質(zhì)的錯(cuò)誤的奄喂。* o4 p1 x4 e, h* o
對(duì)了之剧,這位朋友提出的是 牛刀使用了一個(gè)系統(tǒng)沒(méi)有的消息 WM_EXIT 這個(gè)消息系統(tǒng)沒(méi)有,后進(jìn)管理員確認(rèn)砍聊,牛刀也確認(rèn)沒(méi)有背稼,于是,管理員經(jīng)過(guò)查找資料玻蝌,提出了一個(gè)問(wèn)題 WM_QUIT 是不是屬于消息蟹肘。
有些資料上對(duì)此不認(rèn)為是一個(gè)消息,而這個(gè)功能就是設(shè)定某些標(biāo)志位俯树,于是帘腹,牛刀就去做了一些程序——
#include
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,7 f??w9 b% D' ~0 }
PSTR szCmdLine, int iCmdShow)) I: F; g4 N5 k1 h/ [
{
static TCHAR szAppName[] = TEXT ("TestWin") ;: e4 [. C- [" n* Q( t% X% @??u
HWND? ? ? ? hwnd ;
MSG? ? ? ? msg ;
WNDCLASS? ? ? ? wndclass ;. _4 W2 }5 C??h6 a
wndclass.style? ? ? ? ? ? ? ?? ?= CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc??= WndProc ;* c, B% D9 e- c' s4 j9 b
wndclass.cbClsExtra? ? ? ?? ?= 0 ;
wndclass.cbWndExtra? ? ? ?? ?= 0 ;
wndclass.hInstance? ? ? ?? ?= hInstance ;
wndclass.hIcon? ? ? ? ? ? ? ?? ?= LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor? ? ? ?? ?= LoadCursor (NULL, IDC_ARROW) ;& z7 m6 x$ j, S, p
wndclass.hbrBackground? ? ? ? = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName? ? ? ? = NULL;' r% x* K3 Q+ K/ H+ T??D
wndclass.lpszClassName? ? ? ? = szAppName ;3 p, S5 _9 |5 `! w
if (!RegisterClass (&wndclass))
{
MessageBox (? ? ? ? NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;7 C4 z, Z. A" v. d
}2 [9 s; x9 Y6 u( Z3 |1 _: ?' T6 S
hwnd = CreateWindow( szAppName,TEXT ("牛刀WM_QUIT測(cè)試"),WS_OVERLAPPEDWINDOW,& O2 U+ G% S3 ^& s& g4 f
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,% o( G3 i1 I! z
NULL,NULL,hInstance,NULL) ;
' U0 Y/ g/ }5 C3 H- X# C
ShowWindow (hwnd, iCmdShow) ;??L) [6 W3 N: P8 a: M' s4 C% a
UpdateWindow (hwnd) ;. Z; t# F2 V% k; |# q
while (GetMessage (&msg, NULL, 0, 0))( }% ~% f( a. J! L
{7 T3 r/ h% Q2 x; n2 Q
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;+ j1 D0 Y3 g7 Q
}/ U% ^3 T! S/ O- V2 t
return msg.wParam ;
}
# n1 W- L; E8 E! X
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{* c# v; [% \. v6 R" z. b: i" @( z
switch (message)" R7 h4 B# p# h* [& m: Y
{
case? ? ? ? WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;??c4 R, s) ^3 \5 L
}
復(fù)制代碼
上面的程序,我們可以運(yùn)行了许饿,并且只在 WM_DESTROY 發(fā)送了 WM_QUIT 消息阳欲,所以說(shuō),如果這一個(gè)消息不響應(yīng)的話,那么我們的程序就結(jié)束不了球化,以前我們?cè)?jīng)說(shuō)過(guò)秽晚,沒(méi)有 PostQuitMessage 消息的話,我們的程序是結(jié)束不了的筒愚。(什么赴蝇?你的程序結(jié)束了?你打開(kāi)任務(wù)管理器看看巢掺,真的結(jié)束了嗎句伶?只不過(guò)是窗口被銷(xiāo)毀了罷了,呵呵陆淀,所以說(shuō)考余,當(dāng) WM_DESTROY 消息響應(yīng)時(shí),我們的程序窗口已經(jīng)被銷(xiāo)毀轧苫。). l# _( x??_' D??l6 W6 @??\
當(dāng)然 WM_CLOSE 消息被響應(yīng)時(shí)秃殉,窗口還沒(méi)有銷(xiāo)毀,當(dāng)然浸剩,那個(gè)消息中钾军,是可以執(zhí)行 DestroyWindow 函數(shù)去銷(xiāo)毀窗口的,而如果不執(zhí)行的話绢要,那么窗口就銷(xiāo)毀不了吏恭,也就是說(shuō),我們?nèi)绻憫?yīng)一個(gè)空消息的話——
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" ^??I9 o: y. Y! C( a3 K7 ~( B
{0 j+ U2 t0 p???9 C
switch (message)
{2 R- _( k% l# ?% M/ ~??l
case WM_CLOSE:
return 0;
default:/ _* h* {+ g0 q9 \# R& j/ m, U
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
}
復(fù)制代碼
我們的窗口是關(guān)不掉的重罪,所以說(shuō)樱哼,系統(tǒng)默認(rèn)函數(shù)在響應(yīng) WM_CLOSE 時(shí),是提供銷(xiāo)毀窗口的函數(shù)的剿配,然而搅幅,在銷(xiāo)毀窗口時(shí),卻沒(méi)有提供發(fā)送 WM_QUIT 消息的函數(shù)呼胚,所以我們的消息處理中茄唐,至少響應(yīng)如下消息:
! J) H3 v' _" ~; z3 C
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" G5 G/ F; C: P4 a( }" j
{, r) l1 X??@9 U& x) {. p
switch (message)
{: U2 W, E" u% x2 L- T/ g
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
default:/ [3 b( s4 ^7 G7 L# w& M
return DefWindowProc (hwnd, message, wParam, lParam);
}1 K) K( H0 B# @% L; K' ~, r4 L8 j
}! x& d6 g7 D- [7 l* r??J
復(fù)制代碼
那好,一個(gè)問(wèn)題蝇更,我們的函數(shù)能夠響應(yīng)WM_QUIT 消息嗎沪编?如果按照某些材料上說(shuō)的,我們就不能響應(yīng)這個(gè)消息了年扩,去做一個(gè)程序試試——
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0) ;9 r??x2 p: Z??k5 V) ~
break;
case WM_QUIT:
MessageBox(hwnd,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);
break;
}- k??n# n, B5 b7 X0 N) ?
return DefWindowProc (hwnd, message, wParam, lParam);
}
復(fù)制代碼
果然不假蚁廓,上面的一些理論得到了證實(shí),可是牛刀不服厨幻,既然沒(méi)有用相嵌,那么要這個(gè)消息干嘛腿时?牛刀不服,換了一個(gè)地方打劫——
) p3 s2 X" v! A! j
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;, g( R! t0 I5 G- N
DispatchMessage (&msg) ;
}* }1 ]. p+ E" j' X4 R4 J. |
if(WM_QUIT==msg.message)MessageBox(NULL,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);
復(fù)制代碼
這一次饭宾,這個(gè)消息被我們打劫到了批糟,并且順利地執(zhí)行,那么為什么我們?cè)凇ndProc 函數(shù)中捏雌,得不到消息呢?我們來(lái)看看我們消息的執(zhí)行過(guò)程)——
- n9 \, X- R% g% I6 r8 E
while (GetMessage (&msg, NULL, 0, 0))??//得到消息笆搓,請(qǐng)注意性湿,如果消息是 WM_QUIT,那么這個(gè)函數(shù)就返回 0 满败,下面的程序就執(zhí)行不到了肤频。8 L0 q& U4 x- L* i
{1 ?% k, y- t2 ^. T& c2 B, m) o
TranslateMessage (&msg) ;??//翻譯程序植袍,翻譯消息# b??u$ h. U/ d) A
DispatchMessage (&msg) ;? ?//執(zhí)行消息饲漾,是這一句將消息隊(duì)列中的消息傳遞給 WndProc 函數(shù)肤京,所以一旦有了 WM_QUIT 消息稠茂,這一句就執(zhí)行不到艾岂,于是隙畜,我們的消息在 WndProc 函數(shù)中就捕捉不到了蒜埋。
}" f5 N9 C6 q2 u1 q; o% o
復(fù)制代碼
明白了上面的道理玖详,那么我們?nèi)绻朐谙⑻幚砗瘮?shù)中捕捉到這個(gè)消息挖藏,那么我們?cè)趺崔k呢暑刃?可以改一下下程序嘛,呵呵膜眠,看——
6 O9 |4 |+ ^3 y
int MsgRet;. i+ Q2 b" a3 i0 _/ v; y1 w
do4 g6 o2 P??F' \+ u
{? ? ? ? MsgRet=GetMessage (&msg, NULL, 0, 0);' V; s9 b2 n9 h' P# O/ j( B
TranslateMessage (&msg) ;! U! }$ k* ?* L& v" p2 H
DispatchMessage (&msg) ;
}while(MsgRet);? ? ? ? //我們改了成 do-while 結(jié)構(gòu)岩臣,這樣上面的消息就每條消息都有機(jī)會(huì)送到 WinProc 函數(shù)嘍
復(fù)制代碼
程序理論講完了,很可惜的是宵膨,我們的程序架谎, WndProc 中的 WM_QUIT 消息仍舊沒(méi)有被執(zhí)行,這是什么原因辟躏?谷扣??: i* O2 x8 _% C; U* q
很顯然捎琐,肯定被系統(tǒng)的 DispatchMessage (&msg) ; 函數(shù)給過(guò)濾掉了抑钟,不知牛刀考慮的有沒(méi)有道理,大家可以各抒己見(jiàn)野哭。
: P, k7 E2 Z: T
結(jié)論:WM_QUIT 是一個(gè)消息在塔,但這個(gè)消息不能在 WndProc 消息函數(shù)中被捕獲,如果要響應(yīng)拨黔,也只能在消息循環(huán)地位置攔截蛔溃,但我們一般不需要這樣做。
原文:"注意到WM_QUIT消息讓消息循環(huán)終止歸根結(jié)底是讓GetMessage返回為0,而GetMessage函數(shù)是從消息對(duì)列里取一條消息贺待,然后再返回徽曲,只能當(dāng)消息為WM_QUIT時(shí)才返回0結(jié)束消息循環(huán)。再仔細(xì)看一下SendMessage的注釋發(fā)現(xiàn)麸塞,SendMessage直接發(fā)送到窗口秃臣,并調(diào)用窗口處理程序,完成消息響應(yīng)哪工,即SendMessage 根本就沒(méi)有將消息發(fā)到消息對(duì)列中奥此,因此GetMessage無(wú)法從消息對(duì)列中收到WM_QUIT的消息。而PostMessage卻直接發(fā)送消息到消息對(duì)列中雁比,然后立即返回稚虎,這一點(diǎn)點(diǎn)的區(qū)別就解決了我們上面的問(wèn)題。陸解了這一點(diǎn)偎捎,就不難理解上面注釋中說(shuō)的為什么不讓直接使用PostMessage來(lái)發(fā)送WM_QUIT消息來(lái)終止程序了蠢终。"
GetMessage 是收到了 WM_QUIT 消息的,但牛刀的結(jié)論是:被 DispatchMessage 函數(shù)給過(guò)濾掉了茴她。( F' P8 F" m8 i: r
也就是說(shuō)寻拂,WM_QUIT 消息發(fā)送給窗口是無(wú)效的,所以使用 SendMessage 向窗口發(fā)送 WM_QUIT 消息則無(wú)效丈牢。6 c. T# _+ [/ ]0 Q# q
為了驗(yàn)證這個(gè)想法兜喻,牛刀去做了一個(gè)測(cè)試——
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{" L. T, v5 @. A% j. w& X
switch (message). K% }" W. Z5 T" `) q
{
case WM_LBUTTONDOWN:6 O* b??Z, C% w0 D
SendMessage(hwnd,WM_QUIT,0,0);# c! }$ H% g" f% j??^5 B. g
break;
case WM_DESTROY:
PostQuitMessage (0) ;
break;
case WM_QUIT:
MessageBox(hwnd,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);/ r6 x* ]" h; E+ ^$ W! l6 g
break;
}
return DefWindowProc (hwnd, message, wParam, lParam);' \4 s! Z4 Y; w6 A5 Q! o0 j
}
復(fù)制代碼
8 T??H" E- @7 y' @. W
2 C& E+ D5 y3 ]# Q( {( ]- {
牛刀驚奇地發(fā)現(xiàn),牛刀上面的 SendMessage 發(fā)送消息無(wú)效的結(jié)論是不正確的赡麦。窗口函數(shù)的確響應(yīng)的 WM_QUIT 消息朴皆,但由于這個(gè)消息沒(méi)有被 GetMessage 捕獲,所以程序根本沒(méi)有退出泛粹,也就是說(shuō)遂铡,使用 SendMessage 發(fā)送這個(gè)消息時(shí),是不經(jīng)過(guò)消息隊(duì)列的晶姊,也就是說(shuō)是不經(jīng)過(guò)——
while(GetMessage (&msg, NULL, 0, 0))7 }5 G% t0 i1 r( l# _
{
TranslateMessage (&msg) ;# B( y/ i1 I. s/ u# Z
DispatchMessage (&msg) ;5 ?+ N0 O9 a/ C8 R6 E6 [5 q
}
復(fù)制代碼
4 M" b??T, L% q$ @" @' q* N" z
這個(gè)消息循環(huán)的扒接,所以不能使得 GetMessage 返回 0 值。
于是们衙,牛刀又去測(cè)試了 PostMessage 消息:: w??C; B2 x% s" g7 @
% K4 _+ q3 ?7 T/ ?4 t6 \3 w! Q2 f
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)# b' n& m, Z" e( [' H
{5 h; Y3 f3 J( }" B% e
case WM_LBUTTONDOWN:
PostMessage(hwnd,WM_QUIT,0,0);
break;
case WM_DESTROY:5 R2 w- b2 k- d1 {/ t
PostQuitMessage (0) ;??h& H/ c' C) q3 C; U9 b
break;
case WM_QUIT:) B* v4 v1 P1 V) h! Z1 C4 u$ e
MessageBox(hwnd,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);
break;
}
return DefWindowProc (hwnd, message, wParam, lParam);& C$ |??W8 P2 Q; R/ @0 S# s$ r. t" Q
}
復(fù)制代碼
& q% Z! H: y5 d
由于消息這次是發(fā)進(jìn)了消息隊(duì)列钾怔,所以我們?cè)凇ndProc 函數(shù)中就又不能響應(yīng)消息了。8 y. Y) Q( r2 j* y??G' g0 N( U
. L2 A, \$ ~% \- u
綜上所述:
·WM_QUIT 的確是一條消息蒙挑,并且這個(gè)消息是可以發(fā)送到消息隊(duì)列中(使用PostMessage)宗侦,亦可以發(fā)送到窗口(使用SendMessage),但是忆蚀,我們是不能通過(guò)消息隊(duì)列將消息發(fā)送到窗口中的矾利,因?yàn)槲覀兊年?duì)列中的消息被 DispatchMessage 給過(guò)濾掉了姑裂。2 O, ]5 P9 x3 I! z# q" |
通過(guò)上面的一些討論與測(cè)試,我們基本可以估計(jì)出 DispatchMessage 的函數(shù)應(yīng)該是這樣或近似這樣的程序——
void DispatchMessage(MSG msg)
{
if(WM_QUIT!=msg.message)
{
SendMessage(msg.hwnd,msg.message,msg.wParam,msg.lParam);
}
}* i0 ]0 p# d??N3 m7 Z6 J
復(fù)制代碼
, @) s/ s, \( q! j
附:為什么不建議直接用 PostMessage 來(lái)發(fā) WM_QIUT 消息的牛刀解釋男旗。" q6 a/ x0 @??N+ U; A/ _
首先一點(diǎn)的就是舶斧,可以使用 PostMessage 來(lái)發(fā)送 WM_QUIT 消息,并且一點(diǎn)殘留都沒(méi)有(注:任務(wù)管理器中一點(diǎn)殘余都沒(méi)有)察皇。* J( d" o, {: b% `8 V1 W+ ?
當(dāng)然茴厉,窗口也沒(méi)有了,程序結(jié)束了什荣,但會(huì)有一個(gè)問(wèn)題矾缓,那就是,我們的窗口并沒(méi)有被銷(xiāo)毀溃睹,因?yàn)闆](méi)有來(lái)得及響應(yīng) WM_DESTROY 消息而账,為了驗(yàn)證胰坟,牛刀做了以下的程序——
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)7 A- O* z* B- H* T0 ~
{; \2 e( o4 i9 B! Z# m3 I
case WM_LBUTTONDOWN:* A: H. ]# x' n
PostMessage(hwnd,WM_QUIT,0,0);
break;1 ?" x" E8 t, D( T3 N9 k
case WM_DESTROY:
MessageBox(hwnd,"消息測(cè)試","WM_DESTROY消息測(cè)試",MB_OK);2 s" W- o1 p" }1 D) G, O
break;8 r9 d2 g2 ?5 y+ G??|( K* r7 L
case WM_QUIT:
MessageBox(hwnd,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);
break;1 x8 A& u% X0 z& C
}7 Z: N6 L2 C! O
return DefWindowProc (hwnd, message, wParam, lParam);& M8 }% t5 i- w
}
復(fù)制代碼
果然不假因篇,我們的銷(xiāo)毀窗口的消息并沒(méi)有接收到,我們的程序就退出了循環(huán)笔横,但是竞滓,窗口關(guān)閉了嗎?5 \' n( W- m6 H
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)" ^7 Y" I; Z' q- {) E
{
switch (message)/ @; z+ L- Y! D8 X
{
case WM_LBUTTONDOWN:) k- [* o* ?$ X
PostMessage(hwnd,WM_QUIT,0,0);2 @3 h: c, n$ r8 F7 F4 B
break;
case WM_CLOSE:( e" B% o( Y: r; F8 |: b8 ~
MessageBox(hwnd,"消息測(cè)試","WM_CLOSE消息測(cè)試",MB_OK);0 Z+ n% J/ `4 |' A" S/ ^# W9 U
break;" `4 B( B4 G* S+ }: E
case WM_DESTROY:
MessageBox(hwnd,"消息測(cè)試","WM_DESTROY消息測(cè)試",MB_OK);( k$ N( E, O4 [
break;
case WM_QUIT:
MessageBox(hwnd,"消息測(cè)試","WM_QUIT消息測(cè)試",MB_OK);
break;, [8 `" |( J) U# C/ i1 ]7 N2 k
}
return DefWindowProc (hwnd, message, wParam, lParam);; i! w) D4 @' {9 `4 B+ t% Z??L
}
復(fù)制代碼
# Z+ t' L6 C6 p- }
; o/ y4 ^1 ]5 u??@4 S
奇怪的是吹缔,窗口也沒(méi)有被關(guān)閉商佑。& Y; H0 A4 y( b
6 Z" R" k3 ?1 V
那么就有問(wèn)題了,窗口既沒(méi)有被銷(xiāo)毀厢塘,也沒(méi)有被關(guān)閉茶没,那么這個(gè)窗口我們也見(jiàn)不到了,那么這個(gè)窗口哪兒去了晚碾?[我們 C++ 中沒(méi)有像 Java 那樣的垃圾回收機(jī)制抓半,所以也不可能消失]
唯一的解釋?zhuān)覀兊拇翱谶€在內(nèi)存中,當(dāng)然格嘁,牛刀沒(méi)當(dāng)過(guò)黑客笛求,如果當(dāng)過(guò)黑客的話,應(yīng)該通過(guò)黑客技術(shù)可以將這個(gè)窗口重新顯示出來(lái)糕簿,但可以想像探入,那時(shí)候的窗口即使顯示出來(lái),也是一個(gè)死窗口懂诗,什么功能也沒(méi)有蜂嗽,因?yàn)檫@個(gè)窗口已經(jīng)和我們的程序脫節(jié)了,當(dāng)然黑客技術(shù)可以通過(guò)一些手段去映射我們的窗口消息到其他的函數(shù)上殃恒,去滿足其他程序的一些需求徒爹,可能功能已經(jīng)不是原來(lái)的功能了——怎么像是在說(shuō)《聊齋》故事啊荚醒,呵呵,比較恐怖隆嗅,呵呵界阁,又感覺(jué)在討論黑客技術(shù)啊,呵呵胖喳。3 R$ J0 n" j) u8 y" c" e9 W! E
" B0 j" M, X% Z; I2 i+ M
總之泡躯,窗口是有的,在內(nèi)存中丽焊,我們看不見(jiàn)了较剃,為什么上面像在搞黑客,也是這個(gè)原因技健,會(huì)出現(xiàn)內(nèi)存泄漏写穴,所以從建議的角度來(lái)說(shuō),是不建議用 PostMessage 來(lái)發(fā)送 WM_QUIT 消息的雌贱。1 K% p4 U??s( u
但啊送,是可以用 SendMessage 來(lái)發(fā)送 WM_QUIT 消息了,但此時(shí)欣孤,這個(gè)消息已經(jīng)沒(méi)有退出程序的功能了馋没,如果有必要,我們完全可以當(dāng)自定義的消息來(lái)使用降传,這樣一來(lái)篷朵,我們?nèi)绻胱远ㄒ粋€(gè)消息,又怕麻煩婆排,那么我們就完全可以不用定義声旺,而直接借用 WM_QUIT 消息來(lái)響應(yīng)就好,唯一的缺點(diǎn)就是段只,那就不能使用 PostMessage 來(lái)發(fā)送用戶自定義消息啦腮猖,呵呵,這不能不說(shuō)是多線程任務(wù)的一個(gè)遺憾翼悴,但如果想將消息當(dāng)函數(shù)用缚够,那一點(diǎn)問(wèn)題都沒(méi)有。6 h4 X* e/ c4 o??r
1 N' q+ [& A* y1 e
這就是牛刀對(duì) WM_QUIT 消息的一點(diǎn)粗淺的認(rèn)識(shí)鹦赎,希望對(duì)大家有所幫助谍椅。
我以為,SendMessage是立即調(diào)用窗口的回調(diào)函數(shù)古话,PostMessage是把消息排到消息隊(duì)列里面雏吭。?4樓
/ f# }/ o; Z1 o3 F3 a
WM_QUIT就是用來(lái)向系統(tǒng)聲明此消息隊(duì)列結(jié)束,不用繼續(xù)維持了陪踩。
重要更正:! M( n; T* |, p% E: r
上面4樓的最后一個(gè)程序杖们,窗口是關(guān)閉了的悉抵,最后打字時(shí),手誤了摘完,呵呵姥饰,不好意思。
⌒⒅巍5樓的說(shuō)法是正確的列粪,但是 WM_QUIT 的確是可以通過(guò) SendMessage 發(fā)送到窗口中去,并且在窗口消息處理中響應(yīng)的谈飒,但程序結(jié)束不了岂座,所以正常情況下,我們是不這樣用的杭措,也沒(méi)有必要费什。
謝謝樓上的回貼,并不是牛刀想復(fù)雜了手素,而是牛刀在討論 WM_QUIT 消息的發(fā)送機(jī)理鸳址。
1 ^- }2 x% Q) g! \( m
因?yàn)橛行┎牧仙险f(shuō) WM_QUIT 不是一個(gè)消息,只是設(shè)置一些標(biāo)志刑桑,而事實(shí)上在回調(diào)函數(shù)中也真的不能響應(yīng) WM_QUIT 消息氯质,所以牛刀寫(xiě)這篇文章募舟。0 E( o' }2 \0 u* x/ Q: ]# H
% z& \?????L& x( ]& D5 r5 k
試驗(yàn)的結(jié)果是—— WM_QUIT 是一個(gè)消息祠斧,并且在 WndProc 中亦可以響應(yīng),但是必須直接向窗口發(fā)出一個(gè)消息拱礁,也就是說(shuō)使用 SendMessage 發(fā)送琢锋;而 GetMessage(&msg,NULL,0,0) 是可以捕捉到消息的,并且僅在捕捉到此消息時(shí)呢灶,返回值是 0 吴超,至于你說(shuō)的 WM_QUIT 不為零,不這奇怪鸯乃,可以想像鲸阻,必定是在 GetMessage 函數(shù)中有如下代碼——" o' E8 ?: S7 _' V' I4 V??}7 V3 o
if(WM_QUIT==message)return 0;
復(fù)制代碼
' \) V% I4 V+ D' U5 R
并且事實(shí)上,WM_QUIT 消息在 DispatchMessage 函數(shù)中缨睡,也的確被過(guò)濾掉了鸟悴。因?yàn)槲覀兩厦娴拇a——4 o( N6 G??W3 b) y??f. u' g1 P
" W7 u% O# i9 _7 j
int MsgRet;
do
{& U1 k% q) O( n& ^- f
MsgRet=GetMessage (&msg, NULL, 0, 0);
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;, h5 v# A; B, N' s/ w/ Y
}while(MsgRet);0 H! |% {- O??G9 x
復(fù)制代碼
( ]; n3 F8 `# F& P0 j& i
是允許 WM_QUIT 消息通過(guò) DispatchMessage 函數(shù)的,然而奖年,并沒(méi)有發(fā)送到窗體细诸,所以這個(gè)消息被過(guò)濾掉了,當(dāng)然陋守,有兩種可能震贵,一種是被 DispatchMessage 函數(shù)給過(guò)濾掉了利赋,另一種可能是被 TranslateMessage 給過(guò)濾掉了,那么是哪一種情況呢猩系?牛刀做了如下程序媚送,看看效果——
! i/ d$ z4 {' P2 l2 C9 f
int MsgRet;
do
{; U3 a1 g6 K- T3 `, j
MsgRet=GetMessage (&msg, NULL, 0, 0);- j2 y. Q: L( Y5 m, b# A# e??}
if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在GetMessage函數(shù)后被捕獲","消息測(cè)試",MB_OK);: O4 U2 U) `, f$ f% e% O1 \
TranslateMessage (&msg) ;2 C??n4 w- t$ P, V! J* G5 m
if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在TranslateMessage函數(shù)后被捕獲","消息測(cè)試",MB_OK);
DispatchMessage (&msg) ;0 X; l6 z$ ~+ D9 Y: ^; O
if(WM_QUIT==msg.message)MessageBox(NULL,"WM_QUIT消息在DispatchMessage函數(shù)后被捕獲","消息測(cè)試",MB_OK);
}while(MsgRet);
復(fù)制代碼
& G; W; T5 x( ~4 `
三個(gè) Message 都能執(zhí)行,所以說(shuō)寇甸,TranslateMessage 并沒(méi)有改變消息季希, DispatchMessage 也根本沒(méi)有改變消息,所以消息必然是被 DispatchMessage 函數(shù)給過(guò)濾掉了幽纷。7 B+ s: Q+ z/ t! e$ z0 ]
2 w4 \8 n5 X- T3 E5 Z- ]+ ~
注:你的那段函數(shù)——
while (GetMessage(&msg,NULL,0,0))2 S9 u+ n1 c3 C" z4 D; l
{
TranslateMessage(&msg);? ? // Translates virtual key codes.
DispatchMessage(&msg);? ???// Dispatches message to window.( l0 K4 Q3 _& t
}
return (msg.wParam);? ?? ?? ???// Returns the value from PostQuitMessage.) m' Z( d: E, ~" c9 {0 Q; x
復(fù)制代碼
$ f0 @0 q$ S3 E+ R% A, D& q2 |