如何在 WinApi C# 中订阅剪贴板事件?
How to subscribe to clipboard events in WinApi C#?
我已经设置了一个查看器,它是当前进程并想接收消息WM_DRAWCLIPBOARD
。
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
var result = WinapiClipboard.SetClipboardViewer(Process.GetCurrentProcess().Handle);
它说 right here 我应该使用应用程序定义的函数来解析该消息。但它永远不会达到 function/method.
private static IntPtr WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam)
{
var hdc = Process.GetCurrentProcess().Handle;
var clipboard = new WinClipboard();
switch (message)
{
case WinapiClipboard.WM_DRAWCLIPBOARD:
var result = clipboard.GetUnicodeTextAsync().Result;
return IntPtr.Zero;
default:
break;
}
return WinapiClipboard.DefWindowProc(hWnd, message, wParam, lParam);
}
我应该如何收到这条消息?我订阅正确了吗?
更新:
我没有使用 WinForms/WPF 或任何 .NET 经典框架功能。我只有 .net 标准 2.0 或 .net 核心。
因为你正在做一个 winforms 项目覆盖现有的 Control.WndProc 而不是提供一个静态的。
protected override void WndProc(ref Message m)
{
if(WM_DRAWCLIPBOARD == msg.Msg)
{ ... }
else
base.WndProc(ref msg);
}
这一切都非常直接来自 winforms 应用程序
Note : you cant do this from a console app (with any ease)
声明此
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
在您的表单构造函数中
// this.handle is your forms handle
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
然后您将通过覆盖 WndProc
在表单中收到 WM_DRAWCLIPBOARD
消息
在你的表单中
protected override void WndProc(ref Message m)
{
switch ((Win32.Msgs)m.Msg)
{
case Win32.Msgs.WM_DRAWCLIPBOARD:
// Handle clipboard changed
break;
// ...
}
// we call this so we to pass the message along
base.WndProc(ref m);
}
执行此操作的另一种方法,也许是一种更现代的方法
声明此
public const int WM_CLIPBOARDUPDATE = 0x031D;
public static IntPtr HWND_MESSAGE = new IntPtr(-3);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
在您的表单构造函数中
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
在你的表单中
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// handle message
}
base.WndProc(ref m);
}
如果您使用的是 class 库,则必须创建一个隐藏的动作或事件并传回该动作或事件
private class HiddenForm : Form
{
public HiddenForm()
{
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// do stuff here like call event
}
base.WndProc(ref m);
}
}
Note : None of this is tested however should get you started
更新 1
SetClipboardViewer
expects a window handle, not a process handle. If
you don't have a window handle, create a message-only window for the
sole purpose of receiving clipboard messages - thanks to IInspectable
更新 2
This will only ever work on the kind of machine that also always has
the full framework available. - thanks to Hans Passant
我已经设置了一个查看器,它是当前进程并想接收消息WM_DRAWCLIPBOARD
。
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
var result = WinapiClipboard.SetClipboardViewer(Process.GetCurrentProcess().Handle);
它说 right here 我应该使用应用程序定义的函数来解析该消息。但它永远不会达到 function/method.
private static IntPtr WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam)
{
var hdc = Process.GetCurrentProcess().Handle;
var clipboard = new WinClipboard();
switch (message)
{
case WinapiClipboard.WM_DRAWCLIPBOARD:
var result = clipboard.GetUnicodeTextAsync().Result;
return IntPtr.Zero;
default:
break;
}
return WinapiClipboard.DefWindowProc(hWnd, message, wParam, lParam);
}
我应该如何收到这条消息?我订阅正确了吗?
更新:
我没有使用 WinForms/WPF 或任何 .NET 经典框架功能。我只有 .net 标准 2.0 或 .net 核心。
因为你正在做一个 winforms 项目覆盖现有的 Control.WndProc 而不是提供一个静态的。
protected override void WndProc(ref Message m)
{
if(WM_DRAWCLIPBOARD == msg.Msg)
{ ... }
else
base.WndProc(ref msg);
}
这一切都非常直接来自 winforms 应用程序
Note : you cant do this from a console app (with any ease)
声明此
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
在您的表单构造函数中
// this.handle is your forms handle
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
然后您将通过覆盖 WndProc
在表单中收到WM_DRAWCLIPBOARD
消息
在你的表单中
protected override void WndProc(ref Message m)
{
switch ((Win32.Msgs)m.Msg)
{
case Win32.Msgs.WM_DRAWCLIPBOARD:
// Handle clipboard changed
break;
// ...
}
// we call this so we to pass the message along
base.WndProc(ref m);
}
执行此操作的另一种方法,也许是一种更现代的方法
声明此
public const int WM_CLIPBOARDUPDATE = 0x031D;
public static IntPtr HWND_MESSAGE = new IntPtr(-3);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
在您的表单构造函数中
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
在你的表单中
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// handle message
}
base.WndProc(ref m);
}
如果您使用的是 class 库,则必须创建一个隐藏的动作或事件并传回该动作或事件
private class HiddenForm : Form
{
public HiddenForm()
{
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// do stuff here like call event
}
base.WndProc(ref m);
}
}
Note : None of this is tested however should get you started
更新 1
SetClipboardViewer
expects a window handle, not a process handle. If you don't have a window handle, create a message-only window for the sole purpose of receiving clipboard messages - thanks to IInspectable
更新 2
This will only ever work on the kind of machine that also always has the full framework available. - thanks to Hans Passant