戻る
MFCで常駐アプリを作成する
ダイアログベースのMFCアプリを作成し、ダイアログを削除する。
ダイアログの代わりにメインウィンドウを作成する。
メインウィンドウクラスにShell_NotifyIcon関数を使用してタスクトレイに登録するメソッドを作る。
ウィンドウ破棄時にトレイアイコンを削除する。
リソースビューワーでメニューを作成し、タスクトレイのアイコン右クリックでメニューを開くようにする。
メニューには「終了」を入れ、終了をクリックするとプロセスを終了するようにする。
サンプルコード
例としてプロジェクト名を「SampleRS」とする。
ダイアログクラスの「SampleRSDlg.cpp」と「SampleRSDlg.h」を削除する。
SampleRS.cppのInitInstance関数
BOOL CSampleApp::InitInstance()
{
〜中略〜
SetRegistryKey(_T("アプリケーション ウィザードで生成されたローカル アプリケーション"));
// ここから下を全部削除する。
// CSampleDlg dlg;
// m_pMainWnd = &dlg;
// INT_PTR nResponse = dlg.DoModal();
// if (nResponse == IDOK)
// {
// // TODO: ダイアログが で消された時のコードを
// // 記述してください。
// }
// else if (nResponse == IDCANCEL)
// {
// // TODO: ダイアログが <キャンセル> で消された時のコードを
// // 記述してください。
// }
//
// // ダイアログは閉じられました。アプリケーションのメッセージ ポンプを開始しないで
// // アプリケーションを終了するために FALSE を返してください。
// return FALSE;
// 代わりにメインウィンドウを作成する。
LPCTSTR lpszClassName;
// CMainWindowはCWndクラスを継承したメインウィンドウクラス。
m_pWnd = new CMainWindow;
RECT rect;
lpszClassName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
rect.left = 0;
rect.right = 4;
rect.top = 0;
rect.bottom = 4;
m_pWnd->CreateEx(
WS_EX_CLIENTEDGE,
lpszClassName,
"任意のウィンドウ名",
WS_CAPTION | WS_SYSMENU,
rect,
NULL,
0);
// 通知領域にアイコンを登録する。
m_pWnd->AddNotifyIcon();
m_pMainWnd = m_pWnd;
return TRUE;
}
クラスウィザードを使用してCWndクラスを継承するMFCクラスを作成する
【MainWindow.h】
#pragma once
// CMainWindow
class CMainWindow : public CWnd
{
DECLARE_DYNAMIC(MainWindow)
public:
CMainWindow();
virtual ~CMainWindow();
protected:
DECLARE_MESSAGE_MAP()
HICON m_hIcon; // アイコンロード用ハンドルを追加する。
HWND m_hWndCopy; // ウィンドウハンドルコピー用ハンドルを追加する。
};
【MainWindow.cpp】
// MainWindow.cpp : 実装ファイル
//
#include "stdafx.h"
#include "SampleRS.h"
#include "MainWindow.h"
// CMainWindow
IMPLEMENT_DYNAMIC(CMainWindow, CWnd)
CMainWindow::CMainWindow()
{
// アイコンをロードする。
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CMainWindow::~CMainWindow()
{
}
BEGIN_MESSAGE_MAP(CMainWindow, CWnd)
ON_COMMAND(ID_MENU_EXIT, &CMainWindow::OnMenuExit)
END_MESSAGE_MAP()
// CMainWindow メッセージ ハンドラ
タスクトレイ登録関数
void CMainWindow::AddNotifyIcon()
{
// 通知領域のアイコンを作成する。
NOTIFYICONDATA notif;
char cToolTipMsg[] = "任意のウィンドウ名";
m_hWndCopy = m_hWnd;
notif.cbSize = sizeof(NOTIFYICONDATA);
notif.hWnd = m_hWnd;
notif.uID = 0;
notif.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
// コールバックメッセージは任意のメッセージを設定する。
// ここでは「#define WM_TRAYICONMESSAGE WM_APP」を設定している。
notif.uCallbackMessage = WM_TRAYICONMESSAGE;
notif.hIcon = m_hIcon;
strcpy_s(notif.szTip, sizeof(notif.szTip), cToolTipMsg);
// アイコンを登録できるかエラーになるまで繰り返す。(リトライ5回まで)
for (int i = 0; i < 5; i ++)
{
if (Shell_NotifyIcon(NIM_ADD, ¬if) == TRUE)
{
// 登録できたら終わり
return;
}
else
{
// タイムアウトかどうか調べる
if (GetLastError() != ERROR_TIMEOUT)
{
// アイコン登録エラーをメッセージ表示する。
AfxMessageBox("通知領域にアイコンを登録できませんでした。\n"
"アプリケーションを終了します。");
// ウィンドウを閉じる
PostQuitMessage(0);
return;
}
// 登録できているか確認する。
if (Shell_NotifyIcon(NIM_MODIFY, ¬if) == TRUE)
{
// 登録できていたら終了。
return;
}
else
{
// 登録できていなかったのでインターバルをおいてリトライする。
Sleep(1000);
}
}
}
// アイコン登録エラーをメッセージ表示する。
AfxMessageBox("通知領域にアイコンを登録できませんでした。\n"
"アプリケーションを終了します。");
// ウィンドウを閉じる。
PostQuitMessage(0);
}
ウィンドウプロシージャを編集する。
WM_CREATEでWindowMessageを登録する。
WM_DESTROYでタスクトレイのアイコン削除処理を行う。
タスクトレイ登録関数のコールバックメッセージでアイコン右クリックの処理を行う。
defaultでアイコンの再登録を行う。
LRESULT CMainWindow::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
static UINT msgTaskBarRestart;
POINT p;
CMenu menu;
CMenu* popupMenu;
switch(message)
{
case WM_CREATE:
msgTaskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
break;
case WM_DESTROY:
// トレイアイコンを削除する。
NOTIFYICONDATA notif;
notif.cbSize = sizeof(NOTIFYICONDATA);
notif.hWnd = m_hWndCopy;
notif.uID = 0;
notif.uFlags = 0;
Shell_NotifyIcon(NIM_DELETE, ¬if);
break;
case WM_TRAYICONMESSAGE:
// 通知領域のアイコンに対して操作が行われた場合の処理を行う。
switch(lParam)
{
case WM_RBUTTONDOWN:
// ポップアップメニューを開く前にメインウィンドウをアクティブにします。
// これを省略すると他のウィンドウにフォーカスが移ってもポップアップメニューが
// 消えなくなってしまいます。
SetForegroundWindow();
// メニューを開く。
GetCursorPos(&p);
menu.LoadMenu(IDR_MENU1);
popupMenu = menu.GetSubMenu(0);
popupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, p.x, p.y, this, NULL);
break;
}
break;
default: // タスクバーが再作成されたらアイコンを再登録する。
if (message == msgTaskBarRestart)
{
AddNotifyIcon();
}
break;
}
return CWnd::DefWindowProc(message, wParam, lParam);
}
リソースビューでメニューを追加し、イベントハンドラでメニュー選択時の関数を追加する。
void CMainWindow::OnMenuExit()
{
// TODO: ここにコマンド ハンドラ コードを追加します。
PostMessage(WM_CLOSE);
}