Как получить PIDL IShellFolder

Если у меня есть IShellFolder указатель на интерфейс. Как я могу получить его PIDL?

Я вижу, как перечислить его дочерние элементы, и я вижу, как использовать его для сравнения любых двух дочерних элементов. Но как мне получить собственный pidl?

Я спрашиваю, потому что хочу знать:

Это IShellFolder == Другой IShellFolder

Я могу использовать IShellFolder::CompareIDs(), но мне нужны идентификаторы обеих папок.


person Mordachai    schedule 19.11.2009    source источник


Ответы (5)


То, что Крис или Мордехай пишут на №1, в любом случае не по делу. Вопрос не в объектах в пространстве имен оболочки, а в объектах, имеющих интерфейс IShellFolder. Наличие интерфейса IShellFolder само по себе не означает присутствия в пространстве имен оболочки. Исходный вопрос неверно сформулирован, поскольку предполагает, что объект с IShellFolder интерфейсом должен иметь «свой собственный PIDL».

Я думаю, лучшее, что вы можете сделать, это то, что предлагает Мордехай:

  • посмотрите, есть ли у объекта IPersistFolder2 интерфейс

Цель этого интерфейса - исправить объект в пространстве имен оболочки, что, в свою очередь, делает папку устойчивой. Вместо того, чтобы делать выводы из отсутствия опубликованной документации, посмотрите, что Microsoft на самом деле говорит об интерфейсах IPersistFolder и IPersistFolder2 и методах Initialize и GetCurFolder. В первую очередь:

вам необходимо реализовать этот интерфейс, чтобы можно было получить ITEMIDLIST объекта папки Shell.

Что касается №2, я боюсь, что Крис определенно не прав. IShellFolder, безусловно, можно получить без PIDL. Панель управления, которую Крис представил для №1, представляет собой готовый контрпример для №2. Просто скачайте CLSID_ControlPanel и IID_IShellFolder в CoCreateInstance. Вы получаете идеально подходящий экземпляр Панели управления, даже не "зная PIDL".

В SHELL32 реализовано несколько других создаваемых папок оболочки, и любая DLL может настраивать любое количество других.

person Geoff Chappell    schedule 14.11.2010

Я обнаружил, что вы можете запросить IShellFolder для его IPersistFolder2, который имеет GetCurFolder (), который возвращает его абсолютный PIDL. Затем я мог бы просто использовать IShellFolder для рабочего стола для CompareIDs (), чтобы определить, равны ли они. Я нашел это в общих чертах, глядя на SHGetIDListFromObject. Я не мог просто использовать эту функцию, потому что это Vista, а мне нужна совместимость с XP.

Вот набросок того, как это работает (при условии, что у вас есть ifolder_desktop и ifolder_other, которые являются указателями IShellFolder. Pidl - простой помощник, который обеспечивает правильное освобождение IDLIST):

CComQIPtr<IPersistFolder2> ipf2_desktop(ifolder_desktop);
CComQIPtr<IPersistFolder2> ipf2_folder(ifolder_other);

Pidl pidl_desktop, pidl_folder;
VERIFY(SUCCEEDED(ipf2_desktop->GetCurFolder(pidl_desktop)));
VERIFY(SUCCEEDED(ipf2_folder->GetCurFolder(pidl_folder)));

HRESULT hr = ifolder_desktop->CompareIDs(NULL, pidl_desktop, pidl_folder);
pCmdUI->Enable(SUCCEEDED(hr) && HRESULT_CODE(hr) != 0);

Если кому-то интересен мой простой класс Pidl:

class Pidl
{
public:
    // create empty
    Pidl() : m_pidl(NULL) { }

    // create one of specified size
    explicit Pidl(size_t size) : m_pidl(Pidl_Create(size)) {}

    // create a copy of a given PIDL
    explicit Pidl(const ITEMIDLIST * pidl) : m_pidl(Pidl_Copy(pidl)) {}

    // create an absolute PIDL from a parent + child
    Pidl(const ITEMIDLIST_ABSOLUTE * pParent, const ITEMIDLIST_RELATIVE * pChild) : m_pidl(Pidl_Concatenate(pParent, pChild)) { }

    // return our PIDL for general use (but retain ownership of it)
    operator const ITEMIDLIST * () { return m_pidl; }

    // return a pointer to our pointer, for use in functions that assign to a PIDL
    operator ITEMIDLIST ** () 
    {
        free();
        return &m_pidl; 
    }

    // release ownership of our PIDL
    ITEMIDLIST * release() 
    { 
        ITEMIDLIST * pidl = m_pidl;
        m_pidl = NULL;
        return pidl;
    }

    void free()
    {
        if (m_pidl)
            //Pidl_Free(m_pidl);
            ILFree(m_pidl);
    }

    // automatically free our pidl (if we have one)
    ~Pidl()
    {
        free();
    }

private:
    ITEMIDLIST * m_pidl;
};
person Mordachai    schedule 19.11.2009


Ответ Мордачай может быть правильным, но для меня этот запрос не имеет смысла с двух сторон:

  1. Я не верю, что есть опубликованный документ, в котором говорится, что у IShellFolder может быть только один родитель. К любой конкретной папке оболочки может быть несколько способов. Панель управления доступна через Мой компьютер, через меню «Пуск» и в любом месте файловой системы, где вы создаете точку соединения с ней. Похоже, первоначальное намерение команд оболочки заключалось в том, что при наличии экземпляра IShellFolder не должно иметь значения для внешних пользователей, какое его произвольное местоположение.

  2. Кроме того, любое приложение, которое создает экземпляр IShellFolder, обязательно делало это ОТ ЗНАНИЯ PIDL. Если ваше приложение заботится о пути к IShellFolder, оно уже ИМЕЕТ эту информацию. Как ты его потерял? (И почему команда оболочки должна добавлять метод, помогающий приложениям отслеживать свои собственные данные?)

person Chris Becke    schedule 21.11.2009
comment
1. Верно, но файловая система - это основная истина для большинства объектов в пространстве оболочки. И хотя в одной папке может быть несколько ссылок, переходов и т. Д., Фактическая родительская папка может быть только одна. Это правда по определению файловой системы. Так было всегда, и существует SHBindToParent, подтверждающий эту истину. 2. Не так. Можно создать экземпляр IShellFolder непосредственно из SHGetDesktopFolder. Во всяком случае, часто проектируются системы, которые могут работать только в одном направлении и в конечном итоге терпят неудачу. Возможность конвертировать из одного в другой более гибкая и надежная. - person Mordachai; 23.11.2009
comment
1. Так что, если у некоторых файловых систем есть ограничения. Пространство имен оболочки было разработано для выражения более общего случая. 2. Спасибо, что указали на один особый случай. Очень умный. - person Chris Becke; 23.11.2009

Как было сказано ранее, может возникнуть множество проблем со специальными папками, такими как Панель управления (я до сих пор не понимаю это полностью), но вот простое решение для "обычных" папок:

HRESULT get_pidl(IShellFolder * sf, LPITEMIDLIST * pidl)
{
    if (!sf || !pidl) return E_FAIL;

    wchar_t FolderName[MAX_PATH] = {0};
    STRRET strDispName; 

    sf->GetDisplayNameOf(NULL, SHGDN_FORPARSING, &strDispName); 
    StrRetToBuf(&strDispName, NULL, FolderName, (UINT)MAX_PATH);

    IShellFolder * desktop = nullptr;
    SHGetDesktopFolder(&desktop);

    ULONG cbEaten, atrib = 0;
    HRESULT hr = desktop->ParseDisplayName(NULL, nullptr, FolderName, &cbEaten, pidl, &atrib);
    desktop->Release();

    return hr;
}
person ChrCury78    schedule 07.01.2019