I have created a console application to monitor when the clipboard changes. It works fine and the code is shown below in the console code section.
My problem is now trying to do this for a WPF application using MVVM. I think I need to pass the MainWindow to my view model, is this the correct way for MVVM?
Update
This is my attempt at creating a window. I have read that I need to implement HwndHost, which I have done in my class MyFirstWindow. I am not sure how to hide the window though?
I assume in my other class below ClipboardManager I need to create an instance of MyFirstWindow. However I am unsure of what HandleRef to pass?
class MyFirstWindow : HwndHost
{
IntPtr hwndHost;
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
hwndHost = IntPtr.Zero;
hwndHost = CreateWindowEx(0, "static", "", WS_CHILD,
0, 0, 50, 50, hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero, 0);
return new HandleRef(this, hwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
internal const int
WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
LBS_NOTIFY = 0x00000001,
HOST_ID = 0x00000002,
LISTBOX_ID = 0x00000001,
WS_VSCROLL = 0x00200000,
WS_BORDER = 0x00800000;
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
}
I have created the ClipboardManager class below in my WPF application.
class ClipboardManager : IDisposable
{
#region variable declaration
/// <summary>
/// Next clipboard viewer window
/// </summary>
private IntPtr _hWndNextViewer;
/// <summary>
/// The <see cref="HwndSource"/> for this window.
/// </summary>
private HwndSource _hWndSource;
private string _clipboardContent;
#endregion
#region property declaration
public string ClipboardContent
{
get
{
return _clipboardContent;
}
set
{
_clipboardContent = value;
}
}
#endregion
public ClipboardManager()
{
hwnd = new MyFirstWindow();
InitCBViewer();
}
private void InitCBViewer(System.Windows.Window wnd)
{
WindowInteropHelper wih = new WindowInteropHelper(wnd);
_hWndSource = HwndSource.FromHwnd(wih.Handle);
_hWndSource.AddHook(WinProc); // start processing window messages
_hWndNextViewer = Win32.SetClipboardViewer(_hWndSource.Handle); // set this window as a viewer
}
private void CloseCBViewer()
{
// remove this window from the clipboard viewer chain
Win32.ChangeClipboardChain(_hWndSource.Handle, _hWndNextViewer);
_hWndNextViewer = IntPtr.Zero;
_hWndSource.RemoveHook(this.WinProc);
}
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == _hWndNextViewer)
{
// clipboard viewer chain changed, need to fix it.
_hWndNextViewer = lParam;
}
else if (_hWndNextViewer != IntPtr.Zero)
{
// pass the message to the next viewer.
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
}
break;
case Win32.WM_DRAWCLIPBOARD:
// clipboard content changed
if (Clipboard.ContainsText())
{
ClipboardContent = Clipboard.GetText();
}
// pass the message to the next viewer.
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
public void Dispose()
{
CloseCBViewer();
}
}
win 32 class
internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WM_DRAWCLIPBOARD = 0x0308;
/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WM_CHANGECBCHAIN = 0x030D;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}