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