add SystemMenuHook

This commit is contained in:
NaBian committed 2019-08-21 21:48:05 +08:00
1 parent a9720f080b
commit 3d32e17afd
15 files changed
+236 -219

No files matched your search

@@ -132,7 +132,7 @@
<Setter Property="Opacity" Value=".8" TargetName="ButtonPanel"/>
</Trigger>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Padding" Value="{x:Static tools:VisualHelper.WindowMaximizedPadding}"/>
<Setter Property="Padding" Value="{x:Static tools:WindowHelper.WindowMaximizedPadding}"/>
<Setter Property="Visibility" Value="Collapsed" TargetName="ButtonMax"/>
<Setter Property="Visibility" Value="Visible" TargetName="ButtonRestore"/>
</Trigger>
@@ -132,7 +132,7 @@
<Setter Property="Opacity" Value=".8" TargetName="ButtonPanel"/>
</Trigger>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Padding" Value="{x:Static tools:VisualHelper.WindowMaximizedPadding}"/>
<Setter Property="Padding" Value="{x:Static tools:WindowHelper.WindowMaximizedPadding}"/>
<Setter Property="Visibility" Value="Collapsed" TargetName="ButtonMax"/>
<Setter Property="Visibility" Value="Visible" TargetName="ButtonRestore"/>
</Trigger>
@@ -132,7 +132,7 @@
<Setter Property="Opacity" Value=".8" TargetName="ButtonPanel"/>
</Trigger>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Padding" Value="{x:Static tools:VisualHelper.WindowMaximizedPadding}"/>
<Setter Property="Padding" Value="{x:Static tools:WindowHelper.WindowMaximizedPadding}"/>
<Setter Property="Visibility" Value="Collapsed" TargetName="ButtonMax"/>
<Setter Property="Visibility" Value="Visible" TargetName="ButtonRestore"/>
</Trigger>
@@ -88,7 +88,7 @@ namespace HandyControlDemo.ViewModel
{
new ImageBrowser(new Uri(info.Enclosure.ToString()))
{
Owner = VisualHelper.GetActiveWindow()
Owner = WindowHelper.GetActiveWindow()
}.Show();
}
else if (info.Type == ChatMessageType.Audio)
@@ -109,7 +109,7 @@ namespace HandyControl.Controls
if (string.IsNullOrEmpty(token))
{
window = VisualHelper.GetActiveWindow();
window = WindowHelper.GetActiveWindow();
}
else
{
@@ -146,7 +146,7 @@ namespace HandyControl.Controls
{
if (string.IsNullOrEmpty(_token))
{
Close(VisualHelper.GetActiveWindow());
Close(WindowHelper.GetActiveWindow());
}
else if (WindowDic.TryGetValue(_token, out var window))
{
@@ -5,7 +5,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using HandyControl.Data;
@@ -508,26 +507,14 @@ namespace HandyControl.Controls
Content = ContextContent
};
_contextContent.IsOpen = true;
var handle = IntPtr.Zero;
var hwndSource = (HwndSource)PresentationSource.FromVisual(_contextContent.Child);
if (hwndSource != null)
{
handle = hwndSource.Handle;
}
UnsafeNativeMethods.SetForegroundWindow(handle);
UnsafeNativeMethods.SetForegroundWindow(_contextContent.Child.GetHandle());
}
else if (ContextMenu != null)
{
ContextMenu.Placement = PlacementMode.Mouse;
ContextMenu.IsOpen = true;
var handle = IntPtr.Zero;
var hwndSource = (HwndSource)PresentationSource.FromVisual(ContextMenu);
if (hwndSource != null)
{
handle = hwndSource.Handle;
}
UnsafeNativeMethods.SetForegroundWindow(handle);
UnsafeNativeMethods.SetForegroundWindow(ContextMenu.GetHandle());
}
}
@@ -51,7 +51,7 @@ namespace HandyControl.Controls
Data = accentPtr
};
ExternDllHelper.SetWindowCompositionAttribute(new WindowInteropHelper(window).Handle, ref data);
ExternDllHelper.SetWindowCompositionAttribute(window.GetHandle(), ref data);
Marshal.FreeHGlobal(accentPtr);
}
@@ -348,7 +348,7 @@ namespace HandyControl.Controls
throw new InvalidEnumArgumentException(nameof(defaultResult), (int)defaultResult, typeof(MessageBoxResult));
}
var ownerWindow = owner ?? VisualHelper.GetActiveWindow();
var ownerWindow = owner ?? WindowHelper.GetActiveWindow();
var ownerIsNull = ownerWindow is null;
return new MessageBox
@@ -261,7 +261,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ArithmeticHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ColorHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ConfigHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\CreateParams.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\DesignerHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\DpiHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ExternDllHelper.cs" />
@@ -271,9 +270,11 @@
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\SingleOpenHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ValidateHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\VisualHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\WindowHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Hook\ClipboardHook.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Hook\KeyboardHook.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Hook\MouseHook.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Hook\SystemMenuHook.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Interop\BitmapHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Interop\BITMAPINFO.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Interop\CommonHandles.cs" />
@@ -1,54 +0,0 @@
using System;
using System.Text;
namespace HandyControl.Tools
{
internal class CreateParams
{
public string ClassName { get; set; }
public string Caption { get; set; }
public int Style { get; set; }
public int ExStyle{ get; set; }
public int ClassStyle { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public IntPtr Parent { get; set; }
public object Param { get; set; }
public override string ToString()
{
var sb = new StringBuilder(64);
sb.Append("CreateParams {'");
sb.Append(ClassName);
sb.Append("', '");
sb.Append(Caption);
sb.Append("', 0x");
sb.Append(Convert.ToString(Style, 16));
sb.Append(", 0x");
sb.Append(Convert.ToString(ExStyle, 16));
sb.Append(", {");
sb.Append(X);
sb.Append(", ");
sb.Append(Y);
sb.Append(", ");
sb.Append(Width);
sb.Append(", ");
sb.Append(Height);
sb.Append("}");
sb.Append("}");
return sb.ToString();
}
}
}
@@ -1,17 +1,12 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using HandyControl.Tools.Interop;
using HandyControl.Tools.Extension;
namespace HandyControl.Tools
{
public class VisualHelper
public static class VisualHelper
{
internal static VisualStateGroup TryGetVisualStateGroup(DependencyObject d, string groupName)
{
@@ -52,136 +47,7 @@ namespace HandyControl.Tools
return default;
}
/// <summary>
/// 获取当前应用中处于激活的一个窗口
/// </summary>
/// <returns></returns>
public static Window GetActiveWindow() => Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
private static readonly BitArray _cacheValid = new BitArray((int)CacheSlot.NumSlots);
private static bool _setDpiX = true;
private static bool _dpiInitialized;
private static readonly object _dpiLock = new object();
private static int _dpi;
internal static int Dpi
{
[SecurityCritical, SecuritySafeCritical]
get
{
if (!_dpiInitialized)
{
lock (_dpiLock)
{
if (!_dpiInitialized)
{
var desktopWnd = new HandleRef(null, IntPtr.Zero);
// Win32Exception will get the Win32 error code so we don't have to
var dc = UnsafeNativeMethods.GetDC(desktopWnd);
// Detecting error case from unmanaged call, required by PREsharp to throw a Win32Exception
if (dc == IntPtr.Zero)
{
throw new Win32Exception();
}
try
{
_dpi = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), NativeMethods.LOGPIXELSY);
_dpiInitialized = true;
}
finally
{
UnsafeNativeMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
}
}
}
}
return _dpi;
}
}
private static int _dpiX;
internal static int DpiX
{
[SecurityCritical, SecuritySafeCritical]
get
{
if (_setDpiX)
{
lock (_cacheValid)
{
if (_setDpiX)
{
_setDpiX = false;
var desktopWnd = new HandleRef(null, IntPtr.Zero);
var dc = UnsafeNativeMethods.GetDC(desktopWnd);
if (dc == IntPtr.Zero)
{
throw new Win32Exception();
}
try
{
_dpiX = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), NativeMethods.LOGPIXELSX);
_cacheValid[(int)CacheSlot.DpiX] = true;
}
finally
{
UnsafeNativeMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
}
}
}
}
return _dpiX;
}
}
private static Thickness _windowResizeBorderThickness;
internal static Thickness WindowResizeBorderThickness
{
[SecurityCritical]
get
{
lock (_cacheValid)
{
while (!_cacheValid[(int)CacheSlot.WindowResizeBorderThickness])
{
_cacheValid[(int)CacheSlot.WindowResizeBorderThickness] = true;
var frameSize = new Size(NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME));
var frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize, DpiX / 96.0, Dpi / 96.0);
_windowResizeBorderThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height, frameSizeInDips.Width, frameSizeInDips.Height);
}
}
return _windowResizeBorderThickness;
}
}
public static Thickness WindowMaximizedPadding
{
get
{
#if netle40
return WindowResizeBorderThickness;
#elif Core
var hdc = UnsafeNativeMethods.GetDC(IntPtr.Zero);
var scale = UnsafeNativeMethods.GetDeviceCaps(hdc, NativeMethods.DESKTOPVERTRES) / (float)UnsafeNativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTRES);
UnsafeNativeMethods.ReleaseDC(IntPtr.Zero, hdc);
return WindowResizeBorderThickness.Add(new Thickness(4 * scale));
#else
return WindowResizeBorderThickness.Add(new Thickness(4));
#endif
}
}
public static IntPtr GetHandle(this Visual visual) =>
(PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero;
}
}
@@ -0,0 +1,152 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using System.Windows.Interop;
using HandyControl.Tools.Extension;
using HandyControl.Tools.Interop;
namespace HandyControl.Tools
{
public static class WindowHelper
{
/// <summary>
/// 获取当前应用中处于激活的一个窗口
/// </summary>
/// <returns></returns>
public static Window GetActiveWindow() => Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
private static readonly BitArray _cacheValid = new BitArray((int)CacheSlot.NumSlots);
private static bool _setDpiX = true;
private static bool _dpiInitialized;
private static readonly object _dpiLock = new object();
private static int _dpi;
internal static int Dpi
{
[SecurityCritical, SecuritySafeCritical]
get
{
if (!_dpiInitialized)
{
lock (_dpiLock)
{
if (!_dpiInitialized)
{
var desktopWnd = new HandleRef(null, IntPtr.Zero);
// Win32Exception will get the Win32 error code so we don't have to
var dc = UnsafeNativeMethods.GetDC(desktopWnd);
// Detecting error case from unmanaged call, required by PREsharp to throw a Win32Exception
if (dc == IntPtr.Zero)
{
throw new Win32Exception();
}
try
{
_dpi = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), NativeMethods.LOGPIXELSY);
_dpiInitialized = true;
}
finally
{
UnsafeNativeMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
}
}
}
}
return _dpi;
}
}
private static int _dpiX;
internal static int DpiX
{
[SecurityCritical, SecuritySafeCritical]
get
{
if (_setDpiX)
{
lock (_cacheValid)
{
if (_setDpiX)
{
_setDpiX = false;
var desktopWnd = new HandleRef(null, IntPtr.Zero);
var dc = UnsafeNativeMethods.GetDC(desktopWnd);
if (dc == IntPtr.Zero)
{
throw new Win32Exception();
}
try
{
_dpiX = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), NativeMethods.LOGPIXELSX);
_cacheValid[(int)CacheSlot.DpiX] = true;
}
finally
{
UnsafeNativeMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
}
}
}
}
return _dpiX;
}
}
private static Thickness _windowResizeBorderThickness;
internal static Thickness WindowResizeBorderThickness
{
[SecurityCritical]
get
{
lock (_cacheValid)
{
while (!_cacheValid[(int)CacheSlot.WindowResizeBorderThickness])
{
_cacheValid[(int)CacheSlot.WindowResizeBorderThickness] = true;
var frameSize = new Size(NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME));
var frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize, DpiX / 96.0, Dpi / 96.0);
_windowResizeBorderThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height, frameSizeInDips.Width, frameSizeInDips.Height);
}
}
return _windowResizeBorderThickness;
}
}
public static Thickness WindowMaximizedPadding
{
get
{
#if netle40
return WindowResizeBorderThickness;
#elif Core
var hdc = UnsafeNativeMethods.GetDC(IntPtr.Zero);
var scale = UnsafeNativeMethods.GetDeviceCaps(hdc, NativeMethods.DESKTOPVERTRES) / (float)UnsafeNativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTRES);
UnsafeNativeMethods.ReleaseDC(IntPtr.Zero, hdc);
return WindowResizeBorderThickness.Add(new Thickness(4 * scale));
#else
return WindowResizeBorderThickness.Add(new Thickness(4));
#endif
}
}
public static IntPtr CreateHandle() => new WindowInteropHelper(new Window()).EnsureHandle();
public static IntPtr GetHandle(this Window window) => new WindowInteropHelper(window).EnsureHandle();
}
}
@@ -1,5 +1,4 @@
using System;
using System.Windows;
using System.Windows.Interop;
using HandyControl.Tools.Interop;
@@ -20,7 +19,7 @@ namespace HandyControl.Tools
Stop();
}
HookId = new WindowInteropHelper(new Window()).EnsureHandle();
HookId = WindowHelper.CreateHandle();
HWndSource = HwndSource.FromHwnd(HookId);
if (HWndSource != null)
{
@@ -29,7 +28,11 @@ namespace HandyControl.Tools
}
}
public static void Stop() => NativeMethods.RemoveClipboardFormatListener(HookId);
public static void Stop()
{
HWndSource.RemoveHook(WinProc);
NativeMethods.RemoveClipboardFormatListener(HookId);
}
private static IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Interop;
using HandyControl.Tools.Interop;
namespace HandyControl.Tools
{
public class SystemMenuHook
{
private static readonly Dictionary<int, HwndSource> DataDic = new Dictionary<int, HwndSource>();
public static event EventHandler<int> Click;
public static void Insert(int index, int id, string text, Window window)
{
var hookId = window.GetHandle();
var source = HwndSource.FromHwnd(hookId);
if (source != null)
{
DataDic[id] = source;
NativeMethods.InsertMenu(NativeMethods.GetSystemMenu(hookId, false), index, NativeMethods.MF_BYPOSITION, id, text);
source.AddHook(WinProc);
}
}
public static void InsertSeperator(int index, Window window) => NativeMethods.InsertMenu(
NativeMethods.GetSystemMenu(window.GetHandle(), false), index,
NativeMethods.MF_BYPOSITION | NativeMethods.MF_SEPARATOR, 0, "");
public static void Remove(int id)
{
if (DataDic.TryGetValue(id, out var data))
{
data.RemoveHook(WinProc);
DataDic.Remove(id);
}
}
private static IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if (msg == NativeMethods.WM_SYSCOMMAND)
{
var id = wparam.ToInt32();
if (DataDic.ContainsKey(id))
{
Click?.Invoke(null, id);
}
}
return IntPtr.Zero;
}
}
}
@@ -36,6 +36,7 @@ namespace HandyControl.Tools.Interop
WM_KEYUP = 0x0101,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105,
WM_SYSCOMMAND = 0x112,
WM_MOUSEMOVE = 0x0200,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
@@ -48,6 +49,8 @@ namespace HandyControl.Tools.Interop
WM_MBUTTONDBLCLK = 0x0209,
WM_CLIPBOARDUPDATE = 0x031D,
WM_USER = 0x0400,
MF_BYPOSITION = 0x400,
MF_SEPARATOR = 0x800,
TB_GETBUTTON = WM_USER + 23,
TB_BUTTONCOUNT = WM_USER + 24,
TB_GETITEMRECT = WM_USER + 29,
@@ -232,5 +235,11 @@ namespace HandyControl.Tools.Interop
[DllImport(ExternDll.User32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
[DllImport(ExternDll.User32)]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport(ExternDll.User32)]
public static extern bool InsertMenu(IntPtr hMenu, int wPosition, int wFlags, int wIDNewItem, string lpNewItem);
}
}