情報アイランド

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

C#でWIN32API step6 タスクトレイアイコンにフライアウトウィンドウを追加する(その2)

step1:ウィンドウの表示

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

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

step4:タスクトレイアイコンにバルーンチップを表示する

step5:タスクトレイアイコンにフライアウトウィンドウを追加する(その1)

前回作成したフライアウトウィンドウは標準的なフライアウトウィンドウとは少し動作が異なります。

普通は一度タスクトレイアイコンをクリックしてウィンドウを表示した後、もう一度タスクトレイアイコンをクリックするとウィンドウが閉じます。前回作成したフライアウトは何度クリックしても表示されたままです(実際は一度閉じてから再表示しています)。

今回はこの動作を変更し、クリックする毎に表示/非表示が切り替わるように改良します。上手く動作させるためにはタイマーによる制御が必要になります。

まず、三個のグローバル変数を宣言します。上からそれぞれメインウィンドウのハンドル、フライアウトウィンドウのハンドル、フライアウトを表示できるかどうかを表すフラグです。

private static IntPtr hwnd = IntPtr.Zero;
private static IntPtr hflyoutwnd = IntPtr.Zero;
private static bool canshowflyout = true;

次に、メインウィンドウの作成部分でウィンドウハンドルをグローバル変数に代入するように変更します。

IntPtr hWnd = hwnd = WIN32.Window.CreateWindowEx(0, wndclassex.lpszClassName, "∀In++n", WIN32.Window.WS.WS_OVERLAPPEDWINDOW, WIN32.Window.CW_USEDEFAULT, WIN32.Window.CW_USEDEFAULT, 800, 600, IntPtr.Zero, IntPtr.Zero, wndclassex.hInstance, IntPtr.Zero);

前回のプログラムのFlyoutWndProcWM_ACTIVATEメッセージを受け取った時にタイマーを作成する処理を追加します。また、グローバル変数を適切に設定します。

private static IntPtr FlyoutWndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
    switch (uMsg)
    {
        case WIN32.Window.WM_ACTIVATE:
            if (WIN32.Common.LOWORD(wParam) == WIN32.Window.WA_INACTIVE)
            {
                WIN32.Window.DestroyWindow(hWnd);

                WIN32.Common.SetTimer(hwnd, 0, WIN32.Common.GetDoubleClickTime(), null);

                hflyoutwnd = IntPtr.Zero;
                canshowflyout = false;
            }
            break;
        default:
            return WIN32.Window.DefWindowProc(hWnd, uMsg, wParam, lParam);
    }

    return IntPtr.Zero;
}

以下のように、前回のプログラムのWndProcWM_TIMERを受け取った場合のコードを追加し、WM_APPNIN_SELECTを受け取った場合のコードを変更します。

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

        case WIN32.Window.WM_TIMER:
            if (wParam.ToInt32() == 0)
            {
                WIN32.Common.KillTimer(hWnd, 0);

                canshowflyout = true;
            }
            break;
        case WIN32.Window.WM_APP:
            switch ((uint)WIN32.Common.LOWORD(lParam))
            {
        (省略)

                case WIN32.NotifyIcon.NIN_SELECT:
                    if (WIN32.Window.IsWindowVisible(hflyoutwnd))
                    {
                        WIN32.Window.DestroyWindow(hWnd);

                        WIN32.Common.SetTimer(hwnd, 0, WIN32.Common.GetDoubleClickTime(), null);

                        hflyoutwnd = IntPtr.Zero;
                        canshowflyout = false;
                    }
                    else if (canshowflyout)
                    {
                        WIN32.Window.RECT rectWindow = new WIN32.Window.RECT();
                        rectWindow.left = 0;
                        rectWindow.top = 0;
                        rectWindow.right = 256;
                        rectWindow.bottom = 256;
                        WIN32.Window.AdjustWindowRectEx(ref rectWindow, WIN32.Window.WS.WS_POPUP | WIN32.Window.WS.WS_THICKFRAME, false, WIN32.Window.WS_EX.WS_EX_TOOLWINDOW);

                        WIN32.Window.RECT rectNotifyIcon = new WIN32.Window.RECT();
                        WIN32.NotifyIcon.NOTIFYICONIDENTIFIER notifyiconidentifier = new WIN32.NotifyIcon.NOTIFYICONIDENTIFIER();
                        notifyiconidentifier.cbSize = (uint)Marshal.SizeOf(notifyiconidentifier);
                        notifyiconidentifier.hWnd = hWnd;
                        notifyiconidentifier.uID = 0;
                        WIN32.NotifyIcon.Shell_NotifyIconGetRect(ref notifyiconidentifier, out rectNotifyIcon);

                        WIN32.Window.POINT point = new WIN32.Window.POINT();
                        point.x = (rectNotifyIcon.left + rectNotifyIcon.right) / 2;
                        point.y = (rectNotifyIcon.top + rectNotifyIcon.bottom) / 2;

                        WIN32.Window.SIZE size = new WIN32.Window.SIZE();
                        size.cx = rectWindow.right - rectWindow.left;
                        size.cy = rectWindow.bottom - rectWindow.top;

                        WIN32.Window.CalculatePopupWindowPosition(ref point, ref size, WIN32.Menu.TPM.TPM_CENTERALIGN | WIN32.Menu.TPM.TPM_VCENTERALIGN | WIN32.Menu.TPM.TPM_VERTICAL | WIN32.Menu.TPM.TPM_WORKAREA, ref rectNotifyIcon, out rectWindow);

                        IntPtr hFlyoutWnd = hflyoutwnd = WIN32.Window.CreateWindowEx(WIN32.Window.WS_EX.WS_EX_TOOLWINDOW, "anttnFlyout", null, WIN32.Window.WS.WS_POPUP | WIN32.Window.WS.WS_THICKFRAME, rectWindow.left, rectWindow.top, rectWindow.right - rectWindow.left, rectWindow.bottom - rectWindow.top, IntPtr.Zero, IntPtr.Zero, hinstance, IntPtr.Zero);

                        WIN32.Window.ShowWindow(hFlyoutWnd, WIN32.Window.SW.SW_SHOW);
                        WIN32.Window.UpdateWindow(hFlyoutWnd);
                        WIN32.Window.SetForegroundWindow(hFlyoutWnd);
                    }

                    break;

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

    return IntPtr.Zero;
}

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

using System;
using System.Runtime.InteropServices;

namespace Anttn.WIN32
{
    public static class Common
    {
        [DllImport("user32.dll")]
        public static extern uint GetDoubleClickTime();

        [DllImport("user32.dll")]
        public static extern uint SetTimer(IntPtr hWnd, uint nIDEvent, uint uElapse, TimerProc lpTimerFunc);

        [DllImport("user32.dll")]
        public static extern bool KillTimer(IntPtr hWnd, uint uIDEvent);

        public delegate void TimerProc(IntPtr hWnd, uint uMsg, uint nIDEvent, uint dwTime);

    (省略)
    }
}
using System;
using System.Runtime.InteropServices;

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

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

    (省略)

        public const uint WM_TIMER = 0x0113;

    (省略)
    }
}
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-C#, WIN32API