NativeMethods.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. using System.Drawing;
  2. using System.Linq;
  3. using System.Runtime.InteropServices;
  4. using System.Windows.Interop;
  5. namespace System.Windows.Forms
  6. {
  7. public enum SizingAction
  8. {
  9. None = 0,
  10. North = 3,
  11. South = 6,
  12. East = 2,
  13. West = 1,
  14. NorthEast = 5,
  15. NorthWest = 4,
  16. SouthEast = 8,
  17. SouthWest = 7
  18. }
  19. internal static class NativeMethods
  20. {
  21. const int WM_SYSCOMMAND = 0x112;
  22. const int SC_SIZE = 0xF000;
  23. const int GWL_STYLE = -16;
  24. const int GWL_EXSTYLE = -20;
  25. const int WS_EX_DLGMODALFRAME = 0x0001;
  26. const int SW_MAXIMIZE = 3;
  27. const int WS_MAXIMIZEBOX = 0x10000;
  28. const int WS_MINIMIZEBOX = 0x20000;
  29. const int WM_SETICON = 0x0080;
  30. [DllImport("user32.dll", SetLastError = true)]
  31. private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
  32. [DllImport("user32.dll")]
  33. static extern int GetWindowLong(IntPtr hwnd, int index);
  34. [DllImport("user32.dll")]
  35. static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
  36. [DllImport("user32.dll")]
  37. [return: MarshalAs(UnmanagedType.Bool)]
  38. internal static extern bool GetCursorPos(ref Win32Point pt);
  39. [DllImport("user32.dll")]
  40. public static extern int GetDoubleClickTime();
  41. [DllImport("user32.dll")]
  42. private extern static int GetWindowRect(IntPtr hWnd, ref RECT lpRect);
  43. [DllImport("user32.dll")]
  44. private extern static int GetClientRect(IntPtr hWnd, ref RECT lpRect);
  45. [DllImport("user32.dll")]
  46. private static extern IntPtr MonitorFromPoint(Win32Point pt, int flags);
  47. [DllImport("user32.dll", SetLastError = true)]
  48. public static extern IntPtr MonitorFromWindow(HandleRef handle, int flags);
  49. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  50. public static extern bool GetMonitorInfo(HandleRef hmonitor, [In][Out] MONITORINFOEX info);
  51. [DllImport("user32.dll")]
  52. public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
  53. public delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
  54. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  55. static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
  56. [DllImport("dwmapi.dll", PreserveSig = true)]
  57. private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
  58. [DllImport("dwmapi.dll")]
  59. private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref NativeMethods.RECT pMarInset);
  60. [StructLayout(LayoutKind.Sequential)]
  61. public struct Win32Point
  62. {
  63. public Int32 X;
  64. public Int32 Y;
  65. };
  66. [StructLayout(LayoutKind.Sequential)]
  67. public struct RECT
  68. {
  69. public int left;
  70. public int top;
  71. public int right;
  72. public int bottom;
  73. public int Width => right - left;
  74. public int Height => bottom - top;
  75. }
  76. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
  77. public class MONITORINFOEX
  78. {
  79. internal int cbSize = SizeOf();
  80. internal RECT rcMonitor;
  81. internal RECT rcWork;
  82. internal int dwFlags;
  83. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  84. internal char[] szDevice = new char[32];
  85. private static int SizeOf() => Marshal.SizeOf(typeof(MONITORINFOEX));
  86. }
  87. [StructLayout(LayoutKind.Sequential)]
  88. public struct MINMAXINFO
  89. {
  90. public Win32Point ptReserved;
  91. public Win32Point ptMaxSize;
  92. public Win32Point ptMaxPosition;
  93. public Win32Point ptMinTrackSize;
  94. public Win32Point ptMaxTrackSize;
  95. };
  96. [StructLayout(LayoutKind.Sequential)]
  97. private struct WINDOWPLACEMENT
  98. {
  99. public int length;
  100. public int flags;
  101. public int showCmd;
  102. public Win32Point ptMinPosition;
  103. public Win32Point ptMaxPosition;
  104. public RECT rcNormalPosition;
  105. public RECT rcDevice;
  106. }
  107. [DllImport("user32.dll")]
  108. private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
  109. public static bool IsWindowMaximized(IntPtr hWnd)
  110. {
  111. var wpl = new WINDOWPLACEMENT();
  112. GetWindowPlacement(hWnd, ref wpl);
  113. return wpl.showCmd == SW_MAXIMIZE;
  114. }
  115. [DllImport("user32.dll")]
  116. private static extern IntPtr GetActiveWindow();
  117. public static Window ActiveWindow()
  118. {
  119. IntPtr active = GetActiveWindow();
  120. return System.Windows.Application.Current.Windows.OfType<System.Windows.Window>()
  121. .SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);
  122. }
  123. [DllImport("Shcore.dll")]
  124. private static extern IntPtr GetDpiForMonitor([In] IntPtr hmonitor, [In] uint dpiType, [Out] out uint dpiX, [Out] out uint dpiY);
  125. public static int GetDpiForMonitor(IntPtr mon)
  126. {
  127. try
  128. {
  129. GetDpiForMonitor(mon, 0, out uint dpiX, out uint dpiY);
  130. return (int)dpiX;
  131. }
  132. catch
  133. {
  134. using (Graphics gr = Graphics.FromHwnd(IntPtr.Zero))
  135. return (int)gr.DpiX;
  136. }
  137. }
  138. public static void MoveWindow(Form form, Rectangle rect)
  139. {
  140. IntPtr handle = new WindowInteropHelper(form.window).EnsureHandle();
  141. // The first move puts it on the correct monitor, which triggers WM_DPICHANGED
  142. // The +1/-1 coerces WPF to update Window.Top/Left/Width/Height in the second move
  143. MoveWindow(handle, rect.Left + 1, rect.Top, rect.Width - 1, rect.Height, false);
  144. MoveWindow(handle, rect.Left, rect.Top, rect.Width, rect.Height, true);
  145. }
  146. public static Drawing.Point GetMousePosition()
  147. {
  148. var w32Mouse = new Win32Point();
  149. GetCursorPos(ref w32Mouse);
  150. return new Drawing.Point(w32Mouse.X, w32Mouse.Y);
  151. }
  152. public static IntPtr GetCurrentMonitorFromMousePosition()
  153. {
  154. var w32Mouse = new Win32Point();
  155. GetCursorPos(ref w32Mouse);
  156. return MonitorFromPoint(w32Mouse, 2);
  157. }
  158. public static IntPtr GetMonitorFromPoint(int x, int y)
  159. {
  160. return MonitorFromPoint(new Win32Point() { X = x, Y = y }, 2);
  161. }
  162. public static RECT WorkAreaBoundsForMointor(IntPtr hMonitor)
  163. {
  164. MONITORINFOEX info = new MONITORINFOEX();
  165. GetMonitorInfo(new HandleRef(null, hMonitor), info);
  166. return info.rcWork;
  167. }
  168. public static Drawing.Size GetClientSizeDelta(Window window)
  169. {
  170. IntPtr handle = new WindowInteropHelper(window).EnsureHandle();
  171. RECT rect = new RECT();
  172. GetWindowRect(handle, ref rect);
  173. RECT clientRect = new RECT();
  174. GetClientRect(handle, ref clientRect);
  175. return new Drawing.Size(rect.Width - clientRect.Width, rect.Height - clientRect.Height);
  176. }
  177. public static void RemoveWindowItems(Window window, bool icon, bool minimize, bool maximize)
  178. {
  179. IntPtr hwnd = new WindowInteropHelper(window).EnsureHandle();
  180. if (!icon)
  181. {
  182. int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  183. SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
  184. // this removes icon if it is set in app resources (case: the WpfDemo)
  185. SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
  186. SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
  187. }
  188. if (!minimize || !maximize)
  189. {
  190. int currentStyle = GetWindowLong(hwnd, GWL_STYLE);
  191. if (!minimize)
  192. currentStyle &= ~WS_MINIMIZEBOX;
  193. if (!maximize)
  194. currentStyle &= ~WS_MAXIMIZEBOX;
  195. SetWindowLong(hwnd, GWL_STYLE, currentStyle);
  196. }
  197. }
  198. public static void DragSize(IntPtr handle, SizingAction sizingAction)
  199. {
  200. SendMessage(handle, WM_SYSCOMMAND, (IntPtr)(SC_SIZE + sizingAction), IntPtr.Zero);
  201. }
  202. public static bool DropShadow(IntPtr handle, bool shadow)
  203. {
  204. try
  205. {
  206. int val = 2;
  207. int ret1 = DwmSetWindowAttribute(handle, 2, ref val, 4);
  208. if (ret1 == 0)
  209. {
  210. var m = new RECT { left = 0, top = shadow ? 1 : 0, right = 0, bottom = 0 };
  211. int ret2 = DwmExtendFrameIntoClientArea(handle, ref m);
  212. return ret2 == 0;
  213. }
  214. else
  215. {
  216. return false;
  217. }
  218. }
  219. catch
  220. {
  221. // Probably dwmapi.dll not found (incompatible OS)
  222. return false;
  223. }
  224. }
  225. }
  226. }