Codefieber.de

IT-Blog

Abrufen von Daten aus der Zwischenablage mit C#

| Keine Kommentare

Clipboard-IconAbrufen von Daten aus der Zwischenablage – Eine kleine Anleitung, wie man Daten aus der Zwischenablage mit C# abrufen kann.

Manche Anwendungen wie GetRight und ClipMate scheinen irgendwie immer zu wissen, wann etwas in der Zwischenablage (Clipboard) passiert. Wir können uns ja mal anschauen wie das funktioniert.

Wir werden die Api-Funktion SetClipboardViewer benutzen, um genau das zu erreichen

SetClipboardViewer.

SetClipboardViewer
In der Win32-API wird die Funktion SetClipboardViewer benutzt, um eine Anwendung so zu
registrieren, dass sie auf Clipboard-Events reagiert.
Wird jetzt etwas in die Zwischenablage kopiert, teilt Windows dass dem registrierten Clipboard-
Viewer mit indem eine WM_DRAWCLIPBOARD message gesendet wird.
Diese können wir dann im WndProc Abfragen.

Beispiel-Anwendung
Wann können wir so etwas brauchen? Z.b. beim Kopieren von Internet-Links oder Internet-
Seiten könnten wir die Links herausfiltern…

 

Die SetClipboardViewer Funktion
Die SetClipboardViewer-Funktion fügt das entsprechende Fenster zur Clipboard-Schlange
hinzu. Clipboard-Viewer-Fenster empfangen eine WM_DRAWCLIPBOARD Nachricht, immer dann
wenn sich der Inhalt des Clipboards ändert.

Sie hat diese Form in C#:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

hWndNewViewer ist das Handle für ein Fenster welches zur Clipboard-Schlange hinzugefügt wird.

Ist SetClipboardViewer erfolgreich, gibt der Return-Wert das nächste Fenster in der
Clipboard-Schlange zurück. Das kann dazu benutzt werden, mehrere Clipboard-Nachrichten
zu bearbeiten und diese an das nächste Fenster in der Kette weiterzuleiten.

 

Den Clipboard Viewer einrichten
Um den Clipboard-Viewer erstellen zu können, müssen wir WndProc überschreiben, so dass
unser Anwendungsfenster auf Fenster-Nachrichten des Betriebssystems reagieren kann.

protected override void WndProc(ref Message m)
{
   ...
}

Als nächstes müssen wir SetClipboardViewer aufrufen, um die Anwendung als Clipboard-Viewer zu registrieren.
Das Fenster empfängt nun die DRAWCLIPBOARD Nachricht.
Diese wird nur für Anwendungen benötigt, die SetClipboardViewer aufrufen.

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

 

Auf WM_DRAWCLIPBOARD Nachricht reagieren
Nach dem Aufruf von SetWindowLong erhält WindowProc die WM_DRAWCLIPBOARD message wenn etwas ins Clipboard kopiert wurde.

protected override void WndProc(ref Message m)
{
   switch ((Win32.Msgs)m.Msg)
   {
      case Win32.Msgs.WM_DRAWCLIPBOARD:

An dieser Stelle werden die Clipboard-Daten verarbeit.

Im .NET Framework gibt es Clipboard, DataObject and DataFormats, um mit dem Clipboard arbeiten zu können.

Clipboard.GetDataObject gibt den aktuellen Inhalt des Clipboards als IDataObject zurück.

IDataObject iData = new DataObject();
iData = Clipboard.GetDataObject();

if (iData.GetDataPresent(DataFormats.Rtf))
{
  // ...

Wenn wir wissen, welches Format im Clipboard enthalten ist, können wir DataObject.GetData benutzen, um die Daten im benötigten Format abzuholen.

So bekommen wir z.B. die Daten als Richtext:

rtbClipboardText.Rtf = (string)iData.GetData(DataFormats.Rtf);

Nach dem Verarbeiten der Nachricht durch die Anwendung muss das nächste Fenster
benachrichtigt werden. Das wird erreicht durch den Aufruf von SendMessage.
Die selben Parameter die WndProc empfängt, müssen mittels SendMessage weitergeleitet
werden.

SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);

Wenn wir WndProc überschreiben, müssen alle unbehandelten Nachrichten and die
Basisklasse weitergeleitet werden, indem wir base.WndProc aufrufen.

protected override void WndProc(ref Message m)
{
    switch ((Win32.Msgs)m.Msg)
    {
        case Win32.Msgs.WM_DRAWCLIPBOARD:
            // ... process Clipboard

        default:
            // unhandled window message
            base.WndProc(ref m);
            break;

 

Die WM_CHANGECBCHAIN Nachricht
Die WM_CHANGECBCHAIN Nachricht, wird gesendet, wenn ein Fenster aus der Clipboard-
Schlange entfernt wird. Achtung: Diese Nachricht wird nur zum ersten Fenster in der
Clipboard-Schlange gesendet.

Dieses und die weiteren Fenster sind dafür verantwortlich die Nachricht weiterzuschicken..
Wenn wParam dem Fensterhandle des nächsten Fensters in der Schlange entspricht,
dann wird der nächste Clipboard-Viewer entfernt, der Pointer bezieht sich dann auf das
nächste Fenster und muss aktualisiert werden.

m.LParam entspricht denn dem Pointer auf den Clipboard Viewer nach dem der andere
entfernt wurde.

if (m.WParam == _ClipboardViewerNext)
{
   _ClipboardViewerNext = m.LParam;
}
else
{
   SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
}

Diese Nachricht könnten wir uns anzeigen lassen, in dem wir mehrere
Instanzen des Clipboard-Viewers starten und uns den Debug-Output anschauen.

 

Deregistrieren der Anwendung als Clipboard Viewer
Wenn die Anwendung beendet wird, müssen wir darauf achten, dass wir
ChangeClipboardChain aufrufen, um die Anwendung aus der Clipboard-Schlange zu
entfernen.

ChangeClipboardChain(this.Handle, _ClipboardViewerNext);

 

Und hier noch mal etwas zusammengefasster Code:

[DllImport("User32.dll")]
protected static extern int SetClipboardViewer(int hWndNewViewer);

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

IntPtr nextClipboardViewer;

public frmMain()
{            
    InitializeComponent();
    nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
}

protected override void WndProc(ref Message m)
{
    // defined in winuser.h
    const int WM_DRAWCLIPBOARD = 0x308;
    const int WM_CHANGECBCHAIN = 0x030D;

    switch (m.Msg)
    {
        case WM_DRAWCLIPBOARD:
            DisplayClipboardData();
            SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
            break;

        case WM_CHANGECBCHAIN:
            if (m.WParam == nextClipboardViewer)
                nextClipboardViewer = m.LParam;
            else
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
				break;

        default:
            base.WndProc(ref m);
            break;
    }
}

public static string DisplayClipboardData()
{
    string clipboardStr = null;

    try
    {
        IDataObject iData = new DataObject();
        iData = Clipboard.GetDataObject();

        clipboardStr = (string)iData.GetData(typeof(string));
        MessageBox.Show(clipboardStr);
	}
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}
avatar

Autor: Pascal

Codefieber.de wird von Pascal Betke geführt, administriert und gestaltet. Alle Inhalte sind persönlich von mir ausgewählt und erstellt, nach bestem Gewissen und Können, was die Möglichkeit von Fehlern nicht ausschließt.

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert.