向我的COM对象的VBScript用户公开事件处理程序
时间:2020-03-05 18:53:05 来源:igfitidea点击:
假设我有一个COM对象,用户可以通过调用来访问它,例如:
Set s = CreateObject("Server")
我想做的是允许用户为对象指定事件处理程序,如下所示:
Function ServerEvent MsgBox "Event handled" End Function s.OnDoSomething = ServerEvent
这可能吗?如果可以,如何在C ++(特别是BCB 2007)的类型库中公开呢?
解决方案
回答
我对细节不太了解,但也许下面的链接可能会有所帮助:
http://msdn.microsoft.com/en-us/library/ms974564.aspx
看来服务器对象需要实现IProvideClassInfo,然后在VBScript代码中调用ConnectObject。也可以看看:
http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx
回答
这就是我最近所做的。向IDL添加一个实现IDispatch的接口和该接口的协类:
[ object, uuid(6EDA5438-0915-4183-841D-D3F0AEDFA466), nonextensible, oleautomation, pointer_default(unique) ] interface IServerEvents : IDispatch { [id(1)] HRESULT OnServerEvent(); } //... [ uuid(FA8F24B3-1751-4D44-8258-D649B6529494), ] coclass ServerEvents { [default] interface IServerEvents; [default, source] dispinterface IServerEvents; };
这是CServerEvents类的声明:
class ATL_NO_VTABLE CServerEvents : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CServerEvents, &CLSID_ServerEvents>, public IDispatchImpl<IServerEvents, &IID_IServerEvents , &LIBID_YourLibrary, -1, -1>, public IConnectionPointContainerImpl<CServerEvents>, public IConnectionPointImpl<CServerEvents,&__uuidof(IServerEvents)> { public: CServerEvents() { } // ... BEGIN_COM_MAP(CServerEvents) COM_INTERFACE_ENTRY(IServerEvents) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IConnectionPointContainer) END_COM_MAP() BEGIN_CONNECTION_POINT_MAP(CServerEvents) CONNECTION_POINT_ENTRY(__uuidof(IServerEvents)) END_CONNECTION_POINT_MAP() // .. // IServerEvents STDMETHOD(OnServerEvent)(); private: CRITICAL_SECTION m_csLock; };
此处的关键是IConnectionPointImpl和IConnectionPointContainerImpl接口以及连接点映射的实现。 OnServerEvent方法的定义如下所示:
STDMETHODIMP CServerEvents::OnServerEvent() { ::EnterCriticalSection( &m_csLock ); IUnknown* pUnknown; for ( unsigned i = 0; ( pUnknown = m_vec.GetAt( i ) ) != NULL; ++i ) { CComPtr<IDispatch> spDisp; pUnknown->QueryInterface( &spDisp ); if ( spDisp ) { spDisp.Invoke0( CComBSTR( L"OnServerEvent" ) ); } } ::LeaveCriticalSection( &m_csLock ); return S_OK; }
我们需要为客户提供一种为事件指定其处理程序的方法。我们可以使用诸如" SetHandler"之类的专用方法来执行此操作,但是我更喜欢将处理程序作为异步调用的方法的参数。这样,用户只需调用一种方法:
STDMETHOD(DoSomethingAsynchronous)( IServerEvents *pCallback );
存储指向IServerEvents的指针,然后在要触发事件时,只需调用该方法:
m_pCallback->OnServerEvent();
对于VB代码,处理事件的语法与我们建议的稍有不同:
Private m_server As Server Private WithEvents m_serverEvents As ServerEvents Private Sub MainMethod() Set s = CreateObject("Server") Set m_serverEvents = New ServerEvents Call m_searchService.DoSomethingAsynchronous(m_serverEvents) End Sub Private Sub m_serverEvents_OnServerEvent() MsgBox "Event handled" End Sub
我希望这有帮助。
回答
我最终遵循了这里描述的技术。