天天看點

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

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

有關 PIDL 

PIDL亦有“絕對路徑”與“相對路徑”的概念。表示“相對路徑”的PIDL(本文簡稱為“相對PIDL”)隻有一個ITEMIDLIST結構的元素,用于辨別相對于父檔案夾的“路徑”;表示“絕對路徑”的PIDL(簡稱為“絕對PIDL”)有若幹個ITEMIDLIST結構的元素,第一個元素表示外殼名字空間根檔案夾(“桌面”)下的某一子檔案夾A,第二個元素則表示檔案夾A下的某一子檔案夾B,其餘依此類推。這樣絕對PIDL就通過儲存一條從“桌面”下的直接子檔案夾或檔案的絕對PIDL與相對PIDL是相同的,而其他的檔案夾或檔案的相對PIDL就隻是其絕對PIDL的最後一部分了。

為什麼要說這些呢?因為有些函數,必須使用絕對PIDL,例如圖示,如果不使用絕對PIDL,某些圖示是無法正常獲得的(驅動器、控制台等)。

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

PIDL.cs

該類實作了 PIDL 的複制和結合功能。現在我們修改 ShellItem 類,使它帶有父節點的 IShellFolder 以及提供擷取絕對 PIDL 的屬性:

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

private ShellItem m_ParentItem;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

public ShellItem ParentItem

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

{

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    get { return m_ParentItem; }

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    set { m_ParentItem = value; }

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

}

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

/// <summary>

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

/// 絕對 PIDL

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

/// </summary>

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

public PIDL PIDLFull

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    get

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    {

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        PIDL pidlFull = new PIDL(PIDL, true);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        ShellItem current = ParentItem;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        while (current != null)

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        {

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

            pidlFull.Insert(current.PIDL);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

            current = current.ParentItem;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        }

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        return pidlFull;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    }

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

擷取圖示

    言歸正傳,既然已經獲得絕對 PIDL,那麼擷取圖示就是很簡單的事情了,我們使用的是 SHGetFileInfo 這個API:

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

[DllImport("shell32", EntryPoint = "SHGetFileInfo", ExactSpelling = false, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    CharSet = CharSet.Auto, SetLastError = true)]

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

public static extern IntPtr SHGetFileInfo(

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    IntPtr ppidl, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    FILE_ATTRIBUTE dwFileAttributes, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    ref SHFILEINFO sfi, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    int cbFileInfo, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    SHGFI uFlags);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

[DllImport("Shell32.dll", CharSet = CharSet.Auto)]

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    string Path, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    FILE_ATTRIBUTE fileAttributes, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    out SHFILEINFO sfi, 

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    int cbFileInfo, SHGFI flags);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

這裡提供了一個重載,你可以選擇是通過 PIDL 還是 路徑 擷取圖示(如果是路徑,那麼僅僅能擷取 檔案夾/檔案 的圖示)。

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

/// 擷取小圖示索引

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

public static int GetSmallIconIndex(string strFilename)

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    SHFILEINFO psfi = new SHFILEINFO();

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    IntPtr ipIcon = SHGetFileInfo(strFilename, 0, out psfi, Marshal.SizeOf(psfi),

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        SHGFI.ICON | SHGFI.SMALLICON | SHGFI.SYSICONINDEX);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    return psfi.iIcon;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

public static int GetSmallIconIndex(IntPtr ipIDList)

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    IntPtr ipIcon = SHGetFileInfo(ipIDList, 0, ref psfi, Marshal.SizeOf(psfi),

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

        SHGFI.ICON | SHGFI.PIDL | SHGFI.SMALLICON | SHGFI.SYSICONINDEX);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

大家也許會覺得奇怪,GetSmallIconIndex 傳回的是 int ,到底要怎麼使用?

其實沒錯,GetSmallIconIndex 僅僅是傳回該圖示在系統圖像清單(System ImageList)的索引(Index)而已。我們隻要擷取系統圖像清單的指針,再把它關聯到你的 TreeView 或 ListView ,即可通過 Icon Index 來顯示圖示了。

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

IntPtr m_ipSmallSystemImageList;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

IntPtr m_ipLargeSystemImageList;

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

//擷取系統 ImageList

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

SHFILEINFO shfi = new SHFILEINFO();

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

m_ipSmallSystemImageList = API.SHGetFileInfo("", 0, out shfi, Marshal.SizeOf(typeof(SHFILEINFO)),

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    SHGFI.SYSICONINDEX | SHGFI.SMALLICON | SHGFI.USEFILEATTRIBUTES);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

m_ipLargeSystemImageList = API.SHGetFileInfo("", 0, out shfi, Marshal.SizeOf(typeof(SHFILEINFO)),

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

    SHGFI.SYSICONINDEX | SHGFI.LARGEICON | SHGFI.USEFILEATTRIBUTES);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

//把系統 ImageList 關聯到 TreeView 和 ListView

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

API.SendMessage(Tree1.Handle, API.TVM_SETIMAGELIST, API.TVSIL_NORMAL, m_ipSmallSystemImageList);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

API.SendMessage(lvFile.Handle, API.LVM_SETIMAGELIST, API.LVSIL_NORMAL, m_ipLargeSystemImageList);

OK,我們修改以往的例子,就可以在 Tree 節點上顯示圖示了:

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

ShellItem shellItem=new ShellItem(pidlSub, iSub, sItem);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

int imgIndex = API.GetSmallIconIndex(shellItem.PIDLFull.Ptr);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

TreeNode nodeSub = new TreeNode(name, imgIndex, imgIndex);

(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示
(C#)Windows Shell 外殼程式設計系列5 - 擷取圖示

(注:關于文中出現的一些結構體或常量,讀者可以自行查閱 MSDN,精力有限實在不能一一說明。)

我們來看一下效果:

事實上,這個代碼改了很多,也涉及到下一節的部分内容,是以代碼将在下一節中抛出...