(本系列文章由檸檬的(lc_mtt)原創,轉載請注明出處,謝謝~)
有關 PIDL
PIDL亦有“絕對路徑”與“相對路徑”的概念。表示“相對路徑”的PIDL(本文簡稱為“相對PIDL”)隻有一個ITEMIDLIST結構的元素,用于辨別相對于父檔案夾的“路徑”;表示“絕對路徑”的PIDL(簡稱為“絕對PIDL”)有若幹個ITEMIDLIST結構的元素,第一個元素表示外殼名字空間根檔案夾(“桌面”)下的某一子檔案夾A,第二個元素則表示檔案夾A下的某一子檔案夾B,其餘依此類推。這樣絕對PIDL就通過儲存一條從“桌面”下的直接子檔案夾或檔案的絕對PIDL與相對PIDL是相同的,而其他的檔案夾或檔案的相對PIDL就隻是其絕對PIDL的最後一部分了。
為什麼要說這些呢?因為有些函數,必須使用絕對PIDL,例如圖示,如果不使用絕對PIDL,某些圖示是無法正常獲得的(驅動器、控制台等)。
PIDL.cs
該類實作了 PIDL 的複制和結合功能。現在我們修改 ShellItem 類,使它帶有父節點的 IShellFolder 以及提供擷取絕對 PIDL 的屬性:
private ShellItem m_ParentItem;
public ShellItem ParentItem
{
get { return m_ParentItem; }
set { m_ParentItem = value; }
}
/// <summary>
/// 絕對 PIDL
/// </summary>
public PIDL PIDLFull
get
{
PIDL pidlFull = new PIDL(PIDL, true);
ShellItem current = ParentItem;
while (current != null)
{
pidlFull.Insert(current.PIDL);
current = current.ParentItem;
}
return pidlFull;
}
擷取圖示
言歸正傳,既然已經獲得絕對 PIDL,那麼擷取圖示就是很簡單的事情了,我們使用的是 SHGetFileInfo 這個API:
[DllImport("shell32", EntryPoint = "SHGetFileInfo", ExactSpelling = false,
CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SHGetFileInfo(
IntPtr ppidl,
FILE_ATTRIBUTE dwFileAttributes,
ref SHFILEINFO sfi,
int cbFileInfo,
SHGFI uFlags);
[DllImport("Shell32.dll", CharSet = CharSet.Auto)]
string Path,
FILE_ATTRIBUTE fileAttributes,
out SHFILEINFO sfi,
int cbFileInfo, SHGFI flags);
這裡提供了一個重載,你可以選擇是通過 PIDL 還是 路徑 擷取圖示(如果是路徑,那麼僅僅能擷取 檔案夾/檔案 的圖示)。
/// 擷取小圖示索引
public static int GetSmallIconIndex(string strFilename)
SHFILEINFO psfi = new SHFILEINFO();
IntPtr ipIcon = SHGetFileInfo(strFilename, 0, out psfi, Marshal.SizeOf(psfi),
SHGFI.ICON | SHGFI.SMALLICON | SHGFI.SYSICONINDEX);
return psfi.iIcon;
public static int GetSmallIconIndex(IntPtr ipIDList)
IntPtr ipIcon = SHGetFileInfo(ipIDList, 0, ref psfi, Marshal.SizeOf(psfi),
SHGFI.ICON | SHGFI.PIDL | SHGFI.SMALLICON | SHGFI.SYSICONINDEX);
大家也許會覺得奇怪,GetSmallIconIndex 傳回的是 int ,到底要怎麼使用?
其實沒錯,GetSmallIconIndex 僅僅是傳回該圖示在系統圖像清單(System ImageList)的索引(Index)而已。我們隻要擷取系統圖像清單的指針,再把它關聯到你的 TreeView 或 ListView ,即可通過 Icon Index 來顯示圖示了。
IntPtr m_ipSmallSystemImageList;
IntPtr m_ipLargeSystemImageList;
//擷取系統 ImageList
SHFILEINFO shfi = new SHFILEINFO();
m_ipSmallSystemImageList = API.SHGetFileInfo("", 0, out shfi, Marshal.SizeOf(typeof(SHFILEINFO)),
SHGFI.SYSICONINDEX | SHGFI.SMALLICON | SHGFI.USEFILEATTRIBUTES);
m_ipLargeSystemImageList = API.SHGetFileInfo("", 0, out shfi, Marshal.SizeOf(typeof(SHFILEINFO)),
SHGFI.SYSICONINDEX | SHGFI.LARGEICON | SHGFI.USEFILEATTRIBUTES);
//把系統 ImageList 關聯到 TreeView 和 ListView
API.SendMessage(Tree1.Handle, API.TVM_SETIMAGELIST, API.TVSIL_NORMAL, m_ipSmallSystemImageList);
API.SendMessage(lvFile.Handle, API.LVM_SETIMAGELIST, API.LVSIL_NORMAL, m_ipLargeSystemImageList);
OK,我們修改以往的例子,就可以在 Tree 節點上顯示圖示了:
ShellItem shellItem=new ShellItem(pidlSub, iSub, sItem);
int imgIndex = API.GetSmallIconIndex(shellItem.PIDLFull.Ptr);
TreeNode nodeSub = new TreeNode(name, imgIndex, imgIndex);
(注:關于文中出現的一些結構體或常量,讀者可以自行查閱 MSDN,精力有限實在不能一一說明。)
我們來看一下效果:
事實上,這個代碼改了很多,也涉及到下一節的部分内容,是以代碼将在下一節中抛出...