中文名 | 消息分流器 | 文章作者 | Bideyore[E.S.T] |
---|---|---|---|
信息來源 | 邪惡八進制 | 相????關 | windowsx.h這個頭文件 |
Windowsx.h包含了這樣一些內容:
宏API,窗口消息分流器,控件API;
所有的這些宏定義,可以使你的程序更加安全,簡潔,結構更清晰,大大提高程序的可讀性;其中窗口消息分流器(message cracker)是我們今天要討論的話題,它可以使我們的API程序變得更簡潔。下面就進入我們的主題:(有關windowsx.h的更多內容,可以參考 MS Knowledge Base Article #83456.)
消息分流器是Windows提供的一組宏定義,它的兩個最大的作用,用MS的話來說,就是:
● 安全的數(shù)據(jù)類型,因為消息分流器完成了大量的類型轉換的工作;
● 使程序向32位windows的轉化更簡單;
當然,使用消息分流器會大大改變程序的面貌,你也可以選擇不使用它。
下面我們就以一個對話框窗口的消息處理過程為例,看看消息分流器到底是怎么運作的。
1.消息分流器的基本使用
先看一個普通的窗口消息處理函數(shù),它可能需要處理一些窗口的初始化,無效客戶區(qū)重繪等消息:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
// ...
return 0;
case WM_PAINT:
// ...
return 0;
case WM_DESTROY:
//...
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
而通過使用消息分流器,我們可以把每個case都寫到相應的消息處理函數(shù)中,就像下面這樣:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate);
case WM_PAINT:
return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);
case WM_DESTROY:
return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
這里用到了三個宏定義:HANDLE_WM_CREATE, HANDLE_WM_PAINT, HANDLE_WM_DESTROY;這三個宏定義就是我們的三個消息分流器(別看叫什么分流器,說穿了也不值幾個錢,呵呵),它們在windowsx.h中的定義如下:
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn)
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) "para" label-module="para">
#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn)
((fn)(hwnd), 0L)
#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn)
((fn)(hwnd), 0L)
把這三個宏定義替換回去,就變成:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return Cls_OnCreate(hwnd, (LPCREATESTRUCT)(lParam) "para" label-module="para">
// 如果處理了消息,則Cls_OnCreate應返回TRUE,導致WndProc返回0,否則Cls_OnCreate返回FALSE,導致WndProc返回-1;
case WM_PAINT:
return Cls_OnPaint(hwnd), 0L;
// 逗號表達式;Cls_OnPaint是void類型,這里返回0;
case WM_DESTROY:
return Cls_OnDestroy(hwnd), 0L; // 同Cls_OnPaint
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
之后我們就可以按照消息分流器的定義編寫相應的消息處理函數(shù)了:
BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct){…};
void Cls_OnPaint(HWND hwnd){…};
void Cls_OnDestroyClipboard(HWND hwnd){…};
windowsx.h還提供了一個更加簡化的方法:使用HANDLE_MSG宏,這個宏是這樣定義的:
#define HANDLE_MSG(hwnd, message, fn)
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
這個宏要做的就是根據(jù)不同的message(##用來連接前后的字符串),把自己“變成”相應的HANDLE_XXXXMESSAGE形式的宏,再通過相應的宏來執(zhí)行消息處理代碼;
比如實際代碼中寫入:
HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate)
則經過轉換就變成:
case (WM_CREATE): return HANDLE_WM_CREATE((hwnd), (wParam), (lParam), (Cls_OnCreate))
這樣,我們就可以直接把程序寫為:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate);
HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint);
HANDLE_MSG(hwnd, WM_DESTROY, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
之后直接編寫相應的消息處理過程就可以了。是不是簡潔多了?而且把消息處理封裝到函數(shù)里面,就可以使用VS直接跳轉到這個函數(shù),再也不用費勁去找那個 case了。要注意的一點是,雖然windowsx.h里包括了所有消息對應的分流器,但它們的參數(shù)是宏定義顯式說明的,在編寫消息處理函數(shù)時,必須遵循宏定義中的參數(shù)類型,否則會導致錯誤;這么多消息分流器,我們每次新寫一個消息處理函數(shù)時就得看看是否把參數(shù)設置正確了,整個過程繁瑣冗長。好在已經有一個工具叫Message Cracker Wizard,可以幫助我們生成消息分流器和相關的處理過程。
2.在對話框中使用消息分流器
在對話框消息處理中,窗口子類化是我們經常使用的手段,這也可以通過消息分流器實現(xiàn),但是有點小問題 :>
下面是一個使用了windowsx.h消息分流器的對話框及其處理過程:
……
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int)
{
DialogBoxParam(
hinstExe, MAKEINTRESOURCE(IDD_PASSTHRU), NULL, (DLGPROC)Dlg_Proc, 0);
return(0);
}
……
LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog); // 不能直接使用HANDLE_MSG宏
HANDLE_MSG(hwnd, WM_COMMAND, Cls_OnCommand); // 不能直接使用HANDLE_MSG宏
}
return false;
}
以上程序中直接使用HANDLE_MSG可能導致錯誤;為什么呢?問題出在子類化的消息處理過程的返回值上,msdn中對于對話框消息處理過程的返回值有如下說明:
一般情況下,對話框過程函數(shù)應該在處理了消息的情況下返回TRUE,如果沒有處理,則返回FALSE。如果對話框過程返回了FALSE,那么對話框管理器為這條消息準備默認的對話操作。
如果對話框處理了一個需要特定返回值的消息,則對話框的返回值應該被設置為調用SetWindowLong(The SetWindowLong function changes an attribute of the specified window. The function also sets a 32-bit (long) value at the specified offset into the extra window memory of a window. )后的返回值,并在返回TRUE之前立即返回這個值。注意你必須立即調用SetWindowLong(這個函數(shù)用于調用窗口子類化的過程),這會導致DWL_MSGRESULT值被一個嵌套的對話框消息改寫。返回值為特定值的消息有:
· WM_CHARTOITEM
· WM_COMPAREITEM
· WM_CTLCOLORBTN
· WM_CTLCOLORDLG
· WM_CTLCOLOREDIT
· WM_CTLCOLORLISTBOX
· WM_CTLCOLORSCROLLBAR
· WM_CTLCOLORSTATIC
· WM_INITDIALOG
· WM_QUERYDRAGICON
· WM_VKEYTOITEM
看到沒有? 我們的消息WM_INITDIALOG也在其中,對這個消息進行處理的過程不能簡單的返回TRUE表示對消息進行了處理,而是另有其意;它將轉化為:
case (WM_INITDIALOG): return HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, Cls_OnInitDialog);
宏HANDLE_WM_INITDIALOG定義如下:
#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn)
(LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)
對WM_INITDIALOG的處理,如果返回TRUE,則表示設置鍵盤焦點到對話框的默認控件,否則返回FALSE;這時好像還看不出什么問題,而對于我們的另外一個消息WM_COMMAND,HANDLE_MSG簡單的把它變成:
case (WM_COMMAND): return HANDLE_WM_COMMAND(hwnd, wParam, lParam, Cls_OnCommand);
宏HANDLE_WM_COMMAND定義如下:
#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn)
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
問題出來了,我們的Cls_OnCommand由于是個void型的函數(shù),是沒有返回值的,因此windows默認這種消息處理過程必須返回一個0值,而返回0值不就表示我們的消息過程不處理這個消息么?這個矛盾是HANDLE_MSG無法解決的。怎么辦才能使消息過程在處理完WM_COMMAND消息之后正確的返回一個TRUE呢? 答案是使用另一個windowsx.h中的宏:SetDlgMsgResult(hwnd, msg, result)
這個宏定義如下:
#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
) "_blank" href="/item/SetWindowLongPtr">SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))
(有沒有注意到,里面多了一個WM_CTLCOLORMSGBOX ? 這個消息是16位WinAPI中的消息,一度被轉換為Win32 API的一個消息;現(xiàn)在在最新的32位API中已經被刪除了;保留它可能考慮到兼容性的問題,這里不做進一步討論)
現(xiàn)在看到了,如果對話框過程處理的消息恰巧為返回特定值中的一個,則如實返回result;不要被前面的BOOL蒙蔽,BOOL在頭文件中的定義實際上是一個int型,一旦需要返回非TRUE或FALSE的其他值,照樣可以;這樣,我們的Cls_OnInitDialog就能夠正確的返回它的BOOL值了,而Cls_OnCommand在處理之后,也可以由后面的逗號表達式正確的返回一個TRUE表示消息已處理。
在《Windows核心編程》一書中,大牛Jeffrey自己定義了一個宏,使SetDlgMsgResult宏的使用更加方便:
#define chHANDLE_DLGMSG(hwnd, message, fn)
case (message): return (SetDlgMsgResult(hwnd, uMsg,
HANDLE_##message((hwnd), (wParam), (lParam), (fn))))
可見這個宏只是簡單的對SetDlgMsgRseult宏進行了封裝。
這樣,我們最終的代碼可以寫成:
LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog); // 使用大牛的chHANDLE_DLGMSG宏
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Cls_OnCommand);
}
return false;
}
下面把原來程序整個框架列出來:
LRESULT CALLBACK Dlg_Proc(HWND hwnd, UNIT umsg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_COMMAND: // 每個case都被一個message cracker代替,這里使用大牛同志的
// do something; // chHANDLE_DLGMSG宏;這個宏負責對消息篩選,處理并返回相應的值
return true;
case WM_INITDIALOG:
// do something;
return xxxx;
}
return false; // 如果消息不在我們的DlgProc過程中被處理,則告訴調用這個DlgProc的消息,
} //告訴系統(tǒng)的對話框管理器,這個消息我們不處理,交給你了
對比一下,消息分流器的作用不言自明。
以上只是介紹了消息分流器的部分應用,更多創(chuàng)造性的用法還等你自己在實踐中發(fā)掘。
文章作者:Bideyore[E.S.T]
對于熟悉Win API編程的同志們來說,windowsx.h這個頭文件應該不會太陌生吧,這次要講的內容就來自這個windowsx.h頭文件。
經常能在msdn上查到這樣一些函數(shù),明明是個函數(shù),而且模樣長得和一般的api函數(shù)也一樣一樣的,可卻叫做macro,為什么呢?留意一下函數(shù)使用的requirement,你會發(fā)現(xiàn),它的聲明正是在windowsx.h這個頭文件里。
1、一根電纜(YJV22-4*95)在各層需要分支到各個電表箱中用導線分流器是可行的。 2、導線分流器在河南08中套電纜中間接頭定額子目
所謂的USB分流器叫做USB HUB?! SB Hub就是USB接口擴展器。是一種可以將一個USB接口擴展為多個(通常為4個),并可以使這些接口同時使用的裝置?! ?、USB-HUB是提供擴展通訊的...
所謂的USB分流器叫做USB HUB?! SB Hub就是USB接口擴展器。是一種可以將一個USB接口擴展為多個(通常為4個),并可以使這些接口同時使用的裝置。 1、USB-HUB是提供擴展通訊的...
格式:pdf
大小:191KB
頁數(shù): 2頁
評分: 4.8
P&H4100XPC電鏟運行中,當電樞電流達到額定電流的140%時,分流器模塊檢測到過流現(xiàn)象,分流器保護電路開始運行。分流電路運行分為三個階段:分流器電容充電、過流檢測、關斷晶閘管以及釋放電機能量。
FL-2型分流器、FL-2B型分流器、FL-2F型風冷平板分流器、FL-2S型水冷平板分流器、FL-2D型分流器(DIN43703 shunt)、FL-13型分流器(俄羅斯型分流器)、FL-15型美式分流器、FL19型電焊機分流器、FL-21出口型分流器(臺灣型分流器)、FL-27型0.2級分流器、FL-29型分流器、FL-39型分流器
(1)按所用電流表(或電流電壓兩用表)表盤上所標出的mV數(shù)選擇分流器的額定壓降規(guī)格(一般常用的是75mV或45mV)。若所用電流表無此值,則用下式計算表的電壓量限,然后再選擇分流器的額定壓降規(guī)格。
表的電壓量限(mV)=電流表滿刻度時的電流(A)×電流表的內阻(Ω)/1000
(2)按欲擴大的電流量程選擇分流器的額定電流規(guī)格。
(3)將選定的分流器兩個電流端分別與電源和負載相連接,電位端接電流表,應注意電流表的端子極性要接對,則電流表的量程就擴大到了分流器上標定的電流值。
對于電機試驗測量,往往一塊電流表要配置多個分流器,以解決在較大測量范圍都能保證要求的測量準確度問題。此時要求所用的所有分流器的額定電壓降都與所配電流表一致,例如75mV。這樣,分流器選定后,電流表的滿量程就是所選分流器的額定電流值,電流表的倍數(shù)(即其表盤刻度每格電流數(shù))即為分流器的額定電流除于表盤刻度總格數(shù)。
用于直流電流測量的分流器有插槽式和非插槽式。分流器有錳鎳銅合金電阻棒和銅帶,并鍍有鎳層。其額定壓降是60mV,但也可被用作75、100、120、150及300mV。插槽式分流器額定電流有以下幾種:5A,10A,15A,20A和25A。
分流器是分流器是測量直流電流用的,根據(jù)直流電流通過電阻時在電阻兩端產生電壓的原理制成。分流器實際就是一個阻值很小的電阻,當有直流電流通過時,產生壓降,供直流電流表顯示; 直流電流表實際是電壓表,滿度值75mV; 直流電流表和分流器是配套使用的; 比如:100A電流表配套的分流器阻值為0.00075歐; 即100A*0.00075歐=75mV; 50A電流表配套的分流器阻值為0.0015歐; 50A*0.0015歐=75mV。