日記 Visual Studio 2019 C++でタスクトレイに常駐するアプリケーションを作成

## 日記

初心者が悪い事をする常駐アプリケーションを作るまでのメモ。
[次の日記「日記 Visual Studio 2019 C++でフォアグラウンドのexeのフルパスとウインドウタイトルの取得」](https://qiita.com/Yamine1San/items/c841995efa184a6b924e)

## 要件

* 最小化時と閉じる時
    * タスクトレイにアイコン表示
    * タスクバーから消す(Alt+Tabで出てこないように)
* タスクトレイのアイコンをダブルクリック時
    * タスクトレイからアイコン削除
    * タスクバーに表示
    * ウインドウ表示

## 手順

### 新規プロジェクトの作成

新しいプロジェクトから「Windowsデスクトップアプリケーション」を選択して作成

### includeとdefineとグローバル変数追加

NOTIFYICONDATA、Shell_NotifyIconの定義の読み込み定義を追加

```Sample.cpp
#include "shellapi.h"

// タスクトレイのアイコンに対してクリックなどをすると実行されるメッセージ定数追加
#define WM_TASKTRAY (WM_APP + 1)

// グローバル変数
HICON hIcon;
```

### 初期化時にグローバル変数のhIconにアイコンセット

```Sample.cpp
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。

    // インスタンスに関連付いたアイコン読み込み
    //  (AddSystemTrayIcon()で使用するため)
    hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLE));

```


### タスクトレイにアイコンを追加、削除する関数追加

```Sample.cpp
void AddSystemTrayIcon(HWND hWnd)
{
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.uFlags = (NIF_ICON | NIF_MESSAGE | NIF_TIP);
    nid.hWnd = hWnd;
    nid.hIcon = hIcon;
    nid.uCallbackMessage = WM_TASKTRAY;
    lstrcpy(nid.szTip, TEXT("アイコンマウスオーバー時の表示テキスト"));
    Shell_NotifyIcon(NIM_ADD, &nid);
}

void DellSystemTrayIcon(HWND hWnd)
{
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hWnd;
    Shell_NotifyIcon(NIM_DELETE, &nid);
}
```


### メッセージを処理するWndProcに追加

上から

* タスクトレイのアイコンをダブルクリックした時
    * タスクトレイからアイコンを削除
    * タスクバーのアプリのアイコンを表示
    * アプリを通常表示
* アプリケーション最小化時
    * タスクトレイにアイコンを追加
    * タスクバーのアプリのアイコンを非表示
* アプリケーション閉じる時
    * タスクトレイにアイコンを追加
    * タスクバーのアプリのアイコンを非表示
* アプリケーションを破棄する時
    * タスクトレイからアイコンを削除

```Sample.cpp
//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND  - アプリケーション メニューの処理
//  WM_PAINT    - メイン ウィンドウを描画する
//  WM_DESTROY  - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
        // ウインドウサイズ変更時の処理
        case WM_SIZE:
        {
            int wmId = LOWORD(wParam);
            switch (wmId)
            {
                // 最小化した時
                case SIZE_MINIMIZED:
                {
                    // タスクトレイにアイコンを追加
                    AddSystemTrayIcon(hWnd);

                    // タスクバー内のアプリアイコンを非表示
                    ShowWindow(FindWindow(TEXT("アプリの名前"), NULL), SW_HIDE);
                }
                break;
            }
        }
        break;
        // タスクトレイのアイコンに対する処理
        case WM_TASKTRAY:
        {

            switch (lParam)
            {
                // 左ダブルクリック
                case WM_LBUTTONDBLCLK:
                {
                    // タスクトレイからアイコンを削除
                    DellSystemTrayIcon(hWnd);

                    // タスクバー内のアプリアイコンを表示
                    ShowWindow(FindWindow(TEXT("アプリの名前"), NULL), SW_SHOW);

                    // アプリの表示
                    ShowWindow(hWnd, SHOW_OPENWINDOW);
                }
                break;
                // 右クリック
                case WM_RBUTTONDOWN:
                {
                    //略
                }
                break;
            }
        }
        break;
        case WM_COMMAND:
        {
            //略
        }
        break;
        case WM_PAINT:
        {
            //略
        }
        break;
        case WM_CLOSE:
        {
            // タスクトレイにアイコンを追加
            AddSystemTrayIcon(hWnd);

            // タスクバー内のアプリアイコンを非表示
            ShowWindow(FindWindow(TEXT("アプリの名前"), NULL), SW_HIDE);
        }
        break;
        case WM_DESTROY:
        {
            // タスクトレイからアイコンを削除
            DellSystemTrayIcon(hWnd);

            PostQuitMessage(0);
        }
        break;
        default:
        {
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    return 0;
}
```

### 最小化で起動させるためInitInstanceの変更

SW_SHOWMINNOACTIVEで最小化起動

```Sample.cpp
//ShowWindow(hWnd, nCmdShow);
ShowWindow(hWnd, SW_SHOWMINNOACTIVE);
```