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