【摘要】利用VBA對Word等辦公軟件進行二次開發(fā)的程序,可移植性差,只能在開發(fā)機器中運行,不便于開發(fā)成果的共享使用。將開發(fā)的程序,通過VBA直接導出,然后再導入到其它Word程序的VBA中,并解決好當中Thisdocument文件的代碼,可以實現(xiàn)程序的移植共享,但安全性差。利用VB將導出的代碼,以DLL文件的形式編譯封裝,并用批處理指令幫助用戶進行注冊,可以極好地解決程序的安全性與移植共享問題。
【關(guān)鍵詞】可移植性;VBA;二次開發(fā);封裝
引言
微軟的Office軟件在一些特殊的應(yīng)用中,有力所不及之處。利用VBA(Visual Basic For Application)對Office進行拓展性的二次開發(fā),是當前解決Office功能不足的常見方法。但此法最明顯的不足就是所開發(fā)的程序不具備可移植性,僅限于開發(fā)者所在的機器中能夠使用,其它需要同樣功能程序的用戶或機器,只能重復開發(fā),極大地影響了開發(fā)成果的共享。因此, VBA二次開發(fā)程序的可移植性問題,是亟待每個程序員研究、解決的問題。下文將以VAB在Word中的二次開發(fā)為例,對其可移植性問題的研究進行詳細闡述。
1.VBA二次開發(fā)的現(xiàn)狀
1.1 關(guān)于VBA
VBA微軟開發(fā)出來的宏語言。主要用來擴展Windows的應(yīng)用程式功能,特別是微軟的Office軟件。它完全繼承了VB(Visual Basic)的語言機制,是VB的一個子集,但又不同于VB,VB是一個可視化的程序開發(fā)環(huán)境,能夠獨立創(chuàng)建一個應(yīng)用程序并編譯運行,而VBA則要求有一個宿主應(yīng)用程序(如Word)才能開發(fā)、運行,而且不能用于創(chuàng)建獨立的應(yīng)用程序。
由于VBA必須寄生于宿主程序,離開宿主程序以后,程序便無法被解讀與運行。這是制約VBA二次開發(fā)程序可移植性的主要因素之一。因此,我們對VBA程序的可移植性研究,主要集中在二次開發(fā)程序在其宿主程序中的移植,即如何使開發(fā)出來的程序,能夠方便、快捷地移植到其它機器中,并在相應(yīng)的宿主軟件中正確運行,使得開發(fā)成果能夠發(fā)揮資源共享的作用。
1.2 VBA對Word的開發(fā)與存在問題
1.2.1 錄制宏
錄制宏是當前VBA對Word最簡單、常見的開發(fā)模式。這種方法優(yōu)點是簡單,易實現(xiàn),完全可視化操作,用戶不需編寫任何代碼,只要按照功能需求,一步步操作Word即可,VBA會根據(jù)用戶的操作,自動生成相應(yīng)的VBA程序代碼,并保存在指定的文件中。
但該法的缺點也很明顯,就是能擴展的功能非常有限。所謂錄制宏,實際就是利用已有的Word功能,將需要反復進行的一系列操作,組合為一步操作,并作以VBA程序的形式保存下來。用戶在打開該文檔的同時,啟動文檔中已保存的VBA程序,并根據(jù)用戶的指令運行、發(fā)揮作用。因此,這種開發(fā)完全依賴于Word中已有的可操作功能,只能在功能組合的基礎(chǔ)上進行。
1.2.2 VBA環(huán)境開發(fā)
利用VBA對Word進行二次開發(fā),更重要的方法是在Word中集成的VBA環(huán)境里,通過編寫程序?qū)崿F(xiàn)。VBA環(huán)境不僅為開發(fā)者準備了窗體、按鈕、組合框等常用的Windows圖形化控件,還繼承了VB中的模塊、類、對象等概念。開發(fā)者不僅可以擺脫Word已有功能的掣肘,還可以像在VB中一樣,自由編寫出功能強大的程序。甚至可以結(jié)合其它軟件,相比于“錄制宏”,更能擴展Word的功能。
如在日常辦公中,有時需將Word與Excel兩個軟件結(jié)合使用。那么,在VBA中,只要以下簡單的程序,即可實現(xiàn)Word對Excel的調(diào)用:
Set E_obj = CreateObject(“Excel.Applicattion”)
E_obj.visible=True
但無論是利用“錄制宏”還是利用VBA環(huán)境進行Word的二次開發(fā),其共同的缺點都是所開發(fā)出來的程序,必須與Word文件捆綁保存,無法獨立于Word程序獨立存在運行。因為在VBA程序中的許多對象、系統(tǒng)變量與系統(tǒng)常量都完全來源并被識別于Word,并且只有開發(fā)所在的機器與用戶能夠正常使用。例如若在VBA中有以下程序:
ActiveDocument.Paragraphs(3).Range.Characters(2).Font.Size = 14
程序中的ActiveDocument,Paragraphs,Range,Characters都屬于Word的專有對象,如果程序被獨立運行的話,便會報錯中斷運行,因為脫離Word環(huán)境以后,這些對象就無法再被識別,成為無效引用。
2.解決VBA程序可移植性的方法
2.1 代碼導入法
代碼導入法即是在Word中的VBA環(huán)境下,完成二次開發(fā)以后,將全部代碼按分類直接導出到一個目錄中,發(fā)布分享。需要同樣的功能程序的用戶,再通過VBA將全部代碼導入到自己的Word中。其操作流程示意圖如圖1所示:
圖1 操作流程示意圖
利用導入法解決VBA程序的可移植性問題,最大的優(yōu)點是簡單、快捷、易實現(xiàn),對于安全要求不高,面向有限的內(nèi)部用戶群體的二次開發(fā)程序,該法是可行的選擇。但必須解決的一個問題,就是“ThisDocument”文件中代碼的移植。在分析這個問題之前,我們必須先對VBA中的文件結(jié)構(gòu)有所了解。Word將VBA程序文件分為五類,分別存放在Microsoft Word對象、窗體、模塊、類模塊、引用五個目錄中,其結(jié)構(gòu)關(guān)系如圖2所示。
圖2 結(jié)構(gòu)關(guān)系
其中,“Microsoft Word對象”目錄下,通常只有一個文件,名為ThisDocument。存放的就是控制、操作當前Word文檔的相關(guān)程序代碼以及公開、通用類的聲明、函數(shù)與過程,如打開文檔時觸發(fā)的“Document_Open()”過程就保存在這里。如果ThisDocument文件中沒有任何VBA代碼的話,代碼導入法解決VBA程序的移植就能正確進行。但是,如果這個文件中增加了開發(fā)的代碼,就會發(fā)現(xiàn)新文檔導入代碼文件以后,程序失效,也即意味著移植失敗。
這是因為在導出代碼時,VBA是把ThisDocument文件中的代碼,作為一個類文件導出保存的,這個類文件的名字默認為ThisDocument.cls。但是當在新文檔中再次導入這個文件中的代碼時,VBA卻并沒有自動將代碼覆蓋到新文檔的“ThisDocument”文件中,而且將其作為一個獨立的類文件,以原來的類文件名保存在新文檔的“類模塊”目錄下。這就會導致新文檔無法運行該文件中的代碼,使程序移植失敗。
注意到這個問題以后,只要在導入This-Document.cls文件以后,打開其中的代碼并全部復制,然后粘貼到新文檔的ThisDocument代碼窗口中,再把所導入的ThisDocument.cls文件移除便可保證全部程序的成功移植。
2.2 將VBA程序封裝成DLL文件
2.2.1 關(guān)于DLL與VBA代碼封裝
DLL即動態(tài)鏈接庫(Dynamic Link Library),是由可被其它程序調(diào)用的函數(shù)集合組成的可執(zhí)行文件模塊。DLL不是應(yīng)用程序的組成部分,而是運行時鏈接到應(yīng)用程序中。將VBA程序封裝成DLL就是通過編譯軟件,將二次開發(fā)的VBA程序編譯成DLL文件,以方便地為其它用戶引用到各自的Word程序中運行使用。其基本的實現(xiàn)流程如圖3所示:
圖3 實現(xiàn)流程
具體的實現(xiàn)過程,不是本文闡述的重點,在此不再累述。通過DLL封裝進行程序移植,其優(yōu)點主要有以下幾點:
(1)一個DLL可以為多個Word文檔同時共享,而且當多個Word文件調(diào)用DLL中的同一個函數(shù)時,裝入的只是該函數(shù)的內(nèi)存地址,從而節(jié)省內(nèi)存和磁盤空間;
(2)便于開發(fā)者維護用戶程序,即使對動態(tài)鏈接庫進行修改也不會影響正在使用的用戶程序;
(3)VBA代碼通過編譯封裝成為DLL文件以后,是以二進制的形式保存在磁盤中的,這就可以保證代碼的安全。
(4)省去了運行時的編譯過程,可以提高代碼的運行速度。
因此,不考慮實現(xiàn)過程相對繁瑣的話,通過DLL封裝,是VBA程序移植的最佳方案。
2.2.2 消除宿主程序的對象模型對封裝DLL的影響
Word中的VB編輯器不能夠?qū)BA代碼編譯成DLL。因此,必須借助微軟的VB軟件。但直接將VBA代碼導入VB進行編譯,通常都會報錯導致編譯中斷。錯誤信息是運行時錯誤,對象的引用無效。這是因為所編譯的代碼中,含有Word程序的特有對象,在Word中運行這些代碼時,程序能夠識別這些對象。代碼移植到VB中以后,VB本身并沒有這些對象,因此,編譯時,就會認為是無效的引用而報錯。
因此,將VBA代碼移到VB中進行編譯工作之前,必須詳細了解Word的對象模型,并對VB中的代碼進行修改,使其能夠通過VB的語法檢查,又能為Word所運行,才能完成DLL的編譯封裝。
編譯前的代碼修改,主要從以下兩個方面檢查:
(1)修改VBA代碼中Word所特有的對象。如果所要編譯移植的代碼中,含有Document、Selection、Tables等等Word所特有類型的對象(如圖4所示),那么VB是無法識別的。必須給這些對象所在的過程或函數(shù),定義一個數(shù)據(jù)類型為Object的參數(shù),將這些對象通過這個參數(shù)進行傳遞調(diào)用。如在一個過程Removal_Test中要訪問對象Tables,即Removal_Test可定義為Removal_Test (Test_Tab As Object)。那么Tables對象就可以用以下程序進行調(diào)用:
Dim new_table as object
Set new_table=CreateObject(“,”Word.Application”) ‘
Removal_Test(new_table)
(2)修改Word的VBA專屬常量。Word的 VBA專屬常量以“wd”開頭,不同的宿主程序的VBA專屬常量具體有所區(qū)別,必須根據(jù)實際情況,進行代碼的修改編寫。比如代碼中有設(shè)置段落格式的命令“.ParagraphFormat.Alignment = wdAlignParagraphCenter”。其中的wdAlignParagraphCenter就屬于Word的專屬常量。如果在VB中直接編譯,就會出現(xiàn)“類型不匹配”或“該屬性值不是一個有效值”的錯誤。解決的方法是需要使用常量的地方,用“常量值”來替代“常量名”。.ParagraphFormat.Alignment = 1。常量值的獲取,可以查閱有關(guān)文檔資料,也可以在Word的VB編輯器中用Msgbox方法,讓Word自己將值返回。如Msgbox wdAlignParagraphCenter 。
2.2.3 相關(guān)類庫的引用
VB環(huán)境中,許多對象,依然需要相關(guān)的類庫文件來支持,才能支持識別其相關(guān)的屬性與方法。
因此,將程序編譯封裝前,還必須在VB環(huán)境中的【工程】菜單下,通過【引用】菜單項,調(diào)出“引用”對話框,然后將所需的類庫引用到VB中來,如圖4所示。
圖4
在Word中利用VBA進行的二次開發(fā)程序,必須引用的至少有兩個類庫:Microsoft Word 12.0 Object Library與Microsoft Office 12.0 Object Library。不同版本的Office,類庫的版本也相應(yīng)不同。如果在開發(fā)的過程中,還曾經(jīng)引用過其他類庫,在VB中編譯時也必須先將這些類庫引用進來。
3.DLL文件的移植
3.1 常見的DLL文件移植問題
封裝成為DLL文件(實驗名為Test_VBA.dll,下同)以后,當中的程序能否為其它Word用戶所運行使用,是決定VBA程序的移植是否成功的關(guān)鍵。通常在編譯工作所在的機器中,這個DLL文件的使用是沒有任何障礙的,但把這個DLL文件轉(zhuǎn)移到其它機器上以后,將其引用到Word中時,卻容易出現(xiàn)各樣的錯誤,程序無法運行,也即意味著程序移植的最后一步失敗。常見的錯誤類型主要有以下幾種:
(1)找不到工程或庫:
這是由于在Windows平臺中,DLL文件未被注冊,因此,無法被引用。
(2)引用的動態(tài)鏈接庫(DLL)丟失:
即使一個DLL文件的注冊信息已經(jīng)寫入系統(tǒng)注冊表,但是文件的存放路徑相對于注冊時的路徑發(fā)生了改變,系統(tǒng)就會認為DLL文件丟失而報錯。
(3)自動化(Automation)錯誤:
錯誤的原因是DLL文件注冊并被Word引用以后,在運行的過程中,文件的路徑再次發(fā)生改變。
3.2 解決DLL文件移植問題的對策
解決DLL文件移植過程中出現(xiàn)的各類問題,可以通過批處理程序完成。程序首先將DLL文件復制到system目錄下,然后運行Regsvr32命令進行注冊。將批處理指令保存成為批處理文件以后,隨同DLL文件一起打包發(fā)布。用戶在獲得文件包以后,運行批處理文件,由批處理文件自動完成DLL文件的復制與注冊,完成后,用戶在Word中進行DLL文件的引用運行即可。批處理指令如下:
@echo off
if exist Test_VBA.dll goto A
if not exist Test_VBA.dll goto B
:A
copy Test_VBA.dll %windir%\system32
regsvr32 %windir%\system32\Test_VBA.dll /s
echo 文件注冊成功,請打開Word并在VBA環(huán)境中引用運行
pause
exit
:B
echo DLL文件丟失,請重新下載
pause
exit
對于已注冊的DLL文件的引用,比較穩(wěn)定且高效的方法,是通過VBA中的CreateObject方法實現(xiàn)引用。關(guān)鍵代碼如下:
Dim New_obj As Object ‘定義一個新對象
Set New_obj = CreateObject(“Test_VBA.Ulogin”) ‘ 將定義的對象實例化
……
Set New_obj = Nothing ‘釋放對象
至此,即可解決VBA二次開發(fā)程序的移植過程中的全部問題。我們可以將問題解決的方法與過程用圖6簡要表述。
圖6
4.結(jié)語
VBA使Word等一系列軟件的功能得到了更廣的拓展,但VBA本身能力的不足,使VBA的二次開發(fā)程序不能直接移植,嚴重影響到Word用戶對開發(fā)成果的分享。直接將代碼導出共享,并在導入使用時,妥當解決好ThisDocument文件中的代碼,是可行的方法之一,但程序毫無安全性可言。而將VBA代碼導出以后,再借助VB作可移植性的代碼修改,然后封裝成為DLL動態(tài)鏈接庫文件,并利用批處理命令對DLL文件注冊,再在Word中進行引用。
這種方法不僅能保證程序代碼安全,而且可以提高運行效率,并且在開發(fā)者的程序維護與用戶的繼續(xù)使用之間,不存在任何沖突,是當前解決VBA程序可移植性問題中,最佳的選擇。
參考文獻
[1]周靜,袁方等. 基于VSTO的Office二次開發(fā)[J].福建電腦,2011(9):22-23.
[2]王燕.VBA在辦公中的編程應(yīng)用[J].福建電腦,2013(10): 177-179.
[3]江云林.DLL巧注冊 系統(tǒng)更隨心[J].電腦愛好者,2013(3): 59-59.
[4]張發(fā)凌.批處理命令在Windows操作中的典型應(yīng)用[M].北京:人民郵電出版社,2008,2.
[5]Word對象模型概述[EB/OL].http://msdn.microsoft.com/zh-cn/library/d2tx7z6d(v=vs.80).aspx.
[6]黃聰會,陳靖等.軟件移植理論與技術(shù)研究[J].計算機應(yīng)用研究,2012(6):2024-2027.
[7][英]Lan Sommerville.軟件工程(第九版)[M] .北京:機械工業(yè)出版社,2011,5.
[8]李殿勛.淺談Windows環(huán)境下對象的鏈接與嵌入[J].中國科技博覽,2011(37):157-157.
[9]何振林,胡綠慧.MS Office與VBA高級應(yīng)用案例教程[M].北京:水利水電出版社,2010,09.
[10]劉春裕.基于VBA開發(fā)技術(shù)的接口測試技術(shù)研究[J].計算機技術(shù)與發(fā)展,2014(1):69-72.
[11]梁潔.利用VB實現(xiàn)OFFICE對象的訪問控制[J]成都醫(yī)學院學報,2007(1):48-51.
[12]梁德強,王省書等.基于ActiveX控件的視頻跟蹤系統(tǒng)軟件設(shè)計[J].微計算機信息,2010(19):201-202.
[13]祝晉.office的二次開發(fā)及在工業(yè)設(shè)計中的應(yīng)用[J].自動化與儀器儀表,2012(1):86-87.
[14]陳永松.Office操作題自動閱卷組件設(shè)計[J].實驗室研究與探索,2013(8):64-67.
[15]周維京.VBA封裝技術(shù)分析[J].電腦與電信,2008(4): 34-35.
[16]羅雨滋.在應(yīng)用程序中使用Office對象的方法[J].遼寧師專學報(自然科學版),2007(1):37-38.
作者簡介:李圓(1984—),女,廣東河源人,惠州商貿(mào)旅游高級職業(yè)技術(shù)學校講師,研究方向:計算機應(yīng)用與程序設(shè)計。