2009-10-22 27 views
1

實施IExplorerBrowser顯然,有主辦Explorer在您的應用程序開始與Vista相當簡單的方法: http://www.codeproject.com/KB/vista/ExplorerBrowser.aspx如何在MFC

然而,該接口僅適用起始與Vista。

我看到有另一種方法可以做到:「一路回到95,但它需要更多的工作 - 實現IExplorerBrowser並通過IShellFolder :: CreateViewObject(IID_IShellView)從數據源獲取視圖」

所以我想走這條路線:實現IExplorerBrowser。

我從哪裏得到一個IShellFolder *來獲取球首先滾動? 如何指定主機窗口來容納shell視圖控件? 如何爲shell視圖指定邊界矩形(並調整其大小)?

是否有一套全面的文檔 - 或白皮書 - 某處爲Windows Shell記錄這些接口?我迄今收集到的信息似乎非常分散,有幾個例子非常過時,甚至不能編譯(它們需要對當前版本的ATL進行大量重寫),並且沒有可以找到的示例MFC。

回答

-1

這樣做可能會使一些shell命名空間擴展名認爲它們在Vista上運行並觸發不期望的結果。

爲什麼你認爲你需要實現比Vista更早的Window版本的IExplorerBrowser?誰會是你的界面的客戶?該接口在Windows SDK頭文件中被保護,以防止它在早期版本中使用。

有一些shell視圖託管示例在http://www.codeproject.com/KB/shell/。我擔心在早期版本中託管shell視圖並不像使用Vista的IExplorerBrowser那麼簡單。

+0

也許他希望他的程序能夠在Vista之前的平臺上工作,並且希望將這部分代碼從其餘部分中抽離出來,以便他可以使用IExplorerBrowser。這就是我們所說的「好設計」。 – 2009-10-25 18:14:52

+0

不幸的是,我們的客戶羣採用新技術的速度很慢。如果可以的話,他們會使用Windows 95! ;)由於其他操作系統限制,我們的應用程序至少需要Windows 2000,但這已經是一段時間了。突然之間向前推進2個操作系統到Vista(這在很多人普遍認爲是可怕的混亂)將是超越蒼白。 – Mordachai 2009-10-26 13:25:35

+0

就優秀設計的高貴動機而言,我們的動機主要在於標準的文件對話方式在用戶可以使用的自定義設置方面太有限。這些年來我們一直遇到極限,我們爲該對話框的早期版本所做的許多自定義已停止與該對話框的Vista +版本一起運行。所以我們需要一個真正可定製的對話框,當它涉及到他們在該界面中所做的和不支持的功能時,它可以獨立於微軟經常出奇異的想法。 – Mordachai 2009-10-26 13:26:36

1

您可以通過首先撥打SHGetDesktopFolder()來獲得滾球。這將爲您提供桌面的IShellFolder。然後調用ISF::BindToObject()以獲取您希望查看的特定子文件夾的IShellFolder。如果您沒有所需的子文件夾的PIDL,則可以撥打SHParseDisplayName()來獲取該PIDL。

0

不幸的是,我從來沒有結束這條路線。相反,我改編了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; 
} 

那麼,希望,讓你的想法,你可以從這裏走。克/升! ;)

0

你不是真的想實現IExplorerBrowser,你想知道如何直接使用IShellView

jeffamaphone's answer應該足以獲得從中獲取IShellView的初始接口。之後,IShellView::CreateViewWindow方法可能是一個很好的開始。

順便說一下,MFC可能與此過程無關。使用ATL智能指針CComPtr或CComQIPtr來存放接口指針。 MFC是純Windows對象的包裝,但COM接口隱藏了你的所有內容。

+0

謝謝馬克。我真的只是給自己添加了一個「答案」給另一個寫我的人問我去哪裏去了。是的,你是完全正確的:我真正需要的是能夠直接進入組成標準文件對話框的底層對象,並且我從那以後發現了各種方法讓我能夠。鑑於我們的代碼庫,MFC純粹是一種方便。 – Mordachai 2010-09-23 19:46:23