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