user32: Add workaround for removed SC_TASKLIST system menu item.

Word 95 assumes that the item exists.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2015-11-19 20:54:34 +09:00
parent 8693805431
commit c82626a4c1
2 changed files with 209 additions and 7 deletions

View file

@ -4001,7 +4001,12 @@ BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
else
TRACE("%p %d %04x %04lx %p\n", hMenu, pos, flags, id, str );
if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
if (!(item = MENU_FindItem( &hMenu, &pos, flags )))
{
/* workaround for Word 95: pretend that SC_TASKLIST item exists */
if (pos == SC_TASKLIST && !(flags & MF_BYPOSITION)) return TRUE;
return FALSE;
}
MENU_GetMenu(hMenu)->Height = 0; /* force size recalculate */
MENU_mnu2mnuii( flags, id, str, &mii);
return SetMenuItemInfo_common( item, &mii, TRUE);
@ -4873,14 +4878,20 @@ static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
const MENUITEMINFOA *lpmii)
{
MENUITEM *menuitem;
MENUITEMINFOW mii;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
&mii, FALSE);
if (!(menuitem = MENU_FindItem( &hmenu, &item, bypos? MF_BYPOSITION : 0 )))
{
/* workaround for Word 95: pretend that SC_TASKLIST item exists */
if (item == SC_TASKLIST && !bypos) return TRUE;
return FALSE;
}
return SetMenuItemInfo_common( menuitem, &mii, FALSE );
}
/**********************************************************************
@ -4889,13 +4900,19 @@ BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
const MENUITEMINFOW *lpmii)
{
MENUITEM *menuitem;
MENUITEMINFOW mii;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
if (!MENU_NormalizeMenuItemInfoStruct( lpmii, &mii )) return FALSE;
return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
&item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
if (!(menuitem = MENU_FindItem( &hmenu, &item, bypos? MF_BYPOSITION : 0 )))
{
/* workaround for Word 95: pretend that SC_TASKLIST item exists */
if (item == SC_TASKLIST && !bypos) return TRUE;
return FALSE;
}
return SetMenuItemInfo_common( menuitem, &mii, TRUE );
}
/**********************************************************************

View file

@ -405,6 +405,191 @@ static void test_getmenubarinfo(void)
DestroyWindow(hwnd);
}
static void test_system_menu(void)
{
WCHAR testW[] = {'t','e','s','t',0};
BOOL ret;
HMENU menu;
HWND hwnd;
MENUITEMINFOA info;
MENUITEMINFOW infoW;
char buffer[80];
char found[0x200];
int i, res;
hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
menu = GetSystemMenu( hwnd, FALSE );
ok( menu != NULL, "no system menu\n" );
for (i = 0xf000; i < 0xf200; i++)
{
memset( &info, 0xcc, sizeof(info) );
info.cbSize = sizeof(info);
info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
info.dwTypeData = buffer;
info.cch = sizeof( buffer );
ret = GetMenuItemInfoA( menu, i, FALSE, &info );
if (ret) trace( "found %x: '%s'\n", i, buffer );
switch (i)
{
case SC_RESTORE:
case SC_SIZE:
case SC_MOVE:
case SC_MINIMIZE:
case SC_MAXIMIZE:
case SC_CLOSE:
ok( ret, "%x menu item not found\n", i );
break;
case SC_SCREENSAVE+1: /* used for the 'About Wine' entry, don't test */
break;
default:
ok( !ret, "%x menu item found\n", i );
break;
}
found[i - 0xf000] = ret;
}
for (i = 0xf000; i < 0xf200; i++)
{
res = CheckMenuItem( menu, i, 0 );
if (res == -1) ok( !found[i - 0xf000], "could not check existent item %x\n", i );
else ok( found[i - 0xf000], "could check non-existent item %x\n", i );
res = EnableMenuItem( menu, i, 0 );
if (res == -1) ok( !found[i - 0xf000], "could not enable existent item %x\n", i );
else ok( found[i - 0xf000], "could enable non-existent item %x\n", i );
res = GetMenuState( menu, i, 0 );
if (res == -1) ok( !found[i - 0xf000], "could not get state existent item %x\n", i );
else ok( found[i - 0xf000], "could get state of non-existent item %x\n", i );
if (!found[i - 0xf000]) /* don't remove the existing ones */
{
ret = RemoveMenu( menu, i, 0 );
ok( !ret, "could remove non-existent item %x\n", i );
}
ret = ModifyMenuA( menu, i, 0, i, "test" );
if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" );
else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i );
else ok( found[i - 0xf000], "could modify non-existent item %x\n", i );
ret = ModifyMenuW( menu, i, 0, i, testW );
if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" );
else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i );
else ok( found[i - 0xf000], "could modify non-existent item %x\n", i );
ret = ModifyMenuA( menu, i, MF_BYPOSITION, i, "test" );
ok( !ret, "could modify non-existent item %x\n", i );
strcpy( buffer, "test" );
memset( &info, 0xcc, sizeof(info) );
info.cbSize = sizeof(info);
info.fMask = MIIM_STRING | MIIM_ID;
info.wID = i;
info.dwTypeData = buffer;
info.cch = strlen( buffer );
ret = SetMenuItemInfoA( menu, i, FALSE, &info );
if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" );
else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i );
else ok( found[i - 0xf000], "could set non-existent item %x\n", i );
ret = SetMenuItemInfoA( menu, i, TRUE, &info );
ok( !ret, "could modify non-existent item %x\n", i );
memset( &infoW, 0xcc, sizeof(infoW) );
infoW.cbSize = sizeof(infoW);
infoW.fMask = MIIM_STRING | MIIM_ID;
infoW.wID = i;
infoW.dwTypeData = testW;
infoW.cch = lstrlenW( testW );
ret = SetMenuItemInfoW( menu, i, FALSE, &infoW );
if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" );
else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i );
else ok( found[i - 0xf000], "could set non-existent item %x\n", i );
ret = SetMenuItemInfoW( menu, i, TRUE, &infoW );
ok( !ret, "could modify non-existent item %x\n", i );
}
/* confirm that SC_TASKLIST still does not exist */
for (i = 0xf000; i < 0xf200; i++)
{
memset( &info, 0xcc, sizeof(info) );
info.cbSize = sizeof(info);
info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
info.dwTypeData = buffer;
info.cch = sizeof( buffer );
ret = GetMenuItemInfoA( menu, i, FALSE, &info );
switch (i)
{
case SC_RESTORE:
case SC_SIZE:
case SC_MOVE:
case SC_MINIMIZE:
case SC_MAXIMIZE:
case SC_CLOSE:
ok( ret, "%x menu item not found\n", i );
break;
case SC_SCREENSAVE+1: /* used for the 'About Wine' entry, don't test */
break;
default:
ok( !ret, "%x menu item found\n", i );
break;
}
}
/* now a normal (non-system) menu */
menu = CreateMenu();
ok( menu != NULL, "CreateMenu failed with error %d\n", GetLastError() );
res = CheckMenuItem( menu, SC_TASKLIST, 0 );
ok( res == -1, "CheckMenuItem succeeded\n" );
res = EnableMenuItem( menu, SC_TASKLIST, 0 );
ok( res == -1, "EnableMenuItem succeeded\n" );
res = GetMenuState( menu, SC_TASKLIST, 0 );
ok( res == -1, "GetMenuState succeeded\n" );
ret = RemoveMenu( menu, SC_TASKLIST, 0 );
ok( !ret, "RemoveMenu succeeded\n" );
ret = ModifyMenuA( menu, SC_TASKLIST, 0, SC_TASKLIST, "test" );
ok( ret, "ModifyMenuA failed err %d\n", GetLastError() );
ret = ModifyMenuW( menu, SC_TASKLIST, 0, SC_TASKLIST, testW );
ok( ret, "ModifyMenuW failed err %d\n", GetLastError() );
ret = ModifyMenuA( menu, SC_TASKLIST-1, 0, SC_TASKLIST, "test" );
ok( !ret, "ModifyMenu succeeded on SC_TASKLIST-1\n" );
strcpy( buffer, "test" );
memset( &info, 0xcc, sizeof(info) );
info.cbSize = sizeof(info);
info.fMask = MIIM_STRING | MIIM_ID;
info.wID = SC_TASKLIST;
info.dwTypeData = buffer;
info.cch = strlen( buffer );
ret = SetMenuItemInfoA( menu, SC_TASKLIST, FALSE, &info );
ok( ret, "failed to set SC_TASKLIST\n" );
ret = SetMenuItemInfoA( menu, SC_TASKLIST+1, FALSE, &info );
ok( !ret, "succeeded setting SC_TASKLIST+1\n" );
ret = SetMenuItemInfoA( menu, SC_TASKLIST, TRUE, &info );
ok( !ret, "succeeded setting by position\n" );
memset( &infoW, 0xcc, sizeof(infoW) );
infoW.cbSize = sizeof(infoW);
infoW.fMask = MIIM_STRING | MIIM_ID;
infoW.wID = SC_TASKLIST;
infoW.dwTypeData = testW;
infoW.cch = lstrlenW( testW );
ret = SetMenuItemInfoW( menu, SC_TASKLIST, FALSE, &infoW );
ok( ret, "failed to set SC_TASKLIST\n" );
ret = SetMenuItemInfoW( menu, SC_TASKLIST+1, FALSE, &infoW );
ok( !ret, "succeeded setting SC_TASKLIST+1\n" );
ret = SetMenuItemInfoW( menu, SC_TASKLIST, TRUE, &infoW );
ok( !ret, "succeeded setting by position\n" );
DestroyMenu( menu );
DestroyWindow( hwnd );
}
/* demonstrates that windows locks the menu object so that it is still valid
* even after a client calls DestroyMenu on it */
static void test_menu_locked_by_window(void)
@ -4123,6 +4308,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */
START_TEST(menu)
{
init_function_pointers();
register_menu_check_class();
/* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't
* handle that.
@ -4136,10 +4322,9 @@ START_TEST(menu)
test_menu_resource_layout();
test_InsertMenu();
test_menualign();
test_system_menu();
}
register_menu_check_class();
test_menu_locked_by_window();
test_subpopup_locked_by_menu();
test_menu_ownerdraw();