翻译:赖仪灵
出处:
http://blog.csdn.net/laiyiling, http://www.cppblog.com/techlab
声明:版权归原作者拥有,请勿随意转载此翻译文档,保留一切权利。
1.8
添加和激发事件
当某些客户端对
COM
对象内部所发生的事情感兴趣时,我们希望,也能够很自然的通知客户端,而不需要客户端检测对象。
COM
提供了一种标准机制——连接点结构,来发送这些通知到客户端(通常称为“激发事件”)
连接点的事件通常是某个接口的方法。为了支持大量不同的客户端,事件接口通常定义为
dispinterface
。在
ATL
的简单对象向导中,如果选择支持连接点,在工程的
IDL
文件中救会生成一个事件。下面的代码演示了向导生成的一个后增事件方法(粗体显示):
[
uuid(B830F523-D87B-434F-933A-623CEF6FC4AA),
helpstring("_ICalcPiEvents Interface")
]
dispinterface _ICalcPiEvents {
properties:
methods:
[id(1)] void OnDigit([in] short nIndex,
[in] short nDigit);
};
支持连接点选项除了修改
IDL
文件外,在类得定义中也会又几处变化。基类中会添加接口
IConnectionPointContainer
的实现
IConnectionPointContainerImpl
,它提供函数管理这个类上的多个事件接口。在此例子中,基类
IConnectionPointImpl
为指定事件接口
_ICalcPiEvent
实现了一个连接点。
COM_MAP
也被修改添加了一个
IConnectionPointContainer
的入口,一个新的
CONNECTION_MAP
也被添加到类中。
向导也同时给连接点生成一个代理类。代理类也被添加到基类列表中,它提供了一种便捷的方法进行真正的事件激发(也就是调用连接点上的方法)。此功能非常有用,因为连接点通常是基于
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
类对象现在可以发送
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
位数字和数字分类。如图
1-11
所示。
图
1-11 PI
的前
50
位小数
关于
ATL
支持连接点的更多信息,参考第九章“连接点”。
1.9
使用窗口
正因为我们开发的是微软窗口程序,因此很多时候可以很方便的弹出窗口或者对话框。比如,我们前面调用的
MessageBox
函数就会产生一个有点讨厌的广告通知。如图
1-12
所示。
图
1-12
讨厌的消息框
通常,建立一个自定义的对话框也是有几分痛苦的。对大多数的
Win32
程序员来说,有时不得不陷于一大堆不喜欢的程序代码中,有时陷于建立大量的消息传递代码,把窗口消息传递到对话框的成员函数(毕竟对话框是一个对象)。和
MFC
一样,
ATL
也有大量的代码来建立窗口和对话框。添加一个新的对话框,选择菜单
Project=>Add Class
,然后从弹出的对话框模板列表中选择
ATL
对话框,如图
1-13
所示。
图
1-13
插入一个对话框类
ATL
对话框向导(如图
1-14
)比其他的
ATL
类向导简单。你仅仅需要输入
C++
类名称,因为对话框是一个
Win32
对象,而不是
COM
对象。
图
1-14 ATL
对话框向导
向导会创建新的对话框资源,并用它创建一个从
CAxDialogImlo
继承的类。派生类利用宏
MSG_MAP
来发送消息给处理函数。如下所示:
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; //
允许系统设置焦点
}
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;
};
如果你还想处理其他的消息,只需要手动在消息映射宏里添加适当的消息入口和处理函数即可。如果你愿意,你还可以通过
Class
视图,在
CAxDialogImli
基类上点击右键添加消息处理函数:选择属性,点击消息工具栏。图
1-15
显示了窗口结果。
图
1-15
添加窗口消息处理函数
有关
ATL
对窗口支持的更多信息(包括建立独立的窗口应用程序),请参考第十章“窗口”。
1.10
COM
控件
COM
控件是一种自己能提供用户界面(
UI
)的对象,而这些
UI
与控件容器紧密集成。
ATL
通过基类
CComControl
、以及其他的一些
IXxxImlp
接口实现,对
COM
控件提供了广泛的支持。这些基类能处理创建简单控件大部分细节(尽管在高级特征里还包括很多内容,这些会在第十一章的“
ActiveX
控件”里介绍)。在生成
CalcPi
类时的
Add Class
对话框里,如果你选择了
ATL Conotrol
,只需要实现
OnDraw
函数可以实现
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;
}
向导同样会生成一个示例
HTML
页面,我们把示例页面修改一下,使它占据整个浏览器,并把初始的小数位设置为
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
页面,它将产生控件的一个视图(图
1-16
)。关于用
ATL
建立控件的更多信息,请参考第十一章“
ActiveX
控件”。
图
1-16 Internet Explorer
中的
CalcPi
控件