Microsoft Outlook のパフォーマンスを測定することを目的としたプロジェクトに取り組んでいます。私の質問は、「送受信イベント (開始と終了) を検出する方法はありますか?」です。このイベントに関連するメソッドを提供する API はどれですか。しばらくグーグルで検索しましたが、興味深いものは見つかりませんでした。
3 に答える
Namespace.SyncObjects コレクションを使用します。
SyncObject.SyncStart/SyncEnd イベントは、おそらく必要なものです。
編集:メソッドを呼び出すだけでは、SyncStart
まったく何もしません。Outlook は、イベント ハンドラーを呼び出す必要があることをどのように認識しますか?
COM イベントをサブスクライブする必要があります。ATL と MFC の両方が COM イベントのラッパーを提供します。低レベルでは、IConnectionPointContainer のイベントを発生させる COM オブジェクト (この場合は SyncObject) を QI し 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;
}
必要なのは、見通しの2つのイベント間の時間間隔を取得することだと思います。これをC++でやろうとすると、ちょっと面倒だと思います。しかし、MS オフィス アプリケーションのいずれかでプログラミングを行いたい場合、MS は API 呼び出しマクロ (VBA) を提供しています。
基本的に:
マクロは、vb スクリプトを使用して記述できるアドオン プログラムであり、ボタンのクリックまたはイベント タイガーの詳細については、任意の MS オフィス アプリケーションで実行できます。
したがって、Outlook を開いて ALT+F11 を押すと、マクロ プログラミング インターフェイスを開くことができます。
このマクロを使用して多くのことを行うことができ、詳細についてはグーグルで検索できます。
C++ アプリケーションに何らかの情報を取得する必要がある場合は、マクロから C++ への API を作成することを検討できます。テスト ファイルを作成するだけかもしれません。
ここにいくつかの例があり、これからいくつかのアイデアを得ることができます
マクロのチュートリアルはこちら
これらのアイデアがあなたの目標を達成するのに役立つことを願っています。