-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathClipboardMonitor.cs
112 lines (95 loc) · 3.61 KB
/
ClipboardMonitor.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace it
{
internal sealed class ClipboardChangedEventArgs : EventArgs
{
public ClipboardChangedEventArgs(IDataObject dataObject)
{
DataObject = dataObject;
}
public IDataObject DataObject { get; }
}
[DefaultEvent("ClipboardChanged")]
internal sealed class ClipboardMonitor : Control
{
private IntPtr NextViewerPtr;
public ClipboardMonitor()
{
CreateHandle();
try
{
NextViewerPtr = NativeMethods.SetClipboardViewer(Handle);
}
catch (EntryPointNotFoundException) { }
}
~ClipboardMonitor()
{
Dispose(disposing: false);
}
public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;
protected override void Dispose(bool disposing)
{
if (NextViewerPtr != IntPtr.Zero)
{
_ = NativeMethods.ChangeClipboardChain(Handle, NextViewerPtr);
NextViewerPtr = IntPtr.Zero;
}
base.Dispose(disposing);
}
protected override void WndProc(ref Message m)
{
{
switch (m.Msg)
{
case NativeMethods.WM_DRAWCLIPBOARD:
_ = NativeMethods.SendMessage(NextViewerPtr, m.Msg, m.WParam, m.LParam);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
OnClipboardChanged();
break;
case NativeMethods.WM_CHANGECBCHAIN:
if (m.WParam == NextViewerPtr)
{
NextViewerPtr = m.LParam;
}
else
{
_ = NativeMethods.SendMessage(NextViewerPtr, m.Msg, m.WParam, m.LParam);
}
break;
default:
base.WndProc(ref m);
break;
}
}
}
private void OnClipboardChanged()
{
try
{
IDataObject dataObject = Clipboard.GetDataObject();
if (dataObject != null)
{
ClipboardChanged?.Invoke(this, new ClipboardChangedEventArgs(dataObject));
}
}
catch (ExternalException) { }
}
private static class NativeMethods
{
internal const int WM_CHANGECBCHAIN = 0x030D;
internal const int WM_DRAWCLIPBOARD = 0x0308;
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
}
}
}