using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Threading; namespace Standard; internal sealed class MessageWindow : DispatcherObject, IDisposable { public IntPtr Handle { get; private set; } [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) { this._wndProcCallback = callback; this._className = "MessageWindowClass+" + Guid.NewGuid().ToString(); WNDCLASSEX wndclassex = new WNDCLASSEX { cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), style = classStyle, lpfnWndProc = MessageWindow.s_WndProc, hInstance = NativeMethods.GetModuleHandle(null), hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), lpszMenuName = "", lpszClassName = this._className }; NativeMethods.RegisterClassEx(ref wndclassex); GCHandle value = default(GCHandle); try { value = GCHandle.Alloc(this); IntPtr lpParam = (IntPtr) value; this.Handle = NativeMethods.CreateWindowEx(exStyle, this._className, name, style, (int) location.X, (int) location.Y, (int) location.Width, (int) location.Height, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, lpParam); } finally { value.Free(); } } ~MessageWindow() { this._Dispose(false, false); } public void Dispose() { this._Dispose(true, false); GC.SuppressFinalize(this); } [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] private void _Dispose(bool disposing, bool isHwndBeingDestroyed) { if (this._isDisposed) { return; } this._isDisposed = true; IntPtr hwnd = this.Handle; string className = this._className; if (isHwndBeingDestroyed) { base.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback((object arg) => MessageWindow._DestroyWindow(IntPtr.Zero, className))); } else if (this.Handle != IntPtr.Zero) { if (base.CheckAccess()) { MessageWindow._DestroyWindow(hwnd, className); } else { base.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback((object arg) => MessageWindow._DestroyWindow(hwnd, className))); } } MessageWindow.s_windowLookup.Remove(hwnd); this._className = null; this.Handle = IntPtr.Zero; } [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) { IntPtr result = IntPtr.Zero; MessageWindow messageWindow = null; if (msg == WM.CREATE) { messageWindow = (MessageWindow) GCHandle.FromIntPtr(((CREATESTRUCT) Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT))).lpCreateParams).Target; MessageWindow.s_windowLookup.Add(hwnd, messageWindow); } else if (!MessageWindow.s_windowLookup.TryGetValue(hwnd, out messageWindow)) { return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); } WndProc wndProcCallback = messageWindow._wndProcCallback; if (wndProcCallback != null) { result = wndProcCallback(hwnd, msg, wParam, lParam); } else { result = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); } if (msg == WM.NCDESTROY) { messageWindow._Dispose(true, true); GC.SuppressFinalize(messageWindow); } return result; } private static object _DestroyWindow(IntPtr hwnd, string className) { Utility.SafeDestroyWindow(ref hwnd); NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); return null; } private static readonly WndProc s_WndProc = new WndProc(MessageWindow._WndProc); private static readonly Dictionary s_windowLookup = new Dictionary(); private WndProc _wndProcCallback; private string _className; private bool _isDisposed; }