2009-11-19 14 views
7

Si j'ai un pointeur d'interface IShellFolder. Comment pourrais-je obtenir son PIDL?Comment obtenir le PIDL d'un IShellFolder

Je peux voir comment énumérer ses enfants, et je peux voir comment l'utiliser pour comparer deux enfants. Mais comment pourrais-je avoir son propre pidl?

Je demande parce que je voudrais savoir:

Est-ce IShellFolder == Un autre IShellFolder

Je peux utiliser IShellFolder::CompareIDs(), mais je dois avoir les ID des deux dossiers.

Répondre

6

J'ai trouvé que vous pouvez interroger un IShellFolder pour son IPersistFolder2, qui a GetCurFolder(), qui retourne son PIDL absolu. Je pourrais alors simplement utiliser le IShellFolder pour le bureau à CompareIDs() pour déterminer s'ils sont égaux. J'ai trouvé les contours de tout cela en regardant SHGetIDListFromObject. Je ne pouvais pas simplement utiliser cette fonction, parce que sa Vista, et j'ai besoin de la compatibilité XP.

Voici un croquis de la façon dont il fonctionne (en supposant que vous avez un ifolder_desktop et ifolder_other, qui sont des pointeurs IShellFolder Pidl est une aide simple qui assure que les IDLISTs sont désallouées correctement.):

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); 

En cas quelqu'un est intéressé par ma classe simple 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; 
}; 
1

réponse de Mordachai pourrait être correcte, mais pour moi, cette requête n'a pas de sens sur deux fronts:

  1. Je ne crois pas qu'il existe un document publié indiquant qu'un IShellFolder ne peut avoir qu'un seul parent. Il peut y avoir plusieurs façons d'accéder à un dossier shell particulier. le panneau de commande est accessible via Poste de travail, via le menu Démarrer, et n'importe où dans le système de fichiers, vous créez un point de jonction . Il semble que l'intention originale des équipes shell était, étant donnée une instance de IShellFolder, cela ne devrait pas importer aux utilisateurs externes ce que son emplacement arbitraire se trouvait être.

  2. De plus, toute application qui instancie un IShellFolder sûrement l'a fait à partir d'une connaissance d'un PIDL. Si votre application se souciait du chemin vers un IShellFolder, elle avait déjà cette information. Comment l'avez-vous perdu? (Et pourquoi l'équipe shell ajouter une méthode pour aider les applications garder une trace de leurs propres données?)

+0

1. Vrai, mais le système de fichiers est la vérité sous-jacente pour la plupart des objets dans l'espace shell. Et bien qu'il soit possible d'avoir plusieurs liens, jonctions, etc., vers un dossier donné, il ne peut y avoir qu'un seul dossier parent réel. C'est vrai par définition du système de fichiers. Cela a toujours été le cas, et il y a SHBindToParent pour corroborer cette vérité. 2. Ce n'est pas le cas. On peut instancier un IShellFolder directement à partir de SHGetDesktopFolder. Quoi qu'il en soit, ce sont souvent des systèmes conçus qui ne peuvent aller que d'une seule façon et finalement échouer. La possibilité de convertir de l'un à l'autre est plus flexible et robuste. – Mordachai

+0

1. Alors, que se passe-t-il si certains systèmes de fichiers ont des limites? L'espace de nommage du shell a été conçu pour exprimer le cas plus général. 2. Merci d'avoir signalé le cas particulier. Très intelligent. –

6

Qu'est-ce que Chris soit ou Mordechai écrit sur # 1 est en tout cas pas au point. La question ne concerne pas les objets dans l'espace de noms shell mais les objets qui ont une interface IShellFolder. La possession d'une interface IShellFolder n'implique pas elle-même une présence dans l'espace de nom du shell. La question d'origine est mal formée, dans la mesure où elle suppose qu'un objet avec une interface IShellFolder doit avoir "son propre PIDL". Je pense que ce que je peux faire de mieux, comme le suggère Mordechai, c'est de voir si l'objet a aussi une interface IPersistFolder2. Le but de cette interface est de réparer l'objet dans l'espace de noms du shell, ce qui permet de rendre le dossier persistant. Plutôt que d'inférer de toute absence de documentation publiée, regardez ce que Microsoft dit réellement des interfaces IPersistFolder et IPersistFolder2 et des méthodes Initialize et GetCurFolder.Plus particulièrement, "vous devez implémenter cette interface afin que ITEMIDLIST de l'objet de dossier Shell puisse être récupéré." Sur le # 2, j'ai bien peur que Chris ne soit pas correct. Un IShellFolder peut certainement être obtenu sans PIDL. Le Panneau de configuration, que Chris a présenté pour # 1, fournit un contre-exemple prêt pour # 2. Envoyez simplement CLSID_ControlPanel et IIS_IShellFolder à CoCreateInstance. Vous obtenez une instanciation parfaitement utilisable du Panneau de configuration sans jamais "avoir connaissance d'un PIDL". Il existe une poignée d'autres dossiers de shell créables implémentés dans SHELL32, et n'importe quelle DLL peut en configurer un certain nombre d'autres.

4

J'ai oublié de mentionner la fonction SHGetIDListFromObject.

Il est uniquement disponible dans Windows Vista et versions ultérieures. Il a l'avantage d'être documenté, bien que laconiquement. Vous obtenez plus de détails, bien sûr, de my own documentation. Cela montre que Microsoft connaît deux autres façons d'obtenir un PIDL pour un pointeur d'interface arbitraire à un objet dans l'espace de noms shell.

+0

Merci pour le lien et les détails. Je ne me souviens pas si je suis tombé sur cette fonction, mais je suis limité à maintenir la compatibilité XP (bien qu'il semble que je pourrais avoir besoin d'un lien dynamique vers shell32.dll). – Mordachai