Zwischenablagevorgänge

Ein Fenster sollte beim Ausschneiden, Kopieren oder Einfügen von Daten die Zwischenablage verwenden. In einem Fenster werden Daten von Ausschneide- und Kopiervorgängen in der Zwischenablage gespeichert und für Einfügevorgänge aus dieser abgerufen. In den folgenden Abschnitten werden diese Vorgänge und damit in Zusammenhang stehende Probleme beschrieben.

Um Daten in der Zwischenablage zu speichern oder daraus abzurufen, muss ein Fenster zuerst die Zwischenablage mithilfe der OpenClipboard-Funktion öffnen. Die Zwischenablage kann immer nur von einem Fenster gleichzeitig geöffnet werden. Rufen Sie die GetOpenClipboardWindow-Funktion auf, um zu ermitteln, welches Fenster die Zwischenablage geöffnet hat. Nach Abschluss des Vorgangs muss das Fenster die Zwischenablage durch einen Aufruf der CloseClipboard-Funktion schließen.

In diesem Abschnitt werden folgende Themen erörtert:

Ausschneide- und Kopiervorgänge

Um Informationen in der Zwischenablage zu speichern, löscht ein Fenster zunächst mithilfe der EmptyClipboard-Funktion alle vorhandenen Inhalte aus der Zwischenablage. Diese Funktion sendet die Nachricht WM_DESTROYCLIPBOARD an den vorherigen Zwischenablagebesitzer, gibt Ressourcen frei, die Daten in der Zwischenablage zugeordnet sind, und weist dem Fenster, in dem die Zwischenablage geöffnet ist, den Besitz der Zwischenablage zu. Um zu ermitteln, welches Fenster die Zwischenablage besitzt, rufen Sie die GetClipboardOwner-Funktion auf.

Nach dem Leeren der Zwischenablage speichert das Fenster Daten in der Zwischenablage in möglichst vielen Zwischenablageformaten, sortiert vom Zwischenablageformat mit der geeignetsten Beschreibung bis zu dem mit der ungeeignetsten. Für jedes Format ruft das Fenster die SetClipboardData-Funktion auf und gibt dabei den Formatbezeichner und ein globaler Speicherhandle an. Das Speicherhandle kann NULL sein. In diesem Fall rendert das Fenster die Daten auf Anforderung. Weitere Informationen finden Sie unter Verzögertes Rendern.

Einfügevorgänge

Zum Abrufen von Einfügeinformationen aus der Zwischenablage bestimmt das jeweilige Fenster zunächst das abzurufende Zwischenablageformat. In der Regel listet ein Fenster die verfügbaren Zwischenablageformate mithilfe der EnumClipboardFormats-Funktion auf und verwendet das erste erkannte Format. Bei dieser Methode wird das beste verfügbare Format gemäß der Priorität ausgewählt, die beim Speichern der Daten in der Zwischenablage festgelegt wurde.

Alternativ kann ein Fenster auch die GetPriorityClipboardFormat-Funktion verwenden. Diese Funktion ermittelt das geeignetste verfügbare Zwischenablageformat gemäß einer angegebenen Priorität. Ein Fenster, das nur ein Zwischenablageformat erkennt, kann einfach mithilfe der IsClipboardFormatAvailable-Funktion bestimmen, ob dieses Format verfügbar ist.

Nach dem Bestimmen des zu verwendenden Zwischenablageformats ruft das Fenster die GetClipboardData-Funktion auf. Diese Funktion gibt das Handle für ein globales Speicherobjekt zurück, das Daten im angegebenen Format enthält. Ein Fenster kann das Speicherobjekt kurz sperren, um die Daten zu untersuchen oder zu kopieren. Ein Fenster sollte das Objekt jedoch nicht für einen längeren Zeitraum freigeben oder sperren.

Besitz der Zwischenablage

Besitzer der Zwischenablage ist das Fenster, das den Informationen in der Zwischenablage zugeordnet ist. Ein Fenster wird zum Besitzer der Zwischenablage, wenn es Daten in der Zwischenablage speichert, insbesondere, wenn es die EmptyClipboard-Funktion aufruft. Das Fenster bleibt so lange Besitzer der Zwischenablage, bis es geschlossen wird oder ein anderes Fenster die Zwischenablage leert.

Wenn die Zwischenablage geleert wird, empfängt der Besitzer der Zwischenablage die Nachricht WM_DESTROYCLIPBOARD. Im Folgenden sind einige Gründe aufgeführt, warum ein Fenster diese Nachricht verarbeiten sollte:

  • Das Fenster hat das Rendern mindestens eines Zwischenablageformats verzögert. Als Reaktion auf die Nachricht WM_DESTROYCLIPBOARD kann das Fenster Ressourcen freigeben, die es reserviert hatte, um Daten auf Anforderung zu rendern. Weitere Informationen zum Rendern von Daten finden Sie unter Verzögertes Rendern.
  • Das Fenster hat Daten in der Zwischenablage in einem privaten Zwischenablageformat gespeichert. Die Daten privater Zwischenablageformate werden vom System nicht freigegeben, wenn die Zwischenablage geleert wird. Daher sollte der Besitzer der Zwischenablage die Daten beim Empfang der Nachricht WM_DESTROYCLIPBOARD freigeben. Weitere Informationen zu privaten Zwischenablageformaten finden Sie unter Zwischenablageformate.
  • Das Fenster hat Daten in der Zwischenablage mithilfe des Zwischenablageformats CF_OWNERDISPLAY gespeichert. Als Reaktion auf die Nachricht WM_DESTROYCLIPBOARD kann das Fenster Ressourcen freigeben, die zum Anzeigen von Informationen im Anzeigefenster der Zwischenablage verwendet wurden. Weitere Informationen zu diesem alternativen Format finden Sie unter Besitzeranzeigeformat.

Verzögertes Rendern

Beim Speichern eines Zwischenablageformats in der Zwischenablage kann ein Fenster das Rendern der Daten in diesem Format verzögern, bis die Daten benötigt werden. Dazu übergibt die Anwendung im hData-Parameter der SetClipboardData-Funktion den Wert NULL. Dies ist nützlich, wenn die Anwendung mehrere Zwischenablageformate unterstützt, deren Rendering zeitaufwendig ist. Durch das Übergeben eines NULL-Handles rendert ein Fenster komplexe Zwischenablageformate nur, wenn sie benötigt werden.

Wenn ein Fenster das Rendern eines Zwischenablageformats verzögert, muss es – so lange es Besitzer der Zwischenablage ist – bereit sein, das Format auf Anforderung zu rendern. Das System sendet dem Zwischenablagebesitzer die Nachricht WM_RENDERFORMAT, wenn eine Anforderung für ein bestimmtes Format empfangen wird, das noch nicht gerendert wurde. Beim Empfang dieser Nachricht sollte das Fenster die SetClipboardData-Funktion aufrufen, um ein globales Speicherhandle in der Zwischenablage im angeforderten Format zu speichern.

Eine Anwendung darf die Zwischenablage nicht öffnen, bevor sie SetClipboardData als Reaktion auf die Nachricht WM_RENDERFORMAT aufruft. Das Öffnen der Zwischenablage ist nicht erforderlich, und jeder entsprechende Versuch führt zu einem Fehler, da die Zwischenablage derzeit von der Anwendung geöffnet ist, die das Rendern des Formats angefordert hat.

Wenn der Besitzer der Zwischenablage zerstört werden soll und das Rendern einiger oder aller Zwischenablageformate verzögert hat, empfängt er die Nachricht WM_RENDERALLFORMATS. Beim Empfang dieser Nachricht sollte das Fenster die Zwischenablage öffnen, mit der GetClipboardOwner-Funktion überprüfen, ob es weiterhin Besitzer der Zwischenablage ist, und dann gültige Speicherhandles für alle bereitgestellten Zwischenablageformate in der Zwischenablage platzieren. Dadurch wird sichergestellt, dass diese Formate nach dem Zerstören des Zwischenablagebesitzers verfügbar bleiben.

Im Gegensatz zu WM_RENDERFORMAT sollte eine Anwendung, die auf WM_RENDERALLFORMATS reagiert, die Zwischenablage öffnen, bevor SetClipboardData aufgerufen wird, um die erforderlichen globalen Speicherhandles in der Zwischenablage zu platzieren.

Zwischenablageformate, die nicht als Reaktion auf die Nachricht WM_RENDERALLFORMATS gerendert werden, sind für andere Anwendungen nicht mehr verfügbar und werden von den Zwischenablagefunktionen nicht mehr aufgelistet.

Leitfaden für verzögertes Rendern

Das verzögerte Rendern ist ein Leistungsfeature, das Anwendungen ermöglicht zu verhindern, dass Zwischenablagedaten in einem Format gerendert werden, das möglicherweise nie angefordert wird. Die Verwendung des verzögerten Renderns weist jedoch die folgenden Nachteile auf, die berücksichtigt werden sollten:

  • Durch die Verwendung des verzögerten Renderns wird die Anwendung etwas komplexer, da zwei Fensternachrichten zum Rendern verarbeitet werden müssen, wie oben beschrieben.
  • Die Verwendung des verzögerten Renderns bedeutet, dass die Anwendung die Möglichkeit verliert, die Benutzeroberfläche reaktionsfähig zu halten, wenn das Rendern der Daten so viel Zeit benötigt, dass es für die Benutzer*innen erkennbar ist. Beim verzögerten Rendern muss das Fenster die Daten, wenn diese benötigt werden, bei der Verarbeitung einer Renderingfensternachricht rendern, wie oben beschrieben. Wenn das Rendern der Daten sehr zeitaufwendig ist, kann die Anwendung daher während des Renderns erkennbar nicht mehr reagieren (hängen), da während des Renderns als Reaktion auf die Renderingfensternachricht keine anderen Fensternachrichten verarbeitet werden können. Eine Anwendung, die das verzögerte Rendering nicht verwendet, kann stattdessen festlegen, dass Daten in einem Hintergrundthread gerendert werden, um die Reaktionsfähigkeit der Benutzeroberfläche während des Rendern zu erhalten, z. B. durch die Bereitstellung von Fortschritts- oder Abbruchoptionen, die bei Verwendung des verzögerten Renderings nicht verfügbar sind.
  • Die Verwendung des verzögerten Renderns verursacht einen geringen Mehraufwand, wenn die Daten letztendlich benötigt werden. Bei Verwendung des verzögerten Renderns ruft ein Fenster zunächst die SetClipboardData-Funktion mit einem NULL-Handle auf. Wenn die Daten dann später benötigt werden, muss das Fenster auf eine Fensternachricht reagieren und die SetClipboardData-Funktion ein zweites Mal mit einem Handle für die gerenderten Daten aufrufen, wie oben beschrieben. Wenn die Daten schließlich benötigt werden, verursacht das verzögerte Rendern Mehraufwand für die Verarbeitung einer Fensternachricht und den zweiten Aufruf der SetClipboardData-Funktion. Dieser Mehraufwand ist gering, aber nicht null. Wenn eine Anwendung nur ein einzelnes Zwischenablageformat unterstützt und die Daten letztendlich immer angefordert werden, verursacht das verzögerte Rendern immer diesen geringen Mehraufwand (er variiert je nach Hardware und liegt geschätzt zwischen 10 und 100 Mikrosekunden). Wenn die Daten jedoch klein sind, kann der Mehraufwand für die Verwendung des verzögerten Renderns den Aufwand zum Rendern der Daten überschreiten und damit den eigentlichen Zweck des verzögerten Renderns zur Verbesserung der Leistung beeinträchtigen. (Bei Daten, die bereits in ihrer endgültigen Form vorliegen, übersteigt der Mehraufwand für die Verwendung des verzögerten Renderns die Kosten zum Kopieren der Daten in die Zwischenablage bereits, wenn die Daten nicht mehr als 100 KiB groß sind. Diese Tests umfassen nicht den Aufwand zum Rendern von Daten, sondern nur das Kopieren der Daten nach dem Rendern.)
  • Das verzögerte Rendern bietet ein Leistungsvorteil, wenn es mehr Zeit einspart, als es Mehraufwand verursacht. Um den Aufwand für das verzögerte Rendern zu ermitteln, eignet sich eine Messung am besten, aber 10 bis 100 Mikrosekunden sind eine plausible Schätzung. Um die Einsparungen bei der Verwendung des verzögerten Renderns für jedes Zwischenablageformat zu berechnen, messen Sie den Aufwand zum Rendern der Daten in diesem Format und bestimmen, wie häufig dieses Format letztendlich angefordert wird (basierend auf den oben beschriebenen Fensternachrichten). Multiplizieren Sie die Kosten für das Rendern der Daten mit dem Prozentsatz der Zeit, die die Daten nicht angefordert werden (bevor die Zwischenablage geleert wird oder sich der Inhalt ändert), um die Einsparungen des verzögerten Renderns für jedes Zwischenablageformat zu bestimmen. Das verzögerte Rendern bietet ein Nettoleistungsvorteil, wenn die Einsparungen den Mehraufwand übersteigen.
  • Als konkrete Richtlinie sollten Sie für Anwendungen, die nur ein einzelnes Zwischenablageformat unterstützen (z. B. Text), bei dem die Daten nicht wesentlich aufwendiger zu rendern sind, in Betracht ziehen, die Daten direkt in der Zwischenablage zu speichern, wenn die Größe der Daten 4 KiB nicht übersteigt.

Arbeitsspeicher und Zwischenablage

Ein Speicherobjekt, das in der Zwischenablage gespeichert werden soll, sollte mithilfe der GlobalAlloc-Funktion und dem GMEM_MOVEABLE-Flag zugewiesen werden.

Nachdem ein Speicherobjekt in der Zwischenablage gespeichert wurde, wird der Besitz dieses Speicherhandles an das System übertragen. Wenn die Zwischenablage geleert wird und das Speicherobjekt eines der folgenden Zwischenablageformate aufweist, gibt das System das Speicherobjekt frei, indem die angegebene Funktion aufgerufen wird:

Funktion zum Freigeben des Objekts Zwischenablageformat
DeleteMetaFile
CF_DSPENHMETAFILE
CF_DSPMETAFILEPICT
CF_ENHMETAFILE
CF_METAFILEPICT
DeleteObject
CF_BITMAP
CF_DSPBITMAP
CF_PALETTE
GlobalFree
CF_DIB
CF_DIBV5
CF_DSPTEXT
CF_OEMTEXT
CF_TEXT
CF_UNICODETEXT
Keine
CF_OWNERDISPLAY
Wenn die Zwischenablage eines CF_OWNERDISPLAY-Objekts geleert wird, muss die Anwendung selbst das Speicherobjekt freigeben.