ソフトウェアの実装
SW設計の概要ができたら実際にコーディングを行っていきます。
CTaskTrayAppクラスの実装
クラス宣言
class CTaskTrayApp :public CWnd
{
/* ~~~省略~~~ */
}
クラスの追加からCTaskTrayAppクラスを追加します。この時、CWndをクラスの継承元として指定します。今後追加される関数は、基本的にVSのクイックリファクタリング機能で宣言を追加していけばうまくいく……はずです。
アプリのCreate()とDelete()の依頼
まずはタスクトレイ常駐型アプリのCreate()とDelete()の依頼を投げる関数について説明します。
//---------------------------------------------------------
// クリエイト
//---------------------------------------------------------
BOOL CTaskTrayApp::Create()
{
// TODO: ここに特定なコードを追加するか、もしくは基底クラスを呼び出してください。
return CreateEx(WS_EX_TOOLWINDOW, // ウィンドウのExスタイル
AfxRegisterWndClass(0), // ウィンドウクラスの名前 デフォルトタイプ指定
_T("TrayWnd"), // ウィンドウタイトル
WS_OVERLAPPED, // ウィンドウのスタイル
0, // 高さとか幅とか
0, // 表示しないので4つとも0
0, //
0, //
NULL, // 親ウィンドウのハンドル
NULL); // 子ウィンドウやメニューの識別子
}
//---------------------------------------------------------
// ウィンドウのデリート依頼
//---------------------------------------------------------
void CTaskTrayApp::PostNcDestroy()
{
// TODO: ここに特定なコードを追加するか、もしくは基底クラスを呼び出してください。
CWnd::PostNcDestroy();
delete this;
}
Create()のポイントですが、タスクトレイ常駐型アプリなので、タスクバーにアイコンを表示しないウィンドウタイプのWS_EX_TOOLWINDOWを指定してCreate()しています。このウィンドウタイプはCreateEx()でないと行えないので、一旦Create()で受けてからCreateEx()をreturnするようにしています。
CreateEx()では、ウィンドウのサイズ指定で高さと横幅を0に指定して、ウィンドウが見えないようにしています。
PostNcDestroy()はウィンドウ破棄のタイミングで呼び出される関数で、オーバーライドしています。よくわかっていないのですが、自動的に呼ばれるこの関数の中で、自分自身をdeleteするように修正します。モードレスウィンドウの場合は明示的に自分自身を殺してやらないといけないみたいで、それをやっています。
タスクトレイへのアイコンの追加
タスクトレイへのアイコンの追加はShell_NotifyIcon()で行います。この関数をコールすると、タスクトレイにアイコンを追加してくれます。
Shell_NotifyIcon()でアイコンの追加、削除、変更が可能です。第一引数には操作内容を、第二引数にはアイコンの設定情報を格納したNOTIFYICONDATA構造体を渡します。
NOTIFYICONDATA構造体で特に重要なメンバがuCallbackMessageです。タスクトレイのアイコン上でマウスイベントが起こった際に、このメンバで指定したメッセージを hWndメンバで指定したウィンドウに送信することができます。
クラスマネージャからユーザ定義のメッセージを追加して、 uCallbackMessageに指定してアイコンの登録を行います。
タスクトレイ常駐アプリのイベントハンドラ
タスクトレイ常駐型アプリを削除するために、アイコンをクリックした場合にメニューを表示し、終了操作をできるようにしておきます。
//---------------------------------------------------------
// タスクトレイのアイコンをクリックした時に発生するイベント
//---------------------------------------------------------
afx_msg LRESULT CTaskTrayApp::OnUserTraynotifyicon(WPARAM wParam, LPARAM lParam)
{
UINT uiIconID = (UINT)wParam;
UINT uiMouseMsg = (UINT)lParam;
if (ID_ICON != uiIconID)
{
return 0;
}
switch (uiMouseMsg)
{
case WM_LBUTTONDOWN:
m_bFireDoubleClick = FALSE;
SetTimer(ID_CLICKTIMER, GetDoubleClickTime(), NULL);
break;
case WM_LBUTTONUP:
if (m_bFireDoubleClick)
{
PostMessage(WM_LBUTTONDBLCLK);
}
break;
case WM_LBUTTONDBLCLK:
m_bFireDoubleClick = TRUE;
KillTimer(ID_CLICKTIMER);
break;
case WM_RBUTTONUP:
PostMessage(WM_RBUTTONUP);
break;
}
return 0;
}
//---------------------------------------------------------
// タイマイベントのハンドラ
//---------------------------------------------------------
void CTaskTrayApp::OnTimer(UINT_PTR nIDEvent)
{
// TODO: ここにメッセージ ハンドラー コードを追加するか、既定の処理を呼び出します。
// OnUserTraynotifyicon()でセットしたタイマを経過したら
// タイマセットしたときのボタンダウンがダブルクリックでないと判断してメッセージを投げる。
if (ID_CLICKTIMER == nIDEvent)
{
KillTimer(nIDEvent);
PostMessage(WM_LBUTTONUP);
}
// CWnd::OnTimer(nIDEvent);
}
//---------------------------------------------------------
// マウスの左ボタンアップでのイベントハンドラ
//---------------------------------------------------------
void CTaskTrayApp::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: ここにメッセージ ハンドラー コードを追加するか、既定の処理を呼び出します。
DoLButtonClick();
// CWnd::OnLButtonUp(nFlags, point);
}
コードに関してはタスクトレイ に常駐する アプリケーション を作成するにはを使わせてもらいました。ここでのポイントは、左マウスボタンのダブルクリックの判定が入っているところです。
これは、タスクトレイアイコンへのマウスイベントは、一旦OnUserTraynotifyicon()で引き受けてマウスイベントを発行し直す作りにしているために、ダブルクリックされたかを判定する必要があるため(と思っています)。
左クリックイベントを受けたときはSetTimer()を呼んでタイマをセットして、PostMessage(WM_LBUTTONUP)で左ボタンアップのイベントを発行しています。
またOnLButtonUp()では、DoLButtonClick()という仮想関数をコールするようにしています。CTaskTrayAppクラスの継承先でオーバーライドして、マウスボタンイベントの実装を楽にしています。
次回予告
とりあえずこれでタスクトレイ常駐型アプリの雛形ができました。
次回は今回作った CTaskTrayAppクラスを継承したCSnipExWndクラスを作っていきます。
コメント