戻る

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);
}
inserted by FC2 system