Shelldatenobjekt

Das Datenobjekt ist für alle Shell-Datenübertragungen zentral. Es handelt sich in erster Linie um einen Container, in dem die übertragenen Daten gespeichert werden. Das Ziel kann jedoch auch mit dem Datenobjekt kommunizieren, um einige spezialisierte Arten der Shell-Datenübertragung zu ermöglichen, z. B. optimierte Verschiebungen. In diesem Thema wird allgemein erläutert, wie Shell-Datenobjekte funktionieren, wie sie von einer Quelle erstellt werden und wie sie von einem Ziel behandelt werden. Eine ausführliche Erläuterung der Verwendung von Datenobjekten zum Übertragen verschiedener Shelldatentypen finden Sie unter Behandeln von Shell-Datenübertragungsszenarien.

Funktionsweise von Datenobjekten

Datenobjekte sind COM-Objekte (Component Object Model), die von der Datenquelle zum Übertragen von Daten an ein Ziel erstellt werden. Sie enthalten in der Regel mehr als ein Datenelement. Für diese Praxis gibt es zwei Gründe:

  • Während fast jeder Datentyp mit einem Datenobjekt übertragen werden kann, weiß die Quelle in der Regel nicht, welche Art von Daten das Ziel akzeptieren kann. Bei instance können die Daten ein Teil eines formatierten Textdokuments sein. Das Ziel kann zwar komplexe Formatierungsinformationen verarbeiten, kann aber auch nur ANSI-Text akzeptieren. Aus diesem Grund enthalten Datenobjekte häufig dieselben Daten in verschiedenen Formaten. Das Ziel kann dann die Daten in einem Format extrahieren, das es verarbeiten kann.
  • Datenobjekte können auch zusätzliche Datenelemente enthalten, die keine Versionen von Quelldaten sind. Diese Art von Datenelement stellt in der Regel zusätzliche Informationen zum Datenübertragungsvorgang bereit. Für instance verwendet die Shell zusätzliche Datenelemente, um anzugeben, ob eine Datei kopiert oder verschoben werden soll.

Zwischenablageformate

Jedes Datenelement in einem Datenobjekt weist ein zugeordnetes Format auf, das in der Regel als Zwischenablageformat bezeichnet wird. Es gibt eine Reihe von Standard-Zwischenablageformaten, die in Winuser.h deklariert sind und den häufig verwendeten Datentypen entsprechen. Bei Zwischenablageformaten handelt es sich um ganze Zahlen, aber sie werden normalerweise mit ihrem entsprechenden Namen bezeichnet, der die Form CF_XXX aufweist. Für instance ist das Zwischenablageformat für ANSI-Text CF_TEXT.

Anwendungen können den Bereich der verfügbaren Zwischenablageformate erweitern, indem sie private Formate definieren. Um ein privates Format zu definieren, ruft eine Anwendung RegisterClipboardFormat mit einer Zeichenfolge auf, die das Format identifiziert. Die ganze Zahl ohne Vorzeichen, die die Funktion zurückgibt, ist ein gültiger Formatwert, der genau wie ein Standardformat für die Zwischenablage verwendet werden kann. Das Format muss jedoch sowohl für die Quelle als auch für das Ziel registriert werden, um es verwenden zu können. Mit einer Ausnahme – CF_HDROP – werden die Zum Übertragen von Shelldaten verwendeten Zwischenablageformate als private Formate definiert. Sie müssen von der Quelle und dem Ziel registriert werden, bevor sie verwendet werden können. Eine Beschreibung der verfügbaren Shell-Zwischenablageformate finden Sie unter Shell-Zwischenablageformate.

Obwohl es einige Ausnahmen gibt, enthalten Datenobjekte normalerweise nur ein Datenelement für jedes unterstützte Zwischenablageformat. Durch diese 1:1-Korrelation zwischen Format und Daten kann der Formatwert als Bezeichner für das zugeordnete Datenelement verwendet werden. In der Tat wird ein bestimmtes Datenelement beim Diskutieren des Inhalts eines Datenobjekts in der Regel als "Format" bezeichnet und durch seinen Formatnamen verwiesen. Beispielsweise Ausdrücke wie "Extrahieren des CF_TEXT-Formats..." werden in der Regel verwendet, wenn das ANSI-Textdatenelement eines Datenobjekts besprochen wird.

Wenn das Ablageziel den Zeiger auf das Datenobjekt empfängt, listet das Ablageziel die verfügbaren Formate auf, um zu bestimmen, welche Datentypen verfügbar sind. Anschließend werden eines oder mehrere der verfügbaren Formate angefordert und die Daten extrahiert. Die spezifische Art und Weise, wie das Ziel Shelldaten aus einem Datenobjekt extrahiert, variiert je nach Format. dies wird ausführlich in Der Umgang mit einem Ziel für ein Datenobjekt erläutert.

Bei einfachen Zwischenablagedatenübertragungen werden die Daten in einem globalen Speicherobjekt platziert. Die Adresse dieses Objekts wird zusammen mit dem Format in der Zwischenablage platziert. Das Zwischenablageformat teilt dem Ziel mit, welche Art von Daten es an der zugeordneten Adresse finden wird. Während einfache Zwischenablageübertragungen einfach zu implementieren sind:

  • Datenobjekte bieten eine viel flexiblere Möglichkeit zum Übertragen von Daten.
  • Datenobjekte eignen sich besser für die Übertragung großer Datenmengen.
  • Datenobjekte müssen verwendet werden, um Daten mit einem Drag-and-Drop-Vorgang zu übertragen.

Aus diesen Gründen verwenden alle Shell-Datenübertragungen Datenobjekte. Bei Datenobjekten werden Zwischenablageformate nicht direkt verwendet. Stattdessen werden Datenelemente mit einer Generalisierung des Zwischenablageformats identifiziert, einer FORMATTC-Struktur .

FORMATETC-Struktur

Die FORMATETC-Struktur ist eine erweiterte Version eines Zwischenablageformats. Wie für Shell-Datenübertragungen verwendet, weist die FORMATETC-Struktur die folgenden Merkmale auf:

  • Ein Datenelement wird weiterhin durch sein Zwischenablageformat im cfFormat-Element identifiziert.

  • Die Datenübertragung ist nicht auf globale Speicherobjekte beschränkt. Das tymed-Element wird verwendet, um den Datenübertragungsmechanismus anzugeben, der in der zugeordneten STGMEDIUM-Struktur enthalten ist. Es ist auf einen der TYMED_XXX Werte festgelegt.

  • Die Shell verwendet den lIndex-Member mit seinem CFSTR_FILECONTENTS Format, damit ein Datenobjekt mehr als ein Datenelement pro Format enthalten kann. Eine Erläuterung der Verwendung dieses Formats finden Sie im Abschnitt Verwenden des CFSTR_FILECONTENTS-Formats zum Extrahieren von Daten aus einer Datei unter Behandeln von Shell-Datenübertragungsszenarien.

  • Das dwAspect-Element ist in der Regel auf DVASPECT_CONTENT festgelegt. Es sind jedoch drei Werte in Shlobj.h definiert, die für die Shell-Datenübertragung verwendet werden können.

    Wert BESCHREIBUNG
    DVASPECT_COPY Wird verwendet, um anzugeben, dass das Format eine Kopie der Daten darstellt.
    DVASPECT_LINK Wird verwendet, um anzugeben, dass das Format eine Verknüpfung zu den Daten darstellt.
    DVASPECT_SHORTNAME Wird mit dem CF_HDROP-Format verwendet, um einen Dateipfad mit den Namen anzufordern, die auf das Format 8.3 gekürzt sind.

     

  • Der ptd-Member wird nicht für Shell-Datenübertragungen verwendet und ist normalerweise auf NULL festgelegt.

STGMEDIUM-Struktur

Die STGMEDIUM-Struktur ermöglicht den Zugriff auf die übertragenen Daten. Für Shelldaten werden drei Datenübertragungsmechanismen unterstützt:

Das tymed-Element der STGMEDIUM-Struktur ist ein TYMED_XXX Wert, der den Datenübertragungsmechanismus identifiziert. Das zweite Element ist ein Zeiger, der vom Ziel verwendet wird, um die Daten zu extrahieren. Der Zeiger kann einer von verschiedenen Typen sein, abhängig vom Tymed-Wert . Die drei Tymed-Werte , die für Shell-Datenübertragungen verwendet werden, sind in der folgenden Tabelle zusammen mit ihrem entsprechenden STGMEDIUM-Membernamen zusammengefasst.

tymed-Wert Membername Beschreibung
TYMED_HGLOBAL hGlobal Ein Zeiger auf ein globales Speicherobjekt. Dieser Zeigertyp wird in der Regel für die Übertragung kleiner Datenmengen verwendet. Für instance verwendet die Shell globale Speicherobjekte, um kurze Textzeichenfolgen wie Dateinamen oder URLs zu übertragen.
TYMED_ISTREAM pstm Ein Zeiger auf eine IStream-Schnittstelle . Dieser Zeigertyp wird für die meisten Shell-Datenübertragungen bevorzugt, da er im Vergleich zu TYMED_HGLOBAL relativ wenig Arbeitsspeicher benötigt. Außerdem erfordert der TYMED_ISTREAM Datenübertragungsmechanismus nicht, dass die Quelle ihre Daten in einer bestimmten Weise speichert.
TYMED_ISTORAGE pstg Ein Zeiger auf eine IStorage-Schnittstelle . Das Ziel ruft die Schnittstellenmethoden auf, um die Daten zu extrahieren. Wie TYMED_ISTREAM benötigt dieser Zeigertyp relativ wenig Arbeitsspeicher. Da TYMED_ISTORAGE jedoch weniger flexibel ist als TYMED_ISTREAM, wird es nicht so häufig verwendet.

 

Erstellen eines Datenobjekts durch eine Quelle

Wenn ein Benutzer eine Shell-Datenübertragung initiiert, ist die Quelle dafür verantwortlich, ein Datenobjekt zu erstellen und mit Daten zu laden. Im folgenden Verfahren wird der Prozess zusammengefasst:

  1. Rufen Sie RegisterClipboardFormat auf, um einen gültigen Zwischenablageformatwert für jedes Shell-Format zu erhalten, das in das Datenobjekt eingeschlossen wird. Denken Sie daran, dass CF_HDROP bereits ein gültiges Zwischenablageformat hat und nicht registriert werden muss.
  2. Legen Sie für jedes zu übertragende Format entweder die zugeordneten Daten in ein globales Speicherobjekt ein, oder erstellen Sie ein Objekt, das zugriff auf diese Daten über eine IStream - oder IStorage-Schnittstelle ermöglicht. Die IStream - und IStorage-Schnittstellen werden mithilfe von COM-Standardtechniken erstellt. Eine Erläuterung zum Behandeln von globalen Speicherobjekten finden Sie unter Hinzufügen eines globalen Speicherobjekts zu einem Datenobjekt.
  3. Erstellen Sie FORMATETC - und STGMEDIUM-Strukturen für jedes Format.
  4. Instanziieren sie ein Datenobjekt.
  5. Laden Sie die Daten in das Datenobjekt, indem Sie die IDataObject::SetData-Methode für jedes unterstützte Format aufrufen und die FORMATETC - und STGMEDIUM-Strukturen des Formats übergeben.
  6. Rufen Sie bei Zwischenablagedatenübertragungen OleSetClipboard auf, um einen Zeiger auf die IDataObject-Schnittstelle des Datenobjekts in der Zwischenablage zu platzieren. Initiieren Sie für Drag-and-Drop-Übertragungen eine Ziehschleife , indem Sie DoDragDrop aufrufen. Der IDataObject-Zeiger wird an das Ablageziel übergeben, wenn die Daten gelöscht werden, wodurch die Ziehschleife beendet wird.

Das Datenobjekt kann nun an das Ziel übertragen werden. Bei Zwischenablage-Datenübertragungen wird das Objekt einfach gehalten, bis das Ziel es durch Aufrufen von OleGetClipboard anfordert. Bei Drag-and-Drop-Datenübertragungen ist das Datenobjekt dafür verantwortlich, ein Symbol zu erstellen, um die Daten darzustellen, und sie zu verschieben, während der Benutzer den Cursor bewegt. Während sich das Objekt in der Ziehschleife befindet, empfängt die Quelle status Informationen über ihre IDropSource-Schnittstelle. Weitere Informationen finden Sie unter Implementieren von IDropSource.

Die Quelle erhält keine Benachrichtigung, wenn das Datenobjekt von einem Ziel aus der Zwischenablage abgerufen wird. Wenn ein Objekt durch einen Drag-and-Drop-Vorgang auf einem Ziel abgelegt wird, wird die DoDragDrop-Funktion zurückgegeben, die aufgerufen wurde, um die Ziehschleife zu initiieren.

Hinzufügen eines globalen Speicherobjekts zu einem Datenobjekt

Viele der Shell-Datenformate haben die Form eines globalen Speicherobjekts. Verwenden Sie das folgende Verfahren, um ein Format zu erstellen, das ein globales Speicherobjekt enthält, und laden Sie es in das Datenobjekt:

  1. Erstellen Sie eine FORMATTC-Struktur . Legen Sie den cfFormat-Member auf den entsprechenden Wert des Zwischenablageformats und das tymed-Element auf TYMED_HGLOBAL fest.
  2. Erstellen Sie eine STGMEDIUM-Struktur . Legen Sie das tymed-Element auf TYMED_HGLOBAL fest.
  3. Erstellen Sie ein globales Speicherobjekt, indem Sie GlobalAlloc aufrufen, um einen speichergerechten Block zuzuweisen.
  4. Weisen Sie den zu übertragenden Datenblock der von GlobalAlloc zurückgegebenen Adresse zu.
  5. Weisen Sie die Adresse des globalen Speicherobjekts dem hGlobal-Member der STGMEDIUM-Struktur zu.
  6. Laden Sie das Format in das Datenobjekt, indem Sie IDataObject::SetData aufrufen und die in den vorherigen Schritten erstellten FORMATETC - und STGMEDIUM-Strukturen übergeben.

Die folgende Beispielfunktion erstellt ein globales Speicherobjekt, das einen DWORD-Wert enthält, und lädt es in ein Datenobjekt. Der pdtobj-Parameter ist ein Zeiger auf die IDataObject-Schnittstelle des Datenobjekts, cf ist der Wert des Zwischenablageformats und dw der Datenwert.

STDAPI DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dw)
{
    FORMATETC fmte = {(CLIPFORMAT) cf, 
                      NULL, 
                      DVASPECT_CONTENT, 
                      -1, 
                      TYMED_HGLOBAL};
    STGMEDIUM medium;

    HRESULT hres = E_OUTOFMEMORY;
    DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
    
    if (pdw)
    {
        *pdw = dw;       
        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pdw;
        medium.pUnkForRelease = NULL;

        hres = pdtobj->SetData(&fmte, &medium, TRUE);
 
        if (FAILED(hres))
            GlobalFree((HGLOBAL)pdw);
    }
    return hres;
}

Implementieren von IDataObject

IDataObject ist die primäre Schnittstelle eines Datenobjekts. Sie muss von allen Datenobjekten implementiert werden. Es wird sowohl von Quelle als auch Ziel für eine Vielzahl von Zwecken verwendet, einschließlich:

  • Laden von Daten in das Datenobjekt.
  • Extrahieren von Daten aus dem Datenobjekt.
  • Bestimmen, welche Datentypen im Datenobjekt enthalten sind.
  • Bereitstellen von Feedback an das Datenobjekt zum Ergebnis der Datenübertragung.

IDataObject unterstützt eine Reihe von Methoden. In diesem Abschnitt wird erläutert, wie Sie die drei wichtigsten Methoden für Shell-Datenobjekte implementieren: SetData, EnumFormatEtc und GetData. Eine Erläuterung der anderen Methoden finden Sie in der IDataObject-Referenz .

SetData-Methode

Die primäre Funktion der IDataObject::SetData-Methode besteht darin, der Quelle das Laden von Daten in das Datenobjekt zu ermöglichen. Für jedes einzufingde Format erstellt die Quelle eine FORMATTC-Struktur , um das Format zu identifizieren, und eine STGMEDIUM-Struktur , die einen Zeiger auf die Daten enthält. Die Quelle ruft dann die IDataObject::SetData-Methode des Objekts auf und übergibt die FORMATETC - und STGMEDIUM-Strukturen des Formats. Die -Methode muss diese Informationen speichern, damit sie verfügbar sind, wenn das Ziel IDataObject::GetData aufruft, um Daten aus dem Objekt zu extrahieren.

Beim Übertragen von Dateien fügt die Shell jedoch häufig die Informationen für jede zu übertragende Datei in ein separates CFSTR_FILECONTENTS-Format ein. Um die verschiedenen Dateien zu unterscheiden, wird der lIndex-Member der FORMATTC-Struktur jeder Datei auf einen Indexwert festgelegt, der die jeweilige Datei identifiziert. Ihre IDataObject::SetData-Implementierung muss in der Lage sein, mehrere CFSTR_FILECONTENTS Formate zu speichern, die sich nur durch ihre lIndex-Member unterscheiden.

Während sich der Cursor über dem Zielfenster befindet, kann das Ziel das Drag-and-Drop-Hilfsobjekt verwenden, um das Ziehbild anzugeben. Das Drag-and-Drop-Hilfsobjekt ruft IDataObject::SetData auf, um private Formate in das Datenobjekt zu laden, die für die prozessübergreifende Unterstützung verwendet werden. Um das Drag-and-Drop-Hilfsobjekt zu unterstützen, muss Ihre IDataObject::SetData-Implementierung in der Lage sein, beliebige private Formate zu akzeptieren und zu speichern.

Nachdem die Daten gelöscht wurden, erfordern einige Shell-Datenübertragungstypen, dass das Ziel IDataObject::SetData aufruft , um dem Datenobjekt Informationen über das Ergebnis des Löschvorgangs bereitzustellen. Wenn Sie z. B. Dateien mit einem optimierten Verschiebungsvorgang verschieben, löscht das Ziel normalerweise die ursprünglichen Dateien, dies ist jedoch nicht erforderlich. Das Ziel informiert das Datenobjekt, ob es die Dateien gelöscht hat, indem es IDataObject::SetData mit einem CFSTR_LOGICALPERFORMEDDROPEFFECT Format aufruft. Es gibt mehrere andere Shell-Zwischenablageformate , die auch vom Ziel verwendet werden, um Informationen an das Datenobjekt zu übergeben. Ihre IDataObject::SetData-Implementierung muss in der Lage sein, diese Formate zu erkennen und entsprechend zu reagieren. Weitere Informationen finden Sie unter Behandeln von Shell-Datenübertragungsszenarien.

EnumFormatEtc-Methode

Wenn das Ziel ein Datenobjekt empfängt, ruft es in der Regel FORMATETC auf, um zu bestimmen, welche Formate das Objekt enthält. Die -Methode erstellt ein OLE-Enumerationsobjekt und gibt einen Zeiger auf die IEnumFORMATETC-Schnittstelle des Objekts zurück. Das Ziel verwendet dann die -Schnittstelle, um die verfügbaren Formate aufzulisten.

Ein Enumerationsobjekt sollte immer die verfügbaren Formate in der Reihenfolge der Qualität aufzählen, beginnend mit den besten. Die relative Qualität von Formaten wird durch die Ablagequelle definiert. Im Allgemeinen enthalten formate höchster Qualität die umfassendsten und vollständigsten Daten. Bei instance würde ein 24-Bit-Farbbild normalerweise als höhere Qualität als eine Graustufenversion dieses Bilds angesehen. Der Grund für die Aufzählung von Formaten in der Reihenfolge ihrer Qualität besteht darin, dass Ziele in der Regel aufzählen, bis sie zu einem formatieren, das sie unterstützen, und dann verwenden sie dieses Format, um die Daten zu extrahieren. Damit dieses Verfahren das beste verfügbare Format erzeugt, das das Ziel unterstützen kann, müssen die Formate in der Reihenfolge ihrer Qualität aufgelistet werden.

Ein Enumerationsobjekt für Shelldaten wird ähnlich wie für andere Arten der Datenübertragung implementiert, mit einer wichtigen Ausnahme. Da Datenobjekte in der Regel nur ein Datenelement pro Format enthalten, listen sie normalerweise jedes Format auf, das an IDataObject::SetData übergeben wird. Wie jedoch im Abschnitt SetData-Methode erläutert, können Shell-Datenobjekte mehrere CFSTR_FILECONTENTS Formate enthalten.

Da der Zweck von IDataObject::EnumFormatEtc darin besteht, dem Ziel zu erlauben, zu bestimmen, welche Datentypen vorhanden sind, ist es nicht erforderlich, mehr als ein CFSTR_FILECONTENTS-Format aufzulisten. Wenn das Ziel wissen muss, wie viele dieser Formate das Datenobjekt enthält, kann das Ziel diese Informationen aus dem zugehörigen CFSTR_FILEDESCRIPTOR Format abrufen. Weitere Informationen zum Implementieren von IDataObject::EnumFormatEtc finden Sie in der Referenzdokumentation der Methode.

GetData-Methode

Das Ziel ruft IDataObject::GetData auf, um ein bestimmtes Datenformat zu extrahieren. Das Ziel gibt das Format an, indem die entsprechende FORMATTC-Struktur übergeben wird. IDataObject::GetData gibt die STGMEDIUM-Struktur des Formats zurück.

Das Ziel kann den tymed-Member der FORMATTC-Struktur auf einen bestimmten TYMED_XXX-Wert festlegen, um anzugeben, welchen Datenübertragungsmechanismus es zum Extrahieren der Daten verwenden soll. Das Ziel kann jedoch auch eine allgemeinere Anforderung stellen und das Datenobjekt entscheiden lassen. Um das Datenobjekt aufzufordern, den Datenübertragungsmechanismus auszuwählen, legt das Ziel alle TYMED_XXX-Werte fest, die es unterstützt. IDataObject::GetData wählt einen dieser Datenübertragungsmechanismen aus und gibt die entsprechende STGMEDIUM-Struktur zurück. Für instance wird tymed häufig auf TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE, um einen der drei Shell-Datenübertragungsmechanismen anzufordern.

Hinweis

Da mehrere CFSTR_FILECONTENTS Formate vorhanden sein können, reichen die cfFormat - und tymed-Member der FORMATTC-Struktur nicht aus, um anzugeben, welche STGMEDIUM-StrukturIDataObject::GetData zurückgegeben werden soll. Für das CFSTR_FILECONTENTS-Format muss IDataObject::GetData auch den lIndex-Member der FORMATETC-Struktur untersuchen, um die richtige STGMEDIUM-Struktur zurückzugeben.

 

Das CFSTR_INDRAGLOOP-Format wird in Datenobjekten platziert, damit Ziele die status der Drag-and-Drop-Schleife überprüfen können, während das speicherintensive Rendern der Objektdaten vermieden wird. Die Daten des Formats sind ein DWORD-Wert , der auf einen Wert ungleich null festgelegt wird, wenn sich das Datenobjekt in einer Ziehschleife befindet. Der Datenwert des Formats wird auf null festgelegt, wenn die Daten gelöscht wurden. Wenn ein Ziel dieses Format anfordert und es nicht von der Quelle geladen wurde, sollte IDataObject::GetData so reagieren, als ob die Quelle das Format mit dem Wert 0 (null) geladen hätte.

Während sich der Cursor über dem Zielfenster befindet, kann das Ziel das Drag-and-Drop-Hilfsobjekt verwenden, um das Ziehbild anzugeben. Das Drag-and-Drop-Hilfsobjekt ruft IDataObject::SetData auf, um private Formate in das Datenobjekt zu laden, die für die prozessübergreifende Unterstützung verwendet werden. Später wird IDataObject::GetData aufgerufen, um sie abzurufen. Um das Drag-and-Drop-Hilfsobjekt zu unterstützen, muss Ihre Shell-Datenobjektimplementierung in der Lage sein, beliebige private Formate zurückzugeben, wenn sie angefordert werden.

Implementieren von IDropSource

Die Quelle muss ein -Objekt erstellen, das eine IDropSource-Schnittstelle verfügbar macht. Mit dieser Schnittstelle kann die Quelle das Ziehbild aktualisieren, das die aktuelle Position des Cursors angibt, und dem System Feedback zum Beenden eines Drag-and-Drop-Vorgangs geben. IDropSource verfügt über zwei Methoden: GiveFeedback und QueryContinueDrag.

GiveFeedback-Methode

In der Ziehschleife ist eine Ablagequelle dafür verantwortlich, die Cursorposition nachzuverfolgen und ein geeignetes Ziehbild anzuzeigen. In einigen Fällen können Sie jedoch die Darstellung des Bilds ändern, wenn es sich über dem Fenster des Ablageziels befindet.

Wenn der Cursor das Zielfenster betritt oder verlässt und während er sich über das Zielfenster bewegt, ruft das System regelmäßig die IDropTarget-Schnittstelle des Ziels auf. Das Ziel antwortet mit einem DROPEFFECT-Wert , der über die GiveFeedback-Methode an die Quelle weitergeleitet wird. Bei Bedarf kann die Quelle die Darstellung des Cursors basierend auf dem DROPEFFECT-Wert ändern. Weitere Informationen finden Sie in den Verweisen GiveFeedback und DoDragDrop .

QueryContinueDrag-Methode

Diese Methode wird aufgerufen, wenn sich der Maus- oder Tastaturzustand ändert, während sich das Datenobjekt in der Ziehschleife befindet. Es benachrichtigt die Quelle, ob die ESC-Taste gedrückt wurde, und gibt den aktuellen Status der Tastaturmodifizierertasten an, z. B. STRG oder UMSCHALT. Der Rückgabewert der QueryContinueDrag-Methode gibt eine von drei Aktionen an:

  • S_OK. Fortsetzen des Ziehvorgangs
  • DRAGDROP_S_DROP. Löschen Sie die Daten. Anschließend ruft das System die IDropTarget::D rop-Methode des Ziels auf.
  • DRAGDROP_S_CANCEL. Beenden Sie die Ziehschleife, ohne die Daten zu löschen. Dieser Wert wird normalerweise zurückgegeben, wenn die ESCAPE-TASTE gedrückt wurde.

Weitere Informationen finden Sie unter den Verweisen QueryContinueDrag und DoDragDrop .

Behandeln eines Datenobjekts durch ein Ziel

Das Ziel empfängt ein Datenobjekt, wenn es entweder das Datenobjekt aus der Zwischenablage abruft oder vom Benutzer im Zielfenster abgelegt wird. Das Ziel kann dann Daten aus dem Datenobjekt extrahieren. Bei Bedarf kann das Ziel auch das Datenobjekt über das Ergebnis des Vorgangs benachrichtigen. Vor einer Shell-Datenübertragung muss sich ein Ablageziel auf den Vorgang vorbereiten:

  1. Das Ziel muss RegisterClipboardFormat aufrufen, um einen gültigen Zwischenablageformatwert für alle Shellformate zu erhalten, die nicht CF_HDROP, die möglicherweise im Datenobjekt enthalten sind. CF_HDROP ist bereits ein gültiges Zwischenablageformat und muss nicht registriert werden.
  2. Um einen Drag-and-Drop-Vorgang zu unterstützen, muss das Ziel eine IDropTarget-Schnittstelle implementieren und ein Zielfenster registrieren. Um ein Zielfenster zu registrieren, ruft das Ziel RegisterDragDrop auf und übergibt das Handle des Fensters und den IDropTarget-Schnittstellenzeiger .

Bei Zwischenablageübertragungen erhält das Ziel keine Benachrichtigung, dass ein Datenobjekt in der Zwischenablage platziert wurde. In der Regel wird eine Anwendung von einer Benutzeraktion benachrichtigt, dass sich ein Objekt in der Zwischenablage befindet, z. B. durch Klicken auf die Schaltfläche Einfügen auf der Symbolleiste der Anwendung. Das Ziel ruft dann den IDataObject-Zeiger des Datenobjekts aus der Zwischenablage ab, indem OleGetClipboard aufgerufen wird. Für Drag-and-Drop-Datenübertragungen verwendet das System die IDropTarget-Schnittstelle des Ziels, um dem Ziel Informationen über den Fortschritt der Datenübertragung bereitzustellen:

  • Das System ruft IDropTarget::D ragEnter auf, wenn der Cursor in das Zielfenster eintritt.
  • Das System ruft in regelmäßigen Abständen IDropTarget::D ragOver auf, während der Cursor das Zielfenster überläuft, um dem Ziel die aktuelle Cursorposition zuzuweisen.
  • Das System ruft IDropTarget::D ragLeave auf, wenn der Cursor das Zielfenster verlässt.
  • Das System ruft IDropTarget::D rop auf, wenn der Benutzer das Datenobjekt im Zielfenster abwirft.

Eine Erläuterung der Implementierung dieser Methoden finden Sie unter IDropTarget.

Wenn die Daten gelöscht werden, stellt IDropTarget::D rop dem Ziel einen Zeiger auf die IDataObject-Schnittstelle des Datenobjekts bereit. Das Ziel verwendet dann diese Schnittstelle, um Daten aus dem Datenobjekt zu extrahieren.

Extrahieren von Shelldaten aus einem Datenobjekt

Nachdem ein Datenobjekt gelöscht oder aus der Zwischenablage abgerufen wurde, kann das Ziel die benötigten Daten extrahieren. Der erste Schritt des Extraktionsprozesses besteht in der Regel darin, die im Datenobjekt enthaltenen Formate aufzulisten:

  • Rufen Sie IDataObject::EnumFormatEtc auf. Das Datenobjekt erstellt ein OLE-Standard-Enumerationsobjekt und gibt einen Zeiger auf seine IEnumFORMATETC-Schnittstelle zurück.
  • Verwenden Sie die IEnumFORMATETC-Methoden , um die im Datenobjekt enthaltenen Formate aufzulisten. Dieser Vorgang ruft normalerweise eine FORMATTC-Struktur für jedes Format ab, das das Objekt enthält. Das Enumerationsobjekt gibt jedoch normalerweise nur eine einzelne FORMATTC-Struktur für das CFSTR_FILECONTENTS-Format zurück, unabhängig davon, wie viele solche Formate im Datenobjekt enthalten sind.
  • Wählen Sie ein oder mehrere Formate aus, die extrahiert werden sollen, und speichern Sie die FORMATETC-Strukturen .

Um ein bestimmtes Format abzurufen, übergeben Sie die zugeordnete FORMATTC-Struktur an IDataObject::GetData. Diese Methode gibt eine STGMEDIUM-Struktur zurück, die Zugriff auf die Daten ermöglicht. Um einen bestimmten Datenübertragungsmechanismus anzugeben, legen Sie den tymed-Wert der FORMATTC-Struktur auf den entsprechenden TYMED_XXX-Wert fest. Um das Datenobjekt aufzufordern, einen Datenübertragungsmechanismus auszuwählen, legt das Ziel die TYMED_XXX-Werte für jeden Datenübertragungsmechanismus fest, den das Ziel verarbeiten kann. Das Datenobjekt wählt einen dieser Datenübertragungsmechanismen aus und gibt die entsprechende STGMEDIUM-Struktur zurück.

Bei den meisten Formaten kann das Ziel die Daten abrufen, indem es die FORMATTC-Struktur übergibt, die es beim Aufzählen der verfügbaren Formate erhalten hat. Eine Ausnahme von dieser Regel ist CFSTR_FILECONTENTS. Da ein Datenobjekt mehrere Instanzen dieses Formats enthalten kann, entspricht die vom Enumerator zurückgegebene FORMATTC-Struktur möglicherweise nicht dem jeweiligen Format, das Sie extrahieren möchten. Zusätzlich zur Angabe der cfFormat - und tymed-Elemente müssen Sie auch den lIndex-Member auf den Indexwert der Datei festlegen. Weitere Informationen finden Sie im Abschnitt Verwenden des CFSTR_FILECONTENTS-Formats zum Extrahieren von Daten aus einer Datei unter Behandeln von Shell-Datenübertragungsszenarien.

Der Datenextraktionsprozess hängt vom Typ des Zeigers ab, der in der zurückgegebenen STGMEDIUM-Struktur enthalten ist. Wenn die -Struktur einen Zeiger auf eine IStream - oder IStorage-Schnittstelle enthält, verwenden Sie die Schnittstellenmethoden, um die Daten zu extrahieren. Der Prozess zum Extrahieren von Daten aus einem globalen Speicherobjekt wird im nächsten Abschnitt erläutert.

Extrahieren eines globalen Speicherobjekts aus einem Datenobjekt

Viele der Shell-Datenformate haben die Form eines globalen Speicherobjekts. Verwenden Sie das folgende Verfahren, um ein Format, das ein globales Speicherobjekt enthält, aus einem Datenobjekt zu extrahieren und seine Daten einer lokalen Variablen zuzuweisen:

  1. Erstellen Sie eine FORMATTC-Struktur . Legen Sie den cfFormat-Member auf den entsprechenden Wert des Zwischenablageformats und das tymed-Element auf TYMED_HGLOBAL fest.

  2. Erstellen Sie eine leere STGMEDIUM-Struktur .

  3. Rufen Sie IDataObject::GetData auf, und übergeben Sie Zeiger auf die FORMATETC - und STGMEDIUM-Strukturen .

    Wenn IDataObject::GetData zurückgegeben wird, enthält die STGMEDIUM-Struktur einen Zeiger auf das globale Speicherobjekt, das die Daten enthält.

  4. Weisen Sie die Daten einer lokalen Variablen zu, indem Sie GlobalLock aufrufen und den hGlobal-Member der STGMEDIUM-Struktur übergeben.

  5. Rufen Sie GlobalUnlock auf, um die Sperre für das globale Speicherobjekt freizugeben.

  6. Rufen Sie ReleaseStgMedium auf, um das globale Speicherobjekt freizugeben.

Hinweis

Sie müssen ReleaseStgMedium verwenden, um das globale Speicherobjekt freizugeben, nicht GlobalFree.

 

Das folgende Beispiel zeigt, wie ein als globales Speicherobjekt gespeicherter DWORD-Wert aus einem Datenobjekt extrahiert wird. Der pdtobj-Parameter ist ein Zeiger auf die IDataObject-Schnittstelle des Datenobjekts, cf ist das Zwischenablageformat, das die gewünschten Daten identifiziert, und pdwOut wird verwendet, um den Datenwert zurückzugeben.

STDAPI DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{    STGMEDIUM medium;
   FORMATETC fmte = {(CLIPFORMAT) cf, NULL, DVASPECT_CONTENT, -1, 
       TYMED_HGLOBAL};
    HRESULT hres = pdtobj->GetData(&fmte, &medium);
    if (SUCCEEDED(hres))
   {
       DWORD *pdw = (DWORD *)GlobalLock(medium.hGlobal);
       if (pdw)
       {
           *pdwOut = *pdw;
           GlobalUnlock(medium.hGlobal);
       }
       else
       {
           hres = E_UNEXPECTED;
       }
       ReleaseStgMedium(&medium);
   }
   return hres;
}

Implementieren von IDropTarget

Das System verwendet die IDropTarget-Schnittstelle , um mit dem Ziel zu kommunizieren, während sich der Cursor über dem Zielfenster befindet. Die Antworten des Ziels werden über die IDropSource-Schnittstelle an die Quelle weitergeleitet. Abhängig von der Antwort kann die Quelle das Symbol ändern, das die Daten darstellt. Wenn das Ablageziel das Datensymbol angeben muss, kann es dazu ein Drag-and-Drop-Hilfsobjekt erstellen.

Bei herkömmlichen Drag-and-Drop-Vorgängen informiert das Ziel das Datenobjekt über das Ergebnis des Vorgangs, indem der pdwEffect-Parameter von IDropTarget::D rop auf den entsprechenden DROPEFFECT-Wert festgelegt wird. Bei Shell-Datenobjekten muss das Ziel möglicherweise auch IDataObject::SetData aufrufen. Eine Erläuterung dazu, wie Ziele für verschiedene Datenübertragungsszenarien reagieren sollten, finden Sie unter Behandeln von Shell-Datenübertragungsszenarien.

In den folgenden Abschnitten wird kurz erläutert, wie die Methoden IDropTarget::D ragEnter, IDropTarget::D ragOver und IDropTarget::D rop implementiert werden. Weitere Informationen finden Sie in der Referenzdokumentation.

DragEnter-Methode

Das System ruft die IDropTarget::D ragEnter-Methode auf, wenn der Cursor in das Zielfenster eintritt. Seine Parameter stellen dem Ziel die Position des Cursors, den Zustand der Tastaturmodifizierertasten wie strg und einen Zeiger auf die IDataObject-Schnittstelle des Datenobjekts bereit. Das Ziel ist dafür verantwortlich, diese Schnittstelle zu verwenden, um zu bestimmen, ob es eines der im Datenobjekt enthaltenen Formate akzeptieren kann. Wenn dies möglich ist, bleibt der Wert von pdwEffect normalerweise unverändert. Wenn keine Daten aus dem Datenobjekt akzeptiert werden können, wird der pdwEffect-Parameter auf DROPEFFECT_NONE festgelegt. Das System übergibt den Wert dieses Parameters an die IDropSource-Schnittstelle des Datenobjekts, damit das entsprechende Ziehbild angezeigt werden kann.

Ziele sollten die IDataObject::GetData-Methode nicht zum Rendern von Shelldaten verwenden, bevor sie gelöscht wurden. Das vollständige Rendern der Objektdaten für jedes solche Vorkommen kann dazu führen, dass der Ziehcursor angehalten wird. Um dieses Problem zu vermeiden, enthalten einige Shell-Objekte ein CFSTR_INDRAGLOOP Format. Durch extrahieren dieses Format können Ziele die status der Ziehschleife überprüfen und gleichzeitig das speicherintensive Rendern der Objektdaten vermeiden. Der Datenwert des Formats ist ein DWORD , der auf einen Wert ungleich null festgelegt wird, wenn sich das Datenobjekt in einer Ziehschleife befindet. Der Datenwert des Formats wird auf null festgelegt, wenn die Daten gelöscht wurden.

Wenn das Ziel Daten aus dem Datenobjekt akzeptieren kann, sollte es grfKeyState untersuchen, um festzustellen, ob Modifizierertasten gedrückt wurden, um das normale Ablageverhalten zu ändern. Für instance ist der Standardvorgang in der Regel eine Verschiebung, aber das Drücken der STRG-TASTE bedeutet in der Regel einen Kopiervorgang.

Während sich der Cursor über dem Zielfenster befindet, kann das Ziel das Drag-and-Drop-Hilfsobjekt verwenden, um das Ziehbild des Datenobjekts durch ein eigenes zu ersetzen. Wenn dies der Fall ist, sollte IDropTarget::D ragEnterIDropTargetHelper::D ragEnter aufrufen, um die in den DragEnter-Parametern enthaltenen Informationen an das Drag-and-Drop-Hilfsprogrammobjekt zu übergeben.

DragOver-Methode

Während sich der Cursor im Zielfenster bewegt, ruft das System regelmäßig die IDropTarget::D ragOver-Methode auf. Seine Parameter stellen dem Ziel die Position des Cursors und den Zustand der Tastaturmodifizierertasten wie die STRG-TASTE bereit. IDropTarget::D ragOver hat die gleichen Zuständigkeiten wie IDropTarget::D ragEnter, und die Implementierungen sind in der Regel sehr ähnlich.

Wenn das Ziel das Drag-and-Drop-Hilfsobjekt verwendet, sollte IDropTarget::D ragOverIDropTargetHelper::D ragOver aufrufen, um die in den DragOver-Parametern enthaltenen Informationen an das Drag-and-Drop-Hilfsobjekt weiterzuleiten.

Drop-Methode

Das System ruft die IDropTarget::D rop-Methode auf, um das Ziel darüber zu benachrichtigen, dass der Benutzer die Daten gelöscht hat, in der Regel durch Loslassen der Maustaste. IDropTarget::D rop verfügt über die gleichen Parameter wie IDropTarget::D ragEnter. Das Ziel antwortet normalerweise, indem es ein oder mehrere Formate aus dem Datenobjekt extrahiert. Nach Abschluss des Vorgangs sollte das Ziel den pdwEffect-Parameter auf einen DROPEFFECT-Wert festlegen, der das Ergebnis des Vorgangs angibt. Bei einigen Shell-Datenübertragungstypen muss das Ziel auch IDataObject::SetData aufrufen, um ein Format mit zusätzlichen Informationen zum Ergebnis des Vorgangs an das Datenobjekt zu übergeben. Eine ausführliche Erläuterung finden Sie unter Behandeln von Shell-Datenübertragungsszenarien.

Wenn das Ziel das Drag-and-Drop-Hilfsobjekt verwendet, sollte IDropTarget::D ropIDropTargetHelper::D rop aufrufen, um die in den IDropTargetHelper::D ragOver-Parametern enthaltenen Informationen an das Drag-and-Drop-Hilfsobjekt weiterzuleiten.

Verwenden des Drag-and-Drop-Hilfsobjekts

Das Drag-and-Drop-Hilfsobjekt (CLSID_DragDropHelper) wird von der Shell exportiert, damit Ziele das Ziehbild angeben können, während es sich über dem Zielfenster befindet. Um das Drag-and-Drop-Hilfsobjekt zu verwenden, erstellen Sie ein prozessinternes Serverobjekt, indem Sie CoCreateInstance mit einem Klassenbezeichner (CLSID) von CLSID_DragDropHelper aufrufen. Das Drag-and-Drop-Hilfsobjekt macht zwei Schnittstellen verfügbar, die wie folgt verwendet werden:

Verwenden der IDragSourceHelper-Schnittstelle

Die IDragSourceHelper-Schnittstelle wird vom Drag-and-Drop-Hilfsobjekt verfügbar gemacht, damit ein Ablageziel das Bild bereitstellen kann, das angezeigt wird, während sich der Cursor über dem Zielfenster befindet. IDragSourceHelper bietet zwei alternative Möglichkeiten zum Angeben der Bitmap, die als Ziehbild verwendet werden soll:

  • Drop-Ziele, die über ein Fenster verfügen, können eine DI_GETDRAGIMAGE-Fenstermeldung registrieren, indem das Drag-and-Drop-Hilfsobjekt mit IDragSourceHelper::InitializeFromWindow initialisiert wird. Wenn das Ziel eine DI_GETDRAGIMAGE Nachricht empfängt, fügt der Handler die Bitmapinformationen zum Ziehen des Bilds in die SHDRAGIMAGE-Struktur ein, die als lParam-Wert der Nachricht übergeben wird.
  • Fensterlose Ablageziele geben eine Bitmap an, wenn sie das Drag-and-Drop-Hilfsobjekt mit IDragSourceHelper::InitializeFromBitmap initialisieren.

Verwenden der IDropTargetHelper-Schnittstelle

Mit dieser Schnittstelle kann das Dropziel das Drag-and-Drop-Hilfsobjekt benachrichtigen, wenn der Cursor das Ziel ein- oder verlässt. Während sich der Cursor über dem Zielfenster befindet, ermöglicht IDropTargetHelper dem Ziel, dem Drag-and-Drop-Hilfsobjekt die Informationen zu geben, die das Ziel über seine IDropTarget-Schnittstelle empfängt.

Vier der IDropTargetHelper-MethodenIDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper::D ragOver und IDropTargetHelper::D rop – sind der IDropTargetHelper ::D rop-Methode mit demselben Namen zugeordnet. Um das Drag-and-Drop-Hilfsobjekt zu verwenden, sollte jede der IDropTarget-Methoden die entsprechende IDropTargetHelper-Methode aufrufen, um die Informationen an das Drag-and-Drop-Hilfsobjekt weiterzuleiten. Die fünfte IDropTargetHelper-Methode , IDropTargetHelper::Show, benachrichtigt das Drag-and-Drop-Hilfsobjekt, das Bild ein- oder auszublenden. Diese Methode wird verwendet, wenn Sie in einem Videomodus mit geringer Farbtiefe über ein Zielfenster ziehen. Das Ziel kann das Bild beim Zeichnen des Fensters ausblenden.