我正在开展一个旨在衡量 Microsoft Outlook 性能的项目。我的问题是“有没有办法检测发送/接收事件(开始和结束)?”。哪个 API 提供与此事件相关的方法。我已经在谷歌上搜索了一段时间,但我没有发现任何有趣的东西。
3 回答
使用 Namespace.SyncObjects 集合。
SyncObject.SyncStart/SyncEnd 事件可能是您想要的。
编辑:只需调用一个方法SyncStart
绝对不会做任何事情。Outlook 如何知道它需要调用您的事件处理程序?
您需要订阅 COM 事件 - ATL 和 MFC 都为 COM 事件提供包装器。在低级别上,您需要 QI 为 IConnectionPointContainer 引发事件的 COM 对象(在您的情况下为 SyncObject),调用 IConnectionPointContainer::FindConnectionPoint
传递适当的 disp 接口 GUID (SyncObjectEvents),然后调用IConnectionPoint.Advise
传递您的IDispatch
. 引发事件时,IDispatch::Invoke()
将使用与特定事件对应的适当 dispid 调用您的实现。
正如 Dimitry 所说,您需要捕获 SyncStart 和 SyncEnd 事件,在 C++ 中执行此操作的最简单方法可能是为 Outlook 创建一个插件,获取正确的接口并实现接收器对象以获取所需的通知。
http://msdn.microsoft.com/en-us/library/ee941475%28v=office.14%29.aspx
编辑
不知道你是否设法让它工作,所以这里是一个没有插件的例子......
创建一个新的控制台应用程序,添加这些包含和导入(相应地更改路径)或使用对应的 libid...
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#import "C:\\Program Files (x86)\\Common Files\\microsoft shared\\OFFICE12\\mso.dll" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search rename("DocumentProperties", "MsoDocumentProperties") rename("RGB", "MsoRGB") exclude("IAccessible")
#import "C:\\Program Files (x86)\\Microsoft Office\\Office12\\msoutl.olb" raw_interfaces_only, raw_native_types, named_guids, auto_search rename("Folder", "OlkFolder") rename("CopyFile", "OlkCopyFile") rename("GetOrganizer", "GetOrganizerAE") rename("PlaySound", "OlkPlaySound") rename_namespace("Outlook")
现在创建一个类来接收事件...您只需要从 IDispatch 派生,我为事件添加了一个 HANDLE,以便在我们完成同步时提供建议。
class COutlookEventSink : public IDispatch
{
public:
COutlookEventSink(HANDLE hEvent);
~COutlookEventSink(void);
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
// IDispatch
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo);
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo);
HRESULT STDMETHODCALLTYPE GetIDsOfNames(
__RPC__in REFIID riid,
__RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
__RPC__in_range(0,16384) UINT cNames,
LCID lcid,
__RPC__out_ecount_full(cNames) DISPID *rgDispId);
HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr);
private:
long _lRef;
HANDLE _hEvent;
};
COutlookEventSink::COutlookEventSink(HANDLE hEvent)
{
_lRef = 0;
_hEvent = hEvent;
}
COutlookEventSink::~COutlookEventSink(void)
{
}
HRESULT STDMETHODCALLTYPE COutlookEventSink::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = NULL;
if(IsEqualGUID(riid, IID_IUnknown))
*ppvObject = reinterpret_cast<void**>(this);
if(IsEqualGUID(riid, IID_IDispatch))
*ppvObject = reinterpret_cast<void**>(this);
if(*ppvObject)
{
((IUnknown*)*ppvObject)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE COutlookEventSink::AddRef()
{
return InterlockedIncrement(&_lRef);
}
ULONG STDMETHODCALLTYPE COutlookEventSink::Release()
{
if (InterlockedDecrement(&_lRef) == 0)
{
delete this;
return 0;
}
return _lRef;
}
HRESULT STDMETHODCALLTYPE COutlookEventSink::GetTypeInfoCount(__RPC__out UINT *pctinfo)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE COutlookEventSink::GetTypeInfo(UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE COutlookEventSink::GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0,16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE COutlookEventSink::Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr)
{
switch(dispIdMember)
{
case 61441: // SyncStart - Start a Timer ?
break;
case 61444: // SyncEnd
SetEvent(_hEvent); // We done, exit
break;
}
return S_OK;
}
现在在您的主要创建 Outlook 应用程序,并将接收器添加到 SyncObjects
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
CComPtr<Outlook::_Application> spApplication;
HRESULT hr = spApplication.CoCreateInstance(__uuidof(Outlook::Application), 0, CLSCTX_LOCAL_SERVER );
if(SUCCEEDED(hr) && spApplication)
{
CComPtr<Outlook::_NameSpace> spSession;
hr = spApplication->get_Session(reinterpret_cast<Outlook::_NameSpace **>(&spSession));
if (SUCCEEDED(hr) && spSession)
{
CComPtr<Outlook::SyncObjects> spSyncObjects;
hr = spSession->get_SyncObjects(reinterpret_cast<Outlook::SyncObjects **>(&spSyncObjects));
if (SUCCEEDED(hr) && spSyncObjects)
{
VARIANT index;
index.intVal = 1;
index.vt = VT_INT;
CComPtr<Outlook::_SyncObject> spSyncObject;
hr = spSyncObjects->Item(index, reinterpret_cast<Outlook::_SyncObject **>(&spSyncObject));
if (SUCCEEDED(hr) && spSyncObject)
{
CComPtr<IConnectionPointContainer> spContainer;
HRESULT hr = spSyncObject->QueryInterface(__uuidof(IConnectionPointContainer),reinterpret_cast<void **>(&spContainer));
if (SUCCEEDED(hr) && spContainer)
{
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
CComPtr<COutlookEventSink> spSink = new COutlookEventSink(hEvent);
CComPtr<IConnectionPoint> spConnectionPoint;
hr = spContainer->FindConnectionPoint(Outlook::DIID_SyncObjectEvents, &spConnectionPoint);
if (SUCCEEDED(hr) && spConnectionPoint)
{
DWORD dwCookie = 0;
CComPtr<IUnknown> spUnknown;
hr = spConnectionPoint->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&spUnknown));
if (SUCCEEDED(hr) && spUnknown)
{
hr = spConnectionPoint->Advise(spSink, &dwCookie);
if (SUCCEEDED(hr))
{
spSyncObject->Start(); // Syncronize
while(true)
{
MSG Message;
while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
DWORD dwStatus = WaitForSingleObject(hEvent, 0); // Wait for end
if(dwStatus == WAIT_OBJECT_0)
break;
}
spConnectionPoint->Unadvise(dwCookie);
}
}
}
}
}
}
}
spApplication.Release();
}
CoUninitialize();
return 0;
}
我认为您需要的是获得两个前景事件之间的时间间隔。如果你打算用C++来做这个,我觉得会有点麻烦。但是,如果您想对任何 MS Office 应用程序进行一些编程,MS 提供了一个 API 调用宏(VBA)。
基本情况:
宏是一个附加程序,您可以使用 vb 脚本编写,并且可以在任何 MS Office 应用程序中运行按钮单击或事件老虎更多详细信息。
所以你可以通过打开outlook然后按ALT+F11来打开宏编程界面。
所以可以使用这个宏做很多事情,你可以谷歌了解更多细节。
如果你需要从 C++ 应用程序中获取一些信息,你可以考虑将 API 从宏转换为 C++,可能只是编写一个测试文件。
这是一些示例,您可能会从中得到一些想法
这是一个关于宏的教程
希望这些想法可以帮助您实现目标。