I am working on a console application that is supposed to catch the event when the clipboard content changes. There is an API in WinRT for this, Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged. I have already tested this on a WinForms and WPF application, and it works perfectly. However I am experiencing problems when doing this in a console application. The code is pretty basic. When doing it on a WinForms application, I simply write this line of code:
public MyApp()
{
InitializeComponent();
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
}
public async void OnClipboardChanged(Object sender, Object e)
{
MyCodeHere
}
However when trying to do the same in my console application:
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");
}
}
Yet the console just exits after starting it. If I put "Console.ReadKey" then it still errors but does not exit. Neither way invokes the event I have written in Main. I want the console to be running and not end, even if there is a clipboard change. So it should constantly run in the background, and everytime the clipboard changes then it should just WriteLine a "Hello" to the console. I have gone through all the other answers but none of them works for me, because they want to manipulate the clipboard whereas I am invoking an event on the content change of the clipboard. Thanks for all the help!
Another question, will there be any perfomance difference if I use C++/winRT instead?
In a console context, you must ensure windows messages are processed as clipboard depends on it, so for example, you can use Winforms' DoEvents method (if you don't have a real window and nothing pumps messages):
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>
If you don't have .NET 5, or don't want to reference Winforms, then you can declare your own message pump using P/Invoke, like this:
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);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.