簡體   English   中英

C# 監視器剪貼板更改控制台

[英]C# Monitor Clipboard changes console

我正在開發一個控制台應用程序,該應用程序應該在剪貼板內容更改時捕獲事件。 為此,WinRT 中有一個 API,Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged。 我已經在 WinForms 和 WPF 應用程序上對此進行了測試,並且效果很好。 但是,在控制台應用程序中執行此操作時遇到問題。 代碼非常基本。 在 WinForms 應用程序上執行此操作時,我只需編寫這行代碼:

public MyApp()
{
    InitializeComponent();
    Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;

}


public async void OnClipboardChanged(Object sender, Object e)
{
   MyCodeHere
}

但是,當嘗試在我的控制台應用程序中執行相同操作時:

class Program
{

    [STAThread]
    static void Main(string[] args)
    {
        Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
    }

    public static void OnClipboardChanged(Object sender, Object e)
    {
        Console.WriteLine("Hello");
    }
}

然而控制台只是在啟動后退出。 如果我輸入“Console.ReadKey”,那么它仍然會出錯但不會退出。 這兩種方式都不會調用我在 Main 中編寫的事件。 我希望控制台正在運行而不是結束,即使剪貼板發生了變化。 所以它應該不斷地在后台運行,並且每次剪貼板發生變化時,它應該只是向控制台寫入一個“Hello”。 我已經完成了所有其他答案,但沒有一個對我有用,因為他們想要操作剪貼板,而我正在調用剪貼板內容更改的事件。 感謝所有的幫助!

另一個問題,如果我改用 C++/winRT 會有任何性能差異嗎?

在控制台上下文中,您必須確保 windows 消息被處理為剪貼板依賴於它,因此,例如,您可以使用 Winforms 的DoEvents方法(如果您沒有真正的 window 並且沒有泵消息):

class Program
{
    static void Main()
    {
        Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
        Console.WriteLine("Press any key to quit");
        do
        {
            System.Windows.Forms.Application.DoEvents();
            if (Console.KeyAvailable)
                break;

            Thread.Sleep(100); // for example
        }
        while (true);
    }
}

To enable Winforms support in a .NET 5 Console project, here is the simplest way of doing it (you don't even need to add the Windows.SDK nuget package), just modify the.csproj to something like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <DisableWinExeOutputInference>true</DisableWinExeOutputInference>
  </PropertyGroup>

</Project>

如果您沒有 .NET 5,或者不想引用 Winforms,那么您可以使用 P/Invoke 聲明自己的消息泵,如下所示:

class Program
{
    [STAThread]
    static void Main()
    {
        Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
        Console.WriteLine("Press any key to quit");
        do
        {
            while (GetMessage(out var msg, IntPtr.Zero, 0, 0) != 0)
            {
                TranslateMessage(ref msg);
                DispatchMessage(ref msg);
            }
            if (Console.KeyAvailable)
                break;

            Thread.Sleep(100);
            Console.Write(".");
        }
        while (true);
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MSG
    {
        public IntPtr hwnd;
        public int message;
        public IntPtr wParam;
        public IntPtr lParam;
        public int time;
        public POINT pt;
        public int lPrivate;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public int x;
        public int y;
    }

    [DllImport("user32")]
    private static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax);

    [DllImport("user32")]
    private static extern bool TranslateMessage(ref MSG lpMsg);

    [DllImport("user32")]
    private static extern IntPtr DispatchMessage(ref MSG lpmsg);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM