/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ /**************************************************************************\ Copyright Microsoft Corporation. All Rights Reserved. \**************************************************************************/ namespace Standard { using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Threading; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; internal sealed class MessageWindow : DispatcherObject, IDisposable { // 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 s_windowLookup = new Dictionary(); private WndProc _wndProcCallback; private string _className; private bool _isDisposed; 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) { // A null callback means just use DefWindowProc. _wndProcCallback = callback; _className = "MessageWindowClass+" + Guid.NewGuid().ToString(); 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(); } } ~MessageWindow() { _Dispose(false, false); } public void Dispose() { _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)(arg => _DestroyWindow(IntPtr.Zero, className))); } else if (Handle != IntPtr.Zero) { if (CheckAccess()) { _DestroyWindow(hwnd, className); } else { Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className))); } } s_windowLookup.Remove(hwnd); _className = null; Handle = IntPtr.Zero; } [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 = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT)); 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 object _DestroyWindow(IntPtr hwnd, string className) { Utility.SafeDestroyWindow(ref hwnd); NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); return null; } } }