diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 8f8a7b408e2..fc6f981b927 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -3447,6 +3447,40 @@ track_menu: MENU_ExitTracking( hwnd ); } +/********************************************************************** + * TrackPopupMenuEx (USER32.@) + */ +BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y, + HWND hWnd, LPTPMPARAMS lpTpm ) +{ + BOOL ret = FALSE; + + TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n", + hMenu, wFlags, x, y, hWnd, lpTpm, + lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" ); + + /* Parameter check */ + /* FIXME: this check is performed several times, here and in the called + functions. That could be optimized */ + if (!MENU_GetMenu( hMenu )) + { + SetLastError( ERROR_INVALID_MENU_HANDLE ); + return FALSE; + } + + MENU_InitTracking(hWnd, hMenu, TRUE, wFlags); + + /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ + if (!(wFlags & TPM_NONOTIFY)) + SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0); + + if (MENU_ShowPopup( hWnd, hMenu, 0, wFlags, x, y, 0, 0 )) + ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, + lpTpm ? &lpTpm->rcExclude : NULL ); + MENU_ExitTracking(hWnd); + + return ret; +} /********************************************************************** * TrackPopupMenu (USER32.@) @@ -3456,35 +3490,9 @@ track_menu: * */ BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y, - INT nReserved, HWND hWnd, const RECT *lpRect ) + INT nReserved, HWND hWnd, const RECT *lpRect ) { - BOOL ret = FALSE; - - TRACE("hmenu %p flags %04x (%d,%d) reserved %d hwnd %p rect %s\n", - hMenu, wFlags, x, y, nReserved, hWnd, wine_dbgstr_rect(lpRect)); - - MENU_InitTracking(hWnd, hMenu, TRUE, wFlags); - - /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ - if (!(wFlags & TPM_NONOTIFY)) - SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0); - - if (MENU_ShowPopup( hWnd, hMenu, 0, wFlags, x, y, 0, 0 )) - ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect ); - MENU_ExitTracking(hWnd); - - return ret; -} - -/********************************************************************** - * TrackPopupMenuEx (USER32.@) - */ -BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y, - HWND hWnd, LPTPMPARAMS lpTpm ) -{ - FIXME("not fully implemented\n" ); - return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd, - lpTpm ? &lpTpm->rcExclude : NULL ); + return TrackPopupMenuEx( hMenu, wFlags, x, y, hWnd, NULL); } /*********************************************************************** diff --git a/dlls/user32/tests/menu.c b/dlls/user32/tests/menu.c index 747970f16ba..06fa35018fa 100644 --- a/dlls/user32/tests/menu.c +++ b/dlls/user32/tests/menu.c @@ -140,12 +140,25 @@ static int MOD_odheight; static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}, {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}}; static int MOD_GotDrawItemMsg = FALSE; +static int gflag_initmenupopup, + gflag_entermenuloop, + gflag_initmenu; + /* wndproc used by test_menu_ownerdraw() */ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { + case WM_INITMENUPOPUP: + gflag_initmenupopup++; + break; + case WM_ENTERMENULOOP: + gflag_entermenuloop++; + break; + case WM_INITMENU: + gflag_initmenu++; + break; case WM_MEASUREITEM: { MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam; @@ -2628,6 +2641,113 @@ static void test_menu_setmenuinfo(void) return; } +/* little func to easy switch either TrackPopupMenu() or TrackPopupMenuEx() */ +static DWORD MyTrackPopupMenu( int ex, HMENU hmenu, UINT flags, INT x, INT y, HWND hwnd, LPTPMPARAMS ptpm) +{ + return ex + ? TrackPopupMenuEx( hmenu, flags, x, y, hwnd, ptpm) + : TrackPopupMenu( hmenu, flags, x, y, 0, hwnd, NULL); +} + +/* some TrackPopupMenu and TrackPopupMenuEx tests */ +/* the LastError values differ between NO_ERROR and invalid handle */ +/* between all windows versions tested. The first value is that valid on XP */ +/* Vista was the only that made returned different error values */ +/* between the TrackPopupMenu and TrackPopupMenuEx functions */ +static void test_menu_trackpopupmenu(void) +{ + BOOL ret; + HMENU hmenu; + DWORD gle; + int Ex; + HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, + NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + if (!hwnd) return; + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); + for( Ex = 0; Ex < 2; Ex++) + { + hmenu = CreatePopupMenu(); + ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + if (!hmenu) + { + DestroyWindow(hwnd); + return; + } + /* display the menu */ + /* start with an invalid menu handle */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, NULL, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); + ok( gle == ERROR_INVALID_MENU_HANDLE + || broken (gle == 0xdeadbeef) /* win95 */ + || broken (gle == NO_ERROR) /* win98/ME */ + ,"TrackPopupMenu%s error got %u expected %u\n", + Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); + ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), + "got unexpected message(s)%s%s%s\n", + gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + gflag_entermenuloop ? "WM_INITMENULOOP ": "", + gflag_initmenu ? "WM_INITMENU": ""); + /* another one but not NULL */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); + ok( gle == ERROR_INVALID_MENU_HANDLE + || broken (gle == 0xdeadbeef) /* win95 */ + || broken (gle == NO_ERROR) /* win98/ME */ + ,"TrackPopupMenu%s error got %u expected %u\n", + Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); + ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), + "got unexpected message(s)%s%s%s\n", + gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + gflag_entermenuloop ? "WM_INITMENULOOP ": "", + gflag_initmenu ? "WM_INITMENU": ""); + /* now a somewhat successfull call */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); + ok( gle == NO_ERROR + || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k */ + || broken (gle == 0xdeadbeef) /* win95 */ + ,"TrackPopupMenu%s error got %u expected %u or %u\n", + Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); + ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, + "missed expected message(s)%s%s%s\n", + !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + !gflag_entermenuloop ? "WM_INITMENULOOP ": "", + !gflag_initmenu ? "WM_INITMENU": ""); + /* and another */ + ret = AppendMenuA( hmenu, MF_STRING, 1, "winetest"); + ok( ret, "AppendMenA has failed!\n"); + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); + ok( gle == NO_ERROR + || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k and Vista in the TrackPopupMenuEx case */ + || broken (gle == 0xdeadbeef) /* win95 */ + ,"TrackPopupMenu%s error got %u expected %u or %u\n", + Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); + ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, + "missed expected message(s)%s%s%s\n", + !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + !gflag_entermenuloop ? "WM_INITMENULOOP ": "", + !gflag_initmenu ? "WM_INITMENU": ""); + DestroyMenu(hmenu); + } + /* clean up */ + DestroyWindow(hwnd); +} + START_TEST(menu) { init_function_pointers(); @@ -2663,4 +2783,5 @@ START_TEST(menu) test_menu_flags(); test_menu_hilitemenuitem(); + test_menu_trackpopupmenu(); }