Zdeslav Vojkovic 提出的解决方案对我来说几乎是完整的答案,但是在 Outlook 加载项中实施接收器时遇到了稳定性问题。在第一次不建议之后,系统变得不稳定,并且可能在下一次建议时崩溃。我的解决方案是将接收器作为 COM 对象。
为简洁起见,我只添加了解决方案的 ATL 方面,因为托管代码可以完全按照 Zdeslav Vojkovic 的建议保留。
我在 Visual Studio 2017 中按照以下步骤操作:
创建 ATL 简单对象
- 右键单击 Project 并选择 Add > New Item...
- 选择 ATL 简单对象并单击添加按钮
- 在“其他”选项卡中,为线程模型选择“单一”
- 点击完成
填写sink接口详情
在生成的 idl 中添加用于初始化和关闭的处理程序:
[
object,
uuid(a5211fba-...),
dual,
nonextensible,
pointer_default(unique)
]
interface IMyClient : IDispatch
{
[id(1), helpstring("method InitHandler"), local] HRESULT InitHandler(IUnknown* myserver);
[id(2), helpstring("method ShutdownHandler"), local] HRESULT ShutdownHandler(void);
};
填写头文件(MyClient.h)
const UINT SINK_ID = 234231341;
extern _ATL_FUNC_INFO SomethingHappenedInfo;
// LIBID_MyATLComLib should point to the LIBID of the type library
class ATL_NO_VTABLE CMyClient :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyClient, &CLSID_MyClient>,
public IDispatchImpl<IMyClient, &IID_IMyClient, &LIBID_MyATLComLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispEventSimpleImpl<SINK_ID, CMyClient, &MyServer::DIID_IMyEvents>
{
public:
typedef IDispEventSimpleImpl</*nID =*/ SINK_ID, CMyClient, &MyServer::DIID_IMyEvents> SomethingHappenedEvent;
...
BEGIN_SINK_MAP(CMyClient)
SINK_ENTRY_INFO(SINK_ID, MyServer::DIID_IMyEvents, 0x1, OnSomethingHappened, &SomethingHappenedInfo)
END_SINK_MAP()
...
private:
CComQIPtr<MyServer::IMyComServer> mMyComServer;
public:
STDMETHOD(InitHandler)(IUnknown* myserver);
STDMETHOD(ShutdownHandler)(void);
void __stdcall OnSomethingHappened(DateTime timestamp, string message);
};
一些生成的代码被保留为“...”
填写C++代码(MyClient.cpp)
_ATL_FUNC_INFO SomethingHappenedInfo = { CC_STDCALL, VT_EMPTY, 2 , {VT_DECIMAL, VT_BSTR} };
STDMETHODIMP CMyClient::InitHandler(IUnknown* myserver)
{
this->mMyComServer = myserver;
SomethingHappenedEvent::DispEventAdvise((IDispatch*)this->mMyComServer);
return S_OK;
}
STDMETHODIMP CMyClient::ShutdownHandler(void)
{
SomethingHappenedEvent::DispEventUnadvise(this->mMyComServer);
return S_OK;
}
void __stdcall CMyClient::OnSomethingHappened(DateTime timestamp, string message)
{
...
}
请注意这里的 Advise/Unadvise 调用是不同的。