【发布时间】:2020-02-20 22:22:17
【问题描述】:
我想监控剪贴板的变化(仅限文本)。我试图找到一些解决方案,我在 StackOverflow 上发现了以下问题:
但我的问题/要求是我不想向 Windows.Forms 或 WPF 添加依赖项(我的应用程序是控制台应用程序)。我尝试查看 user32.dll 中的可用方法。我编写了一个创建窗口和窗口样式的代码。将 WndPrc 方法覆盖为自定义方法,然后将侦听器添加到剪贴板更改。 WndProcFunction 被以下消息调用了 4 次:
- WM_GETMINMAXINFO
- WM_NCCREATE
- WM_NCCALCSIZE
- WM_CREATE
但是,当我更改剪贴板的内容时,会发送 WM_CLIPBOARDUPDATE 类型的消息,也不会发送任何适合 WndProcFunction 的消息。我尝试使用“旧 API”(SetDashboardViewer),但它没有任何改变。代码如下:
using PInvoke;
...
internal static class User32Ext
{
[DllImport("user32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
[DllImport("kernel32.dll")]
internal static extern uint GetLastError();
}
class Program
{
private static IntPtr _nextInChain = IntPtr.Zero;
internal static unsafe IntPtr WndProcFunction(IntPtr hwnd, User32.WindowMessage windowMessage, void* wParam1, void* lParam1)
{
if (windowMessage == User32.WindowMessage.WM_CREATE)
{
var listener = User32Ext.AddClipboardFormatListener(hwnd);
var result = User32.OpenClipboard(window);
//_nextInChain = User32Ext.SetClipboardViewer(hwnd);
}
if (windowMessage == User32.WindowMessage.WM_CLIPBOARDUPDATE)
{
var pointerToText = User32.GetClipboardData_IntPtr(1);
var text = Marshal.PtrToStringAnsi(pointerToText);
Console.WriteLine(text);
}
if (windowMessage == User32.WindowMessage.WM_DRAWCLIPBOARD)
{
if (_nextInChain != IntPtr.Zero)
{
User32.SendMessage(_nextInChain, windowMessage, wParam1, lParam1);
}
}
if (windowMessage == User32.WindowMessage.WM_CHANGECBCHAIN)
{
_nextInChain = hwnd;
//send message...
}
if (windowMessage == User32.WM_DESTROY)
{
//chain msg
User32Ext.RemoveClipboardFormatListener(hwnd);
}
return hwnd; //success
}
static void Main(string[] args)
{
unsafe
{
var hInstance = Marshal.GetHINSTANCE(typeof(Program).Module);
string name = "Test";
User32.WNDCLASSEX wndClassEx = new User32.WNDCLASSEX
{
cbSize = Marshal.SizeOf(typeof(User32.WNDCLASSEX)),
style = User32.ClassStyles.CS_GLOBALCLASS,
cbClsExtra = 0,
cbWndExtra = 0,
hbrBackground = IntPtr.Zero,
hCursor = IntPtr.Zero,
hIcon = IntPtr.Zero,
hIconSm = IntPtr.Zero,
lpszMenuName = null,
hInstance = hInstance,
lpfnWndProc = new User32.WndProc(WndProcFunction)
};
var stringPtr = Marshal.StringToHGlobalAuto(name);
wndClassEx.lpszClassName_IntPtr = stringPtr;
var register = User32.RegisterClassEx(ref wndClassEx);
var window = User32.CreateWindowEx(
User32.WindowStylesEx.WS_EX_TRANSPARENT,
name,
"Test Window",
0,
0, 0, 0, 0,
IntPtr.Zero,
IntPtr.Zero,
wndClassEx.hInstance,
IntPtr.Zero
);
User32.SetClipboardData(13, stringPtr);
...
}
}
}
代码中是否还缺少一些额外的侦听器?每次从 user32.dll 调用方法后,我都会查看错误代码。但都成功了,没有任何失败。
【问题讨论】:
-
检查过
AddClipboardFormatListener是否被调用?如果是,请检查return value 是否执行成功?如果没有,请通过检查返回值和窗口句柄确保您的窗口创建成功。 -
@RitaHan-MSFT “每次从 user32.dll 调用方法后,我都会查看错误代码。但一切都成功了,没有任何失败。”。此外,所有侦听器函数都返回
true。一切似乎都是正确的。