How to listen for COM events from Office applications that run independently?

What I want to do:

Write an application that listens for Office events. I want to listen to events from any instance open on the machine. For instance. if I listen to BeforeDocumentSave in Word, then I want my receiver for this method to be activated whenever any instance of Word on the host saves the document.

Another requirement is that I write in C ++ without MFC or ATL.

What I've done:

I wrote a program that should listen for Word events. See code below.

Problem:

This does not work - event handlers are never entered, although I open a text application and perform actions that should trigger events.

I have some specific questions, and of course, any other input would be very welcome!

Questions:

  • Can I listen to events from an application that was not launched by me? In all the examples I found, the listening application launches the office application that it wants to listen to.

  • In the Microsoft manual (http://support.microsoft.com/kb/183599/EN-US/) I found the following comment:

However, most events, such as Microsoft Excel Workbook Events, do not start with DISPID 1. In such cases, you must explicitly change the map to MyEventSink.cpp to map DISPIDs to the correct Methods.

How to change the sending card?

  • Startup, Quit DocumentChange, . , , , , Document. , MFC?

:

, C:

#ifndef _OFFICEEVENTHANDLER_H_
#define _OFFICEEVENTHANDLER_H_

// 000209FE-0000-0000-C000-000000000046
static const GUID IID_IApplicationEvents2 =  
{0x000209FE,0x0000,0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};

struct IApplicationEvents2 : public IDispatch // Pretty much copied from typelib
{
/*
 * IDispatch methods
 */
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj) = 0; 
STDMETHODIMP_(ULONG) AddRef()  = 0;  
STDMETHODIMP_(ULONG) Release() = 0;

STDMETHODIMP GetTypeInfoCount(UINT *iTInfo) = 0;
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) = 0;
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, 
                              UINT cNames,  LCID lcid, DISPID *rgDispId) = 0;
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
                              WORD wFlags, DISPPARAMS* pDispParams,
                              VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
                              UINT* puArgErr) = 0;

/*
 * IApplicationEvents2 methods
 */
STDMETHODIMP Startup();
STDMETHODIMP Quit();
STDMETHODIMP DocumentChange();
};


class COfficeEventHandler : IApplicationEvents2
{

public:
DWORD                        m_dwEventCookie;

COfficeEventHandler
(
) :
m_cRef(1),
m_dwEventCookie(0)
{
}

STDMETHOD_(ULONG, AddRef)()
{
InterlockedIncrement(&m_cRef);

return m_cRef;  
}

STDMETHOD_(ULONG, Release)()
{
InterlockedDecrement(&m_cRef);

if (m_cRef == 0)
{
    delete this;
    return 0;
}

return m_cRef;
}

STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj)
{
 if (riid == IID_IUnknown){
    *ppvObj = static_cast<IApplicationEvents2*>(this);
}

else if (riid == IID_IApplicationEvents2){
    *ppvObj = static_cast<IApplicationEvents2*>(this);
}
else if (riid == IID_IDispatch){
    *ppvObj = static_cast<IApplicationEvents2*>(this);
}

else
{
    char clsidStr[256];
    WCHAR wClsidStr[256];
    char txt[512];

    StringFromGUID2(riid, (LPOLESTR)&wClsidStr, 256);

    // Convert down to ANSI
    WideCharToMultiByte(CP_ACP, 0, wClsidStr, -1, clsidStr, 256, NULL, NULL);

    sprintf_s(txt, 512, "riid is : %s: Unsupported Interface", clsidStr);

    *ppvObj = NULL;
    return E_NOINTERFACE;
}

static_cast<IUnknown*>(*ppvObj)->AddRef();

return S_OK;
}

STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{
return E_NOTIMPL;
}

STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
return E_NOTIMPL;
}

STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
       LCID lcid, DISPID* rgdispid)
{
return E_NOTIMPL;
}

STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
       LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
       EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return E_NOTIMPL;
}

// IApplicationEvents2 methods
void Startup();
void Quit();
void DocumentChange();


protected:
LONG                        m_cRef;
};

#endif // _OFFICEEVENTHANDLER_H_

C:

#include <windows.h>
#include <stdio.h>
#include "OfficeEventHandler.h"
#include "OCIdl.h"



int main()
{
CLSID clsid;                   // CLSID of automation object 
HRESULT hr; 
LPUNKNOWN punk = NULL;         // IUnknown of automation object 
LPDISPATCH pdisp = NULL;       // IDispatch of automation object 
IConnectionPointContainer *pConnPntCont;
IConnectionPoint *pConnPoint;
IUnknown *iu;
IID id;  
COfficeEventHandler *officeEventHandler = new COfficeEventHandler;

CoInitialize(NULL);

hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid); 

hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,  
                      IID_IUnknown, (void FAR* FAR*)&punk); 

hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont); 

// IID for ApplicationEvents2 
hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}",&id);

hr = pConnPntCont->FindConnectionPoint( id, &pConnPoint );

hr = officeEventHandler->QueryInterface( IID_IUnknown, (void FAR* FAR*)&iu);

hr = pConnPoint->Advise( iu, &officeEventHandler->m_dwEventCookie );

Sleep( 360000 );

hr = pConnPoint->Unadvise( officeEventHandler->m_dwEventCookie );
if (punk) punk->Release(); 
if (pdisp) pdisp->Release(); 

CoUninitialize();

return hr; 
}

// IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
printf( "In Startup\n" );
}

void COfficeEventHandler::Quit()
{
printf( "In Quit\n" );
}

void COfficeEventHandler::DocumentChange()
{
printf( "In DocumentChnage\n" );
}
+3
2

: -, COM- - Windows, Sleep(), -.

+3

, :

  • Sharptooth, Sleep . , , . sharptooth.
  • "Invoke". , , , . invoke dispid . typelib. OLE viewer, "id", , -, .

.cpp . .h Invoke .

:

  • , , , , .
  • COM, GetActiveObject, CoCreateInstance. , . . Word , , , Word, . , , , .

, !

#include <windows.h>
#include <stdio.h>
#include "OfficeEventHandler.h"
#include "OCIdl.h"



int main()
{
    CLSID clsid;                   // CLSID of automation object 
    HRESULT hr; 
    LPUNKNOWN punk = NULL;         // IUnknown of automation object 
    LPDISPATCH pdisp = NULL;       // IDispatch of automation object 
    IConnectionPointContainer *pConnPntCont;
    IConnectionPoint *pConnPoint;
    IUnknown *iu;
    IID id;  
    COfficeEventHandler *officeEventHandler = new COfficeEventHandler;

    CoInitialize(NULL);

    hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid); 

 /*  hr = GetActiveObject( clsid, NULL, &punk );
 */  hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,  
                          IID_IUnknown, (void FAR* FAR*)&punk); 

    hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont); 

    // IID for ApplicationEvents2 
    hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}",&id);

    hr = pConnPntCont->FindConnectionPoint( id, &pConnPoint );

    hr = officeEventHandler->QueryInterface( IID_IUnknown, (void FAR* FAR*)&iu);

    hr = pConnPoint->Advise( iu, &officeEventHandler->m_dwEventCookie );

    MSG   msg;
    BOOL  bRet;

    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }

        if( msg.message == WM_QUERYENDSESSION || msg.message == WM_QUIT || msg.message == WM_DESTROY )
        {
            break;
        }
    }

    hr = pConnPoint->Unadvise( officeEventHandler->m_dwEventCookie );
    if (punk) punk->Release(); 
    if (pdisp) pdisp->Release(); 

    CoUninitialize();

    return hr; 
}

    // IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
    printf( "In Startup\n" );
}

void COfficeEventHandler::Quit()
{
    printf( "In Quit\n" );
}

void COfficeEventHandler::DocumentChange()
{
    printf( "In DocumentChnage\n" );
}

STDMETHODIMP COfficeEventHandler::Invoke(DISPID dispIdMember, REFIID riid,
           LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
           EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    //Validate arguments
    if ((riid != IID_NULL))
        return E_INVALIDARG;

    HRESULT hr = S_OK;  // Initialize

    /* To see what Word sends as dispid values */
    static char myBuf[80];
    memset( &myBuf, '\0', 80 );
    sprintf_s( (char*)&myBuf, 80, " Dispid: %d :", dispIdMember );

    switch(dispIdMember){
    case 0x01:    // Startup
        Startup();
    break;
    case 0x02:    // Quit
        Quit();
    break;
    case 0x03:    // DocumentChange
        DocumentChange();
    break;
    }

    return S_OK;
 }
+3

Source: https://habr.com/ru/post/1770313/


All Articles