翻譯:賴儀靈
出處:
http://blog.csdn.net/laiyiling,? http://www.shnenglu.com/techlab
聲明:版權(quán)歸原作者擁有,請勿隨意轉(zhuǎn)載此翻譯文檔,保留一切權(quán)利。
?
1.8???
添加和激發(fā)事件
?
當(dāng)某些客戶端對
COM
對象內(nèi)部所發(fā)生的事情感興趣時,我們希望,也能夠很自然的通知客戶端,而不需要客戶端檢測對象。
COM
提供了一種標(biāo)準(zhǔn)機(jī)制——連接點(diǎn)結(jié)構(gòu),來發(fā)送這些通知到客戶端(通常稱為“激發(fā)事件”)
?
連接點(diǎn)的事件通常是某個接口的方法。為了支持大量不同的客戶端,事件接口通常定義為
dispinterface
。在
ATL
的簡單對象向?qū)е校绻x擇支持連接點(diǎn),在工程的
IDL
文件中救會生成一個事件。下面的代碼演示了向?qū)傻囊粋€后增事件方法(粗體顯示):
[
?????????uuid(B830F523-D87B-434F-933A-623CEF6FC4AA),
?????????helpstring("_ICalcPiEvents Interface")
]
dispinterface _ICalcPiEvents {
?????????properties:
???????? methods:
????????[id(1)] void OnDigit([in] short nIndex,
?????????????? [in] short nDigit);
};
支持連接點(diǎn)選項(xiàng)除了修改
IDL
文件外,在類得定義中也會又幾處變化?;愔袝砑咏涌?/span>
IConnectionPointContainer
的實(shí)現(xiàn)
IConnectionPointContainerImpl
,它提供函數(shù)管理這個類上的多個事件接口。在此例子中,基類
IConnectionPointImpl
為指定事件接口
_ICalcPiEvent
實(shí)現(xiàn)了一個連接點(diǎn)。
COM_MAP
也被修改添加了一個
IConnectionPointContainer
的入口,一個新的
CONNECTION_MAP
也被添加到類中。
?
向?qū)б餐瑫r給連接點(diǎn)生成一個代理類。代理類也被添加到基類列表中,它提供了一種便捷的方法進(jìn)行真正的事件激發(fā)(也就是調(diào)用連接點(diǎn)上的方法)。此功能非常有用,因?yàn)檫B接點(diǎn)通常是基于
dispinterface
。
比如:
STDMETHODIMP CCalcPi::CalcPi(BSTR *pbstrPi) {
// (code to calculate pi removed for clarity)
...
// Fire each digit
for( short j = 0; j != m_nDigits; ++j ) {
Fire_OnDigit(j, (*pbstrPi)[j+2] - L'0');
}
...
}
CCalcPi
類對象現(xiàn)在可以發(fā)送
HTML
頁面能夠處理的事件:
<object classid="clsid:E5F91723-E7AD-4596-AC90-17586D400BF7"
??????? id=objPiCalculator>
??????? <param name=digits value=50>
</object>
<input type=button name=cmdCalcPi value="Pi to 50 Digits:">
<span id=spanPi>unknown</span>
<p>Distribution of first 50 digits in pi:
<table border cellpadding=4>
... <!- table code removed for clarity >
</table>
<script language=vbscript>
? ' Handle button click event
? sub cmdCalcPi_onClick
??? spanPi.innerText = objPiCalculator.CalcPi
? end sub
? ' Handle calculator digit event
? sub objPiCalculator_onDigit(index, digit)
??? select case digit
??? case 0: span0.innerText = span0.innerText + 1
??? case 1: span1.innerText = span1.innerText + 1
??? ... <! etc >
??? end select
??? spanTotal.innerText = spanTotal.innerText + 1
? end sub
</script>???
此示例
HTML
頁面處理這些事件,返回了
PI
的前
50
位數(shù)字和數(shù)字分類。如圖
1-11
所示。
?
圖
1-11? PI
的前
50
位小數(shù)
?
關(guān)于
ATL
支持連接點(diǎn)的更多信息,參考第九章“連接點(diǎn)”。
?
1.9???
使用窗口
?
正因?yàn)槲覀冮_發(fā)的是微軟窗口程序,因此很多時候可以很方便的彈出窗口或者對話框。比如,我們前面調(diào)用的
MessageBox
函數(shù)就會產(chǎn)生一個有點(diǎn)討厭的廣告通知。如圖
1-12
所示。
?
圖
1-12?
討厭的消息框
?
通常,建立一個自定義的對話框也是有幾分痛苦的。對大多數(shù)的
Win32
程序員來說,有時不得不陷于一大堆不喜歡的程序代碼中,有時陷于建立大量的消息傳遞代碼,把窗口消息傳遞到對話框的成員函數(shù)(畢竟對話框是一個對象)。和
MFC
一樣,
ATL
也有大量的代碼來建立窗口和對話框。添加一個新的對話框,選擇菜單
Project=>Add Class
,然后從彈出的對話框模板列表中選擇
ATL
對話框,如圖
1-13
所示。
?
圖
1-13?
插入一個對話框類
?
ATL
對話框向?qū)Вㄈ鐖D
1-14
)比其他的
ATL
類向?qū)Ш唵巍D銉H僅需要輸入
C++
類名稱,因?yàn)閷υ捒蚴且粋€
Win32
對象,而不是
COM
對象。
?
圖
1-14? ATL
對話框向?qū)?/span>
?
向?qū)?chuàng)建新的對話框資源,并用它創(chuàng)建一個從
CAxDialogImlo
繼承的類。派生類利用宏
MSG_MAP
來發(fā)送消息給處理函數(shù)。如下所示:
?
class CAdvert : public CAxDialogImpl<CAdvert> {
public:
? CAdvert() {}
? ~CAdvert() {}
? enum { IDD = IDD_ADVERT };
?
BEGIN_MSG_MAP(CAdvert)
???
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
??? COMMAND_HANDLER(IDOK, BN_CLICKED, OnClickedOK)
??? COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnClickedCancel)
??? CHAIN_MSG_MAP(CAxDialogImpl<CAdvert>)
END_MSG_MAP()
?
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam,
????????????????????? BOOL& bHandled) {
??? if( m_bstrClient.Length() ) {
????? CComBSTR bstrCaption = OLESTR("CalcPi sponsored by ");
????? bstrCaption += m_bstrClient;
?
????? USES_CONVERSION;
????? SetWindowText(OLE2CT(bstrCaption));
??? }
???
return 1; //
允許系統(tǒng)設(shè)置焦點(diǎn)
? }
?
? LRESULT OnClickedOK(WORD wNotifyCode, WORD wID, HWND hWndCtl,
???? BOOL& bHandled) {
??? EndDialog(wID);
??? return 0;
}
?
? LRESULT OnClickedCancel(WORD wNotifyCode, WORD wID,
??? HWND hWndCtl, BOOL& bHandled) {
??? EndDialog(wID);
??? return 0;
? }
?
?
?CComBSTR m_bstrClient;
};
?
如果你還想處理其他的消息,只需要手動在消息映射宏里添加適當(dāng)?shù)南⑷肟诤吞幚砗瘮?shù)即可。如果你愿意,你還可以通過
Class
視圖,在
CAxDialogImli
基類上點(diǎn)擊右鍵添加消息處理函數(shù):選擇屬性,點(diǎn)擊消息工具欄。圖
1-15
顯示了窗口結(jié)果。
?
圖
1-15
添加窗口消息處理函數(shù)
?
?
有關(guān)
ATL
對窗口支持的更多信息(包括建立獨(dú)立的窗口應(yīng)用程序),請參考第十章“窗口”。
?
1.10
?COM
控件
?
COM
控件是一種自己能提供用戶界面(
UI
)的對象,而這些
UI
與控件容器緊密集成。
ATL
通過基類
CComControl
、以及其他的一些
IXxxImlp
接口實(shí)現(xiàn),對
COM
控件提供了廣泛的支持。這些基類能處理創(chuàng)建簡單控件大部分細(xì)節(jié)(盡管在高級特征里還包括很多內(nèi)容,這些會在第十一章的“
ActiveX
控件”里介紹)。在生成
CalcPi
類時的
Add Class
對話框里,如果你選擇了
ATL Conotrol
,只需要實(shí)現(xiàn)
OnDraw
函數(shù)可以實(shí)現(xiàn)
UI
了:?
HRESULT CCalcPi::OnDraw(ATL_DRAWINFO& di) {
CComBSTR bstrPi;
if( SUCCEEDED(this->CalcPi(&bstrPi)) ) {
DrawText(di.hdcDraw, COLE2CT(bstrPi), -1,
(RECT*)di.prcBounds,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
return S_OK;
}
向?qū)瑯訒梢粋€示例
HTML
頁面,我們把示例頁面修改一下,使它占據(jù)整個瀏覽器,并把初始的小數(shù)位設(shè)置為
50
:
?
<HTML>
<HEAD>
<TITLE>ATL 8.0 test page for object CalcPiControl</TITLE>
</HEAD>
<BODY>
?
<OBJECT ID="CalcPi"
??? CLASSID="CLSID:9E7ABA7A-C106-4813-A50C-B15C967264B6"
??? height="100%" width="100%">
??? <param name="Digits" value="50">
</OBJECT>
?
</BODY>
</HTML>
?
在
IE
中顯示這個
HTML
頁面,它將產(chǎn)生控件的一個視圖(圖
1-16
)。關(guān)于用
ATL
建立控件的更多信息,請參考第十一章“
ActiveX
控件”。
?
圖
1-16 ?Internet Explorer
中的
CalcPi
控件