Add to right click application menu in taskbar in .NET
Asked Answered
M

2

7

Most applications only have "Restore, Move, Size, Minimize, Maximize and Close", however MS SQL offers extra options "Help, Customize view". Along those lines, is it possible to add to the right click menu of an application in the task bar?

Note: I'm not referring to an icon in the notification area next to the clock.

Mediterranean answered 30/9, 2008 at 15:4 Comment(2)
I can't help you directly, but the menu you are referring to is the System Menu. This is the same that is displayed when clicking on the application icon in the window title bar. Maybe this will help you or others with finding the answer :)Feudatory
This article gives you a walk through in C#!Illomened
S
1

This is a simpler answer I found. I quickly tested it and it works.

My code:

    private const int WMTaskbarRClick = 0x0313;

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WMTaskbarRClick:
                {
                    // Show your own context menu here, i do it like this
                    // there's a context menu present on my main form so i use it

                    MessageBox.Show("I see that.");

                    break;
                }
            default:
                {
                    base.WndProc(ref m);
                    break;
                }
        }
    }
Sopher answered 30/9, 2008 at 15:31 Comment(3)
But this wouldn't be integrated with the existing menu, if you simply show your menu.Illomened
This seems to only work, when holding the SHIFT key down while right-clickingLucianolucias
@Lucianolucias Seems it is for the Windows XP menu (the one starting restore, move, size), which is shown by shift+click on Vista+. This isn't usually the one you want to override.Shaeffer
D
0

The menu on right click of the minimized program or Alt+Space or right click of the window icon in the title bar is called the SysMenu.

Here's an option for WPF:

// License MIT 2019 Mitch Gaffigan
// https://mcmap.net/q/1570926/-add-to-right-click-application-menu-in-taskbar-in-net
public class SysMenu
{
    private readonly Window Window;
    private readonly List<MenuItem> Items;
    private bool isInitialized;
    private IntPtr NextID = (IntPtr)1000;
    private int StartPosition = 5;

    public SysMenu(Window window)
    {
        this.Items = new List<MenuItem>();
        this.Window = window ?? throw new ArgumentNullException(nameof(window));
        this.Window.SourceInitialized += this.Window_SourceInitialized;
    }

    class MenuItem
    {
        public IntPtr ID;
        public string Text;
        public Action OnClick;
    }

    public void AddSysMenuItem(string text, Action onClick)
    {
        if (string.IsNullOrWhiteSpace(text))
        {
            throw new ArgumentNullException(nameof(text));
        }
        if (onClick == null)
        {
            throw new ArgumentNullException(nameof(onClick));
        }

        var thisId = NextID;
        NextID += 1;

        var newItem = new MenuItem()
        {
            ID = thisId,
            Text = text,
            OnClick = onClick
        };
        Items.Add(newItem);
        var thisPosition = StartPosition + Items.Count;

        if (isInitialized)
        {
            var hwndSource = PresentationSource.FromVisual(Window) as HwndSource;
            if (hwndSource == null)
            {
                return;
            }
            var hSysMenu = GetSystemMenu(hwndSource.Handle, false);
            InsertMenu(hSysMenu, thisPosition, MF_BYPOSITION, thisId, text);
        }
    }

    private void Window_SourceInitialized(object sender, EventArgs e)
    {
        var hwndSource = PresentationSource.FromVisual(Window) as HwndSource;
        if (hwndSource == null)
        {
            return;
        }

        hwndSource.AddHook(WndProc);

        var hSysMenu = GetSystemMenu(hwndSource.Handle, false);

        /// Create our new System Menu items just before the Close menu item
        InsertMenu(hSysMenu, StartPosition, MF_BYPOSITION | MF_SEPARATOR, IntPtr.Zero, string.Empty);
        int pos = StartPosition + 1;
        foreach (var item in Items)
        {
            InsertMenu(hSysMenu, pos, MF_BYPOSITION, item.ID, item.Text);
            pos += 1;
        }

        isInitialized = true;
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_SYSCOMMAND)
        {
            var item = Items.FirstOrDefault(d => d.ID == wParam);
            if (item != null)
            {
                item.OnClick();
                handled = true;
                return IntPtr.Zero;
            }
        }

        return IntPtr.Zero;
    }

    #region Win32

    private const Int32 WM_SYSCOMMAND = 0x112;
    private const Int32 MF_SEPARATOR = 0x800;
    private const Int32 MF_BYPOSITION = 0x400;
    private const Int32 MF_STRING = 0x0;

    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    private static extern bool InsertMenu(IntPtr hMenu, int wPosition, int wFlags, IntPtr wIDNewItem, string lpNewItem);

    #endregion
}

Example of use:

internal partial class MainWindow : Window
{
    public MainWindow()
    {
        var sysMenu = new SysMenu(this);
        sysMenu.AddSysMenuItem("Quit", miQuit_Click);
        sysMenu.AddSysMenuItem("Show debug tools", miShowDebug_Click);
    }

    private void miQuit_Click()
    {
        // "On-Click" logic here
    }

    private void miShowDebug_Click()
    {
        // "On-Click" logic here
    }
}
Daphene answered 30/9, 2019 at 1:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.