P
Phillip N Rounds
Sorry to start a new thread on this topic, but I think I've made sufficient
progress to warrant it.
Anyway, what I am trying to do in this automation project is to have Word
initiated from
within a C++ ( VC++ 6) app, trap some user activity and perform some
background functions
based on these traps. I've followed MS's KB183599 with some modifications.
My problem is that when I run the code as is, it works fine. However, the
code as is utilizes the UUID of the dispApplicationEvents interface
( UUID 000209F7-0000-0000-C000-000000000049), which doesn't include some of
the specific events I want to trap ( specifically, the Save function ).
When I change to the UUID of dispApplicationEvents2 interface
( UUID 000209FE-0000-0000-C000-000000000049) I still can't trap the any
events supposidly in ApplicationEvents2, I can only trap events
in ApplicationEvents
I think I'm missing something simple but fundamental here. Is
IID_IWordAppEvents, as in the following example, supposed to bye the IID
of the ApplicationEvents interface? If not, what is it supposed to be?
Any and all help would be greatly appreciated.
My (Pseudo) code is
static const GUID IID_IWordAppEvents =
{0x000209F7,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
// Define & Initialize my WORD appliction, m_App
_Application m_App ;
m_App.m_app.CreateDispatch("Word.Application.11", &e);
// Create a ConnectionPointContainter to hold the connection points for
m_App
IConnectionPointContainer *pConnPtContainer;
hr = m_app.m_lpDispatch->QueryInterface(
IID_IConnectionPointContainer, (void **)&pConnPtContainer );
// Get the Connection Points
hr = pConnPtContainer->FindConnectionPoint(IID_IWordAppEvents,
&m_pConnectionPoint );
The complete code is:
My code to start Word: // This is exactly as it appears in the KB
article with a few exceptions.
// I have included all of Word from the type library
MSWORD.OLB ( Word 11 )
// m_app is declared as _Application, where _Application
is defined in msword.h
//
void CWordEventsDlg::OnBUTTONStart()
{
// Check to see if you've already started the server.
if(m_app.m_lpDispatch != NULL) {
AfxMessageBox("Server already started.");
return;
}
char buf[256]; // General purpose buffer.
// Start Automation server.
COleException e;
if(!m_app.CreateDispatch("Word.Application.11", &e)) {
sprintf(buf, "Error on CreateDispatch(): %ld (%08lx)", e.m_sc,
e.m_sc);
AfxMessageBox(buf, MB_SETFOREGROUND);
return; }
// Make server visible through automation.
// I.e.: Application.Visible = TRUE
DISPID dispID;
unsigned short *ucPtr;
BYTE *parmStr;
ucPtr = L"visible";
m_app.m_lpDispatch->GetIDsOfNames( IID_NULL, &ucPtr, 1,
LOCALE_USER_DEFAULT, &dispID );
parmStr = (BYTE *)( VTS_VARIANT );
m_app.InvokeHelper( dispID, DISPATCH_METHOD |
DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parmStr, &COleVariant((short)
);
// Declare the events you want to catch.
// {000209F7-0000-0000-C000-000000000046}
static const GUID IID_IWord8AppEvents =
{0x000209F7,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
// Steps for setting up events.
// 1. Get server's IConnectionPointContainer interface.
// 2. Call IConnectionPointContainerFindConnectionPoint()
// to find the event you want to catch.
// 3. Call IConnectionPoint::Advise() with the IUnknown
// interface of your implementation of the events.
HRESULT hr;
m_myEventSink.pParent = (CWnd*) this; // This is different, I have
a field in MyEventSink referencing the calling window so It can post back a
message
// Get server's IConnectionPointContainer interface.
IConnectionPointContainer *pConnPtContainer;
hr = m_app.m_lpDispatch->QueryInterface(
IID_IConnectionPointContainer, (void **)&pConnPtContainer );
ASSERT(!FAILED(hr));
// Find connection point for events you're interested in.
hr = pConnPtContainer->FindConnectionPoint( IID_IWord8AppEvents,
&m_pConnectionPoint );
ASSERT(!FAILED(hr));
// Get the IUnknown interface of your event implementation.
LPUNKNOWN pUnk = m_myEventSink.GetInterface(&IID_IUnknown);
ASSERT(pUnk);
// Setup advisory connection!
hr = m_pConnectionPoint->Advise(pUnk, &m_adviseCookie);
ASSERT(!FAILED(hr));
// Release IConnectionPointContainer interface.
pConnPtContainer->Release();
}
My implimentation of MyEventSink is as follows: Here I have changed some of
the DISP_FUNCTION declarations to DISP_FUNCTION_ID declarations
BEGIN_DISPATCH_MAP(MyEventSink, CCmdTarget)
//{{AFX_DISPATCH_MAP(MyEventSink)
DISP_FUNCTION_ID(MyEventSink, "Quit", 2, Quit, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "Save", 8, Save, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "Startup", 1, Startup, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "DocumentChange", 3, DocumentChange,
VT_EMPTY, VTS_NONE)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
void MyEventSink::Startup()
{
TRACE0("\r\nWord Started");
WPARAM wpar = 0; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar); //
SinkReceived = WM_USER + 101 is my MessageID}
void MyEventSink::Quit()
{
TRACE0("\r\nWord Quit");
WPARAM wpar = 1; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar); }
void MyEventSink:ocumentChange()
{
TRACE0("\r\nDocument Changed!!!!!!!");
WPARAM wpar = 2; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar);
}
void MyEventSink::Save()
{
WPARAM wpar= 8;
LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar);}
progress to warrant it.
Anyway, what I am trying to do in this automation project is to have Word
initiated from
within a C++ ( VC++ 6) app, trap some user activity and perform some
background functions
based on these traps. I've followed MS's KB183599 with some modifications.
My problem is that when I run the code as is, it works fine. However, the
code as is utilizes the UUID of the dispApplicationEvents interface
( UUID 000209F7-0000-0000-C000-000000000049), which doesn't include some of
the specific events I want to trap ( specifically, the Save function ).
When I change to the UUID of dispApplicationEvents2 interface
( UUID 000209FE-0000-0000-C000-000000000049) I still can't trap the any
events supposidly in ApplicationEvents2, I can only trap events
in ApplicationEvents
I think I'm missing something simple but fundamental here. Is
IID_IWordAppEvents, as in the following example, supposed to bye the IID
of the ApplicationEvents interface? If not, what is it supposed to be?
Any and all help would be greatly appreciated.
My (Pseudo) code is
static const GUID IID_IWordAppEvents =
{0x000209F7,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
// Define & Initialize my WORD appliction, m_App
_Application m_App ;
m_App.m_app.CreateDispatch("Word.Application.11", &e);
// Create a ConnectionPointContainter to hold the connection points for
m_App
IConnectionPointContainer *pConnPtContainer;
hr = m_app.m_lpDispatch->QueryInterface(
IID_IConnectionPointContainer, (void **)&pConnPtContainer );
// Get the Connection Points
hr = pConnPtContainer->FindConnectionPoint(IID_IWordAppEvents,
&m_pConnectionPoint );
The complete code is:
My code to start Word: // This is exactly as it appears in the KB
article with a few exceptions.
// I have included all of Word from the type library
MSWORD.OLB ( Word 11 )
// m_app is declared as _Application, where _Application
is defined in msword.h
//
void CWordEventsDlg::OnBUTTONStart()
{
// Check to see if you've already started the server.
if(m_app.m_lpDispatch != NULL) {
AfxMessageBox("Server already started.");
return;
}
char buf[256]; // General purpose buffer.
// Start Automation server.
COleException e;
if(!m_app.CreateDispatch("Word.Application.11", &e)) {
sprintf(buf, "Error on CreateDispatch(): %ld (%08lx)", e.m_sc,
e.m_sc);
AfxMessageBox(buf, MB_SETFOREGROUND);
return; }
// Make server visible through automation.
// I.e.: Application.Visible = TRUE
DISPID dispID;
unsigned short *ucPtr;
BYTE *parmStr;
ucPtr = L"visible";
m_app.m_lpDispatch->GetIDsOfNames( IID_NULL, &ucPtr, 1,
LOCALE_USER_DEFAULT, &dispID );
parmStr = (BYTE *)( VTS_VARIANT );
m_app.InvokeHelper( dispID, DISPATCH_METHOD |
DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parmStr, &COleVariant((short)
);
// Declare the events you want to catch.
// {000209F7-0000-0000-C000-000000000046}
static const GUID IID_IWord8AppEvents =
{0x000209F7,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
// Steps for setting up events.
// 1. Get server's IConnectionPointContainer interface.
// 2. Call IConnectionPointContainerFindConnectionPoint()
// to find the event you want to catch.
// 3. Call IConnectionPoint::Advise() with the IUnknown
// interface of your implementation of the events.
HRESULT hr;
m_myEventSink.pParent = (CWnd*) this; // This is different, I have
a field in MyEventSink referencing the calling window so It can post back a
message
// Get server's IConnectionPointContainer interface.
IConnectionPointContainer *pConnPtContainer;
hr = m_app.m_lpDispatch->QueryInterface(
IID_IConnectionPointContainer, (void **)&pConnPtContainer );
ASSERT(!FAILED(hr));
// Find connection point for events you're interested in.
hr = pConnPtContainer->FindConnectionPoint( IID_IWord8AppEvents,
&m_pConnectionPoint );
ASSERT(!FAILED(hr));
// Get the IUnknown interface of your event implementation.
LPUNKNOWN pUnk = m_myEventSink.GetInterface(&IID_IUnknown);
ASSERT(pUnk);
// Setup advisory connection!
hr = m_pConnectionPoint->Advise(pUnk, &m_adviseCookie);
ASSERT(!FAILED(hr));
// Release IConnectionPointContainer interface.
pConnPtContainer->Release();
}
My implimentation of MyEventSink is as follows: Here I have changed some of
the DISP_FUNCTION declarations to DISP_FUNCTION_ID declarations
BEGIN_DISPATCH_MAP(MyEventSink, CCmdTarget)
//{{AFX_DISPATCH_MAP(MyEventSink)
DISP_FUNCTION_ID(MyEventSink, "Quit", 2, Quit, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "Save", 8, Save, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "Startup", 1, Startup, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(MyEventSink, "DocumentChange", 3, DocumentChange,
VT_EMPTY, VTS_NONE)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
void MyEventSink::Startup()
{
TRACE0("\r\nWord Started");
WPARAM wpar = 0; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar); //
SinkReceived = WM_USER + 101 is my MessageID}
void MyEventSink::Quit()
{
TRACE0("\r\nWord Quit");
WPARAM wpar = 1; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar); }
void MyEventSink:ocumentChange()
{
TRACE0("\r\nDocument Changed!!!!!!!");
WPARAM wpar = 2; LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar);
}
void MyEventSink::Save()
{
WPARAM wpar= 8;
LPARAM lpar = NULL;
:ostMessage( pParent->m_hWnd, SinkReceived, wpar, lpar);}