185 lines
6.5 KiB
C#
185 lines
6.5 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
|
|
{
|
|
class SystemMenu : IDisposable
|
|
{
|
|
private const int WM_SYSCOMMAND = 0x112;
|
|
public delegate void SystemMenuActionHandler(SystemMenu sender, uint menuId);
|
|
|
|
private readonly SystemMenuActionHandler m_handler;
|
|
private readonly HwndSource m_hwndSource;
|
|
private readonly Dictionary<uint, string> m_menuItems = new Dictionary<uint, string>();
|
|
|
|
private bool m_firstItem = true;
|
|
private uint m_nextMenuId = 100;
|
|
|
|
private volatile bool m_disposed = false;
|
|
|
|
// =============================================================================
|
|
// Constructor
|
|
// =============================================================================
|
|
|
|
public SystemMenu(Window window, SystemMenuActionHandler handler)
|
|
{
|
|
if (ReferenceEquals(window, null))
|
|
{
|
|
throw new ArgumentNullException("Window must not be null!");
|
|
}
|
|
if (ReferenceEquals(m_handler = handler, null))
|
|
{
|
|
throw new ArgumentNullException("SystemMenuActionHandler 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)
|
|
{
|
|
if (m_disposed)
|
|
{
|
|
throw new ObjectDisposedException("Already disposed!");
|
|
}
|
|
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, captionStr);
|
|
return menuItemId;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public bool ModifyMenu(uint menuId, bool isChecked)
|
|
{
|
|
if (m_disposed)
|
|
{
|
|
throw new ObjectDisposedException("Already disposed!");
|
|
}
|
|
m_hwndSource.Dispatcher.VerifyAccess();
|
|
string captionStr;
|
|
if (m_menuItems.TryGetValue(menuId, out captionStr))
|
|
{
|
|
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, captionStr);
|
|
}
|
|
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;
|
|
if (m_menuItems.ContainsKey(menuId = (uint) wParam.ToInt32()))
|
|
{
|
|
m_handler(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);
|
|
}
|
|
}
|
|
}
|