- Office VBA開發(fā)經(jīng)典:中級(jí)進(jìn)階卷
- 劉永富 劉行
- 4772字
- 2019-11-22 18:29:04
2.1 Shell函數(shù)
Shell用于執(zhí)行一個(gè)可執(zhí)行文件,返回一個(gè)Variant (Double)類型的結(jié)果,如果成功,代表這個(gè)程序的任務(wù)ID,若不成功,則會(huì)返回0。
Shell的語法格式是:
Shell(PathName,WindowStyle)
具體的參數(shù)說明:
PathName:是一個(gè)字符串,必須包含一個(gè)可執(zhí)行文件的名稱,后面還可以加上一些命令參數(shù),各個(gè)參數(shù)之間用空格隔開。
WindowStyle:枚舉常量,用來規(guī)定窗口樣式,如表2-1所示。
表2-1 Shell命令的窗口樣式常量

需要注意的是,在VBA或VB6編程中,Shell函數(shù)是內(nèi)置函數(shù),不需要添加任何外部引用,也不需要?jiǎng)?chuàng)建對(duì)象。
Shell函數(shù)的功能可以這樣理解,就是代替手工去打開某個(gè)應(yīng)用程序或文檔。
實(shí)際上,屏幕上面的窗口的根源絕大多數(shù)都來源于一個(gè)可執(zhí)行文件(擴(kuò)展名為.exe)。例如微軟的Word,其窗口根本路徑是Office安裝路徑下的WINWORD.EXE文件,當(dāng)打開一個(gè)文本文件時(shí),其根源文件是C:\Windows\System32\notepad.exe。那么Windows系統(tǒng)中的可執(zhí)行文件,一部分是系統(tǒng)自帶的,例如記事本、計(jì)算器、注冊表編輯器等,它們都處于System32文件夾下,是系統(tǒng)內(nèi)置可執(zhí)行文件。而另一部分如QQ、Excel這些應(yīng)用軟件則是后期安裝上的,根源文件往往位于用戶指定的路徑。
為了更好地理解Shell函數(shù)的原理,下面使用計(jì)算機(jī)的“運(yùn)行”窗口完成一些動(dòng)作。按下快捷鍵【W(wǎng)indows + R】,在屏幕左下角彈出“運(yùn)行”窗口,如圖2-1所示。

圖2-1 運(yùn)行窗口
在路徑框中輸入:C:\windows\System32\notepad.exe C:\temp\new.txt,單擊“確定”按鈕,就可以看到桌面自動(dòng)彈出記事本,并能看到其中的內(nèi)容。
我們仔細(xì)分析路徑的構(gòu)成,C:\windows\System32\notepad.exe其實(shí)就是系統(tǒng)文件記事本的根源文件,空格后面的路徑是命令參數(shù)部分,也就是告訴記事本程序,要打開這個(gè)文件,而不是其他的文本文件。
針對(duì)以上實(shí)例,可以使用下面的Shell函數(shù)來達(dá)到同樣目的。只需要把“運(yùn)行”中的內(nèi)容傳遞給Shell函數(shù)即可。

上述代碼中的vbMaximizedFocus表示打開的記事本窗口取得焦點(diǎn),并且最大化記事本窗口,如果改為vbHide,則打開的新窗口在屏幕上看不見,在某些場合下這樣是很危險(xiǎn)的。
對(duì)于上述過程,我們要認(rèn)識(shí)到以下幾點(diǎn)。
Shell函數(shù)的參數(shù)由可執(zhí)行文件的路徑以及命令參數(shù)路徑構(gòu)成。
可執(zhí)行文件的路徑,根據(jù)需要可以盡可能縮短簡化。
命令參數(shù)不是必需的,如果不帶命令參數(shù),則默認(rèn)只打開該應(yīng)用程序。
由于上例中的notepad.exe處于系統(tǒng)文件夾中,系統(tǒng)的環(huán)境變量中一定有C:\windows\System32這個(gè)路徑。因此,Shell函數(shù)還可以省略所在路徑,以及后面的擴(kuò)展名,從而簡化為:Shell "notepad C:\temp\new.txt", vbMaximizedFocus。
如果不打開具體的文件,只打開記事本,則不需帶命令參數(shù)。進(jìn)一步簡化為:
Shell "notepad"
根據(jù)以上心得,我們嘗試用下面的代碼打開一個(gè)Word文檔。
Shell "WinWord C:\temp\公務(wù)員.docx"
代碼中的WinWord是Offi ce安裝文件夾中Word程序的主文件,如圖2-2所示。

圖2-2 Word的執(zhí)行文件
2.1.1 System32中常用的可執(zhí)行文件
Windows系統(tǒng)中,很多實(shí)用的工具都處于System32這個(gè)文件夾下,因此可以利用Shell函數(shù)調(diào)用這些可執(zhí)行文件,完成一些特定的任務(wù)。比較常用的可執(zhí)行文件如表2-2所示。
表2-2 常用的可執(zhí)行文件

①這類文件有可能不在System32文件夾中。
2.1.2 執(zhí)行DOS命令
DOS命令的可執(zhí)行文件是cmd.exe,用Shell函數(shù)調(diào)用DOS命令后,會(huì)彈出黑屏窗口,當(dāng)DOS命令執(zhí)行完畢后,有可能自動(dòng)退出黑屏,也有可能停留,這取決于cmd的參數(shù)。/c表示自動(dòng)退出,/k表示停留。
下面的代碼,首先切換磁盤分區(qū)到D盤,其次切換當(dāng)前目錄到Download文件夾,最后用Shell函數(shù)調(diào)用DOS窗口,用dir命令列舉出該文件夾中的內(nèi)容。

由于cmd的參數(shù)使用了/k,因此,當(dāng)dir命令執(zhí)行完后,黑屏仍然停留在屏幕上,如圖2-3所示。

圖2-3 Shell調(diào)用DOS命令
DOS命令眾多,此處僅舉幾個(gè)典型的例子。
下面的代碼用DOS命令自動(dòng)把D:盤根目錄下的VMware10.7z壓縮包(該文件大約470MB)復(fù)制到D:\Download文件夾中,并試圖把復(fù)制后的文件重命名。

運(yùn)行上述過程,當(dāng)運(yùn)行到第二行時(shí),彈出如下的運(yùn)行時(shí)錯(cuò)誤,如圖2-4所示。
結(jié)束程序后,可以看到Download文件夾下確實(shí)多了一個(gè)文件。也就是說,復(fù)制操作成功地執(zhí)行了,但是重命名失敗。
導(dǎo)致操作失敗的原因是,Shell函數(shù)是異步執(zhí)行的,也就是說,復(fù)制文件的宿主程序是cmd文件,并不是VBA代碼。因此VBA并不能監(jiān)測到cmd那邊復(fù)制操作是否已經(jīng)完成。換句話說,在VBA中執(zhí)行一句Shell語句幾乎不花時(shí)間,而實(shí)際上的復(fù)制動(dòng)作可能持續(xù)好幾秒或好幾分鐘。由于VBA監(jiān)測不到復(fù)制的狀態(tài),就立即運(yùn)行后續(xù)的代碼,進(jìn)行重命名,出現(xiàn)運(yùn)行時(shí)錯(cuò)誤也就可以理解了。

圖2-4 不可移動(dòng)或重命名
2.1.3 認(rèn)識(shí)Shell函數(shù)的異步
為了提高Shell函數(shù)的健壯性,利用Shell函數(shù)的返回值,再配合一些API函數(shù),可以讓程序在執(zhí)行Shell函數(shù)的時(shí)候智能等待。也就是說,只有Shell函數(shù)中的動(dòng)作已完成時(shí),才往下繼續(xù)執(zhí)行代碼,否則在空循環(huán)中等待。
在標(biāo)準(zhǔn)模塊中寫入如下代碼。

代碼分析:當(dāng)文件正在復(fù)制時(shí),代碼中的ExitCode和常量STILL_ALIVE是相等的,都是非零值,此時(shí)跳不出Do循環(huán)體。
當(dāng)復(fù)制動(dòng)作完成時(shí),ExitCode變?yōu)?,Do循環(huán)的條件不再成立,就跳出并執(zhí)行后續(xù)重命名的代碼。
運(yùn)行上述CopyFile過程,即可進(jìn)行先復(fù)制文件,然后重命名復(fù)制的文件,如圖2-5所示。

圖2-5 處理Shell的異步
因此,只要Shell函數(shù)中的新窗口不關(guān)閉,就不會(huì)跳出Do循環(huán),讀者可以把上述代碼中的Pid = Shell("cmd.exe /c copy D:\VMware10.7z C:\lib\", vbNormalFocus),更改為Pid =Shell("notepad.exe", vbNormalFocus),再試一次,可以發(fā)現(xiàn),彈出的記事本窗口如果不手工關(guān)閉,程序就阻滯在Do循環(huán)體中。
2.1.4 處理Shell函數(shù)中的空格
計(jì)算機(jī)的文件夾或文件名中經(jīng)常包含空格,如果把包含空格的路徑作為參數(shù)傳遞給Shell函數(shù),該函數(shù)會(huì)以空格作為分隔符,把一個(gè)路徑理解為多個(gè)參數(shù)的連接。
例如,試圖用Word 2013打開C:\temp文件夾下的“公務(wù)員.docx”,如果寫成如下形式。
Shell "C:\Program Files\Microsoft Office\Office15\WINWORD.EXE C:\temp\公 務(wù) 員.docx", vbNormalFocus

圖2-6 文件或路徑中包含空格
執(zhí)行時(shí),并不能打開名稱或路徑帶空格的文件,而是彈出如圖2-6所示錯(cuò)誤對(duì)話框。
這是因?yàn)椴粌HWord的路徑包含空格,而且計(jì)劃打開的文檔名稱也有空格,Shell函數(shù)無法解釋這些參數(shù)的含義,因此不能打開。
如果為Shell函數(shù)中各路徑事先用雙引號(hào)包起來,就不會(huì)有上述麻煩。
自定義函數(shù)AddQuote的作用是給路徑兩側(cè)加上雙引號(hào),并且添補(bǔ)一個(gè)空格,以防止連在一起。

運(yùn)行上面的“處理空格”過程,該文檔可以正常地在Word中打開。
2.1.5 自動(dòng)打開控制面板
控制面板的主文件是位于System32文件夾下的control.exe,因此只需要執(zhí)行:
Shell "control.exe", vbNormalFocus
就可以打開控制面板的主頁,如圖2-7所示。

圖2-7 自動(dòng)打開控制面板
如果要直接打開控制面板中特定的一項(xiàng),需要添加命令參數(shù)。
Shell "control.exe appwiz.cpl", vbNormalFocus
上述代碼表示直接打開控制面板中的“卸載程序”,命令參數(shù)appwiz.cpl是Application Wizard的縮寫,意思是程序向?qū)В鐖D2-8所示。
因此,只需要把Shell函數(shù)命令參數(shù)中的cpl文件更改一下,就可以打開控制面板中的其他各項(xiàng)。常用的有如下這些。
卸載程序:Shell "Control.exe " & "appwiz.cpl", vbMaximizedFocus
顯示屬性:Shell "Control.exe " & "desk.cpl", vbMaximizedFocus
瀏覽器屬性:Shell "Control.exe " & "inetcpl.cpl", vbMaximizedFocus

圖2-8 控制面板中的項(xiàng)目
區(qū)域和語言:Shell "Control.exe " & "intl.cpl", vbMaximizedFocus
聲音和音頻:Shell "Control.exe " & "mmsys.cpl", vbMaximizedFocus
網(wǎng)絡(luò)連接:Shell "Control.exe " & "ncpa.cpl", vbMaximizedFocus
用戶賬戶:Shell "Control.exe " & "nusrmgr.cpl", vbMaximizedFocus
電源選項(xiàng):Shell "Control.exe " & "powercfg.cpl", vbMaximizedFocus
計(jì)算機(jī)屬性:Shell "Control.exe " & "sysdm.cpl", vbMaximizedFocus
日期和時(shí)間:Shell "Control.exe " & "timedate.cpl", vbMaximizedFocus
安全中心:Shell "Control.exe " & "wscui.cpl", vbMaximizedFocus
2.1.6 打開資源管理器
資源管理器是以樹狀結(jié)構(gòu)顯示計(jì)算機(jī)中的文件系統(tǒng)的窗口,在Windows XP系統(tǒng)中雙擊“我的電腦”,在Windows 7系統(tǒng)中雙擊“計(jì)算機(jī)”,或者按下快捷鍵【W(wǎng)indows + E】,都可以打開資源管理器。
資源管理器的主文件為explorer.exe。
在實(shí)際編程中,經(jīng)常用到自動(dòng)打開某個(gè)文件夾,或者自動(dòng)選中文件、文件夾的操作。如下面的代碼。
Shell "explorer.exe C:\temp\成績表.pdf", vbNormalFocus
上述代碼表示用系統(tǒng)默認(rèn)程序打開指定的PDF文件,這相當(dāng)于用鼠標(biāo)雙擊了計(jì)算機(jī)中的“成績表.pdf”文件,如果計(jì)算機(jī)中安裝的是Adobe Acrobat,那么用該軟件打開PDF文件。對(duì)于其他擴(kuò)展名的文件也是如此,因此這個(gè)代碼實(shí)用價(jià)值很高。
Shell "explorer.exe C:\temp\", vbNormalFocus
上述代碼表示打開temp文件夾,相當(dāng)于用鼠標(biāo)雙擊了該文件夾,進(jìn)入該文件夾內(nèi)部。
針對(duì)以上兩句代碼,如果添加參數(shù)“/select,”,那么不是打開文件或文件夾,而是選中。
Shell "explorer.exe /select, C:\temp\成績表.pdf", vbNormalFocus
上述代碼表示顯示資源管理器,并自動(dòng)選中文件,如圖2-9所示。

圖2-9 在資源管理器中自動(dòng)選中文件
Shell "explorer.exe /select, C:\temp\", vbNormalFocus
上述代碼表示自動(dòng)選中temp文件夾,而不打開。
此外,利用explorer還可以自動(dòng)打開指定url的網(wǎng)頁。
Shell "explorer.exe http://vba.mahoupao.net/forum.php", vbNormalFocus
上述代碼會(huì)用計(jì)算機(jī)默認(rèn)的網(wǎng)頁瀏覽器打開一個(gè)論壇。
2.1.7 注冊ocx文件和dll文件
ocx文件是指對(duì)象類別擴(kuò)充組件。計(jì)算機(jī)中擴(kuò)展名為.ocx的文件,不能直接雙擊執(zhí)行,一般要把ocx控件插入到窗體中使用。例如在VBA的UserForm中,可以插入CommonDialog、DataGrid這些ActiveX控件,如圖2-10所示。

圖2-10 用戶窗體中使用ocx控件
這些ocx文件大多數(shù)是微軟公司開發(fā)的性能優(yōu)良的控件,插入到窗體后,可以讓編程更加簡單,界面更加專業(yè)、美觀。
此外,用戶根據(jù)需要也可以自己制作專用的ocx控件。但是,ocx的移植,也就是說從一臺(tái)計(jì)算機(jī)把ocx控件復(fù)制到另一臺(tái)計(jì)算機(jī),是不能直接使用的,必須在目標(biāo)計(jì)算機(jī)上注冊。因?yàn)槲醋缘膐cx控件不會(huì)顯示在“附加控件”對(duì)話框中,也就無法裝入窗體。所謂注冊,就是為該控件分配一個(gè)GUID,并保存于注冊表中。反注冊,就是從注冊表中移除該控件的有關(guān)信息,使其無法在編程環(huán)境中訪問。
注冊和反注冊文件,可以用Shell函數(shù)調(diào)用System32文件夾下的regsvr32.exe文件實(shí)現(xiàn)。
注冊ocx文件的語法格式如下。
Shell "regsvr32.exe ocx文件的路徑"
下面嘗試注冊一款筆者開發(fā)的TreeviewExplorer.ocx控件,并在VBA中運(yùn)行。
Shell "regsvr32.exe E:\TreeviewExplorer\TreeviewExplorer.ocx"
執(zhí)行上述過程會(huì)彈出注冊成功的提示框,如圖2-11所示。
如果要屏蔽注冊成功的對(duì)話框,可以在regsvr32.exe后面添加/s參數(shù),也就是改為如下形式。

圖2-11 成功注冊ocx控件
Shell "regsvr32.exe /s E:\TreeviewExplorer\ TreeviewExplorer.ocx"
那么,注冊成功后,到底引起了哪些變化呢?
運(yùn)行Shell "regedt32.exe" ,vbNormalFocus,自動(dòng)打開注冊表編輯器,在查找對(duì)話框中輸入關(guān)鍵字,可以快速找到該控件的注冊信息,如圖2-12所示。

圖2-12 ocx控件的信息寫入注冊表
可以看出注冊信息位于:HKEY_CLASSES_ROOT\TreeviewExplorer.UC。
注冊成功的控件,更重要的變化在于能夠在各種窗體中使用該控件。下面是VBA的用戶窗體中的“附加控件”對(duì)話框,在該項(xiàng)前面勾選,即可把自定義控件添加到“控件工具箱”中,從而可以插入窗體中,如圖2-13所示。

圖2-13 使用自定義控件
控件的反注冊也很簡單,只需要在上述注冊的代碼中插入一個(gè)/u參數(shù),就是反注冊。
Shell "regsvr32.exe /u E:\TreeviewExplorer\TreeviewExplorer.ocx"
如果不彈出提示對(duì)話框,更改為如下代碼。
Shell "regsvr32.exe /s /u E:\TreeviewExplorer\TreeviewExplorer.ocx"
控件被反注冊以后,注冊表中會(huì)刪除該控件的信息,在“附加控件”對(duì)話框中也找不到該控件。
dll文件,即動(dòng)態(tài)鏈接庫文件(Dynamic Link Library),也可以稱為類庫,與ocx文件一樣,不能直接運(yùn)行。dll文件中主要封裝了一些函數(shù)和代碼。Office的COM加載項(xiàng)就是一種擴(kuò)展名為.dll的文件。
在VBA編程中,可以向VBA工程的引用中添加dll文件,從而使用dll文件中的功能和函數(shù)。
dll文件的注冊、反注冊方法和ocx的代碼是一模一樣的,只需要把ocx控件的路徑更改為dll文件的路徑即可。
OfficeDll是筆者開發(fā)的一款功能豐富的動(dòng)態(tài)鏈接庫,把該文件復(fù)制到目標(biāo)計(jì)算機(jī)后,運(yùn)行下面的代碼進(jìn)行注冊。
Shell "regsvr32.exe E:\OfficeDll\OfficeDll.dll"
注冊成功后,單擊VBA編輯器的菜單【工具/引用】,在“可使用的引用”列表中可以看到該動(dòng)態(tài)鏈接庫,如圖2-14所示。
添加引用成功后,編寫代碼,可以看到該類庫的成員列表,如圖2-15所示。
注意,如果同一臺(tái)計(jì)算機(jī)中存在多個(gè)同名ocx或dll文件,以最近注冊的為準(zhǔn)。
注冊和反注冊的方法總結(jié)如下。
Shell "regsvr32.exe文件"表示注冊一個(gè)文件,并彈出提示對(duì)話框。
Shell "regsvr32.exe /s文件"表示注冊一個(gè)文件,不彈出提示對(duì)話框。
Shell "regsvr32.exe /u文件"表示取消注冊一個(gè)文件,并彈出提示對(duì)話框。
Shell "regsvr32.exe /s /u文件"表示取消注冊一個(gè)文件,不彈出提示對(duì)話框。

圖2-14 動(dòng)態(tài)鏈接庫的注冊和使用

圖2-15 VBA中使用動(dòng)態(tài)鏈接庫
關(guān)于ocx控件和動(dòng)態(tài)鏈接庫的開發(fā)和應(yīng)用,本書暫不討論。
2.1.8 結(jié)束進(jìn)程
在Windows系統(tǒng)中按下快捷鍵【Ctrl+Shift+Esc】可以彈出Windows任務(wù)管理器,通過Windows任務(wù)管理器可以強(qiáng)行結(jié)束一個(gè)進(jìn)程,如圖2-16所示。

圖2-16 Windows任務(wù)管理器
假定現(xiàn)在屏幕上打開了計(jì)算器,進(jìn)程列表中一定有calc.exe進(jìn)程,然后在VBA中運(yùn)行如下代碼。
Shell "taskkill /f /im calc.exe", vbHide
可以看到計(jì)算器自動(dòng)被終止。taskkill.exe也是System32文件夾下的一個(gè)可執(zhí)行文件,專門用來終止進(jìn)程。
2.1.9 自動(dòng)關(guān)機(jī)
shutdown.exe是一個(gè)用于關(guān)機(jī)的系統(tǒng)文件,用Shell函數(shù)調(diào)用shutdown可以實(shí)現(xiàn)自動(dòng)關(guān)機(jī)、取消關(guān)機(jī)、自動(dòng)重啟等操作。

運(yùn)行上述Test1或Test2,會(huì)彈出提示框,如圖2-17所示。
如果又不想關(guān)機(jī)或重啟,那么需要運(yùn)行Test3取消計(jì)劃。計(jì)劃被取消時(shí),屏幕右下角彈出提示,如圖2-18所示。

圖2-17 計(jì)劃關(guān)機(jī)

圖2-18 取消計(jì)劃
在日常辦公中,一臺(tái)計(jì)算機(jī)經(jīng)常會(huì)連續(xù)工作好幾天,此時(shí),可以用Excel VBA設(shè)置一個(gè)計(jì)劃,在未來某一天的某一時(shí)刻定時(shí)關(guān)機(jī)。
Application對(duì)象的OnTime方法可以在某一時(shí)刻準(zhǔn)時(shí)執(zhí)行某個(gè)過程,因此,運(yùn)行下面的MySchedule過程,計(jì)算機(jī)不會(huì)發(fā)生任何變化,但是到了指定的時(shí)刻,會(huì)準(zhǔn)時(shí)調(diào)用AutoShutdown過程,從而實(shí)現(xiàn)自動(dòng)關(guān)機(jī)。

注意 運(yùn)行MySchedule過程后,Excel要一直保持打開狀態(tài),如果退出Excel,計(jì)劃無效。
以上內(nèi)容的源代碼文件為“實(shí)例文檔06.xlsm”。
- Extending Jenkins
- Flutter開發(fā)實(shí)戰(zhàn)詳解
- 數(shù)字媒體應(yīng)用教程
- Android開發(fā)精要
- Linux C/C++服務(wù)器開發(fā)實(shí)踐
- Building a RESTful Web Service with Spring
- 數(shù)據(jù)庫系統(tǒng)原理及MySQL應(yīng)用教程
- Windows Presentation Foundation Development Cookbook
- 精通網(wǎng)絡(luò)視頻核心開發(fā)技術(shù)
- Hands-On Enterprise Automation with Python.
- Learning R for Geospatial Analysis
- Scala Reactive Programming
- Java Fundamentals
- Visual C#.NET Web應(yīng)用程序設(shè)計(jì)
- Everyday Data Structures