using System;
using System.Runtime.InteropServices;
using static Vanara.PInvoke.Kernel32;
using static Vanara.PInvoke.User32;
namespace Vanara.PInvoke
{
/// A filter method that handles messages sent to a window.
/// A handle to the window.
/// The MSG.
/// Additional message information. The contents of this parameter depend on the value of the uMsg parameter.
/// Additional message information. The contents of this parameter depend on the value of the uMsg parameter.
/// The return value is the result of the message processing and depends on the message sent.
///
/// if the message is handled and should not be called;
/// otherwise.
///
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate bool BasicMessageWindowFilter(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam, out IntPtr lReturn);
/// Simple window to process messages.
///
///
///
public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle
{
private readonly WeakReference weakSelfRef;
private SafeHWND hwnd;
private bool isDisposed;
private WindowClass wCls;
/// Initializes a new instance of the class.
/// Specifies the callback method to use to process messages.
public BasicMessageWindow(BasicMessageWindowFilter callback = null)
{
MessageFilter = callback;
weakSelfRef = new WeakReference(this);
hwnd = CreateWindow();
}
/// Finalizes an instance of the class.
~BasicMessageWindow() => Dispose(false);
/// Gets the handle.
/// The handle.
public HWND Handle => hwnd ?? HWND.NULL;
/// Gets or sets the callback method used to filter window messages.
/// The callback method.
public BasicMessageWindowFilter MessageFilter { get; set; }
/// Gets the name of the class.
/// The name of the class.
public string ClassName => wCls?.ClassName;
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
/// Returns the value of the handle field.
/// An IntPtr representing the value of the handle field.
IntPtr IHandle.DangerousGetHandle() => (IntPtr)Handle;
///
/// Method used to create the window. When overriding, the hWnd field must be set to the handle of the created window.
///
protected virtual SafeHWND CreateWindow()
{
lock (this)
{
if (!Handle.IsNull)
throw new InvalidOperationException("Window handle already exists.");
HINSTANCE hInst = GetModuleHandle();
wCls = new WindowClass($"{GetType().Name}+{Guid.NewGuid()}", hInst, WndProc);
return Win32Error.ThrowLastErrorIfInvalid(CreateWindowEx(0, wCls.Atom, hWndParent: HWND.HWND_MESSAGE, hInstance: hInst));
}
}
/// Releases unmanaged and - optionally - managed resources.
///
/// to release both managed and unmanaged resources; to release only unmanaged resources.
///
protected virtual void Dispose(bool disposing)
{
if (isDisposed)
return;
isDisposed = true;
hwnd?.Dispose(); // Calls DestroyWindow
hwnd = null;
wCls?.Unregister();
}
private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
{
if (msg == (uint)WindowMessage.WM_NCCREATE)
return (IntPtr)1;
return !weakSelfRef.IsAlive || weakSelfRef.Target is null || MessageFilter is null || !MessageFilter.Invoke(hwnd, msg, wParam, lParam, out IntPtr lRet)
? DefWindowProc(hwnd, msg, wParam, lParam)
: lRet;
}
}
}