Wie Zwischenablage und Drag-and-Drop funktionieren — OLE-Datenübertragung in Geschäftsanwendungen richtig behandeln

· · Windows, Zwischenablage, Drag-and-Drop, OLE, COM, Windows-Entwicklung, WinForms, WPF

„Wenn wir eine aus Excel kopierte Tabelle einfügen, fällt die Formatierung auseinander. Wir wollen, dass sie als Tabelle eingefügt wird.“ „Inhalt, den wir in unserer App kopieren, wird zu etwas Seltsamem, wenn wir ihn in Word einfügen.“ „Wir wollen Dateien per Drag-and-Drop aufnehmen können.“ — In Beratungsgesprächen über Änderungen an Geschäftsanwendungen sind Anfragen rund um Kopieren-und-Einfügen und Drag-and-Drop (D&D) ein Grundnahrungsmittel.

Gerade weil dies „Funktionen sind, die jeder als selbstverständlich nimmt“, ist, wie sie tatsächlich funktionieren, überraschend wenig bekannt. Wenn Sie die Zwischenablage als „eine Kiste, in die Sie ein Datenstück legen“ denken, können Sie nicht erklären, warum dieselbe Kopie je nach Einfügeort verschiedene Ergebnisse erzeugt, oder warum Einfügen aufhört zu funktionieren, nachdem Sie die Quell-App geschlossen haben. Die wirkliche Zwischenablage ist ein Mechanismus, der denselben Inhalt in mehreren Formaten gleichzeitig ablegt und die Einfügeseite ein Format wählen lässt, das sie versteht.

Und Drag-and-Drop ist im Grunde OLE-Datenübertragung, die genau dieselbe Datendarstellung wie die Zwischenablage (IDataObject) über COM-Schnittstellen übergibt. Mit anderen Worten: Kopieren-und-Einfügen und D&D sind Geschwister: Verstehen Sie eines richtig, liegt das andere direkt daneben.

Dieser Artikel richtet sich an IT-Personal in kleinen und mittleren Unternehmen und an Windows-App-Entwickler. Er bindet in einem einzigen Bild zusammen, wie Zwischenablageformate funktionieren, die Praktiken auf der Einfügeseite und der Kopierseite, die richtige Art, die Zwischenablage zu überwachen, die Verwaltungsrichtlinien für Zwischenablageverlauf, Cloud-Synchronisierung und RDP sowie die Struktur und Fallstricke von OLE-Drag-and-Drop.

1. Zuerst das Fazit

  • Die Zwischenablage ist ein einzelner Bereich, den die Apps auf demselben Desktop (Window Station) teilen, und was dort sitzt, ist nicht „ein Datenstück“, sondern derselbe Inhalt in mehreren Formaten gleichzeitig. Eine andere Sitzung, etwa RDP, hat ursprünglich eine andere Zwischenablage; die Umleitungsfunktion ist das, was die zwei überbrückt. Weil das Ziel ein Format wählt, das es versteht, erzeugt dieselbe Kopie je nach Einfügeort verschiedene Ergebnisse.12
  • Für Text nutzen Sie CF_UNICODETEXT. CF_TEXT ist ANSI und codepage-abhängig, und auf japanischen Systemen ist es ein Brutplatz für Mojibake. Das System wandelt zwischen den zwei implizit um, aber die kanonische Seite ist Unicode.3
  • Dateien reisen als CF_HDROP (ein doppelt-NUL-terminiertes Array von Pfaden), und formatierter Text nutzt das registrierte Format „HTML Format“. HTML Format hat eine ungewöhnliche Struktur: UTF-8-Text mit einem Header aus Byte-Offsets.45
  • Die wirkliche Ursache von „ich habe die Quell-App geschlossen und konnte nicht mehr einfügen“ ist verzögertes Rendering. Es ist ein Mechanismus, der nicht die Nutzlast, sondern nur ein Versprechen ablegt, sie „zu erzeugen, wenn gefragt“; wenn Sie das Materialisieren beim Ende überspringen (Antwort auf WM_RENDERALLFORMATS, oder OleFlushClipboard für OLE), hört Einfügen auf zu funktionieren.26
  • Behandeln Sie eingefügte Daten als nicht vertrauenswürdige Eingabe von außen. Microsoft selbst stellt deutlich fest, dass „Zwischenablagedaten nicht vertrauenswürdig sind. Parsen Sie sie sorgfältig“.7
  • Für das Überwachen der Zwischenablage ist AddClipboardFormatListener + WM_CLIPBOARDUPDATE die einzige Option. Nutzen Sie kein Polling und nicht das alte SetClipboardViewer (die Viewer-Kette). Registrierte Formate, die Geheimnisse aus Verlauf und Synchronisierung heraushalten (ExcludeClipboardContentFromMonitorProcessing und Freunde), sind ebenfalls bereitgestellt.81
  • Zwischenablageverlauf (Win+V) und Cloud-Synchronisierung sind eine IT-Verwaltungsangelegenheit. Sie können sie mit AllowClipboardHistory und AllowCrossDeviceClipboard über GPO / Intune (Policy CSP) steuern, und RDP-Zwischenablageumleitung hat eine eigene dedizierte Richtlinie.91011
  • Drag-and-Drop ist COM. Dasselbe IDataObject wie die Zwischenablage wird zwischen IDropSource (der Ziehquelle) und IDropTarget (dem Ablegeziel) durch die DoDragDrop-Schleife übergeben. RegisterDragDrop verlangt Initialisierung mit OleInitialize (STA).1213
  • Sie können nicht vom Datei-Explorer mit gewöhnlichen Rechten auf eine erhöhte App ablegen. UIPI (Nachrichtenblockierung nach Integritätsstufe) ist die Ursache, und es ist eine Einschränkung, die Sie zur Entwurfszeit kennen sollten.14

Im Folgenden gehen wir das von den Zwischenablagegrundlagen aufwärts durch.

2. Was die Zwischenablage wirklich ist — Nicht „ein Datenstück“, sondern „derselbe Inhalt in mehreren Formaten“

Die Zwischenablage ist ein gemeinsamer Datenteilungsmechanismus, den jede App erreichen kann, die denselben Desktop teilt (genauer: sie ist pro Window Station: eine andere Benutzer- oder RDP-Sitzung hat jeweils ihre eigene Zwischenablage. Kopieren-und-Einfügen funktioniert über RDP, weil die Umleitungsfunktion die zwei überbrückt — Kapitel 7). Das erste Prinzip ist, dass sie benutzergesteuert ist: Die offizielle Entwurfsposition ist, dass Sie Daten nicht hinter dem Rücken des Benutzers hineinlegen oder herausnehmen.1

Der wichtige Punkt ist, dass eine Kopie nicht „ein Datenstück“ ablegt. Das Fenster, das kopiert, leert die Zwischenablage und legt dann mehrere Formate hintereinander ab, die denselben Inhalt vom fähigeren Format zum weniger fähigen ausdrücken.2 Zum Beispiel liegt, wenn Sie eine Tabelle in einer Tabellenkalkulation kopieren, begrifflich etwa Folgendes gleichzeitig auf der Zwischenablage.

Priorität Format Inhalt
1 App-privates Format Eine vollständige interne Darstellung, einschließlich Formeln und Formatierung (zum Wiedereinfügen in dieselbe App)
2 HTML Format Ein HTML-Fragment, das die Tabellenstruktur und Formatierung behält
3 CSV Zellengetrennter Text
4 CF_UNICODETEXT Tabulatorgetrennter einfacher Text
5 Bildformat Ein Bitmap davon, wie die Tabelle aussieht

Die Einfügeseite wählt aus dieser Liste ein Format, das sie versteht, und extrahiert es. In Word einfügen und Sie bekommen eine formatierte Tabelle; in Editor einfügen und Sie bekommen tabulatorgetrennten Text — weil die zwei verschiedene Formate gewählt haben. „Das Ergebnis hängt davon ab, wo Sie einfügen“ ist kein Fehler; es ist die normale Folge dieses Entwurfs.

Warum dieselbe Kopie je nach Einfügeort verschiedene Ergebnisse erzeugtDie Kopierseite legt denselben Inhalt in mehreren Formaten auf die Zwischenablage, und die Einfügeseite wählt ein Format, das sie versteht, sodass Word eine formatierte Tabelle bekommt und Editor tabulatorgetrennten TextWordEditorKopieren: TabellenkalkulationZwischenablage(viele Formate)Reichere FormateEinfachere FormateApp-privatHTML FormatCSVCF_UNICODETEXTFormatierte TabelleTabulatorgetrennter Text

Andersherum: Die Eingangsbeschwerden — „die Formatierung fällt auseinander“, „etwas Seltsames wird eingefügt“ — reduzieren sich fast alle auf ein Problem davon, wie eine Seite Formate wählt oder wie die andere sie anbietet. Kapitel 4 behandelt die Einfügeseite; Kapitel 5 die Kopierseite.

3. Standardformate und registrierte Formate — CF_UNICODETEXT, CF_HDROP, HTML Format

3.1. Standardformate — Nutzen Sie für Text die Unicode-Seite

Formate, die das Betriebssystem im Voraus definiert, heißen Standardformate. Die, die in Geschäftsanwendungen ständig auftauchen, sind die folgenden.3

Format Wert Inhalt
CF_TEXT 1 ANSI-Text (codepage-abhängig)
CF_UNICODETEXT 13 Unicode-Text. Das ist das kanonische Format für Text
CF_HDROP 15 Eine Liste von Dateipfaden (ein HDROP-Handle)
CF_DIB 8 Ein geräteunabhängiges Bitmap
CF_LOCALE 16 Der dem Text zugeordnete Gebietsschema-Bezeichner

CF_TEXT und CF_UNICODETEXT werden vom System implizit ineinander umgewandelt (synthetisierte Formate). Die Zeichencodeumwandlung nutzt die Codepage, die CF_LOCALE zugeordnet ist.3 Sich auf diese Umwandlung zu verlassen, wirft Zeichen weg, die ANSI nicht darstellen kann (zum Beispiel nur-Unicode-Symbole und kombinierende Zeichen), also lautet die Regel: vereinheitlichen Sie, was die App liest und schreibt, auf CF_UNICODETEXT (DataFormats.UnicodeText in .NET).

Implizite Umwandlung zwischen CF_UNICODETEXT und CF_TEXTDie App liest und schreibt nur CF_UNICODETEXT; das System synthetisiert CF_TEXT durch implizite Umwandlung mit der CF_LOCALE-Codepage. Zeichen, die ANSI nicht darstellen kann, werden in dieser Umwandlung weggeworfenCF_LOCALE-UmwandlungApp liest und schreibtCF_UNICODETEXTCF_TEXT(ANSI)Nicht darstellbare Zeichen werden weggeworfen

3.2. CF_HDROP — Dateien reisen als „eine Liste von Pfaden“

CF_HDROP ist das, was genutzt wird, wenn Sie Dateien im Datei-Explorer kopieren oder Dateien ziehen und ablegen. Die Nutzlast sind nicht die Dateien selbst; es ist ein Speicherblock, der ein „doppelt-NUL-terminiertes“ Array auslegt: nach einem DROPFILES-Struktur-Header Vollpfadzeichenfolgen, getrennt durch NUL-Zeichen, und eine leere Zeichenfolge am Ende. Das pFiles des Headers ist der Start-Offset der Pfadliste, und fWide sagt, ob die Zeichenfolgen Unicode sind.4

[DROPFILES header: pFiles=start offset of the path list, fWide=1(Unicode)]
C:\data\a.txt(NUL)C:\data\b.txt(NUL)(NUL)

In nativem Code ziehen Sie sie einzeln mit DragQueryFile heraus; in .NET empfangen Sie sie als string[] über DataFormats.FileDrop. Die Tatsache, dass „was reist, nur die Pfade sind, nicht die Dateien selbst“, wird in dem D&D der Kapitel 8 und 9 wieder zählen.

Speicherblock-Layout von CF_HDROPEine DROPFILES-Struktur sitzt am Anfang des globalen Speichers; pFiles ist der Start-Offset der Pfadliste und fWide sagt, ob es Unicode ist. Vollpfade folgen dann, NUL-getrennt, und der Block endet mit einer leeren Zeichenfolge(doppeltes NUL). Was reist, sind nur die Pfade, nicht die Dateien selbstDROPFILES(pFiles / fWide)C:\\data\\a.txt + NULC:\\data\\b.txt + NULLeere Zeichenfolge(doppeltes NUL)Nur Pfade reisen, nicht Dateien

3.3. Registrierte Formate — RegisterClipboardFormat und „HTML Format“

Für Daten, die Standardformate nicht ausdrücken können, kann eine App einen Namen wählen und ihr eigenes Format registrieren. Übergeben Sie einen Namen an RegisterClipboardFormat und Sie bekommen eine Format-ID zurück; das Registrieren unter demselben Namen aus einer anderen App gibt dieselbe ID zurück, sodass Sie einmal, wenn Sie sich auf den Namen einigen, Daten zwischen Apps teilen können.1 Wenn Sie strukturierte Daten unter Ihrer eigenen App-Suite übergeben, nutzen Sie einen Namen, der nicht kollidiert, etwa KomuraSoft.Report.RowData.

Das repräsentative registrierte Format ist „HTML Format“, für formatierten Text (zusammen mit RTF eines der zwei großen Rich-Text-Formate). Die Nutzlast ist UTF-8-Text, hat aber eine ungewöhnliche Struktur: ein Header, der Byte-Offsets auflistet, ist vorne angehängt.5

Version:0.9
StartHTML:<byte offset of the start of the whole HTML>
EndHTML:<byte offset of the end of the whole HTML>
StartFragment:<byte offset of the start of the fragment>
EndFragment:<byte offset of the end of the fragment>
<html><body>
<!--StartFragment--><b>bold</b> fragment text<!--EndFragment-->
</body></html>

Jeder Offset ist eine Byte-Position vom Anfang der Daten, einschließlich des Headers selbst; die übliche Praxis ist, eine feste Breite zu reservieren (zum Beispiel 10 Ziffern) und die gemessenen Werte zurückzuschreiben, nachdem Sie den Körper gebaut haben. StartFragment/EndFragment markieren Anfang und Ende „des Fragments, das der Benutzer tatsächlich ausgewählt hat“ in Bytes (nicht in Zeichen). In UTF-8, das Japanisch einschließt, weichen Zeichenzahl und Bytezahl auseinander, also wirft Einfügen in eine andere App den Anfang oder das Ende weg, wenn Sie diese Offset-Berechnung falsch machen. Wenn Sie HTML Format selbst erzeugen, müssen Sie den Header mit Byte-Positionen füllen, die nach der Kodierung nach UTF-8 gemessen sind.5

Wie der HTML-Format-Header zu den Offsets stehtDas StartHTML und EndHTML des Headers zeigen auf das ganze HTML, und StartFragment und EndFragment zeigen auf das vom Benutzer ausgewählte Fragment, beides als Byte-Positionen vom Anfang der Daten. Weil Zeichenzahl und Bytezahl in UTF-8 auseinanderweichen, füllen Sie den Header mit Byte-Positionen, die nach der Kodierung gemessen sindHeader(Byte-Offsets)Ganzes HTMLAusgewähltes FragmentOffsets sind Bytes nach UTF-8

CSV (DataFormats.CommaSeparatedValue in .NET) wird für tabellarische Daten ebenfalls häufig genutzt. Für die Zusammenarbeit mit Excel bedeutet das gleichzeitige Anbieten von HTML Format (mit Formatierung), CSV (nur Werte) und CF_UNICODETEXT (tabulatorgetrennt), dass Sie kein einzelnes Einfügeziel wählen müssen.

4. Praktiken auf der Einfügeseite — Formatpriorität und Validierung

4.1. Schauen Sie von reichen Formaten abwärts

Die Formate auf der Zwischenablage sind in der Reihenfolge aufgereiht, in der die Kopierseite sie abgelegt hat (das heißt vom ausdrucksstärkeren zum weniger ausdrucksstarken). Die Grundlinie der Einfügeseite ist, unter den Formaten, die Sie behandeln können, vom dem mit den meisten Informationen an zu schauen. In Win32 zählen Sie entweder mit EnumClipboardFormats auf und nutzen das erste Format, das Sie erkennen, oder Sie übergeben Ihre eigene Prioritätsliste an GetPriorityClipboardFormat und lassen es wählen.2

In .NET sieht die Verzweigung etwa wie folgt aus.

// Pasting a table: look from rich to plain
var data = Clipboard.GetDataObject();
if (data is null) return;

// Advertising a format does not guarantee the payload is a string. Use this
// branch only when the type also checks out; otherwise fall through to the next candidate
if (data.GetDataPresent(DataFormats.Html)
    && data.GetData(DataFormats.Html) is string html)
{
    // Validate the HTML Format header, then import as a table
}
else if (data.GetDataPresent(DataFormats.CommaSeparatedValue))
{
    // Import as CSV
}
else if (data.GetDataPresent(DataFormats.UnicodeText))
{
    // Import as tab-separated text
}

Das ist die Antwort auf die Eingangsbeschwerde „das Einfügen einer Excel-Tabelle fällt auseinander“. Eine App, die nur einfachen Text liest, empfängt die Tabellenstruktur nie. Wie weit unten auf der Formatliste Sie akzeptieren, ist eine Entwurfsentscheidung auf der Einfügeseite.

Einfügeverzweigung, die von reichen Formaten abwärts schautWenn HTML Format vorhanden ist und die Nutzlast auch eine Zeichenfolge ist, als Tabelle importieren; sonst CSV versuchen; fehlt das auch, auf tabulatorgetrennten Text fallen. Ist keiner der Kandidaten vorhanden, ablehnenjaneinjaneinjaneinEinfügen beginnenHTML Format + Zeichenfolge?Header validieren → TabelleCSV vorhanden?Als CSV importierenUnicodeText?Tabulatorgetrennter TextAblehnen

4.2. Eingefügte Daten sind äußere Eingabe

Es ist leicht zu übersehen, aber Zwischenablageinhalte sind Daten von außen, und Sie wissen nicht, welche App sie abgelegt hat. Microsoft warnt auch in der OLE-Zwischenablagedokumentation, dass „Zwischenablagedaten nicht vertrauenswürdig sind. Parsen Sie sie sorgfältig, bevor Sie sie in der App nutzen“.7

  • Validieren Sie, dass HTML-Format-Header-Offsets nicht außerhalb des Puffers zeigen (Apps, die kaputte Header ausgeben, existieren).
  • Werte, die Sie als Zahlen, Daten oder Codes importieren, sollten durch dieselbe Validierung gehen wie Bildschirmeingabe.
  • Setzen Sie eine Verteidigung gegen riesige Daten ein. Selbst wenn jemand ein Bild von Hunderten Megabyte oder Millionen Zeilen Text einfügt, blockieren Sie die UI nicht, und lehnen Sie ab, sobald eine Grenze überschritten ist. Eine Vorsicht: .NETs GetData materialisiert im Moment des Aufrufs die ganze Nutzlast in eine verwaltete Zeichenfolge (und verzögertes Rendering läuft als Teil davon), also ist eine Größenprüfung nach GetData keine Verteidigung. In Win32 gibt das Prüfen von GlobalSize auf dem HGLOBAL, den GetClipboardData zurückgibt, Ihnen eine Verteidigung auf der Stufe „nicht in Umwandlung und Parsen als verwaltete Zeichenfolge fortfahren“, aber für Formate mit verzögertem Rendering stößt GetClipboardData selbst das Rendering an, sodass Sie Materialisierung auf der Kopierquellseite trotzdem nicht verhindern können. Um die UI am Einfrieren zu hindern, nehmen Sie das Holen vom UI-Thread herunter (und selbst dann, weil .NETs Clipboard STA verlangt, tun Sie es auf einem eigenen Thread, der auf STA gesetzt ist, nicht auf dem Task.Run-Thread-Pool-Thread (MTA) — Abschnitt 5.1).

Die Idee, dass „ein Wert, der von außen ankommt, welchen Pfad auch immer, validiert wird, bevor Sie ihn nutzen“, ist dieselbe, die in „Verwenden Sie den ausgelesenen Wert eines QR-Codes nie ungeprüft“ ausgelegt ist. Die Annahme, Einfügen sei sicher, weil es eine Benutzeraktion ist, ist, wie Unfälle beginnen.

Validieren Sie eingefügte Daten, bevor Sie sie nutzenDaten, die aus der Zwischenablage genommen werden, gehen der Reihe nach durch Format-vorhanden, Nutzlasttyp, Größengrenze und Inhaltsvalidierung; scheitert eines davon, lehnen Sie ab oder fallen Sie auf das nächste Kandidatenformatfalscher Typzu großungültigFormat vorhanden?Nutzlasttyp in Ordnung?Größe innerhalb der Grenze?Inhalt validierenImportierenAblehnen / nächstes Format

5. Praktiken auf der Kopierseite — Mehrere Formate gleichzeitig anbieten, und verzögertes Rendering

5.1. Legen Sie mehrere Formate gleichzeitig ab

Die Praxis der Kopierseite ist die Umkehrung von 4.1: bieten Sie ein reiches Format und ein einfaches Format gleichzeitig an. Mit dem WinForms/WPF-DataObject können Sie es in wenigen Zeilen schreiben.15

// WinForms (System.Windows.Forms). WPF is the same shape with System.Windows DataObject/Clipboard
var data = new DataObject();
data.SetData(DataFormats.Html, htmlFormatText);       // HTML Format string including the header
data.SetData(DataFormats.CommaSeparatedValue, csv);   // CSV
data.SetData(DataFormats.UnicodeText, plainText);     // Plain text
Clipboard.SetDataObject(data, copy: true);            // copy:true = keep after the app exits

Zwei Hinweise. Erstens: .NETs Clipboard-Klasse kann nur von einem STA-Thread genutzt werden.15 Der WinForms/WPF-UI-Thread ist wegen [STAThread] STA, also ist das normalerweise kein Problem, aber sie von einem Hintergrundthread anzufassen schlägt fehl (die STA/MTA-Grundlagen stehen in „Grundlagenwissen zu COM STA/MTA“). Zweitens: Was copy: true bedeutet, ist an verzögertes Rendering im nächsten Unterabschnitt gebunden.

5.2. Verzögertes Rendering — Warum „Quelle schließen und Sie können nicht einfügen“

Jedes Mal eine große Nutzlast in vielen Formaten zu bauen ist verschwenderisch, also hat die Zwischenablage einen Mechanismus namens verzögertes Rendering. Übergeben Sie NULL als Daten-Handle an SetClipboardData, und statt der Nutzlast wird nur ein Versprechen registriert, sie „zu erzeugen, wenn gefragt“; wenn jemand dieses Format anfordert, kommt WM_RENDERFORMAT an der Kopierquelle an, und erst dann werden die Daten erzeugt.2

Die Folge dieses Entwurfs ist das Eingangs-„ich habe die Quell-App geschlossen und konnte nicht mehr einfügen“. Bevor sie endet, empfängt die Kopierquelle WM_RENDERALLFORMATS und ist verantwortlich, jedes Format zu materialisieren, das noch nicht gerendert ist; enden Sie ohne das, und das Format ist verloren.2

Verzögertes Rendering und warum Schließen-dann-Einfügen fehlschlägtDie Kopierquelle registriert mit einem NULL-Handle nur ein Versprechen und materialisiert auf Anforderung über WM_RENDERFORMAT. Beim Ende ist sie verantwortlich, jedes Format mit WM_RENDERALLFORMATS zu materialisieren; überspringen Sie das, und das Format ist verlorenRENDERALLFORMATSMaterialisieren überspringenSetClipboardData NULL = VersprechenEinfügeseite fordert es anWM_RENDERFORMAT → jetzt bauenKopierquelle im Begriff zu endenEinfügen funktioniert nach dem EndeFormat nach dem Schließen verloren

Auf der OLE-Zwischenablage (der Stil, der ein IDataObject mit OleSetClipboard ablegt) ist diese Beziehung noch klarer. Alles, was die Zwischenablage hält, ist ein Zeiger auf das Datenobjekt, und das Aufrufen von OleFlushClipboard beim App-Ende materialisiert die Daten auf die Zwischenablage, sodass Einfügen nach dem Ende noch funktioniert.6 .NETs Clipboard.SetDataObject(data, copy: true) ist das, was dieses Verhalten „nach dem Ende behalten“ angibt.

Wenn Sie in Excel einen großen Bereich kopieren und zu beenden versuchen, ist die Aufforderung „Auf der Zwischenablage befindet sich eine große Menge Informationen. Möchten Sie diese Informationen später in ein anderes Programm einfügen können?“ genau die Bestätigung, ob diese Materialisierung (der Flush) ausgeführt werden soll. Wenn Sie verzögertes Rendering in Ihrer eigenen App nutzen, denken Sie daran, dass die Materialisierung zur Endezeit Teil desselben Satzes ist. Verzögertes Rendering ist eine Leistungsoptimierung, und weil die Renderanforderung synchron innerhalb der Nachrichtenverarbeitung läuft, hat Daten, deren Erzeugung lange dauert, den Kompromiss, die UI einzufrieren.2

6. Praktiken für das Überwachen der Zwischenablage — Listener, Wiederholung und Verlaufsausschluss

6.1. Nutzen Sie AddClipboardFormatListener

Anforderungen wie „wir wollen einen Barcode-Leser-Wert oder eine Kopie aus dem Fachsystem erkennen und automatisch importieren“ erfordern, Zwischenablageänderungen zu überwachen. Historisch gibt es drei Methoden; heute ist die richtige Antwort eine.8

Methode Einschätzung
Auf einem Timer lesen (Polling) Verschwenderisch, und Sie können Aktualisierungen verpassen. Nicht nutzen
SetClipboardViewer (Viewer-Kette) Ein Fehler in einer App in der Kette bricht die ganze Kette. Nur für Abwärtskompatibilität gehalten
AddClipboardFormatListener Empfohlen. WM_CLIPBOARDUPDATE kommt am registrierten Fenster an
Ablauf der ZwischenablageüberwachungRegistrieren Sie mit AddClipboardFormatListener, wenn das Handle angelegt wird, und WM_CLIPBOARDUPDATE kommt an, gleich welche App kopiert hat. Lesen Sie mit einer Wiederholung, und deregistrieren Sie symmetrisch mit RemoveClipboardFormatListener, wenn das Handle zerstört wirdderegistrierenAddClipboardFormatListenerWartenIrgendeine App kopiertWM_CLIPBOARDUPDATEMit Wiederholung lesen(6.2)RemoveClipboardFormatListener
// Minimal WinForms implementation
public partial class MainForm : Form
{
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool AddClipboardFormatListener(IntPtr hwnd);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
    const int WM_CLIPBOARDUPDATE = 0x031D;

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        AddClipboardFormatListener(Handle);
    }

    protected override void OnHandleDestroyed(EventArgs e)
    {
        // Unregister symmetrically to match handle destruction / recreation
        RemoveClipboardFormatListener(Handle);
        base.OnHandleDestroyed(e);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_CLIPBOARDUPDATE)
        {
            // Read Clipboard.GetDataObject() here and import if the format is one you need
        }
        base.WndProc(ref m);
    }
}

6.2. Wiederholen, wenn Sie sie nicht öffnen können

Nur ein Fenster zur Zeit kann die Zwischenablage öffnen; während ein anderer Prozess sie offen hat, schlägt OpenClipboard fehl.2 Unmittelbar nach WM_CLIPBOARDUPDATE ist die Kopierquelle oder ein anderer Überwacher oft noch in Betrieb, also ist ein vorübergehender Lesefehler ein normales Ereignis. Setzen Sie immer ein paar Wiederholungen mit einem kurzen Warten (mehrere zehn Millisekunden) dazwischen ein. Beachten Sie, dass die .NET-Clipboard-Überladungen, die Sie eine Wiederholungszahl und ein Intervall angeben lassen, nur auf der Schreibseite existieren, SetDataObject. Auf der Leseseite (GetDataObject und Freunde) gibt es kein Äquivalent, also schreiben Sie das Fangen-Warten-Wiederholen selbst — ExternalException unter WinForms, COMException unter WPF.

Ablauf der Wiederholung beim Zwischenablage-LesenNur ein Fenster zur Zeit kann die Zwischenablage öffnen, also kann ein Lesen direkt nach der Änderungsbenachrichtigung fehlschlagen, weil es mit einem anderen Prozess um die Wette läuft. Bei einer Ausnahme warten Sie mehrere zehn Millisekunden und wiederholen; treffen Sie die Grenze, geben Sie diesmal auf und holen Sie es bei der nächsten AktualisierungErfolgin NutzungwiederholenGrenzeWM_CLIPBOARDUPDATEEin Lesen versuchenImportieren(Prüfungen aus Kap. 4)Mehrere zehn ms wartenDiesmal aufgeben

6.3. Halten Sie es aus Verlauf und Synchronisierung heraus — Sorgfalt für Kopierfunktionen, die Geheimnisse behandeln

Windows hat Zwischenablageverlauf (Win+V) und geräteübergreifende Synchronisierung (die Cloud-Zwischenablage), und Daten, die eine App ablegt, sind standardmäßig für beides im Geltungsbereich. Eine App, die Geheimnisse wie Kennwörter oder Kontonummern auf eine Kopierfunktion legt, legt auch ein registriertes Format ab, das den Inhalt aus Verlauf und Synchronisierung ausschließt.1

  • ExcludeClipboardContentFromMonitorProcessing: Legen Sie das ab, und der Inhalt dieser Kopie ist weder im Verlauf noch in der Synchronisierung enthalten.
  • CanIncludeInClipboardHistory (DWORD 0): Nur den Verlauf unterdrücken.
  • CanUploadToCloudClipboard (DWORD 0): Nur die geräteübergreifende Synchronisierung unterdrücken.

Der Grund, warum ein von einem Kennwortmanager kopiertes Kennwort nicht auf Win+V bleibt, ist dieser Mechanismus. Sie bekommen eine Format-ID, indem Sie den Namen an RegisterClipboardFormat übergeben, und setzen sie neben die gewöhnlichen Daten, also lohnt sich die Umsetzung in jeder Geschäftsanwendung, die Geheimnisse behandelt.

7. Die Zwischenablage aus IT-Sicht — Verlauf, Cloud-Synchronisierung und RDP-Steuerungen

Einen Schritt von der Entwicklung weg sind hier die Punkte, die für einen Administrator zählen. Zwischenablageverlauf sammelt jüngste Kopien, und die Cloud-Zwischenablage synchronisiert Kopien über Geräte, die mit demselben Microsoft-Konto / Microsoft-Entra-Konto angemeldet sind.10 So bequem das ist, erzeugt es auch Rückstände und Überlaufen: aus einem Fachsystem kopierte personenbezogene Daten sammeln sich im Verlauf, und auf einem Arbeits-PC kopierter Inhalt synchronisiert sich auf einen privaten PC.

Die zwei Richtlinien, mit denen Sie das in einer Organisation steuern, sind die folgenden.

Was Sie steuern GPO (Computerkonfiguration > Administrative Vorlagen > System > Betriebssystemrichtlinien) Policy CSP (Intune) Vorgabe
Zwischenablageverlauf Allow Clipboard History Experience/AllowClipboardHistory Erlaubt
Geräteübergreifende Synchronisierung Allow Clipboard synchronization across devices Privacy/AllowCrossDeviceClipboard Erlaubt

Beide sind ab Windows 10 Version 1809 verfügbar; deaktivieren Sie sie, und die entsprechenden Einträge in der Einstellungen-App sind ausgegraut, und die Richtlinie greift sofort.910

Das andere Grundnahrungsmittel ist RDP-Zwischenablageumleitung (Remotedesktop). Standardmäßig funktioniert Kopieren-und-Einfügen zwischen dem lokalen PC und der Remotesitzung, also kann es ein Pfad werden, Geheimnisse von einem Server herunterzunehmen. Die Richtlinie „Zwischenablageumleitung nicht zulassen“ (Registrierungswert fDisableClip) kann beide Richtungen blockieren.11 Jüngere Windows-Server- / Windows-11-Versionen haben auch feinere Richtlinien hinzugefügt, etwa die Richtung Server-zu-Client auf nur Text einzuengen. Ob Sie es ganz verbieten oder gestuft einschränken, ist eine Balance aus Betrieb und Sicherheit.

Pfade, entlang derer Zwischenablageinhalte sich ausbreiten können, und die SteuerpunkteKopierte Inhalte sind standardmäßig für Verlauf und Cloud-Synchronisierung im Geltungsbereich, und auf RDP reisen sie über Umleitung in eine andere Sitzung. Jeder Pfad kann durch Richtlinie gesteuert werden, und die App-Seite kann sich mit den Ausschlussformaten aus Verlauf und Synchronisierung ausschließenZwischenablageVerlauf(Win+V)Cloud-SynchronisierungRDP-UmleitungAllowClipboardHistoryAllowCrossDeviceClipboardfDisableClipApp-Ausschlussformate(6.3)

8. Drag-and-Drop ist COM — IDataObject + IDropSource + IDropTarget

8.1. Dieselben Daten wie die Zwischenablage, eine andere Art sie zu tragen

OLE-Drag-and-Drop läuft mit den folgenden drei Rollen.12

Rolle Wer setzt sie um Aufgabe
IDataObject Ziehquelle Die getragene Nutzlast. Dasselbe Mehrformat-Datenobjekt wie die Zwischenablage
IDropSource Ziehquelle Entscheiden, ob das Ziehen weitergeht oder abgebrochen wird, und Cursor-Rückmeldung
IDropTarget Ablegeziel Annehmen/Ablehnen in DragEnter/DragOver/DragLeave/Drop erklären und das Ablegen empfangen

Die Ziehquelle ruft DoDragDrop auf, die Ziehschleife beginnt, und wenn die Maus ein Ablegeziel-Fenster betritt, wird dieses IDropTarget benachrichtigt; beim Ablegen wird das IDataObject übergeben. Offizielle Dokumentation sagt auch, dass „D&D genau dieselbe Funktionalität bereitstellt wie Kopieren-und-Einfügen der Zwischenablage. Wenn eine App Kopieren-und-Einfügen bereits umsetzt, ist die Ergänzung klein“.12 Mit anderen Worten: das Mehrformat-DataObject, das Sie in den Kapiteln 2 bis 5 gebaut haben, wird so, wie es ist, zur D&D-Nutzlast.

Ablauf von OLE-Drag-and-DropDie Ziehquelle legt ein IDataObject in die Nutzlast und ruft DoDragDrop auf, um die Ziehschleife zu starten; das IDropTarget des Ablegeziels erklärt Annehmen/Ablehnen in DragEnter und DragOver, und bei Drop wählt es ein Format aus dem IDataObject und extrahiert esDoDragDropMaus betrittTaste hochIDataObject + IDropSourceZiehschleifeDragEnter/Over: EffectIDropTarget.DropEin Format wählen und extrahieren

8.2. OleInitialize (STA) ist erforderlich

Ein Fenster, das Ablegeziel sein wird, registriert sich mit RegisterDragDrop, und hier gibt es einen klassischen Fallstrick. Wenn Sie COM mit CoInitialize/CoInitializeEx initialisiert haben, schlägt RegisterDragDrop immer mit E_OUTOFMEMORY fehl; Sie müssen mit OleInitialize initialisieren.13 OleInitialize initialisiert COM als STA, weil D&D eine Funktion ist, die in der STA-Welt von Fenstern und einer Nachrichtenpumpe wurzelt. Der aufrufende Thread muss außerdem eine Nachrichtenpumpe ausführen; überspringen Sie das, und andere Apps hängen während des Ziehens.13 Der Hintergrund hier ist genau die Threadmodell-Erörterung in „Grundlagenwissen zu COM STA/MTA“.

In einer WinForms/WPF-App übernimmt das Framework die OLE-Initialisierung und die Schnittstellenumsetzungen, sodass der Entwickler nur die Ereignisse schreiben muss.

// WinForms: accept dropped files
listView1.AllowDrop = true;
listView1.DragEnter += (s, e) =>
{
    // Also check that the source allows Copy (some sources only allow Move/Link)
    e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
            && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy
        ? DragDropEffects.Copy      // Accept: receive as a copy
        : DragDropEffects.None;     // Do not accept
};
listView1.DragDrop += (s, e) =>
{
    // Drag data is also untrusted input. Even if it advertises FileDrop, the payload
    // can be null or a different type, and GetData itself can fail
    object data;
    try { data = e.Data.GetData(DataFormats.FileDrop); }
    catch (COMException) { return; }
    if (data is not string[] paths) return;
    foreach (var path in paths)
    {
        // Validate the path before importing (Section 9.3)
    }
};

Die Form ist in WPF dieselbe: Sie empfangen mit AllowDrop="True" und den Ereignissen DragOver/Drop am Element und extrahieren das Pfadarray mit e.Data.GetData(DataFormats.FileDrop). Annehmen/Ablehnen (Effect) bei jedem DragEnter/DragOver zu erklären ist die IDropTarget-Konvention; überspringen Sie das, und Sie bekommen den Fehler, dass der Cursor auf „nicht erlaubt“ bleibt und sich nie ändert.

9. D&D-Fallstricke — Erhöhung, Verschieben und Pfadvalidierung

9.1. Sie können nicht auf eine als Administrator erhöhte App ablegen

Eine Datei vom Datei-Explorer auf eine mit „Als Administrator ausführen“ gestartete App zu legen und nichts passiert — das ist kein Umsetzungsfehler, es ist Betriebssystemverhalten. UIPI (User Interface Privilege Isolation) blockiert Nachrichten von einem Prozess niedrigerer Integrität an ein Fenster höherer Integrität standardmäßig, also erreichen Ablegebenachrichtigungen vom Datei-Explorer mit gewöhnlichen Rechten (mittlerer Integrität) eine erhöhte App nie.14

Wie UIPI Ablegen auf eine erhöhte App blockiertAblegebenachrichtigungen vom Datei-Explorer mittlerer Integrität an eine erhöhte App hoher Integrität werden von UIPI standardmäßig blockiert und kommen nie an. Halten Sie die UI bei gewöhnlichen Rechten und isolieren Sie privilegierte Arbeit, und das Ablegen kommt anAblegebenachrichtigungblockiertgeht durchprivilegierte Arbeit delegierenExplorer(mittel)UIPIErhöhte App: kein AblegenGewöhnliche UI: Ablegen kommt anIsolierter erhöhter Prozess

Ein Workaround, der bestimmte Nachrichten wie WM_DROPFILES einzeln mit ChangeWindowMessageFilterEx erlaubt, ist wohlbekannt,14 aber was das durchlässt, ist die ältere (WM_DROPFILES-)Ablegebenachrichtigung; es löst OLE-D&D als Ganzes nicht. Die praktische Leitlinie ist klar: hören Sie auf, die App so zu entwerfen, dass sie die ganze Zeit erhöht läuft. Isolieren Sie nur die Arbeit, die Erhöhung braucht, in einen eigenen Prozess, und die UI selbst kann bei gewöhnlichen Rechten bleiben und D&D empfangen (der Isolierungsentwurf ist ausführlich in „Wie man in einer Windows-App konkret nur die „Vorgänge, die Administratorrechte brauchen“ isoliert“ behandelt).

9.2. Was DragDropEffects bedeutet — Move ist ein Vertrag, dass „das Original weggeht“

Copy/Move/Link auf DragDropEffects sind keine Dekoration; sie sind ein Vertrag zwischen der Ziehquelle und dem Ablegeziel. Die Ziehquelle erklärt die Menge der Effekte, die sie erlaubt, in DoDragDrop, das Ablegeziel wählt den tatsächlichen Effekt, und wenn Move gelingt, löscht die Ziehquelle die Daten (die Datei) — das ist die Konvention. Wenn die Empfangsseite gedankenlos Move zurückgibt, bekommen Sie den Unfall „ich habe es abgelegt und die Originaldatei ist verschwunden“. Für den Importgebrauch einer Geschäftsanwendung ist dass die Empfangsseite Copy erklärt die sichere Vorgabe.

Der DragDropEffects-Vertrag — Move löscht das OriginalDie Ziehquelle erklärt die Menge erlaubter Effekte in DoDragDrop, und das Ablegeziel wählt den tatsächlichen Effekt. Wenn Move gelingt, löscht die Ziehquelle die Datei, also sollte die Empfangsseite für Import Copy erklärenCopyMoveQuelle: erlaubte EffekteZiel: Effect wählenOriginal bleibt(Import)Quelle löscht die Datei

9.3. Einen abgelegten Pfad validieren

Was in CF_HDROP/FileDrop reist, ist nur der Pfad (Abschnitt 3.2). Bevor Sie importieren, schicken Sie ihn durch dieselbe Validierung nicht vertrauenswürdiger Eingabe wie beim Einfügen.

  • Datei oder Ordner: Entscheiden Sie als Spezifikation, was geschieht, wenn ein ganzer Ordner abgelegt wird (rekursiv importieren oder ablehnen).
  • OneDrive-Platzhalter: Der Pfad kann existieren, während der Dateikörper nicht lokal ist — eine On-Demand-Datei. In dem Moment, in dem Sie sie öffnen, beginnt ein Download, und offline schlägt es fehl. Verhalten und Gegenmaßnahmen stehen in „OneDrive „Files On-Demand“ und Geschäftsanwendungen“.
  • Lange Pfade und ungewöhnliche Pfade: Pfade über MAX_PATH, Netz-(UNC-)Pfade und Pfade auf Wechselmedien sollten Sie nur akzeptieren, nachdem Sie bestätigt haben, dass die nachgelagerte Verarbeitung sie behandeln kann.
  • Anzahl und Gesamtgröße: Damit das Ablegen von Tausenden Dateien die UI nicht einfriert, machen Sie den Import asynchron und setzen Sie eine Grenze und eine Fortschrittsanzeige ein.

10. Zusammenfassung

  • Die Zwischenablage ist ein Mechanismus, der denselben Inhalt in mehreren Formaten gleichzeitig in einem einzelnen Bereich ablegt, der innerhalb desselben Desktops (Window Station) geteilt wird. Die Einfügeseite wählt das Format, also erzeugt dieselbe Kopie verschiedene Ergebnisse.
  • Text ist CF_UNICODETEXT, Dateien sind CF_HDROP, und formatierter Text ist das registrierte Format HTML Format (ein Byte-Offset-Header + UTF-8).
  • Die Einfügeseite schaut von reich nach einfach und behandelt die Nutzlast als äußere Eingabe. Die Kopierseite bietet mehrere Formate gleichzeitig an, und wenn sie verzögertes Rendering nutzt, setzt sie auch die Materialisierung zur Endezeit um (WM_RENDERALLFORMATS / OleFlushClipboard).
  • Überwachen ist AddClipboardFormatListener + WM_CLIPBOARDUPDATE. Bereiten Sie sich auf OpenClipboard-Wettläufe mit einer Wiederholung vor, und halten Sie Geheimnisse mit ExcludeClipboardContentFromMonitorProcessing und Freunden aus Verlauf und Synchronisierung heraus.
  • IT kann Zwischenablageverlauf, Cloud-Synchronisierung und RDP-Umleitung mit GPO / Intune steuern. Die Vorgabe ist für alle erlaubt, also entscheiden Sie in Umgebungen, die Geheimnisse behandeln, bewusst.
  • D&D ist COM: IDropSource/IDropTarget übergeben dasselbe IDataObject wie die Zwischenablage. RegisterDragDrop verlangt OleInitialize (STA).
  • Ablegen auf eine erhöhte App wird von UIPI blockiert. Move auf DragDropEffects ist ein Vertrag, dass „das Original weggeht“; validieren Sie einen abgelegten Pfad, bevor Sie ihn importieren.

Kopieren-und-Einfügen und D&D sind für den Benutzer Funktionen, die sich wie Luft anfühlen sollten. Genau deshalb tun „ich kann nicht einfügen“, „es fällt auseinander“ und „es ist verschwunden“ der Erfahrung so weh — und warum eine App, die mehrere Formate anbietet und Ablegen richtig behandelt, den Alltagsbetrieb von selbst glatter macht. Ich hoffe, das ist nützliches Material, wenn Sie entscheiden, was Sie zuerst reparieren.

Weiterführende Artikel

Zugehörige Beratungsfelder

KomuraSoft LLC übernimmt Entwurf und Umsetzung der Kopieren-und-Einfügen- und Drag-and-Drop-Unterstützung in Geschäftsanwendungen (Anbieten mehrerer Formate, Excel-Zusammenarbeit, Import abgelegter Dateien), Ursachenuntersuchung von Problemen wie „es fällt auseinander, wenn ich einfüge“ oder „die Kopie verschwindet“, Eingabeautomatisierung, die die Zwischenablage überwacht, sowie Umsetzungen, die vertrauliche Daten aus Verlauf und Synchronisierung heraushalten. Fälle, die die unteren Schichten von COM und OLE einbeziehen, sind willkommen, auch wenn Sie vom Isolieren des Symptoms beginnen.

Quellen

  1. Microsoft Learn, Clipboard Formats. Dazu, dass ein Fenster dieselbe Information in mehreren Zwischenablageformaten ablegen kann; zu registrierten Formaten über RegisterClipboardFormat (das Registrieren desselben Namens gibt denselben Wert zurück, sodass Apps ihn teilen können); zu synthetisierten Formaten; sowie zum Ausschließen von Inhalt aus Zwischenablageverlauf / Cloud-Synchronisierung mit ExcludeClipboardContentFromMonitorProcessing, CanIncludeInClipboardHistory und CanUploadToCloudClipboard.  2 3 4 5

  2. Microsoft Learn, Clipboard Operations. Dazu, dass nur ein Fenster zur Zeit die Zwischenablage öffnen kann; zum Ablegen von Formaten vom ausdrucksstärkeren zum weniger ausdrucksstarken zur Kopierzeit; zur Formatwahl zur Einfügezeit mit EnumClipboardFormats / GetPriorityClipboardFormat; zum verzögerten Rendering durch Übergeben von NULL an SetClipboardData und den Verantwortlichkeiten WM_RENDERFORMAT / WM_RENDERALLFORMATS; sowie zu den Kompromissen des verzögerten Renderings.  2 3 4 5 6 7 8

  3. Microsoft Learn, Standard Clipboard Formats. Zu den Definitionen der Standardformate CF_TEXT (ANSI), CF_UNICODETEXT, CF_HDROP, CF_DIB und CF_LOCALE sowie dazu, dass das System CF_TEXT und CF_UNICODETEXT implizit mit der CF_LOCALE zugeordneten Codepage umwandelt.  2 3

  4. Microsoft Learn, Shell Clipboard Formats. Dazu, dass CF_HDROP aus einer DROPFILES-Struktur plus einem doppelt-NUL-terminierten Array von Vollpfadzeichenfolgen besteht; zum Abrufen einzelner Pfade mit DragQueryFile; sowie dazu, dass CFSTR_-Shell-Formate Registrierung über RegisterClipboardFormat verlangen.  2

  5. Microsoft Learn, HTML Clipboard Format. Dazu, dass der registrierte Name „HTML Format“ ist; zur Headerstruktur mit Byte-Offsets wie Version, StartHTML, EndHTML, StartFragment und EndFragment; dazu, dass die Kodierung immer UTF-8 ist; sowie zur StartFragment/EndFragment-Kommentar-Konvention.  2 3

  6. Microsoft Learn, OleFlushClipboard function (ole2.h). Dazu, dass OleSetClipboard die Zwischenablage nur einen Zeiger auf das Datenobjekt halten lässt; dazu, dass OleFlushClipboard die Daten auf die Zwischenablage materialisiert, sodass Einfügen nach dem App-Ende noch funktioniert; sowie zum Leeren der Zwischenablage mit OleSetClipboard(NULL), wenn Sie sie beim Ende nicht behalten müssen.  2

  7. Microsoft Learn, OleGetClipboard function (ole2.h). Dazu, wie man ein IDataObject von der Zwischenablage erhält, und zur Warnung, dass Zwischenablagedaten nicht vertrauenswürdig sind und sorgfältig geparst werden sollten, bevor die App sie nutzt.  2

  8. Microsoft Learn, Using the clipboard. Zum Vergleich der drei Arten, die Zwischenablage zu überwachen (Viewer-Fenster, Sequenznummern und Format-Listener); dazu, dass neue Programme einen Listener über AddClipboardFormatListener nutzen sollen; dazu, dass die Viewer-Kette zerbrechlich ist, wenn die Kettenpflege unvollständig ist; sowie dazu, dass Sequenznummern nichts sind, das Sie pollen sollten.  2

  9. Microsoft Learn, Policy CSP - Experience. Zum Erlauben oder Verweigern von Zwischenablageverlauf mit der Richtlinie Experience/AllowClipboardHistory; zur Verfügbarkeit ab Windows 10 Version 1809; dazu, dass die Vorgabe erlaubt ist; sowie zur GPO-Zuordnung unter „System > Betriebssystemrichtlinien“ mit Änderungen, die sofort greifen.  2

  10. Microsoft Learn, Policy CSP - Privacy. Zum Erlauben oder Verweigern geräteübergreifender Zwischenablagesynchronisierung mit der Richtlinie Privacy/AllowCrossDeviceClipboard; dazu, dass Synchronisierung zwischen Geräten geschieht, die mit demselben Microsoft-Konto / Microsoft-Entra-Konto angemeldet sind; sowie dazu, dass die Vorgabe erlaubt ist.  2 3

  11. Microsoft Learn, Policy CSP - ADMX_TerminalServer. Dazu, dass TS_CLIENT_CLIPBOARD („Zwischenablageumleitung nicht zulassen“, Registrierungswert fDisableClip) das Teilen der Zwischenablage zwischen lokal und remote in einer Remotedesktopsitzung verbieten kann, und dazu, dass Umleitung standardmäßig erlaubt ist.  2

  12. Microsoft Learn, Drag and Drop (COM). Dazu, dass OLE-Drag-and-Drop mit den dreien IDropSource (Ziehquelle), IDropTarget (Ablegeziel) und DoDragDrop (der Schleife, die OLE bereitstellt) läuft; dazu, dieselbe Funktionalität wie Kopieren-und-Einfügen der Zwischenablage bereitzustellen, sodass eine App, die Kopieren-und-Einfügen bereits umsetzt, nur eine kleine Ergänzung braucht; sowie zu den Arten der Rückmeldung.  2 3

  13. Microsoft Learn, RegisterDragDrop function (ole2.h). Zum Registrieren eines Ablegeziel-Fensters mit einem IDropTarget; dazu, immer mit E_OUTOFMEMORY fehlzuschlagen, wenn COM mit CoInitialize/CoInitializeEx initialisiert wurde, sodass OleInitialize erforderlich ist; sowie dazu, dass die Ziehquellen-App hängt, wenn der aufrufende Thread keine Nachrichtenpumpe ausführt.  2 3

  14. Microsoft Learn, ChangeWindowMessageFilterEx function (winuser.h). Dazu, dass UIPI ein Sicherheitsmechanismus ist, der standardmäßig das Empfangen von Nachrichten von einem Sender niedrigerer Integrität blockiert, und zum Erlauben bestimmter Nachrichten pro Fenster mit einem Nachrichtenfilter (MSGFLT_ALLOW).  2 3

  15. Microsoft Learn, How to add data to the Clipboard (Windows Forms). Zum Ablegen von Daten in mehreren Formaten gleichzeitig mit DataObject und Clipboard.SetDataObject; zum Hinzufügen in mehreren Formaten, sodass andere Apps es erkennen können; sowie dazu, dass die Clipboard-Klasse nur von einem STA-Thread nutzbar ist, sodass [STAThread] erforderlich ist.  2

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Warum fällt die Formatierung einer aus Excel kopierten Tabelle auseinander, wenn ich sie in meine App einfüge?
Die Zwischenablage hält nicht „ein Datenstück“. Derselbe Inhalt wird in mehreren Formaten gleichzeitig abgelegt (das private Format der Quell-App, HTML Format, CSV, Unicode-Text und so weiter), und die Ziel-App wählt ein Format, das sie versteht, und extrahiert das. Wenn die Formatierung auseinanderfällt, ist die typische Ursache, dass das Ziel nur einfachen Text liest (CF_UNICODETEXT). Wenn Sie auch die Tabellenstruktur wollen, setzen Sie die Einfügeseite so um, dass sie HTML Format oder CSV bevorzugt. Umgekehrt: Wenn Sie wollen, dass andere Apps aus einer in Ihrer eigenen App gemachten Kopie korrekt einfügen, bieten Sie zur Kopierzeit sowohl ein reiches Format als auch ein einfaches Format an.
Warum kann ich nicht mehr einfügen, nachdem ich die App geschlossen habe, aus der ich kopiert habe?
Weil die Quelle verzögertes Rendering nutzt. Apps, die große Daten behandeln, legen die Nutzlast zur Kopierzeit nicht ab; sie registrieren auf der Zwischenablage nur ein Versprechen, sie „zu erzeugen, wenn gefragt“. Wenn die Quelle dann endet, ohne die Daten als Antwort auf WM_RENDERALLFORMATS beim Herunterfahren zu materialisieren, geht jedes Format verloren, das noch nicht gerendert ist. Eine App, die die OLE-Zwischenablage (IDataObject) nutzt, kann Einfügen nach dem Ende am Leben halten, indem sie beim Herunterfahren OleFlushClipboard aufruft, um die Daten zu materialisieren.
Wie kann meine eigene App die Zwischenablage auf Änderungen überwachen?
Die derzeit empfohlene Methode ist, Ihr Fenster mit AddClipboardFormatListener als Listener zu registrieren und die Nachricht WM_CLIPBOARDUPDATE zu behandeln, die jedes Mal ankommt, wenn sich der Inhalt ändert. Das Pollen des Inhalts auf einem Timer verschwendet Arbeit und kann Aktualisierungen verpassen, und die alte Viewer-Kette auf Basis von SetClipboardViewer wird nur für Abwärtskompatibilität gehalten, weil ein Fehler in einer App in der Kette die ganze Kette bricht. Beachten Sie außerdem, dass OpenClipboard bei einem Lesen fehlschlagen kann, weil ein anderer Prozess die Zwischenablage hält, also setzen Sie eine Wiederholung mit kurzem Warten um, wenn Sie das Lesen stabil haben wollen.
Gibt es einen Weg, Geheimnisse wie Kennwörter aus dem Zwischenablageverlauf (Win+V) herauszuhalten?
Es gibt zwei Hebel, einen auf der App-Seite und einen auf der Richtlinienseite. Auf der App-Seite: Wenn Sie beim Kopieren auch das registrierte Format ExcludeClipboardContentFromMonitorProcessing ablegen, ist dieser Inhalt weder im Verlauf noch in der geräteübergreifenden Synchronisierung enthalten. Sie können jedes auch unabhängig steuern mit CanIncludeInClipboardHistory (nur Verlauf) und CanUploadToCloudClipboard (nur Synchronisierung). Das ist der Mechanismus, den Kennwortmanager nutzen. Wenn Sie es für die ganze Organisation ausschalten wollen, können Sie Verlauf und Cloud-Synchronisierung selbst mit AllowClipboardHistory und AllowCrossDeviceClipboard über Gruppenrichtlinie oder Intune (Policy CSP) deaktivieren.
Warum kann ich eine Datei nicht auf eine App ziehen und ablegen, die als Administrator läuft?
Weil ein Sicherheitsmechanismus namens UIPI (User Interface Privilege Isolation) die Nachrichtenzustellung von einem Prozess niedrigerer Integrität an ein Fenster höherer Integrität blockiert. Der Datei-Explorer läuft mit gewöhnlichen Rechten (mittlere Integrität), also erreichen Drag-and-Drop-Benachrichtigungen das Fenster einer erhöhten App nie. Ein Workaround, der Nachrichten wie WM_DROPFILES einzeln mit ChangeWindowMessageFilterEx erlaubt, ist wohlbekannt, gilt aber nur für die ältere Ablegebenachrichtigung. Die echte Lösung ist, aufzuhören, die App so zu entwerfen, dass sie die ganze Zeit erhöht läuft, und nur die Arbeit, die Erhöhung braucht, in einen eigenen Prozess zu isolieren.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog