Adding a custom context menu item to Windows Form

2019-01-31 15:29发布

I found a thread on MSDN that shows how to add an item to the context menu of a winform title bar. Unfortunately it does not show how to register an event with the custom menu item and I have been unable to figure out how to do it. Below is a sample app that can be copied and pasted into a new Windows Forms Application. I would appreciate it if someone could complete the sample for me. Thanks

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            IntPtr hMenu = GetSystemMenu(Handle, false);
            if (hMenu != IntPtr.Zero)
            {
                var menuInfo = new MENUITEMINFO
                   {
                       cbSize = (uint) Marshal.SizeOf(typeof (MENUITEMINFO)),
                       cch = 255,
                       dwTypeData = "Test Item",
                       fMask = 0x1 | 0x2 | 0x10,
                       fState = 0,
                       fType = 0x0
                   };

                InsertMenuItem(hMenu, 0, true, ref menuInfo);
                DrawMenuBar(Handle);
            }
        }

        [DllImport("user32.dll")] 
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
        [DllImport("user32.dll")] 
        static extern bool DrawMenuBar(IntPtr hWnd);
        [DllImport("user32.dll")] 
        static extern bool InsertMenuItem(IntPtr hMenu, uint uItem, 
                          bool fByPosition, [In] ref MENUITEMINFO lpmii);


        [StructLayout(LayoutKind.Sequential)]
        public struct MENUITEMINFO
        {
            public uint cbSize;
            public uint fMask;
            public uint fType;
            public uint fState;
            public uint wID;
            public IntPtr hSubMenu;
            public IntPtr hbmpChecked;
            public IntPtr hbmpUnchecked;
            public IntPtr dwItemData;
            public string dwTypeData;
            public uint cch;
            public IntPtr hbmpItem;
        }
    }
}

3条回答
Evening l夕情丶
2楼-- · 2019-01-31 15:49

You must override WndProc Method and intercept the id of your new menu.

try this

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication11
{
  public partial class Form1 : Form
  {
    public const Int32 WM_SYSCOMMAND = 0x112;
    public const Int32 MF_BYPOSITION = 0x400;
    public const Int32 MYMENU1 = 1000;
    public const Int32 MUMENU2 = 1001;

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

    public Form1()
    {
      InitializeComponent();
    }

    protected override void WndProc(ref Message msg)
    {
      if (msg.Msg == WM_SYSCOMMAND)
      {
        switch (msg.WParam.ToInt32())
        {
          case MYMENU1:
            MessageBox.Show("Hi from My Menu 1¡¡¡¡");
            return;
          case MUMENU2:
            MessageBox.Show("Hi from My Menu 2¡¡¡¡");
            return;
          default:
            break;
        }
      }
      base.WndProc(ref msg);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      IntPtr MenuHandle = GetSystemMenu(this.Handle, false);
      InsertMenu(MenuHandle, 5, MF_BYPOSITION, MYMENU1, "My Menu 1");
      InsertMenu(MenuHandle, 6, MF_BYPOSITION, MUMENU2, "My Menu 2");
    }
  }
}
查看更多
再贱就再见
3楼-- · 2019-01-31 15:49

For a separator just add:

public const Int32 MF_SEPARATOR = 0x800;

and in Form_load:

InsertMenu(MenuHandle, 7, MF_BYPOSITION | MF_SEPARATOR, 0, string.Empty); // <-- Add a menu seperator
查看更多
该账号已被封号
4楼-- · 2019-01-31 16:07

I went ahead and just added the necessary elements to the sample code to register the WndProc. This answers the basic question of registering the WndProc without altering the code as much as the previous solution. (It keeps the added menu on top of the system menu).

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
            public Form1()
    {
        InitializeComponent();

        IntPtr hMenu = GetSystemMenu(Handle, false);
        if (hMenu != IntPtr.Zero)
        {
            var menuInfo = new MENUITEMINFO
            {
                cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO)),
                cch = 255,
                dwTypeData = "Test Item",
                fMask = 0x1 | 0x2 | 0x10,
                fState = 0,
                // Add an ID for your Menu Item
                wID = 0x1,  
                fType = 0x0
            };

            InsertMenuItem(hMenu, 0, true, ref menuInfo);
            DrawMenuBar(Handle);
        }
    }

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
    [DllImport("user32.dll")]
    static extern bool DrawMenuBar(IntPtr hWnd);
    [DllImport("user32.dll")]
    static extern bool InsertMenuItem(IntPtr hMenu, uint uItem,
                      bool fByPosition, [In] ref MENUITEMINFO lpmii);


    [StructLayout(LayoutKind.Sequential)]
    public struct MENUITEMINFO
    {
        public uint cbSize;
        public uint fMask;
        public uint fType;
        public uint fState;
        public uint wID;
        public IntPtr hSubMenu;
        public IntPtr hbmpChecked;
        public IntPtr hbmpUnchecked;
        public IntPtr dwItemData;
        public string dwTypeData;
        public uint cch;
        public IntPtr hbmpItem;
    }

    // Add ID for the Menu
    private const int WM_SYSCOMMAND = 0x112; 
    // Event method for the Menu
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
                                            //m.WParam = the wID you gave the Menu Item
        if ((m.Msg == WM_SYSCOMMAND) && ((int)m.WParam == 0x1))
        {
            MessageBox.Show("Test Item Dialog");
        }

    }
}

}

查看更多
登录 后发表回答