環境は WinXP Pro SP1 + VC++.NET 2003 です。
タスクトレイに常駐するプログラムを作ろうとしています。
タスクトレイアイコンをクリックするとメニューが表示され、このメニュー経由ですべ
ての操作を行うため、ユーザーインターフェイスとしてのウィンドウを必要としませ
ん。
ドキュメントもビューも必要ないので、SDI でプロジェクトをつくり、InitInstance の
処理を以下のように書き換えました。
すると、ファイル→終了 を選んでもプログラムが終了しなくなってしまいました。
システムメニューからは終了できるので、どうやらメニューをクリックしたメッセージ
が飛んでこないようです。
どうすれば、メッセージを捕まえられるでしょうか?
以下、InitInstance 抜粋
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = AfxWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = AfxGetInstanceHandle();
wc.hIcon = NULL;
wc.hCursor = ::LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = reinterpret_cast< HBRUSH >( COLOR_WINDOW + 1 );
wc.lpszMenuName = MAKEINTRESOURCE( IDR_MAINFRAME );
wc.lpszClassName = AxClass;
if( ! AfxRegisterClass( &wc ) )
{
return FALSE;
}
CAxWnd *pWnd = new CAxWnd;
if( ! pWnd )
{
return FALSE;
}
pWnd->CreateEx( 0, AxClass, AxWindow, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL );
pWnd->ShowWindow( SW_SHOW );
pWnd->UpdateWindow();
m_pMainWnd = pWnd;
>どうすれば、メッセージを捕まえられるでしょうか?
普通に作れば飛んできます。
ハンドラを作ってるクラスがまずいのでは?
CAxWnd::OnXXXXになってる?
この事象の場合「InitInstance」に問題があるのではなく
「CALLBACK WndProc」に問題があるのだと思われます
そちらを提示してみてはどうでしょうか?
http://www.kumei.ne.jp/c_lang/sdk/sdk_06.htm
を眺めてみてはどうでしょうか
SDKに疎いものですみません
言葉が足りませんでした。申し訳ありません。
自作のメニューではまだ試していないのですが、とりあえず「アプリケーションの終
了」というメニューのクリックを捕まえたいのです。
これは ID が ID_APP_EXIT で、既定では CWinApp::OnAppExit でハンドリングされてい
ます。
AppWizard で作っただけの、まったくいじっていないプログラムを見ると、このハンド
ラは定義されてなく、既定のハンドラが呼ばれますが、今回はこれが呼ばれません(ア
プリが終了しません)。
また、バージョン情報(ID_APP_ABOUT)もこの上のほうに
BEGIN_MESSAGE_MAP(CAxApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP()
とマッピングされていますが、やはり OnAppAbout が呼ばれません。
CAxWnd はただ CWnd を継承しただけの、何もしないコンストラクタとデストラクタがあ
るだけのクラスなのですが、ここに何か書かなければならないのでしょうか?
> タスクトレイアイコンをクリックするとメニューが表示され、このメニュー経由ですべ
> ての操作を行うため、ユーザーインターフェイスとしてのウィンドウを必要としません。
そのメニューはどのように表示しているのでしょうか?
TrackPopupMenu ですか?
CMenu::TrackPopupMenu を使っているとして,(メニュー選択時には)
その 3 番目の引数 pWnd に指定したウィンドウに WM_COMMAND が送られているはずです。
まずここまで確認してください。
でここから先,CWinApp::OnAppExit が呼ばれるかどうかは,
メッセージルーティングの話が関わってきます。↓を読んで下さい。
http://www.microsoft.com/japan/developer/library/vccore/_core_command_routing.ht
m
> メッセージルーティングの話が関わってきます。
失礼。コマンドのルーティングです。
ウィンドウにコマンドハンドラ(CAxWnd::OnAppExit)を追加したところ、これが呼ばれ
ていることが確認できました。
提示していただいた文書によると…
フレームワークは、メインフレームが捕まえたコマンドをルーティングに従って転送し
ていって、そのメッセージをハンドリングできるオブジェクトをメッセージマップを見
ながら探していく。
どこでもハンドリングされていなかったら、元のオブジェクト(メインフレーム)で処
理する。
つまり、フレームウィンドウを排して自作のウィンドウに置き換えたこの場合、CAxWnd
にハンドラを作ってそこで捕まえて、CWinApp::OnAppExit を呼びたければ CWinApp の
メッセージマップを見て自分で転送してやるしかない、と。
こういう理解でよろしいでしょうか?
OnCmdMsgをオーバーライドして
AfxGetApp()->OnCmdMsgすればOKと思います。
yukihiko さんありがとうございます。
面倒かと思ってたら、そんな簡単な方法でできたんですね。
レスをいただいたハートレーさん、woodさん、ちいさんもありがとうございました。
以下、今回のコードを掲載しておきます。
BOOL CAxWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO*
pHandlerInfo)
{
if( CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo) )
{
return TRUE;
}
if( AfxGetApp()->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) )
{
return TRUE;
}
return FALSE;
}