Đâ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.
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. –
@ 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 đó. –
@ 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