187 lines
6.6 KiB
C#
187 lines
6.6 KiB
C#
|
/******************************************************************************/
|
|||
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
|||
|
/* This work has been released under the CC0 1.0 Universal license! */
|
|||
|
/******************************************************************************/
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Windows;
|
|||
|
using System.Windows.Interop;
|
|||
|
|
|||
|
namespace com.muldersoft.slunkcrypt.gui.utils
|
|||
|
{
|
|||
|
using ItemInfo = Tuple<string, SystemMenu.SystemMenuActionHandler>;
|
|||
|
|
|||
|
class SystemMenu : IDisposable
|
|||
|
{
|
|||
|
private const int WM_SYSCOMMAND = 0x112;
|
|||
|
public delegate void SystemMenuActionHandler(SystemMenu sender, uint menuId);
|
|||
|
|
|||
|
private readonly HwndSource m_hwndSource;
|
|||
|
private readonly Dictionary<uint, ItemInfo> m_menuItems = new Dictionary<uint, ItemInfo>();
|
|||
|
|
|||
|
private bool m_firstItem = true;
|
|||
|
private uint m_nextMenuId = 100;
|
|||
|
|
|||
|
private volatile bool m_disposed = false;
|
|||
|
|
|||
|
// =============================================================================
|
|||
|
// Constructor
|
|||
|
// =============================================================================
|
|||
|
|
|||
|
public SystemMenu(Window window)
|
|||
|
{
|
|||
|
if (ReferenceEquals(window, null))
|
|||
|
{
|
|||
|
throw new ArgumentNullException("Window must not be null!");
|
|||
|
}
|
|||
|
window.Dispatcher.VerifyAccess();
|
|||
|
m_hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);
|
|||
|
m_hwndSource.AddHook(WndProcHook);
|
|||
|
}
|
|||
|
|
|||
|
// =============================================================================
|
|||
|
// Public methods
|
|||
|
// =============================================================================
|
|||
|
|
|||
|
public uint AppendMenu(string captionStr, SystemMenuActionHandler handler)
|
|||
|
{
|
|||
|
if (m_disposed)
|
|||
|
{
|
|||
|
throw new ObjectDisposedException("Already disposed!");
|
|||
|
}
|
|||
|
if (ReferenceEquals(handler, null))
|
|||
|
{
|
|||
|
throw new ArgumentNullException("SystemMenuActionHandler must not be null!");
|
|||
|
}
|
|||
|
m_hwndSource.Dispatcher.VerifyAccess();
|
|||
|
IntPtr hSysMenu = GetSystemMenu(m_hwndSource.Handle, false);
|
|||
|
if (hSysMenu != IntPtr.Zero)
|
|||
|
{
|
|||
|
if (m_firstItem)
|
|||
|
{
|
|||
|
if (AppendMenu(hSysMenu, Native.MenuFlags.MF_SEPARATOR, 0, string.Empty))
|
|||
|
{
|
|||
|
m_firstItem = false;
|
|||
|
}
|
|||
|
}
|
|||
|
if (AppendMenu(hSysMenu, Native.MenuFlags.MF_STRING, m_nextMenuId, captionStr))
|
|||
|
{
|
|||
|
uint menuItemId = m_nextMenuId++;
|
|||
|
m_menuItems.Add(menuItemId, Tuple.Create(captionStr, handler));
|
|||
|
return menuItemId;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
public bool ModifyMenu(uint menuId, bool isChecked)
|
|||
|
{
|
|||
|
if (m_disposed)
|
|||
|
{
|
|||
|
throw new ObjectDisposedException("Already disposed!");
|
|||
|
}
|
|||
|
m_hwndSource.Dispatcher.VerifyAccess();
|
|||
|
ItemInfo itemInfo;
|
|||
|
if (m_menuItems.TryGetValue(menuId, out itemInfo))
|
|||
|
{
|
|||
|
IntPtr hSysMenu = GetSystemMenu(m_hwndSource.Handle, false);
|
|||
|
if (hSysMenu != IntPtr.Zero)
|
|||
|
{
|
|||
|
return ModifyMenu(hSysMenu, menuId, Native.MenuFlags.MF_BYCOMMAND | (isChecked ? Native.MenuFlags.MF_CHECKED : Native.MenuFlags.MF_UNCHECKED), menuId, itemInfo.Item1);
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
throw new ArgumentException("Menu item ID is unknown!");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// =============================================================================
|
|||
|
// Internal methods
|
|||
|
// =============================================================================
|
|||
|
|
|||
|
private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
|||
|
{
|
|||
|
if (msg == WM_SYSCOMMAND)
|
|||
|
{
|
|||
|
uint menuId = (uint)wParam.ToInt32();
|
|||
|
ItemInfo itemInfo;
|
|||
|
if (m_menuItems.TryGetValue(menuId, out itemInfo))
|
|||
|
{
|
|||
|
itemInfo.Item2(this, menuId);
|
|||
|
handled = true;
|
|||
|
}
|
|||
|
}
|
|||
|
return IntPtr.Zero;
|
|||
|
}
|
|||
|
|
|||
|
private IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
return Native.GetSystemMenu(hWnd, bRevert);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return IntPtr.Zero;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool AppendMenu(IntPtr hMenu, Native.MenuFlags uFlags, uint uIDNewItem, string lpNewItem)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
return Native.AppendMenu(hMenu, uFlags, new UIntPtr(uIDNewItem), lpNewItem);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool ModifyMenu(IntPtr hMenu, uint uPosition, Native.MenuFlags uFlags, uint uIDNewItem, string lpNewItem)
|
|||
|
{
|
|||
|
return Native.ModifyMenu(hMenu, uPosition, uFlags, new UIntPtr(uIDNewItem), lpNewItem);
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
if (!m_disposed)
|
|||
|
{
|
|||
|
m_disposed = true;
|
|||
|
m_hwndSource.RemoveHook(WndProcHook);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// =============================================================================
|
|||
|
// Event handlers
|
|||
|
// =============================================================================
|
|||
|
|
|||
|
private class Native
|
|||
|
{
|
|||
|
[Flags]
|
|||
|
public enum MenuFlags : uint
|
|||
|
{
|
|||
|
MF_STRING = 0x0000,
|
|||
|
MF_UNCHECKED = 0x0000,
|
|||
|
MF_BYCOMMAND = 0x0000,
|
|||
|
MF_CHECKED = 0x0008,
|
|||
|
MF_BYPOSITION = 0x0400,
|
|||
|
MF_SEPARATOR = 0x0800
|
|||
|
}
|
|||
|
|
|||
|
[DllImport("user32.dll")]
|
|||
|
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
|
|||
|
|
|||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
|||
|
public static extern bool AppendMenu(IntPtr hMenu, MenuFlags uFlags, UIntPtr uIDNewItem, string lpNewItem);
|
|||
|
|
|||
|
[DllImport("user32.dll")]
|
|||
|
public static extern bool ModifyMenu(IntPtr hMenu, uint uPosition, MenuFlags uFlags, UIntPtr uIDNewItem, string lpNewItem);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|