Imports System.ComponentModel
Imports System.Runtime.InteropServices

Public Class ClassClipboardWatcher : Inherits NativeWindow : Implements IDisposable
    <DllImport("user32", EntryPoint:="AddClipboardFormatListener")>
    Private Shared Function AddClipboardFormatListener(ByVal hWnd As IntPtr) As Boolean
    End Function

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

    Public Event Changed As EventHandler(Of String)

    Private ReadOnly _Handle As IntPtr
    Private _IsDisposed As Boolean = False

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

    Const WM_CLIPBOARDUPDATE As Integer = &H31D

    Private Sub New()
        MyBase.CreateHandle(New CreateParams)
        _Handle = AddClipboardFormatListener(Handle)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM_CLIPBOARDUPDATE
                Dim oWindow = ClassWindowAPI.GetWindowInfo()

                If IsNothing(oWindow.ProcessName) Then
                    Exit Sub
                End If

                If oWindow.ProcessName.StartsWith("DD_Clipboard_Watcher") Then
                    Exit Sub
                End If

                Dim oText = Clipboard.GetText

                RaiseEvent Changed(Me, oText)
        End Select
        MyBase.WndProc(m)
    End Sub

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not _IsDisposed Then
            If disposing Then
                ' TODO: Verwaltete Ressourcen freigeben, wenn sie explizit 
                ' aufgerufen werden
            End If
            MyBase.DestroyHandle()
            RemoveClipboardFormatListener(_Handle)
        End If
        _IsDisposed = 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 Class

