代码之家  ›  专栏  ›  技术社区  ›  Georg Fritzsche

internet explorer内容插件中的脚本对象

  •  5
  • Georg Fritzsche  · 技术社区  · 15 年前

    虽然有很多关于浏览器助手对象的指南,但我很难找到关于如何为内容插件(即嵌入到网站中)实现脚本化对象(即除了主控件)的资源。
    为了避免误解:问题是关于可编写脚本的对象,插件对象可能会返回到网站中的脚本,例如从方法调用返回。

    IDispatch ,我不知道如何处理事件(即 attachEvent ).您是否应该手动执行此操作(例如,处理呼叫 附件

    1 回复  |  直到 15 年前
        1
  •  3
  •   meklarian    15 年前

    更新(从插件发布事件)

    好的,我也这么认为 女朋友 另外,我看到期望的机制是相反的——从DOM之外提供的组件发出事件。

    这与MSHTML事件的处理方式类似,但插件的对象需要使用不同的机制检查提供给它的对象。

    在提供事件(或支持为事件附加对象)的对象上,通过IDispatch(如果需要,还可以通过双接口)提供attachEvent和detachEvent方法。如果希望它与HTML元素无缝结合,那么应该以与IHTMlement上提供的相同的方式声明它们。dispid不必匹配,但参数和类型的顺序应该匹配。

    attachEvent Method (IHTMLElement2) @ MSDN
    detachEvent Method (IHTMLElement2) @ MSDN

    [id(DISPID_IHTMLELEMENT2_ATTACHEVENT)] HRESULT attachEvent(
      [in] BSTR event,
      [in] IDispatch* pDisp,
      [retval, out] VARIANT_BOOL* pfResult);
    [id(DISPID_IHTMLELEMENT2_DETACHEVENT)] HRESULT detachEvent(
      [in] BSTR event,
      [in] IDispatch* pDisp);
    

    通过attachEvent接收呼叫时,需要将事件名称与接收的对象相关联。类似地,当您通过detachEvent接收调用时,需要清除对象和事件名称的关联。

    当您希望发出事件时,请检查您存储的所有对象,以查找与您的事件匹配的应调用的方法。理论上,您不必使用与事件名称相同的方法名称,但在实践中,如果您这样做,维护和管理将更容易。首先检查IDispatch本身,调用GetIDsOfNames()为事件找到精确匹配。如果没有,请检查IDispatchEx并通过GetDispID()查找与事件匹配的expando方法。

    IDispatch Interface @ MSDN
    IDispatch::GetIDsOfNames @ MSDN
    IDispatchEx Interface @ MSDN
    IDispatchEx::GetDispID @ MSDN (查找收件人事件方法)

    最后,从一个或另一个找到处理程序后,调用关联的Invoke()方法。

    IDispatch::Invoke @ MSDN
    IDispatchEx::InvokeEx @ MSDN

    初始(处理预定义的MSHTML事件)

    大多数事件处理程序对象都是手动创建的,因为这允许它们在通过attachEvent()接收调用或分配给事件属性时通过IDispatch接受MSHTML事件。这种机制从典型的ConnectionPointContainer到COM中流行的EventSink设置都有所不同。但是,创建一个对象来处理这些事件更简单。如果要创建这样一个对象来处理事件,则应该注意一些关键的区别。

    1. 第一个约束是接收到的事件的DISPID和方法名称必须与接收到的事件的DISPID和方法匹配。关于这方面的文档有点少,但是解决正确DISPID的最佳方法是查看C++头文件。如果安装了Microsoft Platform SDK,则可以查看文件的include子目录 <mshtmdid.h> (MSHTML调度ID的缩写)。它包含所有相关MSHTML分派ID的列表。

    2. 第二个约束是IE/MSHTML不调用在基于vtable的接口中声明的方法的二进制版本,因此调用将通过IDispatch::Invoke()到达。如果所需的COM框架不负责将这两种类型的调用路由到代码中的同一个处理程序,那么这可能是一个问题。

    3. 要创建处理程序对象,需要创建支持IUnknown、IDispatch和IObjectSafety的COM对象。IUnknown对于其他接口都是隐式的,但不要忘记IObjectSafety。

    4. 不是特别要求的,但您的对象应该是单元线程对象,以避免编组问题。由于调用是通过变量包装器直接到IDispatch的,因此如果您正在执行需要多个单元的操作,或者如果您试图使用自由线程组件,则可能会遇到问题。大多数框架为该模型创建对象,或者默认情况下建议使用该类型(VB6、Delphi、MFC、ATL)。

    上面提到的C++头文件中的定义与IHTMlement上列出的项完全对应。这里有一个具体的项目让你开始。

    首先,关闭HTMLDOM元素的事件。

    onclick Property (IHTMLElement) @ MSDN

    我们注意到这个属性的名称是onclick。现在,转到头文件。

    MSHTMDID.H @ DDART.NET

    我们想要的匹配项是 DISPID\u EVMETH\u ONCLICK

    #define DISPID_EVMETH_ONCLICK                DISPID_CLICK
    

    某些定义重叠或循环使用为一般ActiveX/OLE控件使用而定义的相同DISPID。 是在OleCtl.h中定义的,所以让我们到那里去追踪最终的值。这个头文件在平台SDK中也可用,并且默认情况下也包含在VC++安装中,至少我记得最早是VC++6.0。

    OLECTL.H @ DDART.NET

    我们要的DISPID是-600。

    #define DISPID_CLICK                    (-600)
    

    现在,在组件的IDL中,您需要声明一个名为onclick()的方法,该方法具有这个DISPID值;或者,您需要在IDispatch::Invoke()的处理程序中处理此DISPID。如果您使用的是ATL,那么声明该方法并提供双布局并没有什么坏处。其他实现可能有所不同。

    开发的其余部分应该是Internet Explorer中脚本对象的典型部分。还请注意,这些dispid中的大多数都在负值范围内,以避免与用户定义的dispid发生冲突。