不幸的是,我從來沒有結束這條路線。相反,我改編了CFileDialog,以XP..Windows 7兼容的方式實現我想要的。
該解決方案的核心是從公共對話框控件獲得IShellBrowser *實例:
// return the IShellBrowser for the common dialog
// NOTE: we force CComPtr to create a new AddRef'd copy (since the one that this gives us is synthesized, and hasn't had an AddRef on our behalf)
CComPtr<IShellBrowser> GetShellBrowser() const { return (IShellBrowser*)::SendMessage(GetCommonDialogHwnd(), CDM_GETISHELLBROWSER, 0, 0); }
爲了做票友的東西(像弄清楚還真是選擇什麼 - 無論什麼是它的真實身份用戶是否隱藏文件擴展名) - 我使用生成的IShellBrowser *。
例如:
//////////////////////////////////////////////////////////////////////////
// Get display name of item in file open dialog. Flags tell how.
// SHGDN_FORPARSING gets the full path name even when user has
// checked `Hide extensions for known file types` in Explorer.
//
CString CMFCToolboxAdvancedFileDialog::GetDisplayNameOfItem(int nItem) const
{
// get the item ID of the given item from the list control
LPITEMIDLIST pidlAbsolute = GetItemIDListOf(nItem);
// no PIDL = no display name
if (!pidlAbsolute)
return "";
// get the display name of our item from the folder IShellFolder interface
CString path = GetDisplayNameOf(pidlAbsolute);
// deallocate the PIDL
ILFree(pidlAbsolute);
// return the pathname
return path;
}
的呼叫:
// return the ITEMIDLIST for the item at the specified index in the list view (caller is responsible for freeing)
LPITEMIDLIST CMFCToolboxAdvancedFileDialog::GetItemIDListOf(UINT nItem) const
{
// This can only succeed if there is an IShellView currently (which implies there is a list control)
CListCtrl * pListCtrl = GetListCtrl();
if (!pListCtrl)
return NULL;
// Use undocumented method (the pidl is stored in the item data)
// NOTE: Much thanks to Paul DiLascia for this technique (worked up until Vista)
// http://www.dilascia.com/index.htm
if (LPCITEMIDLIST pidlChild = (LPCITEMIDLIST)pListCtrl->GetItemData(nItem))
{
// get PIDL of current folder from the common dialog
LRESULT len = ::SendMessage(GetCommonDialogHwnd(), CDM_GETFOLDERIDLIST, 0, NULL);
if (!len)
return NULL;
LPCITEMIDLIST pidlFolder = (LPCITEMIDLIST)CoTaskMemAlloc(len);
::SendMessage(GetCommonDialogHwnd(), CDM_GETFOLDERIDLIST, len, (LPARAM)(void*)pidlFolder);
// return the absolute ITEMIDLIST
return ILCombine(pidlFolder, pidlChild);
}
// Use another undocumented feature: WM_GETISHELLBROWSER
CComPtr<IShellBrowser> pShellBrowser(GetShellBrowser());
if (!pShellBrowser)
return NULL;
// attempt to get access to the view
CComPtr<IShellView> pShellView;
if (FAILED(pShellBrowser->QueryActiveShellView(&pShellView)))
return NULL;
// attempt to get an IDataObject of all items in the view (in view-order)
CComPtr<IDataObject> pDataObj;
if (FAILED(pShellView->GetItemObject(SVGIO_ALLVIEW|SVGIO_FLAG_VIEWORDER, IID_IDataObject, (void**)&pDataObj)))
return NULL;
// attempt to get the ITEMIDLIST from our clipboard data object
const UINT cfFormat = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
FORMATETC fmtetc = { cfFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
ClipboardStorageMedium stgmed;
if (FAILED(pDataObj->GetData(&fmtetc, &stgmed)))
return NULL;
// cast to the actual data requested
CIDA * pida = (CIDA*)stgmed.hGlobal;
// ensure we have that index
ASSERT(pida->cidl > nItem);
if (nItem >= pida->cidl)
return NULL;
// find the data for the item requested
const ITEMIDLIST * pidlParent = GetPIDLFolder(pida);
const ITEMIDLIST * pidlChild = GetPIDLItem(pida, nItem);
// return the absolute PIDL
return ILCombine(pidlParent, pidlChild);
}
的呼叫:
// NOTE: this is the only way I know to get the actual list control!
CListCtrl * GetListCtrl() const
{
// return &GetListView()->GetListCtrl();
// we have to be a window to answer such a question
ASSERT(IsWindow(GetCommonDialogHwnd()));
HWND hwnd = ::GetDlgItem(GetCommonDialogHwnd(), IDC_FILE_LIST_VIEW);
if (hwnd)
return static_cast<CListCtrl*>(CListCtrl::FromHandle(::GetWindow(hwnd, GW_CHILD)));
return NULL;
}
那麼,希望,讓你的想法,你可以從這裏走。克/升! ;)
也許他希望他的程序能夠在Vista之前的平臺上工作,並且希望將這部分代碼從其餘部分中抽離出來,以便他可以使用IExplorerBrowser。這就是我們所說的「好設計」。 – 2009-10-25 18:14:52
不幸的是,我們的客戶羣採用新技術的速度很慢。如果可以的話,他們會使用Windows 95! ;)由於其他操作系統限制,我們的應用程序至少需要Windows 2000,但這已經是一段時間了。突然之間向前推進2個操作系統到Vista(這在很多人普遍認爲是可怕的混亂)將是超越蒼白。 – Mordachai 2009-10-26 13:25:35
就優秀設計的高貴動機而言,我們的動機主要在於標準的文件對話方式在用戶可以使用的自定義設置方面太有限。這些年來我們一直遇到極限,我們爲該對話框的早期版本所做的許多自定義已停止與該對話框的Vista +版本一起運行。所以我們需要一個真正可定製的對話框,當它涉及到他們在該界面中所做的和不支持的功能時,它可以獨立於微軟經常出奇異的想法。 – Mordachai 2009-10-26 13:26:36