Closed jiayinzhang-mint closed 4 years ago
It looks like .Net Core console applications may require a reference to System.Windows.Forms
in order to obtain a Window handle to the System Clipboard.
I've tested the library with .Net Core 3.1
Windows Forms app and it's working perfectly.
I'll probably need to update the repo with a few projects targeting .Net Core later.
Thanks for reply! It looks like some thread-related issues. Like native windows Clipboard API, which works on main thread but fails if running in a new thread / task.
That's another very likely cause. Let's keep testing...
I can't get this to work.
@mintxtinm Do you have some guidance or a minimal project where it works?
@KoalaBear84 This piece of code seems to work fine with console app, through far less elegant than this project.
` class ClipboardMonitor { public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data); public static event OnClipboardChangeEventHandler OnClipboardChange;
public static void Start()
{
ClipboardWatcher.Start();
ClipboardWatcher.OnClipboardChange += (ClipboardFormat format, object data) =>
{
if (OnClipboardChange != null)
OnClipboardChange(format, data);
};
}
public static void Stop()
{
OnClipboardChange = null;
ClipboardWatcher.Stop();
}
class ClipboardWatcher : Form
{
// static instance of this form
private static ClipboardWatcher mInstance;
// needed to dispose this form
static IntPtr nextClipboardViewer;
public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
public static event OnClipboardChangeEventHandler OnClipboardChange;
// start listening
public static void Start()
{
// we can only have one instance if this class
if (mInstance != null)
return;
Thread t = new Thread(new ParameterizedThreadStart(x =>
{
Application.Run(new ClipboardWatcher());
}));
t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
t.Start();
}
// stop listening (dispose form)
public static void Stop()
{
mInstance.Invoke(new MethodInvoker(() =>
{
ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
}));
mInstance.Invoke(new MethodInvoker(mInstance.Close));
mInstance.Dispose();
mInstance = null;
}
// on load: (hide this window)
protected override void SetVisibleCore(bool value)
{
CreateHandle();
mInstance = this;
nextClipboardViewer = SetClipboardViewer(mInstance.Handle);
base.SetVisibleCore(false);
}
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
// defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
ClipChanged();
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextClipboardViewer)
nextClipboardViewer = m.LParam;
else
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
default:
base.WndProc(ref m);
break;
}
}
static readonly string[] formats = Enum.GetNames(typeof(ClipboardFormat));
private void ClipChanged()
{
IDataObject iData = Clipboard.GetDataObject();
ClipboardFormat? format = null;
foreach (var f in formats)
{
if (iData.GetDataPresent(f))
{
format = (ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);
break;
}
}
object data = iData.GetData(format.ToString());
if (data == null || format == null)
return;
if (OnClipboardChange != null)
OnClipboardChange((ClipboardFormat)format, data);
}
}
}
public enum ClipboardFormat : byte
{
Text,
UnicodeText,
Dib,
Bitmap,
EnhancedMetafile,
MetafilePict,
SymbolicLink,
Dif,
Tiff,
OemText,
Palette,
PenData,
Riff,
WaveAudio,
FileDrop,
Locale,
Html,
Rtf,
CommaSeparatedValue,
StringFormat,
Serializable,
}
`
Thanks, I'm going to take a look at it ASAP. 👍
Issue: the event listener start successfully, but ClipboardChanged function is never triggered.
Target framework: .NET Core 3.1 Output type: Console Application
Code: `namespace TestClipboardWatcher { class Watcher { [STAThread] static void Main(string[] args) { using SharpClipboard clipboard = new SharpClipboard(); clipboard.ClipboardChanged += ClipboardChanged;
}`