Note that there are some explanatory texts on larger screens.

plurals
  1. POATL COM events for javascript
    text
    copied!<p>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.</p> <p>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.</p> <p>IDL:</p> <pre><code>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; }; }; </code></pre> <p>COM class header:</p> <pre><code>// CCtrl class ATL_NO_VTABLE CCtrl : public CComObjectRootEx&lt;CComSingleThreadModel&gt;, public CComCoClass&lt;CCtrl, &amp;CLSID_Ctrl&gt;, public IConnectionPointContainerImpl&lt;CCtrl&gt;, public CProxy_ICtrlEvents&lt;CCtrl&gt;, public IDispatchImpl&lt;ICtrl, &amp;IID_ICtrl, &amp;LIBID_MyControlLib, /*wMajor =*/ 1, /*wMinor =*/ 0&gt;, public IDispatchImpl&lt;_ICtrlEvents, &amp;__uuidof(_ICtrlEvents), &amp;LIBID_MyControlLib, /* wMajor = */ 1, /* wMinor = */ 0&gt;, public IObjectSafetyImpl&lt;CCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER&gt;, public IProvideClassInfo2Impl&lt;&amp;CLSID_Ctrl, NULL, &amp;LIBID_MyControlLib&gt; { 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) </code></pre> <p>ATL-generated event firing code:</p> <pre><code>#pragma once template&lt;class T&gt; class CProxy_ICtrlEvents : public ATL::IConnectionPointImpl&lt;T, &amp;__uuidof(_ICtrlEvents)&gt; { public: HRESULT OnCtrlEvent1(LONG ErrorCode) { HRESULT hr = S_OK; T * pThis = static_cast&lt;T *&gt;(this); int cConnections = m_vec.GetSize(); for (int iConnection = 0; iConnection &lt; cConnections; iConnection++) { pThis-&gt;Lock(); CComPtr&lt;IUnknown&gt; punkConnection = m_vec.GetAt(iConnection); pThis-&gt;Unlock(); IDispatch * pConnection = static_cast&lt;IDispatch *&gt;(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-&gt;Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &amp;params, &amp;varResult, NULL, NULL); } } return hr; } HRESULT Fire_OnCtrlEvent2(LONG ErrorCode) { HRESULT hr = S_OK; T * pThis = static_cast&lt;T *&gt;(this); int cConnections = m_vec.GetSize(); for (int iConnection = 0; iConnection &lt; cConnections; iConnection++) { pThis-&gt;Lock(); CComPtr&lt;IUnknown&gt; punkConnection = m_vec.GetAt(iConnection); pThis-&gt;Unlock(); IDispatch * pConnection = static_cast&lt;IDispatch *&gt;(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-&gt;Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &amp;params, &amp;varResult, NULL, NULL); } } return hr; } }; </code></pre> <p>In the javascript code, the COM object is created using </p> <pre><code>var CtrlObj = new ActiveXObject('ProgID_of_Ctrl') </code></pre> <p>'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.</p> <p>-CodeFarmer</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload