本文將告訴您,如何攔截使用 Microsoft Visual C++ 的 Microsoft Word 97 中的應用程式事件。不過,概念和本文的程式碼不是 Microsoft Word 的特定 ; 它們是適用於 Microsoft Office 應用程式,以及其他任何公開 (Expose) 事件的應用程式為整個組件。
下列步驟說明如何建立一個 MFC 應用程式會攔截 Microsoft Word 97 應用程式事件 Startup()、 DocumentChange() 和 Quit():
- 建立一個新對話方塊方塊架構應用程式使用 MFC AppWizard。命名您的專案 WordEvents,並接受預設設定。
- 將兩個按鈕加入至您的對話方塊並命名按鈕 」 啟動安裝及程式 」 和 「 結束 」 清潔向上,分別。
- 將下列程式碼加入至 「 開始安裝及程式 」 按鈕的處理常式:
// 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.8", &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)TRUE)
);
// Declare the events you want to catch.
// {000209F7-0000-0000-C000-000000000046}
static const GUID IID_IWord8AppEvents =
{0x000209f7,0x000,0x0000,{0xc0,0x00,0x0,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;
// 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();
- 將下列程式碼加入至"結束並正常上 」 按鈕的處理常式:
// Check if you've started the server.
if(m_app.m_lpDispatch == NULL) {
AfxMessageBox("You haven't started the server yet.");
return;
}
m_pConnectionPoint->Unadvise(m_adviseCookie);
// Tell server to quit.
// Application.Quit()
DISPID dispID; // Temporary DISPID
unsigned short *ucPtr; // Temporary name holder
ucPtr = L"quit";
m_app.m_lpDispatch->GetIDsOfNames(
IID_NULL, &ucPtr, 1, LOCALE_USER_DEFAULT, &dispID
);
m_app.InvokeHelper(dispID, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
// Release application object.
m_app.ReleaseDispatch();
- 啟動 MFC ClassWizard (CTRL + W),並加入新的類別衍生從 CCmdTarget 並具有自動化支援 (請檢查 「 自動化 」 選項)。命名這個類別 MyEventSink ; 它就是我們的 Microsoft Word 應用程式事件的實作。
- 在 MFC ClassWizard,按一下 [自動化] 索引標籤,然後在順序中新增這些三種方法:
void Startup()
void Quit()
void DocumentChange()
- MyEventSink.cpp,在實作這些新方法來顯示訊息方塊,當它們呼叫,讓您知道它們觸發時:
void MyEventSink::Startup()
{
AfxMessageBox("MyEventSink::Startup() called.");
}
void MyEventSink::Quit()
{
AfxMessageBox("MyEventSink::Quit() called.");
}
void MyEventSink::DocumentChange()
{
AfxMessageBox("MyEventSink::DocumentChange() called.");
}
- 開啟 MyEventSink.cpp 檔案,並尋找 IID_IMyEventSink 的宣告。[ClassWizard 產生新的隨機 GUID 為您的介面,但是因為您正在實作特定介面已經具有 GUID,您必須變更以符合您自己。修改 IID_IMyEventSink 的宣告如下: 靜態 const GUID IID_IMyEventSink = {0x000209f7、 0x000、 0x0000,{0xc0、 0x00,0x0、 0x00,0x00、 0x00,0x00,0x46}};
- 將下列的公用成員變數加入至您的 WordEventsDlg 類別中 WordEventsDlg.h:
COleDispatchDriver m_app;
IConnectionPoint *m_pConnectionPoint;
DWORD m_adviseCookie;
MyEventSink m_myEventSink;
- 下面這一行 WordEventsDlg.h 右前會加入類別 CWordEventsDlg 宣告:
- 開啟檔案 MyEventSink.h 並尋找解構函式的宣告] ; 它將會出現,如下所示:
// Implementation
protected:
virtual ~MyEventSink();
- 移動該宣告 Protected"這個字上面,讓幾行程式碼顯示如下:
virtual ~MyEventSink();
// Implementation
protected:
// virtual ~MyEventSink(); // Or this line may be removed.
- 最後,請確定 OLE/COM 程式庫機會來初始化。加入下列程式碼右邊的 [開始安裝及程式] 按鈕處理常式之前。這會建立全域的類別取得建立在應用程式啟動和結束時被終結。建構函式和解構函式的這個類別提供便利的方式來執行初始化和清除:
// Ole-initialization class.
class OleInitClass {
public:
OleInitClass() {
OleInitialize(NULL);
}
~OleInitClass() {
OleUninitialize();
}
};
// This global class calls OleInitialize() at
// application startup, and calls OleUninitialize()
// at application exit.
OleInitClass g_OleInitClass;
- 編譯並執行。
執行 [應用程式後按一下 [「
開始時間] 及 [安裝程式 」] 按鈕,以啟動 Microsoft Word 並設定事件通知]。 在 Microsoft Word 中在 [
檔案] 功能表上按一下 [
新增],以建立新的文件]。DocumentChange() 事件應該取得引發。開啟另一份文件,並請注意它也取得發生於您切換到另一份文件從啟動。您可以按 「
結束並清洗向上 」] 按鈕,以停止事件通知,結束 Microsoft Word 或您可以從 Microsoft Word 結束 (按一下 [
檔案] 功能表的 [
結束]),並注意 Quit 通知。
您可能會注意到永遠不會觸發啟動事件。這是因為它引發之前您設定事件。請注意沒有真正處理這個事件沒有理由因為應用程式必須已經開始,然後再呼叫並設定自動化方法和屬性。
Microsoft Excel 支援許多的有趣且有用事件,而且您可以遵循此處的步驟來捕捉它們。不過,是要記住的幾個事項:
- 使用 OLE/COM 物件檢視器隨附 Microsoft Visual C++ 5.0 來檢視的伺服器您感興趣的型別程式庫。若要尋找之事件開啟 coclass 宣告 (通常是在樹狀目錄的底部) ; 會列出每一個 Coclass 關聯的事件。當您按一下) 您可以看到哪些事件是可用的事件介面、 其 DISPID 和它們在右側檢視中的宣告方式。
- 您不需要修改 DISPID 對於我們我們 MyEventSink 類別中的方法,因為 Microsoft Word 應用程式事件、 Startup()、 Quit(),DocumentChange() 有 DISPID 1、 2 和 3,分別。 如果您建立這些方法的順序,您沒有修改它們符合型別程式庫,因為 ClassWizard 從 DISPID 1 開始。不過,像 Microsoft Excel 活頁簿事件的大部分事件無法啟動與 DISPID 1。在這種情況下,您必須明確地修改分派對應中 MyEventSink.cpp 符合之 DISPID 的正確方法。
如需詳細資訊,有關建立接收器介面,],然後簡化連線程序,按一下下面的文件編號,檢視 「 Microsoft 知識庫 」 中上的 []:
181845?
(http://support.microsoft.com/kb/181845/
)
HOWTO: 建立在以 MFC 為基礎的 COM 用戶端接收器介面
一般範例的以及更多的資訊,有關,連接點請參閱下列文章 「 Microsoft 知識庫 」 中所述的 Connpts.exe 範例:
152087?
(http://support.microsoft.com/kb/152087/
)
Connpts.exe 在 MFC 應用程式中實作連接點