カテゴリー
C++

Windows アプリケーション タスクトレイ表示

Windows アプリケーションのメインウィンドウを表示しないで、タスクトレイ(下記画像)へアイコンとして表示しておいて、マウスでクリックしたら何か表示して、処理をするというのをやってみたいと思います。
(※呼び方がタスクトレイで良いのかわかりませんが、タスクバーの通知領域またはシステムトレイとも言われるようです。)

タスクトレイ アイコン
タスクトレイ アイコン

手順として:
1.Visual Studio で Windows ダイアログ アプリケーションを作ります
2.起動時にアイコンをタスクトレイへ表示します。
3.メインウィンドウを非表示にします。
4.タスクトレイのアイコンがクリックされたらメインウィンドウを表示します。
5.終了時にアイコンをタスクトレイから削除

といった感じで作成します。 なお、1については割愛します。

起動時にアイコンをタスクトレイへ表示

アイコンをタスクトレイへ表示するには、Shell_NotifyIcon API で簡単にできます。パラメータは「追加」、「変更」、「削除」があり、ウィンドウの作成時に追加して、クローズ時に削除すればよいです。

Shell_NotifyIcon を使うために便利な関数を自分のメインウィンドウのクラスに用意してみました。(下記参照)
アイコンなどのリソースはあらかじめ作成しておきます。ここでは、 IDR_TRAYICON というアイコンがある前提です。

MYWM_TRAYNOTIFY というメッセージID を nid.uCallbackMessage に設定してます。これは WM_USER + 1 で定義したユーザー定義メッセージで、タスクトレイのアイコンがクリックされたらメインウィンドウに通知されてきます。

... (省略) ...

#define MYWM_TRAYNOTIFY        WM_USER + 1

... (省略) ...

//
// TrayNotifyIconMessage
//
// dwMessage:
//        NIM_ADD
//        NIM_MODIFY
//        NIM_DELETE
//
BOOL CMyDialog::TrayNotifyIconMessage(DWORD dwMessage)
{
    CString sTip = _T("ポイントされたら表示するテキストを指定します");
    NOTIFYICONDATA nid;

    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd   = GetSafeHwnd();
    nid.uID    = IDR_TRAYICON;        // <-- アイコンIDを指定してます
    nid.uFlags = NIF_MESSAGE | NIF_ICON;
    nid.uCallbackMessage = MYWM_TRAYNOTIFY;    // <-- WM_USER + 1 とかでメッセージ定義
    nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    nid.hIcon  = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TRAYICON));
    _tcscpy_s(nid.szTip, _countof(nid.szTip), (LPCTSTR)sTip);
    
    return Shell_NotifyIcon(dwMessage, &nid);
}

起動時にアイコンをタスクトレイへ追加します。ダイアログアプリケーションでは OnInitDialog 内で上記の TrayNotifyIconMessage を NIM_ADD をパラメータで指定するだけです。これで、起動時にタスクトレイにアイコンが表示されます。

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

... (省略) ...

    // タスクトレイへアイコンを追加
    TrayNotifyIconMessage(NIM_ADD);    

    return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
}

メインウィンドウを非表示にする

アプリケーション最小化時にタスクトレイに表示させて、タスクバーには表示されないようにするようなので、それを実現するために、メインウィンドウを最小化時に非表示にします。(もちろん、起動時に非表示にしてしまうこともできますが。。。)

WM_SIZE のメッセージハンドラ OnSize 内でパラメータの nType が SIZE_MINIMIZED だった時に ShowWIndow で非表示にします。

void CMyDialog::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);

    if (nType == SIZE_MINIMIZED)
    {
        ShowWindow(SW_HIDE);
    }
}

このままだと、二度とメインウィンドウが表示されることがないので、タスクトレイのアイコンがダブルクリックされたらメインウィンドウを再表示するようにします。

タスクトレイのアイコンがクリックされたらメインウィンドウを表示

まずは、最初に定義済みの MYWM_TRAYNOTIFY というユーザー定義メッセージをハンドルする OnTrayNotify 関数を用意します。

パラメータの lParam にイベントの種類が入ってきますので、ダブルクリックされたのを判定する WM_LBUTTONDBLCLK と自アプリケーションのアイコンかを判定し、処理を行います。

ここでは、メインウィンドウを表示してフォアグラウンドに持ってきます。

... (省略) ...

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_WM_SIZE()
    ON_WM_CLOSE()
    ON_MESSAGE(MYWM_TRAYNOTIFY, OnTrayNotify)
END_MESSAGE_MAP()

... (省略) ...

LRESULT CMyDialog::OnTrayNotify(WPARAM wParam, LPARAM lParam)
{
    switch (lParam)
    {
    case WM_LBUTTONDBLCLK: 
        if (wParam == IDR_TRAYICON)
        {
            ShowWindow(SW_NORMAL);
            SetForegroundWindow();
            SetFocus();
        } 
        break;

    default:
        break;
    } 

    return 0;
}

終了時の処理

そして、最後にメインアプリケーションがクローズされるときに、タスクトレイのアイコンを削除します。

void CMyDialog::OnClose()
{
    // タスクトレイからアイコンを削除
    TrayNotifyIconMessage(NIM_DELETE);    

    CDialog::OnClose();
}

以上です。

あとは、必要に応じて、ポップアップメニューを表示したりする処理を OnTrayNotify 内に追加するなど応用できます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください