情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

C#でWIN32API step3 タスクトレイアイコンにコンテキストメニューを追加する

step1:ウィンドウの表示

step2:タスクトレイアイコンを表示する

前回のプログラムを改良して、タスクトレイアイコンの右クリック時にコンテキストメニューを表示するようにします。

タスクトレイアイコンに関係する事象が発生するとNOTIFYICONDATA構造体のuCallbackMessageに指定した値のメッセージが飛んできますのでこれを捕捉します。

コンテキストメニューを表示すべき場合にはlParamの下位にWM_CONTEXTMENUが格納されていますので、その場合にコンテキストメニューを表示するようにします。

空のコンテキストメニューはCreatePopupMenu関数を使って生成し、InsertMenuItem関数を使って項目を追加していきます。InsertMenuItem関数にはメニュー項目の設定を格納したMENUITEMINFO構造体を渡します。

作成したコンテキストメニューはTrackPopupMenuEx関数を使って表示します。

最後にDestroyMenuでメニューのリソースを破棄しておきます。

メニュー項目が選択された場合は、WM_COMMANDメッセージが飛んできます。wParamの下位にMENUITEMINFO構造体のwIDで指定した値が格納されています。

注意点としては、コンテキストメニューを作成して表示する前に、SetForegroundWindow関数を使ってキーボード入力がこのウィンドウに送られるようにせねばなりません。これを怠ると、コンテキストメニュー表示時にキーボードによるメニューの操作ができません。しかし、この関数を使うと、ウィンドウが表示されている場合にはそのウィンドウが前面に来てしまいます。この動作が望ましくない場合は、タスクトレイアイコン専用のダミーウィンドウを作成して非表示にしておくと良いでしょう。そのようにすることで、前面にありキーボード入力を受け取るけれども見えないウィンドウを実現できます。

前回のプログラムのWndProcWM_COMMANDとWM_APPを受け取った場合の処理を追加するだけです(前回と同じ部分は省略しました)。

private static IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
    switch (uMsg)
    {
    (省略)

        case WIN32.Window.WM_COMMAND:
            switch ((uint)WIN32.Common.LOWORD(wParam))
            {
                case 0:
                    WIN32.Window.DestroyWindow(hWnd);
                    break;
            }
            break;
        case WIN32.Window.WM_APP:
            switch ((uint)WIN32.Common.LOWORD(lParam))
            {
                case WIN32.Window.WM_CONTEXTMENU:
                    WIN32.Window.SetForegroundWindow(hWnd);

                    IntPtr hMenu = WIN32.Menu.CreatePopupMenu();

                    WIN32.Menu.MENUITEMINFO menuiteminfo = new WIN32.Menu.MENUITEMINFO();
                            menuiteminfo.cbSize = (uint)Marshal.SizeOf(menuiteminfo);
                            menuiteminfo.fMask = WIN32.Menu.MIIM.MIIM_STRING | WIN32.Menu.MIIM.MIIM_ID;
                            menuiteminfo.wID = 0;
                            menuiteminfo.dwTypeData = "終了";
                            menuiteminfo.cch = (uint)menuiteminfo.dwTypeData.Length;

                    WIN32.Menu.InsertMenuItem(hMenu, 0, true, ref menuiteminfo);

                    WIN32.Menu.TrackPopupMenuEx(hMenu, WIN32.Menu.TPM.TPM_LEFTALIGN, WIN32.Common.LOWORD(wParam), WIN32.Common.HIWORD(wParam), hWnd, IntPtr.Zero);
                    WIN32.Menu.DestroyMenu(hMenu);

                    break;
            }
            break;
        default:
            return WIN32.Window.DefWindowProc(hWnd, uMsg, wParam, lParam);
    }

    return IntPtr.Zero;
}

こちらが、P/I用のコードです(前回からの追加部分)。

using System;

namespace Anttn.WIN32
{
    public static class Common
    {
        public static int LOWORD(IntPtr dwValue)
        {
            return (dwValue.ToInt32() & 0xFFFF);
        }

        public static int HIWORD(IntPtr dwValue)
        {
            return (dwValue.ToInt32() >> 16) & 0xFFFF;
        }
    }
}
using System;
using System.Runtime.InteropServices;

namespace Anttn.WIN32
{
    public static partial class Window
    {
    (省略)

        [DllImport("user32.dll")]
        public static extern bool DestroyWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

    (省略)

        public const uint WM_CONTEXTMENU = 0x007B;
        public const uint WM_COMMAND = 0x0111;
        public const uint WM_APP = 0x8000;
    }
}
using System;
using System.Runtime.InteropServices;

namespace Anttn.WIN32
{
    public static partial class Menu
    {
        [DllImport("user32.dll")]
        public static extern IntPtr CreatePopupMenu();

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

        [DllImport("user32.dll")]
        public static extern bool TrackPopupMenuEx(IntPtr hmenu, TPM fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);

        [DllImport("user32.dll")]
        public static extern bool DestroyMenu(IntPtr hMenu);

        [StructLayout(LayoutKind.Sequential)]
        public struct MENUITEMINFO
        {
            public uint cbSize;
            public MIIM fMask;
            public MFT fType;
            public MFS 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;
        }

        [Flags]
        public enum MIIM : uint
        {
            MIIM_STATE = 0x00000001,
            MIIM_ID = 0x00000002,
            MIIM_SUBMENU = 0x00000004,
            MIIM_CHECKMARKS = 0x00000008,
            MIIM_TYPE = 0x00000010,
            MIIM_DATA = 0x00000020,
            MIIM_STRING = 0x00000040,
            MIIM_BITMAP = 0x00000080,
            MIIM_FTYPE = 0x00000100,
        }

        [Flags]
        public enum MFT : uint
        {
            MFT_STRING = 0x00000000,
            MFT_BITMAP = 0x00000004,
            MFT_MENUBARBREAK = 0x00000020,
            MFT_MENUBREAK = 0x00000040,
            MFT_OWNERDRAW = 0x00000100,
            MFT_RADIOCHECK = 0x00000200,
            MFT_SEPARATOR = 0x00000800,
            MFT_RIGHTORDER = 0x00002000,
            MFT_RIGHTJUSTIFY = 0x00004000,
        }

        [Flags]
        public enum MFS : uint
        {
            MFS_GRAYED = 0x00000003,
            MFS_DISABLED = 0x00000003,
            MFS_CHECKED = 0x00000008,
            MFS_HILITE = 0x00000080,
            MFS_ENABLED = 0x00000000,
            MFS_UNCHECKED = 0x00000000,
            MFS_UNHILITE = 0x00000000,
            MFS_DEFAULT = 0x00001000,
        }

        [Flags]
        public enum TPM : uint
        {
            TPM_LEFTBUTTON = 0x00000000,
            TPM_RECURSE = 0x00000001,
            TPM_RIGHTBUTTON = 0x00000002,
            TPM_LEFTALIGN = 0x00000000,
            TPM_CENTERALIGN = 0x00000004,
            TPM_RIGHTALIGN = 0x00000008,
            TPM_TOPALIGN = 0x00000000,
            TPM_VCENTERALIGN = 0x00000010,
            TPM_BOTTOMALIGN = 0x00000020,
            TPM_HORIZONTAL = 0x00000000,
            TPM_VERTICAL = 0x00000040,
            TPM_NONOTIFY = 0x00000080,
            TPM_RETURNCMD = 0x00000100,
            TPM_HORPOSANIMATION = 0x00000400,
            TPM_HORNEGANIMATION = 0x00000800,
            TPM_VERPOSANIMATION = 0x00001000,
            TPM_VERNEGANIMATION = 0x00002000,
            TPM_NOANIMATION = 0x00004000,
            TPM_LAYOUTRTL = 0x00008000,
            TPM_WORKAREA = 0x00010000,
        }
    }
}
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-C#, WIN32API