Shelldatenobjekt
Das Datenobjekt ist für alle Shell-Datenübertragungen von zentraler Bedeutung. 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 Typen der Shell-Datenübertragung zu ermöglichen, z. B. optimierte Verschiebebewegungen. In diesem Thema wird allgemein beschrieben, 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 Typen von Shelldaten finden Sie unter Behandeln von Shell-Datenübertragungsszenarien.
- Funktionsweise von Datenobjekten
- Erstellen eines Datenobjekts durch eine Quelle
- So behandelt ein Ziel ein Datenobjekt
- Using the Drag-and-Drop Helper Object
Funktionsweise von Datenobjekten
Datenobjekte sind Component Object Model (COM)-Objekte, die von der Datenquelle erstellt werden, um Daten an ein Ziel zu übertragen. Sie enthalten in der Regel mehr als ein Datenelement. Für diese Vorgehensweise gibt es zwei Gründe:
- Obwohl fast jede Art von Daten mit einem Datenobjekt übertragen werden kann, weiß die Quelle in der Regel nicht, welche Art von Daten das Ziel akzeptieren kann. Beispielsweise können die Daten ein Teil eines formatierten Textdokuments sein. Obwohl das Ziel möglicherweise komplexe Formatierungsinformationen verarbeiten kann, kann es auch nur ANSI-Text akzeptieren. Aus diesem Grund enthalten Datenobjekte häufig dieselben Daten in verschiedenen Formaten. Das Ziel kann die Daten dann in einem Format extrahieren, das es verarbeiten kann.
- Datenobjekte können auch zusätzliche Datenelemente enthalten, die keine Versionen der Quelldaten sind. Diese Art von Datenelement stellt in der Regel zusätzliche Informationen zum Datenübertragungsvorgang zur Verfügung. Beispielsweise verwendet die Shell zusätzliche Datenelemente, um anzugeben, ob eine Datei kopiert oder verschoben werden soll.
Zwischenablageformate
Jedem Datenelement in einem Datenobjekt ist ein Format zugeordnet, das in der Regel als Zwischenablageformat bezeichnet wird. Es gibt eine Reihe von Standardformaten für die Zwischenablage, die in Winuser.h deklariert sind und häufig verwendeten Datentypen entsprechen. Zwischenablageformate sind ganze Zahlen, aber normalerweise wird auf sie durch ihren entsprechenden Namen verwiesen, der die Form CF _ XXX hat. Das Zwischenablageformat für ANSI-Text ist beispielsweise 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. Allerdings müssen sowohl quelle als auch target das Format registrieren, um es verwenden zu können. Mit einer Ausnahme–CF _ HDROP– werden die Zwischenablageformate, die zum Übertragen von Shelldaten verwendet werden, 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 von ihnen unterstützte Zwischenablageformat. Diese 1:1-Korrelation zwischen Format und Daten ermöglicht die Verwendung des Formatwerts als Bezeichner für das zugeordnete Datenelement. Bei der Erörterung des Inhalts eines Datenobjekts wird ein bestimmtes Datenelement in der Regel als "Format" bezeichnet und durch seinen Formatnamen bezeichnet. Beispiele hierfür sind Ausdrücke wie "Extrahieren des _ CF-TEXTformats...". werden in der Regel verwendet, wenn das ANSI-Textdatenelement eines Datenobjekts diskutiert wird.
Wenn das Abbruchziel den Zeiger auf das Datenobjekt empfängt, werden die verfügbaren Formate aufzählt, um zu bestimmen, welche Datentypen verfügbar sind. Anschließend werden eines oder mehrere der verfügbaren Formate anfordern 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 unter Verarbeiten eines Datenobjektsdurch ein Ziel erläutert.
Bei einfachen Datenübertragungen in der Zwischenablage werden die Daten in einem globalen Speicherobjekt platziert. Die Adresse dieses Objekts wird zusammen mit seinem Format in der Zwischenablage platziert. Das Format der Zwischenablage teilt dem Ziel mit, welche Art von Daten es an der zugeordneten Adresse findet. Einfache Zwischenablageübertragungen sind zwar einfach zu implementieren:
- Datenobjekte bieten eine wesentlich flexiblere Möglichkeit zum Übertragen von Daten.
- Datenobjekte eignen sich besser für die Übertragung großer Datenmengen.
- Datenobjekte müssen zum Übertragen von Daten mit einem Drag & Drop-Vorgang verwendet werden.
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 FORMATETC-Struktur.
FORMATETC-Struktur
Die FORMATETC-Struktur ist eine erweiterte Version eines Zwischenablageformats. Wie bei Shell-Datenübertragungen verwendet, hat die FORMATETC-Struktur die folgenden Merkmale:
Ein Datenelement wird weiterhin durch sein Zwischenablageformat im cfFormat-Element identifiziert.
Die Datenübertragung ist nicht auf globale Speicherobjekte beschränkt. Das tymed-Member wird verwendet, um den Datenübertragungsmechanismus anzugeben, der in der zugeordneten STGMEDIUM-Struktur enthalten ist. Sie 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 Erörterung der Verwendung dieses Formats finden Sie im Abschnitt Using the CFSTR FILECONTENTS Format to Extract Data from a File (Verwenden des CFSTR _ FILECONTENTS-Formats zum Extrahieren von Daten aus einer Datei) unter Handling Shell Data Transfer Scenarios (Behandeln von Shell-Datenübertragungsszenarien).
Das dwAspect-Member ist in der Regel auf DVASPECT _ CONTENT festgelegt. In Shlobj.h sind jedoch drei Werte 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 mit den Daten darstellt. DVASPECT _ SHORTNAME Wird mit dem CF HDROP-Format verwendet, um einen Dateipfad mit den Namen an fordern, die auf das _ 8.3-Format verkü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:
- Ein globales Speicherobjekt.
- Eine IStream-Schnittstelle.
- Eine IStorage-Schnittstelle.
Das tymed-Member der STGMEDIUM-Struktur ist ein TYMED _ XXX-Wert, der den Datenübertragungsmechanismus identifiziert. Der zweite Member ist ein Zeiger, der vom Ziel zum Extrahieren der Daten verwendet wird. Der Zeiger kann je nach tyd-Wert einen von einer Vielzahl von Typen sein. Die drei für Shell-Datenübertragungen verwendeten tymed-Werte werden in der folgenden Tabelle zusammen mit dem entsprechenden STGMEDIUM-Membernamen zusammengefasst.
| tymed Value | Membername | Beschreibung |
|---|---|---|
| TYMED _ HGLOBAL | hGlobal | Ein Zeiger auf ein globales Speicherobjekt. Dieser Zeigertyp wird in der Regel zum Übertragen kleiner Datenmengen verwendet. Beispielsweise 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 im Vergleich zu TYMED HGLOBAL relativ wenig _ Arbeitsspeicher benötigt wird. Außerdem erfordert der TYMED ISTREAM-Datenübertragungsmechanismus nicht, dass die Quelle ihre Daten _ auf bestimmte Weise speichern muss. |
| TYMED _ ISTORAGE | pstg | Ein Zeiger auf eine IStorage-Schnittstelle. Das Ziel ruft die Schnittstellenmethoden auf, um die Daten zu extrahieren. Wie TYMED _ ISTREAM erfordert dieser Zeigertyp relativ wenig Arbeitsspeicher. Da TYMED _ ISTORAGE jedoch weniger flexibel als TYMED _ ISTREAM ist, 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. Das folgende Verfahren fasst den Prozess zusammen:
- Rufen Sie RegisterClipboardFormat auf, um einen gültigen Zwischenablageformatwert für jedes Shellformat zu erhalten, das in das Datenobjekt eingeschlossen wird. Beachten Sie, dass CF _ HDROP bereits ein gültiges Zwischenablageformat ist und nicht registriert werden muss.
- Legen Sie für jedes zu übertragende Format die zugeordneten Daten entweder in ein globales Speicherobjekt ab, oder erstellen Sie ein Objekt, das den Zugriff auf diese Daten über eine IStream- oder IStorage-Schnittstelle ermöglicht. Die IStream- und IStorage-Schnittstellen werden mit com-Standardverfahren erstellt. Eine Erörterung der Handhabung globaler Speicherobjekte finden Sie unter Hinzufügen eines globalen Speicherobjekts zu einem Datenobjekt.
- Erstellen Sie FORMATETC- und STGMEDIUM-Strukturen für jedes Format.
- Instanziieren Sie ein Datenobjekt.
- 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.
- Rufen Sie bei Datenübertragungen in der Zwischenablage OleSetClipboard auf, um einen Zeiger auf die IDataObject-Schnittstelle des Datenobjekts in der Zwischenablage zu platzieren. For drag-and-drop transfers, initiate a drag loop by calling DoDragDrop. Der IDataObject-Zeiger wird an das Abbruchziel übergeben, wenn die Daten gelöscht werden, was die Ziehschleife beendet.
Das Datenobjekt kann jetzt an das Ziel übertragen werden. Bei Datenübertragungen in der Zwischenablage wird das -Objekt einfach gehalten, bis das Ziel es durch Aufrufen von OleGetClipboard anweist. Bei Drag & Drop-Datenübertragungen ist das Datenobjekt dafür verantwortlich, ein Symbol zur Darstellung der Daten zu erstellen und zu verschieben, während der Benutzer den Cursor bewegt. Während sich das Objekt in der Ziehschleife befindet, empfängt die Quelle Statusinformationen über die IDropSource-Schnittstelle. Weitere Informationen finden Sie unter Implementieren von IDropSource.
Die Quelle empfängt keine Benachrichtigung, wenn das Datenobjekt von einem Ziel aus der Zwischenablage abgerufen wird. When an object is dropped on a target by a drag-and-drop operation, the DoDragDrop function that was called to initiate the drag loop will return.
Hinzufügen eines globalen Speicherobjekts zu einem Datenobjekt
Viele der Shell-Datenformate liegen in Form eines globalen Speicherobjekts vor. Verwenden Sie das folgende Verfahren, um ein Format zu erstellen, das ein globales Speicherobjekt enthält, und laden Sie es in das Datenobjekt:
- Erstellen Sie eine FORMATETC-Struktur. Legen Sie das cfFormat-Member auf den entsprechenden Zwischenablageformatwert und das Tymed-Member auf TYMED _ HGLOBAL fest.
- Erstellen Sie eine STGMEDIUM-Struktur. Legen Sie das Tymed-Mitglied auf TYMED _ HGLOBAL fest.
- Erstellen Sie ein globales Speicherobjekt, indem Sie GlobalAlloc aufrufen, um einen Speicherblock mit entsprechender Größe zu reservieren.
- Weisen Sie den Datenblock zu, der an die von GlobalAlloczurückgegebene Adresse übertragen werden soll.
- Weisen Sie die Adresse des globalen Speicherobjekts dem hGlobal-Member der STGMEDIUM-Struktur zu.
- Laden Sie das Format in das Datenobjekt, indem Sie IDataObject::SetData aufrufen und die FORMATETC- und STGMEDIUM-Strukturen übergeben, die in den vorherigen Schritten erstellt wurden.
Die folgende Beispielfunktion erstellt ein globales Speicherobjekt, das einen DWORD-Wert enthält, und lädt ihn in ein Datenobjekt. Der pdtobj-Parameter ist ein Zeiger auf die IDataObject-Schnittstelle des Datenobjekts, cf ist der Formatwert der Zwischenablage 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. Sie wird sowohl von der Quelle als auch vom Ziel für eine Vielzahl von Zwecken verwendet, z. B.:
- Laden von Daten in das Datenobjekt.
- Extrahieren von Daten aus dem Datenobjekt.
- Bestimmen, welche Datentypen sich im Datenobjekt befinden.
- Senden von Feedback zum Ergebnis der Datenübertragung an das Datenobjekt.
IDataObject unterstützt eine Reihe von Methoden. In diesem Abschnitt wird erläutert, wie die drei wichtigsten Methoden für Shell-Datenobjekte implementiert werden: SetData, EnumFormatEtcund GetData. Eine Erörterung der anderen Methoden finden Sie in der IDataObject-Referenz.
SetData-Methode
Die primäre Funktion der IDataObject::SetData-Methode besteht im Zulassen, dass die Quelle Daten in das Datenobjekt laden kann. Für jedes enthaltene Format erstellt die Quelle eine FORMATETC-Struktur, um das Format zu identifizieren, und eine STGMEDIUM-Struktur, die einen Zeiger auf die Daten enthalten soll. 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 legt die Shell jedoch häufig die Informationen für jede Datei, die übertragen werden soll, in ein separates CFSTR _ FILECONTENTS-Format ab. Um die verschiedenen Dateien zu unterscheiden, wird das lIndex-Member der FORMATETC-Struktur jeder Datei auf einen Indexwert festgelegt, der die bestimmte Datei identifiziert. Ihre IDataObject::SetData-Implementierung muss mehrere CFSTR FILECONTENTS-Formate speichern können, die sich nur durch ihre _ lIndex-Member unterscheiden.
While the cursor is over the target window, the target can use the drag-and-drop helper object to specify the drag image. The drag-and-drop helper object calls IDataObject::SetData to load private formats into the data object that are used for cross-process support. To support the drag-and-drop helper object, your IDataObject::SetData implementation must be able to accept and store arbitrary private formats.
Nachdem die Daten gelöscht wurden, erfordern einige Typen der Shell-Datenübertragung, dass das Ziel IDataObject::SetData aufruft, um dem Datenobjekt Informationen zum Ergebnis des Abbruchs zur Verfügung zu stellen. Wenn Sie z. B. Dateien mit einem optimierten Verschieben 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 häufig 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 zu aufzählen.
Ein Enumerationsobjekt sollte die verfügbaren Formate immer in der Reihenfolge der Qualität auflisten, beginnend mit dem besten. Die relative Qualität von Formaten wird durch die Abbruchquelle definiert. Im Allgemeinen enthalten die Formate mit der höchsten Qualität die meisten und vollständigsten Daten. Beispielsweise würde ein 24-Bit-Farbbild normalerweise als eine höhere Qualität als eine graue Version dieses Bilds angesehen werden. Der Grund für das Aufzählen von Formaten in der Reihenfolge ihrer Qualität ist, 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 aufzählt werden.
Ein Enumerationsobjekt für Shelldaten wird ähnlich wie bei anderen Datenübertragungstypen implementiert, mit einer wichtigen Ausnahme. Da Datenobjekte in der Regel nur ein Datenelement pro Format enthalten, werden normalerweise jedes Format aufzählt, das an IDataObject::SetData übergeben wird. Wie im Abschnitt SetData-Methode erläutert, können Shell-Datenobjekte jedoch mehrere CFSTR _ FILECONTENTS-Formate enthalten.
Da der Zweck von IDataObject::EnumFormatEtc ist, dem Ziel zu ermöglichen, zu bestimmen, welche Datentypen vorhanden sind, ist es nicht notwendig, mehr als ein CFSTR _ FILECONTENTS-Format aufzählen. 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 zur Implementierung 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 FORMATETC-Struktur übergeben wird. IDataObject::GetData gibt die STGMEDIUM-Struktur des Formats zurück.
Das Ziel kann das tymed-Member der FORMATETC-Struktur auf einen bestimmten TYMED _ XXX-Wert festlegen, um anzugeben, welcher Datenübertragungsmechanismus zum Extrahieren der Daten verwendet wird. Das Ziel kann jedoch auch eine allgemeinere Anforderung erstellen und das Datenobjekt entscheiden lassen. Damit das Datenobjekt den Datenübertragungsmechanismus auswählen kann, legt das Ziel alle unterstützten TYMED _ XXX-Werte fest. IDataObject::GetData wählt einen dieser Datenübertragungsmechanismen aus und gibt die entsprechende STGMEDIUM-Struktur zurück. Tymed ist beispielsweise häufig auf TYMED _ HGLOBAL | TYMED ISTREAM TYMED ISTORAGE festgelegt, um einen der drei _ | _ Shell-Datenübertragungsmechanismen an fordern zu können.
Hinweis
Da es mehrere CFSTR _ FILECONTENTS-Formate geben kann, reichen die cfFormat- und tymed-Member der FORMATETC-Struktur nicht aus, um anzugeben, welche STGMEDIUM-Struktur IDataObject::GetData zurückgeben 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.
The CFSTR_INDRAGLOOP format is placed in data objects to allow targets to check the status of the drag-and-drop loop while avoiding memory intensive rendering of the object's data. Die Daten des Formats sind ein DWORD-Wert, der auf einen Wert ungleich 0 (null) festgelegt wird, wenn sich das Datenobjekt in einer Ziehschleife befindet. Der Datenwert des Formats wird auf 0 (null) festgelegt, wenn die Daten gelöscht wurden. Wenn ein Ziel dieses Format anfordert und 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.
While the cursor is over the target window, the target can use the drag-and-drop helper object to specify the drag image. The drag-and-drop helper object calls IDataObject::SetData to load private formats into the data object that are used for cross-process support. Später wird IDataObject::GetData aufgerufen, um sie abzurufen. Um das Drag & Drop-Hilfsobjekt zu unterstützen, muss die Implementierung des Shelldatenobjekts 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. This interface allows the source to update the drag image that indicates the current position of the cursor and to provide feedback to the system on how to terminate a drag-and-drop operation. 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 entsprechendes Ziehbild anzuzeigen. In einigen Fällen können Sie jedoch die Darstellung des Ziehbilds ändern, wenn es sich über dem Fenster des Ablageziels befindet.
Wenn der Cursor das Zielfenster ein- oder verlässt und sich über das Zielfenster bewegt, ruft das System in regelmäßigen Abständen 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 auf GiveFeedback und DoDragDrop.
QueryContinueDrag-Methode
Diese Methode wird aufgerufen, wenn sich die Maustaste oder der Tastaturzustand ändert, während sich das Datenobjekt in der Ziehschleife befindet. Er benachrichtigt die Quelle, ob die ESC-Taste gedrückt wurde, und stellt den aktuellen Zustand der Tastenkombinationen bereit, 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. Das System ruft dann 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 in den Verweisen queryContinueDrag und DoDragDrop.
So behandelt ein Ziel ein Datenobjekt
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:
- Das Ziel muss RegisterClipboardFormat aufrufen, um einen gültigen Zwischenablageformatwert für alle Shellformate außer CF _ HDROPabzurufen, die möglicherweise im Datenobjekt enthalten sind. CF _ HDROP ist bereits ein gültiges Zwischenablageformat und muss nicht registriert werden.
- To support a drag-and-drop operation, the target must implement an IDropTarget interface and register a target window. Um ein Zielfenster zu registrieren, ruft das Ziel RegisterDragDrop auf und übergibt das Handle des Fensters und den IDropTarget-Schnittstellenzeiger.
Bei Übertragungen in der Zwischenablage erhält das Ziel keine Benachrichtigung, dass ein Datenobjekt in der Zwischenablage platziert wurde. In der Regel wird eine Anwendung durch eine 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 OleGetClipboardaufgerufen wird. For drag-and-drop data transfers, the system uses the target's IDropTarget interface to provide the target with information about the progress of the data transfer:
- Das System ruft IDropTarget::D ragEnter auf, wenn der Cursor in das Zielfenster eintritt.
- Das System ruft IDropTarget::D ragOver regelmäßig auf, wenn der Cursor über das Zielfenster geht, 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 löscht.
Eine Erläuterung zur 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 im Extraktionsprozess besteht in der Regel darin, die im Datenobjekt enthaltenen Formate aufzuzählen:
- Rufen Sie IDataObject::EnumFormatEtc auf. Das Datenobjekt erstellt ein OLE-Standardenumerationsobjekt und gibt einen Zeiger auf seine IEnumFORMATETC-Schnittstelle zurück.
- Verwenden Sie die IEnumFORMATETC-Methoden, um die im Datenobjekt enthaltenen Formate aufzuzählen. Dieser Vorgang ruft in der Regel eine FORMATETC-Struktur für jedes Format ab, das das -Objekt enthält. Das Enumerationsobjekt gibt jedoch normalerweise nur eine einzelne FORMATETC-Struktur für das CFSTR _ FILECONTENTS-Format zurück, unabhängig davon, wie viele formate im Datenobjekt enthalten sind.
- Wählen Sie ein oder mehrere Zu extrahierende Formate aus, und speichern Sie deren FORMATETC-Strukturen.
Um ein bestimmtes Format abzurufen, übergeben Sie die zugeordnete FORMATETC-Struktur an IDataObject::GetData. Diese Methode gibt eine STGMEDIUM-Struktur zurück, die Zugriff auf die Daten bereitstellt. Um einen bestimmten Datenübertragungsmechanismus anzugeben, legen Sie den gebundenen Wert der FORMATETC-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 FORMATETC-Struktur möglicherweise nicht dem formatspezifischen Format, das Sie extrahieren möchten. Zusätzlich zur Angabe der Member cfFormat und tymed müssen Sie auch den lIndex-Member auf den Indexwert der Datei festlegen. Weitere Informationen finden Sie im Abschnitt Using the CFSTR FILECONTENTS Format to Extract Data from a File (Verwenden des CFSTR _ FILECONTENTS-Formats zum Extrahieren von Daten aus einer Datei) unter Handling Shell Data Transfer Scenarios (Behandeln von Shell-Datenübertragungsszenarien).
Der Datenextraktionsvorgang 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 des Extrahierens 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 zu extrahieren, das ein globales Speicherobjekt aus einem Datenobjekt enthält, und weisen Sie dessen Daten einer lokalen Variablen zu:
Erstellen Sie eine FORMATETC-Struktur. Legen Sie den cfFormat-Member auf den entsprechenden Zwischenablageformatwert und den gebundenen Member auf TYMED _ CABLOBAL fest.
Erstellen Sie eine leere STGMEDIUM-Struktur.
Rufen Sie IDataObject::GetDataauf, 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.
Weisen Sie die Daten einer lokalen Variablen zu, indem Sie GlobalLock aufrufen und den hGlobal-Member der STGMEDIUM-Struktur übergeben.
Rufen Sie GlobalUnlock auf, um die Sperre für das globale Speicherobjekt freizugeben.
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 sie einen DWORD-Wert extrahieren, der als globales Speicherobjekt aus einem Datenobjekt gespeichert ist. 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. If the drop target needs to specify the data icon, it can do so by creating a drag-and-drop helper object.
With conventional drag-and-drop operations, the target informs the data object of the outcome of the operation by setting the pdwEffect parameter of IDropTarget::Drop to the appropriate DROPEFFECT value. Bei Shell-Datenobjekten muss das Ziel möglicherweise auch IDataObject::SetDataaufrufen. Eine Erläuterung, wie Ziele auf 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 ragOverund 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. Die Parameter geben dem Ziel die Position des Cursors, den Zustand von Tastaturmodifizierertasten wie strG-Taste und einen Zeiger auf die IDataObject-Schnittstelle des Datenobjekts an. Das Ziel ist für die Verwendung dieser Schnittstelle verantwortlich, um zu bestimmen, ob es eines der im Datenobjekt enthaltenen Formate akzeptieren kann. Wenn dies der Welt ist, bleibt der Wert von pdwEffect in der Regel 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 es das entsprechende Ziehbild anzeigen kann.
Ziele sollten die IDataObject::GetData-Methode nicht verwenden, um Shelldaten zu rendern, bevor sie gelöscht wurden. Das vollständige Rendern der Objektdaten für jedes solche Vorkommen kann dazu führen, dass der Ziehcursor nicht mehr verwendet wird. Um dieses Problem zu vermeiden, enthalten einige Shell-Objekte ein CFSTR _ INDRAGLOOP-Format. Durch Extrahieren dieses Formats können Ziele den Status der Ziehschleife überprüfen und gleichzeitig das speicherintensive Rendering der Objektdaten vermeiden. Der Datenwert des Formats ist ein DWORD-Wert, der auf einen Wert ungleich 0 (null) festgelegt ist, wenn sich das Datenobjekt innerhalb einer Ziehschleife befindet. Der Datenwert des Formats wird auf 0 (null) festgelegt, wenn die Daten gelöscht wurden.
Wenn das Ziel Daten aus dem Datenobjekt akzeptieren kann, sollte es grfKeyState untersuchen, um zu bestimmen, ob Modifizierertasten gedrückt wurden, um das normale Absturzverhalten zu ändern. Der Standardvorgang ist z. B. in der Regel eine Bewegung, aber das Drücken der STRG-Taste deutet in der Regel auf einen Kopiervorgang hin.
While the cursor is over the target window, the target can use the drag-and-drop helper object to replace the data object's drag image with its own. If so, IDropTarget::DragEnter should call IDropTargetHelper::DragEnter to pass the information contained in the DragEnter parameters to the drag-and-drop helper object.
DragOver-Methode
Wenn der Cursor innerhalb des Zielfensters bewegt wird, ruft das System in regelmäßigen Abständen die IDropTarget::D ragOver-Methode auf. Die Parameter geben dem Ziel die Position des Cursors und den Zustand der Tastaturmodifizierertasten an, z. B. die STRG-Taste. IDropTarget::D ragOver hat die gleichen Zuständigkeiten wie IDropTarget::D ragEnter,und die Implementierungen sind in der Regel sehr ähnlich.
If the target is using the drag-and-drop helper object, IDropTarget::DragOver should call IDropTargetHelper::DragOver to forward the information contained in the DragOver parameters to the drag-and-drop helper object.
Drop-Methode
Das System ruft die IDropTarget::D rop-Methode auf, um das Ziel 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 ein oder mehrere Formate aus dem Datenobjekt extrahiert werden. 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.
If the target is using the drag-and-drop helper object, IDropTarget::Drop should call IDropTargetHelper::Drop to forward the information contained in the IDropTargetHelper::DragOver parameters to the drag-and-drop helper object.
Verwenden des Drag & Drop-Hilfsobjekts
The drag-and-drop helper object (CLSID_DragDropHelper) is exported by the Shell to allow targets to specify the drag image while it is over the target window. To use the drag-and-drop helper object, create an in-process server object by calling CoCreateInstance with a class identifier (CLSID) of CLSID_DragDropHelper. Das Drag & Drop-Hilfsobjekt macht zwei Schnittstellen verfügbar, die auf folgende Weise verwendet werden:
- Die IDragSourceHelper-Schnittstelle ermöglicht es dem Abbruchziel, ein Symbol anzugeben, das das Datenobjekt darstellen soll.
- The IDropTargetHelper interface allows the drop target to inform the drag-and-drop helper object of the cursor location, and to show or hide the data icon.
Verwenden der IDragSourceHelper-Schnittstelle
The IDragSourceHelper interface is exposed by the drag-and-drop helper object to allow a drop target to provide the image that will be displayed while the cursor is over the target window. IDragSourceHelper bietet zwei alternative Möglichkeiten zum Angeben der Bitmap, die als Ziehbild verwendet werden soll:
- Drop targets that have a window can register a DI_GETDRAGIMAGE window message for it by initializing the drag-and-drop helper object with IDragSourceHelper::InitializeFromWindow. Wenn das Ziel eine DI GETDRAGIMAGE-Nachricht empfängt, legt der Handler die Bitmapinformationen des Ziehbilds in der _ SHDRAGIMAGE-Struktur ab, die als lParam-Wert der Nachricht übergeben wird.
- Windowless drop targets specify a bitmap when they initialize the drag-and-drop helper object with IDragSourceHelper::InitializeFromBitmap.
Verwenden der IDropTargetHelper-Schnittstelle
Diese Schnittstelle ermöglicht es dem Absturzziel, das Drag & Drop-Hilfsobjekt zu benachrichtigen, wenn der Cursor in das Ziel eintritt oder das Ziel verlässt. While the cursor is over the target window, IDropTargetHelper allows the target to give the drag-and-drop helper object the information that the target receives through its IDropTarget interface.
Vier der IDropTargetHelper-Methoden – IDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper::D ragOverund IDropTargetHelper::D rop– sind der IDropTarget-Methode desselben Namens zugeordnet. To use the drag-and-drop helper object, each of the IDropTarget methods should call the corresponding IDropTargetHelper method to forward the information to the drag-and-drop helper object. The fifth IDropTargetHelper method, IDropTargetHelper::Show, notifies the drag-and-drop helper object to show or hide the drag image. Diese Methode wird beim Ziehen über ein Zielfenster in einem Videomodus mit niedriger Farbtiefe verwendet. Dadurch kann das Ziel das Ziehbild ausblenden, während es das Fenster malt.