天天看點

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

 原文  

(本系列文章由檸檬的(lc_mtt)原創,轉載請注明出處,謝謝~)

讓我們詳細解釋一下 Shell 程式設計中最基本的一些函數、結構體和枚舉。

SHGetDesktopFolder  擷取桌面的 IShellFolder 接口

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

[DllImport("shell32.dll")]

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

        public static extern Int32 SHGetDesktopFolder(out IntPtr ppshf);

要使用這個函數,必須先定義一個 IntPtr 指針。然後通過指針,使用 GetObjectForIUnknown 傳回通過指向 COM 對象的 IShellFolder 接口的指針執行個體。于是需要編寫以下函數:

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

public static IShellFolder GetDesktopFolder(out IntPtr ppshf)

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

        {

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            SHGetDesktopFolder(out ppshf);

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            Object obj = Marshal.GetObjectForIUnknown(ppshf);

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            return (IShellFolder)obj;

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

        }

ParseDisplayName 

獲得對象的PIDL,即便對象在目錄樹中處于目前目錄下一層或更多層。例如,對于檔案對象來說,它的解析名就是它的路徑,我們用檔案系統對象的完全路徑名來調用桌面的IshellFolder接口的 ParseDisplayName 方法,它會傳回這個對象的完全PIDL。定義:

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

void ParseDisplayName(

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            IntPtr hwnd,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            IntPtr pbc,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            out uint pchEaten,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            out IntPtr ppidl,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            ref uint pdwAttributes);

裡面最重要的參數就是 out IntPtr ppidl 了,它傳回 pszDisplayName 指定路徑對應的 PIDL。然而僅僅是 PIDL 并不能讓你做更多的事情。這時候還需要調用 BindToObject 來傳回 IShellFolder 接口。

BindToObject 

根據 PIDL 建立和初始化 IShellFolder 對象。定義:

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

void BindToObject(

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            IntPtr pidl,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開
(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            [In()] ref Guid riid,

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

            out IShellFolder ppv);

裡面有一個 [In()] ref Guid riid 參數,表示接口的接口辨別符 (IID)。GUID其實就是一個唯一的辨別符。世界上的任何兩台計算機都不會生成重複的 GUID 值。GUID 主要用于在擁有多個節點、多台計算機的網絡或系統中,配置設定必須具有唯一性的辨別符。我們這裡使用 IID_IShellFolder 表示它擷取的是一個 IShellFolder 接口。

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

public static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");

另外介紹 IEnumIDList 接口。IEnumIDList 接口使資料總管獲得檔案夾包含的全部對象的PIDL,PIDL然後可以用來獲得這些對象的資訊。

是以,我們使用 EnumObjects 函數傳回的将是 IEnumIDList 的指針:

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

int EnumObjects(IntPtr hWnd, SHCONTF flags, out IntPtr enumIDList);

其中 flags 是 SHCONTF 枚舉類型,它決定了枚舉的内容:

是以,我們可以通過 flags 的不同來分别列舉子檔案和子目錄。這裡會遇到一個問題,怎麼擷取 PIDL 對象的名稱呢。這裡編寫了2個函數,可以通過 PIDL 或者 IShellFolder 傳回對象的名稱(詳細解釋留到下一節):

例子二,從“桌面”開始展開

這個例子将使你深入了解之前的内容。它是這樣的一個例子,允許你從“桌面”開始,一直展開到最深層的對象。

照例,附圖檔和源代碼:

(C#)Windows Shell 程式設計系列2 - 解釋,從“桌面”開始展開

下一節将講述 Shell 程式設計中的 IContextMenu ,也就是上下文菜單,将使你的應用程式列舉 Shell 對象的同時,還能在右鍵操控它們的菜單。