2008-09-14 3 views
8

Предположим, у меня есть COM-объект, который пользователи могут получить доступ через вызов таких как:Expose обработчик событий для пользователей VBScript моего COM объекта

Set s = CreateObject("Server") 

То, что я хотел бы быть в состоянии сделать это позволить пользователю задать обработчик события для объекта, например, так:

Function ServerEvent 

    MsgBox "Event handled" 

End Function 

s.OnDoSomething = ServerEvent 

возможно ли это, и если да, то как я могу выставить это в моей библиотеке типов в C++ (в частности, BCB 2007)?

ответ

5

Это, как я сделал это совсем недавно. Добавить интерфейс, который реализует IDispatch и компонентный класс для этого интерфейса в вашем 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 

Я надеюсь, что это помогает.

+1

Код, который вы указали, является синтаксисом VB, а не VBScript. Ключевое слово «As» и «WithEvents» недоступны в VBScript. – 2008-09-15 00:53:16

+0

@ 1800 ИНФОРМАЦИЯ, Вы правы. Я использовал и VB, и VBScript, но с тех пор, как я сделал что-то с VBScript, прошло много времени. Я забыл или не знал об этой конкретной разнице. – 2008-09-15 10:32:30

2

Я закончил работу по описанной методике here.

Смежные вопросы