Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0086: Clipboard überwachen

 von 

Beschreibung

Verwendung der Win32-API-Funktion "SetClipboardViewer", Subclassing eines "NativeWindows" mit WndProc(). "NativeWindow" ist die primitivste Klasse, die noch Windowmessages empfangen kann. Eine solche ist hier erforderlich, um der SetClipboardViewer()-Funktion ein Ziel angeben zu können, an welches Benachrichtigungen über Änderung des Zwischenablage gesandt werden können.

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 1.0, .NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2002, Visual Basic 2003, Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [12,57 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2005
' Option Strict:    An
'
' Referenzen: 
'  - System
'  - System.Data
'  - System.Drawing
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - Microsoft.VisualBasic.ControlChars
'  - System
'  - System.Collections
'  - System.Collections.Generic
'  - System.Data
'  - System.Drawing
'  - System.Diagnostics
'  - System.Windows.Forms
'

' ##############################################################################
' ############################ ClipboardWatcher.vb #############################
' ##############################################################################
Imports Microsoft.VisualBasic.ControlChars
Imports System.Runtime.InteropServices

Public Class ClipboardWatcher : Inherits NativeWindow : Implements IDisposable

    <DllImport("user32", EntryPoint:="SetClipboardViewer")> _
    Private Shared Function SetClipboardViewer(ByVal hWnd As IntPtr) As IntPtr
    End Function

    Public Event Changed As EventHandler

    Private _hview As IntPtr

    'nur eine globale Instanz zulassen
    Public Shared Singleton As New ClipboardWatcher

    Private Sub New()
        MyBase.CreateHandle(New CreateParams)
        _hview = SetClipboardViewer(MyBase.Handle)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Const WM_DRAWCLIPBOARD As Integer = &H308
        Select Case m.Msg
            Case WM_DRAWCLIPBOARD
                RaiseEvent Changed(Me, EventArgs.Empty)
        End Select
        MyBase.WndProc(m)
    End Sub

#Region " IDisposable Support "
    ' Für diese Klasse ist korrekte Ressourcenbereinigung besonders wichtig, da 
    ' mit systemübergreifenden Ressourcen gearbeitet wird

    ' So ermitteln Sie überflüssige Aufrufe
    Private disposedValue As Boolean = False

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: Verwaltete Ressourcen freigeben, wenn sie explizit 
                ' aufgerufen werden
            End If
            MyBase.DestroyHandle()
            Dim H As IntPtr = SetClipboardViewer(_hview)
        End If
        Me.disposedValue = True
    End Sub

    ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster 
    ' richtig zu implementieren.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Sie sollten diesen Code nicht ändern, sondern stattdessen ihren
        ' Bereinigungscode oben in 
        ' Dispose(ByVal disposing As Boolean) einfügen.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
        Dispose(False)
    End Sub

#End Region

End Class

' ##############################################################################
' ########################### frmClipboardWatch.vb #############################
' ##############################################################################
Public Class frmClipboardWatch
    Private WithEvents _Watcher As ClipboardWatcher = ClipboardWatcher.Singleton

    Private Sub frmClipboardWatch_Disposed(ByVal sender As Object, _
        ByVal e As EventArgs) Handles Me.Disposed

        _Watcher.Dispose()
    End Sub

    Private Sub _Watcher_Changed(ByVal sender As Object, _
        ByVal e As EventArgs) Handles _Watcher.Changed

        Dim Data As IDataObject = Clipboard.GetDataObject
        With Me.TextBox1
            .AppendText(String.Concat("Available Formats:", CrLf))
            .AppendText(String.Join(CrLf, Data.GetFormats))
            .AppendText(String.Concat(CrLf, CrLf, "Text = '", _
                Clipboard.GetText, "'", CrLf, CrLf))
        End With
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 3 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von Tobiii am 23.08.2009 um 16:49

Aber bei mir blebt das Problem...
Der Text wird doppelt angezeigt.
Warum???????????????????????????????

Kommentar von Alex am 04.08.2009 um 11:21

Hallo,
ich habe die Version von pamkkkkk genutzt.
Wenn ich nun einen Text kopiere, bekomme ich den kopierten Text einmal zurück. Kopieren ich nun einen z.B einen Text aus einer Homepage, bekomme ich den Text doppelt angezeigt. Warum?

MfG Alex

Kommentar von pamkkkkk am 10.06.2009 um 18:58

Diese Implementierung ist unvollständig !!

Da Windows die Nachricht, das sich das Clpboard geändert hat, NUR an das ERSTE FENSTER (Aplikation) weiterleitet, und diese Fenster dafür zuständig ist DIESE NACHRICHT AN ANDERE FENSTER (APLIKATIONEN) WEITERZULEITEN. Bekommen alle anderen Applikation die nach dieser ein Interesse an der Nachricht haben keine Informationen mehr.

DIE NACHRICHTENKETTE WIRD ALSO UNTERBROCHEN !!!!!!!!

Siehe auch :

Richtige Implementierung in VB6:
VB 5/6-Tipp 0348: Zwischenablage überwachen, Clipboard-Viewer
http://www.activevb.de/tipps/vb6tipps/tipp0348.html

PDF erklärung von Windows Clipboard Ereigniss:
http://www.mycsharp.de/wbb2/attachment.php?attachmentid=3624&sid=df710d2d943da809b2603fec3edd74af

Sehr guter Artikel der DotNetPro dazu:
http://www.dotnetpro.de/articles/downloadpdf.ashx?id=2334

Hier die Lösung.

Code:
-----------------------------------------------

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion: Visual Studio 2005
' Option Strict: On
'
' Referenzen:
' - System
' - System.Data
' - System.Drawing
' - System.Windows.Forms
' - System.Xml
'
' Imports:
' - Microsoft.VisualBasic
' - System
' - System.Collections
' - System.Collections.Generic
' - System.Data
' - System.Drawing
' - System.Diagnostics
' - System.Windows.Forms


' ##############################################################################
' ############################ ClipboardWatcher.vb #############################
' ##############################################################################

Imports System.Runtime.InteropServices

Public Class ClipboardWatcher1 : Inherits NativeWindow : Implements IDisposable

#Region "Klassen Variablen"

' Das Öffentliche Ereignis zum auslösen der Clipboard-Änderung
Public Event Changed As EventHandler

'Über das Singleton Muster, nur eine globale Instanz zulassen
Public Shared Singleton As New ClipboardWatcher1

'Fenster-Handle für das nächste Fenster in der ClipboardViewer Kette das benachrichtigt werden soll
Private mNextClipBoardViewerHWnd As IntPtr = IntPtr.Zero ' zuerstmal nur ein Nullzeiger...

#End Region '"Klassen Variablen"

#Region "Konstuktor(en)"

Private Sub New() ' Privat damit man ein Sigleton erstellen muss (nur eine einzige Instanz erstellen kann)!
MyBase.CreateHandle(New CreateParams) ' ein Handle für NativWindow erstellen

' dieses NativWindow als ClipboardViewer bei Windows registrieren und
' das Handle des nächsten Fensters in der Nachrichtenkette "retten"
mNextClipBoardViewerHWnd = SetClipboardViewer(MyBase.Handle)
End Sub

#End Region '"Konstuktor(en)"

#Region "API-Win32"

'Konstanten für API Calls
Private Const WM_DRAWCLIPBOARD As Integer = &H308
Private Const WM_CHANGECBCHAIN As Integer = &H30D

'Win32-API Funktionen deklarieren
<DllImport("user32", EntryPoint:="SetClipboardViewer")> _
Private Shared Function SetClipboardViewer(ByVal hWnd As IntPtr) As IntPtr
' Ein Fenster bei Windows in die ClipboardViewer Ketten einhängen (zum Nachrichten empfangen)
' (Register Window)
End Function

<DllImport("user32", EntryPoint:="ChangeClipboardChain")> _
Private Shared Function ChangeClipboardChain(ByVal HWnd As IntPtr, ByVal HWndNext As IntPtr) As Boolean
' Windows über ClipboardViewer Ketten Änderung benachrichten (sich selbst aus der Kette schmeissen)
' (Deregister Window)
End Function

<DllImport("user32", EntryPoint:="SendMessage")> _
Private Shared Function SendMessage(ByVal HWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Long

' Nachrichten an andere Fenster verschicken
End Function

#End Region '"API-Win32"

#Region "WndProc"

Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case WM_DRAWCLIPBOARD 'Nachricht von Windows, daß sich das Clipboard geändert hat

'##########################################################################
RaiseEvent Changed(Me, EventArgs.Empty)
'##########################################################################

' Nachricht über Clipboard-Änderung an das nächste Fenster senden
SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)

Case Is = WM_CHANGECBCHAIN 'Nachricht von Windows, daß sich die ClipboardViewer Kette geändert hat

' Hat sich unser nächster Partner in der Ketten verabschiedet ?
If m.WParam = CType(mNextClipBoardViewerHWnd, IntPtr) Then
' Fenster hat sich geändert.
' Ein neues Fenster ist das nächse hinter uns ,
' also müssen wir uns das Handle des neuen Partners merken.
mNextClipBoardViewerHWnd = m.LParam
Else
' Nachricht über ClipboardViewer-Ketten-Änderung an das nächste Fenster senden
SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)
End If
End Select
MyBase.WndProc(m)
End Sub

#End Region '"WndProc"

#Region " IDisposable Support "
' Für diese Klasse ist korrekte Ressourcenbereinigung besonders wichtig, da
' mit systemübergreifenden Ressourcen gearbeitet wird

' So ermitteln Sie überflüssige Aufrufe
Private disposedValue As Boolean = False

Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: Verwaltete Ressourcen freigeben, wenn sie explizit
' aufgerufen werden
End If

' Wir entfernen uns aus der Nachrichtenkette und
' setzen das nächste Fenster in der Kette als neues Kettenglied
ChangeClipboardChain(Me.Handle, mNextClipBoardViewerHWnd)

MyBase.DestroyHandle()

End If
Me.disposedValue = True
End Sub

' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster
' richtig zu implementieren.
Public Sub Dispose() Implements IDisposable.Dispose
' Sie sollten diesen Code nicht ändern, sondern stattdessen ihren
' Bereinigungscode oben in
' Dispose(ByVal disposing As Boolean) einfügen.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
Dispose(False)
End Sub

#End Region '" IDisposable Support "

End Class

'' ##############################################################################
'' Beispiel für Form1.vb
'' ##############################################################################
'Partial Class Form1
' Private WithEvents _Watcher As ClipboardWatcher1 = ClipboardWatcher1.Singleton

' Private Sub frmClipboardWatch_Disposed(ByVal sender As Object, _
' ByVal e As EventArgs) Handles Me.Disposed

' _Watcher.Dispose()
' End Sub

' Private Sub _Watcher_Changed(ByVal sender As Object, _
' ByVal e As EventArgs) Handles _Watcher.Changed

' Dim Data As IDataObject = Clipboard.GetDataObject
' With Me.TextBox1
' .AppendText(String.Concat("Available Formats:", vbCrLf))
' .AppendText(String.Join(vbCrLf, Data.GetFormats))
' .AppendText(String.Concat(vbCrLf, vbCrLf, "Text = '", _
' Clipboard.GetText, "'", vbCrLf, vbCrLf))
' End With
' End Sub
'End Class