在工做中咱們要實現一個功能,須要建立MS Office 和 WPS 兼容插件,也就是建立一個DLL,能夠同時兼容office和wps。這樣帶來的好處就是隻須要維護同一份代碼,大大下降維護的工做!c++
1. 咱們先看看要建立office插件都有哪些技術能夠用編程
VSTO = Visual Studo Tools for Office,基於.net framework框架的Office開發技術。相對於傳統的VBA(Visual Basic Application)開發,VSTO爲中高級開發人員提供了更增強大的開發平臺和語言,並部分解決了傳統Office開發中的諸多問題(難於更新、可擴展性差、難以維護、安全性低等),開發人員可使用熟悉的技術來構建更加靈活的、強大的、跨平臺的企業級解決方案。api
下圖是個人機器上VS2013的建立項目:安全
主要採用C#語言開發,功能強大,感興趣的同窗能夠去google更多相關知識。app
個人需求是要建立可兼容兩大辦公軟件平臺的插件,很顯然這種技術在WPS下不大可能支持,並且對於XP系統的用戶,咱們不可能讓用戶再去安裝一個幾百M的.net框架,畢竟國內使用XP的量還比較大。所以這個方案不屬於咱們的要求,繼續尋找中。。。框架
這是VS2010的項目建立截圖:函數
在擴展插件項目下,有兩種類型的插件能夠建立。ui
1) Visual Studio Add-in 顧名思義,這個項目類型是用於建立 Visual Studio IDE插件的項目,不是咱們的菜。this
2) Shared Add-in 字面意思是共享插件 項目,這個正是咱們所須要的插件類型。google
Shared Add-in 的官方解釋:Conversely, a Shared add-in can be loaded only into Microsoft Office applications such as Microsoft Word, Microsoft Publisher, Microsoft Visio, and Microsoft Excel. 大意是,Shared add-in能夠被MS Office系列軟件調用。
進一步研究後得知,Shared Add-in 也就是com插件技術,在wps的最新版本上支持這種com插件,這樣就初步知足了咱們要的全平臺兼容插件。
2. 開始建立咱們的插件
建立項目
點擊OK後,會出來一個建立嚮導,第一步是能夠選擇你要使用的語言,若是用C#語言可能會致使引入.net的依賴,這不是咱們所但願,咱們但願建立的插件儘量是本地代碼,因此咱們選擇了使用C++/ATL。
選擇要支持的哪些軟件,可選項不少。這裏選擇軟件的意義,就是增長一些接口和註冊表項,這裏的選擇對WPS系列軟件的支持沒有影響,推薦這裏選一個就行了,後面咱們會使用手工自定義的方式來作。
填寫你的插件名字和描述。
若是你但願在應用程序啓動時通知你的插件,你就勾選那個選項。
最後確認你的選擇沒有問題後,點擊 Finish就能建立你的插件了。
3. 認識插件項目
下圖是建立項目後文件分佈,rpc文件夾是我本身建立的,請忽略。
咱們主要會對如下文件進行修改:
Addin.rgs文件 - 註冊腳本(Register Script, 簡 稱RGS),該文件會主要用於將插件註冊到相應註冊表中。在ATL中,COM服務程序的註冊是在工程編譯鏈接的最後階段,由ATL輔助完成的。在手工的COM編程中,服務程序的註冊是比較麻煩的工做。在ATL中,系統經過讀取在創建工程過程當中造成的註冊腳本文件來完成註冊工做。
Connect.h\cpp 文件 - 插件的事件通知接口均在該文件中定義。
其它文件幾乎不用動,都是一些自動生成的代碼。
4. 鏈接插件事件
Office系列軟件的版本不少,從Office2003 到 Office2013 都有,好消息是,com插件是向下兼容的,不一樣版本間的不一樣點在於高版本一搬會增長更多的事件通知,根據你須要的事件通知來選擇你要從哪一個版本的office系列開始支持。
我須要監控office打開某個文件的事件通知,選擇了從Office10版本開始進行支持,該事件能夠被所有版本兼容。
1) 添加com庫類型文件
安裝office07後,在安裝目錄下office10目錄中,其中com庫對應關係以下:
word - MSWORD.OLB
PPT - MSPPT.OLB
EXCEL – EXCEL.exe
其中EXCEL比較特殊,com庫存在於其exe之中,其它office軟件也有相應的com庫,這裏就不一一列出了。
把上述文件copy出來到你的目錄中。
2)引入com庫文件到項目
有了上述com類型庫文件後,咱們就能夠引入須要的com了。在Connect.h增長好下代碼:
#import "..\3rdparty\Office12\MSO.DLL" rename_namespace("Office2010") rename("RGB","RGB2"), rename("DocumentProperties","DocumentProperties2")
MSO.DLL是咱們要用到的office系列com庫的公共庫文件,必需要先引入該庫。
引入VBA,主要是爲了防止編譯不過去:
#import "..\3rdparty\VBA6\VBE6EXT.OLB"
一樣方法,引入實際com:
#import "..\3rdparty\Office12\MSWORD.OLB" rename_namespace("MSWord"), rename("ExitWindows","WordExitWindows"),rename("FindText","WordFindText"), named_guids
#import "..\3rdparty\Office12\excel.tlb" rename_namespace("MSExcel"), rename("DialogBox","ExcelDialogBox"), rename("RGB", "ignorethis"), rename("DialogBox", "ignorethis"), rename("ReplaceText", "EReplaceText"), rename("CopyFile","ECopyFile"), rename("FindText", "EFindText"), rename("NoPrompt", "ENoPrompt") exclude("IFont","IPicture")
#import "..\3rdparty\Office12\MSPPT.OLB" rename_namespace("MSPowerPoint"), rename("RGB", "ignorethis")
編譯代碼,會在項目目錄下生成衆多相關文件。tlh、tli文件:他們是vc++編譯器解析tlb文件生成的標準c++文件。由於odl和tlb並非C++標準的東東,有必要把它們翻譯成標準的 C++類型,使得C++開發者可使用。相信vb和j++也會把tlb翻譯成本身語言兼容的類型描述信息。
tlh至關於類型申明(頭文件)
tli至關於定義實現(CPP文件)編譯上面的com時,你的本機必需要安裝了相應的office版本,不然頗有可能會出錯。因爲咱們的代碼是在單獨的構建機上編譯,爲了不在純淨的構建機上安裝office10軟件,我作了些處理,直接使用解析後的文件。相似於以下代碼:
#include "..\3rdparty\Office12\include\msword.tlh"
#include "..\3rdparty\Office12\include\excel.tlh"
#include "..\3rdparty\Office12\include\msppt.tlh"wps相關:
#include "..\3rdparty\wps-office6\include\ksoapiv8.tlh"
#include "..\3rdparty\wps-office6\include\wpsapiv8.tlh"
#include "..\3rdparty\wps-office6\include\etapiv8.tlh"
#include "..\3rdparty\wps-office6\include\wppapiv8.tlh"tlh文件中,有相應tli文件的絕對位置,這個可能在其它機器上編譯不經過,所以須要手動修改成引用相對地址,根據編譯錯誤,很好修改。
3)鏈接com事件
經過上述步驟後,已經可使用com中的事件了。首先實現一個模板類:
typedef IDispEventSimpleImpl</*nID =*/ MSWord_ID, CConnect, &__uuidof(MSWord::ApplicationEvents2)> MSWordDispEventImpl;
MSWord_ID : 隨意定義一個ID便可,用於下面區分不一樣事件。
CConnect增長一個繼承類MSWordDispEventImpl,增長以下一個消息循環:
BEGIN_SINK_MAP(CConnect)
// msword events
SINK_ENTRY_INFO(/*nID =*/ MSWord_ID, __uuidof(MSWord::ApplicationEvents2), /*dispid =*/ 0x4, OnDocumentOpen, &DocumentOpenInfo)END_SINK_MAP()
其中:
dispid - 事件ID號,查詢MSDN官方文檔,或者tlh中會有相關ID
OnDocumentOpen - 事件響應函數,函數類型:void __stdcall OnDocumentOpen(LPDISPATCH ptr); 這裏的參數類型要根據這個事件實際的參數類型來建立
DocumentOpenInfo – 參數類型信息,_ATL_FUNC_INFO DocumentOpenInfo = {CC_STDCALL,VT_EMPTY,1,{VT_DISPATCH|VT_BYREF}};,具體參數信息,能夠查詢其它相關文檔
上面操做完成後,CConnect已經能夠收到Word打開文檔的事件通知,關於該事件的詳細觸發時間點,能夠查詢相關MSDN文檔。在OnDocumentOpen函數體中,你已經能夠寫下你想要的功能代碼了。
其它各類事件採用相同方式完成便可。
4)註冊插件
在AddIn.rgs文件中加入以下代碼,完成註冊過程:
HKLM
{
Software
{
Microsoft
{
Office
{
Word
{
Addins
{
ForceRemove 'YourAddin.Connect'
{
val Description = s 'Yourdesc'
val FriendlyName = s 'YourName'
val LoadBehavior = d '3'
}
}
}Excel
{
Addins
{
ForceRemove 'YourAddin.Connect'
{
val Description = s ''Yourdesc''
val FriendlyName = s 'YourName'
val LoadBehavior = d '3'
}
}
}
}
}
}}
有關rgs文件語法說明,須要參考其它相關文件。
5)調試插件
插件寫好,咱們得要調試插件。首先你運行的vs必須是要以「管理員」方式啓動的,把插件庫設置爲啓動項,在啓動參數裏寫入world.exe的絕對目錄,啓動調試後就能夠調試插件中的事件響應了。
6. 總結
本篇是是對Office的插件技術實現的描述,特色是實現了兼容wps的插件事件。優勢在於使用C++語言實現,生成的插件dll體積小,不依賴於.net ,方便安裝使用;缺點是c++語言,對ATL com的知識也有必定要求,開發難道較高。