Web検索はbingがおすすめ!

システムメニューにメニューを追加する - C#

システムメニューにメニューを追加するコードを紹介します。

システムメニュー

ウィンドウの左上をクリックすると表示されるメニューがシステムメニューです。

UI

下図のUIを作成します。

コード

以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TaskBarMenu
{

  public partial class FormMain : Form
  {
    [StructLayout(LayoutKind.Sequential)]
    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;

      // return the size of the structure
      public static uint sizeOf
      {
        get { return (uint)Marshal.SizeOf(typeof(MENUITEMINFO)); }
      }
    }

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

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

    private const uint MENU_ID_01 = 0x0001;
    private const uint MENU_ID_02 = 0x0002;

    private const uint MFT_BITMAP = 0x00000004;
    private const uint MFT_MENUBARBREAK = 0x00000020;
    private const uint MFT_MENUBREAK = 0x00000040;
    private const uint MFT_OWNERDRAW = 0x00000100;
    private const uint MFT_RADIOCHECK = 0x00000200;
    private const uint MFT_RIGHTJUSTIFY = 0x00004000;
    private const uint MFT_RIGHTORDER = 0x000002000;

    private const uint MFT_SEPARATOR = 0x00000800;
    private const uint MFT_STRING = 0x00000000;

    private const uint MIIM_FTYPE = 0x00000100;
    private const uint MIIM_STRING = 0x00000040;
    private const uint MIIM_ID = 0x00000002;

    private const uint WM_SYSCOMMAND = 0x0112;

    public FormMain()
    {
      InitializeComponent();

      IntPtr hSysMenu = GetSystemMenu(this.Handle, false);

      MENUITEMINFO item1 = new MENUITEMINFO();
      item1.cbSize = (uint)Marshal.SizeOf(item1);
      item1.fMask = MIIM_FTYPE;
      item1.fType = MFT_SEPARATOR;
      InsertMenuItem(hSysMenu, 5, true, ref item1);

      MENUITEMINFO item2 = new MENUITEMINFO();
      item2.cbSize = (uint)Marshal.SizeOf(item2);
      item2.fMask = MIIM_STRING | MIIM_ID;
      item2.wID = MENU_ID_01;
      item2.dwTypeData = "てすと1";
      InsertMenuItem(hSysMenu, 6, true, ref item2);

      MENUITEMINFO item3 = new MENUITEMINFO();
      item3.cbSize = (uint)Marshal.SizeOf(item2);
      item3.fMask = MIIM_STRING | MIIM_ID;
      item3.wID = MENU_ID_02;
      item3.dwTypeData = "てすと2";
      InsertMenuItem(hSysMenu, 6, true, ref item3);
    
    }

    protected override void WndProc(ref Message m)
    {
      base.WndProc(ref m);
      if (m.Msg == WM_SYSCOMMAND){
        uint menuid = (uint)(m.WParam.ToInt32() & 0xffff);

        switch (menuid) {
          case MENU_ID_01:
            MessageBox.Show("てすと1が選択されました。");
            break;
          case MENU_ID_02:
            MessageBox.Show("てすと2が選択されました。");
            break;

        }
      }
    } 
  }
}

解説

IntPtr hSysMenu = GetSystemMenu(this.Handle, false);
にてウィンドウのシステムメニューを取得します。

MENUITEMINFO item1 = new MENUITEMINFO();
item1.cbSize = (uint)Marshal.SizeOf(item1);
item1.fMask = MIIM_FTYPE;
item1.fType = MFT_SEPARATOR;
InsertMenuItem(hSysMenu, 5, true, ref item1);
では、セパレーターのメニュー要素を設定します。メニュー要素はMENUITEMINFO構造体に値を設定します。cbSizeには構造体のサイズをfMaskにはこの構造体で設定するメンバを指定します。今回はfTypeを指定するのみですので、MIIM_FTYPEを指定しています。fTypeはメニューのタイプになります。MFT_SEPARATORを設定しているため、セパレーターとなります。構造体の設定ができたのちInsertMenuItemを呼び出しシステムメニューにメニュー要素を追加します。

MENUITEMINFO item2 = new MENUITEMINFO();
item2.cbSize = (uint)Marshal.SizeOf(item2);
item2.fMask = MIIM_STRING | MIIM_ID;
item2.wID = MENU_ID_01;
item2.dwTypeData = "てすと1";
InsertMenuItem(hSysMenu, 6, true, ref item2);

MENUITEMINFO item3 = new MENUITEMINFO();
item3.cbSize = (uint)Marshal.SizeOf(item2);
item3.fMask = MIIM_STRING | MIIM_ID;
item3.wID = MENU_ID_02;
item3.dwTypeData = "てすと2";
InsertMenuItem(hSysMenu, 6, true, ref item3);
では、メニュー要素を作成して追加します。wIDとdwTypeDataを設定するため、fMaskには"MIIM_STRING | MIIM_ID"を指定します。wIDはメニュー要素を識別するためのIDを指定します。dwTypeData にはメニューに表示されるキャプションを設定します。MENUITEMINFO 構造体を設定した後InsertMenuItem でシステムメニューにメニュー要素を追加します。

protected override void WndProc(ref Message m)
{
  base.WndProc(ref m);
  if (m.Msg == WM_SYSCOMMAND){
    uint menuid = (uint)(m.WParam.ToInt32() & 0xffff);

    switch (menuid) {
      case MENU_ID_01:
        MessageBox.Show("てすと1が選択されました。");
        break;
      case MENU_ID_02:
        MessageBox.Show("てすと2が選択されました。");
        break;
      }
    }
  } 
}
システムメニューがクリックされるとWM_SYSCOMMANDウィンドウメッセージがウィンドウに送信されます。WndProcメソッドをオーバーライドしてウィンドウメッセージを取得します。ウィンドウメッセージがWM_SYSCOMMANDならば、wParamの下位16ビットを取得し、どのメニューアイテムがクリックされたかを判別します。

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


ウィンドウ左上をクリックします。システムメニューが表示されます。システムメニューに[てすと1]、[てすと2]のメニュー項目が追加されています。


[てすと1]メニューをクリックします。下図のメッセージボックスが表示され、メニュー要素に対するクリックに応答できていることがわかります。


[てすと2]のメニューを選択した場合は下図の画面となります。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2012-08-24
iPentec all rights reserverd.