Archive Browser
Download MessageFilterDemo.zip, last updated 01/01/2019 (11.93 KB)
Download- md5: dd6db4054824db8b977c862915aff068
- sha1: 6bb3415a3961d9cbc340e034ddea7f89193c95f2
- sha256: 4b813ad6c216885567cf570f290919e9043cee4a865a06a56b864f8f323a1a8d
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
// Using message filters in Windows Forms applications
// http://cyotek.com/blog/using-message-filters-in-windows-forms-applications
// Severely stripped down version of https://github.com/ygoe/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs
// with IMessageFilter support to avoid having to pass messages into the class from the owner form
namespace Cyotek.Demonstrations.MessageFilter
{
internal sealed class SystemMenu : IMessageFilter
{
#region Externals
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
#endregion
#region Constants
private const int MF_SEPARATOR = 0x800;
private const int MF_STRING = 0x0;
private const int WM_SYSCOMMAND = 0x112;
#endregion
#region Fields
private List<Action> _actions = new List<Action>();
private int _lastId = 0;
private Form _owner;
#endregion
#region Constructors
/// <summary>
/// Initialises a new instance of the <see cref="SystemMenu"/> class for the specified
/// <see cref="Form"/>.
/// </summary>
/// <param name="owner">The window for which the system menu is expanded.</param>
public SystemMenu(Form owner)
{
if (owner == null)
{
throw new ArgumentNullException(nameof(owner));
}
_owner = owner;
owner.FormClosed += this.FormClosedHandler;
Application.AddMessageFilter(this);
}
#endregion
#region Methods
/// <summary>
/// Adds a command to the system menu.
/// </summary>
/// <param name="text">The displayed command text.</param>
/// <param name="action">The action that is executed when the user clicks on the command.</param>
/// <param name="separatorBeforeCommand">Indicates whether a separator is inserted before the command.</param>
public void AddCommand(string text, Action action, bool separatorBeforeCommand)
{
IntPtr systemMenuHandle;
int id;
systemMenuHandle = GetSystemMenu(_owner.Handle, false);
id = ++_lastId;
if (separatorBeforeCommand)
{
AppendMenu(systemMenuHandle, MF_SEPARATOR, 0, string.Empty);
}
AppendMenu(systemMenuHandle, MF_STRING, id, text);
_actions.Add(action);
}
private void FormClosedHandler(object sender, FormClosedEventArgs e)
{
Application.RemoveMessageFilter(this);
_actions = null;
_owner.FormClosed -= this.FormClosedHandler;
_owner = null;
}
private bool OnSysCommandMessage(ref Message msg)
{
bool result;
int commandId;
commandId = msg.WParam.ToInt32();
result = commandId > 0 && commandId <= _lastId;
Debug.WriteLine("System menu command: " + commandId);
if (result)
{
_actions[commandId - 1].Invoke();
}
return result;
}
#endregion
#region IMessageFilter Interface
bool IMessageFilter.PreFilterMessage(ref Message m)
{
bool result;
//Debug.WriteLine(m);
if (m.Msg == WM_SYSCOMMAND && m.HWnd == _owner.Handle)
{
result = this.OnSysCommandMessage(ref m);
}
else
{
result = false; // allow the message to continue being processed
}
return result;
}
#endregion
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate