How to Monitor Clipboard Content Changes in C#

How do I monitor clipboard content changes in C#?

You could use SetClipboardViewer provided by Win32 API (through P/Invoke).

Here is a page which contains code to set one up in C#: http://www.codeguru.com/csharp/.net/net_general/tipstricks/article.php/c7315/

How do I monitor clipboard changes in C#?

I think you'll have to use some p/invoke:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

See this article on how to set up a clipboard monitor in c#

Basically you register your app as a clipboard viewer using

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

and then you will recieve the WM_DRAWCLIPBOARD message, which you can handle by overriding WndProc:

protected override void WndProc(ref Message m)
{
switch ((Win32.Msgs)m.Msg)
{
case Win32.Msgs.WM_DRAWCLIPBOARD:
// Handle clipboard changed
break;
// ...
}
}

(There's more to be done; passing things along the clipboard chain and unregistering your view, but you can get that from the article)

C# Monitor Clipboard changes console

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);
}

Clipboard Monitor

The problem is that you're handling the wrong window message. Quoting the documentation for AddClipboardFormatListener:

When a window has been added to the clipboard format listener list, it is posted a WM_CLIPBOARDUPDATE message whenever the contents of the clipboard have changed.

With that knowledge, change the code to:

const int WM_CLIPBOARDUPDATE = 0x031D;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_CLIPBOARDUPDATE:
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
string data = (string)iData.GetData(DataFormats.Text);
}
break;

default:
base.WndProc(ref m);
break;
}
}

how to monitor clipboard changes in C# to Capture Only Hyperlinks

Here's the URL checker linked by Ashutosh Pandey plugged into my existing implementation of the ClipBoard chain API:

public partial class Form1 : Form
{

private ClipBoardMonitor cbm = null;

public Form1()
{
InitializeComponent();
cbm = new ClipBoardMonitor();
cbm.NewUrl += cbm_NewUrl;
}

private void cbm_NewUrl(string txt)
{
this.label1.Text = txt;
}

}

public class ClipBoardMonitor : NativeWindow
{

private const int WM_DESTROY = 0x2;
private const int WM_DRAWCLIPBOARD = 0x308;
private const int WM_CHANGECBCHAIN = 0x30d;

[DllImport("user32.dll")]
private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll")]
private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

public event NewUrlHandler NewUrl;
public delegate void NewUrlHandler(string txt);

private IntPtr NextClipBoardViewerHandle;

public ClipBoardMonitor()
{
this.CreateHandle(new CreateParams());
this.NextClipBoardViewerHandle = SetClipboardViewer(this.Handle);
}

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
if (Clipboard.ContainsText())
{
string txt = Clipboard.GetText();
if (this.NewUrl != null && this.IsValidUrl(txt))
{
this.NewUrl(txt);
}
}
SendMessage(this.NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);

break;

case WM_CHANGECBCHAIN:
if (m.WParam.Equals(this.NextClipBoardViewerHandle))
{
this.NextClipBoardViewerHandle = m.LParam;
}
else if (!this.NextClipBoardViewerHandle.Equals(IntPtr.Zero))
{
SendMessage(this.NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);
}
break;

case WM_DESTROY:
ChangeClipboardChain(this.Handle, this.NextClipBoardViewerHandle);
break;

}

base.WndProc(ref m);
}

private bool IsValidUrl(string txt)
{
Uri uriResult;
return Uri.TryCreate(txt, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
}

}

Monitor changes in Clipboard via WinApi32

A message loop is required for receiving messages. If you don't want a window you can create a message-only window which enables you to send and receive messages.

It is not visible, has no z-order, cannot be enumerated, and does not
receive broadcast messages. The window simply dispatches messages.

In C#, at the end of your main function, it will like this:

    MSG msg;  
while (User32.GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
{
User32.TranslateMessage(ref msg);
User32.DispatchMessage(ref msg);
}

Refer to MSG, Creating a Message Loop.

ClipBoard Monitor C#

Here are some more helpful links, with source code:

Monitoring Activity: http://www.codeguru.com/columns/dotnettips/article.php/c7315

A viewer: http://www.doogal.co.uk/clip.php

Clipboard change event code is complicated and isn't working

To monitor Clipboard in a form, you should create your form first , then use these codes, for example:

public class Form1: Form
{
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
}

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

public const int WM_DRAWCLIPBOARD = 0x0308;

private void Form1_Load(object sender, EventArgs e)
{
SetClipboardViewer(this.Handle);
}

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg != WM_DRAWCLIPBOARD)
return;
//Code To handle Clipboard change event
}
}

Don't forget to add using System.Runtime.InteropServices;

Is it possible to code an access clipboard monitoring program?

There is no Win32 API for monitoring access to the clipboard, only for detecting when changes are made to the clipboard's content.

To do what you are asking for, you will have to write a DLL that directly hooks the Win32 OpenClipboard() function, such as with a detour, and then you can inject that DLL into all running processes, such as with SetWindowsHookEx(), AppInit_DLLs, etc. When your hook is called, it can communicate information about the calling process back to your main app as needed, such as the process ID.



Related Topics



Leave a reply



Submit