chHANDLE_DLGMSG(windows核心編程)講解

來源:互聯網
上載者:User

看完《Windows程式設計》後開始看《windows核心編程》,

結果看第一個案例的時候就很驚人的發現,Jeffery大牛的代碼很深奧。乍一看好像沒有包含《windows.h》。

看看包含的標頭檔發現,CmnHdr.h中已經包含了《windows.h》。而CmnHdr.h中的代碼更嚇人,如果沒有講解,不知道怎麼看才好。後來才知道原來書的最後有專門的搭建環境的介紹,基本上全面的講解了CmnHdr.h的東西。

 

CmnHdr.h中包含了大牛的很多自己的東西。在看到chHANDLE_DLGMSG這個宏的時候,才知道有訊息分流器這麼個東西。後來到處尋找資訊,才發現很多以前不知道的東西。具體的訊息分流器我不介紹,只是想屢一下大牛寫chHANDLE_DLGMSG的動機。書中介紹很簡短,只是說HANDLE_MSG對處理訊息對話方塊過程不能返回TRUE或FALSE來告訴對話方塊過程我們到底有沒有處理訊息。為什麼HANDLE_MSG不能正確返回呢?

 

原因在於HANDLE_MSG只是針對HANDLE_##message的簡單封轉。##message是指將HANDLE與具體的訊息串連起來,而且是訊息的宏定義方式(如WM_INITDIALOG而不是0x0110)。例如:

HANDLE_##WM_INITDIALOG就得到HANDLE_WM_INITDIALOG,但你可不能把WM_INITDIALOG的具體的數字寫進去。

 

HANDLE_MSG宏定義如下:

 

#define HANDLE_MSG(hwnd, message, fn)    /
    case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

 

可以看到只是加上case和return語句。所以HANDLE_MSG只是考慮到了形式上正確,卻無法應對所有的訊息處理的傳回值。HANDLE_MSG的訊息返回完全靠HANDLE_##message的宏處理。

 

假如:HANDLE_##message的message是WM_INITDIALOG,那麼HANDLE_##message就是HANDLE_WM_INITIDALOG。

 

HANDLE_WM_INITDIALOG宏定義如下:

 

#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) /
    (LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)

 

可以看到如果在訊息對話方塊過程中使用HANDLE_MSG(hwnd,WM_INITDIALOG,Dlg_InitDialog);是沒有問題的。是啊,我只說了對WM_INITDIALOG沒有問題,windows裡面那麼多訊息,其他訊息就很有問題。看WM_COMMAND訊息吧!

 

HANDLE_WM_COMMAND宏定義如下:

 

#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) /
    ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)

 

可以看出HANDLE_WM_COMMAND根本沒有傳回值,因為fn的形式根本有沒指明傳回值。沒有傳回值那為什麼HANDLE_MSG要返回呢?

這就是HANDLE_MSG的問題了,設計HANDLE_WM_COMMAND的只是想做case WM_COMMAND和return TRUE之間的過程。而HANDLE_MSG卻只是做的了簡單形式的封裝,所以這就是HANDLE_MSG的問題。

 

對於對話方塊訊息處理過程我們應該使用SetDlgMsgResult宏,來正確返回。這就是大牛chHANDLE_DLGMSG用到的宏,chHANDLE_DLGMSG中封裝了SetDlgMsgResult。

 

這是大牛的chHANDLE_DLGMSG的宏定義:

 

#define chHANDLE_DLGMSG(hWnd, message, fn)                 /
   case (message): return (SetDlgMsgResult(hWnd, uMsg,     /
      HANDLE_##message((hWnd), (wParam), (lParam), (fn))))

 

這是SetDlgMsgResult宏定義:

 

#define     SetDlgMsgResult(hwnd, msg, result) (( /
        (msg) == WM_CTLCOLORMSGBOX      || /
        (msg) == WM_CTLCOLOREDIT        || /
        (msg) == WM_CTLCOLORLISTBOX     || /
        (msg) == WM_CTLCOLORBTN         || /
        (msg) == WM_CTLCOLORDLG         || /
        (msg) == WM_CTLCOLORSCROLLBAR   || /
        (msg) == WM_CTLCOLORSTATIC      || /
        (msg) == WM_COMPAREITEM         || /
        (msg) == WM_VKEYTOITEM          || /
        (msg) == WM_CHARTOITEM          || /
        (msg) == WM_QUERYDRAGICON       || /
        (msg) == WM_INITDIALOG             /
    ) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))

 

chHANDLE_DLGMSG中,return返回的值即使SetDlgMsgResult返回的值。那麼SetDlgMsgResult返回什麼值呢?

讓我們看看,如果訊息是

(msg) == WM_CTLCOLORMSGBOX      || /
        (msg) == WM_CTLCOLOREDIT        || /
        (msg) == WM_CTLCOLORLISTBOX     || /
        (msg) == WM_CTLCOLORBTN         || /
        (msg) == WM_CTLCOLORDLG         || /
        (msg) == WM_CTLCOLORSCROLLBAR   || /
        (msg) == WM_CTLCOLORSTATIC      || /
        (msg) == WM_COMPAREITEM         || /
        (msg) == WM_VKEYTOITEM          || /
        (msg) == WM_CHARTOITEM          || /
        (msg) == WM_QUERYDRAGICON       || /
        (msg) == WM_INITDIALOG             /
中的一個,那麼傳回值就是我們寫的函數的傳回值,result在chHANDLE_DLGMSG中被替換成對應的訊息處理函數fn。如果訊息不是其中的,那麼那麼我們先執行SetWindowLongPtr(稍後講),最後返回TRUE(根據逗號操作符特性)。注意執行SetWindowLongPtr的時候調用的訊息處理函數result(其實就是fn)。

 

但為什麼要這麼做呢?這些WM_CTLCOLORMSGBOX     WM_CTLCOLOREDIT 。。。有什麼特殊的嗎? 這些訊息的傳回值都是有已知的且有自己含義的,對於這些訊息只需要返回它們函數處理的傳回值就讓程式正常運行。但對於訊息WM_COMMAND就很難說了,很有可能是某個控制項的通知訊息,需要一個值,這個值可能是零也可能不是零,所以不能像WM_CTLCOLORMSGBOX那樣處理了,因為對話方塊過程中TRUE大部分時候代表使用者處理此訊息,FALSE或0代表使用者沒處理此訊息,那麼對話方塊的父訊息處理過程會進行預設處理。這樣的話,如果一個WM_COMMAND的處理訊息需要返回0,怎麼辦?這樣辦,先返回TRUE,然後用SetWindowLongPtr設定需要返回的傳回值,返回TRUE是向父視窗表明你已經處理了,但傳回值最後被代替成了SetWindowlongPtr的值,這樣才能正常工作。就這樣了!

 

其實這麼繞人的根本原因是因為:

 

windows內的對話方塊訊息過程是這樣處理的.

LRESULT CALLBACK DefDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
  DLGPROC dp = (DLGPROC)GetWindowLongPtr(hdlg, DWLP_DLGPROC);  
  SetWindowLongPtr(hdlg, DWLP_MSGRESULT, 0);  
  INT_PTR fResult = dp(hdlg, uMsg, wParam, lParam);  
 if (fResult) return GetWindowLongPtr(hdlg, DWLP_MSGRESULT);  
  else ...做預設的事...  

 

 

上述代碼轉載了以為csdn朋友的內容,我稍加解釋:
就是因為對話方塊真正的訊息處理過程是這樣的。通過對話方塊過程(對話方塊視窗過程和對話方塊過程要分清)傳回值表明對話方塊過程是否處理此訊息,通過SetWindowlongPtr(...,DLG_MSGRESULT)設定對話方塊的傳回值,因為對話方塊視窗過程用GetWindowLongPtr獲得此值並做妥善處理。

 

繼續努力!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.