Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在MFC中实现IExplorerBrowser_C++_Com_Mfc_Windows Shell - Fatal编程技术网

C++ 如何在MFC中实现IExplorerBrowser

C++ 如何在MFC中实现IExplorerBrowser,c++,com,mfc,windows-shell,C++,Com,Mfc,Windows Shell,显然,从Vista开始,有一种相当简单的方法可以在应用程序中托管Explorer: 但是,该界面仅从Vista开始提供 我发现还有另一种方法可以做到这一点:“一直回到95,但它需要更多的工作-实现IExplorerBrowser并通过IShellFolder::CreateViewObject(IID_IShellView)从数据源获取视图” 所以我想采用后一种方法:实现IExplorerBrowser 我从哪里获得IShellFolder*以使球首先滚动? 如何指定宿主窗口以容纳shell视

显然,从Vista开始,有一种相当简单的方法可以在应用程序中托管Explorer:

但是,该界面仅从Vista开始提供

我发现还有另一种方法可以做到这一点:“一直回到95,但它需要更多的工作-实现IExplorerBrowser并通过IShellFolder::CreateViewObject(IID_IShellView)从数据源获取视图”

所以我想采用后一种方法:实现IExplorerBrowser

我从哪里获得IShellFolder*以使球首先滚动? 如何指定宿主窗口以容纳shell视图控件? 如何为shell视图指定边界矩形(并调整其大小)


是否有一套完整的文档(或白页)来记录Windows Shell的这些接口?到目前为止,我收集到的信息似乎非常零碎,有一些示例非常过时,甚至无法编译(它们需要大量重写到ATL的当前版本),我根本找不到MFC的例子。

这样做可能会使一些shell名称空间扩展认为它们正在Vista上运行,并触发不希望的结果

为什么您认为需要为早于Vista的Windows版本实施IExplorerBrowser?谁将是您界面的客户?此接口在Windows SDK头文件中受保护,以防止在早期版本中使用


上有一些shell视图宿主示例。恐怕在早期版本中托管shell view并不像使用Vista的IExplorerBrowser那么容易。

您可以先调用。这将为您提供桌面的IShell文件夹。然后调用以获取要查看的特定子文件夹的IShellFolder。如果您没有所需子文件夹的PIDL,可以打电话获取该PIDL。

不幸的是,我从来没有这样做过。相反,我调整了CFileDialog,以XP..Windows7兼容的方式实现了我想要的

解决方案的关键是从公共对话框控件获取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); }
这要求:

// 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;
}
//返回列表视图中指定索引处项目的ItemIdle列表(调用者负责释放)
LPITEMIDLIST CMFCToolboxAdvancedFileDialog::GetItemIDListOf(UINT nItem)常量
{
//只有当前存在IShellView(这意味着存在列表控件)时,此操作才能成功
CListCtrl*pListCtrl=GetListCtrl();
如果(!pListCtrl)
返回NULL;
//使用未记录的方法(pidl存储在项目数据中)
//注:非常感谢Paul DiLascia的这项技术(直到Vista)
//       http://www.dilascia.com/index.htm
if(LPCITEMIDLIST pidlChild=(LPCITEMIDLIST)pListCtrl->GetItemData(nItem))
{
//从“公用”对话框中获取当前文件夹的PIDL
LRESULT len=::SendMessage(GetCommonDialogHwnd(),CDM_getFolderList,0,NULL);
如果(!len)
返回NULL;
LPCITEMIDLIST pidlFolder=(LPCITEMIDLIST)CoTaskMemAlloc(len);
::SendMessage(GetCommonDialogHwnd(),CDM_getFolderList,len,(LPARAM)(void*)pidlFolder);
//返回绝对项IDList
返回ILCombine(pidlFolder、pidlChild);
}
//使用另一个未记录的功能:WM_GETISHELLBROWSER
CComPtr pShellBrowser(GetShellBrowser());
如果(!pShellBrowser)
返回NULL;
//尝试访问该视图
CComPtr pShellView;
if(失败(pShellBrowser->QueryActiveShellView(&pShellView)))
返回NULL;
//尝试获取视图中所有项的IDataObject(按视图顺序)
首席采购官pDataObj;
if(失败(pShellView->GetItemObject(SVGIO_ALLVIEW | SVGIO_FLAG_VIEWORDER,IID_IDataObject,(void**)和pDataObj)))
返回NULL;
//尝试从剪贴板数据对象获取ITEMIDLIST
const UINT cfFormat=寄存器clipboardformat(CFSTR_SHELLIDLIST);
FORMATETC fmtetc={cfFormat,0,DVASPECT\u CONTENT,-1,TYMED\u HGLOBAL};
剪贴簿存储介质stgmed;
if(失败(pDataObj->GetData(&fmtetc,&stgmed)))
返回NULL;
//转换为请求的实际数据
CIDA*pida=(CIDA*)stgmed.hGlobal;
//确保我们有那个索引
断言(pida->cidl>nItem);
如果(nItem>=pida->cidl)
返回NULL;
//查找所请求项目的数据
const ITEMIDLIST*pidlParent=GetPIDLFolder(pida);
const ITEMIDLIST*pidlChild=GetPIDLItem(pida,nItem);
//返回绝对PIDL
返回ILCombine(pidlParent,pidlChild);
}
这要求:

// 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;
}
//注意:这是我知道的获得实际列表控件的唯一方法!
CListCtrl*GetListCtrl()常量
{
//return&GetListView()->GetListCtrl();
//我们必须成为回答这样一个问题的窗口
断言(IsWindow(GetCommonDialogHwnd());
HWND HWND=::GetDlgItem(GetCommonDialogHwnd(),IDC\u文件\u列表\u视图);
如果(hwnd)
返回static_cast(CListCtrl::FromHandle(::GetWindow(hwnd,GW_CHILD));
返回NULL;
}

好吧,希望这能给你一个想法,你可以从这里开始。G/L!;)

您并不是真的想实现IExplorerBrowser,而是想知道如何直接使用它

应足以获取从中获取IShellView的初始接口。之后,该方法可能是一个很好的开始


顺便说一下,MFC可能与此过程无关。使用ATL智能指针CComPtr或CComQIPtr保存接口指针。MFC是纯Windows对象的包装器,但COM接口对您隐藏了所有这些。

也许他希望他的程序能够在Vista之前的平台上运行,并希望将这部分代码从其余部分中抽象出来,以便只使用IExplorerBrowser。这就是我们所说的“好设计”。不幸的是,我们的客户群采用新技术的速度非常慢。如果可能的话,他们会使用Windows95!