1

我正在开展一个旨在衡量 Microsoft Outlook 性能的项目。我的问题是“有没有办法检测发送/接收事件(开始和结束)?”。哪个 API 提供与此事件相关的方法。我已经在谷歌上搜索了一段时间,但我没有发现任何有趣的东西。

4

3 回答 3

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 调用您的实现。

于 2013-09-03T16:15:27.720 回答
3

正如 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;
}
于 2013-09-10T14:44:44.457 回答
1

我认为您需要的是获得两个前景事件之间的时间间隔。如果你打算用C++来做这个,我觉得会有点麻烦。但是,如果您想对任何 MS Office 应用程序进行一些编程,MS 提供了一个 API 调用宏(VBA)。

基本情况:

  1. 宏是一个附加程序,您可以使用 vb 脚本编写,并且可以在任何 MS Office 应用程序中运行按钮单击或事件老虎更多详细信息

  2. 所以你可以通过打开outlook然后按ALT+F11来打开宏编程界面。

  3. 所以可以使用这个宏做很多事情,你可以谷歌了解更多细节。

  4. 如果你需要从 C++ 应用程序中获取一些信息,你可以考虑将 API 从宏转换为 C++,可能只是编写一个测试文件。

  5. 是一些示例,您可能会从中得到一些想法

  6. 是一个关于宏的教程

希望这些想法可以帮助您实现目标。

于 2013-09-09T07:40:44.123 回答