摘要
本文解答了有關從 Visual C++ 自動化到 Microsoft Office 的常見問題。
更多資訊
目錄
-
什麼是自動化?
-
我不熟悉自動化,在哪裡可以找到要了解詳細資訊的好資源?
-
是否有其他方法可以使用自動化?
-
什麼是 COM?
-
如何實現附加到正在執行的 Office 應用程式例項?
-
如何實現傳遞可選引數?
-
如何實現捕獲 Office 應用程式公開的事件?
-
我的自動化程式碼太慢了。 如何加快速度?
-
這些巨大的錯誤值(如 -2147352573 或 0x80030002)是什麼意思?
-
什麼是型別庫?
-
我的自動化程式碼適用於 Microsoft Excel 95,但 Microsoft Excel 97 失敗。 為什麼?
-
為什麼在程式完成後,我自動執行的應用程式會保留在記憶體中?
-
我知道作為 Microsoft Office 應用程式使用者我想做什麼,但如何使用自動化以程式設計方式執行此操作?
-
是否可以自動執行嵌入式 Microsoft Office 應用程式?
-
如何實現 Microsoft Office 文件中訪問我的文件屬性?
問題和解答
-
什麼是自動化?
自動化 (以前為 OLE 自動化) 是一種技術,可用於利用現有程式的功能並將其合併到自己的應用程式中。 例如,可以在應用程式中利用 Microsoft Word 拼寫和語法檢查功能,而使用者看不到 Microsoft Word。 甚至可以使用所有 Microsoft Excel 圖表、列印和資料分析工具。 這項技術可以大大簡化和加快開發速度。
-
我不熟悉自動化,在哪裡可以找到要了解詳細資訊的好資源? David Kruglinski 的“Visual C++內部” (ISBN:1-57231-565-2) 提供了一般概述和一些很好的示例。 此外,Microsoft 知識庫是一個很好的資訊來源。
如果你更喜歡透過示例學習,請參閱 Microsoft 知識庫中的以下文章:
179706 如何使用 MFC 自動執行 Excel &建立新工作簿/設定其格式
-
是否有其他方法可以使用自動化?
可以使用自動化的三種基本方法:MFC、#import和 C/C++:
-
使用 MFC 時,使用 Visual C++ ClassWizard 從 Microsoft Office 型別庫生成“包裝類”。 這些類以及其他 MFC 類(如 COleVariant、COleSafeArray、COleException)簡化了自動化的任務。 通常建議使用此方法,而其他方法,並且大多數 Microsoft 知識庫示例都使用 MFC。
-
#import是 Visual C++ 5.0 中提供的一個新指令,它從指定的型別庫建立 VC++“智慧指標”。 它非常強大,但通常不建議使用,因為與 Microsoft Office 應用程式一起使用時通常會發生引用計數問題。
-
C/C++ 自動化要困難得多,但有時需要避免 MFC 開銷或#import問題。 基本上,可以使用 CoCreateInstance () 等 API 以及 IDispatch 和 IUnknown 等 COM 介面。
請務必注意,與純 C 相比,C++ 中的自動化之間存在一些細微差別,因為 COM 是圍繞 C++ 類設計的。
-
-
什麼是 COM?
自動化基於元件物件模型 (COM) 。 COM 是基於介面的標準軟體體系結構,旨在將程式碼分隔成獨立的物件。 將其視為物件導向的程式設計 (OOP) 範例的擴充套件,但適用於單獨的應用程式。 每個物件公開一組介面,與物件的所有通訊(如初始化、通知和資料傳輸)都透過這些介面進行。
COM 也是動態連結庫提供的一組服務, (DLL) 隨作業系統一起安裝。 自動化使用其中許多服務。 一個示例是“封送”服務,該服務打包客戶端應用程式對伺服器應用程式介面成員函式的呼叫,並將這些呼叫及其引數傳遞給伺服器應用程式。 它使伺服器的介面似乎在客戶端的記憶體空間中公開,當客戶端是在其自己的程序空間中執行的.exe時,情況並非如此。 封送處理還會跨程序邊界從伺服器的方法獲取返回值,並安全地交到客戶端呼叫手中。 還有許多其他對自動化至關重要的服務,這些服務由各種 COM 庫提供。 有關這些資訊的來源包括 Kraig Brockschmidt 的“Inside Ole - 第二版”、ISBN 1-55615-843-2、戴爾·羅傑森的“Inside COM”-ISBN 1-57231-349-8 和“自動化程式設計師參考”,ISBN 1-57231-584-9。 -
如何實現附加到 Office 應用程式的正在執行的例項?
使用 GetActiveObject () API。 自動化伺服器透過 RegisterActiveObject () API 在 ROT (Running Object Table) 中註冊自己。 自動化客戶端可以使用以下程式碼訪問正在執行的例項:
// Translate server ProgID into a CLSID. ClsidFromProgID // gets this information from the registry. CLSID clsid; CLSIDFromProgID(L"Excel.Application", &clsid); // Get an interface to the running instance, if any.. IUnknown *pUnk; HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk); ASSERT(!FAILED(hr)); // Get IDispatch interface for Automation... IDispatch *pDisp; hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp); ASSERT(!FAILED(hr)); // Release the no-longer-needed IUnknown... pUnk->Release();
注意:如果要附加的 Office 應用程式執行多個例項,則只能附加到使用 GetActiveObject () API 啟動的第一個例項。
從理論上講,可以迴圈訪問每個單獨例項的 ROT,但如果另一個例項已在 ROT 中,Office 應用不會自行註冊,因為本身的名字物件始終是相同的 (它無論如何都無法區分) 。 這意味著不能附加到除第一個例項之外的任何例項。 但是,由於 Office 應用也在 ROT 中註冊其文件,因此可以透過迴圈訪問 ROT 查詢特定文件、附加該文件,然後從中獲取 Application 物件來成功附加到其他例項。
無需為 PowerPoint 執行此操作,因為它是單例項應用程式;只能執行它的一個例項。 -
如何實現傳遞可選引數?
某些方法具有“可選”引數。 在 Visual Basic 中,可以在呼叫 方法時隨意省略它們。 但是,在使用 Visual C++ 呼叫時,必須傳遞一個特殊 VARIANT,該變數的 .vt 欄位VT_ERROR,而 .scode 欄位DISP_E_PARAMNOTFOUND。 那是:
// VARIANT used in place of optional-parameters. VARIANT varOpt; varOpt.vt = VT_ERROR; varOpt.scode = DISP_E_PARAMNOTFOUND;
這確實是 Visual Basic 在幕後執行的操作。
-
如何實現捕獲 Office 應用程式公開的事件?
基本上,實現要捕獲 (“接收器”) 的事件介面,並 (“源”) 與應用程式建立諮詢連線。
通常,若要設定諮詢連線,請獲取伺服器的 IConnectionPointContainer,並使用事件介面的 IID 呼叫 FindConnectionPoint () 。 這為你提供了一個 IConnectionPoint 介面,剩下的就是使用事件介面的例項呼叫 Advise () 。 然後,當發生這些事件時,伺服器將透過此介面回撥。 -
我的自動化程式碼太慢了。 如何加快速度?
自動化速度問題的一個常見原因是重複讀取和寫入資料。 這是 Excel 自動化客戶端的典型應用。 但是,大多數人不知道此資料通常可以使用 SAFEARRAY 一次性寫入或讀取。 有關詳細資訊和資訊性示例,請參閱以下 Microsoft 知識庫文章:179706 HOWTO:使用 MFC 自動執行 Excel 和建立新工作簿/設定新工作簿
的格式 此外,請務必指出,使用剪貼簿有時可以提高效能。 例如,法律時刻可以將資料複製到剪貼簿,然後使用自動化來告知伺服器進行貼上。 反之亦然;告知伺服器複製到剪貼簿,並貼上到應用程式中。 -
這些巨大的錯誤值(如 -2147352573 或 0x80030002)是什麼意思?
這些值稱為 HRESULT,在 winerror.h 中定義。 數字如此之大,因為第一個位表示它是否是錯誤結果。 可以使用 Visual C++ 附帶的 ErrLook.Exe 實用工具將這些數字轉換為有意義的說明。
如果要以程式設計方式獲取錯誤說明,可以使用 FormatMessage () API。注意:如果使用 Visual C++ 6.0 並在除錯監視視窗中有一個包含此值的變數,請追加“, hr” (不帶引號) ,以便 Visual C++ 為你翻譯它!
-
什麼是型別庫?
型別庫類似於 C/C++ 標頭檔案。 它包含伺服器正在釋出的介面、方法和屬性。 可以使用 Visual C++ 附帶的 OLE/COM 物件檢視器 (Oleview.exe) 檢視型別庫。 下面是 Microsoft Office 95、97 和 2000 的型別庫檔名列表:
Office 應用程式|型別庫
------------------------+----------------
Word 95 和以前的|wb70en32.tlb
Excel 95 及更早版本的|xl5en32.olb
Powerpoint 95 和以前的|Powerpoint.tlb
Access 95 及更早|msaccess.tlb
Binder 95 |binder.tlb
Schedule+ |sp7en32.olb
專案|pj4en32.olb
團隊經理|mstmgr1.olb
Word 97 |msword8.olb
Excel 97 |excel8.olb
Powerpoint 97 |msppt8.olb
Access 97 |msacc8.olb
Binder 97 |msbdr8.olb
圖 97 |graph8.olb
Outlook 97 |msoutl8.olb
Outlook 98 |msoutl85.olb
Word 2000 |msword9.olb
Excel 2000 |excel9.olb
Powerpoint 2000 |msppt9.olb
Access 2000 |msacc9.olb
Outlook 2000 |msoutl9.olb
Word 2002 |msword.olb
Excel 2002 |
excel.exe Powerpoint 2002 |msppt.olb
Access 2002 |msacc.olb
Outlook 2002 |msoutl.olb
-
我的自動化程式碼適用於 Excel 95,但 Excel 97 失敗。 發生了什麼事情?
Excel 的物件模型進行了從版本 95 到 97 的重大更改。 Excel 95 在 IDispatch 的單個實現中實現了其所有方法和屬性。 這意味著,通常可以從物件 Y 呼叫用於物件 X 的方法。這不是一個很好的設計,因此在 Office 97 中,每個物件都有其自己的獨立 Idispatch 實現。 這意味著,如果從單獨的物件 Y 從物件 X 請求方法或屬性,則會收到錯誤0x80020003 -2147352573,“找不到成員”。 若要避免此錯誤,需要確保呼叫的基礎 IDispatch 介面在語義上正確。
-
程式完成後,我自動執行的應用程式將保留在記憶體中。 發生了什麼事情?
很可能是因為你忘記了釋出獲取的介面,需要跟蹤它。 下面是一些常規建議和要查詢的事項:
-
如果使用 #import,則很可能遇到與之關聯的引用計數 bug 之一。 通常,可以解決 bug,但通常首選使用其他自動化方法之一。 #import不太適用於 Office 應用程式,因為它的型別庫和用法相當複雜。 此外,此類引用計數問題很難跟蹤,因為使用 #import 時,許多介面級 COM 呼叫都是幕後呼叫。
-
檢查是否呼叫任何方法(如 Open 或 New),這些方法返回 IDispatch * (LPDISPATCH) ,並忽略返回值。 如果是,則放棄此返回的介面,並且需要更改程式碼,以便在不再需要時將其釋放。
-
逐步註釋掉程式碼的各部分,直到問題消失,然後明智地將其新增,以跟蹤問題開始的位置。
-
請注意,如果使用者已“觸控”應用程式,某些應用程式將保持執行。 如果在自動化時發生這種情況,則應用程式可能會在之後繼續執行。 Office 應用程式在 Application 物件上具有“UserControl”屬性,可讀寫該屬性來更改此行為。
-
此外,如果發生了足夠的使用者介面“操作”,某些應用程式將決定繼續執行。 如果打算退出應用程式,請在 Application 物件上呼叫其 Quit () 方法。 呼叫 Quit 時,無論 Word 的引用計數如何,Word 都將關閉。 這不是預期的 COM 行為。 但是,Excel 將正確隱藏自身,但會一直執行,直到釋放所有未完成的介面。 通常,應釋放所有未完成的引用,並且僅當打算退出應用程式時呼叫 Quit () 。
-
-
我知道作為 Office 應用程式使用者我想做什麼,但如何透過自動化以程式設計方式執行此操作?
你感興趣的是需要使用哪些物件、方法和屬性。 若要了解如何根據使用者需要執行的操作導航 Word、Excel 和 Powerpoint 的物件模型,最佳方法是使用宏錄製器。 只需從“工具”選單中選擇“宏”“錄製新宏”,執行感興趣的任務,然後選擇“宏”“停止錄製”。 錄製完成後,從“工具”選單中選擇“宏\宏”,選擇錄製的宏,然後單擊“編輯”。 這會將你帶到生成的 VBA 程式碼,該程式碼將完成你記錄的任務。 請記住,在大多數情況下,錄製的宏不是最好的程式碼,但對於快速示例來說,它非常有用。 -
是否可以自動執行嵌入式 Office 應用程式?
絕對。 技巧在於獲取 IDispatch 指標:Visual C++ 技術說明 39 (TN039) 中提供了此指標。
-
如何實現 Office 文件中訪問我的文件屬性?
文件屬性可透過自動化或直接透過 IPropertyStorage 進行訪問。