Implementieren der grundlegenden Ordnerobjektschnittstellen

Die Vorgehensweise zum Implementieren einer Namespaceerweiterung ist ähnlich wie bei jedem anderen prozessinternen Component Object Model (COM)-Objektobjekt. Alle Erweiterungen müssen drei primäre Schnittstellen unterstützen, die Windows-Explorer die grundlegenden Informationen bereitstellen, die zum Anzeigen der Ordner der Erweiterung in der Strukturansicht erforderlich sind. Damit Sie die Möglichkeiten von Windows-Explorer jedoch voll ausschöpfen können, muss Ihre Erweiterung auch eine oder mehrere optionale Schnittstellen verfügbar machen, die komplexere Funktionen wie z. B. Kontextmenüs oder Drag & Drop unterstützen und eine Ordneransicht bieten.

Dieses Dokument erläutert, wie Sie die primären und optionalen Schnittstellen implementieren, die Windows-Explorer aufruft, um Informationen über die Inhalte Ihrer Erweiterung zu erhalten. Informationen dazu, wie Sie eine Ordneransicht implementieren und Windows-Explorer anpassen, finden Sie unter Implementieren einer Ordneransicht.

Grundlegende Implementierung und Registrierung

Als prozessinterner COM-Server muss Ihre DLL mehrere Standardfunktionen und Schnittstellen verfügbar machen:

Diese Funktionen und Schnittstellen werden wie für die meisten anderen COM-Objekte implementiert. Ausführliche Informationen finden Sie in der COM-Dokumentation.

Registrieren einer Erweiterung

Wie bei allen COM-Objekten müssen Sie eine Klassen-ID (CLSID)-GUID für Ihre Erweiterung erstellen. Registrieren Sie das Objekt, indem Sie einen Unterschlüssel von HKEY_CLASSES_ROOT\CLSID erstellen, der nach der CLSID Ihrer Erweiterung benannt ist. Die DLL sollte als In-Process-Server registriert werden und das Apartmentthreadingmodell angeben. Sie können das Verhalten des Stammordners einer Erweiterung anpassen, indem Sie eine Vielzahl von Unterschlüsseln und Werten zum CLSID-Schlüssel der Erweiterung hinzufügen.

Einige dieser Werte gelten nur für Erweiterungen mit virtuellen Verknüpfungspunkten. Diese Werte gelten nicht für Erweiterungen, deren Verknüpfungspunkte Dateisystemordner sind. Weitere Informationen finden Sie unter Angeben des Speicherorts einer Namespaceerweiterung. Wenn Sie das Verhalten einer Erweiterung mit einem virtuellen Verknüpfungspunkt ändern möchten, fügen Sie dem CLSID-Schlüssel der Erweiterung einen oder mehrere der folgenden Werte hinzu:

  • WantsFORPARSING. Der Analysename für eine Erweiterung mit einem virtuellen Verknüpfungspunkt weist normalerweise die Form ::{GUID} auf. Erweiterungen dieses Typs enthalten in der Regel virtuelle Elemente. Einige Erweiterungen, z. B. „Eigene Dokumente“, entsprechen jedoch eigentlich Dateisystemordnern, obwohl sie über virtuelle Verknüpfungspunkte verfügen. Wenn Ihre Erweiterung Dateisystemobjekte auf diese Weise darstellt, können Sie den Wert für WantsFORPARSING festlegen. Windows-Explorer fordert dann den Analysenamen des Stammordners an. Dazu wird die Methode IShellFolder::GetDisplayNameOf des Ordnerobjekts aufgerufen, wobei uFlags auf SHGDN_FORPARSING gesetzt ist und für pidl ein einzelner leerer Zeiger auf eine Elementbezeichnerliste (PIDL) festgelegt ist. Eine leere PIDL enthält nur ein Abschlusszeichen. Die Methode sollte dann den Analysenamen des Stammordners ::{GUID} zurückgeben.
  • HideFolderVerbs. Die unter HKEY_CLASSES_ROOT\Folder registrierten Verben sind normalerweise allen Erweiterungen zugeordnet. Sie werden im Kontextmenü der Erweiterung angezeigt und können von ShellExecute aufgerufen werden. Damit Ihrer Erweiterung nicht eines dieser Verben zugeordnet wird, legen Sie den HideFolderVerbs-Wert fest.
  • HideAsDelete. Wenn ein Benutzer versucht, Ihre Erweiterung zu löschen, blendet Windows-Explorer die Erweiterung stattdessen aus.
  • HideAsDeletePerUser. Dieser Wert hat denselben Effekt wie HideAsDelete, jedoch auf Benutzerbasis. Die Erweiterung wird nur für Benutzer ausgeblendet, die versucht haben, sie zu löschen. Für alle anderen Benutzer ist die Erweiterung sichtbar.
  • QueryForOverlay. Legen Sie diesen Wert fest, um anzugeben, dass das Symbol des Stammordners eine Symbolüberlagerung aufweisen kann. Das Ordnerobjekt muss die IShellIconOverlay-Schnittstelle unterstützen. Bevor das Symbol des Stammordners angezeigt wird, fordert Windows-Explorer ein Überlagerungssymbol an. Dazu wird eine der beiden IShellIconOverlay-Methoden aufgerufen, wobei für pidlItem eine leere PIDL festgelegt ist.

Die verbleibenden Werte und Unterschlüssel gelten für alle Erweiterungen:

  • Um den Anzeigenamen des Verknüpfungspunktordners der Erweiterung anzugeben, legen Sie als Standardwert des CLSID-Unterschlüssels der Erweiterung eine entsprechende Zeichenfolge fest.
  • Wenn der Cursor auf einen Ordner zeigt, wird in der Regel ein Infotipp mit einer Beschreibung des Ordnerinhalts angezeigt. Um einen Infotipp für den Stammordner Ihrer Erweiterung bereitzustellen, erstellen Sie einen Infotipp-Wert REG_SZ für den CLSID-Schlüssel der Erweiterung, und setzen Sie ihn auf eine entsprechende Zeichenfolge.
  • Um ein benutzerdefiniertes Symbol für den Stammordner Ihrer Erweiterung anzugeben, erstellen Sie einen Unterschlüssel des CLSID-Unterschlüssels der Erweiterung mit der Bezeichnung DefaultIcon. Legen Sie als Standardwert von DefaultIcon einen REG_SZ-Wert fest, der den Namen der Datei mit dem Symbol enthält, gefolgt von einem Komma, dann von einem Minuszeichen und schließlich vom Index des Symbols in dieser Datei.
  • Standardmäßig enthält das Kontextmenü des Stammordners Ihrer Erweiterung die unter HKEY_CLASSES_ROOT\Folder definierten Elemente. Die Elemente Löschen, Umbenennen und Eigenschaften werden hinzugefügt, wenn Sie die entsprechenden SFGAO_XXX-Flags gesetzt haben. Sie können dem Kontextmenü des Stammordners weitere Elemente hinzufügen oder vorhandene Elemente außer Kraft setzen, ähnlich wie Sie es bei einem Dateityp tun würden. Erstellen Sie einen Shell-Unterschlüssel unter dem CLSID-Schlüssel der Erweiterung, und definieren Sie Befehle, wie unter Erweitern von Kontextmenüs erläutert.
  • Wenn Sie eine flexiblere Möglichkeit zur Bearbeitung des Kontextmenüs des Stammordners benötigen, können Sie einen Kontextmenühandler implementieren. Erstellen Sie zum Registrieren des Kontextmenühandlers unter dem CLSID-Schlüssel der Erweiterung einen ShellEx-Schlüssel. Registrieren Sie die CLSID des Handlers wie beim herkömmlichen Erstellen von Shellerweiterungshandlern.
  • Wenn Sie dem Eigenschaftenblatt „Eigenschaften“ des Stammordners eine Seite hinzufügen möchten, weisen Sie dem Ordner das Attribut SFGAO_HASPROPSHEET zu, und implementieren Sie einen Eigenschaftenblatthandler. Erstellen Sie zum Registrieren des Eigenschaftenblatthandlers unter dem CLSID-Schlüssel der Erweiterung einen ShellEx-Schlüssel. Registrieren Sie die CLSID des Handlers wie beim herkömmlichen Erstellen von Shellerweiterungshandlern.
  • Fügen Sie dem CLSID-Unterschlüssel der Erweiterung einen ShellFolder-Unterschlüssel hinzu, um die Attribute des Stammordners anzugeben. Erstellen Sie einen Attributes-Wert, und legen Sie die entsprechende Kombination von SFGAO_XXX-Flags dafür fest.

In der folgenden Tabelle sind einige häufig verwendete Attribute für Stammordner aufgeführt.

Flag Wert Beschreibung
SFGAO_FOLDER 0x20000000 Der Stammordner der Erweiterung enthält ein oder mehrere Elemente.
SFGAO_HASSUBFOLDER 0x80000000 Der Stammordner der Erweiterung enthält einen oder mehrere Unterordner. Windows-Explorer gibt ein Pluszeichen ( + ) neben dem Ordnersymbol an.
SFGAO_CANDELETE 0x00000020 Der Stammordner der Erweiterung kann vom Benutzer gelöscht werden. Das Kontextmenü des Ordners enthält ein Element Löschen. Dieses Flag sollte für Verknüpfungspunkte festgelegt werden, die unter einem der virtuellen Ordner platziert werden.
SFGAO_CANRENAME 0x00000010 Der Stammordner der Erweiterung kann vom Benutzer umbenannt werden. Das Kontextmenü des Ordners enthält ein Element Umbenennen.
SFGAO_HASPROPSHEET 0x00000040 Der Stammordner der Erweiterung enthält ein Eigenschaftenblatt Eigenschaften. Das Kontextmenü des Ordners enthält ein Element Eigenschaften. Um das Eigenschaftenblatt bereitzustellen, müssen Sie einen Eigenschaftenblatthandler implementieren. Registrieren Sie den Handler unter dem CLSID-Schlüssel der Erweiterung, wie zuvor beschrieben.

 

Das folgende Beispiel zeigt den CLSID-Registrierungseintrag für eine Erweiterung mit dem Anzeigenamen MyExtension. Die Erweiterung verfügt über ein benutzerdefiniertes Symbol, das in der DLL der Erweiterung mit einem Index von 1 enthalten ist. Die Attribute SFGAO_FOLDER, SFGAO_HASSUBFOLDER und SFGAO_CANDELETE sind festgelegt.

HKEY_CLASSES_ROOT
   CLSID
      {Extension CLSID}
         (Default) = MyExtension
         InfoTip = Some appropriate text
      DefaultIcon
         (Default) = c:\MyDir\MyExtension.dll,-1
      InProcServer32
         (Default) = c:\MyDir\MyExtension.dll
         ThreadingModel = Apartment
      ShellFolder
         Attributes = 0xA00000020

Handhabung von PIDLs

Jedes Element im Shell-Namespace muss über eine eindeutige PIDL verfügen. Windows-Explorer weist Ihrem Stammordner eine PIDL zu und übergibt den Wert während der Initialisierung an Ihre Erweiterung. Es ist dann Aufgabe Ihrer Erweiterung, jedem ihrer Objekte eine ordnungsgemäß konstruierte PIDL zuzuweisen und diese PIDLs auf Anfrage für Windows-Explorer bereitzustellen. Wenn die Shell eine PIDL verwendet, um eines der Objekte Ihrer Erweiterung zu identifizieren, muss Ihre Erweiterung in der Lage sein, die PIDL zu interpretieren und das betreffende Objekt zu identifizieren. Die Erweiterung muss jedem Objekt auch einen Anzeigenamen und einen Analysenamen zuweisen. Da PIDLs von nahezu jeder Ordnerschnittstelle verwendet werden, implementieren Erweiterungen häufig einen einzelnen PIDL-Manager für alle diese Aufgaben.

Der Begriff PIDL ist je nach Kontext die Kurzform für eine ITEMIDLIST-Struktur oder einen Zeiger auf eine solche Struktur. Wie angegeben, verfügt eine ITEMIDLIST-Struktur über ein einzelnes Element, eine SHITEMID-Struktur. Bei der ITEMIDLIST-Struktur eines Objekts handelt es sich um ein gepacktes Array von zwei oder mehr SHITEMID-Strukturen. Die Reihenfolge dieser Strukturen definiert einen Pfad durch den Namespace, ähnlich wie c:\MyDirectory\MyFile einen Pfad durch das Dateisystem definiert. In der Regel besteht die PIDL eines Objekts aus einer Reihe von SHITEMID-Strukturen, die den Ordnern entsprechen, welche den Namespacepfad definieren, gefolgt von der SHITEMID-Struktur des Objekts, auf die wiederum ein Abschlusszeichen folgt.

Das Abschlusszeichen ist eine SHITEMID-Struktur, wobei das cb-Element auf NULL gesetzt ist. Das Abschlusszeichen ist erforderlich, da die Anzahl der SHITEMID-Strukturen in der PIDL eines Objekts von der Position des Objekts im Shell-Namespace und vom Ausgangspunkt des Pfads abhängt. Darüber hinaus kann die Größe der verschiedenen SHITEMID-Strukturen variieren. Wenn Sie eine PIDL erhalten, gibt es keine einfache Möglichkeit, die Größe oder sogar die Gesamtzahl der SHITEMID-Strukturen zu bestimmen. Sie müssen vielmehr das gepackte Array Struktur für Struktur durchgehen, bis Sie das Abschlusszeichen erreicht haben.

Zum Erstellen einer PIDL muss Ihre Anwendung folgende Schritte ausführen:

  1. Eine SHITEMID-Struktur für jedes ihrer Objekte erstellen.
  2. Die relevanten SHITEMID-Strukturen zu einer PIDL zusammenstellen.

Erstellen einer SHITEMID-Struktur

Die SHITEMID-Struktur eines Objekts identifiziert das Objekt innerhalb seines Ordners eindeutig. Eine Art von PIDL, die von vielen IShellFolder-Methoden verwendet wird, besteht einfach nur aus der SHITEMID-Struktur des Objekts, gefolgt von einem Abschlusszeichen. Die Definition einer SHITEMID-Struktur lautet:

typedef struct _SHITEMID { 
    USHORT cb; 
    BYTE   abID[1]; 
} SHITEMID, * LPSHITEMID;

Das abID-Element ist der Bezeichner des Objekts. Da die Länge von abID nicht definiert ist und variieren kann, wird für das cb-Element die Größe der SHITEMID-Struktur in Byte festgelegt.

Da weder die Länge noch der Inhalt von abID standardisiert ist, können Sie jedes beliebige Schema verwenden, um Ihren Objekten abID-Werte zuzuweisen. Die einzige Anforderung besteht darin, dass es nicht zwei Objekte mit identischen Werten in demselben Ordner geben kann. Aus Leistungsgründen sollte Ihre SHITEMID-Struktur jedoch auf DWORD ausgerichtet sein. Mit anderen Worten, Sie sollten Ihre abID-Werte so bilden, dass cb ein ganzzahliges Vielfaches von 4 ist.

In der Regel verweist abID auf eine von der Erweiterung definierte Struktur. Neben der Objekt-ID wird diese Struktur häufig verwendet, um verschiedene verwandte Informationen, z. B. den Typ oder die Attribute des Objekts, zu speichern. Die Ordnerobjekte Ihrer Erweiterung können dann schnell die Informationen aus der PIDL extrahieren, anstatt sie abfragen zu müssen.

Hinweis

Einer der wichtigsten Aspekte bei der Gestaltung einer Datenstruktur für eine PIDL besteht darin, dass die Struktur persistent und übertragbar sein muss. Im Zusammenhang mit PIDLs haben diese Begriffe folgende Bedeutung:

  • Persistent. Das System platziert häufig PIDLs in verschiedenen Arten von langfristigem Speicher, beispielsweise in Verknüpfungsdateien. Es kann diese PIDLs dann später aus dem Speicher wiederherstellen, möglicherweise nach einem Neustart des Systems. Eine aus dem Speicher wiederhergestellte PIDL muss für Ihre Erweiterung weiterhin gültig und aussagekräftig sein. Diese Anforderung bedeutet beispielsweise, dass Sie keine Zeiger oder Handles in Ihrer PIDL-Struktur verwenden sollten. PIDLs, die diese Art von Daten enthalten, sind in der Regel bedeutungslos, wenn das System sie später aus dem Speicher wiederherstellt.
  • Übertragbar. Eine PIDL muss aussagekräftig bleiben, wenn sie von einem Computer auf einen anderen übertragen wird. So kann eine PIDL beispielsweise in eine Verknüpfungsdatei geschrieben, auf einen Datenträger kopiert und auf einen anderen Computer übertragen werden. Diese PIDL sollte für Ihre Erweiterung, die auf dem zweiten Computer ausgeführt wird, dennoch aussagekräftig sein. Um beispielsweise sicherzustellen, dass Ihre PIDLs übertragbar sind, sollten Sie explizit ANSI- oder Unicode-Zeichen verwenden. Vermeiden Sie Datentypen wie TCHAR oder LPTSTR. Wenn Sie diese Datentypen verwenden, kann eine PIDL, die auf einem Computer mit einer Unicode-Version Ihrer Erweiterung erstellt wurde, nicht von einer ANSI-Version dieser Erweiterung gelesen werden, die auf einem anderen Computer ausgeführt wird.

 

Die folgende Deklaration zeigt ein einfaches Beispiel einer Datenstruktur.

typedef struct tagMYPIDLDATA {
  USHORT cb;
  DWORD dwType;
  WCHAR wszDisplayName[40];
} MYPIDLDATA, *LPMYPIDLDATA;

Für das cb-Element wird die Größe der MYPIDLDATA-Struktur festgelegt. Dieses Element macht MYPIDLDATA zu einer gültigen SHITEMID-Struktur. Die restlichen Elemente entsprechen dem abID-Element einer SHITEMID-Struktur und enthalten private Daten. Das dwType-Element ist ein von der Erweiterung definierter Wert, der den Typ des Objekts angibt. In diesem Beispiel ist dwType für Ordner auf TRUE und andernfalls auf FALSE gesetzt. Anhand dieses Elements können Sie beispielsweise schnell ermitteln, ob es sich bei dem Objekt um einen Ordner handelt oder nicht. Das wszDisplayName-Element enthält den Anzeigenamen des Objekts. Da Sie nicht zwei Objekten im selben Ordner denselben Anzeigenamen zuweisen würden, dient der Anzeigename auch als Objekt-ID. In diesem Beispiel ist wszDisplayName auf 40 Zeichen festgelegt, um sicherzustellen, dass die SHITEMID-Struktur auf DWORD ausgerichtet sein wird. Um die Größe Ihrer PIDLs zu beschränken, können Sie stattdessen ein Zeichenarray mit variabler Länge verwenden und den Wert von cb entsprechend anpassen. Füllen Sie die Anzeigezeichenfolge mit genügend '\0'-Zeichen auf, um die DWORD-Ausrichtung der Struktur beizubehalten. Andere Elemente, die in die Struktur aufgenommen werden können, sind die Größe, Attribute oder der Analysename des Objekts.

Erstellen einer PIDL

Nachdem Sie SHITEMID-Strukturen für Ihre Objekte definiert haben, können Sie diese zum Erstellen einer PIDL verwenden. PIDLs können für eine Vielzahl von Zwecken erstellt werden, für die meisten Aufgaben wird jedoch einer von zwei PIDL-Typen verwendet. Am einfachsten identifiziert eine PIDL mit einer Ebene das Objekt relativ zu seinem übergeordneten Ordner. Dieser PIDL-Typ wird von vielen IShellFolder-Methoden verwendet. Eine PIDL mit einer Ebene enthält die SHITEMID-Struktur des Objekts, gefolgt von einem Abschlusszeichen. Eine vollqualifizierte PIDL definiert einen Pfad durch die Namespacehierarchie vom Desktop zum Objekt. Dieser PIDL-Typ beginnt auf dem Desktop und enthält eine SHITEMID-Struktur für jeden Ordner im Pfad, gefolgt von dem Objekt und dem Abschlusszeichen. Eine vollqualifizierte PIDL identifiziert das Objekt innerhalb des gesamten Shell-Namespace eindeutig.

Die einfachste Möglichkeit zum Erstellen einer PIDL besteht darin, direkt mit der ITEMIDLIST-Struktur zu arbeiten. Erstellen Sie eine ITEMIDLIST-Struktur, weisen Sie jedoch genügend Arbeitsspeicher zu, um alle SHITEMID-Strukturen zu speichern. Die Adresse dieser Struktur verweist auf die anfängliche SHITEMID-Struktur. Definieren Sie Werte für die Elemente dieser anfänglichen Struktur, und fügen Sie dann so viele weitere SHITEMID-Strukturen wie nötig in der entsprechenden Reihenfolge an. Das folgende Verfahren beschreibt, wie eine PIDL mit einer Ebene erstellt wird. Sie enthält zwei SHITEMID-Strukturen – eine MYPIDLDATA-Struktur, gefolgt von einem Abschlusszeichen:

  1. Verwenden Sie die Funktion CoTaskMemAlloc, um Speicher für die PIDL zuzuweisen. Weisen Sie genügend Arbeitsspeicher für Ihre privaten Daten sowie ein USHORT (zwei Bytes) für das Abschlusszeichen zu. Wandeln Sie das Ergebnis in LPMYPIDLDATA um.
  2. Legen Sie für das cb-Element der ersten MYPIDLDATA-Struktur die Größe dieser Struktur fest. In diesem Beispiel würden Sie für cb „sizeof(MYPIDLDATA)“ festlegen. Wenn Sie eine Struktur mit variabler Länge verwenden möchten, müssen Sie den Wert von cb berechnen.
  3. Weisen Sie den privaten Datenmembern geeignete Werte zu.
  4. Berechnen Sie die Adresse der nächsten SHITEMID-Struktur. Wandeln Sie die Adresse der aktuellen MYPIDLDATA-Struktur in LPBYTE um, und fügen Sie diesen Wert zu dem in Schritt 3 ermittelten Wert von cb hinzu.
  5. In diesem Fall ist die nächste SHITEMID-Struktur das Abschlusszeichen. Legen Sie für das cb-Element der Struktur Null fest.

Weisen Sie für längere PIDLs ausreichend Arbeitsspeicher zu, und wiederholen Sie die Schritte 3 bis 5 für jede weitere SHITEMID-Struktur.

Die folgende Beispielfunktion verwendet den Typ und den Anzeigenamen eines Objekts und gibt die PIDL mit einer Ebene des Objekts zurück. Die Funktion geht davon aus, dass der Anzeigename, einschließlich des Null-Abschlusszeichens, die für die MYPIDLDATA-Struktur deklarierte Zeichenzahl nicht überschreitet. Wenn sich diese Annahme als falsch erweist, schneidet die StringCbCopyW-Funktion den Anzeigenamen ab. Die Variable g_pMalloc ist ein IMalloc-Zeiger, der an anderer Stelle erstellt wurde und in einer globalen Variablen gespeichert ist.

LPITEMIDLIST CreatePIDL(DWORD dwType, LPCWSTR pwszDisplayName)
{
    LPMYPIDLDATA   pidlOut;
    USHORT         uSize;

    pidlOut = NULL;

    //Calculate the size of the MYPIDLDATA structure.
    uSize = sizeof(MYPIDLDATA);

    // Allocate enough memory for the PIDL to hold a MYPIDLDATA structure 
    // plus the terminator
    pidlOut = (LPMYPIDLDATA)m_pMalloc->Alloc(uSize + sizeof(USHORT));

    if(pidlOut)
    {
       //Assign values to the members of the MYPIDLDATA structure
       //that is the PIDL's first SHITEMID structure
       pidlOut->cb = uSize;
       pidlOut->dwType = dwType;
       hr = StringCbCopyW(pidlOut->wszDisplayName, 
                          sizeof(pidlOut->wszDisplayName), pwszDisplayName);
       
       // TODO: Add error handling here to verify the HRESULT returned 
       // by StringCbCopyW.

       //Advance the pointer to the start of the next SHITEMID structure.
       pidlOut = (LPMYPIDLDATA)((LPBYTE)pidlOut + pidlOut->cb);

       //Create the terminating null character by setting cb to 0.
       pidlOut->cb = 0;
    }

    return pidlOut;

Eine vollqualifizierte PIDL muss SHITEMID-Strukturen für jedes Objekt vom Desktop bis zu Ihrem Objekt aufweisen. Ihre Erweiterung erhält eine vollqualifizierte PIDL für Ihren Stammordner, wenn die Shell IPersistFolder::Initialize aufruft. Um eine vollqualifizierte PIDL für ein Objekt zu erstellen, fügen Sie der PIDL, die die Shell Ihrem Stammordner zugewiesen hat, die nötigen SHITEMID-Strukturen an, um vom Stammordner zum Objekt zu gelangen.

Interpretieren von PIDLs

Wenn die Shell oder eine Anwendung eine der Schnittstellen Ihrer Erweiterung aufruft, um Informationen zu einem Objekt anzufordern, wird das Objekt in der Regel durch eine PIDL identifiziert. Einige Methoden, wie z. B. IShellFolder::GetUIObjectOf, verwenden relative PIDLs zum übergeordneten Ordner, die einfach zu interpretieren sind. Ihre Erweiterung erhält jedoch wahrscheinlich auch vollqualifizierte PIDLs. Ihr PIDL-Manager muss dann bestimmen, auf welche Objekte die betreffende PIDL verweist.

Ein Objekt mit einer vollqualifizierten PIDL zu verknüpfen, ist deshalb so schwierig, da mindestens eine der anfänglichen SHITEMID-Strukturen in der PIDL zu Objekten außerhalb Ihrer Erweiterung im Shell-Namespace gehören kann. Sie haben keine Möglichkeit, die Bedeutung des abID-Elements dieser Strukturen zu interpretieren. Ihre Erweiterung muss die Liste der SHITEMID-Strukturen bis zu der Struktur, die Ihrem Stammordner entspricht, durchgehen. Von da an wissen Sie, wie Sie die Informationen in den SHITEMID-Strukturen interpretieren können.

Um die PIDL durchzugehen, nehmen Sie den ersten cb-Wert, und fügen Sie ihn der Adresse der PIDL hinzu, um den Zeiger an den Anfang der nächsten SHITEMID-Struktur zu setzen. Er zeigt dann auf das cb-Element dieser Struktur, das Sie verwenden können, um den Zeiger an den Anfang der nächsten SHITEMID-Struktur zu setzen usw. Überprüfen Sie jedes Mal, wenn Sie den Zeiger weiterbewegen, die SHITEMID-Struktur, um herauszufinden, ob Sie den Stamm des Namespace Ihrer Erweiterung erreicht haben.

Implementieren der primären Schnittstellen

Wie bei allen COM-Objekten gilt: Bei der Implementierung einer Erweiterung handelt es sich im Wesentlichen um die Implementierung einer Sammlung von Schnittstellen. In diesem Abschnitt werden die drei primären Schnittstellen erläutert, die von allen Erweiterungen implementiert werden müssen. Sie werden für die Initialisierung verwendet und stellen Windows-Explorer grundlegende Informationen zu den Inhalten der Erweiterung bereit. Diese Schnittstellen sowie eine Ordneransicht sind alles, was für eine funktionale Erweiterung erforderlich ist. Um jedoch die Funktionen von Windows-Explorer vollständig nutzen zu können, implementieren die meisten Erweiterungen auch eine oder mehrere der optionalen Schnittstellen.

IPersistFolder-Schnittstelle

Die IPersistFolder-Schnittstelle wird aufgerufen, um ein neues Ordnerobjekt zu initialisieren. Die Methode IPersistFolder::Initialize weist dem neuen Objekt eine vollqualifizierte PIDL zu. Speichern Sie diese PIDL zur späteren Verwendung. Ein Ordnerobjekt muss diese PIDL beispielsweise verwenden, um vollqualifizierte PIDLs für die untergeordneten Elemente des Objekts zu erstellen. Der Ersteller des Ordnerobjekts kann auch IPersist::GetClassID aufrufen, um die CLSID des Objekts anzufordern.

In der Regel wird ein Ordnerobjekt durch die Methode IShellFolder::BindToObject des übergeordneten Ordners erstellt und initialisiert. Wenn ein Benutzer jedoch zu Ihrer Erweiterung navigiert, erstellt und initialisiert Windows-Explorer das Stammordnerobjekt der Erweiterung. Die PIDL, die das Stammordnerobjekt über IPersistFolder::Initialize empfängt, enthält den Pfad vom Desktop zum Stammordner, den Sie zum Erstellen vollqualifizierter PIDLs für Ihre Erweiterung benötigen.

IShellFolder-Schnittstelle

Die Shell behandelt eine Erweiterung als eine hierarchisch geordnete Sammlung von Ordnerobjekten. Die IShellFolder-Schnittstelle bildet den Kern jeder Erweiterungsimplementierung. Sie stellt ein Ordnerobjekt dar und stellt Windows-Explorer einen Großteil der Informationen zur Verfügung, die zum Anzeigen der Inhalte des Ordners benötigt werden.

IShellFolder ist in der Regel die einzige Ordnerschnittstelle außer IPersistFolder, die direkt von einem Ordnerobjekt verfügbar gemacht wird. Windows-Explorer verwendet zwar eine Vielzahl von erforderlichen und optionalen Schnittstellen, um Informationen über die Inhalte des Ordners abzurufen, Zeiger auf diese Schnittstellen werden jedoch über IShellFolder abgerufen.

Windows-Explorer ruft die CLSID des Stammordners Ihrer Erweiterung auf verschiedene Weise ab. Ausführliche Informationen finden Sie unter Angeben des Speicherorts einer Namespaceerweiterung oder Anzeigen einer eigenständigen Ansicht einer Namespaceerweiterung. Windows-Explorer verwendet dann diese CLSID, um eine Instanz des Stammordners zu erstellen und zu initialisieren und eine IShellFolder-Schnittstelle abzufragen. Die Erweiterung erstellt ein Ordnerobjekt, das den Stammordner darstellt, und gibt die IShellFolder-Schnittstelle des Objekts zurück. Die weitere Interaktion zwischen Ihrer Erweiterung und Windows-Explorer erfolgt dann großenteils über IShellFolder. Windows-Explorer ruft IShellFolder zu folgenden Zwecken auf:

  • Anfordern eines Objekts, das die Inhalte des Stammordners aufzählen kann.
  • Abrufen verschiedener Arten von Informationen über die Inhalte des Stammordners.
  • Anfordern eines Objekts, das eine der optionalen Schnittstellen zur verfügbar macht. Diese Schnittstellen können dann nach zusätzlichen Informationen, wie z. B. Symbolen oder Kontextmenüs, abgefragt werden.
  • Anfordern eines Ordnerobjekts, das einen Unterordner des Stammordners darstellt.

Wenn ein Benutzer einen Unterordner des Stammordners öffnet, ruft Windows-Explorer IShellFolder::BindToObject auf. Die Erweiterung erstellt und initialisiert ein neues Ordnerobjekt, um den Unterordner darzustellen, und gibt seine IShellFolder-Schnittstelle zurück. Windows-Explorer ruft diese Schnittstelle dann für verschiedene Arten von Informationen auf, bis der Benutzer entscheidet, zu einer anderen Stelle im Shell-Namespace zu navigieren oder Windows-Explorer zu schließen.

Im verbleibenden Teil dieses Abschnitts werden die wichtigeren IShellFolder-Methoden und ihre Implementierung kurz erläutert.

EnumObjects

Bevor die Inhalte eines Ordners in der Strukturansicht angezeigt werden, muss Windows-Explorer zunächst herausfinden, was der Ordner enthält. Hierfür wird die Methode IShellFolder::EnumObjects aufgerufen. Diese Methode erstellt ein standardmäßiges OLE-Enumerationsobjekt, das eine IEnumIDList-Schnittstelle verfügbar macht und diesen Schnittstellenzeiger zurückgibt. Die IEnumIDList-Schnittstelle ermöglicht Windows-Explorer das Abrufen der PIDLs aller Objekte, die im Ordner enthalten sind. Diese PIDLs werden dann verwendet, um Informationen zu den in dem Ordner enthaltenen Objekten abzurufen. Weitere Informationen finden Sie unter IEnumIDList-Schnittstelle.

Hinweis

Die Methode IEnumIDList::Next sollte nur relative PIDLs zum übergeordneten Ordner zurückgeben. Die PIDL sollte nur die SHITEMID-Struktur des Objekts enthalten, gefolgt von einem Abschlusszeichen.

 

CreateViewObject

Bevor die Inhalte eines Ordners angezeigt werden, ruft Windows-Explorer diese Methode auf, um einen Zeiger auf eine IShellView-Schnittstelle anzufordern. Diese Schnittstelle wird von Windows-Explorer zum Verwalten der Ordneransicht verwendet. Erstellen Sie ein Ordneransichtsobjekt, und geben Sie die IShellView-Schnittstelle zurück.

Die Methode IShellFolder::CreateViewObject wird auch aufgerufen, um eine der optionalen Schnittstellen wie z. B. IContextMenu für den Ordner selbst anzufordern. Die Implementierung dieser Methode sollte ein Objekt erstellen, das die angeforderte Schnittstelle verfügbar macht und den Schnittstellenzeiger zurückgibt. Wenn Windows-Explorer eine optionale Schnittstelle für eines der in dem Ordner enthaltenen Objekte benötigt, wird IShellFolder::GetUIObjectOf aufgerufen.

GetUIObjectOf

Während grundlegende Informationen zu den Inhalten eines Ordners über die IShellFolder-Methoden verfügbar sind, kann Ihre Erweiterung Windows-Explorer zudem verschiedene Arten von weiteren Informationen bereitstellen. Sie können beispielsweise Symbole für die Inhalte eines Ordners oder das Kontextmenü eines Objekts angeben. Windows-Explorer ruft die Methode IShellFolder::GetUIObjectOf auf, um weitere Informationen zu einem Objekt abzurufen, das in einem Ordner enthalten ist. Windows-Explorer gibt das Objekt, zu dem Informationen benötigt werden, sowie die IID der betreffenden Schnittstelle an. Das Ordnerobjekt erstellt dann ein Objekt, das die angeforderte Schnittstelle verfügbar macht und den Schnittstellenzeiger zurückgibt.

Wenn es Ihre Erweiterung Benutzern ermöglicht, Objekte mit Drag & Drop oder über die Zwischenablage zu übertragen, ruft Windows-Explorer IShellFolder::GetUIObjectOf auf, um eine IDataObject- oder IDropTarget-Schnittstelle anzufordern. Ausführliche Informationen finden Sie unter Übertragen von Shellobjekten mit Drag & Drop und der Zwischenablage.

Windows-Explorer ruft IShellFolder::CreateViewObject auf, um dieselbe Art von Informationen über den Ordner selbst abzurufen.

BindToObject

Windows-Explorer ruft die Methode IShellFolder::BindToObject auf, wenn ein Benutzer versucht, einen der Unterordner Ihrer Erweiterung zu öffnen. Wenn für riid „IID_IShellFolder“ festgelegt ist, sollten Sie ein Ordnerobjekt erstellen und initialisieren, das den Unterordner darstellt, und die IShellFolder-Schnittstelle des Objekts zurückgeben.

Hinweis

Derzeit ruft Windows-Explorer diese Methode nur auf, um eine IShellFolder-Schnittstelle anzufordern. Sie sollten jedoch nicht davon ausgehen, dass dies immer der Fall sein wird. Bevor Sie fortfahren, sollten Sie immer den Wert von riid überprüfen.

 

GetDisplayNameOf

Windows-Explorer ruft die Methode IShellFolder::GetDisplayNameOf auf, um die PIDL eines der Objekte des Ordners in einen Namen zu konvertieren. Dabei muss es sich um eine relative PIDL zum übergeordneten Ordner des Objekts handeln. Mit anderen Worten: Sie muss eine einzelne Nicht-NULL-SHITEMID-Struktur enthalten. Da Objekte auf verschiedene Arten benannt werden können, gibt Windows-Explorer die Art des Namens durch Festlegung eines oder mehrerer SHGDNF-Flags im Parameter uFlags an. Es wird einer von zwei Werten, SHGDN_NORMAL oder SHGDN_INFOLDER, festgelegt, um anzugeben, ob der Name relativ zum Ordner oder relativ zum Desktop sein soll. Einer der anderen drei Werte, SHGDN_FOREDITING, SHGDN_FORADDRESSBAR oder SHGDN_FORPARSING, kann festgelegt werden, um anzugeben, wofür der Name verwendet wird.

Sie müssen den Namen in Form einer STRRET-Struktur zurückgeben. Wenn SHGDN_FOREDITING, SHGDN_FORADDRESSBAR und SHGDN_FORPARSING nicht festgelegt sind, geben Sie den Anzeigenamen des Objekts zurück. Wenn das Flag SHGDN_FORPARSING festgelegt ist, fordert Windows-Explorer einen Analysenamen an. Analysenamen werden an IShellFolder::P arseDisplayName übergeben, um die PIDL eines Objekts abzurufen, auch wenn sich diese möglicherweise eine oder mehrere Ebenen unterhalb des aktuellen Ordners in der Namespacehierarchie befindet. Der Analysename eines Dateisystemobjekts ist beispielsweise sein Pfad. Sie können den vollqualifizierten Pfad eines Objekts im Dateisystem an die Methode IShellFolder::ParseDisplayName des Desktops übergeben, und diese wird die vollqualifizierte PIDL des Objekts zurückgeben.

Zwar handelt es sich bei Analysenamen um Textzeichenfolgen, sie müssen jedoch nicht unbedingt den Anzeigenamen enthalten. Sie sollten bei der Zuweisung von Analysenamen darauf achten, was beim Aufruf von IShellFolder::P arseDisplayName am effizientesten ist. So sind beispielsweise viele der virtuellen Ordner der Shell nicht Teil des Dateisystems und verfügen nicht über einen vollqualifizierten Pfad. Stattdessen wird jedem Ordner eine GUID zugewiesen, und der Analysename hat das Format ::{GUID}. Unabhängig davon, welches Schema Sie verwenden, sollte es in der Lage sein, einen zuverlässigen „Roundtrip“ durchzuführen. Wenn ein Aufrufer beispielsweise einen Analysenamen an IShellFolder::P arseDisplayName übergibt, um die PIDL eines Objekts abzurufen, und dann diese PIDL an IShellFolder::GetDisplayNameOf mit festgelegtem Flag SHGDN_FORPARSING übergibt, sollte der Aufrufer den ursprünglichen Analysenamen wiederherstellen.

GetAttributesOf

Windows-Explorer ruft die Methode IShellFolder::GetAttributesOf auf, um die Attribute eines oder mehrerer Elemente zu bestimmen, die in einem Ordnerobjekt enthalten sind. Der Wert von cidl gibt die Anzahl der Elemente in der Abfrage an, und aPidl verweist auf eine Liste ihrer PIDLs.

Da das Testen für einige Attribute zeitaufwendig sein kann, beschränkt Windows-Explorer die Abfrage in der Regel auf eine Teilmenge der verfügbaren Flags und legt zu diesem Zweck ihre Werte in rfgInOut fest. Ihre Methode sollte nur auf die Attribute testen, deren Flags in rfgInOut festgelegt sind. Lassen Sie die gültigen Flags festgelegt, und löschen Sie die übrigen. Wenn mehr als ein Element in der Abfrage enthalten ist, legen Sie nur die Flags fest, die für alle Elemente gelten.

Hinweis

Die Attribute müssen ordnungsgemäß festgelegt werden, damit ein Element ordnungsgemäß angezeigt wird. Wenn es sich bei einem Element beispielsweise um einen Ordner mit Unterordnern handelt, müssen Sie das Flag SFGAO_HASSUBFOLDER festlegen. Andernfalls zeigt Windows-Explorer in der Strukturansicht kein + neben dem Elementsymbol an.

 

ParseDisplayName

Die Methode IShellFolder::P arseDisplayName ist in gewisser Weise ein Spiegelbild von IShellFolder::GetDisplayNameOf. Die häufigste Verwendung dieser Methode besteht darin, den Analysenamen eines Objekts in die zugeordnete PIDL zu konvertieren. Der Analysename kann auf jedes Objekt verweisen, das sich unter dem Ordner in der Namespacehierarchie befindet. Die zurückgegebene PIDL ist relativ zu dem Ordnerobjekt, das die Methode verfügbar macht, und ist in der Regel nicht vollqualifiziert. Mit anderen Worten: Zwar kann die PIDL mehrere SHITEMID-Strukturen enthalten, die erste ist jedoch entweder die des Objekts selbst oder des ersten Unterordners im Pfad vom Ordner zum Objekt. Der Aufrufer muss diese PIDL an die vollqualifizierte PIDL des Ordners anfügen, um eine vollqualifizierte PIDL für das Objekt zu erhalten.

IShellFolder::P arseDisplayName kann auch aufgerufen werden, um die Attribute eines Objekts anzufordern. Da das Ermitteln aller anwendbaren Attribute zeitaufwendig sein kann, legt der Aufrufer nur die SFGAO_XXX-Flags fest, die Informationen darstellen, an denen der Aufrufer interessiert ist. Sie sollten bestimmen, welche dieser Attribute für das Objekt zutreffen, und die verbleibenden Flags löschen.

IEnumIDList-Schnittstelle

Wenn Windows-Explorer die in einem Ordner enthaltenen Objekte aufzählen muss, wird IShellFolder::EnumObjects aufgerufen. Das Ordnerobjekt muss ein Enumerationsobjekt erstellen, das die IEnumIDList-Schnittstelle verfügbar macht, und diesen Schnittstellenzeiger zurückgeben. Windows-Explorer verwendet iEnumIDList dann in der Regel zum Aufzählen der PIDLs aller Objekte, die im Ordner enthalten sind.

IEnumIDList ist eine standardmäßige OLE-Enumerationsschnittstelle und wird in der üblichen Weise implementiert. Beachten Sie jedoch, dass die zurückgegebenen PIDLs relativ zum Ordner sein müssen und nur die SHITEMID-Struktur des Objekts und ein Abschlusszeichen enthalten dürfen.

Implementieren der optionalen Schnittstellen

Die Ordnerobjekte Ihrer Erweiterung können eine Reihe von optionalen Shellschnittstellen unterstützen. Viele von ihnen, wie z. B. IExtractIcon, ermöglichen es Ihnen, die Art und Weise, wie der Benutzer Ihre Erweiterung sieht, in verschiedener Hinsicht anzupassen. Andere, wie z. B. IDataObject, ermöglichen es Ihrer Erweiterung, Features wie Drag & Drop zu unterstützen.

Keine der optionalen Schnittstellen wird direkt von einem Ordnerobjekt verfügbar gemacht. Windows-Explorer ruft vielmehr eine von zwei IShellFolder-Methoden auf, um eine Schnittstelle anzufordern:

  • Windows-Explorer ruft IShellFolder::GetUIObjectOf eines Ordnerobjekts auf, um eine Schnittstelle für eines der im Ordner enthaltenen Objekte anzufordern.
  • Windows-Explorer ruft IShellFolder::CreateViewObject eines Ordnerobjekts auf, um eine Schnittstelle für den Ordner selbst anzufordern.

Um die Informationen bereitzustellen, erstellt das Ordnerobjekt ein Objekt, das die angeforderte Schnittstelle verfügbar macht und den Schnittstellenzeiger zurückgibt. Windows-Explorer ruft dann diese Schnittstelle auf, um die erforderlichen Informationen abzurufen. In diesem Abschnitt werden die am häufigsten verwendeten optionalen Schnittstellen erläutert.

IExtractIcon

Windows-Explorer fordert eine IExtractIcon-Schnittstelle an, bevor die Inhalte eines Ordners angezeigt werden. Die Schnittstelle ermöglicht es Ihrer Erweiterung, benutzerdefinierte Symbole für die Objekte anzugeben, die im Ordner enthalten sind. Andernfalls werden die Standardsymbole für Dateien und Ordner verwendet. Um ein benutzerdefiniertes Symbol bereitzustellen, erstellen Sie ein Symbolextraktionsobjekt, das IExtractIcon verfügbar macht, und geben Sie einen Zeiger auf diese Schnittstelle zurück. Weitere Informationen finden Sie in der Referenzdokumentation zu IExtractIcon oder unter Erstellen von Symbolhandlern.

IContextMenu

Wenn ein Benutzer mit der rechten Maustaste auf ein Objekt klickt, fordert Windows-Explorer eine IContextMenu-Schnittstelle an. Um Kontextmenüs für Ihre Objekte bereitzustellen, erstellen Sie ein Menühandlerobjekt, und geben Sie seine IContextMenu-Schnittstelle zurück.

Die Verfahren zum Erstellen eines Menühandlerobjekts sind den Verfahren zum Erstellen einer Menühandler-Shellerweiterung sehr ähnlich. Ausführliche Informationen finden Sie unter Erstellen von Kontextmenühandlern oder in der Referenz zu IContextMenu, IContextMenu2 oder IContextMenu3.

IQueryInfo

Windows-Explorer ruft die IQueryInfo-Schnittstelle auf, um eine Infotipp-Textzeichenfolge abzurufen.

IDataObject und IDropTarget

Wenn Ihre Objekte von Windows-Explorer angezeigt werden, hat ein Ordnerobjekt keine direkte Möglichkeit, zu wissen, wann ein Benutzer versucht, ein Objekt auszuschneiden, zu kopieren oder zu ziehen. Stattdessen fordert Windows-Explorer eine IDataObject-Schnittstelle an. Damit das Objekt übertragen werden kann, erstellen Sie ein Datenobjekt, und geben Sie einen Zeiger auf die IDataObject-Schnittstelle zurück.

In ähnlicher Weise kann ein Benutzer versuchen, ein Datenobjekt in einer Windows-Explorer-Darstellung von einem Ihrer Objekte, beispielsweise einem Symbol oder einem Adressleistenpfad, abzulegen. Windows-Explorer fordert dann eine IDropTarget-Schnittstelle an. Damit das Datenobjekt abgelegt werden kann, erstellen Sie ein Objekt, das eine IDropTarget-Schnittstelle verfügbar macht, und geben den Schnittstellenzeiger zurück.

Die Verarbeitung der Datenübertragung gehört zu den komplizierteren Aspekten des Schreibens von Namespaceerweiterungen. Eine ausführliche Erläuterung finden Sie unter Übertragen von Shellobjekten mit Drag & Drop und der Zwischenablage.

Arbeiten mit der Standardimplementierung der Shellordneransicht

Datenquellen, die das standardmäßige Shell-Ordneransichtsobjekt (DefView) verwenden, müssen diese Schnittstellen implementieren:

Optional können sie auch IPersistFolder3 implementieren.