Question

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;
        }
    }
}
Was it helpful?

Solution

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");
    }
  }
}

OTHER TIPS

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

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");
        }

    }
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top