All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.7 KiB

/*************************************************************************************
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<IntPtr, MessageWindow> s_windowLookup = new Dictionary<IntPtr, MessageWindow>();
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;
}
}
}