MessageWindow.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*************************************************************************************
  2. Extended WPF Toolkit
  3. Copyright (C) 2007-2013 Xceed Software Inc.
  4. This program is provided to you under the terms of the Microsoft Public
  5. License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
  6. For more features, controls, and fast professional support,
  7. pick up the Plus Edition at http://xceed.com/wpf_toolkit
  8. Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
  9. ***********************************************************************************/
  10. /**************************************************************************\
  11. Copyright Microsoft Corporation. All Rights Reserved.
  12. \**************************************************************************/
  13. namespace Standard
  14. {
  15. using System;
  16. using System.Runtime.InteropServices;
  17. using System.Windows;
  18. using System.Windows.Threading;
  19. using System.Collections.Generic;
  20. using System.Diagnostics.CodeAnalysis;
  21. internal sealed class MessageWindow : DispatcherObject, IDisposable
  22. {
  23. // Alias this to a static so the wrapper doesn't get GC'd
  24. private static readonly WndProc s_WndProc = new WndProc(_WndProc);
  25. private static readonly Dictionary<IntPtr, MessageWindow> s_windowLookup = new Dictionary<IntPtr, MessageWindow>();
  26. private WndProc _wndProcCallback;
  27. private string _className;
  28. private bool _isDisposed;
  29. public IntPtr Handle { get; private set; }
  30. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  31. public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback)
  32. {
  33. // A null callback means just use DefWindowProc.
  34. _wndProcCallback = callback;
  35. _className = "MessageWindowClass+" + Guid.NewGuid().ToString();
  36. var wc = new WNDCLASSEX
  37. {
  38. cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)),
  39. style = classStyle,
  40. lpfnWndProc = s_WndProc,
  41. hInstance = NativeMethods.GetModuleHandle(null),
  42. hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH),
  43. lpszMenuName = "",
  44. lpszClassName = _className,
  45. };
  46. NativeMethods.RegisterClassEx(ref wc);
  47. GCHandle gcHandle = default(GCHandle);
  48. try
  49. {
  50. gcHandle = GCHandle.Alloc(this);
  51. IntPtr pinnedThisPtr = (IntPtr)gcHandle;
  52. Handle = NativeMethods.CreateWindowEx(
  53. exStyle,
  54. _className,
  55. name,
  56. style,
  57. (int)location.X,
  58. (int)location.Y,
  59. (int)location.Width,
  60. (int)location.Height,
  61. IntPtr.Zero,
  62. IntPtr.Zero,
  63. IntPtr.Zero,
  64. pinnedThisPtr);
  65. }
  66. finally
  67. {
  68. gcHandle.Free();
  69. }
  70. }
  71. ~MessageWindow()
  72. {
  73. _Dispose(false, false);
  74. }
  75. public void Dispose()
  76. {
  77. _Dispose(true, false);
  78. GC.SuppressFinalize(this);
  79. }
  80. // This isn't right if the Dispatcher has already started shutting down.
  81. // It will wind up leaking the class ATOM...
  82. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")]
  83. private void _Dispose(bool disposing, bool isHwndBeingDestroyed)
  84. {
  85. if (_isDisposed)
  86. {
  87. // Block against reentrancy.
  88. return;
  89. }
  90. _isDisposed = true;
  91. IntPtr hwnd = Handle;
  92. string className = _className;
  93. if (isHwndBeingDestroyed)
  94. {
  95. Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(IntPtr.Zero, className)));
  96. }
  97. else if (Handle != IntPtr.Zero)
  98. {
  99. if (CheckAccess())
  100. {
  101. _DestroyWindow(hwnd, className);
  102. }
  103. else
  104. {
  105. Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className)));
  106. }
  107. }
  108. s_windowLookup.Remove(hwnd);
  109. _className = null;
  110. Handle = IntPtr.Zero;
  111. }
  112. [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")]
  113. private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam)
  114. {
  115. IntPtr ret = IntPtr.Zero;
  116. MessageWindow hwndWrapper = null;
  117. if (msg == WM.CREATE)
  118. {
  119. var createStruct = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT));
  120. GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams);
  121. hwndWrapper = (MessageWindow)gcHandle.Target;
  122. s_windowLookup.Add(hwnd, hwndWrapper);
  123. }
  124. else
  125. {
  126. if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper))
  127. {
  128. return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam);
  129. }
  130. }
  131. Assert.IsNotNull(hwndWrapper);
  132. WndProc callback = hwndWrapper._wndProcCallback;
  133. if (callback != null)
  134. {
  135. ret = callback(hwnd, msg, wParam, lParam);
  136. }
  137. else
  138. {
  139. ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam);
  140. }
  141. if (msg == WM.NCDESTROY)
  142. {
  143. hwndWrapper._Dispose(true, true);
  144. GC.SuppressFinalize(hwndWrapper);
  145. }
  146. return ret;
  147. }
  148. private static object _DestroyWindow(IntPtr hwnd, string className)
  149. {
  150. Utility.SafeDestroyWindow(ref hwnd);
  151. NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null));
  152. return null;
  153. }
  154. }
  155. }