これは、インサイドウィンドウズ1996年9月号の「WindowsProgramingTips」第2回――タスクバーを有意義に使おう!――の、タスクトレイにアイコンを表示し、そのアイコンに対するメッセージを受け取るアプリケーションを、MFCを使って実装する方法です。
まず、CMainFrameにNOTIFYICONDATA型のメンバ変数m_stNtfyIconを作成してください。 |
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; ////////////////////////////////// // アイコンをタスクトレイに表示します。 m_stNtfyIcon.cbSize = sizeof( NOTIFYICONDATA ); //構造体のサイズです。 m_stNtfyIcon.uID = 0; //アイコンの識別ナンバーです。 m_stNtfyIcon.hWnd = m_hWnd; //メッセージを送らせるウィンドウのハンドルです。 m_stNtfyIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; //各種設定です。 m_stNtfyIcon.hIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME ); //アプリケーションのアイコンです。 m_stNtfyIcon.uCallbackMessage = WM_USER_NTFYICON; //送ってもらうメッセージです。 lstrcpy( m_stNtfyIcon.szTip, _T( "テスト" ) ); //チップの文字列です。 ::Shell_NotifyIcon( NIM_ADD, &m_stNtfyIcon ); //タスクトレイに表示します。 return 0; }
m_stNtfyIconに関連づけるウィンドウハンドラは、このCMainFrameのメンバ変数m_hWndを使います。
アイコンの取得はAfxGetApp()を使って、このアプリケーションのCWinAppオブジェクトtheAppへのポインタを取得してから、アプリケーションのリソースからアイコンを取得します。 lstrcpyはC言語の文字列をコピーする関数です。_TはUnicodeに対応するためのマクロです。 タスクトレイにアイコンを表示する関数Shell_NotifyIcon()はAPIです。
|
void CMainFrame::OnDestroy() { CFrameWnd::OnDestroy(); ::Shell_NotifyIcon( NIM_DELETE, &m_stNtfyIcon ); //タスクトレイのアイコンを削除します。 }
これは、記事とほとんど同じコードです。
まず、MainFrm.cppのIMPLEMENT_DYNCREATEの前に次のコードを書き込みます。 |
#define WM_USER_NTFYICON (WM_USER+100) //ウィンドウメッセージの登録。
メッセージはすべてUINT型なので、このように定義しておきます。100という数字に特に意味はありません。ちなみに、カッコでくくるのにはわけがあります。例えば、
|
iTemp = WM_USER_NTFYICON * 100; //こんなことフツーないが。
というコードがあった場合、カッコがあるときとないときでは結果が変わってしまいます。これは、#defineマクロというものが単に文字列を置き換えるだけだからです。メッセージにかけ算をする何てことはフツーありませんが、念のためということで。
次に、メッセージマップにメッセージをハンドラと関連づけるためのコードを加えます。 |
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_MESSAGE( WM_USER_NTFYICON, OnNotifyIconIvents ) //メッセージをハンドラと関連づけます。 //}}AFX_MSG_MAP END_MESSAGE_MAP()
ON_MESSAGEの行を加えてください。
ON_MESSAGEはユーザー定義メッセージを関数へと関連づけるためのマクロです。
さらに、MainFrm.hの中に、次のコードを書き込みます。 |
// 生成されたメッセージ マップ関数 protected: //{{AFX_MSG(CMainFrame) afx_msg LRESULT OnNotifyIconIvents( WPARAM wParam, LPARAM lParam ); //}}AFX_MSG DECLARE_MESSAGE_MAP()
afx_msgの行を加えてください。
以上で、やっとアイコンからのメッセージを処理する関数を宣言することができました。つまり、アイコンでクリックしたりしたとき、そのメッセージはOnNotifyIconIvents関数ですべて処理されるようにしたということです。
さて、最後の締めです。OnNotifyIconIvents関数を定義しましょう。 |
// アイコンをクリックしたときの動作。 LRESULT CMainFrame::OnNotifyIconIvents( WPARAM wParam, LPARAM lParam ) { switch( lParam ) { case WM_LBUTTONDOWN: //ここに、左クリックしたときの処理を書き込みます。 break; case WM_RBUTTONDOWN: //ここに、右クリックしたときの処理を書き込みます。 break; } return 0; }
この関数は「関数の追加」を使わずに書き込んでください。前もってメッセージと関連づけてあるので、もし「関数の追加」を使って加えると、二重にメッセージと関連づけることになってしまいます。
WM_LBUTTONDOWNはウィンドウズ95の「マウスの左ボタンをクリック」という意味のメッセージです。このパラメーターを調べることで、タスクトレイ上のアイコンがどのようなことをされたのか分かるでしょう。
以上で、メッセージのフレームウィンドウへの対応は完了しました。
ウィンドウメッセージの登録までは同じです。つまり、 |
#define WM_USER_NTFYICON (WM_USER+100) //ウィンドウメッセージの登録。
までは同じようにコーディングしてください。ちなみに、すべてのウィンドウメッセージはこのように整数です。Winuser.hに基本的なメッセージが書かれています。していることは同じです。
さて、まず「仮想関数の追加」を選択し、その中からWndProcを選びます。この関数は、すべてのメッセージを処理できる関数です。 |
LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { switch( message ) { case WM_USER_NTFYICON: //アイコンからのメッセージ。 if( lParam == WM_LBUTTONDOWN ) ; //左クリックされました。 else if( lParam == WM_RBUTTONDOWN ) ; //右クリックされました。 return 0; } return CFrameWnd::WindowProc(message, wParam, lParam); }
というような形でWM_USER_NTFYICONを受け取り処理すればいいということです。このメッセージを受け取ったとき、lParamには、そのアイコンが実際に受け取ったイベントのメッセージが格納されています。これを処理すればいいわけです。
ちなみにwParamには常に0が入っています。また、どうやらそのイベントのlParamやwParamなどの情報はまったく得られないようです。「コントロールキーが押されてるかどうか」などをチェックしたい場合にはWin32APIの::GetKeyState( VK_CONTROL )を使うといいでしょう。
これで、一応コーディングは終了です。この方法だと非常に簡単に済みます。 |
SetForegroundWindow(); //ウィンドウをフォアグラウンドに持ってきます。 SetFocus(); //これをしないと、メニューが消えなくなります。 cIconMenu.TrackPopupMenu( TPM_CENTERALIGN | TPM_LEFTBUTTON, 0, 0, m_hWnd ); //ポップアップメニューを表示します。 PostMessage( WM_NULL ); //これをしないと、2度目のメニューがすぐ消えちゃいます。
この情報はKnowledgeBaseの"PRB: Menus for Notification Icons Don't Work Correctly -- Article ID: Q135788"に書かれていました。これ解決するのに無茶苦茶時間掛かったのに、こんなところに書かれてたなんて……。
この問題を解決するには、単純に小さいアイコンしか作製されていないアイコンをしていすればOKです。
アプリケーションのアイコンがIDR_MAINFRAMEにあるとします。まずこのアイコンをコピーします。ワークスペース内でアイコンを表示させ、IDR_MAINFRAMEをCTRLキーを押しながらドラッグして、適当なところで離します。そうするとIDR_MAINFRAME1が作製されるはずです。 |
(C)KAB-studio 1997 ALL RIGHTS RESERVED. |