| File: System\Windows\Standard\MessageWindow.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Threading; using System.Diagnostics.CodeAnalysis; namespace Standard { internal sealed class MessageWindow : CriticalFinalizerObject { static MessageWindow() { } // Alias this to a static so the wrapper doesn't get GC'd private static readonly WndProc s_WndProc = new WndProc(_WndProc); private static readonly Dictionary<IntPtr, MessageWindow> s_windowLookup = new Dictionary<IntPtr, MessageWindow>(); private WndProc _wndProcCallback; private string _className; private bool _isDisposed; private Dispatcher _dispatcher; public IntPtr Handle { get; private set; } public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) { // A null callback means just use DefWindowProc. _wndProcCallback = callback; _className = $"MessageWindowClass+{Guid.NewGuid()}"; var wc = new WNDCLASSEX { cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), style = classStyle, lpfnWndProc = s_WndProc, hInstance = NativeMethods.GetModuleHandle(null), hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), lpszMenuName = "", lpszClassName = _className, }; NativeMethods.RegisterClassEx(ref wc); GCHandle gcHandle = default(GCHandle); try { gcHandle = GCHandle.Alloc(this); IntPtr pinnedThisPtr = (IntPtr)gcHandle; Handle = NativeMethods.CreateWindowEx( exStyle, _className, name, style, (int)location.X, (int)location.Y, (int)location.Width, (int)location.Height, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, pinnedThisPtr); } finally { gcHandle.Free(); } _dispatcher = Dispatcher.CurrentDispatcher; } ~MessageWindow() { _Dispose(false, false); } public void Release() { _Dispose(true, false); GC.SuppressFinalize(this); } // This isn't right if the Dispatcher has already started shutting down. // It will wind up leaking the class ATOM... [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] private void _Dispose(bool disposing, bool isHwndBeingDestroyed) { if (_isDisposed) { // Block against reentrancy. return; } _isDisposed = true; IntPtr hwnd = Handle; string className = _className; if (isHwndBeingDestroyed) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)_DestroyWindowCallback, new object [] { IntPtr.Zero, className }); } else if (Handle != IntPtr.Zero) { if (_dispatcher.CheckAccess()) { _DestroyWindow(hwnd, className); } else { _dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)_DestroyWindowCallback, new object [] { hwnd, className }); } } s_windowLookup.Remove(hwnd); _className = null; Handle = IntPtr.Zero; } private object _DestroyWindowCallback(object arg) { object [] args = (object[])arg; _DestroyWindow((IntPtr)args[0], (string)args[1]); return null; } [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) { IntPtr ret = IntPtr.Zero; MessageWindow hwndWrapper = null; if (msg == WM.CREATE) { var createStruct = Marshal.PtrToStructure<CREATESTRUCT>(lParam); GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams); hwndWrapper = (MessageWindow)gcHandle.Target; s_windowLookup.Add(hwnd, hwndWrapper); } else { if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper)) { return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); } } Assert.IsNotNull(hwndWrapper); WndProc callback = hwndWrapper._wndProcCallback; if (callback != null) { ret = callback(hwnd, msg, wParam, lParam); } else { ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); } if (msg == WM.NCDESTROY) { hwndWrapper._Dispose(true, true); GC.SuppressFinalize(hwndWrapper); } return ret; } private static void _DestroyWindow(IntPtr hwnd, string className) { Utility.SafeDestroyWindow(ref hwnd); NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); } } }