代码之家  ›  专栏  ›  技术社区  ›  Carl

向COM对象的VBScript用户公开事件处理程序

  •  8
  • Carl  · 技术社区  · 16 年前

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

    Set s = CreateObject("Server")
    

    Function ServerEvent
    
       MsgBox "Event handled"
    
    End Function
    
    s.OnDoSomething = ServerEvent
    

    这是可能的吗?如果是,我如何在C++中的我的类型库中公开这个(具体地说是BCB 2007)?

    3 回复  |  直到 15 年前
        1
  •  5
  •   Jeff Hillman    16 年前

    [
        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;
    }
    

    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
    

    希望这有帮助。

        2
  •  2
  •   1800 INFORMATION    16 年前

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

    看起来您的服务器对象需要实现 IProvideClassInfo 然后你打电话来 ConnectObject

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

        3
  •  1
  •   Brian Webster Jason    13 年前

    我最终还是采用了描述的技术 here .