アイエスエス株式会社 "Innovative System Solutions"
気まぐれ Programming TIPS 【1】
【1】 タスクトレイ常駐アプリ(C++,Win32 API,MFC)
気まぐれに思いついた内容を、備忘録的に殴り書く。
今回はタスクトレイ常駐アプリについて。
タスクトレイ常駐アプリを作るには、
・タスクトレイにアイコンを追加する
・メインウィンドウを非表示にする
とすれば良いのではなかろうか。
●タスクトレイにアイコンを追加する
これをやるにはAPIの「Shell_NotifyIcon」関数を使う。
Shell_NotifyIcon関数は、タスクバーのステータスエリアにメッセージを送る関数らしい。
BOOL
Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA lpdata
);
第一引数がメッセージの種類、第二引数がもろもろの情報をまとめたNOTIFYICONDATA構造体。
で、関数が成功したらTRUE,失敗したらFALSEを返す。
ちなみにShell_NotifyIconを使うにはshellapi.hをインクルード、shell32.libをリンクする。
メッセージの種類は以下の通り。
NIM_ADD - アイコンの追加
NIM_MODIFY - アイコンの変更
NIM_DELETE - アイコンの削除
NIM_SETFOCUS - タスクトレイにフォーカスをセット
NIM_SETVERSION - バージョン設定
NOTIFYICONDATA構造体のメンバは以下の通り。
cbSize - 構造体のサイズをバイト単位で指定する
hWnd - アイコンの通知メッセージを受け取るウィンドウのハンドル
uID - アイコンのアプリケーショ定義のID
uFlags - 構造体のどのメンバを有効にするかのフラグ
(
NIF_MESSAGE:uCallbackMessage
NIF_ICON:hIcon
NIF_TIP:szTip
NIF_STATE:dwState, dwStateMask
NIF_INFO:szInfo, uTimeout,szInfoTitle,dwInfoFlags
NIF_GUID:使用しない
)
uCallbackMessage - アプリケーション定義のメッセージコード、タスクトレイアイコンにイベントが起こったと時にhWndで指定したウィンドウに送られる
hIcon - 表示アイコンのハンドル
szTip - ツールチップに表示される文字列
dwState - アイコンの状態
(
NIS_HIDDEN:アイコンは非表示
NIS_SHAREDICON:アイコンは共有
)
dwStateMask - dwStateメンバでどの状態を設定、取得するのかの指定
szInfo - バルーンツールチップに表示される文字列
uTimeout - バルーンツールチップの表示タイムアウト時間(10000 ~ 30000 msec)
uVersion - バージョン指定
(
0:Windows 95
NOTIFYICON_VERSION:Windows 2000
)
szTitleInfo - バルーンツールチップのタイトルとして表示される文字列
dwInfoFlags - バルーンツールチップに表示されるアイコンに設定
(
NIIF_NONE:アイコン無し
NIIF_INFO:情報アイコン
NIIF_WARNING:警告アイコン
NIIF_ERROR:エラーアイコン
NIIF_ICON_MASK:使用しない
NIIF_NOSOUND:音を鳴らさないようにする
)
guidItem - 使用しない
実際のコード
NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = GetSafeHwnd(); nid.uID = 0; nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; nid.uCallbackMessage = MSG_TASKTRAY; nid.hIcon = AfxGetApp()->LoadIcon(IDI_ICON); strcpy(nid.szTip,"tool tip"); Shell_NotifyIcon(NIM_ADD, &m_nid);最低限上記で、表示できる。
で、メインウィンドウを非表示にすれば、タスクトレイ常駐アプリの完成。ついでに、バルーンツールチップの表示の仕方。
NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); nid.uFlags = NIF_INFO; nid.hWnd = GetSafeHwnd(); strcpy(nid.szTip,"balloon title"); strcpy(nid.szInfo,"balloon info"); nid.dwInfoFlags = NIIF_INFO; nid.uTimeout = 20; Shell_NotifyIcon(NIM_MODIFY, &nid);
徘徊アプリの動作骨組(2)
●状態クラスの例(待機状態)
状態クラスの例として,「徘徊を中断させているとき」に対応する状態の実装方法を示します.
この状態は,
- ポップアップメニューで「箱入り猫」を選択されたらこの状態になる
- 「猫が箱に入った画像」が表示される
- 徘徊しない(ほっとくと,ずっと同じ場所)
- マウスドラッグで移動させることができる
ものとします.
ポップアップメニューから状態変更.
箱入り猫画像.
本当は「*はこのなかにいる*」まで描きたいのだが短縮系.足りない「にいる」については脳内補間で対応.
●OnCreate()
CDMManagerがこのクラスのオブジェクトを作ったときに呼びます.
猫ウィンドウクラスに箱入り猫のアニメーションを登録するだけです.(コード省略)
●OnSelect()
状態変更時に(CDMManager::ChangeState()内から)呼びます.
状態クラスはここで,猫ウィンドウに対して,自分用のアニメーションを選択させます.
また,その他の必要な設定(ポップアップメニュー項目のEnable,Disableとか)を行います.
箱入り猫状態では,ポップアップメニュー項目の「箱入り猫」項目にチェックをいれたりします.
void CDMState_InBox::OnSelect( CCatWnd *pCatWnd, class CDMManager *pManager ) { pCatWnd->SetBltMode( CCatWnd::BLT_NORMAL );//アニメーションを普通に描画する pCatWnd->EnablePopupMenuItem( MENU_ID_INBOX, true );//メニュー項目を有効に pCatWnd->CheckPopupMenuItem( MENU_ID_INBOX, true );//メニュー項目にチェックを入れる pCatWnd->SetCurAnimFrame( ANIM_ID_INBOX, 0 );//箱入り猫なアニメーションを選択する }CCatWnd::SetBltMode()は,画像を反転表示させたりするための設定用関数です.
(左右向き分の画像を用意するのが面倒なので::StretchBlt()で反転表示.)
●OnPreChangeAnimFrame()
アニメーションの切り替わり時の処理ですが,箱入り猫状態では,特にすることがないのでオーバーロードしません.
(デフォルト動作で,アニメーションがループ)
●OnPopupMenu()
ポップアップメニューへの対応です.
選択された項目が「箱入り猫」だった場合,この状態を抜けて「徘徊」状態に移行させます.bool CDMState_InBox::OnPopupMenu( CCatWnd *pCatWnd, class CDMManager *pManager, UINT ItemID ) { return pManager->ChangeState( pCatWnd, ANIM_ID_WALKA );//徘徊状態に切換え }「箱入り猫」メニュー項目のチェックを外したりするのは,徘徊状態クラス側のOnSelect()の仕事にしているので,単純に状態切換えをするだけです.
●OnOtherEvent()
その他のメッセージへの対応処理です.
箱入り猫状態では,ドラッグによる移動を可能にするためのコードを記述します.
コードは省略しますが,WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE で普通に処理しています.
なお,この処理のためにマウスキャプチャを行う必要に迫られ,既に「CCatWndにHWNDを返すメソッドを追加したくて仕方が無い」精神状態に追いやられています.
●動作骨組みはこれだけ.
個々の状態での処理は少しずつ異なるだけ(他の状態への遷移の条件等が違う)なので,ひとつ作れば増やすのは(コードのコピーとちょっとした修正で済むので)楽です.
CDMManagerクラスが状態クラスのメンバを適切なタイミングで呼ぶ部分ができているので,徘徊アプリケーションが動作する骨組み自体はほぼ出来上がりです.
一番の問題は,
状態(アニメパターン)を増やすためにはアニメーションの絵を描かなければならない
ということです.
あと,猫にカーソルを合わせると砂時計カーソルになる原因不明の現象が発生中.誰か助けて!