【问题标题】:Expose an event handler to VBScript users of my COM object向我的 COM 对象的 VBScript 用户公开事件处理程序
【发布时间】:2010-09-08 20:49:21
【问题描述】:

假设我有一个 COM 对象,用户可以通过如下调用访问它:

Set s = CreateObject("Server")

我想做的是允许用户为对象指定一个事件处理程序,如下所示:

Function ServerEvent

   MsgBox "Event handled"

End Function

s.OnDoSomething = ServerEvent

这可能吗?如果可以,我如何在我的 C++ 类型库(特别是 BCB 2007)中公开它?

【问题讨论】:

    标签: events com vbscript c++builder


    【解决方案1】:

    这就是我最近的做法。将实现 IDispatch 的接口和该接口的 coclass 添加到 IDL:

    [
        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
    

    我希望这会有所帮助。

    【讨论】:

    • 您提供的代码是 VB 语法,而不是 VBScript。 “As”关键字和“WithEvents”在 VBScript 中不可用。
    • @1800 信息,没错。我用过 VB 和 VBScript,但是我已经很久没有用 VBScript 做过任何事情了。我已经忘记或不知道那个特别的区别。
    • @JeffHillman,提供的解决方案适用于 C++。现在我有类似的要求,但对于通过 C# 开发的 ActiveX COM(我们有源代码)。你知道 C#/.Net 世界有类似的方法吗?
    【解决方案2】:

    我对细节有点模糊,但也许下面的链接可能会有所帮助:

    http://msdn.microsoft.com/en-us/library/ms974564.aspx

    看起来您的服务器对象需要实现IProvideClassInfo,然后您在VBScript 代码中调用ConnectObject。另见:

    http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx

    【讨论】:

      【解决方案3】:

      我最终采用了here 描述的技术。

      【讨论】:

      • 这可能是最好的答案
      • 那个链接现在好像失效了。
      猜你喜欢
      • 2012-07-27
      • 2011-08-14
      • 2017-01-23
      • 1970-01-01
      • 2017-08-24
      • 2011-08-13
      • 2012-09-20
      • 2019-12-14
      相关资源
      最近更新 更多