【问题标题】:How do non-window program monitor system clipboard?非窗口程序如何监控系统剪贴板?
【发布时间】:2013-07-01 21:58:51
【问题描述】:

我想编写一个程序来使用 C# 监视 Windows 剪贴板。我发现了一些关于这个主题的帖子。根据线程How to monitor clipboard content changes in C#?Finding the handle to a WPF window,我用WPF写了一个demo。在我找到的所有示例代码中,它们都是 WinForm 或 WPF 应用程序,并且它们与需要窗口句柄作为参数互操作的 win32 api。 如api函数SetClipboardViewer(HWND hWndNewViewer)

但在我的场景中,我需要我的程序运行后台作为服务来监控和收集剪贴板内容。如何在没有窗口 UI 的情况下监视剪贴板?

你能给我一些建议吗?提前致谢。


根据user1795804的建议,我写了如下测试代码

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    public static class User32
    {


  [DllImport("User32.dll")]
    public static extern IntPtr OpenClipboard(IntPtr hWndNewOwner);

    [DllImport("User32.dll")]
    public static extern IntPtr GetClipboardData(uint uFormat);
}
class Program
{
    static void Main(string[] args)
    {
        int result = (int)User32.OpenClipboard(new IntPtr(0));
        if (result == 0)
        {
            Console.WriteLine("error");
        }
        else
        {
            Console.WriteLine("success");
        }

        int returnHandle = (int)User32.GetClipboardData(1); //CF_TEXT 1
        if (returnHandle == 0)
        {
            Console.WriteLine("can't get text data");
        }

        Console.ReadKey();
    }
    }
}

结果是我可以打开剪贴板并且似乎获得了日期对象的句柄。 但现在我有两个问题。

1. 虽然我在剪贴板中有一个数据对象的句柄,但如何使用句柄获取这些数据?找不到相关功能。

2. 我需要传递一个 proc 函数作为回调,以便它可以在系统事件引发时接收消息。但是我在非窗口应用程序中找不到对应的。

【问题讨论】:

    标签: c# .net windows-services interop clipboard


    【解决方案1】:

    根据微软的说法,“监视剪贴板更改的方法有三种。最古老的方法是创建剪贴板查看器窗口。Windows 2000 增加了查询剪贴板序列号的功能,Windows Vista 增加了对剪贴板格式的支持侦听器。支持剪贴板查看器窗口是为了向后兼容早期版本的 Windows。新程序应使用剪贴板格式侦听器或剪贴板序列号。"

    这个 GetClipboardSequenceNumber 不接受任何参数,根据微软的说法, “系统为每个窗口站的剪贴板保留一个序列号。每当剪贴板的内容发生变化或剪贴板被清空时,该编号就会递增。您可以跟踪该值以确定剪贴板内容是否已更改并优化创建DataObjects。如果剪贴板呈现延迟,则在呈现更改之前,序列号不会递增。"

    这将满足您“我想编写一个程序来使用 C# 监视 Windows 剪贴板”的要求。

    【讨论】:

    • 看起来,虽然我没有尝试过,但如果上述指示发生变化,您可以使用 HANDLE WINAPI GetClipboardData() 来获取文本。希望这会有所帮助!
    • 在使用函数GetClipboardData之前,使用函数GetClipboardData(HWND hWndNewOwner),“剪贴板必须已经打开过”,它需要句柄作为参数。看来我们必须要另辟蹊径了。
    • 请原谅,但我没有看到它说必须使用 GetClipboardData() 打开它。如果它可以使用 OpenClipboard 打开,也许你会使用它。请注意,它表示如果将 null 传递给它,则剪贴板与当前任务相关联。 BOOL WINAPI OpenClipboard( In_opt HWND hWndNewOwner );参数:要与打开的剪贴板关联的窗口句柄。如果此参数为NULL,则打开的剪贴板与当前任务相关联。
    • 我不确定“当前任务”是什么意思,但它可能值得探索。
    • 对不起,我打错了。我的意思是“使用 OpenClipboard(HWND hWndNewOwner)。我会尝试并希望它有效。
    猜你喜欢
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 2018-11-11
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    相关资源
    最近更新 更多