Commit e9bae2cf authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

user32: Block TrackPopupMenu if menu is already active.

parent 2e5d1f19
...@@ -3270,6 +3270,12 @@ static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags) ...@@ -3270,6 +3270,12 @@ static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
HideCaret(0); HideCaret(0);
/* This makes the menus of applications built with Delphi work.
* It also enables menus to be displayed in more than one window,
* but there are some bugs left that need to be fixed in this case.
*/
if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
/* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
if (!(wFlags & TPM_NONOTIFY)) if (!(wFlags & TPM_NONOTIFY))
SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 ); SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
...@@ -3283,13 +3289,7 @@ static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags) ...@@ -3283,13 +3289,7 @@ static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
* menu sizes will be recalculated once the menu created/shown. * menu sizes will be recalculated once the menu created/shown.
*/ */
} }
/* This makes the menus of applications built with Delphi work.
* It also enables menus to be displayed in more than one window,
* but there are some bugs left that need to be fixed in this case.
*/
if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
return TRUE; return TRUE;
} }
/*********************************************************************** /***********************************************************************
...@@ -3393,6 +3393,7 @@ track_menu: ...@@ -3393,6 +3393,7 @@ track_menu:
BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y, BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
HWND hWnd, LPTPMPARAMS lpTpm ) HWND hWnd, LPTPMPARAMS lpTpm )
{ {
POPUPMENU *menu;
BOOL ret = FALSE; BOOL ret = FALSE;
TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n", TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
...@@ -3402,12 +3403,18 @@ BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y, ...@@ -3402,12 +3403,18 @@ BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
/* Parameter check */ /* Parameter check */
/* FIXME: this check is performed several times, here and in the called /* FIXME: this check is performed several times, here and in the called
functions. That could be optimized */ functions. That could be optimized */
if (!MENU_GetMenu( hMenu )) if (!(menu = MENU_GetMenu( hMenu )))
{ {
SetLastError( ERROR_INVALID_MENU_HANDLE ); SetLastError( ERROR_INVALID_MENU_HANDLE );
return FALSE; return FALSE;
} }
if (IsWindow(menu->hWnd))
{
SetLastError( ERROR_POPUP_ALREADY_ACTIVE );
return FALSE;
}
MENU_InitTracking(hWnd, hMenu, TRUE, wFlags); MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
/* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
......
...@@ -357,7 +357,7 @@ static void test_subpopup_locked_by_menu(void) ...@@ -357,7 +357,7 @@ static void test_subpopup_locked_by_menu(void)
ret = IsMenu( hsubmenu); ret = IsMenu( hsubmenu);
ok( ret , "Menu handle is not valid\n"); ok( ret , "Menu handle is not valid\n");
SetLastError( 0xdeadbeef); SetLastError( 0xdeadbeef);
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
if( ret == (itemid & 0xffff)) { if( ret == (itemid & 0xffff)) {
win_skip("not on 16 bit menu subsystem\n"); win_skip("not on 16 bit menu subsystem\n");
DestroyMenu( hsubmenu); DestroyMenu( hsubmenu);
...@@ -384,7 +384,7 @@ static void test_subpopup_locked_by_menu(void) ...@@ -384,7 +384,7 @@ static void test_subpopup_locked_by_menu(void)
ok( !ret , "Menu handle should be invalid\n"); ok( !ret , "Menu handle should be invalid\n");
/* but TrackPopupMenu still works! */ /* but TrackPopupMenu still works! */
SetLastError( 0xdeadbeef); SetLastError( 0xdeadbeef);
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
gle = GetLastError(); gle = GetLastError();
todo_wine { todo_wine {
ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle);
...@@ -425,7 +425,7 @@ static void test_menu_ownerdraw(void) ...@@ -425,7 +425,7 @@ static void test_menu_ownerdraw(void)
MOD_maxid = k-1; MOD_maxid = k-1;
assert( k <= sizeof(MOD_rc)/sizeof(RECT)); assert( k <= sizeof(MOD_rc)/sizeof(RECT));
/* display the menu */ /* display the menu */
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
/* columns have a 4 pixel gap between them */ /* columns have a 4 pixel gap between them */
ok( MOD_rc[0].right + 4 == MOD_rc[2].left, ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
...@@ -449,7 +449,7 @@ static void test_menu_ownerdraw(void) ...@@ -449,7 +449,7 @@ static void test_menu_ownerdraw(void)
leftcol= MOD_rc[0].left; leftcol= MOD_rc[0].left;
ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0); ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
/* display the menu */ /* display the menu */
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
/* left should be 4 pixels less now */ /* left should be 4 pixels less now */
ok( leftcol == MOD_rc[0].left + 4, ok( leftcol == MOD_rc[0].left + 4,
"columns should be 4 pixels to the left (actual %d).\n", "columns should be 4 pixels to the left (actual %d).\n",
...@@ -562,7 +562,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, ...@@ -562,7 +562,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt,
ReleaseDC( hwnd, hdc); ReleaseDC( hwnd, hdc);
} }
if(ispop) if(ispop)
ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
else { else {
ret = SetMenu( hwnd, hmenu); ret = SetMenu( hwnd, hmenu);
ok(ret, "SetMenu failed with error %d\n", GetLastError()); ok(ret, "SetMenu failed with error %d\n", GetLastError());
...@@ -2032,6 +2032,12 @@ static void test_menu_input(void) { ...@@ -2032,6 +2032,12 @@ static void test_menu_input(void) {
HANDLE hThread, hWnd; HANDLE hThread, hWnd;
DWORD tid; DWORD tid;
if (!pSendInput)
{
win_skip("SendInput is not available\n");
return;
}
wclass.lpszClassName = "MenuTestClass"; wclass.lpszClassName = "MenuTestClass";
wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.style = CS_HREDRAW | CS_VREDRAW;
wclass.lpfnWndProc = WndProc; wclass.lpfnWndProc = WndProc;
...@@ -2670,6 +2676,12 @@ static void test_menu_getmenuinfo(void) ...@@ -2670,6 +2676,12 @@ static void test_menu_getmenuinfo(void)
BOOL ret; BOOL ret;
DWORD gle; DWORD gle;
if (!pGetMenuInfo)
{
win_skip("GetMenuInfo is not available\n");
return;
}
/* create a menu */ /* create a menu */
hmenu = CreateMenu(); hmenu = CreateMenu();
assert( hmenu); assert( hmenu);
...@@ -2716,6 +2728,12 @@ static void test_menu_setmenuinfo(void) ...@@ -2716,6 +2728,12 @@ static void test_menu_setmenuinfo(void)
BOOL ret; BOOL ret;
DWORD gle; DWORD gle;
if (!pGetMenuInfo || !pSetMenuInfo)
{
win_skip("Get/SetMenuInfo are not available\n");
return;
}
/* create a menu with a submenu */ /* create a menu with a submenu */
hmenu = CreateMenu(); hmenu = CreateMenu();
hsubmenu = CreateMenu(); hsubmenu = CreateMenu();
...@@ -2868,7 +2886,7 @@ static void test_menu_trackpopupmenu(void) ...@@ -2868,7 +2886,7 @@ static void test_menu_trackpopupmenu(void)
/* start with an invalid menu handle */ /* start with an invalid menu handle */
gle = 0xdeadbeef; gle = 0xdeadbeef;
gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
ret = MyTrackPopupMenu( Ex, NULL, 0x100, 100,100, hwnd, NULL); ret = MyTrackPopupMenu( Ex, NULL, TPM_RETURNCMD, 100,100, hwnd, NULL);
gle = GetLastError(); gle = GetLastError();
ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : "");
ok( gle == ERROR_INVALID_MENU_HANDLE ok( gle == ERROR_INVALID_MENU_HANDLE
...@@ -2884,7 +2902,7 @@ static void test_menu_trackpopupmenu(void) ...@@ -2884,7 +2902,7 @@ static void test_menu_trackpopupmenu(void)
/* another one but not NULL */ /* another one but not NULL */
gle = 0xdeadbeef; gle = 0xdeadbeef;
gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, 0x100, 100,100, hwnd, NULL); ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, TPM_RETURNCMD, 100,100, hwnd, NULL);
gle = GetLastError(); gle = GetLastError();
ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : "");
ok( gle == ERROR_INVALID_MENU_HANDLE ok( gle == ERROR_INVALID_MENU_HANDLE
...@@ -2900,7 +2918,7 @@ static void test_menu_trackpopupmenu(void) ...@@ -2900,7 +2918,7 @@ static void test_menu_trackpopupmenu(void)
/* now a somewhat successful call */ /* now a somewhat successful call */
gle = 0xdeadbeef; gle = 0xdeadbeef;
gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL);
gle = GetLastError(); gle = GetLastError();
ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret);
ok( gle == NO_ERROR ok( gle == NO_ERROR
...@@ -2918,7 +2936,7 @@ static void test_menu_trackpopupmenu(void) ...@@ -2918,7 +2936,7 @@ static void test_menu_trackpopupmenu(void)
ok( ret, "AppendMenA has failed!\n"); ok( ret, "AppendMenA has failed!\n");
gle = 0xdeadbeef; gle = 0xdeadbeef;
gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL);
gle = GetLastError(); gle = GetLastError();
ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret);
ok( gle == NO_ERROR ok( gle == NO_ERROR
...@@ -2937,6 +2955,53 @@ static void test_menu_trackpopupmenu(void) ...@@ -2937,6 +2955,53 @@ static void test_menu_trackpopupmenu(void)
DestroyWindow(hwnd); DestroyWindow(hwnd);
} }
static HMENU g_hmenu;
static LRESULT WINAPI menu_track_again_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_ENTERMENULOOP:
{
BOOL ret;
/* try a recursive call */
SetLastError(0xdeadbeef);
ret = TrackPopupMenu(g_hmenu, 0, 100, 100, 0, hwnd, NULL);
ok(ret == FALSE, "got %d\n", ret);
ok(GetLastError() == ERROR_POPUP_ALREADY_ACTIVE ||
broken(GetLastError() == 0xdeadbeef) /* W9x */, "got %d\n", GetLastError());
/* exit menu modal loop
* ( A SendMessage does not work on NT3.51 here ) */
return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
static void test_menu_trackagain(void)
{
HWND hwnd;
BOOL ret;
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_track_again_wnd_proc);
g_hmenu = CreatePopupMenu();
ok(g_hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
ret = TrackPopupMenu( g_hmenu, 0, 100, 100, 0, hwnd, NULL);
todo_wine ok(ret == FALSE, "got %d\n", ret);
DestroyMenu(g_hmenu);
DestroyWindow(hwnd);
}
/* test handling of WM_CANCELMODE messages */ /* test handling of WM_CANCELMODE messages */
static int g_got_enteridle; static int g_got_enteridle;
static HWND g_hwndtosend; static HWND g_hwndtosend;
...@@ -2997,14 +3062,14 @@ static void test_menu_cancelmode(void) ...@@ -2997,14 +3062,14 @@ static void test_menu_cancelmode(void)
*/ */
/* menu owner is top level window */ /* menu owner is top level window */
g_hwndtosend = hwnd; g_hwndtosend = hwnd;
ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwnd, NULL); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
todo_wine { todo_wine {
ok( g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); ok( g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
} }
ok( g_got_enteridle < 2, "received %d WM_ENTERIDLE messages, should be less than 2\n", g_got_enteridle); ok( g_got_enteridle < 2, "received %d WM_ENTERIDLE messages, should be less than 2\n", g_got_enteridle);
/* menu owner is child window */ /* menu owner is child window */
g_hwndtosend = hwndchild; g_hwndtosend = hwndchild;
ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwndchild, NULL); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL);
todo_wine { todo_wine {
ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
} }
...@@ -3012,7 +3077,7 @@ static void test_menu_cancelmode(void) ...@@ -3012,7 +3077,7 @@ static void test_menu_cancelmode(void)
/* now send the WM_CANCELMODE messages to the WRONG window */ /* now send the WM_CANCELMODE messages to the WRONG window */
/* those should fail ( to have any effect) */ /* those should fail ( to have any effect) */
g_hwndtosend = hwnd; g_hwndtosend = hwnd;
ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwndchild, NULL); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL);
ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle); ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle);
/* cleanup */ /* cleanup */
DestroyMenu( menu); DestroyMenu( menu);
...@@ -3204,20 +3269,14 @@ START_TEST(menu) ...@@ -3204,20 +3269,14 @@ START_TEST(menu)
test_subpopup_locked_by_menu(); test_subpopup_locked_by_menu();
test_menu_ownerdraw(); test_menu_ownerdraw();
test_menu_bmp_and_string(); test_menu_bmp_and_string();
/* test Get/SetMenuInfo if available */ test_menu_getmenuinfo();
if( pGetMenuInfo && pSetMenuInfo) { test_menu_setmenuinfo();
test_menu_getmenuinfo(); test_menu_input();
test_menu_setmenuinfo();
} else
win_skip("Get/SetMenuInfo are not available\n");
if( !pSendInput)
win_skip("SendInput is not available\n");
else
test_menu_input();
test_menu_flags(); test_menu_flags();
test_menu_hilitemenuitem(); test_menu_hilitemenuitem();
test_menu_trackpopupmenu(); test_menu_trackpopupmenu();
test_menu_trackagain();
test_menu_cancelmode(); test_menu_cancelmode();
test_menu_maxdepth(); test_menu_maxdepth();
test_menu_circref(); test_menu_circref();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment