7

IShellFolderインターフェイスポインタがある場合。どうすればそのPIDLを入手できますか?

その子を列挙する方法と、2人の子を比較するためにそれを使用する方法を見ることができます。しかし、どうすれば独自のpidlを取得できますか?

私が知りたいので私は尋ねます:

これはIShellFolderですか==別のIShellFolder

を使用できますIShellFolder::CompareIDs()が、両方のフォルダーのIDが必要です。

4

5 に答える 5

8

クリスかモルデチャイのどちらかが#1に書いていることは、とにかく要点ではありません。IShellFolder問題は、シェル名前空間内のオブジェクトではなく、インターフェイスを持つオブジェクトに関するものです。インターフェイスの所有は、IShellFolderそれ自体がシェル名前空間に存在することを意味するものではありません。IShellFolder元の質問は、インターフェイスを持つオブジェクトが「独自のPIDL」を持っている必要があると想定しているため、形式が正しくありません。

あなたができる最善のことは、Mordechaiが示唆していることだと思います。

  • IPersistFolder2オブジェクトにインターフェイスもあるかどうかを確認します

このインターフェイスの目的は、シェル名前空間内のオブジェクトを修正することです。これにより、フォルダーが永続化されます。公開されたドキュメントがないことから推測するのではなく、Microsoftが実際にIPersistFolderandIPersistFolder2インターフェイスとInitializeメソッドとGetCurFolderメソッドについて何を言っているかを見てください。最も注目すべき点:

ShellフォルダオブジェクトのITEMIDLISTを取得できるように、このインターフェイスを実装する必要があります。

#2では、クリスは間違いなく正しくないのではないかと思います。確かにIShellFolderPIDLなしで得ることができます。クリスが#1のために紹介したコントロールパネルは、#2のためのすぐに使える反例を提供します。フィードCLSID_ControlPanelIID_IShellFolderCoCreateInstanceに送信するだけです。「PIDLの知識がなくても」、コントロールパネルの完全に使用可能なインスタンス化を取得できます。

SHELL32には、他にもいくつかの作成可能なシェルフォルダーが実装されており、どのDLLでも他のフォルダーをいくつでもセットアップできます。

于 2010-11-14T17:09:15.320 に答える
6

IShellFolderにIPersistFolder2を照会できることがわかりました。これには、絶対PIDLを返すGetCurFolder()があります。次に、デスクトップ用のIShellFolderをCompareIDs()に使用して、それらが等しいかどうかを判断できます。SHGetIDListFromObjectを見ていると、この概要がわかりました。Vistaなので、その機能だけを使うことはできませんでした。XPとの互換性が必要です。

これがどのように機能するかのスケッチです(IShellFolderポインターであるifolder_desktopとifolder_otherがあると仮定します。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;
};
于 2009-11-19T23:34:19.883 に答える
5

機能について言及するのを忘れましたSHGetIDListFromObject

WindowsVista以降でのみ使用できます。簡潔ではありますが、文書化されるという利点があります。もちろん、私自身のドキュメントから詳細を入手できます。これは、Microsoftがシェル名前空間内のオブジェクトへの任意のインターフェイスポインターのPIDLを取得する方法をさらに2つ知っていることを示しています。

于 2010-11-16T07:23:02.370 に答える
1

Mordachaiの答えは正しいかもしれませんが、私にとって、このクエリは2つの面で意味がありません。

  1. IShellFolderが持つことができる親は1つだけであるという公開されたドキュメントはないと思います。特定のシェルフォルダには複数の方法があります。コントロールパネルには、[マイコンピュータ]、[スタート]メニュー、およびファイルシステム内の任意の場所からアクセスできます。シェルチームの当初の意図は、IShellFolderインスタンスが与えられた場合、その任意の場所がたまたま何であったかは外部ユーザーにとって重要ではないようです。

  2. さらに、IShellFolderをインスタンス化するアプリケーションは、PIDLの知識を持っていることから確実にインスタンス化されます。アプリがIShellFolderへのパスを気にかけている場合、その情報はすでに含まれています。どのようにそれを失ったのですか?(そして、なぜシェルチームは、アプリが自分のデータを追跡するのに役立つメソッドを追加する必要があるのですか?)

于 2009-11-21T11:13:46.023 に答える
0

前に述べたように、コントロールパネルのような特別なフォルダには多くの問題があるかもしれません(私はまだ完全には理解していません)が、ここに「通常の」フォルダの簡単な解決策があります:

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;
}
于 2019-01-07T17:07:34.050 に答える