[MFC]常駐型のアプリケーションを作る(実装編 その2)

MFC
この記事は約6分で読めます。

前回の復習~今回の記事でやること

前回まではタスクトレイ常駐型アプリとして、クリップボードに保存したイメージを画像ファイルにするアプリケーションの作成をしていました。

今回はタスクトレイ常駐型アプリの雛形を継承して実装クラスのCSnipExWndクラスを作っていきます。

ソフトウェアの実装

CSnipExWndクラスの実装

クラス宣言

CTaskTrayAppクラスを継承して、CSnipExWndクラスを定義します。

class CSnipExWnd :	public CTaskTrayApp
{
   /* ~~~省略~~~ */
}

Create()とDelete()時の処理

//---------------------------------------------------------
// Create処理
//---------------------------------------------------------
int CSnipExWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CTaskTrayApp::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO: ここに特定な作成コードを追加してください。
	// アイコンのロードとタスクトレイへの登録
	m_hIcon_main = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	NotifyIcon(NIM_ADD, m_hIcon_main, _T("SnipEx"));
	
	// INIファイルの読み込み
	ReadINIFile();

	return 0;
}

//---------------------------------------------------------
// Destroy処理
//---------------------------------------------------------
void CSnipExWnd::OnDestroy()
{
	CTaskTrayApp::OnDestroy();

	NotifyIcon(NIM_DELETE, m_hIcon_main, _T("SnipEx"));

	// TODO: ここにメッセージ ハンドラー コードを追加します。
	ChangeClipboardChain(m_hNextViewr);
}

Create()とDelete()でそれぞれNotifyIcon()をコールして、タスクトレイへのアイコンの登録と削除を行っています。

Create()のReadINIFile()は設定ファイルの読み込みを行っていて、イメージの保存先のディレクトリを取り込んでいます。Destroy()で行っているChangeClipboardChain()は、クリップボードの監視を中止をOSに伝えています。

どちらもこのあとに説明します。

アイコン右クリックでメニューを表示する

アプリは起動した以上いつかは終了しなければなりません。

しかし、SnipExはウィンドウを表示しないアプリケーションのため閉じるボタンは押せないですし、タスクバーにもアイコンがないのでメニューからの終了もできないです。

そのためタスクトレイのアイコンを右クリックしたらメニューが表示されるようにして、表示したメニューから終了を押すとアプリを終了できるようにします。

まずはじめに表示するメニューをリソースに追加します。

設定メニューは、押すとダイアログ表示して保存先ウィンドウを変更できるようにしようとした名残なので気にしなくていいです。表示するのは右クリックメニューのサブメニューなので、「右クリック」の部分は何でも構いません。

メニューを追加したら次は右クリックでメニューを表示する処理です。親クラスのDoRButtonClick()をオーバーライドして、右クリック時の処理を記載します。

//---------------------------------------------------------
// トレイアイコンでの右ボタンクリック
//---------------------------------------------------------
void CSnipExWnd::DoRButtonClick()
{
	POINT pt;
	GetCursorPos(&pt);

	CMenu menu;
	menu.LoadMenu(IDR_R_CLK_MENU);

	CMenu*	pPopup = menu.GetSubMenu(0);

	// SetForgroundWindowとPostMessageが必要な理由は、
	// Knowledge Base (Q135788)参照のこと
	SetForegroundWindow();
	pPopup->TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
	PostMessage(WM_NULL);
}

LoadMenu()で指定IDのメニューを読み込んで、TrackPopupMenu()でメニューをポップアップさせています。参考にしたサイトのソースそのままですが、TrackPopupMenu()の前後にSetForegroundWindow()とPostMessage()が必要なの理由である「Knowledge Base (Q135788)」は見つけることができませんでした。

しかし、どうやらこのTrackPopupMenu()を呼び出す前後でこれらの処理をしておかないと、ポップアップしたメニューとアプリケーションがうまく関連付けられず、メニューが消えなくなったりソフトが終了できなくなったりするようです。

と思っていたのですが、Microsoftの公式ドキュメントにそれらしい記述がありました。アイコンのアプリケーションを必ずForegroundにしないとメニューの挙動がおかしくなると記載がありますね。ページ下部にサンプルソースも書いてあります。

アプリケーションを終了する

終了メニューが押されたらWM_CLOSEメッセージをポストしてアプリを終了します。

//---------------------------------------------------------
// アプリケーションの終了
// (メニューのイベントハンドラ)
//---------------------------------------------------------
void CSnipExWnd::OnAppExit()
{
	// TODO: ここにコマンド ハンドラー コードを追加します。
	PostMessage(WM_CLOSE);
}

次回予告

これで常駐型アプリの起動~常駐~終了までが実装できました!

次回はホットキーでアプリケーションを操作する方法についてまとめたいとおもいます。

コメント

タイトルとURLをコピーしました