システムメニューにメニューを追加する
システムメニューにメニューを追加するコードを紹介します。
システムメニュー
ウィンドウの左上をクリックすると表示されるメニューがシステムメニューです。
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を愛用