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 が発生しなくなることがわかりますが、それは既にわかっていることなので、蛇足でしたね。
このサイトのページへのリンクは自由に行っていただいてかまいません。
このサイトで公開している全ての画像、プログラム、文書の無断転載を禁止します。
ここをクリック
すると表示されるページから作者へメールで連絡できます。