摘要:這篇文章著重講述了如何使用MFC將Microsoft Word嵌入到應用程序中的方法。對在VC下使用類型庫和COM技術也做了簡要闡述。
關鍵字:VC++、MFC、COM、自動化
一、 引言
Microsoft Office辦公套件以其功能強大、方便實用而被廣泛使用。我們可以使用自動化作為Word用以把其功能顯露給其他應用的方式,采用這種方式可以盡可能少的占用自動化客戶的資源,并且不需要被訪問對象的類型信息就可以進行調用。
二、 創建工程
以下是創建這個MFC應用程序的步驟:
(一)使用AppWizard創建一個新的MFC AppWizard(EXE)工程,命名為"Embed_Word"
。ǘ┻x擇單文檔視圖(SDI)結構,在第3步中需要選中Container,以提供容器支持。 其它都為默認。在ClassView中將產生如下類:
應用類: CEmbed_WordApp in Embed_Word.h and Embed_Word.cpp
框架類: CMainFrame in MainFrm.h and MainFrm.cpp
文檔類: CEmbed_WordDoc in Embed_WordDoc.h and Embed_WordDoc.cpp
視圖類: CEmbed_WordView in Embed_WordView.h and Embed_WordView.cpp
容器類: CEmbed_WordCntrItem in CntrItem.h and CntrItem.cpp 。ㄈ┰赩iew菜單中,選ClassWizard,選Automation選項卡,選Add Class,選擇From a TypeLibrary, 在Office目錄中選中Microsoft Word 97/2000 類型庫Word8.olb或Word9.olb,會將把類型庫中的所有類添加到你的工程中。這時,ClassView中會多出幾十個類,可以通過這些類提供的接口來實現必要的功能。
。ㄋ模┰贑CntrItem.h中添加獲取標準COM接口IDispach的函數:
LPDISPATCH GetIDispatch(); 其函數實現如下: LPDISPATCH CEmbed_WordCntrItem::GetIDispatch() { ASSERT_VALID(this); ASSERT(m_lpObject != NULL); LPUNKNOWN lpUnk = m_lpObject; Run(); LPOLELINK lpOleLink = NULL; if(m_lpObject->QueryInterface(IID_IOleLink,(LPVOID FAR*)&lpOleLink)== NOERROR) { ASSERT(lpOleLink != NULL); lpUnk = NULL; if(lpOleLink->GetBoundSource(&lpUnk) != NOERROR) { TRACE0("Warning: Link is not connected!\n"); lpOleLink->Release(); } ASSERT(lpUnk != NULL); } LPDISPATCH lpDispatch = NULL; if(lpUnk->QueryInterface(IID_IDispatch,(LPVOID FAR*)&lpDispatch) != NOERROR) { TRACE0("Waring: does not support IDispatch!\n"); return NULL; } ASSERT(lpDispatch != NULL); return lpDispatch; }
通過此函數來返回標準COM接口IDispatch。
(五)在Embed_WordView.cpp中添加對"MSWord8.h"的引用:#include "MSWord8.h",如使用Word2000,則包含對"MSWord9.h"的引用。 然后在視類CEmbed_WordView中添加函數EmbedAutomateExcel():
void CEmbed_WordView::EmbedAutomateWord() { BeginWaitCursor(); CEmbed_WordCntrItem* pItem = NULL; TRY { CEmbed_WordDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pItem = new CEmbed_WordCntrItem(pDoc); ASSERT_VALID(pItem); GetClientRect(&pItem->rect);
CLSID clsid; if(FAILED(::CLSIDFromProgID(L"Word.document",&clsid))) AfxThrowMemoryException(); if(!pItem->CreateNewItem(clsid)) AfxThrowMemoryException(); ASSERT_VALID(pItem); pItem->DoVerb(OLEIVERB_SHOW, this); m_pSelection = pItem; pDoc->UpdateAllViews(NULL); LPDISPATCH lpDisp; lpDisp = pItem->GetIDispatch(); } CATCH(CException, e) { if (pItem != NULL) { ASSERT_VALID(pItem); pItem->Delete(); } AfxMessageBox(IDP_FAILED_TO_CREATE); } END_CATCH EndWaitCursor(); }
如果仔細研究過這段代碼,會發現它同AppWizard自動生成的OnInsertObject()函數有著驚人的相似程度,看一下View類中的 OnInsertObject() 方法,對其中的注釋引起了我們的興趣,因為它和我們剛寫的方法有驚人的相似。事實上,我們剛才寫的只不過是OnInsertObject()的一個特例:OnInsertObject()允許用戶從可用的OLE對象列表中選擇其一插入到應用程序中。因為在此我們只需對Word進行自動化,所以派生了這一行為。
(六)為了在程序剛啟動時便將Word嵌入到程序中來,還需在視類的OnInitialUpdate()函數中添加代碼:
void CEmbed_WordView::OnInitialUpdate() { CView::OnInitialUpdate(); EmbedAutomateWord(); //將Word嵌入 m_pSelection = NULL; }
。ㄆ撸榱耸骨度氲墓ぷ鲄^占滿整個客戶區可以通過修改OnDraw函數來實現:
void CEmbed_WordView::OnDraw(CDC* pDC) { CEmbed_WordDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (m_pSelection == NULL) { POSITION pos = pDoc->GetStartPosition(); m_pSelection = (CEmbed_WordCntrItem*)pDoc->GetNextClientItem(pos); } if (m_pSelection != NULL) { CRect rect; GetClientRect(&m_pSelection->rect); m_pSelection->OnGetItemPosition(rect); m_pSelection->Draw(pDC,rect); } }
三、 編譯執行
編譯執行該程序,當程序啟動時便會試圖啟動Word自動化服務,這時鼠標會處于等待狀態,當鼠標恢復正常狀態時,Word以經被嵌入到了程序中來,工具條和菜單上會多出許多Word上的工具條和菜單,并可以使用Word的這些功能來為我們服務。
小結:
通過這個例子我們可以對COM技術有初步的了解,也可以用類似的方法為程序添加其他服務,如Excel、PowerPoint等其他Office套件,使廣大讀者對自動化技術有基本的認識。
|