タスクトレイ に常駐する アプリケーション を作成するには

解説

タスクトレイ (デスクトップ画面の下などに表示されているタスクバーの右端などの時刻表示といくつかの常駐アプリケーションアイコンがあるところ) に常駐するアプリケーションを作成する方法をまとめます。

タスクトレイに常駐するアプリケーションを作成するには、アプリケーションのメインウィンドウとして登録するウィンドウの、ウィンドウクラスに、以下の処理を用意します。

  1. タスクバーに表示されない、かつ、見えない、ウィンドウを作成する処理。
  2. ウィンドウ破棄時に、ウィンドウクラスオブジェクト自身が自分自身を削除する処理。
  3. タスクトレイに対して、アイコン(、ツールチップ文字列、コールバックメッセージコード)を登録/変更/削除する処理。
  4. タスクトレイのアイコンに対するイベントの応答処理
  5. ウィンドウ作成時に、「タスクトレイに対して、アイコンを登録する処理」を呼び出す処理。
  6. ウィンドウ破棄時に、「タスクトレイに対して、アイコンを削除する処理」を呼び出す処理。

サンプルコード

プロジェクトの作成

「メニュー/新規作成/プロジェクト」を選択します。

プロジェクトの種類:MFC
テンプレート:MFC アプリケーション
プロジェクト名:適当な名前(今回は「MyApplication」)
場所:適当なフォルダを指定
ソリューションのディレクトリの作成:チェックしない
でOKボタンを押します。



次へボタンを押します。


アプリケーションの種類:ダイアログベース
MFCの使用:共有DLLでMFCを使用
リソース言語:日本語
ユニコードライブラリを使用する:チェックする
で次へボタンを押します。


設定を変更せず次へボタンを押します。


設定を変更せず次へボタンを押します。


設定を変更せず完了ボタンを押します。

ビルドし、エラー、警告がないことを確認します。

アプリケーションのメインウィンドウとして登録するウィンドウの、ウィンドウクラスの追加

タスクトレイに常駐するアプリケーションに共通の処理を有する規定ウィンドウクラスと、アプリケーション固有の処理を有する派生ウィンドウクラスの2つのクラスを作成します。規定ウィンドウクラスの名前を、CTrayWnd、派生ウィンドウクラスの名前を、CMyApplicationTrayWnd とします。

まず、CTrayWndクラスを追加します。
「メニュー/プロジェクト/クラスの追加」を選択します。


カテゴリ:MFC
テンプレート:MFC クラス
追加ボタンを押します。


クラス名:CTrayWnd
基本クラス:CWnd
(それ他の設定は自動入力に任せます)

「完了」ボタンを押します。

ビルドし、エラー、警告がないことを確認します。

タスクバーに表示されない、かつ、見えない、ウィンドウを作成する処理。

追加した CTrayWndクラス に、ウインドウ作成関数を追加します。
タスクバーに表示されないウィンドウを作成するために、CreateEx関数を利用し、拡張ウィンドウスタイルとして、WS_EX_TOOLWINDOW を指定します。
見えないウィンドウを作成するために、ウィンドウの幅、高さをゼロにします。



TrayWnd.h のCTrayWndクラス宣言部に、Create関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

ウィンドウ破棄時に、ウィンドウクラスオブジェクト自身が自分自身を削除する処理。

プロパティウィンドウを用いて、CTrayWndクラス に PostNcDestroy関数 を追加します。

追加したPostNcDestroy関数に、自分自身を削除する処理を追加します。



ビルドし、エラー、警告がないことを確認します。

タスクトレイに対して、アイコン(、ツールチップ文字列、コールバックメッセージコード)を登録/変更/削除する処理。

追加した CTrayWndクラス に、「タスクトレイに対して、アイコンを登録/変更/削除する関数」を追加します。

タスクトレイに対して、アイコンを登録/変更/削除する処理は、最終的には、Win32API の Shell_NotifyIcon関数 が担います。
Shell_NotifyIcon の第1引数で、アイコンの登録なのか、編集なのか、削除なのか、を指定します。
Shell_NotifyIcon の第2引数のNOTIFYICONDATA構造体データで、アイコン、ツールチップ文字列、コールバックメッセージコードを指定します。



TrayWnd.cpp のファイルヘッダー部に、ID_ICON および WM_USER_TRAYNOTIFYICON の定義を追加します。
CTrayWndクラスのコンストラクタに、m_hIcon_currentメンバ変数の初期化処理を追加します。



TrayWnd.h のCTrayWndクラス宣言部に、m_hIcon_current変数の宣言、および、NotifyIcon関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

タスクトレイのアイコンに対するイベントの応答処理(タスクトレイに常駐するアプリケーションに共通の処理)

CTrayWndクラスに、タスクトレイのアイコンに対するイベントの応答処理を追加します。

タスクトレイのアイコンに対するイベント応答は、できるだけ早く抜け出す必要があるらしく、イベントに応じて、ウィンドウメッセージをポストするようにします。



TrayWnd.cpp のファイルヘッダー部に、ID_CLICKTIMER の定義を追加します。
CTrayWndクラスのコンストラクタに、m_bFireDoubleClickメンバ変数の初期化処理を追加します。



TrayWnd.cpp のメッセージマップ定義部に、以下を追加します。
ON_MESSAGE(WM_USER_TRAYNOTIFYICON, OnTrayNotify)



TrayWnd.h のCTrayWndクラス宣言部に、m_bFireDoubleClick変数の宣言、および、OnTrayNotify関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

プロパティウィンドウを用いて、CTrayWndクラス に WM_TIMER、WM_LBUTTONUP、WM_RBUTTONUP、WM_LBUTTONDBLCLK メッセージに対応するメッセージハンドラ OnTimer関数、OnLButtonUp関数、OnRButtonUp関数、OnLButtonDblClk関数を追加します。
追加した関数の内容を以下のようにします。



TrayWnd.h のCTrayWndクラス宣言部に、DoLButtonClick関数、DoRButtonClick関数、DoLButtonDoubleClick関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

アプリケーション固有の処理を有するCTrayWndの派生ウィンドウクラス

ここまでで、タスクトレイに常駐するアプリケーションに共通の処理を有する規定ウィンドウクラスができました。続いて、アプリケーション固有の処理を有する派生ウィンドウクラスを作成します。

CMyApplicationTrayWnd クラスを追加します。
「メニュー/プロジェクト/クラスの追加」を選択します。


カテゴリ:MFC
テンプレート:MFC クラス
追加ボタンを押します。


クラス名:CMyApplicationTrayWnd
基本クラス:CWnd
(それ他の設定は自動入力に任せます)

「完了」ボタンを押します。

ビルドし、エラー、警告がないことを確認します。

MyApplicationTrayWnd.h のファイルヘッダー部に、TrayWnd.h のインクルード文を追加します。



MyApplicationTrayWnd.h と MyApplicationTrayWnd.cpp の
CWnd を CTrayWnd に置換します。(「大文字と小文字を区別する」「単語単位」にチェックを入れます。)

ビルドし、エラー、警告がないことを確認します。

アプリケーションのメインウィンドウとして登録するウィンドウのウィンドウクラスの変更

ソリューションエクスプローラを用いて、MyApplicationDlg.cpp のファイル名を AboutDlg.cpp に、MyApplicationDlg.h のファイル名を AboutDlg.h に変更します。
AboutDlg.cpp にある CAboutDlgクラスの宣言部を、AboutDlg.h に移動します。
AboutDlg.cpp と AboutDlg.h にある CMyApplicationDlg クラスに関する記述をすべて削除します。
AboutDlg.cpp と AboutDlg.h のファイルヘッダー部のコメント中の、ファイル名、MyApplicationDlg.cpp、MyApplicationDlg.h をAboutDlg.cpp、AboutDlg.h に変更します。
AboutDlg.cpp のファイルヘッダー部の MyApplicationDlg.h のインクルード文を、AboutDlg.h のインクルード文に変更します。





MyApplication.cpp のファイルヘッダー部の MyApplicationDlg.h のインクルード文を、MyApplicationTrayWnd.h のインクルード文に変更します。
MyApplication.cpp のCMyApplicationApp::InitInstance関数の CMyApplicationDlg に関する記述をすべて削除します。代わりに、CMyApplicationTrayWnd に関する記述を追加します。
関数の最期のreturn FALSE; をコメントアウトし、return TRUE; を追加します。



ビルドし、エラー、警告がないことを確認します。

メニューの追加

リソースビューを用いて、メニューリソースを追加し、追加したメニューのIDを、IDM_TRAY_Lとし、以下のメニューアイテムを追加します。

メニュー名 メニューID
トレイ左クリック
終了(&X) ID_APP_EXIT

メニューアイテム追加画面例


リソースビューを用いて、メニューリソースを追加し、追加したメニューのIDを、IDM_TRAY_Rとし、以下のメニューアイテムを追加します。

メニュー名 メニューID
トレイ右クリック
終了(&X) ID_APP_EXIT
(区切り記号)
バージョン情報(&A)... ID_APP_ABOUT

メニューアイテム追加画面例


ビルドし、エラー、警告がないことを確認します。

タスクトレイのアイコンに対するイベントの応答処理(アプリケーション固有の処理)

タスクトレイのアイコンの、左クリック時の処理関数 DoLButtonClick、右クリック時の処理関数 DoRButtonClick、左ダブルクリック時の処理関数 DoLButtonDoubleClick、を追加します。



MyApplicationTrayWnd.h のCMyApplicationTrayWndクラス宣言部に、DoLButtonClick関数、DoRButtonClick関数、DoLButtonDoubleClick関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

メニューアイテムの応答関数の追加、編集

プロパティウィンドウを用いて、CMyApplicationTrayWndクラス に ID_APP_EXIT、ID_APP_ABOUT、のCOMMANDメッセージ応答関数を追加します。

メニューコマンドID COMMANDメッセージ
応答関数名
ID_APP_EXIT OnAppExit
ID_APP_ABOUT OnAppAbout

追加した関数の内容を以下のようにします。



MyApplicationTrayWnd.h のファイルヘッダー部に AboutDlg.h のインクルード文を追加します。



ビルドし、エラー、警告がないことを確認します。

ウィンドウ作成時に、「タスクトレイに対して、アイコンを登録する処理」を呼び出す処理。ウィンドウ破棄時に、「タスクトレイに対して、アイコンを削除する処理」を呼び出す処理。

プロパティウィンドウを用いて、CMyApplicationTrayWndクラス に WM_CREATE、WM_DESTROYメッセージに対応するメッセージハンドラ OnCreate関数、OnDestroy関数を追加します。
追加した関数の内容を以下のようにします。



CMyApplicationTrayWndクラスのコンストラクタに、m_hIcon_mainメンバ変数の初期化処理を追加します。



MyApplicationTrayWnd.h のCMyApplicationTrayWndクラス宣言部に、m_hIcon_main変数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

不要リソースの削除、不要IDの削除

リソースビューを用いて、ダイアログ IDD_MYAPPLICATION_DIALOG を削除します。
ソリューションエクスプローラーを用いて、Resource.h を開き、不要IDを削除します。



ビルドし、エラー、警告がないことを確認します。

実行

実行結果

タスクトレイのアイコンの上にマウスカーソルを置くと、「MyApplication」というツールチップが表示されます。


タスクトレイのアイコンを右クリックすると、右クリックメニューが表示されます。「終了(X)」を選択すると終了します。


タスクトレイのアイコンを左クリックすると、左クリックメニューが表示されます。「終了(X)」を選択すると終了します。「バージョン情報(A)...」を選択すると、バージョン情報ダイアログが表示されます。


タスクトレイのアイコンを右ダブルクリックすると、バージョン情報ダイアログが表示されます。

ダウンロード

サンプルプロジェクト

参考

Visual C++ 5 パワフルテクニック大全集 「9.1 タスクトレイに収まるCDプレイヤーを作るには」