2012-02-07 9 views
0

私はATL COMサーバーコンポーネント(exe)を作成しました。それは(IDispatchから派生した)いくつかの通常のCOM APIを公開し、またいくつかのCOMイベントを発生させました。イベントメカニズムは、ATL IConnectionPointContainerを使用して実装されました。このCOMサーバーは、最初はCOMサーバーへの参照を直接追加した単純なC#アプリケーションで使用されていました。すべてのAPIとイベントは、C#アプリでうまく動作します。JavaScriptのATL COMイベント

次に、Webサーバー(IE)でjavascriptでCOMサーバーを使用できるようにする必要がありました。したがって、元のCOMクラスにIProvideClassInfo2、IObjectSafety実装を追加しました。しかし、COMイベントは決して働きませんでした。以下のIDL、COMクラスヘッダファイル、イベント発射コードを参照してください。

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) 

ATL-生成されたイベント焼成コード:

#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コードでは、COMオブジェクトが

を使用して作成され
var CtrlObj = new ActiveXObject('ProgID_of_Ctrl') 

'ProgID_of_Ctrl'は__uuidof(Ctrl)にマッピングされています。 IEデバッガでは、作成されるオブジェクトはICtrl型です。 COM APIは表示されますが、COMイベントは表示されません。 CtrlObj.attachEvent()を使用しようとすると、javascriptエラーが発生します。私はCtrlObjがC#アプリケーションの場合と同様にコクラス(Ctrl)タイプでなければならないと思います。 COM_MAPセクションにエラーがあるかどうかご意見やご協力をいただければ幸いです。 -CodeFarmer

答えて

1

私が読んだ、あなたはHTMLでのATL/COMのイベントをフックするOBJECTタグとSCRIPT forタグを使用する必要がありますから。このような何か:

<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プロパティをカンニングして作るのが好きではイベントの動作をシミュレート。 OnCtrlEvent1とOnCtrlEvent2が機能に割り当てられている方法を次のJScriptコードスニペットノートで:

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インターフェイスを含むVARIANTとして渡されます。ここに私の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; 
    }; 
}; 

ここでは、JScriptの関数はVARIANTメンバーに保存されます参照して私のCtrl.hです:Ctrl.cppで

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) 

策略は我々がのJScriptを探していますこれらのVARIANTのIDispatchインターフェイスとパラメータの知識を使用して、適切なパラメータで各イベントを呼び出します。

#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); 
} 
+0

ありがとう。あなたのソリューションは機能します。私は実際にそれをチートとして見ません。別のイベントインターフェイスを持つ代わりに、メインインターフェイスはJavaScriptがコールバックを登録する方法を提供します。 – CodeFarmer

関連する問題