ATL COM事件的javascript [英] ATL COM events for javascript

查看:171
本文介绍了ATL COM事件的javascript的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前创建了一个ATL COM服务器组件(exe)。它暴露了一些正常的COM API(从IDispatch派生),并且还触发了一些COM事件。事件机制是使用ATL IConnectionPointContainer实现的。这个COM服务器最初由一个简单的C#应用​​程序使用,它直接添加了对COM服务器的引用。一切,API和事件,在C#应用程序中正常工作。

I created an ATL COM server component (exe) some time ago. It exposed a few normal COM APIs (derived from IDispatch) and also fired a few COM events. The event mechanism was implemented using ATL IConnectionPointContainer. This COM server was initially used by a simple C# application, which directly added a reference to the COM server. Everything, the APIs and events, works fine in C# app.

然后出现了COM服务器能够在一个网页(IE)中使用javascript的要求。因此我添加了IProvideClassInfo2,IObjectSafety实现到原来的COM类。然而,COM事件从来没有工作。请参阅下面的IDL,COM类头文件和事件触发代码。

Then came the requirement for the COM server to able to used with javascript in a webpage (IE). I therefore added IProvideClassInfo2, IObjectSafety implementation to the original COM class. However, the COM event never worked. Please refer to the IDL, COM class header file and event firing code below.

IDL:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    // uuid replaced with dummy
    uuid(00000000-0000-0000-0000-000000000000), 
    dual,
    nonextensible,
    helpstring("ICtrl Interface"),
    pointer_default(unique)
]
interface ICtrl : IDispatch{
    [id(1), helpstring("method CtrlMethod1")] 
    HRESULT CtrlMethod1(void);
    [id(2), helpstring("method CtrlMethod2")] 
    HRESULT CtrlMethod2([in] ULONG Reason);
};


[
    // uuid replaced with dummy
    uuid(00000000-0000-0000-0000-000000000001), 
    version(1.0),
]
library MyControlLib
{
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    [
        // uuid replaced with dummy 
        uuid(00000000-0000-0000-0000-000000000002)   
    ]
    dispinterface _ICtrlEvents
    {
        properties:
        methods:
            [id(1), helpstring("method OnCtrlEvent1")] 
            HRESULT OnCtrlEvent1([in] LONG ErrorCode);
            [id(2), helpstring("method OnCtrlEvent2")] 
            HRESULT OnCtrlEvent2([in] LONG ErrorCode);
    };


    [
        // uuid replaced with dummy
        uuid(00000000-0000-0000-0000-000000000003)       
    ]
    coclass Ctrl
    {
        [default] interface ICtrl;
        [default, source] dispinterface _ICtrlEvents;
    };
};

COM类标题:

// CCtrl

class ATL_NO_VTABLE CCtrl :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CCtrl, &CLSID_Ctrl>,
    public IConnectionPointContainerImpl<CCtrl>,
    public CProxy_ICtrlEvents<CCtrl>,
    public IDispatchImpl<ICtrl, &IID_ICtrl, &LIBID_MyControlLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDispatchImpl<_ICtrlEvents, &__uuidof(_ICtrlEvents), &LIBID_MyControlLib, /* wMajor = */ 1, /* wMinor = */ 0>,
    public IObjectSafetyImpl<CCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
    public IProvideClassInfo2Impl<&CLSID_Ctrl, NULL, &LIBID_MyControlLib>
{
public:
    DECLARE_CLASSFACTORY_SINGLETON(CCtrl)
    CCtrl();


    DECLARE_REGISTRY_RESOURCEID(IDR_CTRL)


    BEGIN_COM_MAP(CCtrl)
        COM_INTERFACE_ENTRY(ICtrl)
        COM_INTERFACE_ENTRY2(IDispatch, ICtrl)
        COM_INTERFACE_ENTRY2(IDispatch, _ICtrlEvents)
        COM_INTERFACE_ENTRY(IConnectionPointContainer)
        COM_INTERFACE_ENTRY(_ICtrlEvents)
        COM_INTERFACE_ENTRY(IObjectSafety)
        COM_INTERFACE_ENTRY(IProvideClassInfo)
        COM_INTERFACE_ENTRY(IProvideClassInfo2)
    END_COM_MAP()

    BEGIN_CONNECTION_POINT_MAP(CCtrl)
        CONNECTION_POINT_ENTRY(__uuidof(_ICtrlEvents))
    END_CONNECTION_POINT_MAP()


    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct();
    void FinalRelease();

public:

    STDMETHOD(CtrlMethod1)(void);
    STDMETHOD(CtrlMethod2)(ULONG Reason);

};

OBJECT_ENTRY_AUTO(__uuidof(Ctrl), CCtrl)

烧写代码:

#pragma once

template<class T>
class CProxy_ICtrlEvents :
    public ATL::IConnectionPointImpl<T, &__uuidof(_ICtrlEvents)>
{
public:

    HRESULT OnCtrlEvent1(LONG ErrorCode)
    {
        HRESULT hr = S_OK;
        T * pThis = static_cast<T *>(this);
        int cConnections = m_vec.GetSize();

        for (int iConnection = 0; iConnection < cConnections; iConnection++)
        {
            pThis->Lock();
            CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
            pThis->Unlock();

            IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

            if (pConnection)
            {
                CComVariant avarParams[1];
                avarParams[0] = ErrorCode;
                avarParams[0].vt = VT_I4;
                CComVariant varResult;

                DISPPARAMS params = { avarParams, NULL, 1, 0 };
                hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);
            }
        }
        return hr;
    }
    HRESULT Fire_OnCtrlEvent2(LONG ErrorCode)
    {
        HRESULT hr = S_OK;
        T * pThis = static_cast<T *>(this);
        int cConnections = m_vec.GetSize();

        for (int iConnection = 0; iConnection < cConnections; iConnection++)
        {
            pThis->Lock();
            CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
            pThis->Unlock();

            IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

            if (pConnection)
            {
                CComVariant avarParams[1];
                avarParams[0] = ErrorCode;
                avarParams[0].vt = VT_I4;
                CComVariant varResult;

                DISPPARAMS params = { avarParams, NULL, 1, 0 };
                hr = pConnection->Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);
            }
        }
        return hr;
    }
};

在JavaScript代码中,使用

In the javascript code, the COM object is created using

var CtrlObj = new ActiveXObject('ProgID_of_Ctrl')

'ProgID_of_Ctrl'映射到__uuidof(Ctrl)。在IE调试器中,创建的对象的类型为ICtrl。 COM API是可见的,但COM事件不可见。任何尝试使用CtrlObj.attachEvent()将导致javascript错误。我希望CtrlObj应该是coclass(Ctrl)类型,在C#应用程序的情况下。 COM_MAP节中是否有错误?

'ProgID_of_Ctrl' is mapped to __uuidof(Ctrl). In the IE debugger, the object created is of the type ICtrl. The COM APIs are visible, but the COM events are not. Any attempt to use CtrlObj.attachEvent() will result in javascript error. I'd expect CtrlObj should be of coclass (Ctrl) type, as was in the case of C# app. Whether there are any errors in COM_MAP section? Any comments and help are appreciated.

-CodeFarmer

-CodeFarmer

推荐答案

我应该使用 OBJECT 标签和 SCRIPT 标签来挂接ATL / COM HTML中的事件。像这样:

From what I've read, you should be using the OBJECT tag and the SCRIPT for tag to hook up ATL/COM events in HTML. Something like this:

<object
  id="myCtrlObj"
  classid="CLSID:00000000-0000-0000-0000-000000000003"
  height="32"
  width="32"/>

<script language="javascript"
   id="myCtrlHandler1"
   event="OnCtrlEvent1()"
   for="myCtrlObj">
   alert("OnCtrlEvent1 fired");
</script>

<script language="javascript"
   id="myCtrlHandler2"
   event="OnCtrlEvent2(reason)"
   for="myCtrlObj">
    alert("OnCtrlEvent2 fired with parameter: " + reason.toString());
</script>

因为你使用JScript,我有时喜欢欺骗和使一个IDispatch VARIANT属性模拟行为的事件。在下面的JScript代码片段中,注意如何将OnCtrlEvent1和OnCtrlEvent2分配给函数:

Because you're using JScript, I sometimes like to cheat and make an IDispatch VARIANT property simulate the behavior of an event. In the following JScript code snippet note how OnCtrlEvent1 and OnCtrlEvent2 are being assigned to functions:

function tst()
{
  var ctrl = new ActiveXObject("MyControl.Ctrl");
  ctrl.OnCtrlEvent1 = myevent1;
  ctrl.OnCtrlEvent2 = myevent2;
  ctrl.CtrlMethod1();
  ctrl.CtrlMethod2();
}

function myevent1()
{
  alert("Event1");
}

function myevent2(reason)
{
  alert("Event2 " + reason.toString());
}

通过将其作为IDL中的属性进行处理,这些JScript函数作为包含可调用IDispatch接口的VARIANTs传递给我们。这是我的MyControl.idl:

The trickery is done by handling it as a property in the IDL. Where those JScript functions are being passed to us as VARIANTs containing invokable IDispatch interfaces. Here's my MyControl.idl:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    // uuid replaced with dummy 
    uuid(00000000-0000-0000-0000-000000000000)  
    dual,
    nonextensible,
    helpstring("ICtrl Interface"),
    pointer_default(unique)
]
interface ICtrl : IDispatch{
    [id(1), helpstring("method CtrlMethod1")] HRESULT CtrlMethod1(void);
    [id(2), helpstring("method CtrlMethod2")] HRESULT CtrlMethod2(void);
    [propget, id(3), helpstring("property OnCtrlEvent1")] HRESULT OnCtrlEvent1([out, retval] VARIANT* pVal);
    [propput, id(3), helpstring("property OnCtrlEvent1")] HRESULT OnCtrlEvent1([in] VARIANT newVal);
    [propget, id(4), helpstring("property OnCtrlEvent2")] HRESULT OnCtrlEvent2([out, retval] VARIANT* pVal);
    [propput, id(4), helpstring("property OnCtrlEvent2")] HRESULT OnCtrlEvent2([in] VARIANT newVal);
};
[
    // uuid replaced with dummy 
    uuid(00000000-0000-0000-0000-000000000001),
    version(1.0),
    helpstring("MyControl 1.0 Type Library")
]
library MyControlLib
{
    importlib("stdole2.tlb");
    [
        // uuid replaced with dummy 
        uuid(00000000-0000-0000-0000-000000000003)
        helpstring("Ctrl Class")
    ]
    coclass Ctrl
    {
        [default] interface ICtrl;
    };
};

这是我的Ctrl.h,你看到JScript函数将保存在VARIANT成员中:

Here's my Ctrl.h where you see the JScript functions will be saved in VARIANT members:

class ATL_NO_VTABLE CCtrl :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CCtrl, &CLSID_Ctrl>,
    public IDispatchImpl<ICtrl, &IID_ICtrl, &LIBID_MyControlLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_CTRL)

BEGIN_COM_MAP(CCtrl)
    COM_INTERFACE_ENTRY(ICtrl)
    COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:
    STDMETHOD(CtrlMethod1)(void);
    STDMETHOD(CtrlMethod2)(void);
    STDMETHOD(get_OnCtrlEvent1)(VARIANT* pVal);
    STDMETHOD(put_OnCtrlEvent1)(VARIANT newVal);
    STDMETHOD(get_OnCtrlEvent2)(VARIANT* pVal);
    STDMETHOD(put_OnCtrlEvent2)(VARIANT newVal);

private:
    CComVariant m_ctrlEvent1;
    CComVariant m_ctrlEvent2;

    STDMETHOD(Invoke_CtrlEvent1)();
    STDMETHOD(Invoke_CtrlEvent2)(LONG nReason);
};

OBJECT_ENTRY_AUTO(__uuidof(Ctrl), CCtrl)

诀窍是我们在这些VARIANT中寻找JScript函数的IDispatch接口,并使用我们对参数的知识,我们使用正确的参数调用每个事件:

In Ctrl.cpp the trickery is we look for the JScript function's IDispatch interfaces in those VARIANTs and with our 'knowledge' of the parameters, we invoke each event with the right parameters:

#include "stdafx.h"
#include "Ctrl.h"

STDMETHODIMP CCtrl::CtrlMethod1(void)
{
    Invoke_CtrlEvent1();
    return S_OK;
}

STDMETHODIMP CCtrl::CtrlMethod2(void)
{
    Invoke_CtrlEvent2(12345);
    return S_OK;
}

STDMETHODIMP CCtrl::get_OnCtrlEvent1(VARIANT* pVal)
{
    VariantInit(pVal);
    return VariantCopy(pVal, &m_ctrlEvent1);
    return S_OK;
}

STDMETHODIMP CCtrl::put_OnCtrlEvent1(VARIANT newVal)
{
    m_ctrlEvent1 = newVal;
    return S_OK;
}

STDMETHODIMP CCtrl::get_OnCtrlEvent2(VARIANT* pVal)
{
    VariantInit(pVal);
    return VariantCopy(pVal, &m_ctrlEvent2);
}

STDMETHODIMP CCtrl::put_OnCtrlEvent2(VARIANT newVal)
{
    m_ctrlEvent2 = newVal;
    return S_OK;
}

STDMETHODIMP CCtrl::Invoke_CtrlEvent1()
{
    if (m_ctrlEvent1.vt != VT_DISPATCH)
    {
        return S_OK;
    }
    DISPPARAMS DispParams = { 0, 0, 0, 0 };
    VARIANT Var = { 0 };
    return V_DISPATCH(&m_ctrlEvent1)->Invoke((DISPID) 0, IID_NULL, 0, DISPATCH_METHOD, &DispParams, &Var, NULL, NULL);
}

STDMETHODIMP CCtrl::Invoke_CtrlEvent2(LONG nReason)
{
    if (m_ctrlEvent1.vt != VT_DISPATCH)
    {
        return S_OK;
    }
    VARIANTARG    Arg = {0};
    Arg.vt = VT_I4;
    Arg.lVal = nReason;
    DISPPARAMS DispParams = { &Arg, 0, 1, 0 };
    VARIANT Var = { 0 };
    return V_DISPATCH(&m_ctrlEvent2)->Invoke((DISPID) 0, IID_NULL, 0, DISPATCH_METHOD, &DispParams, &Var, NULL, NULL);
}

这篇关于ATL COM事件的javascript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆