科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件MFC程序员的WTL指南之包容ActiveX

MFC程序员的WTL指南之包容ActiveX

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在本文中我将介绍ATL对在对话框中使用ActiveX控件的支持

作者:LITH 来源:BLOG 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
 响应控件触发的事件

  从浏览器控件得到接口非常简单,通过它可以单向的与控件通信。通常控件也会以事件的形式与外界通信,ATL有专用的类包装连接点和事件相应,所以我们可以从控件接收到这些事件。为使用对事件的支持需要做四件事:

  将CMainDlg变成COM对象

  添加IDispEventSimpleImpl到CMainDlg的继承列表

  填写事件映射链,它指示哪些事件需要处理

  编写事件响应函数

  CMainDlg的修改

  将CMainDlg转变成COM对象的原因是事件相应是基于IDispatch的,为了让CMainDlg暴露这个接口,它必须是个COM对象。IDispEventSimpleImpl提供了IDispatch接口的实现和建立连接点所需的处理函数,当事件发生时IDispEventSimpleImpl还调用我们想要接收的事件的处理函数。

  以下的类需要添加到CMainDlg的集成列表中,同时COM_MAP列出了CMainDlg暴露的接口:

#include <exdisp.h> // browser control definitions
#include <exdispid.h> // browser event dispatch IDs

class CMainDlg : public CAxDialogImpl<CMainDlg>,
public CUpdateUI<CMainDlg>,
public CMessageFilter, public CIdleHandler,
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMainDlg>,
public IDispEventSimpleImpl<37, CMainDlg, &DIID_DWebBrowserEvents2>
{
...
BEGIN_COM_MAP(CMainDlg)
COM_INTERFACE_ENTRY2(IDispatch, IDispEventSimpleImpl)
END_COM_MAP()
};

  CComObjectRootEx类CComCoClass共同使CMainDlg成为一个COM对象,IDispEventSimpleImpl的模板参数是事件的ID,我们的类名和连接点接口的IID。事件ID可以是任意正数,连接点对象的IID是DIID_DWebBrowserEvents2,可以在浏览器控件的相关文档中找到这些参数,也可以查看exdisp.h。

  填写事件映射链

  下一步是给CMainDlg添加事件映射链,这个映射链将我们感兴趣的事件和我们的处理函数联系起来。我们要看的第一个事件是DownloadBegin,当浏览器开始下载一个页面时就会触发这个事件,我们响应这个事件显示“please wait”信息给用户,让用户知道浏览器正在忙。在MSDN中可以查到DWebBrowserEvents2::DownloadBegin事件的原型

void DownloadBegin();

  这个事件没有参数,也不需要返回值。为了将这个事件的原型转换成事件响应链,我们需要写一个_ATL_FUNC_INFO结构,它包含返回值,参数的个数和参数类型。由于事件是基于IDispatch的,所以所有的参数都用VARIANT表示,这个数据结构的描述相当长(支持很多个数据类型),以下是常用的几个:

  VT_EMPTY: void
  VT_BSTR: BSTR 格式的字符串
  VT_I4: 4字节有符号整数,用于long类型的参数
  VT_DISPATCH: IDispatch*
  VT_VARIANT>: VARIANT
  VT_BOOL: VARIANT_BOOL (允许的取值是VARIANT_TRUE和VARIANT_FALSE)

  另外,标志VT_BYREF表示将一个参数转换成相应的指针。例如,VT_VARIANT|VT_BYREF表示VARIANT*类型。下面是_ATL_FUNC_INFO的定义:

#define _ATL_MAX_VARTYPES 8

struct _ATL_FUNC_INFO
{
CALLCONV cc;
VARTYPE vtReturn;
SHORT nParams;
VARTYPE pVarTypes[_ATL_MAX_VARTYPES];
};

  参数:

  cc

  我们的事件响应函数的调用方式约定,这个参数必须是CC_STDCALL,表示是__stdcall方式

  vtReturn

  事件响应函数的返回值类型

  nParams

  事件带的参数个数

  pVarTypes

  相应的参数类型,按从左到右的顺序

  了解这些之后,我们就可以填写DownloadBegin事件处理的_ATL_FUNC_INFO结构:

_ATL_FUNC_INFO DownloadInfo = { CC_STDCALL, VT_EMPTY, 0 };

  现在,回到事件响应链,我们为每一个我们想要处理的事件添加一个SINK_ENTRY_INFO宏,下面是处理DownloadBegin事件的宏:

class CMainDlg : public ...
{
 ...
 BEGIN_SINK_MAP(CMainDlg)
  SINK_ENTRY_INFO(37, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN,OnDownloadBegin, &DownloadInfo)
 END_SINK_MAP()
};

  这个宏的参数是事件的ID(37,与我们在IDispEventSimpleImpl的继承列表中使用的ID一样),事件接口的IID,事件的dispatch ID(可以在MSDN或exdispid.h头文件中查到),事件处理函数的名字和指向描述这个事件处理的_ATL_FUNC_INFO结构的指针。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章