2008-09-14 5 views
8

Giả sử tôi có một đối tượng COM mà người dùng có thể truy cập thông qua một cuộc gọi như:Expose một event handler cho người dùng VBScript của đối tượng COM của tôi

Set s = CreateObject("Server") 

Những gì tôi muốn để có thể làm là cho phép sử dụng để xác định một event handler cho các đối tượng, như vậy:

Function ServerEvent 

    MsgBox "Event handled" 

End Function 

s.OnDoSomething = ServerEvent 

đây có phải là tốt, và nếu như vậy, làm thế nào để vạch trần này trong thư viện kiểu của tôi trong C++ (đặc biệt là BCB 2007)?

Trả lời

5

Đây là cách tôi đã làm nó gần đây. Thêm một giao diện mà thực hiện IDispatch và coclass cho giao diện đó để IDL của bạn:

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

Đây là tuyên bố của lớp 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;   
}; 

Mấu chốt ở đây là việc thực hiện IConnectionPointImpl và IConnectionPointContainerImpl giao diện và bản đồ điểm kết nối. Định nghĩa của phương pháp OnServerEvent trông giống như sau:

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

Bạn cần cung cấp cách để khách hàng chỉ định trình xử lý cho các sự kiện của bạn. Bạn có thể làm điều này với một phương thức chuyên dụng như "SetHandler" hoặc một cái gì đó, nhưng tôi thích làm cho trình xử lý một đối số cho phương thức được gọi là không đồng bộ. Bằng cách này, người dùng chỉ phải gọi một phương pháp:

STDMETHOD(DoSomethingAsynchronous)(IServerEvents *pCallback); 

Store trỏ đến IServerEvents, và sau đó khi bạn muốn kích hoạt sự kiện của bạn, chỉ cần gọi phương thức:

m_pCallback->OnServerEvent(); 

Đối với mã VB, cú pháp để xử lý sự kiện hơi khác so với những gì bạn đề xuất:

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 

Tôi hy vọng điều này sẽ hữu ích.

+1

Mã bạn cung cấp là cú pháp VB, không phải VBScript. Từ khóa "As" và "WithEvents" không có sẵn trong VBScript. –

+0

@ 1800 THÔNG TIN, Đúng vậy. Tôi đã sử dụng cả VB và VBScript, nhưng nó đã được một thời gian dài kể từ khi tôi đã làm bất cứ điều gì với VBScript. Tôi đã quên hoặc không biết sự khác biệt đó. –

+0

@ JeffHillman, giải pháp được cung cấp là dành cho C++. Bây giờ tôi có một yêu cầu tương tự, nhưng đối với ActiveX COM phát triển thông qua C# (chúng tôi có mã nguồn cho điều đó). Bạn có biết có cách tiếp cận tương tự cho C# /. Net thế giới? – user908645

2

Tôi đã kết thúc theo kỹ thuật được mô tả here.

+0

Đây có lẽ là câu trả lời hay nhất của lô –