Как реализовать IExplorerBrowser в MFC - PullRequest
1 голос
/ 23 октября 2009

Очевидно, есть довольно простой способ разместить Explorer в вашем приложении, начиная с Vista: http://www.codeproject.com/KB/vista/ExplorerBrowser.aspx

Однако этот интерфейс доступен только начиная с Vista.

Я вижу, что есть другой способ сделать это: "вернуться к 95, но это требует больше работы - реализовать IExplorerBrowser и получить представление из источника данных через IShellFolder :: CreateViewObject (IID_IShellView)"

Так что я бы хотел пойти по этому последнему пути: реализовать IExplorerBrowser.

Откуда мне взять IShellFolder *, чтобы в первую очередь перевернуть мяч? Как указать окно хоста для размещения элемента управления оболочки? Как указать прямоугольник границ для вида оболочки (и изменить его размер)?

Существует ли где-нибудь полный набор документов или белых страниц, где документируются эти интерфейсы для оболочки Windows? Информация, которую я почерпнул до сих пор, кажется очень разбитой, с несколькими примерами, которые очень устарели и даже не будут компилироваться (они требуют обширного переписывания в текущую версию ATL), и никаких примеров, которые я могу найти для МФЦ вообще.

Ответы [ 4 ]

1 голос
/ 25 октября 2009

Вы можете получить мяч, сначала вызвав SHGetDesktopFolder () . Это даст вам IShellFolder для рабочего стола. Затем вызовите ISF :: BindToObject () , чтобы получить IShellFolder для конкретной подпапки, которую вы хотите просмотреть. Если у вас нет PIDL для нужной дочерней папки, вы можете вызвать SHParseDisplayName () , чтобы получить этот PIDL.

0 голосов
/ 23 сентября 2010

Вы действительно не хотите реализовывать IExplorerBrowser, вы хотите знать, как работать с IShellView напрямую.

ответа jeffamaphone должно быть достаточно для получения начального интерфейса, из которого можно получить IShellView. После этого метод IShellView :: CreateViewWindow , вероятно, является хорошим местом для начала.

Кстати, MFC, вероятно, не имеет отношения к этому процессу. Используйте интеллектуальные указатели ATL CComPtr или CComQIPtr для хранения указателей интерфейса. MFC - это оболочка для чистых объектов Windows, но интерфейсы COM скрывают все это от вас.

0 голосов
/ 23 сентября 2010

К сожалению, я так и не пошел по этому пути. Вместо этого я адаптировал 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;
}

Ну, надеюсь, это дает вам идею, и вы можете идти отсюда. G / L! ;)

0 голосов
/ 25 октября 2009

Это может заставить некоторые расширения пространства имен оболочки думать, что они работают в Vista, и вызывать нежелательные результаты.

Почему вы думаете, что вам нужно реализовать IExplorerBrowser для Windows более ранних версий, чем Vista? Кто будет клиентами вашего интерфейса? Этот интерфейс защищен в заголовочных файлах Windows SDK, чтобы его нельзя было использовать в более ранних версиях.

На * 1006 есть несколько примеров хостинга вида оболочки. Боюсь, хостинг вида оболочки в более ранних версиях не так прост, как использование Vista IExplorerBrowser.

...