如果你喜歡驚喜的話,那麼隨IE 4.01及其以上版本安裝的Microsoft Shell Controls and Automation COM對象無疑就是一大驚喜。這個COM對象提供了一系列的功能強大的方法包括打開、浏覽文件夾,最小化、還原、級聯和平鋪系統中打開的窗口,啟動控制面板程序,顯示系統對話框等等功能。
1.安裝Shell Controls and Automation 對象
在Delphi中選Project Import Type Library命令,在對話框中選Import Microsoft Shell Controls And Automation類型庫(見下圖2.18),點Install後,在Delphi的ActiveX控件板上就多了TShellFolderItem,TShellLinkObject,TShellFolderVIEw,TShell,TSearchCommand等幾個組件。
圖2.18
其中TShell組件就是COM對象的核心,先讓我們來簡單的看看TShell組件都能干些什麼來小小的興奮一下。新建一個項目,在窗體上放置一個TShell組件,然後再放一個按鈕,在按鈕的OnClick事件中寫下下面代碼:
procedure TForm1.Button1Click(Sender: TObject);
begin
Shell1.FileRun;
end;
運行後,按下按鈕後就會顯示一個對話框,見下圖2.19:
圖2.19
很眼熟啊,這不就是前面我們費了半天勁使用那些丑陋的未公開的函數調用出來的系統運行對話框嗎,現在使用Shell組件,只用一行代碼就搞定了,真是很棒吧,還等什麼,就讓我們來看看TShell組件還提供了些什麼好東西吧。下面是TShell組件的定義:
TShell = class(TOleServer)
private
FIntf: IShellDispatch;
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
FProps: TShellPropertIEs;
function GetServerProperties: TShellPropertIEs;
{$ENDIF}
function GetDefaultInterface: IShellDispatch;
protected
procedure InitServerData; override;
function Get_Application: IDispatch;
function Get_Parent: IDispatch;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Connect; override;
procedure ConnectTo(svrIntf: IShellDispatch);
procedure Disconnect; override;
function NameSpace(vDir: OleVariant): Folder;
function BrowseForFolder(Hwnd: Integer; const Title: WideString; Options: Integer): Folder; overload;
function BrowseForFolder(Hwnd: Integer; const Title: WideString; Options: Integer;
RootFolder: OleVariant): Folder; overload;
function Windows: IDispatch;
procedure Open(vDir: OleVariant);
procedure Explore(vDir: OleVariant);
procedure MinimizeAll;
procedure UndoMinimizeALL;
procedure FileRun;
procedure CascadeWindows;
procedure TileVertically;
procedure TileHorizontally;
procedure ShutdownWindows;
procedure Suspend;
procedure EjectPC;
procedure SetTime;
procedure TrayPropertIEs;
procedure Help;
procedure FindFiles;
procedure FindComputer;
procedure RefreshMenu;
procedure ControlPanelItem(const szDir: WideString);
property DefaultInterface: IShellDispatch read GetDefaultInterface;
property Application: IDispatch read Get_Application;
property Parent: IDispatch read Get_Parent;
published
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
property Server: TShellProperties read GetServerPropertIEs;
{$ENDIF}
end;
其中ControlPanelItem方法可以根據輸入的控制面板程序文件名調用相應的程序,用法如下:
//調用Internet 選項設定面板
Shell1.ControlPanelItem('INETCPL.cpl');
FindFiles和FindComputer方法調用的結果就是顯示查找文件和查找電腦對話框,而Help方法是調出系統幫助,其他方法顧名思義比如MinimizeAll就是最小化全部打開的窗口,UndoMinimizeAll顯然就是還原全部窗口的狀態了,CascadeWindows是級聯式排布窗口,而TileVertically和TileHorizontally則是垂直和水平平鋪窗口,不過我運行的效果不怎麼樣,感覺桌面上的窗口一片混亂,不知道是為什麼?調用ShutdownWindows方法後會顯示關機對話框,而運行Suspend方法後將會把系統掛起,EjectPC命令一般電腦並不支持,這裡就不討論了,SetTime命令則會調出時間設置對話框,而TrayPropertIEs則會調出下圖2.20所示意的任務欄屬性對話框(這可是用未公開的對話框函數無法調出的系統對話框啊)。
圖2.20
接下來的方法就稍微復雜些了,其中Open方法可以用來打開文件夾或文件,用法如下:
Shell1.Open('c:FRUNLOG.TXT');//或 Shell1.Open('c:');
Expoler方法主要用來調用資源管理器來浏覽文件夾,用法如下:
Shell1.Explore('c:Windows');
Windows方法則會創建並返回一個ShellWindow對象,它代表屬於外殼的全部打開的窗口。其實我發現它代表的只是Internet Explorer,下面代碼可以返回系統中已經打開的IE窗口數目:
implementation
uses shdocvw;
...
procedure TForm1.Button1Click(Sender: TObject);
var
ShWin:IShellWindows;
begin
ShWin:=Shell1.windows as IShellWindows;
ShowMessage(IntToStr(ShWin.Get_Count));
end;
進一步的我們甚至可以通過這個接口來完全控制系統中的Internet Explorer,下面代碼獲得對系統中第一個IE的引用,並返回缺省的主頁:
procedure TForm1.Button1Click(Sender: TObject);
var
ShWin:IShellWindows;
Wb:IWebBrowser2;
begin
ShWin:=Shell1.windows as IShellWindows;
Wb:=ShWin.Item(0) as IWebBrowser2;
Wb.GoHome;
end;
BrowseForFolder用來顯示前面外殼對話框中提到的浏覽文件夾對話框,其中Hwnd是對話框父窗口的句柄,這個值可以為0。Title是用來設定浏覽對話框的標題。Options則可以是0或前文中提到的BIF_xxxx的常數的組合。RootFolder可任選,可以設置為特定的文件夾的路徑或特殊文件夾常數值從ssfDESKTOP到ssfPROFILE。用法示意如下:
Shell1.BrowseForFolder(0,'demo',0);
必須指出的是既然外殼COM對象名為Shell Controls and Automation,它自然也就支持自動化控制,下面就是通過自動化調用它的FileRun方法的例子:
procedure TForm1.Button2Click(Sender: TObject);
var
v:Variant;
begin
v:=CreateOleObject('Shell.Application');
v.filerun;
end;
此外,它還支持使用腳本語言如JScript和VBScript進行控制,因此又被稱為可腳本化的對象,不過既然本書是關於Delphi的,腳本語言已經超出了本書的范圍,這裡就不詳細介紹了,感興趣的朋友可以自己查閱相關資料。
2.Folder對象
前面提到了TShell組件的全部方法,唯獨剩下了NameSpace函數沒有介紹,接下來我們就介紹這個可以用來創建Folder對象的方法,它的用法很簡單,只要給定一個路徑字符串或同特殊文件夾相關的ssfxxx常數就可以了,代碼示意如下:
procedure TForm1.Button2Click(Sender: TObject);
var
F:Folder;
begin
F:=Shell1.NameSpace('c:temp');
end;
那麼獲得的Folder對象有什麼用呢?Folder對象實際上就代表著一個外殼文件夾對象,我們可以使用Folder對象暴露的方法來獲得文件夾的信息,創建子文件夾,移動或復制文件對象到文件夾中。比如下面的代碼就實現了移動C:Scandisk.Log文件到C:temp目錄下:
procedure TForm1.Button2Click(Sender: TObject);
var
F:Folder;
begin
F:=Shell1.NameSpace('c:temp') as folder ;
F.MoveHere('c:SCANDISK.LOG',0);
end;
Folder對象同資源浏覽器的文件夾視圖是密切相關的,Folder的GetDetailsOf 方法可以返回相應視圖的欄目信息。通常來說Column 0 是名字,column 1是文件大小,接著是文件類型和上次修改時間。由於它是同視圖相關的,因此對於特殊的文件夾返回的信息是不同的,比如回收站的第二欄就是文件的原始位置。下面代碼演示了如果獲得相關信息:
var
sFolder:Folder;
sItem:FolderItem;
begin
sFolder:=Shell1.NameSpace('c:temp');
//獲得第一個外殼對象的名字
Edit1.Text:=sFolder.GetDetailsOf(sFolder.Items.Item(0),0);
end;
Folder對象同時還在Items屬性中返回它所包含的外殼對象的集合,大多數情況下這些外殼對象是文件。每個Folder中的外殼對象對應於一個FolderItem對象,它提供了很多屬性象Path, Size, ModifyDate 和Type等來獲得外殼對象的有用信息以及一堆方法來檢驗外殼對象是一個聯接、標准文件、還是目錄或虛擬文件夾。
下面的例子演示了如何獲得外殼對象的路徑,當用戶點下按鈕會顯示一個文件夾浏覽對話框,用戶選擇一個文件夾後,文件夾中第一個外殼對象的路徑會顯示在文本框中。代碼如下:
procedure TForm1.Button1Click(Sender: TObject);
var
sFolder:Folder;
sItem:FolderItem;
begin
sFolder:=Shell1.BrowseForFolder(Self.Handle,'選擇目錄',0,ssfDRIVES);
sItem:=sFolder.Items.Item(0);
Edit1.Text:=sItem.Path;
end;
還有一個很有用的特性就是可以使用對象的方法來執行外殼對象的上下文相關的菜單命令,或者通過FolderItemVerbs對象獲得上下文相關的菜單信息。調用上下文菜單命令非常簡單,只需要調用命令的菜單項字符串,然後調用FolderItem的InvokeVerb方法即可
var
Form1: TForm1;
sFolder:Folder;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
I:integer;
Begin
//獲得外殼對象的上下文菜單命令字符串
sFolder:=Shell1.NameSpace('c:temp');
for I:=0 to sFolder.Items.item(0).verbs.Count-1 do
Listbox1.Items.Add(sFolder.Items.Item(0).verbs.Item(i).Name);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
//執行選中的菜單命令
sFolder.Items.Item(0).InvokeVerb(ListBox1.Items.Strings[ListBox1.ItemIndex]);
end;
運行結果見下圖2.21所示:
圖2.21
注意,菜單命令中通常有”&”的快捷按鍵符號,這個符號在調用InvokeVerb時是不能省略的,否則命令不會被調用。
3.Windows 2000的新特性
在Windows 2000上,Shell對象進一步擴展了對外殼的支持,支持IShellDispatch2和Folder2、FolderItems2等等接口。其中IShellDispatch2接口聲明如下:
IShellDispatch2 = interface(IShellDispatch)
['{A4C6892C-3BA9-11D2-9DEA-00C04FB16162}']
function IsRestricted(const Group: WideString; const Restriction: WideString):
Integer; safecall;
procedure ShellExecute(const File_: WideString; vArgs: OleVariant; vDir: OleVariant;
vOperation: OleVariant; vShow: OleVariant); safecall;
procedure FindPrinter(const Name: WideString; const location: WideString;
const model: WideString); safecall;
function GetSystemInformation(const Name: WideString): OleVariant; safecall;
function ServiceStart(const ServiceName: WideString; Persistent: OleVariant):
OleVariant; safecall;
function ServiceStop(const ServiceName: WideString; Persistent: OleVariant):
OleVariant; safecall;
function IsServiceRunning(const ServiceName: WideString): OleVariant; safecall;
function CanStartStopService(const ServiceName: WideString): OleVariant; safecall;
function ShowBrowserBar(const bstrClsid: WideString; bShow: OleVariant):
OleVariant; safecall;
end;
下表2.10列出了所有新接口方法的說明:
表2.10
方法 功能
CanStartStopService 確定當前用戶是否有啟動和停止服務的權限。
FindPrinter 在目錄服務中查找一個打印機。
GetSystemInformation 獲得系統信息。
IsRestricted 當前還沒實現。
IsServiceRunning 確定指定名字的服務正在運行。
ServiceStart 根據服務名啟動服務。
ServiceStop 停止服務。
ShellExecute 執行命令。
ShowBrowserBar 顯示或隱藏浏覽器工具條。
①獲得接口
同前面只需要簡單地在窗體上放置TShell組件就可以調用IShellDispatch接口的方法不同,IShellDispatch2接口需要從CoShell對象獲得,下面代碼演示了如何獲得IShellDispatch2接口並調用ShellExecute方法打開C:下的一個文本文件:
implementation
//must include Shell controls and Automation type library unit
uses Shell32_tlb;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
sShell:IShellDispatch2;
begin
sShell:=CoShell.Create as IShelldispatch2;
sShell.ShellExecute('c:demo.txt',0,0,'open',SW_SHOW );
end;
注意:別忘了在uses部分添加對Shell32_tlb單元的引用(就是引入Shell Controls and Automation類型庫時,創建的接口單元)。
結論
Shell組件封裝了很多有用的外殼相關的功能,熟練的使用它將使我們的開發變得非常愉快和簡單。在本文中,我們簡單的探索了一下它的應用潛力,只是涉及到了它的皮毛,很多有趣的接口像IShellDispatch2、IShellLinkDual2等以及Folder2、ShellFolderView、ShellFolderVIEwOC等對象是本文短小的篇幅所無法涵蓋的,感興趣的朋友可以自行去研究,你越深入,你就越會發現它就像一個大金庫一樣,內容非常豐富。