程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 再談CFileDialog對話框的定制

再談CFileDialog對話框的定制

編輯:關於VC++

有一篇文章題為:“一個定制CFileDialog對話框的實例”,此文示范了如何定制“打開”文件對話框,通過調用 GetItemText 函數直接從列表中獲得選中的文件名, 有心的讀者肯定會留意,在這篇文章的最後作者留下一個不大不小的尾巴:

“....其實,在程序中有個致命的問題——如果用戶定制了資源管理器來隱藏已知文件類型的擴展名。那麼,.txt就不會出現在列表框中。也就是說CFileDlgHelper::GetItemName 返回 foo,而不是foo.txt。實際上,如果擴展名被隱藏,那麼象 foo.txt、foo.jpg 和 foo.doc 等等這樣的文件都以名字foo出現(試一下就知道了)。如此一來,怎麼知道這個 foo 文件到底是此 foo,還是彼 foo 呢?問題真是解決不完啊,搞掂這個問題,又出那個問題。唉,好累啊,下次再說吧......”

很多人都在翹首企盼這個“下次再說吧......”究竟會如何?本文且讓我將這個尾巴割掉,從而徹底解決遺留的問題。同時也解除大家心頭的牽掛。

其實,解決方法很簡單,之所以當時沒有揭穿,主要是因為它涉及到一個未公開的秘密,而這個秘密我未曾通過微軟公司的大老們確認。在前述文章中,我創建了一個類,這個類名叫 CFileDlgHelper,它提供了諸多方便的函數來處理文件 打開對話框。其中有一個函數是 CFileDlgHelper::GetListCtrl,用它可以獲得含有特定文件名的列表控制,用 GetItemName 來從列表控制中獲取條目名稱。正如大家所見到的,GetItemName (它調用 CListCtrl::GetItemText)是有瑕疵的,也就是說,如果你在資源管理器的選項設置中隱藏已知類型的擴展名,那麼該函數返回的串不包括擴展名。這樣就沒辦法區分 bugs.txt 和 bugs.bmp,因為 GetItemName 的返回值都是 bugs。

那麼,這個微軟在“打開”文件對話框中未公開的秘密到底是什麼呢?它就是CListCtrl::GetItemData 返回的列表項的數據,一個 DWORD 類型的值,它實際上是該列表項的 PIDL。這個 PIDL 是 Windows 外殼中的東西,它唯一標識一個外殼對象,象文件、文件夾、鏈接、磁盤驅動器或者是象“我的文檔”這樣的偽對象。對於一般普通文件,PIDL 是用寬字符表示的文件相對路徑名。

一旦你了解了項目數據就是其PIDL,那麼要獲得它的路徑名就很輕松。只不過要懂一點討厭的外殼編程。首先,向對話框發送一個 CDM_GETFOLDERIDLIST 消息以便獲得當前文件夾的 PIDL。它包括兩個步驟:1、用空(NULL)緩沖發送一次 CDM_GETFOLDERIDLIST 獲取路徑長度,分配實際緩沖後再發送一次 CDM_GETFOLDERIDLIST;2、必須組合文件夾的 PIDL (路徑名)和數據項的 PIDL(即相對路徑名)來獲取完整的 PIDL (全路徑名)。為此,你必須獲得文件夾的 IShellFolder 接口並用神奇的 SHGDN_FORPARSING 標志調用 IShellFolder::GetDisplayNameOf,以次獲取全路徑名,包括擴展名。

為了減輕大家的勞動,我添加了一個新函數 CFileDlgHelper::GetItemPathName,用它可以輕松獲取想要的物理路徑名。這個函數的使用方法如下:

CString path = m_dlgHelper.GetItemPathName(i);

圖一 修改後的程序運行畫面

就這麼簡單,CFileDlgHelper::GetItemPathName 是調用 CFileDlgHelper::GetDisplayNameOf 的打包函數,幾經重載。圖一是修改後的程序運行時顯示選中文件的完整物理路徑名。具體實現細節請參考源代碼。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved