TrackPopupMenu (MSDN) の TPM_NONOTIFY フラグの説明には、「ユーザーが 1 つのメニュー項目をクリックしたとき、この関数は通知メッセージを送信しません。」とありますが、挙動が変だったので実験してみました。
※ コンパイルオプションの例: cl /EHsc 1.cpp
#include <Windows.h>
#include <Tchar.h>
#include <iostream>
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Gdi32.lib")
using namespace std;
static int mode = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU menu = NULL;
static bool onTrackPopupMenu = false;
if (onTrackPopupMenu && msg != WM_ENTERIDLE)
cout << "msg(hex): " << hex << msg << endl;
BOOL ok;
switch (msg)
{
case WM_COMMAND:
cout << "WM_COMMAND: " << LOWORD(wParam) << endl;
break;
case WM_CREATE:
menu = CreatePopupMenu();
if (!menu)
cerr << "CreatePopupMenu failed" << endl;
{
MENUITEMINFO item;
ZeroMemory(&item, sizeof(item));
item.cbSize = sizeof(item);
item.fMask = MIIM_FTYPE|MIIM_ID|MIIM_STRING;
item.fType = MFT_STRING;
item.wID = 1;
item.dwTypeData = (LPTSTR)_T("TEST");
ok = InsertMenuItem(menu, 0, TRUE, &item);
if (!ok)
cerr << "InsertMenuItem failed" << endl;
}
break;
case WM_DESTROY:
DestroyMenu(menu);
PostQuitMessage(0);
break;
case WM_RBUTTONDOWN:
{
UINT flags = TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON;
switch (mode)
{
case 0:
cout << "[START] NONE" << endl;
break;
case 1:
flags |= TPM_RETURNCMD;
cout << "[START] TPM_RETURNCMD" << endl;
break;
case 2:
flags |= TPM_NONOTIFY;
cout << "[START] TPM_NONOTIFY" << endl;
break;
case 3:
flags |= TPM_RETURNCMD;
flags |= TPM_NONOTIFY;
cout << "[START] TPM_RETURNCMD|TPM_NONOTIFY" << endl;
break;
}
DWORD posW = GetMessagePos();
int x = (int)LOWORD(posW);
int y = (int)HIWORD(posW);
onTrackPopupMenu = true;
ok = TrackPopupMenu(menu, flags, x, y, 0, hWnd, NULL);
onTrackPopupMenu = false;
if (!ok)
cerr << "TrackPopupMenu failed: " << GetLastError() << endl;
}
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
void main(int argc, char *argv[])
{
if (argc > 1)
mode = (int)(argv[1][0] - '0');
HINSTANCE hInst = GetModuleHandle(NULL);
LPCTSTR className = _T("SssTestClass");
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = className;
if (!RegisterClassEx(&wc))
{
cerr << "RegisterClass failed." << endl;
return;
}
HWND hwnd = CreateWindow(
className, _T("TrackPopupMenu Test"), WS_OVERLAPPEDWINDOW,
0, 0, 640, 480, NULL, NULL, hInst, NULL
);
if (!hwnd)
{
cerr << "CreateWindow failed." << endl;
return;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
[START] NONE msg(hex): 211 msg(hex): 20 msg(hex): 116 msg(hex): 117 msg(hex): 93 msg(hex): 94 msg(hex): 11f msg(hex): 215 msg(hex): 125 msg(hex): 11f msg(hex): 212 msg(hex): 84 WM_COMMAND: 1
上の出力結果は、コマンドラインオプション無しで実行するか、オプションとして "0" を指定して実行したときのものです。実験方法は、実行するとウィンドウが表示されるので、右クリックメニューから「TEST」を選択した後に×ボタンで閉じます。
この結果から、フラグに
TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON
を指定した場合、TrackPopupMenu 呼び出し中に、以下のメッセージが発生したことがわかります。
※ 実は、WM_ENTERIDLE も何度も発生しますが、重要じゃないので、プログラムで出力をスキップしてます。WndProc 内の 4 行目参照。
当然ながら、WM_COMMAND メッセージも発生することがわかります※。
※ WM_COMMAND の処理が走るのは、TrackPopupMenu の呼び出し後です。おそらく、TrackPopupMenu の中で、PostMessage されてるんでしょうね。
[START] TPM_RETURNCMD msg(hex): 211 msg(hex): 20 msg(hex): 116 msg(hex): 117 msg(hex): 93 msg(hex): 94 msg(hex): 11f msg(hex): 215 msg(hex): 125 msg(hex): 11f msg(hex): 212 msg(hex): 84
上の出力結果は、コマンドラインオプションとして "1" を指定して実行したときのものです。実験方法は、同じで、メニューで選択して終了します。TPM_RETURNCMD を指定した場合、WM_COMMAND メッセージが発生しなくなることがわかります。
TPM_NONOTIFY フラグの説明には、「ユーザーが 1 つのメニュー項目をクリックしたとき、この関数は通知メッセージを送信しません。」とあるので、TPM_RETURNCMD と同時に指定すべきフラグのように感じますが、この実験によって、その必要が無いことがわかります。WM_COMMAND が発生しないからです。
[START] TPM_NONOTIFY msg(hex): 20 msg(hex): 93 msg(hex): 94 msg(hex): 11f msg(hex): 215 msg(hex): 11f msg(hex): 84 WM_COMMAND: 1
上の出力結果は、コマンドラインオプションとして "2" を指定して実行したときのものです。実験方法は、同じで、メニューで選択して終了します。TPM_NONOTIFY を指定した場合、以下のメッセージが発生しなくなることがわかります。
奇妙なことに、 WM_MENUSELECT (0x11f) は発生したままです。また、WM_COMMAND メッセージも発生しています。この結果から、「ユーザーが 1 つのメニュー項目をクリックしたとき、この関数は通知メッセージを送信しません。」の説明はかなり誤解をまねく表現だということがわかります。「ユーザーがメニュー項目をクリックしたときに発生する "副次的な" 通知メッセージを送信しません。」とかだったら、少しはよかったかもしれませんね。
[START] TPM_RETURNCMD|TPM_NONOTIFY msg(hex): 20 msg(hex): 93 msg(hex): 94 msg(hex): 11f msg(hex): 215 msg(hex): 11f msg(hex): 84
上の出力結果は、コマンドラインオプションとして "3" を指定して実行したときのものです。実験方法は、同じで、メニューで選択して終了します。TPM_NONTOFY に関係なく、TPM_RETURNCMD を指定すると、WM_COMMAND が発生しなくなることがわかりますが、それは既にわかっていることなので、蛇足でしたね。
このサイトのページへのリンクは自由に行っていただいてかまいません。
このサイトで公開している全ての画像、プログラム、文書の無断転載を禁止します。
ここをクリック
すると表示されるページから作者へメールで連絡できます。