potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C# 9&Win API システムメニューを表示する

システムメニューを表示するサンプルコードです。

#nullable enable

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

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

sealed class Form1 : Form
{
    public Form1() : base()
    {
        Controls.AddRange(new[] {
            new Label(){
                Text="右クリックでシステムメニューが表示されます。",
                AutoSize=true
            }
        });
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            this.ShowSystemMenu(Cursor.Position);
        }
        else
        {
            base.OnMouseUp(e);
        }
    }
}

public static class FormSystemMenuExtensions
{
    /// <summary>
    /// ウィンドウのシステムメニューを表示します。
    /// </summary>
    /// <param name="form">システムメニューを表示するフォーム。</param>
    /// <param name="location">システムメニューを表示する画面上の位置。</param>
    /// <param name="flags">フラグ。</param>
    /// <returns></returns>
    public static int ShowSystemMenu(this Form form, Point location, TrackPopupMenuFlags flags = 0)
    {
        const uint TPM_RETURNCMD = 0x0100;
        const int WM_SYSCOMMAND = 0x0112;

        var sysMenuHandle = NativeMethods.GetSystemMenu(form.Handle, false);
        var id = NativeMethods.TrackPopupMenu(sysMenuHandle,
            (uint)flags | TPM_RETURNCMD, location.X, location.Y, 0, form.Handle);
        NativeMethods.SendMessage(form.Handle, WM_SYSCOMMAND, id, 0);
        return id;
    }

    private static class NativeMethods
    {
        [DllImport("user32.dll")]
        public static extern nint SendMessage(IntPtr hwnd, int msg, nint wParam, nint lParam);

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

        [DllImport("user32.dll")]
        public static extern int TrackPopupMenu(
            IntPtr hMenu,
            uint uFlags,
            int x,
            int y,
            int nReserved,
            IntPtr hWnd,
            IntPtr prcRect = default);
    }

    public enum TrackPopupMenuFlags : uint
    {
        LButton = 0x0000,
        RButton = 0x0002,
        Leftn = 0x0000,
        Center = 0x0004,
        Right = 0x0008,
        Top = 0x0000,
        Middle = 0x0010,
        Bottom = 0x0020,

        Hozirontal = 0x0000,
        Vertical = 0x0040,
        NoNotify = 0x0080,
        //TPM_RETURNCMD = 0x0100,
        Recurse = 0x0001,
        AnimationLR = 0x0400,
        AnimationRL = 0x0800,
        AnimationTB = 0x1000,
        AnimationBT = 0x2000,
        NoAnimation = 0x4000,
        LayoutRTL = 0x8000,
        WorkArea = 0x10000,
    }
}