1 /* 2 * Unit tests for menus 3 * 4 * Copyright 2005 Robert Shearman 5 * Copyright 2007 Dmitry Timoshkov 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 static ATOM atomMenuCheckClass; 25 26 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO); 27 static BOOL (WINAPI *pGetMenuBarInfo)(HWND,LONG,LONG,PMENUBARINFO); 28 static UINT (WINAPI *pSendInput)(UINT, INPUT*, size_t); 29 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO); 30 static BOOL (WINAPI *pEndMenu) (void); 31 32 static void init_function_pointers(void) 33 { 34 HMODULE hdll = GetModuleHandleA("user32"); 35 36 #define GET_PROC(func) \ 37 p ## func = (void*)GetProcAddress(hdll, #func); \ 38 if(!p ## func) \ 39 trace("GetProcAddress(%s) failed\n", #func); 40 41 GET_PROC(GetMenuInfo) 42 GET_PROC(GetMenuBarInfo) 43 GET_PROC(SendInput) 44 GET_PROC(SetMenuInfo) 45 GET_PROC(EndMenu) 46 47 #undef GET_PROC 48 } 49 50 static BOOL correct_behavior(void) 51 { 52 HMENU hmenu; 53 MENUITEMINFOA info; 54 BOOL rc; 55 56 hmenu = CreateMenu(); 57 58 memset(&info, 0, sizeof(MENUITEMINFOA)); 59 info.cbSize= sizeof(MENUITEMINFOA); 60 SetLastError(0xdeadbeef); 61 rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); 62 /* Win9x : 0xdeadbeef 63 * NT4 : ERROR_INVALID_PARAMETER 64 * >= W2K : ERROR_MENU_ITEM_NOT_FOUND 65 */ 66 if (!rc && GetLastError() != ERROR_MENU_ITEM_NOT_FOUND) 67 { 68 win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n"); 69 DestroyMenu(hmenu); 70 return FALSE; 71 } 72 73 DestroyMenu(hmenu); 74 return TRUE; 75 } 76 77 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 78 { 79 switch (msg) 80 { 81 case WM_ENTERMENULOOP: 82 /* mark window as having entered menu loop */ 83 SetWindowLongPtrA(hwnd, GWLP_USERDATA, TRUE); 84 /* exit menu modal loop 85 * ( A SendMessage does not work on NT3.51 here ) */ 86 return PostMessageA(hwnd, WM_CANCELMODE, 0, 0); 87 } 88 return DefWindowProcA(hwnd, msg, wparam, lparam); 89 } 90 91 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define 92 * our own type */ 93 typedef struct 94 { 95 DWORD type; 96 union 97 { 98 MOUSEINPUT mi; 99 KEYBDINPUT ki; 100 HARDWAREINPUT hi; 101 } u; 102 } TEST_INPUT; 103 104 /* globals to communicate between test and wndproc */ 105 106 static BOOL bMenuVisible; 107 static INT popmenu; 108 static BOOL got_input; 109 static HMENU hMenus[4]; 110 111 #define MOD_SIZE 10 112 #define MOD_NRMENUS 8 113 114 /* menu texts with their sizes */ 115 static struct { 116 LPCSTR text; 117 SIZE size; /* size of text up to any \t */ 118 SIZE sc_size; /* size of the short-cut */ 119 } MOD_txtsizes[] = { 120 { "Pinot &Noir" }, 121 { "&Merlot\bF4" }, 122 { "Shira&z\tAlt+S" }, 123 { "" }, 124 { NULL } 125 }; 126 127 static unsigned int MOD_maxid; 128 static RECT MOD_rc[MOD_NRMENUS]; 129 static int MOD_avec, MOD_hic; 130 static int MOD_odheight; 131 static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}, 132 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}}; 133 static BOOL MOD_GotDrawItemMsg = FALSE; 134 static int gflag_initmenupopup, 135 gflag_entermenuloop, 136 gflag_initmenu, 137 gflag_enteridle; 138 static WPARAM selectitem_wp; 139 static LPARAM selectitem_lp; 140 141 /* wndproc used by test_menu_ownerdraw() */ 142 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, 143 WPARAM wparam, LPARAM lparam) 144 { 145 static HMENU hmenupopup; 146 switch (msg) 147 { 148 case WM_INITMENUPOPUP: 149 gflag_initmenupopup++; 150 hmenupopup = (HMENU) wparam; 151 break; 152 case WM_ENTERMENULOOP: 153 gflag_entermenuloop++; 154 break; 155 case WM_INITMENU: 156 gflag_initmenu++; 157 break; 158 case WM_MEASUREITEM: 159 { 160 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam; 161 if (winetest_debug > 1) 162 trace("WM_MEASUREITEM received data %lx size %dx%d\n", 163 pmis->itemData, pmis->itemWidth, pmis->itemHeight); 164 ok( !wparam, "wrong wparam %lx\n", wparam ); 165 ok( pmis->CtlType == ODT_MENU, "wrong type %x\n", pmis->CtlType ); 166 MOD_odheight = pmis->itemHeight; 167 pmis->itemWidth = MODsizes[pmis->itemData].cx; 168 pmis->itemHeight = MODsizes[pmis->itemData].cy; 169 return TRUE; 170 } 171 case WM_DRAWITEM: 172 { 173 DRAWITEMSTRUCT * pdis; 174 TEXTMETRICA tm; 175 HPEN oldpen; 176 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 177 SIZE sz; 178 int i; 179 pdis = (DRAWITEMSTRUCT *) lparam; 180 if (winetest_debug > 1) { 181 RECT rc; 182 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc); 183 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %s itemrc: %s\n", 184 hwnd, pdis->hwndItem, pdis->itemData, pdis->itemID, 185 wine_dbgstr_rect(&pdis->rcItem), wine_dbgstr_rect(&rc)); 186 oldpen=SelectObject( pdis->hDC, GetStockObject( 187 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN)); 188 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top, 189 pdis->rcItem.right,pdis->rcItem.bottom ); 190 SelectObject( pdis->hDC, oldpen); 191 } 192 ok( !wparam, "wrong wparam %lx\n", wparam ); 193 ok( pdis->CtlType == ODT_MENU, "wrong type %x\n", pdis->CtlType ); 194 /* calculate widths of some menu texts */ 195 if( ! MOD_txtsizes[0].size.cx) 196 for(i = 0; MOD_txtsizes[i].text; i++) { 197 char buf[100], *p; 198 RECT rc={0,0,0,0}; 199 strcpy( buf, MOD_txtsizes[i].text); 200 if( ( p = strchr( buf, '\t'))) { 201 *p = '\0'; 202 DrawTextA( pdis->hDC, p + 1, -1, &rc, 203 DT_SINGLELINE|DT_CALCRECT); 204 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left; 205 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top; 206 } 207 DrawTextA( pdis->hDC, buf, -1, &rc, 208 DT_SINGLELINE|DT_CALCRECT); 209 MOD_txtsizes[i].size.cx= rc.right - rc.left; 210 MOD_txtsizes[i].size.cy= rc.bottom - rc.top; 211 } 212 213 if( pdis->itemData > MOD_maxid) return TRUE; 214 /* store the rectangle */ 215 MOD_rc[pdis->itemData] = pdis->rcItem; 216 /* calculate average character width */ 217 GetTextExtentPointA( pdis->hDC, chrs, 52, &sz ); 218 MOD_avec = (sz.cx + 26)/52; 219 GetTextMetricsA( pdis->hDC, &tm); 220 MOD_hic = tm.tmHeight; 221 MOD_GotDrawItemMsg = TRUE; 222 return TRUE; 223 } 224 case WM_ENTERIDLE: 225 { 226 gflag_enteridle++; 227 ok( lparam || broken(!lparam), /* win9x, nt4 */ 228 "Menu window handle is NULL!\n"); 229 if( lparam) { 230 HMENU hmenu = (HMENU)SendMessageA( (HWND)lparam, MN_GETHMENU, 0, 0); 231 ok( hmenupopup == hmenu, "MN_GETHMENU returns %p expected %p\n", 232 hmenu, hmenupopup); 233 } 234 PostMessageA(hwnd, WM_CANCELMODE, 0, 0); 235 return TRUE; 236 } 237 case WM_MENUSELECT: 238 selectitem_wp = wparam; 239 selectitem_lp = lparam; 240 break; 241 } 242 return DefWindowProcA(hwnd, msg, wparam, lparam); 243 } 244 245 static void register_menu_check_class(void) 246 { 247 WNDCLASSA wc = 248 { 249 0, 250 menu_check_wnd_proc, 251 0, 252 0, 253 GetModuleHandleA(NULL), 254 NULL, 255 LoadCursorA(NULL, (LPCSTR)IDC_ARROW), 256 (HBRUSH)(COLOR_BTNFACE+1), 257 NULL, 258 "WineMenuCheck", 259 }; 260 261 atomMenuCheckClass = RegisterClassA(&wc); 262 } 263 264 static void test_getmenubarinfo(void) 265 { 266 BOOL ret; 267 HMENU hmenu; 268 MENUBARINFO mbi; 269 RECT rcw, rci; 270 HWND hwnd; 271 INT err; 272 273 if (!pGetMenuBarInfo) { 274 win_skip("GetMenuBarInfo is not available\n"); 275 return; 276 } 277 278 mbi.cbSize = sizeof(MENUBARINFO); 279 280 hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 281 WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, 282 NULL, NULL, NULL, NULL); 283 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 284 285 /* no menu: getmenubarinfo should fail */ 286 SetLastError(0xdeadbeef); 287 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); 288 err = GetLastError(); 289 ok(ret == FALSE, "GetMenuBarInfo should not have been successful\n"); 290 ok(err == 0xdeadbeef, "err = %d\n", err); 291 292 /* create menubar, no items yet */ 293 hmenu = CreateMenu(); 294 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 295 296 ret = SetMenu(hwnd, hmenu); 297 ok(ret, "SetMenu failed with error %d\n", GetLastError()); 298 299 SetLastError(0xdeadbeef); 300 ret = pGetMenuBarInfo(NULL, OBJID_CLIENT, 0, &mbi); 301 err = GetLastError(); 302 ok(!ret, "GetMenuBarInfo succeeded\n"); 303 ok(err == ERROR_INVALID_WINDOW_HANDLE, "err = %d\n", err); 304 305 SetLastError(0xdeadbeef); 306 ret = pGetMenuBarInfo(hwnd, OBJID_CLIENT, 0, &mbi); 307 err = GetLastError(); 308 ok(!ret, "GetMenuBarInfo succeeded\n"); 309 ok(err==ERROR_INVALID_MENU_HANDLE || broken(err==0xdeadbeef) /* NT, W2K, XP */, "err = %d\n", err); 310 311 SetLastError(0xdeadbeef); 312 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, -1, &mbi); 313 err = GetLastError(); 314 ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); 315 ok(err == 0xdeadbeef, "err = %d\n", err); 316 317 mbi.cbSize = 1000; 318 SetLastError(0xdeadbeef); 319 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); 320 err = GetLastError(); 321 ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); 322 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err); 323 mbi.cbSize = sizeof(MENUBARINFO); 324 325 SetLastError(0xdeadbeef); 326 ret = pGetMenuBarInfo(hwnd, 123, 0, &mbi); 327 err = GetLastError(); 328 ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); 329 ok(err == 0xdeadbeef, "err = %d\n", err); 330 331 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); 332 ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); 333 334 ok(mbi.rcBar.left == 0 && mbi.rcBar.top == 0 && mbi.rcBar.bottom == 0 && mbi.rcBar.right == 0, 335 "rcBar: Expected (0,0)-(0,0), got: %s\n", wine_dbgstr_rect(&mbi.rcBar)); 336 ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", 337 mbi.hMenu, hmenu); 338 ok(mbi.fBarFocused == 0, "fBarFocused: Got %d instead of 0.\n", mbi.fBarFocused); 339 ok(mbi.fFocused == 0, "fFocused: Got %d instead of 0.\n", mbi.fFocused); 340 341 /* add some items */ 342 ret = AppendMenuA(hmenu, MF_STRING , 100, "item 1"); 343 ok(ret, "AppendMenu failed.\n"); 344 ret = AppendMenuA(hmenu, MF_STRING , 101, "item 2"); 345 ok(ret, "AppendMenu failed.\n"); 346 ret = SetMenu(hwnd, hmenu); 347 ok(ret, "SetMenu failed with error %d\n", GetLastError()); 348 349 SetLastError(0xdeadbeef); 350 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 200, &mbi); 351 err = GetLastError(); 352 ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); 353 ok(err == 0xdeadbeef, "err = %d\n", err); 354 355 /* get info for the whole menu */ 356 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); 357 ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); 358 359 /* calculate menu rectangle, from window rectangle and the position of the first item */ 360 ret = GetWindowRect(hwnd, &rcw); 361 ok(ret, "GetWindowRect failed.\n"); 362 ret = GetMenuItemRect(hwnd, hmenu, 0, &rci); 363 ok(ret, "GetMenuItemRect failed.\n"); 364 todo_wine ok(mbi.rcBar.left == rci.left && mbi.rcBar.top == rci.top && 365 mbi.rcBar.bottom == rci.bottom && mbi.rcBar.right == rcw.right - rci.left + rcw.left, 366 "rcBar: Got %s instead of (%d,%d)-(%d,%d)\n", wine_dbgstr_rect(&mbi.rcBar), 367 rci.left, rci.top, rcw.right - rci.left + rcw.left, rci.bottom); 368 ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", mbi.hMenu, hmenu); 369 ok(mbi.fBarFocused == 0, "fBarFocused: got %d instead of 0\n", mbi.fBarFocused); 370 ok(mbi.fFocused == 0, "fFocused: got %d instead of 0\n", mbi.fFocused); 371 372 /* get info for item nr.2 */ 373 ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 2, &mbi); 374 ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); 375 ret = GetMenuItemRect(hwnd, hmenu, 1, &rci); 376 ok(ret, "GetMenuItemRect failed.\n"); 377 ok(EqualRect(&mbi.rcBar, &rci), "rcBar: Got %s instead of %s\n", wine_dbgstr_rect(&mbi.rcBar), 378 wine_dbgstr_rect(&rci)); 379 ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", mbi.hMenu, hmenu); 380 ok(mbi.fBarFocused == 0, "fBarFocused: got %d instead of 0\n", mbi.fBarFocused); 381 ok(mbi.fFocused == 0, "fFocused: got %d instead of 0\n", mbi.fFocused); 382 383 DestroyWindow(hwnd); 384 } 385 386 static void test_system_menu(void) 387 { 388 WCHAR testW[] = {'t','e','s','t',0}; 389 BOOL ret; 390 HMENU menu; 391 HWND hwnd; 392 MENUITEMINFOA info; 393 MENUITEMINFOW infoW; 394 char buffer[80]; 395 char found[0x200]; 396 int i, res; 397 398 hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 399 WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, 400 NULL, NULL, NULL, NULL); 401 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 402 menu = GetSystemMenu( hwnd, FALSE ); 403 ok( menu != NULL, "no system menu\n" ); 404 405 for (i = 0xf000; i < 0xf200; i++) 406 { 407 memset( &info, 0xcc, sizeof(info) ); 408 info.cbSize = sizeof(info); 409 info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID; 410 info.dwTypeData = buffer; 411 info.cch = sizeof( buffer ); 412 ret = GetMenuItemInfoA( menu, i, FALSE, &info ); 413 if (ret) trace( "found %x: '%s'\n", i, buffer ); 414 switch (i) 415 { 416 case SC_RESTORE: 417 case SC_SIZE: 418 case SC_MOVE: 419 case SC_MINIMIZE: 420 case SC_MAXIMIZE: 421 case SC_CLOSE: 422 ok( ret, "%x menu item not found\n", i ); 423 break; 424 case SC_SCREENSAVE+1: /* used for the 'About Wine' entry, don't test */ 425 break; 426 default: 427 ok( !ret, "%x menu item found\n", i ); 428 break; 429 } 430 found[i - 0xf000] = ret; 431 } 432 433 for (i = 0xf000; i < 0xf200; i++) 434 { 435 res = CheckMenuItem( menu, i, 0 ); 436 if (res == -1) ok( !found[i - 0xf000], "could not check existent item %x\n", i ); 437 else ok( found[i - 0xf000], "could check non-existent item %x\n", i ); 438 439 res = EnableMenuItem( menu, i, 0 ); 440 if (res == -1) ok( !found[i - 0xf000], "could not enable existent item %x\n", i ); 441 else ok( found[i - 0xf000], "could enable non-existent item %x\n", i ); 442 443 res = GetMenuState( menu, i, 0 ); 444 if (res == -1) ok( !found[i - 0xf000], "could not get state existent item %x\n", i ); 445 else ok( found[i - 0xf000], "could get state of non-existent item %x\n", i ); 446 447 if (!found[i - 0xf000]) /* don't remove the existing ones */ 448 { 449 ret = RemoveMenu( menu, i, 0 ); 450 ok( !ret, "could remove non-existent item %x\n", i ); 451 } 452 453 ret = ModifyMenuA( menu, i, 0, i, "test" ); 454 if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" ); 455 else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i ); 456 else ok( found[i - 0xf000], "could modify non-existent item %x\n", i ); 457 458 ret = ModifyMenuW( menu, i, 0, i, testW ); 459 if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" ); 460 else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i ); 461 else ok( found[i - 0xf000], "could modify non-existent item %x\n", i ); 462 463 ret = ModifyMenuA( menu, i, MF_BYPOSITION, i, "test" ); 464 ok( !ret, "could modify non-existent item %x\n", i ); 465 466 strcpy( buffer, "test" ); 467 memset( &info, 0xcc, sizeof(info) ); 468 info.cbSize = sizeof(info); 469 info.fMask = MIIM_STRING | MIIM_ID; 470 info.wID = i; 471 info.dwTypeData = buffer; 472 info.cch = strlen( buffer ); 473 ret = SetMenuItemInfoA( menu, i, FALSE, &info ); 474 if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" ); 475 else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i ); 476 else ok( found[i - 0xf000], "could set non-existent item %x\n", i ); 477 ret = SetMenuItemInfoA( menu, i, TRUE, &info ); 478 ok( !ret, "could modify non-existent item %x\n", i ); 479 480 memset( &infoW, 0xcc, sizeof(infoW) ); 481 infoW.cbSize = sizeof(infoW); 482 infoW.fMask = MIIM_STRING | MIIM_ID; 483 infoW.wID = i; 484 infoW.dwTypeData = testW; 485 infoW.cch = lstrlenW( testW ); 486 ret = SetMenuItemInfoW( menu, i, FALSE, &infoW ); 487 if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" ); 488 else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i ); 489 else ok( found[i - 0xf000], "could set non-existent item %x\n", i ); 490 ret = SetMenuItemInfoW( menu, i, TRUE, &infoW ); 491 ok( !ret, "could modify non-existent item %x\n", i ); 492 } 493 494 /* confirm that SC_TASKLIST still does not exist */ 495 for (i = 0xf000; i < 0xf200; i++) 496 { 497 memset( &info, 0xcc, sizeof(info) ); 498 info.cbSize = sizeof(info); 499 info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID; 500 info.dwTypeData = buffer; 501 info.cch = sizeof( buffer ); 502 ret = GetMenuItemInfoA( menu, i, FALSE, &info ); 503 switch (i) 504 { 505 case SC_RESTORE: 506 case SC_SIZE: 507 case SC_MOVE: 508 case SC_MINIMIZE: 509 case SC_MAXIMIZE: 510 case SC_CLOSE: 511 ok( ret, "%x menu item not found\n", i ); 512 break; 513 case SC_SCREENSAVE+1: /* used for the 'About Wine' entry, don't test */ 514 break; 515 default: 516 ok( !ret, "%x menu item found\n", i ); 517 break; 518 } 519 } 520 521 /* now a normal (non-system) menu */ 522 523 menu = CreateMenu(); 524 ok( menu != NULL, "CreateMenu failed with error %d\n", GetLastError() ); 525 526 res = CheckMenuItem( menu, SC_TASKLIST, 0 ); 527 ok( res == -1, "CheckMenuItem succeeded\n" ); 528 res = EnableMenuItem( menu, SC_TASKLIST, 0 ); 529 ok( res == -1, "EnableMenuItem succeeded\n" ); 530 res = GetMenuState( menu, SC_TASKLIST, 0 ); 531 ok( res == -1, "GetMenuState succeeded\n" ); 532 ret = RemoveMenu( menu, SC_TASKLIST, 0 ); 533 ok( !ret, "RemoveMenu succeeded\n" ); 534 ret = ModifyMenuA( menu, SC_TASKLIST, 0, SC_TASKLIST, "test" ); 535 ok( ret, "ModifyMenuA failed err %d\n", GetLastError() ); 536 ret = ModifyMenuW( menu, SC_TASKLIST, 0, SC_TASKLIST, testW ); 537 ok( ret, "ModifyMenuW failed err %d\n", GetLastError() ); 538 ret = ModifyMenuA( menu, SC_TASKLIST-1, 0, SC_TASKLIST, "test" ); 539 ok( !ret, "ModifyMenu succeeded on SC_TASKLIST-1\n" ); 540 strcpy( buffer, "test" ); 541 memset( &info, 0xcc, sizeof(info) ); 542 info.cbSize = sizeof(info); 543 info.fMask = MIIM_STRING | MIIM_ID; 544 info.wID = SC_TASKLIST; 545 info.dwTypeData = buffer; 546 info.cch = strlen( buffer ); 547 ret = SetMenuItemInfoA( menu, SC_TASKLIST, FALSE, &info ); 548 ok( ret, "failed to set SC_TASKLIST\n" ); 549 ret = SetMenuItemInfoA( menu, SC_TASKLIST+1, FALSE, &info ); 550 ok( !ret, "succeeded setting SC_TASKLIST+1\n" ); 551 ret = SetMenuItemInfoA( menu, SC_TASKLIST, TRUE, &info ); 552 ok( !ret, "succeeded setting by position\n" ); 553 554 memset( &infoW, 0xcc, sizeof(infoW) ); 555 infoW.cbSize = sizeof(infoW); 556 infoW.fMask = MIIM_STRING | MIIM_ID; 557 infoW.wID = SC_TASKLIST; 558 infoW.dwTypeData = testW; 559 infoW.cch = lstrlenW( testW ); 560 ret = SetMenuItemInfoW( menu, SC_TASKLIST, FALSE, &infoW ); 561 ok( ret, "failed to set SC_TASKLIST\n" ); 562 ret = SetMenuItemInfoW( menu, SC_TASKLIST+1, FALSE, &infoW ); 563 ok( !ret, "succeeded setting SC_TASKLIST+1\n" ); 564 ret = SetMenuItemInfoW( menu, SC_TASKLIST, TRUE, &infoW ); 565 ok( !ret, "succeeded setting by position\n" ); 566 567 DestroyMenu( menu ); 568 DestroyWindow( hwnd ); 569 } 570 571 /* demonstrates that windows locks the menu object so that it is still valid 572 * even after a client calls DestroyMenu on it */ 573 static void test_menu_locked_by_window(void) 574 { 575 BOOL ret; 576 HMENU hmenu; 577 HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 578 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 579 NULL, NULL, NULL, NULL); 580 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 581 hmenu = CreateMenu(); 582 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 583 ret = InsertMenuA(hmenu, 0, MF_STRING, 0, "&Test"); 584 ok(ret, "InsertMenu failed with error %d\n", GetLastError()); 585 ret = SetMenu(hwnd, hmenu); 586 ok(ret, "SetMenu failed with error %d\n", GetLastError()); 587 ret = DestroyMenu(hmenu); 588 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 589 590 ret = DrawMenuBar(hwnd); 591 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError()); 592 ret = IsMenu(GetMenu(hwnd)); 593 ok(!ret || broken(ret) /* nt4 */, "Menu handle should have been destroyed\n"); 594 595 SendMessageA(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); 596 /* did we process the WM_INITMENU message? */ 597 ret = GetWindowLongPtrA(hwnd, GWLP_USERDATA); 598 todo_wine { 599 ok(ret, "WM_INITMENU should have been sent\n"); 600 } 601 602 DestroyWindow(hwnd); 603 } 604 605 /* demonstrates that subpopup's are locked 606 * even after a client calls DestroyMenu on it */ 607 static LRESULT WINAPI subpopuplocked_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 608 { 609 HWND hwndmenu; 610 switch (msg) 611 { 612 case WM_ENTERIDLE: 613 hwndmenu = GetCapture(); 614 if( hwndmenu) { 615 PostMessageA( hwndmenu, WM_KEYDOWN, VK_DOWN, 0); 616 PostMessageA( hwndmenu, WM_KEYDOWN, VK_RIGHT, 0); 617 PostMessageA( hwndmenu, WM_KEYDOWN, VK_RETURN, 0); 618 } 619 } 620 return DefWindowProcA(hwnd, msg, wparam, lparam); 621 } 622 623 static void test_subpopup_locked_by_menu(void) 624 { 625 DWORD gle; 626 BOOL ret; 627 HMENU hmenu, hsubmenu; 628 MENUINFO mi = { sizeof( MENUINFO)}; 629 MENUITEMINFOA mii = { sizeof( MENUITEMINFOA)}; 630 HWND hwnd; 631 const int itemid = 0x1234567; 632 if( !pGetMenuInfo) 633 { 634 win_skip("GetMenuInfo is not available\n"); 635 return; 636 } 637 /* create window, popupmenu with one subpopup */ 638 hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 639 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 640 NULL, NULL, NULL, NULL); 641 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 642 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR) subpopuplocked_wnd_proc); 643 hmenu = CreatePopupMenu(); 644 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 645 hsubmenu = CreatePopupMenu(); 646 ok(hsubmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 647 ret = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hsubmenu, 648 "PopUpLockTest"); 649 ok(ret, "InsertMenu failed with error %d\n", GetLastError()); 650 ret = InsertMenuA(hsubmenu, 0, MF_BYPOSITION | MF_STRING, itemid, "PopUpMenu"); 651 ok(ret, "InsertMenu failed with error %d\n", GetLastError()); 652 /* first some tests that all this functions properly */ 653 mii.fMask = MIIM_SUBMENU; 654 ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); 655 ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); 656 ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); 657 mi.fMask |= MIM_STYLE; 658 ret = pGetMenuInfo( hsubmenu, &mi); 659 ok( ret , "GetMenuInfo returned 0 with error %d\n", GetLastError()); 660 ret = IsMenu( hsubmenu); 661 ok( ret , "Menu handle is not valid\n"); 662 SetLastError( 0xdeadbeef); 663 ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 664 if( ret == (itemid & 0xffff)) { 665 win_skip("not on 16 bit menu subsystem\n"); 666 DestroyMenu( hsubmenu); 667 } else { 668 gle = GetLastError(); 669 ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); 670 ok( gle == 0 || 671 broken( gle == 0xdeadbeef), /* win2k0 */ 672 "Last error is %d\n", gle); 673 /* then destroy the sub-popup */ 674 ret = DestroyMenu( hsubmenu); 675 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 676 /* and repeat the tests */ 677 mii.fMask = MIIM_SUBMENU; 678 ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); 679 ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); 680 /* GetMenuInfo fails now */ 681 ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); 682 mi.fMask |= MIM_STYLE; 683 ret = pGetMenuInfo( hsubmenu, &mi); 684 ok( !ret , "GetMenuInfo should have failed\n"); 685 /* IsMenu says it is not */ 686 ret = IsMenu( hsubmenu); 687 ok( !ret , "Menu handle should be invalid\n"); 688 /* but TrackPopupMenu still works! */ 689 SetLastError( 0xdeadbeef); 690 ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 691 gle = GetLastError(); 692 todo_wine { 693 ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); 694 } 695 ok( gle == 0 || 696 broken(gle == 0xdeadbeef) || /* wow64 */ 697 broken(gle == ERROR_INVALID_PARAMETER), /* win2k0 */ 698 "Last error is %d\n", gle); 699 } 700 /* clean up */ 701 DestroyMenu( hmenu); 702 DestroyWindow(hwnd); 703 } 704 705 static void test_menu_ownerdraw(void) 706 { 707 int i,j,k; 708 BOOL ret; 709 HMENU hmenu; 710 MENUITEMINFOA mii; 711 LONG leftcol; 712 HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 713 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 714 NULL, NULL, NULL, NULL); 715 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 716 if( !hwnd) return; 717 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); 718 hmenu = CreatePopupMenu(); 719 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 720 if( !hmenu) { DestroyWindow(hwnd);return;} 721 k=0; 722 for( j=0;j<2;j++) /* create columns */ 723 for(i=0;i<2;i++) { /* create rows */ 724 ret = AppendMenuA( hmenu, MF_OWNERDRAW | 725 (i==0 ? MF_MENUBREAK : 0), k, (LPCSTR)MAKEINTRESOURCE(k)); 726 k++; 727 ok( ret, "AppendMenu failed for %d\n", k-1); 728 } 729 MOD_maxid = k-1; 730 assert( k <= sizeof(MOD_rc)/sizeof(RECT)); 731 /* display the menu */ 732 TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 733 734 /* columns have a 4 pixel gap between them */ 735 ok( MOD_rc[0].right + 4 == MOD_rc[2].left, 736 "item rectangles are not separated by 4 pixels space\n"); 737 /* height should be what the MEASUREITEM message has returned */ 738 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE, 739 "menu item has wrong height: %d should be %d\n", 740 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE); 741 /* no gaps between the rows */ 742 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0, 743 "There should not be a space between the rows, gap is %d\n", 744 MOD_rc[0].bottom - MOD_rc[1].top); 745 /* test the correct value of the item height that was sent 746 * by the WM_MEASUREITEM message */ 747 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */ 748 MOD_odheight == MOD_hic, /* Win95,98,ME */ 749 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n", 750 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight); 751 /* test what MF_MENUBREAK did at the first position. Also show 752 * that an MF_SEPARATOR is ignored in the height calculation. */ 753 leftcol= MOD_rc[0].left; 754 ModifyMenuA( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0); 755 /* display the menu */ 756 TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 757 /* left should be 4 pixels less now */ 758 ok( leftcol == MOD_rc[0].left + 4, 759 "columns should be 4 pixels to the left (actual %d).\n", 760 leftcol - MOD_rc[0].left); 761 /* test width */ 762 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE, 763 "width of owner drawn menu item is wrong. Got %d expected %d\n", 764 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE); 765 /* and height */ 766 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE, 767 "Height is incorrect. Got %d expected %d\n", 768 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE); 769 770 /* test owner-drawn callback bitmap */ 771 ModifyMenuA( hmenu, 1, MF_BYPOSITION | MFT_BITMAP, 1, (LPCSTR)HBMMENU_CALLBACK ); 772 mii.cbSize = sizeof(mii); 773 mii.fMask = MIIM_BITMAP | MIIM_FTYPE | MIIM_ID; 774 if (GetMenuItemInfoA( hmenu, 1, TRUE, &mii )) 775 { 776 ok( mii.fType == MFT_BITMAP, "wrong type %x\n", mii.fType ); 777 ok( mii.wID == 1, "wrong id %x\n", mii.wID ); 778 ok( mii.hbmpItem == HBMMENU_CALLBACK, "wrong data %p\n", mii.hbmpItem ); 779 } 780 TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 781 782 /* test width/height of an ownerdraw menu bar as well */ 783 ret = DestroyMenu(hmenu); 784 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 785 hmenu = CreateMenu(); 786 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 787 if( !hmenu) { DestroyWindow(hwnd);return;} 788 MOD_maxid=1; 789 for(i=0;i<2;i++) { 790 ret = AppendMenuA( hmenu, MF_OWNERDRAW, i, 0 ); 791 ok( ret, "AppendMenu failed for %d\n", i); 792 } 793 ret = SetMenu( hwnd, hmenu); 794 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */ 795 ok(ret, "SetMenu failed with error %d\n", GetLastError()); 796 /* test width */ 797 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE, 798 "width of owner drawn menu item is wrong. Got %d expected %d\n", 799 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE); 800 /* test height */ 801 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1, 802 "Height of owner drawn menu item is wrong. Got %d expected %d\n", 803 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1); 804 805 /* clean up */ 806 ret = DestroyMenu(hmenu); 807 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 808 DestroyWindow(hwnd); 809 } 810 811 /* helper for test_menu_bmp_and_string() */ 812 static void test_mbs_help( int ispop, int hassub, int mnuopt, 813 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp, 814 SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size) 815 { 816 BOOL ret; 817 HMENU hmenu, submenu; 818 MENUITEMINFOA mii={ sizeof( MENUITEMINFOA )}; 819 MENUINFO mi; 820 RECT rc; 821 CHAR text_copy[16]; 822 int hastab, expect; 823 BOOL failed = FALSE; 824 825 MOD_GotDrawItemMsg = FALSE; 826 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE; 827 mii.fType = 0; 828 /* check the menu item unless MNS_CHECKORBMP is set */ 829 mii.fState = (mnuopt != 2 ? MFS_CHECKED : MFS_UNCHECKED); 830 mii.dwItemData =0; 831 MODsizes[0] = bmpsize; 832 hastab = 0; 833 if( text ) { 834 char *p; 835 mii.fMask |= MIIM_STRING; 836 strcpy(text_copy, text); 837 mii.dwTypeData = text_copy; /* structure member declared non-const */ 838 if( ( p = strchr( text, '\t'))) { 839 hastab = *(p + 1) ? 2 : 1; 840 } 841 } 842 /* tabs don't make sense in menubars */ 843 if(hastab && !ispop) return; 844 if( hbmp) { 845 mii.fMask |= MIIM_BITMAP; 846 mii.hbmpItem = hbmp; 847 } 848 submenu = CreateMenu(); 849 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError()); 850 if( ispop) 851 hmenu = CreatePopupMenu(); 852 else 853 hmenu = CreateMenu(); 854 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError()); 855 if( hassub) { 856 mii.fMask |= MIIM_SUBMENU; 857 mii.hSubMenu = submenu; 858 } 859 if( mnuopt) { 860 mi.cbSize = sizeof(mi); 861 mi.fMask = MIM_STYLE; 862 pGetMenuInfo( hmenu, &mi); 863 if( mnuopt) mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP; 864 ret = pSetMenuInfo( hmenu, &mi); 865 ok( ret, "SetMenuInfo failed with error %d\n", GetLastError()); 866 } 867 ret = InsertMenuItemA( hmenu, 0, FALSE, &mii); 868 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); 869 failed = !ret; 870 if( winetest_debug) { 871 HDC hdc=GetDC(hwnd); 872 RECT rc = {100, 50, 400, 70}; 873 char buf[100]; 874 875 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt); 876 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW); 877 TextOutA( hdc, 10, 50, buf, strlen( buf)); 878 ReleaseDC( hwnd, hdc); 879 } 880 if(ispop) 881 TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 882 else { 883 ret = SetMenu( hwnd, hmenu); 884 ok(ret, "SetMenu failed with error %d\n", GetLastError()); 885 DrawMenuBar( hwnd); 886 } 887 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc); 888 ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError()); 889 890 if (0) /* comment out menu size checks, behavior is different in almost every Windows version */ 891 /* the tests should however succeed on win2000, XP and Wine (at least up to 1.1.15) */ 892 /* with a variety of dpis and desktop font sizes */ 893 { 894 /* check menu width */ 895 if( ispop) 896 expect = ( text || hbmp ? 897 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0) 898 : 0) + 899 arrowwidth + MOD_avec + (hbmp ? 900 ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ? bmpsize.cx + 2 : GetSystemMetrics( SM_CXMENUSIZE) + 2) 901 : 0) + 902 (text && hastab ? /* TAB space */ 903 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) + 904 (text ? 2 + (text[0] ? size.cx :0): 0) ; 905 else 906 expect = !(text || hbmp) ? 0 : 907 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) + 908 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ; 909 ok( rc.right - rc.left == expect, 910 "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect); 911 failed = failed || !(rc.right - rc.left == expect); 912 /* check menu height */ 913 if( ispop) 914 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0), 915 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0), 916 (hbmp ? 917 ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ? 918 bmpsize.cy + 2 919 : GetSystemMetrics( SM_CYMENUSIZE) + 2) 920 : 0))); 921 else 922 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 923 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0))); 924 ok( rc.bottom - rc.top == expect, 925 "menu height wrong, got %d expected %d (%d)\n", 926 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU)); 927 failed = failed || !(rc.bottom - rc.top == expect); 928 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) { 929 /* check the position of the bitmap */ 930 /* horizontal */ 931 if (!ispop) 932 expect = 3; 933 else if (mnuopt == 0) 934 expect = 4 + GetSystemMetrics(SM_CXMENUCHECK); 935 else if (mnuopt == 1) 936 expect = 4; 937 else /* mnuopt == 2 */ 938 expect = 2; 939 ok( expect == MOD_rc[0].left, 940 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect); 941 failed = failed || !(expect == MOD_rc[0].left); 942 /* vertical */ 943 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2; 944 ok( expect == MOD_rc[0].top, 945 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect); 946 failed = failed || !(expect == MOD_rc[0].top); 947 } 948 } 949 /* if there was a failure, report details */ 950 if( failed) { 951 trace("*** count %d %s text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n", 952 count, (ispop? "POPUP": "MENUBAR"),text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy, 953 size.cx, size.cy, sc_size.cx, mnuopt, hastab); 954 trace(" check %d,%d arrow %d avechar %d\n", 955 GetSystemMetrics(SM_CXMENUCHECK ), 956 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec); 957 if( hbmp == HBMMENU_CALLBACK) 958 trace( " rc %s bmp.rc %s\n", wine_dbgstr_rect(&rc), wine_dbgstr_rect(&MOD_rc[0])); 959 } 960 /* clean up */ 961 ret = DestroyMenu(submenu); 962 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 963 ret = DestroyMenu(hmenu); 964 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 965 } 966 967 968 static void test_menu_bmp_and_string(void) 969 { 970 BYTE bmfill[300]; 971 HBITMAP hbm_arrow; 972 BITMAP bm; 973 INT arrowwidth; 974 HWND hwnd; 975 HMENU hsysmenu; 976 MENUINFO mi= {sizeof(MENUINFO)}; 977 MENUITEMINFOA mii= {sizeof(MENUITEMINFOA)}; 978 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop; 979 BOOL got; 980 981 if( !pGetMenuInfo) 982 { 983 win_skip("GetMenuInfo is not available\n"); 984 return; 985 } 986 987 memset( bmfill, 0xcc, sizeof( bmfill)); 988 hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU | 989 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 990 NULL, NULL, NULL, NULL); 991 hbm_arrow = LoadBitmapA( 0, (LPCSTR)OBM_MNARROW); 992 GetObjectA( hbm_arrow, sizeof(bm), &bm); 993 arrowwidth = bm.bmWidth; 994 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 995 if( !hwnd) return; 996 /* test system menu */ 997 hsysmenu = GetSystemMenu( hwnd, FALSE); 998 ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError()); 999 mi.fMask = MIM_STYLE; 1000 mi.dwStyle = 0; 1001 got = pGetMenuInfo( hsysmenu, &mi); 1002 ok( got, "GetMenuInfo failed gle=%d\n", GetLastError()); 1003 ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08x, without the bit %08x\n", 1004 mi.dwStyle, MNS_CHECKORBMP); 1005 mii.fMask = MIIM_BITMAP; 1006 mii.hbmpItem = NULL; 1007 got = GetMenuItemInfoA( hsysmenu, SC_CLOSE, FALSE, &mii); 1008 ok( got, "GetMenuItemInfoA failed gle=%d\n", GetLastError()); 1009 ok( HBMMENU_POPUP_CLOSE == mii.hbmpItem, "Item info did not get the right hbitmap: got %p expected %p\n", 1010 mii.hbmpItem, HBMMENU_POPUP_CLOSE); 1011 1012 memset(&mii, 0x81, sizeof(mii)); 1013 mii.cbSize = sizeof(mii); 1014 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA; 1015 mii.dwTypeData = (LPSTR)bmfill; 1016 mii.cch = sizeof(bmfill); 1017 mii.dwItemData = 0x81818181; 1018 got = GetMenuItemInfoA(hsysmenu, SC_RESTORE, FALSE, &mii); 1019 ok(got, "GetMenuItemInfo failed\n"); 1020 ok((mii.fType & ~(MFT_RIGHTJUSTIFY|MFT_RIGHTORDER)) == MFT_STRING, "expected MFT_STRING, got %#x\n", mii.fType); 1021 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 1022 ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID); 1023 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 1024 ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); 1025 ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData); 1026 ok(mii.cch != 0, "cch should not be 0\n"); 1027 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 1028 1029 mii.cbSize = sizeof(mii); 1030 mii.fMask = MIIM_TYPE; 1031 mii.hbmpItem = (HBITMAP)0x81818181; 1032 got = GetMenuItemInfoA(hsysmenu, SC_CLOSE, FALSE, &mii); 1033 ok(got, "GetMenuItemInfo failed\n"); 1034 ok((mii.fType & ~(MFT_RIGHTJUSTIFY|MFT_RIGHTORDER)) == MFT_STRING, "expected MFT_STRING, got %#x\n", mii.fType); 1035 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 1036 ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID); 1037 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 1038 ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); 1039 ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData); 1040 ok(mii.cch != 0, "cch should not be 0\n"); 1041 ok(mii.hbmpItem == HBMMENU_POPUP_CLOSE, "expected HBMMENU_POPUP_CLOSE, got %p\n", mii.hbmpItem); 1042 1043 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); 1044 1045 if( winetest_debug) 1046 trace(" check %d,%d arrow %d avechar %d\n", 1047 GetSystemMetrics(SM_CXMENUCHECK ), 1048 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec); 1049 count = 0; 1050 MOD_maxid = 0; 1051 for( ispop=1; ispop >= 0; ispop--){ 1052 static SIZE bmsizes[]= { 1053 {10,10},{38,38},{1,30},{55,5}}; 1054 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) { 1055 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill); 1056 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, HBMMENU_POPUP_CLOSE, NULL }; 1057 ok( hbm != 0, "CreateBitmap failed err %d\n", GetLastError()); 1058 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) { 1059 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */ 1060 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */ 1061 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) { 1062 /* no need to test NULL bitmaps of several sizes */ 1063 if( !bitmaps[bmpidx] && szidx > 0) continue; 1064 /* the HBMMENU_POPUP not to test for menu bars */ 1065 if( !ispop && 1066 bitmaps[bmpidx] >= HBMMENU_POPUP_CLOSE && 1067 bitmaps[bmpidx] <= HBMMENU_POPUP_MINIMIZE) continue; 1068 if( !ispop && hassub) continue; 1069 test_mbs_help( ispop, hassub, mnuopt, 1070 hwnd, arrowwidth, ++count, 1071 bitmaps[bmpidx], 1072 bmsizes[szidx], 1073 MOD_txtsizes[txtidx].text, 1074 MOD_txtsizes[txtidx].size, 1075 MOD_txtsizes[txtidx].sc_size); 1076 } 1077 } 1078 } 1079 } 1080 DeleteObject( hbm); 1081 } 1082 } 1083 /* clean up */ 1084 DestroyWindow(hwnd); 1085 } 1086 1087 static void test_menu_add_string( void ) 1088 { 1089 HMENU hmenu; 1090 MENUITEMINFOA info; 1091 BOOL rc; 1092 int ret; 1093 1094 char string[0x80]; 1095 char string2[0x80]; 1096 1097 char strback[0x80]; 1098 WCHAR strbackW[0x80]; 1099 static CHAR blah[] = "blah"; 1100 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0}; 1101 1102 hmenu = CreateMenu(); 1103 1104 memset( &info, 0, sizeof info ); 1105 info.cbSize = sizeof info; 1106 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID; 1107 info.dwTypeData = blah; 1108 info.cch = 6; 1109 info.dwItemData = 0; 1110 info.wID = 1; 1111 info.fState = 0; 1112 InsertMenuItemA(hmenu, 0, TRUE, &info ); 1113 1114 memset( &info, 0, sizeof info ); 1115 info.cbSize = sizeof info; 1116 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID; 1117 info.dwTypeData = string; 1118 info.cch = sizeof string; 1119 string[0] = 0; 1120 GetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1121 1122 ok( !strcmp( string, "blah" ), "menu item name differed\n"); 1123 1124 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */ 1125 strcpy(string, "Dummy string"); 1126 memset(&info, 0x00, sizeof(info)); 1127 info.cbSize= sizeof(MENUITEMINFOA); 1128 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */ 1129 info.fType= MFT_OWNERDRAW; 1130 info.dwTypeData= string; 1131 rc = InsertMenuItemA( hmenu, 0, TRUE, &info ); 1132 ok (rc, "InsertMenuItem failed\n"); 1133 1134 strcpy(string,"Garbage"); 1135 ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n"); 1136 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n"); 1137 1138 SetLastError(0xdeadbeef); 1139 ret = GetMenuStringW( hmenu, 0, strbackW, 99, MF_BYPOSITION ); 1140 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1141 win_skip("GetMenuStringW is not implemented\n"); 1142 else 1143 { 1144 ok (ret, "GetMenuStringW on ownerdraw entry failed\n"); 1145 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n"); 1146 } 1147 1148 /* Just try some invalid parameter tests */ 1149 SetLastError(0xdeadbeef); 1150 rc = SetMenuItemInfoA( hmenu, 0, TRUE, NULL ); 1151 ret = GetLastError(); 1152 ok (!rc, "SetMenuItemInfoA succeeded unexpectedly\n"); 1153 ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %d\n", ret); 1154 1155 SetLastError(0xdeadbeef); 1156 rc = SetMenuItemInfoA( hmenu, 0, FALSE, NULL ); 1157 ret = GetLastError(); 1158 ok (!rc, "SetMenuItemInfoA succeeded unexpectedly\n"); 1159 ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %d\n", ret); 1160 1161 /* Just change ftype to string and see what text is stored */ 1162 memset(&info, 0x00, sizeof(info)); 1163 info.cbSize= sizeof(MENUITEMINFOA); 1164 info.fMask= MIIM_FTYPE; /* Set string type */ 1165 info.fType= MFT_STRING; 1166 info.dwTypeData= (char *)0xdeadbeef; 1167 rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1168 ok (rc, "SetMenuItemInfo failed\n"); 1169 1170 /* Did we keep the old dwTypeData? */ 1171 ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n"); 1172 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n"); 1173 1174 /* Ensure change to bitmap type fails */ 1175 memset(&info, 0x00, sizeof(info)); 1176 info.cbSize= sizeof(MENUITEMINFOA); 1177 info.fMask= MIIM_FTYPE; /* Set as bitmap type */ 1178 info.fType= MFT_BITMAP; 1179 info.dwTypeData= (char *)0xdeadbee2; 1180 rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1181 ok (!rc, "SetMenuItemInfo unexpectedly worked\n"); 1182 1183 /* Just change ftype back and ensure data hasn't been freed */ 1184 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */ 1185 info.dwTypeData= (char *)0xdeadbee3; 1186 rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1187 ok (rc, "SetMenuItemInfo failed\n"); 1188 1189 /* Did we keep the old dwTypeData? */ 1190 ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n"); 1191 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n"); 1192 1193 /* Just change string value (not type) */ 1194 memset(&info, 0x00, sizeof(info)); 1195 info.cbSize= sizeof(MENUITEMINFOA); 1196 info.fMask= MIIM_STRING; /* Set typeData */ 1197 strcpy(string2, "string2"); 1198 info.dwTypeData= string2; 1199 rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1200 ok (rc, "SetMenuItemInfo failed\n"); 1201 1202 ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n"); 1203 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n"); 1204 1205 /* crashes with wine 0.9.5 */ 1206 memset(&info, 0x00, sizeof(info)); 1207 info.cbSize= sizeof(MENUITEMINFOA); 1208 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */ 1209 info.fType= MFT_OWNERDRAW; 1210 rc = InsertMenuItemA( hmenu, 0, TRUE, &info ); 1211 ok (rc, "InsertMenuItem failed\n"); 1212 ok (!GetMenuStringA( hmenu, 0, NULL, 0, MF_BYPOSITION), 1213 "GetMenuString on ownerdraw entry succeeded.\n"); 1214 SetLastError(0xdeadbeef); 1215 ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION); 1216 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1217 win_skip("GetMenuStringW is not implemented\n"); 1218 else 1219 ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n"); 1220 1221 DestroyMenu( hmenu ); 1222 } 1223 1224 /* define building blocks for the menu item info tests */ 1225 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) 1226 { 1227 if (n <= 0) return 0; 1228 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } 1229 return *str1 - *str2; 1230 } 1231 1232 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src ) 1233 { 1234 WCHAR *p = dst; 1235 while ((*p++ = *src++)); 1236 return dst; 1237 } 1238 1239 static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, UINT id, 1240 HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data, 1241 void *type_data, UINT len, HBITMAP item, BOOL expect ) 1242 { 1243 MENUITEMINFOA info; 1244 BOOL ret; 1245 1246 /* magic bitmap handle to test smaller cbSize */ 1247 if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef) 1248 info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem); 1249 else 1250 info.cbSize = sizeof(info); 1251 info.fMask = mask; 1252 info.fType = type; 1253 info.fState = state; 1254 info.wID = id; 1255 info.hSubMenu = submenu; 1256 info.hbmpChecked = checked; 1257 info.hbmpUnchecked = unchecked; 1258 info.dwItemData = data; 1259 info.dwTypeData = type_data; 1260 info.cch = len; 1261 info.hbmpItem = item; 1262 SetLastError( 0xdeadbeef ); 1263 if (ansi) ret = InsertMenuItemA( hmenu, 0, TRUE, &info ); 1264 else ret = InsertMenuItemW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); 1265 if (!expect) ok_(__FILE__, line)( !ret, "InsertMenuItem should have failed.\n" ); 1266 else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %u\n", GetLastError()); 1267 } 1268 1269 static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, 1270 UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, 1271 ULONG_PTR data, void *type_data, UINT in_len, UINT out_len, 1272 HBITMAP item, LPCSTR expname, BOOL expect, BOOL expstring ) 1273 { 1274 MENUITEMINFOA info; 1275 BOOL ret; 1276 WCHAR buffer[80]; 1277 1278 SetLastError( 0xdeadbeef ); 1279 memset( &info, 0xcc, sizeof(info) ); 1280 info.cbSize = sizeof(info); 1281 info.fMask = mask; 1282 info.dwTypeData = type_data; 1283 info.cch = in_len; 1284 1285 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, &info ) : 1286 GetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW *)&info ); 1287 if (!expect) 1288 { 1289 ok_(__FILE__, line)( !ret, "GetMenuItemInfo should have failed.\n" ); 1290 return; 1291 } 1292 ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %u\n", GetLastError()); 1293 if (mask & MIIM_TYPE) 1294 ok_(__FILE__, line)( info.fType == type || info.fType == LOWORD(type), 1295 "wrong type %x/%x\n", info.fType, type ); 1296 if (mask & MIIM_STATE) 1297 ok_(__FILE__, line)( info.fState == state || info.fState == LOWORD(state), 1298 "wrong state %x/%x\n", info.fState, state ); 1299 if (mask & MIIM_ID) 1300 ok_(__FILE__, line)( info.wID == id || info.wID == LOWORD(id), 1301 "wrong id %x/%x\n", info.wID, id ); 1302 if (mask & MIIM_SUBMENU) 1303 ok_(__FILE__, line)( info.hSubMenu == submenu || (ULONG_PTR)info.hSubMenu == LOWORD(submenu), 1304 "wrong submenu %p/%p\n", info.hSubMenu, submenu ); 1305 if (mask & MIIM_CHECKMARKS) 1306 { 1307 ok_(__FILE__, line)( info.hbmpChecked == checked || (ULONG_PTR)info.hbmpChecked == LOWORD(checked), 1308 "wrong bmpchecked %p/%p\n", info.hbmpChecked, checked ); 1309 ok_(__FILE__, line)( info.hbmpUnchecked == unchecked || (ULONG_PTR)info.hbmpUnchecked == LOWORD(unchecked), 1310 "wrong bmpunchecked %p/%p\n", info.hbmpUnchecked, unchecked ); 1311 } 1312 if (mask & MIIM_DATA) 1313 ok_(__FILE__, line)( info.dwItemData == data || info.dwItemData == LOWORD(data), 1314 "wrong item data %lx/%lx\n", info.dwItemData, data ); 1315 if (mask & MIIM_BITMAP) 1316 ok_(__FILE__, line)( info.hbmpItem == item || (ULONG_PTR)info.hbmpItem == LOWORD(item), 1317 "wrong bmpitem %p/%p\n", info.hbmpItem, item ); 1318 ok_(__FILE__, line)( info.dwTypeData == type_data || (ULONG_PTR)info.dwTypeData == LOWORD(type_data), 1319 "wrong type data %p/%p\n", info.dwTypeData, type_data ); 1320 ok_(__FILE__, line)( info.cch == out_len || 1321 broken(! ansi && info.cch == 2 * out_len) /* East-Asian */, 1322 "wrong len %x/%x\n", info.cch, out_len ); 1323 if (expname) 1324 { 1325 if(ansi) 1326 ok_(__FILE__, line)( !strncmp( expname, info.dwTypeData, out_len ), 1327 "menu item name differed from '%s' '%s'\n", expname, info.dwTypeData ); 1328 else 1329 ok_(__FILE__, line)( !strncmpW( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ), 1330 "menu item name wrong\n" ); 1331 1332 SetLastError( 0xdeadbeef ); 1333 ret = ansi ? GetMenuStringA( hmenu, 0, (char *)buffer, 80, MF_BYPOSITION ) : 1334 GetMenuStringW( hmenu, 0, buffer, 80, MF_BYPOSITION ); 1335 if (expstring) 1336 ok_(__FILE__, line)( ret, "GetMenuString failed, err %u\n", GetLastError()); 1337 else 1338 ok_(__FILE__, line)( !ret, "GetMenuString should have failed\n" ); 1339 } 1340 } 1341 1342 static void modify_menu( int line, HMENU hmenu, BOOL ansi, UINT flags, UINT_PTR id, void *data ) 1343 { 1344 BOOL ret; 1345 1346 SetLastError( 0xdeadbeef ); 1347 if (ansi) ret = ModifyMenuA( hmenu, 0, flags, id, data ); 1348 else ret = ModifyMenuW( hmenu, 0, flags, id, data ); 1349 ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %u\n", GetLastError()); 1350 } 1351 1352 static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, 1353 UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data, 1354 void *type_data, UINT len, HBITMAP item ) 1355 1356 { 1357 MENUITEMINFOA info; 1358 BOOL ret; 1359 1360 /* magic bitmap handle to test smaller cbSize */ 1361 if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef) 1362 info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem); 1363 else 1364 info.cbSize = sizeof(info); 1365 info.fMask = mask; 1366 info.fType = type; 1367 info.fState = state; 1368 info.wID = id; 1369 info.hSubMenu = submenu; 1370 info.hbmpChecked = checked; 1371 info.hbmpUnchecked = unchecked; 1372 info.dwItemData = data; 1373 info.dwTypeData = type_data; 1374 info.cch = len; 1375 info.hbmpItem = item; 1376 SetLastError( 0xdeadbeef ); 1377 if (ansi) ret = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); 1378 else ret = SetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); 1379 ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %u\n", GetLastError()); 1380 } 1381 1382 #define TMII_INSMI( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,eret1 )\ 1383 hmenu = CreateMenu();\ 1384 submenu = CreateMenu();\ 1385 if(ansi)strcpy( string, init );\ 1386 else strcpyW( string, init );\ 1387 insert_menu_item( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, eret1 ) 1388 1389 /* GetMenuItemInfo + GetMenuString */ 1390 #define TMII_GMII( c2,l2,\ 1391 d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,\ 1392 expname, eret2, eret3)\ 1393 check_menu_item_info( __LINE__, hmenu, ansi, c2, d3, e3, f3, g3, h3, i3, j3, k3, l2, l3, m3, \ 1394 expname, eret2, eret3 ) 1395 1396 #define TMII_DONE \ 1397 RemoveMenu(hmenu, 0, TRUE );\ 1398 DestroyMenu( hmenu );\ 1399 DestroyMenu( submenu ); 1400 1401 /* modify menu */ 1402 #define TMII_MODM( flags, id, data ) \ 1403 modify_menu( __LINE__, hmenu, ansi, flags, id, data ) 1404 1405 /* SetMenuItemInfo */ 1406 #define TMII_SMII( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1 ) \ 1407 set_menu_item_info( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1 ) 1408 1409 1410 #define OK 1 1411 #define ER 0 1412 1413 1414 static void test_menu_iteminfo( void ) 1415 { 1416 BOOL ansi = TRUE; 1417 char txtA[]="wine"; 1418 char initA[]="XYZ"; 1419 char emptyA[]=""; 1420 WCHAR txtW[]={'W','i','n','e',0}; 1421 WCHAR initW[]={'X','Y','Z',0}; 1422 WCHAR emptyW[]={0}; 1423 void *txt, *init, *empty, *string; 1424 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL); 1425 char stringA[0x80]; 1426 HMENU hmenu, submenu; 1427 HBITMAP dummy_hbm = (HBITMAP)(ULONG_PTR)0xdeadbeef; 1428 1429 do { 1430 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;} 1431 else {txt=txtW;init=initW;empty=emptyW;string=stringA;} 1432 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt); 1433 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */ 1434 /* (since MFT_STRING is zero, there are four of them) */ 1435 TMII_INSMI( MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK ); 1436 TMII_GMII ( MIIM_TYPE, 80, 1437 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1438 txt, OK, OK ); 1439 TMII_DONE 1440 TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1441 TMII_GMII ( MIIM_TYPE, 80, 1442 MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1443 NULL, OK, ER ); 1444 TMII_DONE 1445 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); 1446 TMII_GMII ( MIIM_TYPE, 80, 1447 MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1448 NULL, OK, ER ); 1449 TMII_DONE 1450 TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); 1451 TMII_GMII ( MIIM_TYPE, 80, 1452 MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1453 NULL, OK, ER ); 1454 TMII_DONE 1455 /* not enough space for name*/ 1456 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1457 TMII_GMII ( MIIM_TYPE, 0, 1458 MFT_STRING, 0, 0, 0, 0, 0, 0, NULL, 4, 0, 1459 NULL, OK, OK ); 1460 TMII_DONE 1461 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1462 TMII_GMII ( MIIM_TYPE, 5, 1463 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1464 txt, OK, OK ); 1465 TMII_DONE 1466 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1467 TMII_GMII ( MIIM_TYPE, 4, 1468 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 3, 0, 1469 txt, OK, OK ); 1470 TMII_DONE 1471 TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1472 TMII_GMII ( MIIM_TYPE, 0, 1473 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 1474 NULL, OK, ER ); 1475 TMII_DONE 1476 /* cannot combine MIIM_TYPE with some other flags */ 1477 TMII_INSMI( MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER ); 1478 TMII_DONE 1479 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1480 TMII_GMII ( MIIM_TYPE|MIIM_STRING, 80, 1481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1482 NULL, ER, OK ); 1483 TMII_DONE 1484 TMII_INSMI( MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER ); 1485 TMII_DONE 1486 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1487 TMII_GMII ( MIIM_TYPE|MIIM_FTYPE, 80, 1488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1489 NULL, ER, OK ); 1490 TMII_DONE 1491 TMII_INSMI( MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, hbm, ER ); 1492 TMII_DONE 1493 /* but succeeds with some others */ 1494 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1495 TMII_GMII ( MIIM_TYPE|MIIM_SUBMENU, 80, 1496 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1497 txt, OK, OK ); 1498 TMII_DONE 1499 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1500 TMII_GMII ( MIIM_TYPE|MIIM_STATE, 80, 1501 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1502 txt, OK, OK ); 1503 TMII_DONE 1504 TMII_INSMI( MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, 0, 0, 0, -1, txt, 6, 0, OK ); 1505 TMII_GMII ( MIIM_TYPE|MIIM_ID, 80, 1506 MFT_STRING, 0, 888, 0, 0, 0, 0, string, 4, 0, 1507 txt, OK, OK ); 1508 TMII_DONE 1509 TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, 0, 0, 0, 999, txt, 6, 0, OK ); 1510 TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, 1511 MFT_STRING, 0, 0, 0, 0, 0, 999, string, 4, 0, 1512 txt, OK, OK ); 1513 TMII_DONE 1514 /* to be continued */ 1515 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ 1516 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1517 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1518 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1519 txt, OK, OK ); 1520 TMII_DONE 1521 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ 1522 TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1523 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1524 MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, 1525 empty, OK, ER ); 1526 TMII_DONE 1527 TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1528 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1529 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, 1530 empty, OK, ER ); 1531 TMII_DONE 1532 TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1533 TMII_GMII ( MIIM_FTYPE, 80, 1534 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, 0, 1535 init, OK, ER ); 1536 TMII_DONE 1537 TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1538 TMII_GMII ( 0, 80, 1539 0, 0, 0, 0, 0, 0, 0, string, 80, 0, 1540 init, OK, OK ); 1541 TMII_DONE 1542 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ 1543 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1544 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1545 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0, 1546 txt, OK, OK ); 1547 TMII_DONE 1548 /* same but retrieve with MIIM_TYPE */ 1549 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1550 TMII_GMII ( MIIM_TYPE, 80, 1551 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1552 NULL, OK, OK ); 1553 TMII_DONE 1554 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1555 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1556 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, 1557 empty, OK, ER ); 1558 TMII_DONE 1559 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1560 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1561 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0, 1562 empty, OK, ER ); 1563 TMII_DONE 1564 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1565 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1566 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 1567 NULL, OK, ER ); 1568 TMII_DONE 1569 1570 /* How is that with bitmaps? */ 1571 TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1572 TMII_GMII ( MIIM_TYPE, 80, 1573 MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1574 NULL, OK, ER ); 1575 TMII_DONE 1576 TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1577 TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, 1578 0, 0, 0, 0, 0, 0, 0, string, 80, hbm, 1579 init, OK, ER ); 1580 TMII_DONE 1581 /* MIIM_BITMAP does not like MFT_BITMAP */ 1582 TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, hbm, ER ); 1583 TMII_DONE 1584 /* no problem with OWNERDRAWN */ 1585 TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1586 TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, 1587 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, hbm, 1588 init, OK, ER ); 1589 TMII_DONE 1590 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */ 1591 TMII_INSMI( MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, 0, ER ); 1592 TMII_DONE 1593 1594 /* menu with submenu */ 1595 TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK ); 1596 TMII_GMII ( MIIM_SUBMENU, 80, 1597 0, 0, 0, submenu, 0, 0, 0, string, 80, 0, 1598 init, OK, ER ); 1599 TMII_DONE 1600 TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, empty, 0, 0, OK ); 1601 TMII_GMII ( MIIM_SUBMENU, 80, 1602 0, 0, 0, submenu, 0, 0, 0, string, 80, 0, 1603 init, OK, ER ); 1604 TMII_DONE 1605 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */ 1606 TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK ); 1607 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1608 MFT_STRING|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0, 1609 empty, OK, ER ); 1610 TMII_GMII ( MIIM_SUBMENU|MIIM_FTYPE, 80, 1611 MFT_SEPARATOR, 0, 0, submenu, 0, 0, 0, string, 80, 0, 1612 empty, OK, ER ); 1613 TMII_DONE 1614 /* menu with invalid submenu */ 1615 TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, (HMENU)999, 0, 0, -1, txt, 0, 0, ER ); 1616 TMII_DONE 1617 /* Separator */ 1618 TMII_INSMI( MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK ); 1619 TMII_GMII ( MIIM_TYPE, 80, 1620 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1621 NULL, OK, ER ); 1622 TMII_DONE 1623 TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); 1624 TMII_GMII ( MIIM_TYPE, 80, 1625 MFT_BITMAP|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1626 NULL, OK, ER ); 1627 TMII_DONE 1628 /* SEPARATOR and STRING go well together */ 1629 /* BITMAP and STRING go well together */ 1630 TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1631 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80, 1632 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, hbm, 1633 txt, OK, OK ); 1634 TMII_DONE 1635 /* BITMAP, SEPARATOR and STRING go well together */ 1636 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1637 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80, 1638 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, hbm, 1639 txt, OK, OK ); 1640 TMII_DONE 1641 /* last two tests, but use MIIM_TYPE to retrieve info */ 1642 TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1643 TMII_GMII ( MIIM_TYPE, 80, 1644 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1645 NULL, OK, OK ); 1646 TMII_DONE 1647 TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1648 TMII_GMII ( MIIM_TYPE, 80, 1649 MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, 1650 NULL, OK, OK ); 1651 TMII_DONE 1652 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1653 TMII_GMII ( MIIM_TYPE, 80, 1654 MFT_SEPARATOR|MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, 1655 NULL, OK, OK ); 1656 TMII_DONE 1657 /* same three with MFT_OWNERDRAW */ 1658 TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); 1659 TMII_GMII ( MIIM_TYPE, 80, 1660 MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1661 NULL, OK, OK ); 1662 TMII_DONE 1663 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1664 TMII_GMII ( MIIM_TYPE, 80, 1665 MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, 1666 NULL, OK, OK ); 1667 TMII_DONE 1668 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1669 TMII_GMII ( MIIM_TYPE, 80, 1670 MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, 1671 NULL, OK, OK ); 1672 TMII_DONE 1673 1674 TMII_INSMI( MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1675 TMII_GMII ( MIIM_TYPE, 80, 1676 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1677 NULL, OK, OK ); 1678 TMII_DONE 1679 /* test with modifymenu: string is preserved after setting OWNERDRAW */ 1680 TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1681 TMII_MODM( MFT_OWNERDRAW, -1, (void*)787 ); 1682 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_DATA, 80, 1683 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 787, string, 4, 0, 1684 txt, OK, OK ); 1685 TMII_DONE 1686 /* same with bitmap: now the text is cleared */ 1687 TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1688 TMII_MODM( MFT_BITMAP, 545, hbm ); 1689 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, 1690 MFT_BITMAP, 0, 545, 0, 0, 0, 0, string, 0, hbm, 1691 empty, OK, ER ); 1692 TMII_DONE 1693 /* start with bitmap: now setting text clears it (though he flag is raised) */ 1694 TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1695 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, 1696 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 0, hbm, 1697 empty, OK, ER ); 1698 TMII_MODM( MFT_STRING, 545, txt ); 1699 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, 1700 MFT_STRING, 0, 545, 0, 0, 0, 0, string, 4, 0, 1701 txt, OK, OK ); 1702 TMII_DONE 1703 /*repeat with text NULL */ 1704 TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1705 TMII_MODM( MFT_STRING, 545, NULL ); 1706 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, 1707 MFT_SEPARATOR, 0, 545, 0, 0, 0, 0, string, 0, 0, 1708 empty, OK, ER ); 1709 TMII_DONE 1710 /* repeat with text "" */ 1711 TMII_INSMI( MIIM_BITMAP, -1 , -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1712 TMII_MODM( MFT_STRING, 545, empty ); 1713 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, 1714 MFT_STRING, 0, 545, 0, 0, 0, 0, string, 0, 0, 1715 empty, OK, ER ); 1716 TMII_DONE 1717 /* start with bitmap: set ownerdraw */ 1718 TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); 1719 TMII_MODM( MFT_OWNERDRAW, -1, (void *)232 ); 1720 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, 80, 1721 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 232, string, 0, hbm, 1722 empty, OK, ER ); 1723 TMII_DONE 1724 /* ask nothing */ 1725 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); 1726 TMII_GMII ( 0, 80, 1727 0, 0, 0, 0, 0, 0, 0, string, 80, 0, 1728 init, OK, OK ); 1729 TMII_DONE 1730 /* some tests with small cbSize: the hbmpItem is to be ignored */ 1731 TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK ); 1732 TMII_GMII ( MIIM_TYPE, 80, 1733 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 1734 NULL, OK, ER ); 1735 TMII_DONE 1736 TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK ); 1737 TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, 1738 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, NULL, 1739 init, OK, ER ); 1740 TMII_DONE 1741 TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); 1742 TMII_GMII ( MIIM_TYPE, 80, 1743 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, NULL, 1744 txt, OK, OK ); 1745 TMII_DONE 1746 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); 1747 TMII_GMII ( MIIM_TYPE, 80, 1748 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1749 NULL, OK, OK ); 1750 TMII_DONE 1751 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); 1752 TMII_GMII ( MIIM_TYPE, 80, 1753 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1754 NULL, OK, OK ); 1755 TMII_DONE 1756 TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); 1757 TMII_GMII ( MIIM_TYPE, 80, 1758 MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, 1759 NULL, OK, OK ); 1760 TMII_DONE 1761 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */ 1762 TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); 1763 TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, 1764 MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 343, 0, 0, 0, 1765 NULL, OK, ER ); 1766 TMII_DONE 1767 TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); 1768 TMII_GMII ( MIIM_TYPE, 80, 1769 MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1770 NULL, OK, ER ); 1771 TMII_DONE 1772 TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); 1773 TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, 1774 MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1775 NULL, OK, ER ); 1776 TMII_DONE 1777 /* set a string menu to ownerdraw with MIIM_TYPE */ 1778 TMII_INSMI( MIIM_TYPE, MFT_STRING, -2, -2, 0, 0, 0, -2, txt, -2, 0, OK ); 1779 TMII_SMII ( MIIM_TYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 1780 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1781 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0, 1782 txt, OK, OK ); 1783 TMII_DONE 1784 /* test with modifymenu add submenu */ 1785 TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); 1786 TMII_MODM( MF_POPUP, (UINT_PTR)submenu, txt ); 1787 TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, 80, 1788 MFT_STRING, 0, 0, submenu, 0, 0, 0, string, 4, 0, 1789 txt, OK, OK ); 1790 TMII_GMII ( MIIM_TYPE, 80, 1791 MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, 1792 txt, OK, OK ); 1793 TMII_DONE 1794 /* MFT_SEPARATOR bit is kept when the text is added */ 1795 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1796 TMII_SMII( MIIM_STRING, 0, 0, 0, 0, 0, 0, 0, txt, 0, 0 ); 1797 TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, 1798 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, 0, 1799 txt, OK, OK ); 1800 TMII_DONE 1801 /* MFT_SEPARATOR bit is kept when bitmap is added */ 1802 TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); 1803 TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, hbm ); 1804 TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, 1805 MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, hbm, 1806 init, OK, ER ); 1807 TMII_DONE 1808 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: 1809 Only the low word of the dwTypeData is used. 1810 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ 1811 TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, 1812 (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); 1813 TMII_GMII ( MIIM_TYPE, 80, 1814 MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, 1815 NULL, OK, OK ); 1816 TMII_DONE 1817 /* Type flags */ 1818 TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1819 TMII_GMII ( MIIM_TYPE, 80, 1820 MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1821 NULL, OK, OK ); 1822 TMII_DONE 1823 /* State flags */ 1824 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1825 TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 ); 1826 TMII_GMII ( MIIM_STATE, 80, 1827 0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0, 1828 NULL, OK, OK ); 1829 TMII_DONE 1830 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ 1831 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1832 TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 ); 1833 TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80, 1834 MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm, 1835 NULL, OK, OK ); 1836 TMII_DONE 1837 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ 1838 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1839 TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 ); 1840 TMII_GMII ( MIIM_FTYPE, 80, 1841 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, 1842 NULL, OK, OK ); 1843 TMII_GMII ( MIIM_TYPE, 80, 1844 MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1845 NULL, OK, OK ); 1846 TMII_GMII ( MIIM_FTYPE, 80, 1847 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, 1848 NULL, OK, OK ); 1849 TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL ); 1850 TMII_GMII ( MIIM_TYPE, 80, 1851 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 1852 NULL, OK, OK ); 1853 TMII_DONE 1854 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: 1855 Only the low word of the dwTypeData is used. 1856 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ 1857 TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, 1858 (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); 1859 TMII_GMII ( MIIM_TYPE, 80, 1860 MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, 1861 NULL, OK, OK ); 1862 TMII_DONE 1863 /* Type flags */ 1864 TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1865 TMII_GMII ( MIIM_TYPE, 80, 1866 MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1867 NULL, OK, OK ); 1868 TMII_DONE 1869 /* State flags */ 1870 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1871 TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 ); 1872 TMII_GMII ( MIIM_STATE, 80, 1873 0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0, 1874 NULL, OK, OK ); 1875 TMII_DONE 1876 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ 1877 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1878 TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 ); 1879 TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80, 1880 MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm, 1881 NULL, OK, OK ); 1882 TMII_DONE 1883 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ 1884 TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); 1885 TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 ); 1886 TMII_GMII ( MIIM_FTYPE, 80, 1887 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, 1888 NULL, OK, OK ); 1889 TMII_GMII ( MIIM_TYPE, 80, 1890 MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, 1891 NULL, OK, OK ); 1892 TMII_GMII ( MIIM_FTYPE, 80, 1893 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, 1894 NULL, OK, OK ); 1895 TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL ); 1896 TMII_GMII ( MIIM_TYPE, 80, 1897 MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 1898 NULL, OK, OK ); 1899 TMII_DONE 1900 } while( !(ansi = !ansi) ); 1901 DeleteObject( hbm); 1902 } 1903 1904 /* 1905 The following tests try to confirm the algorithm used to return the menu items 1906 when there is a collision between a menu item and a popup menu 1907 */ 1908 static void test_menu_search_bycommand( void ) 1909 { 1910 HMENU hmenu, hmenuSub, hmenuSub2; 1911 MENUITEMINFOA info; 1912 BOOL rc; 1913 UINT id; 1914 char strback[0x80]; 1915 char strIn[0x80]; 1916 static CHAR menuitem[] = "MenuItem", 1917 menuitem2[] = "MenuItem 2"; 1918 1919 /* Case 1: Menu containing a menu item */ 1920 hmenu = CreateMenu(); 1921 1922 memset( &info, 0, sizeof info ); 1923 info.cbSize = sizeof info; 1924 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 1925 info.fType = MFT_STRING; 1926 strcpy(strIn, "Case 1 MenuItem"); 1927 info.dwTypeData = strIn; 1928 info.wID = (UINT) 0x1234; 1929 1930 rc = InsertMenuItemA(hmenu, 0, TRUE, &info ); 1931 ok (rc, "Inserting the menuitem failed\n"); 1932 1933 id = GetMenuItemID(hmenu, 0); 1934 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id); 1935 1936 /* Confirm the menuitem was given the id supplied (getting by position) */ 1937 memset( &info, 0, sizeof info ); 1938 strback[0] = 0x00; 1939 info.cbSize = sizeof(MENUITEMINFOA); 1940 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 1941 info.dwTypeData = strback; 1942 info.cch = sizeof(strback); 1943 1944 rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); /* Get by position */ 1945 ok (rc, "Getting the menu items info failed\n"); 1946 ok (info.wID == 0x1234, "IDs differ for the menuitem\n"); 1947 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n"); 1948 1949 /* Search by id - Should return the item */ 1950 memset( &info, 0, sizeof info ); 1951 strback[0] = 0x00; 1952 info.cbSize = sizeof(MENUITEMINFOA); 1953 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 1954 info.dwTypeData = strback; 1955 info.cch = sizeof(strback); 1956 rc = GetMenuItemInfoA(hmenu, 0x1234, FALSE, &info); /* Get by ID */ 1957 1958 ok (rc, "Getting the menu items info failed\n"); 1959 ok (info.wID == 0x1234, "IDs differ for the menuitem\n"); 1960 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n"); 1961 1962 DestroyMenu( hmenu ); 1963 1964 /* Case 2: Menu containing a popup menu */ 1965 hmenu = CreateMenu(); 1966 hmenuSub = CreateMenu(); 1967 1968 strcpy(strIn, "Case 2 SubMenu"); 1969 rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn); 1970 ok (rc, "Inserting the popup menu into the main menu failed\n"); 1971 1972 id = GetMenuItemID(hmenu, 0); 1973 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id); 1974 1975 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */ 1976 memset( &info, 0, sizeof info ); 1977 strback[0] = 0x00; 1978 info.cbSize = sizeof(MENUITEMINFOA); 1979 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 1980 info.dwTypeData = strback; 1981 info.cch = sizeof(strback); 1982 info.wID = 0xdeadbeef; 1983 1984 rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); /* Get by position */ 1985 ok (rc, "Getting the menu items info failed\n"); 1986 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n"); 1987 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n"); 1988 1989 /* Search by id - returns the popup menu itself */ 1990 memset( &info, 0, sizeof info ); 1991 strback[0] = 0x00; 1992 info.cbSize = sizeof(MENUITEMINFOA); 1993 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 1994 info.dwTypeData = strback; 1995 info.cch = sizeof(strback); 1996 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */ 1997 1998 ok (rc, "Getting the menu items info failed\n"); 1999 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n"); 2000 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n"); 2001 2002 /* 2003 Now add an item after it with the same id 2004 */ 2005 memset( &info, 0, sizeof info ); 2006 info.cbSize = sizeof info; 2007 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2008 info.fType = MFT_STRING; 2009 strcpy(strIn, "Case 2 MenuItem 1"); 2010 info.dwTypeData = strIn; 2011 info.wID = (UINT_PTR) hmenuSub; 2012 rc = InsertMenuItemA(hmenu, -1, TRUE, &info ); 2013 ok (rc, "Inserting the menuitem failed\n"); 2014 2015 /* Search by id - returns the item which follows the popup menu */ 2016 memset( &info, 0, sizeof info ); 2017 strback[0] = 0x00; 2018 info.cbSize = sizeof(MENUITEMINFOA); 2019 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 2020 info.dwTypeData = strback; 2021 info.cch = sizeof(strback); 2022 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */ 2023 2024 ok (rc, "Getting the menu items info failed\n"); 2025 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n"); 2026 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2027 2028 /* 2029 Now add an item before the popup (with the same id) 2030 */ 2031 memset( &info, 0, sizeof info ); 2032 info.cbSize = sizeof info; 2033 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2034 info.fType = MFT_STRING; 2035 strcpy(strIn, "Case 2 MenuItem 2"); 2036 info.dwTypeData = strIn; 2037 info.wID = (UINT_PTR) hmenuSub; 2038 rc = InsertMenuItemA(hmenu, 0, TRUE, &info ); 2039 ok (rc, "Inserting the menuitem failed\n"); 2040 2041 /* Search by id - returns the item which precedes the popup menu */ 2042 memset( &info, 0, sizeof info ); 2043 strback[0] = 0x00; 2044 info.cbSize = sizeof(MENUITEMINFOA); 2045 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; 2046 info.dwTypeData = strback; 2047 info.cch = sizeof(strback); 2048 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */ 2049 2050 ok (rc, "Getting the menu items info failed\n"); 2051 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n"); 2052 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2053 2054 DestroyMenu( hmenu ); 2055 DestroyMenu( hmenuSub ); 2056 2057 /* 2058 Case 3: Menu containing a popup menu which in turn 2059 contains 2 items with the same id as the popup itself 2060 */ 2061 2062 hmenu = CreateMenu(); 2063 hmenuSub = CreateMenu(); 2064 2065 memset( &info, 0, sizeof info ); 2066 info.cbSize = sizeof info; 2067 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2068 info.fType = MFT_STRING; 2069 info.dwTypeData = menuitem; 2070 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/ 2071 2072 rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu"); 2073 ok (rc, "Inserting the popup menu into the main menu failed\n"); 2074 2075 rc = InsertMenuItemA(hmenuSub, 0, TRUE, &info ); 2076 ok (rc, "Inserting the sub menu menuitem failed\n"); 2077 2078 memset( &info, 0, sizeof info ); 2079 info.cbSize = sizeof info; 2080 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2081 info.fType = MFT_STRING; 2082 info.dwTypeData = menuitem2; 2083 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/ 2084 2085 rc = InsertMenuItemA(hmenuSub, 1, TRUE, &info ); 2086 ok (rc, "Inserting the sub menu menuitem 2 failed\n"); 2087 2088 /* Prove that you can't query the id of a popup directly (By position) */ 2089 id = GetMenuItemID(hmenu, 0); 2090 ok (id == -1, "Getting the sub menu id should have failed because it's a popup (gave %x)\n", id); 2091 2092 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/ 2093 memset( &info, 0, sizeof info ); 2094 strback[0] = 0x00; 2095 info.cbSize = sizeof(MENUITEMINFOA); 2096 info.fMask = MIIM_STRING | MIIM_ID; 2097 info.dwTypeData = strback; 2098 info.cch = sizeof(strback); 2099 2100 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); 2101 ok (rc, "Getting the menus info failed\n"); 2102 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n"); 2103 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2104 DestroyMenu( hmenu ); 2105 DestroyMenu( hmenuSub ); 2106 2107 /* 2108 Case 4: Menu containing 2 popup menus, the second 2109 contains 2 items with the same id as the first popup menu 2110 */ 2111 hmenu = CreateMenu(); 2112 hmenuSub = CreateMenu(); 2113 hmenuSub2 = CreateMenu(); 2114 2115 rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu"); 2116 ok (rc, "Inserting the popup menu into the main menu failed\n"); 2117 2118 rc = InsertMenuA(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2"); 2119 ok (rc, "Inserting the popup menu into the main menu failed\n"); 2120 2121 memset( &info, 0, sizeof info ); 2122 info.cbSize = sizeof info; 2123 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2124 info.fType = MFT_STRING; 2125 info.dwTypeData = menuitem; 2126 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/ 2127 2128 rc = InsertMenuItemA(hmenuSub2, 0, TRUE, &info ); 2129 ok (rc, "Inserting the sub menu menuitem failed\n"); 2130 2131 memset( &info, 0, sizeof info ); 2132 info.cbSize = sizeof info; 2133 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; 2134 info.fType = MFT_STRING; 2135 info.dwTypeData = menuitem2; 2136 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/ 2137 2138 rc = InsertMenuItemA(hmenuSub2, 1, TRUE, &info ); 2139 ok (rc, "Inserting the sub menu menuitem 2 failed\n"); 2140 2141 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/ 2142 memset( &info, 0, sizeof info ); 2143 strback[0] = 0x00; 2144 info.cbSize = sizeof(MENUITEMINFOA); 2145 info.fMask = MIIM_STRING | MIIM_ID; 2146 info.dwTypeData = strback; 2147 info.cch = sizeof(strback); 2148 2149 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); 2150 ok (rc, "Getting the menus info failed\n"); 2151 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n"); 2152 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2153 2154 memset( &info, 0, sizeof info ); 2155 strback[0] = 0x00; 2156 info.cbSize = sizeof(MENUITEMINFOA); 2157 info.fMask = MIIM_STRING | MIIM_ID; 2158 info.dwTypeData = strback; 2159 info.cch = sizeof(strback); 2160 2161 rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info); 2162 ok (rc, "Getting the menus info failed\n"); 2163 ok (info.wID == (UINT_PTR)hmenuSub2, "IDs differ for popup menu\n"); 2164 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2165 2166 DestroyMenu( hmenu ); 2167 DestroyMenu( hmenuSub ); 2168 DestroyMenu( hmenuSub2 ); 2169 2170 2171 /* 2172 Case 5: Menu containing a popup menu which in turn 2173 contains an item with a different id than the popup menu. 2174 This tests the fallback to a popup menu ID. 2175 */ 2176 2177 hmenu = CreateMenu(); 2178 hmenuSub = CreateMenu(); 2179 2180 rc = AppendMenuA(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu"); 2181 ok (rc, "Appending the popup menu to the main menu failed\n"); 2182 2183 rc = AppendMenuA(hmenuSub, MF_STRING, 102, "Item"); 2184 ok (rc, "Appending the item to the popup menu failed\n"); 2185 2186 /* Set the ID for hmenuSub */ 2187 info.cbSize = sizeof(info); 2188 info.fMask = MIIM_ID; 2189 info.wID = 101; 2190 2191 rc = SetMenuItemInfoA(hmenu, 0, TRUE, &info); 2192 ok(rc, "Setting the ID for the popup menu failed\n"); 2193 2194 /* Check if the ID has been set */ 2195 info.wID = 0; 2196 rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); 2197 ok(rc, "Getting the ID for the popup menu failed\n"); 2198 ok(info.wID == 101, "The ID for the popup menu has not been set\n"); 2199 2200 /* Prove getting the item info via ID returns the popup menu */ 2201 memset( &info, 0, sizeof(info)); 2202 strback[0] = 0x00; 2203 info.cbSize = sizeof(MENUITEMINFOA); 2204 info.fMask = MIIM_STRING | MIIM_ID; 2205 info.dwTypeData = strback; 2206 info.cch = sizeof(strback); 2207 2208 rc = GetMenuItemInfoA(hmenu, 101, FALSE, &info); 2209 ok (rc, "Getting the menu info failed\n"); 2210 ok (info.wID == 101, "IDs differ\n"); 2211 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2212 2213 /* Also look for the menu item */ 2214 memset( &info, 0, sizeof(info)); 2215 strback[0] = 0x00; 2216 info.cbSize = sizeof(MENUITEMINFOA); 2217 info.fMask = MIIM_STRING | MIIM_ID; 2218 info.dwTypeData = strback; 2219 info.cch = sizeof(strback); 2220 2221 rc = GetMenuItemInfoA(hmenu, 102, FALSE, &info); 2222 ok (rc, "Getting the menu info failed\n"); 2223 ok (info.wID == 102, "IDs differ\n"); 2224 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData); 2225 2226 DestroyMenu(hmenu); 2227 DestroyMenu(hmenuSub); 2228 } 2229 2230 struct menu_item_pair_s { 2231 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled] 2232 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled] 2233 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */ 2234 UINT uItem; 2235 }; 2236 2237 static struct menu_mouse_tests_s { 2238 DWORD type; 2239 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */ 2240 WORD wVk[5]; /* keys */ 2241 BOOL bMenuVisible; 2242 BOOL _todo_wine; 2243 } menu_tests[] = { 2244 /* for each test, send keys or clicks and check for menu visibility */ 2245 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, /* test 0 */ 2246 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE }, 2247 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, 2248 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, 2249 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, 2250 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, 2251 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, 2252 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE }, 2253 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE }, 2254 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE }, 2255 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, 2256 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, 2257 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, 2258 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, 2259 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE }, 2260 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, 2261 { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE }, 2262 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, 2263 { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, TRUE, FALSE }, 2264 { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, FALSE, FALSE }, 2265 2266 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 20 */ 2267 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, 2268 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE }, 2269 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, 2270 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE }, 2271 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE }, 2272 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE }, 2273 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE }, 2274 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE }, 2275 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE }, 2276 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, 2277 { -1 } 2278 }; 2279 2280 static void send_key(WORD wVk) 2281 { 2282 TEST_INPUT i[2]; 2283 memset(i, 0, sizeof(i)); 2284 i[0].type = i[1].type = INPUT_KEYBOARD; 2285 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk; 2286 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP; 2287 pSendInput(2, (INPUT *) i, sizeof(INPUT)); 2288 } 2289 2290 static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) 2291 { 2292 HMENU hMenu = hMenus[mi->uMenu]; 2293 TEST_INPUT i[3]; 2294 MSG msg; 2295 RECT r; 2296 int screen_w = GetSystemMetrics(SM_CXSCREEN); 2297 int screen_h = GetSystemMetrics(SM_CYSCREEN); 2298 BOOL ret = GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r); 2299 if(!ret) return FALSE; 2300 2301 memset(i, 0, sizeof(i)); 2302 i[0].type = i[1].type = i[2].type = INPUT_MOUSE; 2303 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx 2304 = ((r.left + 5) * 65535) / screen_w; 2305 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy 2306 = ((r.top + 5) * 65535) / screen_h; 2307 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags 2308 = MOUSEEVENTF_ABSOLUTE; 2309 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE; 2310 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; 2311 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP; 2312 ret = pSendInput(3, (INPUT *) i, sizeof(INPUT)); 2313 2314 /* hack to prevent mouse message buildup in Wine */ 2315 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); 2316 return ret; 2317 } 2318 2319 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) 2320 { 2321 int i, j; 2322 HANDLE hWnd = lpParameter; 2323 2324 Sleep(500); 2325 /* mixed keyboard/mouse test */ 2326 for (i = 0; menu_tests[i].type != -1; i++) 2327 { 2328 BOOL ret = TRUE; 2329 int elapsed = 0; 2330 2331 got_input = i && menu_tests[i-1].bMenuVisible; 2332 2333 if (menu_tests[i].type == INPUT_KEYBOARD) 2334 for (j = 0; menu_tests[i].wVk[j] != 0; j++) 2335 send_key(menu_tests[i].wVk[j]); 2336 else 2337 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++) 2338 if (!(ret = click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]))) break; 2339 2340 if (!ret) 2341 { 2342 skip( "test %u: failed to send input\n", i ); 2343 PostMessageA( hWnd, WM_CANCELMODE, 0, 0 ); 2344 return 0; 2345 } 2346 while (menu_tests[i].bMenuVisible != bMenuVisible) 2347 { 2348 if (elapsed > 200) 2349 break; 2350 elapsed += 20; 2351 Sleep(20); 2352 } 2353 2354 if (!got_input) 2355 { 2356 skip( "test %u: didn't receive input\n", i ); 2357 PostMessageA( hWnd, WM_CANCELMODE, 0, 0 ); 2358 return 0; 2359 } 2360 2361 todo_wine_if (menu_tests[i]._todo_wine) 2362 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i); 2363 } 2364 return 0; 2365 } 2366 2367 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, 2368 LPARAM lParam) 2369 { 2370 switch (msg) { 2371 case WM_ENTERMENULOOP: 2372 bMenuVisible = TRUE; 2373 break; 2374 case WM_INITMENUPOPUP: 2375 case WM_UNINITMENUPOPUP: 2376 case WM_EXITMENULOOP: 2377 case WM_MENUSELECT: 2378 break; 2379 2380 case WM_KEYDOWN: 2381 case WM_SYSKEYDOWN: 2382 case WM_MOUSEMOVE: 2383 case WM_LBUTTONDOWN: 2384 case WM_LBUTTONUP: 2385 case WM_NCMOUSEMOVE: 2386 case WM_NCLBUTTONDOWN: 2387 case WM_NCLBUTTONUP: 2388 got_input = TRUE; 2389 /* fall through */ 2390 default: 2391 return( DefWindowProcA( hWnd, msg, wParam, lParam ) ); 2392 } 2393 2394 if(pGetMenuBarInfo) 2395 { 2396 MENUBARINFO mbi; 2397 HMENU hmenu; 2398 UINT state; 2399 BOOL br; 2400 2401 mbi.cbSize = sizeof(MENUBARINFO); 2402 2403 /* get info for the menu */ 2404 br = pGetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi); 2405 ok(br, "msg %x: GetMenuBarInfo failed\n", msg); 2406 hmenu = GetMenu(hWnd); 2407 ok(!mbi.hwndMenu, "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected NULL\n", 2408 msg, mbi.hwndMenu); 2409 ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", 2410 msg, mbi.hMenu, hmenu); 2411 ok(!bMenuVisible == !mbi.fBarFocused, "msg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", 2412 msg, mbi.fBarFocused != 0); 2413 ok(!bMenuVisible == !mbi.fFocused, "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", 2414 msg, mbi.fFocused != 0); 2415 2416 /* get info for the menu's first item */ 2417 br = pGetMenuBarInfo(hWnd, OBJID_MENU, 1, &mbi); 2418 ok(br, "msg %x: GetMenuBarInfo failed\n", msg); 2419 state = GetMenuState(hmenu, 0, MF_BYPOSITION); 2420 if (pGetMenuInfo) /* Skip on NT */ 2421 { 2422 /* Native returns handle to destroyed window */ 2423 todo_wine_if (msg==WM_UNINITMENUPOPUP && popmenu==1) 2424 ok(!mbi.hwndMenu == !popmenu, 2425 "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected %sNULL\n", 2426 msg, mbi.hwndMenu, popmenu ? "not " : ""); 2427 } 2428 ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", 2429 msg, mbi.hMenu, hmenu); 2430 ok(!bMenuVisible == !mbi.fBarFocused, "nsg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", 2431 msg, mbi.fBarFocused != 0); 2432 ok(!(bMenuVisible && (state & MF_HILITE)) == !mbi.fFocused, 2433 "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", msg, mbi.fFocused != 0); 2434 } 2435 2436 if (msg == WM_EXITMENULOOP) 2437 bMenuVisible = FALSE; 2438 else if (msg == WM_INITMENUPOPUP) 2439 popmenu++; 2440 else if (msg == WM_UNINITMENUPOPUP) 2441 popmenu--; 2442 return 0; 2443 } 2444 2445 static void test_menu_input(void) { 2446 MSG msg; 2447 WNDCLASSA wclass; 2448 HINSTANCE hInstance = GetModuleHandleA( NULL ); 2449 HANDLE hThread, hWnd; 2450 DWORD tid; 2451 ATOM aclass; 2452 POINT orig_pos; 2453 2454 if (!pSendInput) 2455 { 2456 win_skip("SendInput is not available\n"); 2457 return; 2458 } 2459 2460 wclass.lpszClassName = "MenuTestClass"; 2461 wclass.style = CS_HREDRAW | CS_VREDRAW; 2462 wclass.lpfnWndProc = WndProc; 2463 wclass.hInstance = hInstance; 2464 wclass.hIcon = LoadIconA( 0, (LPCSTR)IDI_APPLICATION ); 2465 wclass.hCursor = LoadCursorA( 0, (LPCSTR)IDC_ARROW ); 2466 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 ); 2467 wclass.lpszMenuName = 0; 2468 wclass.cbClsExtra = 0; 2469 wclass.cbWndExtra = 0; 2470 aclass = RegisterClassA( &wclass ); 2471 ok (aclass, "MenuTest class not created\n"); 2472 if (!aclass) return; 2473 hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest", 2474 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 2475 400, 200, NULL, NULL, hInstance, NULL); 2476 ok (hWnd != NULL, "MenuTest window not created\n"); 2477 if (!hWnd) return; 2478 /* fixed menus */ 2479 hMenus[3] = CreatePopupMenu(); 2480 AppendMenuA(hMenus[3], MF_STRING, 0, "&Enabled"); 2481 AppendMenuA(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled"); 2482 2483 hMenus[2] = CreatePopupMenu(); 2484 AppendMenuA(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup"); 2485 AppendMenuA(hMenus[2], MF_STRING, 0, "&Enabled"); 2486 AppendMenuA(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled"); 2487 2488 hMenus[1] = CreateMenu(); 2489 AppendMenuA(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu"); 2490 AppendMenuA(hMenus[1], MF_STRING, 0, "&Enabled"); 2491 AppendMenuA(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled"); 2492 2493 SetMenu(hWnd, hMenus[1]); 2494 ShowWindow(hWnd, SW_SHOW); 2495 UpdateWindow(hWnd); 2496 2497 GetCursorPos(&orig_pos); 2498 2499 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid); 2500 while(1) 2501 { 2502 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50)) 2503 break; 2504 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); 2505 } 2506 SetCursorPos(orig_pos.x, orig_pos.y); 2507 DestroyWindow(hWnd); 2508 } 2509 2510 static void test_menu_flags( void ) 2511 { 2512 HMENU hMenu, hPopupMenu; 2513 2514 hMenu = CreateMenu(); 2515 hPopupMenu = CreatePopupMenu(); 2516 2517 AppendMenuA(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup"); 2518 2519 AppendMenuA(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1"); 2520 InsertMenuA(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2"); 2521 AppendMenuA(hPopupMenu, MF_STRING, 103, "Item 3"); 2522 ModifyMenuA(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3"); 2523 2524 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE, 2525 "AppendMenu should accept MF_HILITE\n"); 2526 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE, 2527 "InsertMenu should accept MF_HILITE\n"); 2528 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE, 2529 "ModifyMenu should accept MF_HILITE\n"); 2530 2531 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT), 2532 "AppendMenu must not accept MF_DEFAULT\n"); 2533 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT), 2534 "InsertMenu must not accept MF_DEFAULT\n"); 2535 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT), 2536 "ModifyMenu must not accept MF_DEFAULT\n"); 2537 2538 DestroyMenu(hMenu); 2539 } 2540 2541 static void test_menu_hilitemenuitem( void ) 2542 { 2543 HMENU hMenu, hPopupMenu; 2544 WNDCLASSA wclass; 2545 HWND hWnd; 2546 ATOM aclass; 2547 2548 wclass.lpszClassName = "HiliteMenuTestClass"; 2549 wclass.style = CS_HREDRAW | CS_VREDRAW; 2550 wclass.lpfnWndProc = WndProc; 2551 wclass.hInstance = GetModuleHandleA( NULL ); 2552 wclass.hIcon = LoadIconA( 0, (LPCSTR)IDI_APPLICATION ); 2553 wclass.hCursor = LoadCursorA( 0, (LPCSTR)IDC_ARROW ); 2554 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 ); 2555 wclass.lpszMenuName = 0; 2556 wclass.cbClsExtra = 0; 2557 wclass.cbWndExtra = 0; 2558 aclass = RegisterClassA( &wclass ); 2559 ok (aclass, "HiliteMenuTest class could not be created\n"); 2560 if (!aclass) return; 2561 hWnd = CreateWindowA( wclass.lpszClassName, "HiliteMenuTest", 2562 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 2563 400, 200, NULL, NULL, wclass.hInstance, NULL); 2564 ok (hWnd != NULL, "HiliteMenuTest window could not be created\n"); 2565 if (!hWnd) return; 2566 2567 hMenu = CreateMenu(); 2568 hPopupMenu = CreatePopupMenu(); 2569 2570 AppendMenuA(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup"); 2571 2572 AppendMenuA(hPopupMenu, MF_STRING, 101, "Item 1"); 2573 AppendMenuA(hPopupMenu, MF_STRING, 102, "Item 2"); 2574 AppendMenuA(hPopupMenu, MF_STRING, 103, "Item 3"); 2575 2576 SetMenu(hWnd, hMenu); 2577 2578 /* test invalid arguments */ 2579 2580 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), 2581 "HiliteMenuItem: Item 2 is hilited\n"); 2582 2583 SetLastError(0xdeadbeef); 2584 todo_wine 2585 { 2586 ok(!HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION), 2587 "HiliteMenuItem: call should have failed.\n"); 2588 } 2589 ok(GetLastError() == 0xdeadbeef || /* 9x */ 2590 GetLastError() == ERROR_INVALID_WINDOW_HANDLE /* NT */, 2591 "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError()); 2592 2593 SetLastError(0xdeadbeef); 2594 ok(!HiliteMenuItem(hWnd, NULL, 1, MF_HILITE | MF_BYPOSITION), 2595 "HiliteMenuItem: call should have failed.\n"); 2596 ok(GetLastError() == 0xdeadbeef || /* 9x */ 2597 GetLastError() == ERROR_INVALID_MENU_HANDLE /* NT */, 2598 "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError()); 2599 2600 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), 2601 "HiliteMenuItem: Item 2 is hilited\n"); 2602 2603 /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */ 2604 2605 SetLastError(0xdeadbeef); 2606 ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_BYPOSITION), 2607 "HiliteMenuItem: call should have succeeded.\n"); 2608 ok(GetLastError() == 0xdeadbeef, 2609 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2610 2611 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), 2612 "HiliteMenuItem: Item 2 is hilited\n"); 2613 2614 SetLastError(0xdeadbeef); 2615 todo_wine 2616 { 2617 ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE), 2618 "HiliteMenuItem: call should have succeeded.\n"); 2619 } 2620 ok(GetLastError() == 0xdeadbeef, 2621 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2622 2623 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), 2624 "HiliteMenuItem: Item 2 is hilited\n"); 2625 2626 /* hilite a menu item (by position) */ 2627 2628 SetLastError(0xdeadbeef); 2629 ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION), 2630 "HiliteMenuItem: call should not have failed.\n"); 2631 ok(GetLastError() == 0xdeadbeef, 2632 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2633 2634 todo_wine 2635 { 2636 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE, 2637 "HiliteMenuItem: Item 2 is not hilited\n"); 2638 } 2639 2640 /* unhilite a menu item (by position) */ 2641 2642 SetLastError(0xdeadbeef); 2643 ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_UNHILITE | MF_BYPOSITION), 2644 "HiliteMenuItem: call should not have failed.\n"); 2645 ok(GetLastError() == 0xdeadbeef, 2646 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2647 2648 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), 2649 "HiliteMenuItem: Item 2 is hilited\n"); 2650 2651 /* hilite a menu item (by command) */ 2652 2653 SetLastError(0xdeadbeef); 2654 ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_HILITE | MF_BYCOMMAND), 2655 "HiliteMenuItem: call should not have failed.\n"); 2656 ok(GetLastError() == 0xdeadbeef, 2657 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2658 2659 todo_wine 2660 { 2661 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE, 2662 "HiliteMenuItem: Item 3 is not hilited\n"); 2663 } 2664 2665 /* unhilite a menu item (by command) */ 2666 2667 SetLastError(0xdeadbeef); 2668 ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_UNHILITE | MF_BYCOMMAND), 2669 "HiliteMenuItem: call should not have failed.\n"); 2670 ok(GetLastError() == 0xdeadbeef, 2671 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); 2672 2673 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE), 2674 "HiliteMenuItem: Item 3 is hilited\n"); 2675 2676 DestroyWindow(hWnd); 2677 } 2678 2679 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type, 2680 UINT checked_state) 2681 { 2682 INT i, count; 2683 2684 count = GetMenuItemCount(hmenu); 2685 ok (count != -1, "GetMenuItemCount returned -1\n"); 2686 2687 for (i = 0; i < count; i++) 2688 { 2689 BOOL ret; 2690 MENUITEMINFOA mii; 2691 2692 memset(&mii, 0, sizeof(mii)); 2693 mii.cbSize = sizeof(mii); 2694 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU; 2695 ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii); 2696 ok(ret, "GetMenuItemInfo(%u) failed\n", i); 2697 2698 if (winetest_debug > 1) 2699 trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n", 2700 i, mii.fType, mii.fState, mii.wID, mii.hSubMenu); 2701 2702 if (mii.hSubMenu) 2703 { 2704 ok(mii.wID == (UINT_PTR)mii.hSubMenu, "id %u: wID %x should be equal to hSubMenu %p\n", 2705 checked_cmd, mii.wID, mii.hSubMenu); 2706 if (!GetMenuItemCount(mii.hSubMenu)) 2707 { 2708 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType); 2709 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState); 2710 } 2711 check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state); 2712 } 2713 else 2714 { 2715 if (mii.wID == checked_cmd) 2716 { 2717 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType); 2718 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState); 2719 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd); 2720 } 2721 else 2722 { 2723 ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID); 2724 2725 if (mii.fType == MFT_SEPARATOR) 2726 { 2727 ok(mii.fState == MFS_GRAYED, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd, mii.fState); 2728 ok(mii.wID == 0, "id %u: expected wID 0, got %u\n", checked_cmd, mii.wID); 2729 } 2730 else 2731 { 2732 ok(mii.fState == 0, "id %u: expected fState 0, got %04x\n", checked_cmd, mii.fState); 2733 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd); 2734 } 2735 } 2736 } 2737 } 2738 } 2739 2740 static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags) 2741 { 2742 BOOL ret; 2743 MENUITEMINFOA mii; 2744 2745 memset(&mii, 0, sizeof(mii)); 2746 mii.cbSize = sizeof(mii); 2747 mii.fMask = MIIM_FTYPE | MIIM_STATE; 2748 ret = SetMenuItemInfoA(hmenu, id, (flags & MF_BYPOSITION) != 0, &mii); 2749 ok(ret, "SetMenuItemInfo(%u) failed\n", id); 2750 } 2751 2752 static void test_CheckMenuRadioItem(void) 2753 { 2754 BOOL ret; 2755 HMENU hmenu; 2756 2757 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1)); 2758 assert(hmenu != 0); 2759 2760 check_menu_items(hmenu, -1, 0, 0); 2761 2762 ret = CheckMenuRadioItem(hmenu, 100, 100, 100, MF_BYCOMMAND); 2763 ok(ret, "CheckMenuRadioItem failed\n"); 2764 check_menu_items(hmenu, 100, MFT_RADIOCHECK, MFS_CHECKED); 2765 2766 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ 2767 ret = CheckMenuRadioItem(hmenu, 100, 100, -1, MF_BYCOMMAND); 2768 ok(!ret, "CheckMenuRadioItem should return FALSE\n"); 2769 check_menu_items(hmenu, 100, MFT_RADIOCHECK, 0); 2770 2771 /* clear check */ 2772 clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND); 2773 check_menu_items(hmenu, -1, 0, 0); 2774 2775 /* first and checked items are on different menus */ 2776 ret = CheckMenuRadioItem(hmenu, 0, 300, 202, MF_BYCOMMAND); 2777 ok(!ret, "CheckMenuRadioItem should return FALSE\n"); 2778 check_menu_items(hmenu, -1, 0, 0); 2779 2780 ret = CheckMenuRadioItem(hmenu, 200, 300, 202, MF_BYCOMMAND); 2781 ok(ret, "CheckMenuRadioItem failed\n"); 2782 check_menu_items(hmenu, 202, MFT_RADIOCHECK, MFS_CHECKED); 2783 2784 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ 2785 ret = CheckMenuRadioItem(hmenu, 202, 202, -1, MF_BYCOMMAND); 2786 ok(!ret, "CheckMenuRadioItem should return FALSE\n"); 2787 check_menu_items(hmenu, 202, MFT_RADIOCHECK, 0); 2788 2789 /* clear check */ 2790 clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND); 2791 check_menu_items(hmenu, -1, 0, 0); 2792 2793 /* just for fun, try to check separator */ 2794 ret = CheckMenuRadioItem(hmenu, 0, 300, 0, MF_BYCOMMAND); 2795 ok(!ret, "CheckMenuRadioItem should return FALSE\n"); 2796 check_menu_items(hmenu, -1, 0, 0); 2797 } 2798 2799 static void test_menu_resource_layout(void) 2800 { 2801 static const struct 2802 { 2803 MENUITEMTEMPLATEHEADER mith; 2804 WORD data[14]; 2805 } menu_template = 2806 { 2807 { 0, 0 }, /* versionNumber, offset */ 2808 { 2809 /* mtOption, mtID, mtString[] '\0' terminated */ 2810 MF_STRING, 1, 'F', 0, 2811 MF_STRING, 2, 0, 2812 MF_SEPARATOR, 3, 0, 2813 /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */ 2814 MF_STRING|MF_GRAYED|MF_END, 5, 'E', 0 2815 } 2816 }; 2817 static const struct 2818 { 2819 UINT type, state, id; 2820 const char *str; 2821 } menu_data[] = 2822 { 2823 { MF_STRING, MF_ENABLED, 1, "F" }, 2824 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 2, "" }, 2825 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 3, "" }, 2826 /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/ 2827 { MF_STRING, MF_GRAYED, 5, "E" }, 2828 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 6, "" }, 2829 { MF_STRING, MF_ENABLED, 7, "" }, 2830 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" } 2831 }; 2832 HMENU hmenu; 2833 INT count, i; 2834 BOOL ret; 2835 2836 hmenu = LoadMenuIndirectA(&menu_template); 2837 ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError()); 2838 2839 ret = AppendMenuA(hmenu, MF_STRING, 6, NULL); 2840 ok(ret, "AppendMenu failed\n"); 2841 ret = AppendMenuA(hmenu, MF_STRING, 7, "\0"); 2842 ok(ret, "AppendMenu failed\n"); 2843 ret = AppendMenuA(hmenu, MF_SEPARATOR, 8, "separator"); 2844 ok(ret, "AppendMenu failed\n"); 2845 2846 count = GetMenuItemCount(hmenu); 2847 ok(count == sizeof(menu_data)/sizeof(menu_data[0]), 2848 "expected %u menu items, got %u\n", 2849 (UINT)(sizeof(menu_data)/sizeof(menu_data[0])), count); 2850 2851 for (i = 0; i < count; i++) 2852 { 2853 char buf[20]; 2854 MENUITEMINFOA mii; 2855 2856 memset(&mii, 0, sizeof(mii)); 2857 mii.cbSize = sizeof(mii); 2858 mii.dwTypeData = buf; 2859 mii.cch = sizeof(buf); 2860 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_STRING; 2861 ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii); 2862 ok(ret, "GetMenuItemInfo(%u) failed\n", i); 2863 if (winetest_debug > 1) 2864 trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n", 2865 i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData); 2866 2867 ok(mii.fType == menu_data[i].type, 2868 "%u: expected fType %04x, got %04x\n", i, menu_data[i].type, mii.fType); 2869 ok(mii.fState == menu_data[i].state, 2870 "%u: expected fState %04x, got %04x\n", i, menu_data[i].state, mii.fState); 2871 ok(mii.wID == menu_data[i].id, 2872 "%u: expected wID %04x, got %04x\n", i, menu_data[i].id, mii.wID); 2873 ok(mii.cch == strlen(menu_data[i].str), 2874 "%u: expected cch %u, got %u\n", i, (UINT)strlen(menu_data[i].str), mii.cch); 2875 ok(!strcmp(mii.dwTypeData, menu_data[i].str), 2876 "%u: expected dwTypeData %s, got %s\n", i, menu_data[i].str, (LPCSTR)mii.dwTypeData); 2877 } 2878 2879 DestroyMenu(hmenu); 2880 } 2881 2882 struct menu_data 2883 { 2884 UINT type, id; 2885 const char *str; 2886 }; 2887 2888 static HMENU create_menu_from_data(const struct menu_data *item, INT item_count) 2889 { 2890 HMENU hmenu; 2891 INT i; 2892 BOOL ret; 2893 2894 hmenu = CreateMenu(); 2895 assert(hmenu != 0); 2896 2897 for (i = 0; i < item_count; i++) 2898 { 2899 SetLastError(0xdeadbeef); 2900 ret = AppendMenuA(hmenu, item[i].type, item[i].id, item[i].str); 2901 ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %u\n", 2902 i, item[i].type, item[i].id, item[i].str, GetLastError()); 2903 } 2904 return hmenu; 2905 } 2906 2907 /* use InsertMenuItem: does not set the MFT_BITMAP flag, 2908 * and does not accept non-magic bitmaps with invalid 2909 * bitmap handles */ 2910 static HMENU create_menuitem_from_data(const struct menu_data *item, INT item_count) 2911 { 2912 HMENU hmenu; 2913 INT i; 2914 BOOL ret; 2915 MENUITEMINFOA mii = { sizeof( MENUITEMINFOA) }; 2916 2917 hmenu = CreateMenu(); 2918 assert(hmenu != 0); 2919 2920 for (i = 0; i < item_count; i++) 2921 { 2922 SetLastError(0xdeadbeef); 2923 2924 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE; 2925 mii.fType = 0; 2926 if( item[i].type & MFT_BITMAP) 2927 { 2928 mii.fMask |= MIIM_BITMAP; 2929 mii.hbmpItem = (HBITMAP)item[i].str; 2930 } 2931 else if( item[i].type & MFT_SEPARATOR) 2932 mii.fType = MFT_SEPARATOR; 2933 else 2934 { 2935 mii.fMask |= MIIM_STRING; 2936 mii.dwTypeData = (LPSTR)item[i].str; 2937 mii.cch = strlen( item[i].str); 2938 } 2939 mii.fState = 0; 2940 if( item[i].type & MF_HELP) mii.fType |= MF_HELP; 2941 mii.wID = item[i].id; 2942 ret = InsertMenuItemA( hmenu, -1, TRUE, &mii); 2943 ok(ret, "%d: InsertMenuItem(%04x, %04x, %p) error %u\n", 2944 i, item[i].type, item[i].id, item[i].str, GetLastError()); 2945 } 2946 return hmenu; 2947 } 2948 2949 static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count) 2950 { 2951 INT count, i; 2952 BOOL ret; 2953 2954 count = GetMenuItemCount(hmenu); 2955 ok(count == item_count, "expected %d, got %d menu items\n", count, item_count); 2956 2957 for (i = 0; i < count; i++) 2958 { 2959 char buf[20]; 2960 MENUITEMINFOA mii; 2961 2962 memset(&mii, 0, sizeof(mii)); 2963 mii.cbSize = sizeof(mii); 2964 mii.dwTypeData = buf; 2965 mii.cch = sizeof(buf); 2966 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_BITMAP; 2967 ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii); 2968 ok(ret, "GetMenuItemInfo(%u) failed\n", i); 2969 2970 if (winetest_debug > 1) 2971 trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n", 2972 i, mii.fType, mii.fState, mii.wID, mii.hbmpItem); 2973 2974 ok(mii.fType == item[i].type, 2975 "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType); 2976 ok(mii.wID == item[i].id, 2977 "%u: expected wID %04x, got %04x\n", i, item[i].id, mii.wID); 2978 if (mii.hbmpItem || !item[i].str) 2979 /* For some reason Windows sets high word to not 0 for 2980 * not "magic" ids. 2981 */ 2982 ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str), 2983 "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem); 2984 else 2985 { 2986 ok(mii.cch == strlen(item[i].str), 2987 "%u: expected cch %u, got %u\n", i, (UINT)strlen(item[i].str), mii.cch); 2988 ok(!strcmp(mii.dwTypeData, item[i].str), 2989 "%u: expected dwTypeData %s, got %s\n", i, item[i].str, (LPCSTR)mii.dwTypeData); 2990 } 2991 } 2992 } 2993 2994 static void test_InsertMenu(void) 2995 { 2996 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL); 2997 /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones 2998 * regardless of their id. 2999 */ 3000 static const struct menu_data in1[] = 3001 { 3002 { MF_STRING, 1, "File" }, 3003 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) }, 3004 { MF_STRING|MF_HELP, 2, "Help" } 3005 }; 3006 static const struct menu_data out1[] = 3007 { 3008 { MF_STRING, 1, "File" }, 3009 { MF_STRING|MF_HELP, 2, "Help" }, 3010 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) } 3011 }; 3012 static const struct menu_data out1a[] = 3013 { 3014 { MF_STRING, 1, "File" }, 3015 { MF_STRING|MF_HELP, 2, "Help" }, 3016 { MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) } 3017 }; 3018 const struct menu_data in2[] = 3019 { 3020 { MF_STRING, 1, "File" }, 3021 { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm }, 3022 { MF_STRING|MF_HELP, 2, "Help" } 3023 }; 3024 const struct menu_data out2[] = 3025 { 3026 { MF_STRING, 1, "File" }, 3027 { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm }, 3028 { MF_STRING|MF_HELP, 2, "Help" } 3029 }; 3030 const struct menu_data out2a[] = 3031 { 3032 { MF_STRING, 1, "File" }, 3033 { MF_HELP, SC_CLOSE, (char*)hbm }, 3034 { MF_STRING|MF_HELP, 2, "Help" } 3035 }; 3036 static const struct menu_data in3[] = 3037 { 3038 { MF_STRING, 1, "File" }, 3039 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) }, 3040 { MF_STRING|MF_HELP, 2, "Help" } 3041 }; 3042 static const struct menu_data out3[] = 3043 { 3044 { MF_STRING, 1, "File" }, 3045 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(0) }, 3046 { MF_STRING|MF_HELP, 2, "Help" }, 3047 }; 3048 static const struct menu_data in4[] = 3049 { 3050 { MF_STRING, 1, "File" }, 3051 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCEA(1) }, 3052 { MF_STRING|MF_HELP, 2, "Help" } 3053 }; 3054 static const struct menu_data out4[] = 3055 { 3056 { MF_STRING, 1, "File" }, 3057 { MF_STRING|MF_HELP, 2, "Help" }, 3058 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCEA(1) } 3059 }; 3060 static const struct menu_data out4a[] = 3061 { 3062 { MF_STRING, 1, "File" }, 3063 { MF_STRING|MF_HELP, 2, "Help" }, 3064 { MF_HELP, 1, MAKEINTRESOURCEA(1) } 3065 }; 3066 HMENU hmenu; 3067 3068 #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0])) 3069 #define create_menuitem(a) create_menuitem_from_data((a), sizeof(a)/sizeof((a)[0])) 3070 #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0])) 3071 3072 hmenu = create_menu(in1); 3073 compare_menu(hmenu, out1); 3074 DestroyMenu(hmenu); 3075 3076 hmenu = create_menu(in2); 3077 compare_menu(hmenu, out2); 3078 DestroyMenu(hmenu); 3079 3080 hmenu = create_menu(in3); 3081 compare_menu(hmenu, out3); 3082 DestroyMenu(hmenu); 3083 3084 hmenu = create_menu(in4); 3085 compare_menu(hmenu, out4); 3086 DestroyMenu(hmenu); 3087 3088 /* now using InsertMenuItemInfo */ 3089 hmenu = create_menuitem(in1); 3090 compare_menu(hmenu, out1a); 3091 DestroyMenu(hmenu); 3092 3093 hmenu = create_menuitem(in2); 3094 compare_menu(hmenu, out2a); 3095 DestroyMenu(hmenu); 3096 3097 hmenu = create_menuitem(in3); 3098 compare_menu(hmenu, out3); 3099 DestroyMenu(hmenu); 3100 3101 hmenu = create_menuitem(in4); 3102 compare_menu(hmenu, out4a); 3103 DestroyMenu(hmenu); 3104 3105 #undef create_menu 3106 #undef create_menuitem 3107 #undef compare_menu 3108 } 3109 3110 static void test_menu_getmenuinfo(void) 3111 { 3112 HMENU hmenu; 3113 MENUINFO mi = {0}; 3114 BOOL ret; 3115 DWORD gle; 3116 3117 if (!pGetMenuInfo) 3118 { 3119 win_skip("GetMenuInfo is not available\n"); 3120 return; 3121 } 3122 3123 /* create a menu */ 3124 hmenu = CreateMenu(); 3125 assert( hmenu); 3126 /* test some parameter errors */ 3127 SetLastError(0xdeadbeef); 3128 ret = pGetMenuInfo( hmenu, NULL); 3129 gle= GetLastError(); 3130 ok( !ret, "GetMenuInfo() should have failed\n"); 3131 ok( gle == ERROR_INVALID_PARAMETER || 3132 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3133 "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3134 SetLastError(0xdeadbeef); 3135 mi.cbSize = 0; 3136 ret = pGetMenuInfo( hmenu, &mi); 3137 gle= GetLastError(); 3138 ok( !ret, "GetMenuInfo() should have failed\n"); 3139 ok( gle == ERROR_INVALID_PARAMETER || 3140 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3141 "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3142 SetLastError(0xdeadbeef); 3143 mi.cbSize = sizeof( MENUINFO); 3144 ret = pGetMenuInfo( hmenu, &mi); 3145 gle= GetLastError(); 3146 ok( ret, "GetMenuInfo() should have succeeded\n"); 3147 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3148 SetLastError(0xdeadbeef); 3149 mi.cbSize = 0; 3150 ret = pGetMenuInfo( NULL, &mi); 3151 gle= GetLastError(); 3152 ok( !ret, "GetMenuInfo() should have failed\n"); 3153 ok( gle == ERROR_INVALID_PARAMETER || 3154 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3155 "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3156 /* clean up */ 3157 DestroyMenu( hmenu); 3158 return; 3159 } 3160 3161 static void test_menu_setmenuinfo(void) 3162 { 3163 HMENU hmenu, hsubmenu; 3164 MENUINFO mi = {0}; 3165 MENUITEMINFOA mii = { sizeof(MENUITEMINFOA) }; 3166 BOOL ret; 3167 DWORD gle; 3168 HBRUSH brush; 3169 3170 if (!pGetMenuInfo || !pSetMenuInfo) 3171 { 3172 win_skip("Get/SetMenuInfo are not available\n"); 3173 return; 3174 } 3175 3176 /* create a menu with a submenu */ 3177 hmenu = CreateMenu(); 3178 hsubmenu = CreateMenu(); 3179 assert( hmenu && hsubmenu); 3180 mii.fMask = MIIM_SUBMENU; 3181 mii.hSubMenu = hsubmenu; 3182 ret = InsertMenuItemA( hmenu, 0, FALSE, &mii); 3183 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); 3184 /* test some parameter errors */ 3185 SetLastError(0xdeadbeef); 3186 ret = pSetMenuInfo( hmenu, NULL); 3187 gle= GetLastError(); 3188 ok( !ret, "SetMenuInfo() should have failed\n"); 3189 ok( gle == ERROR_INVALID_PARAMETER || 3190 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3191 "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3192 SetLastError(0xdeadbeef); 3193 mi.cbSize = 0; 3194 ret = pSetMenuInfo( hmenu, &mi); 3195 gle= GetLastError(); 3196 ok( !ret, "SetMenuInfo() should have failed\n"); 3197 ok( gle == ERROR_INVALID_PARAMETER || 3198 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3199 "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3200 SetLastError(0xdeadbeef); 3201 mi.cbSize = sizeof( MENUINFO); 3202 ret = pSetMenuInfo( hmenu, &mi); 3203 gle= GetLastError(); 3204 ok( ret, "SetMenuInfo() should have succeeded\n"); 3205 ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); 3206 SetLastError(0xdeadbeef); 3207 mi.cbSize = 0; 3208 ret = pSetMenuInfo( NULL, &mi); 3209 gle= GetLastError(); 3210 ok( !ret, "SetMenuInfo() should have failed\n"); 3211 ok( gle == ERROR_INVALID_PARAMETER || 3212 broken(gle == 0xdeadbeef), /* Win98, WinME */ 3213 "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); 3214 /* functional tests */ 3215 /* menu and submenu should have the CHECKORBMP style bit cleared */ 3216 SetLastError(0xdeadbeef); 3217 mi.cbSize = sizeof( MENUINFO); 3218 mi.fMask = MIM_STYLE; 3219 ret = pGetMenuInfo( hmenu, &mi); 3220 gle= GetLastError(); 3221 ok( ret, "GetMenuInfo() should have succeeded\n"); 3222 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3223 ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); 3224 SetLastError(0xdeadbeef); 3225 mi.cbSize = sizeof( MENUINFO); 3226 mi.fMask = MIM_STYLE; 3227 ret = pGetMenuInfo( hsubmenu, &mi); 3228 gle= GetLastError(); 3229 ok( ret, "GetMenuInfo() should have succeeded\n"); 3230 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3231 ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); 3232 /* SetMenuInfo() */ 3233 SetLastError(0xdeadbeef); 3234 mi.cbSize = sizeof( MENUINFO); 3235 mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS; 3236 mi.dwStyle = MNS_CHECKORBMP; 3237 ret = pSetMenuInfo( hmenu, &mi); 3238 gle= GetLastError(); 3239 ok( ret, "SetMenuInfo() should have succeeded\n"); 3240 ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); 3241 /* Now both menus should have the MNS_CHECKORBMP style bit set */ 3242 SetLastError(0xdeadbeef); 3243 mi.cbSize = sizeof( MENUINFO); 3244 mi.fMask = MIM_STYLE; 3245 ret = pGetMenuInfo( hmenu, &mi); 3246 gle= GetLastError(); 3247 ok( ret, "GetMenuInfo() should have succeeded\n"); 3248 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3249 ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); 3250 SetLastError(0xdeadbeef); 3251 mi.cbSize = sizeof( MENUINFO); 3252 mi.fMask = MIM_STYLE; 3253 ret = pGetMenuInfo( hsubmenu, &mi); 3254 gle= GetLastError(); 3255 ok( ret, "GetMenuInfo() should have succeeded\n"); 3256 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3257 ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); 3258 /* now repeat that without the APPLYTOSUBMENUS flag and another style bit */ 3259 SetLastError(0xdeadbeef); 3260 mi.cbSize = sizeof( MENUINFO); 3261 mi.fMask = MIM_STYLE ; 3262 mi.dwStyle = MNS_NOCHECK; 3263 ret = pSetMenuInfo( hmenu, &mi); 3264 gle= GetLastError(); 3265 ok( ret, "SetMenuInfo() should have succeeded\n"); 3266 ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); 3267 /* Now only the top menu should have the MNS_NOCHECK style bit set */ 3268 SetLastError(0xdeadbeef); 3269 mi.cbSize = sizeof( MENUINFO); 3270 mi.fMask = MIM_STYLE; 3271 ret = pGetMenuInfo( hmenu, &mi); 3272 gle= GetLastError(); 3273 ok( ret, "GetMenuInfo() should have succeeded\n"); 3274 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3275 ok( mi.dwStyle & MNS_NOCHECK, "menustyle was expected to have the MNS_NOCHECK flag\n"); 3276 SetLastError(0xdeadbeef); 3277 mi.cbSize = sizeof( MENUINFO); 3278 mi.fMask = MIM_STYLE; 3279 ret = pGetMenuInfo( hsubmenu, &mi); 3280 gle= GetLastError(); 3281 ok( ret, "GetMenuInfo() should have succeeded\n"); 3282 ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); 3283 ok( !(mi.dwStyle & MNS_NOCHECK), "menustyle was not expected to have the MNS_NOCHECK flag\n"); 3284 3285 /* test background brush */ 3286 mi.cbSize = sizeof(mi); 3287 mi.fMask = MIM_BACKGROUND; 3288 ret = pGetMenuInfo( hmenu, &mi ); 3289 ok( ret, "GetMenuInfo() should have succeeded\n" ); 3290 ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack ); 3291 3292 brush = CreateSolidBrush( RGB(0xff, 0, 0) ); 3293 mi.hbrBack = brush; 3294 ret = pSetMenuInfo( hmenu, &mi ); 3295 ok( ret, "SetMenuInfo() should have succeeded\n" ); 3296 mi.hbrBack = NULL; 3297 ret = pGetMenuInfo( hmenu, &mi ); 3298 ok( ret, "GetMenuInfo() should have succeeded\n" ); 3299 ok( mi.hbrBack == brush, "got %p original %p\n", mi.hbrBack, brush ); 3300 3301 mi.hbrBack = NULL; 3302 ret = pSetMenuInfo( hmenu, &mi ); 3303 ok( ret, "SetMenuInfo() should have succeeded\n" ); 3304 ret = pGetMenuInfo( hmenu, &mi ); 3305 ok( ret, "GetMenuInfo() should have succeeded\n" ); 3306 ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack ); 3307 DeleteObject( brush ); 3308 3309 /* clean up */ 3310 DestroyMenu( hsubmenu); 3311 DestroyMenu( hmenu); 3312 return; 3313 } 3314 3315 /* little func to easy switch either TrackPopupMenu() or TrackPopupMenuEx() */ 3316 static DWORD MyTrackPopupMenu( int ex, HMENU hmenu, UINT flags, INT x, INT y, HWND hwnd, LPTPMPARAMS ptpm) 3317 { 3318 return ex 3319 ? TrackPopupMenuEx( hmenu, flags, x, y, hwnd, ptpm) 3320 : TrackPopupMenu( hmenu, flags, x, y, 0, hwnd, NULL); 3321 } 3322 3323 /* some TrackPopupMenu and TrackPopupMenuEx tests */ 3324 /* the LastError values differ between NO_ERROR and invalid handle */ 3325 /* between all windows versions tested. The first value is that valid on XP */ 3326 /* Vista was the only that made returned different error values */ 3327 /* between the TrackPopupMenu and TrackPopupMenuEx functions */ 3328 static void test_menu_trackpopupmenu(void) 3329 { 3330 BOOL ret; 3331 HMENU hmenu; 3332 DWORD gle; 3333 int Ex; 3334 HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 3335 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 3336 NULL, NULL, NULL, NULL); 3337 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 3338 if (!hwnd) return; 3339 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); 3340 for( Ex = 0; Ex < 2; Ex++) 3341 { 3342 hmenu = CreatePopupMenu(); 3343 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 3344 if (!hmenu) 3345 { 3346 DestroyWindow(hwnd); 3347 return; 3348 } 3349 /* display the menu */ 3350 /* start with an invalid menu handle */ 3351 SetLastError(0xdeadbeef); 3352 3353 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; 3354 ret = MyTrackPopupMenu( Ex, NULL, TPM_RETURNCMD, 100,100, hwnd, NULL); 3355 gle = GetLastError(); 3356 ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); 3357 ok( gle == ERROR_INVALID_MENU_HANDLE 3358 || broken (gle == 0xdeadbeef) /* win95 */ 3359 || broken (gle == NO_ERROR) /* win98/ME */ 3360 ,"TrackPopupMenu%s error got %u expected %u\n", 3361 Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); 3362 ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), 3363 "got unexpected message(s)%s%s%s\n", 3364 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", 3365 gflag_entermenuloop ? "WM_INITMENULOOP ": "", 3366 gflag_initmenu ? "WM_INITMENU": ""); 3367 /* another one but not NULL */ 3368 SetLastError(0xdeadbeef); 3369 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; 3370 ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, TPM_RETURNCMD, 100,100, hwnd, NULL); 3371 gle = GetLastError(); 3372 ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); 3373 ok( gle == ERROR_INVALID_MENU_HANDLE 3374 || broken (gle == 0xdeadbeef) /* win95 */ 3375 || broken (gle == NO_ERROR) /* win98/ME */ 3376 ,"TrackPopupMenu%s error got %u expected %u\n", 3377 Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); 3378 ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), 3379 "got unexpected message(s)%s%s%s\n", 3380 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", 3381 gflag_entermenuloop ? "WM_INITMENULOOP ": "", 3382 gflag_initmenu ? "WM_INITMENU": ""); 3383 3384 /* invalid window */ 3385 SetLastError(0xdeadbeef); 3386 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; 3387 ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, 0, NULL); 3388 gle = GetLastError(); 3389 ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); 3390 ok( gle == ERROR_INVALID_WINDOW_HANDLE, "TrackPopupMenu%s error got %u\n", Ex ? "Ex" : "", gle ); 3391 ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), 3392 "got unexpected message(s)%s%s%s\n", 3393 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", 3394 gflag_entermenuloop ? "WM_INITMENULOOP ": "", 3395 gflag_initmenu ? "WM_INITMENU": ""); 3396 3397 /* now a somewhat successful call */ 3398 SetLastError(0xdeadbeef); 3399 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; 3400 ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL); 3401 gle = GetLastError(); 3402 ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); 3403 ok( gle == NO_ERROR 3404 || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k */ 3405 || broken (gle == 0xdeadbeef) /* win95 */ 3406 ,"TrackPopupMenu%s error got %u expected %u or %u\n", 3407 Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); 3408 ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, 3409 "missed expected message(s)%s%s%s\n", 3410 !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", 3411 !gflag_entermenuloop ? "WM_INITMENULOOP ": "", 3412 !gflag_initmenu ? "WM_INITMENU": ""); 3413 /* and another */ 3414 ret = AppendMenuA( hmenu, MF_STRING, 1, "winetest"); 3415 ok( ret, "AppendMenA has failed!\n"); 3416 SetLastError(0xdeadbeef); 3417 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; 3418 ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL); 3419 gle = GetLastError(); 3420 ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); 3421 ok( gle == NO_ERROR 3422 || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k and Vista in the TrackPopupMenuEx case */ 3423 || broken (gle == 0xdeadbeef) /* win95 */ 3424 ,"TrackPopupMenu%s error got %u expected %u or %u\n", 3425 Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); 3426 ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, 3427 "missed expected message(s)%s%s%s\n", 3428 !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", 3429 !gflag_entermenuloop ? "WM_INITMENULOOP ": "", 3430 !gflag_initmenu ? "WM_INITMENU": ""); 3431 DestroyMenu(hmenu); 3432 } 3433 /* clean up */ 3434 DestroyWindow(hwnd); 3435 } 3436 3437 static HMENU g_hmenu; 3438 3439 static LRESULT WINAPI menu_track_again_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 3440 { 3441 switch (msg) 3442 { 3443 case WM_ENTERMENULOOP: 3444 { 3445 BOOL ret; 3446 3447 /* try a recursive call */ 3448 SetLastError(0xdeadbeef); 3449 ret = TrackPopupMenu(g_hmenu, 0, 100, 100, 0, hwnd, NULL); 3450 ok(ret == FALSE, "got %d\n", ret); 3451 ok(GetLastError() == ERROR_POPUP_ALREADY_ACTIVE || 3452 broken(GetLastError() == 0xdeadbeef) /* W9x */, "got %d\n", GetLastError()); 3453 3454 /* exit menu modal loop 3455 * ( A SendMessage does not work on NT3.51 here ) */ 3456 return PostMessageA(hwnd, WM_CANCELMODE, 0, 0); 3457 } 3458 } 3459 return DefWindowProcA(hwnd, msg, wparam, lparam); 3460 } 3461 3462 static void test_menu_trackagain(void) 3463 { 3464 HWND hwnd; 3465 BOOL ret; 3466 3467 hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 3468 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 3469 NULL, NULL, NULL, NULL); 3470 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 3471 if (!hwnd) return; 3472 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_track_again_wnd_proc); 3473 3474 g_hmenu = CreatePopupMenu(); 3475 ok(g_hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 3476 3477 ret = AppendMenuA(g_hmenu, MF_STRING , 100, "item 1"); 3478 ok(ret, "AppendMenu failed.\n"); 3479 ret = AppendMenuA(g_hmenu, MF_STRING , 101, "item 2"); 3480 ok(ret, "AppendMenu failed.\n"); 3481 3482 ret = TrackPopupMenu( g_hmenu, 0, 100, 100, 0, hwnd, NULL); 3483 ok(ret == TRUE, "got %d\n", ret); 3484 3485 DestroyMenu(g_hmenu); 3486 DestroyWindow(hwnd); 3487 } 3488 3489 /* test handling of WM_CANCELMODE messages */ 3490 static int g_got_enteridle; 3491 static HWND g_hwndtosend; 3492 static LRESULT WINAPI menu_cancelmode_wnd_proc(HWND hwnd, UINT msg, 3493 WPARAM wparam, LPARAM lparam) 3494 { 3495 switch (msg) 3496 { 3497 case WM_ENTERMENULOOP: 3498 g_got_enteridle = 0; 3499 return SendMessageA( g_hwndtosend, WM_CANCELMODE, 0, 0); 3500 case WM_ENTERIDLE: 3501 { 3502 if( g_got_enteridle++ == 0) { 3503 /* little hack to get another WM_ENTERIDLE message */ 3504 PostMessageA( hwnd, WM_MOUSEMOVE, 0, 0); 3505 return SendMessageA( g_hwndtosend, WM_CANCELMODE, 0, 0); 3506 } 3507 pEndMenu(); 3508 return TRUE; 3509 } 3510 } 3511 return DefWindowProcA( hwnd, msg, wparam, lparam); 3512 } 3513 3514 static void test_menu_cancelmode(void) 3515 { 3516 DWORD ret; 3517 HWND hwnd, hwndchild; 3518 HMENU menu, menubar; 3519 MSG msg; 3520 if( !pEndMenu) { /* win95 */ 3521 win_skip( "EndMenu is not available\n"); 3522 return; 3523 } 3524 hwnd = CreateWindowExA( 0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 3525 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 3526 NULL, NULL, NULL, NULL); 3527 hwndchild = CreateWindowExA( 0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 3528 WS_VISIBLE | WS_CHILD, 10, 10, 20, 20, 3529 hwnd, NULL, NULL, NULL); 3530 ok( hwnd != NULL && hwndchild != NULL, 3531 "CreateWindowEx failed with error %d\n", GetLastError()); 3532 g_hwndtosend = hwnd; 3533 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); 3534 SetWindowLongPtrA( hwndchild, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); 3535 menu = CreatePopupMenu(); 3536 ok( menu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError()); 3537 ret = AppendMenuA( menu, MF_STRING, 1, "winetest"); 3538 ok( ret, "Functie failed lasterror is %u\n", GetLastError()); 3539 /* seems to be needed only on wine :( */ 3540 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) 3541 DispatchMessageA(&msg); 3542 /* test the effect of sending a WM_CANCELMODE message in the WM_INITMENULOOP 3543 * handler of the menu owner */ 3544 /* test results is extracted from variable g_got_enteridle. Possible values: 3545 * 0 : complete conformance. Sending WM_CANCELMODE cancels a menu initializing tracking 3546 * 1 : Sending WM_CANCELMODE cancels a menu that is in tracking state 3547 * 2 : Sending WM_CANCELMODE does not work 3548 */ 3549 /* menu owner is top level window */ 3550 g_hwndtosend = hwnd; 3551 TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 3552 ok( g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); 3553 /* menu owner is child window */ 3554 g_hwndtosend = hwndchild; 3555 TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL); 3556 ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); 3557 /* now send the WM_CANCELMODE messages to the WRONG window */ 3558 /* those should fail ( to have any effect) */ 3559 g_hwndtosend = hwnd; 3560 TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL); 3561 ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle); 3562 3563 /* test canceling tracking in a window's menu bar */ 3564 menubar = CreateMenu(); 3565 ok( menubar != NULL, "CreateMenu failed with error %d\n", GetLastError()); 3566 ret = AppendMenuA( menubar, MF_POPUP|MF_STRING, (UINT_PTR)menu, "winetest"); 3567 ok( ret, "AppendMenuA failed lasterror is %u\n", GetLastError()); 3568 ret = SetMenu( hwnd, menubar ); 3569 ok( ret, "SetMenu failed lasterror is %u\n", GetLastError()); 3570 /* initiate tracking */ 3571 g_hwndtosend = hwnd; 3572 ret = SendMessageA( hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0 ); 3573 ok( ret == 0, "Sending WM_SYSCOMMAND/SC_KEYMENU failed lasterror is %u\n", GetLastError()); 3574 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) 3575 DispatchMessageA(&msg); 3576 ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); 3577 3578 /* cleanup */ 3579 DestroyMenu( menubar ); 3580 DestroyMenu( menu); 3581 DestroyWindow( hwndchild); 3582 DestroyWindow( hwnd); 3583 } 3584 3585 /* show menu trees have a maximum depth */ 3586 static void test_menu_maxdepth(void) 3587 { 3588 #define NR_MENUS 100 3589 HMENU hmenus[ NR_MENUS]; 3590 int i; 3591 DWORD ret; 3592 3593 SetLastError(12345678); 3594 for( i = 0; i < NR_MENUS; i++) { 3595 hmenus[i] = CreatePopupMenu(); 3596 if( !hmenus[i]) break; 3597 } 3598 ok( i == NR_MENUS, "could not create more than %d menu's\n", i); 3599 for( i = 1; i < NR_MENUS; i++) { 3600 ret = AppendMenuA( hmenus[i], MF_POPUP, (UINT_PTR)hmenus[i-1],"test"); 3601 if( !ret) break; 3602 } 3603 trace("Maximum depth is %d\n", i); 3604 ok( GetLastError() == 12345678, "unexpected error %d\n", GetLastError()); 3605 ok( i < NR_MENUS || 3606 broken( i == NR_MENUS), /* win98, NT */ 3607 "no ( or very large) limit on menu depth!\n"); 3608 3609 for( i = 0; i < NR_MENUS; i++) 3610 DestroyMenu( hmenus[i]); 3611 } 3612 3613 /* bug #12171 */ 3614 static void test_menu_circref(void) 3615 { 3616 HMENU menu1, menu2; 3617 DWORD ret; 3618 3619 menu1 = CreatePopupMenu(); 3620 menu2 = CreatePopupMenu(); 3621 ok( menu1 && menu2, "error creating menus.\n"); 3622 ret = AppendMenuA( menu1, MF_POPUP, (UINT_PTR)menu2, "winetest"); 3623 ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); 3624 ret = AppendMenuA( menu1, MF_STRING | MF_HILITE, 123, "winetest"); 3625 ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); 3626 /* app chooses an id that happens to clash with its own hmenu */ 3627 ret = AppendMenuA( menu2, MF_STRING, (UINT_PTR)menu2, "winetest"); 3628 ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); 3629 /* now attempt to change the string of the first item of menu1 */ 3630 ret = ModifyMenuA( menu1, (UINT_PTR)menu2, MF_POPUP, (UINT_PTR)menu2, "menu 2"); 3631 ok( !ret || 3632 broken( ret), /* win98, NT */ 3633 "ModifyMenu should have failed.\n"); 3634 if( !ret) { /* will probably stack fault if the ModifyMenu succeeded */ 3635 ret = GetMenuState( menu1, 123, 0); 3636 ok( ret == MF_HILITE, "GetMenuState returned %x\n",ret); 3637 } 3638 DestroyMenu( menu2); 3639 DestroyMenu( menu1); 3640 } 3641 3642 /* test how the menu texts are aligned when the menu items have 3643 * different combinations of text and bitmaps (bug #13350) */ 3644 static void test_menualign(void) 3645 { 3646 BYTE bmfill[300]; 3647 HMENU menu; 3648 HBITMAP hbm1, hbm2, hbm3; 3649 MENUITEMINFOA mii = { sizeof(MENUITEMINFOA) }; 3650 DWORD ret; 3651 HWND hwnd; 3652 MENUINFO mi = { sizeof( MENUINFO)}; 3653 3654 if( !winetest_interactive) { 3655 skip( "interactive alignment tests.\n"); 3656 return; 3657 } 3658 hwnd = CreateWindowExA(0, 3659 "STATIC", 3660 "Menu text alignment Test\nPlease make a selection.", 3661 WS_OVERLAPPEDWINDOW, 3662 100, 100, 3663 300, 300, 3664 NULL, NULL, 0, NULL); 3665 ShowWindow( hwnd, SW_SHOW); 3666 /* create bitmaps */ 3667 memset( bmfill, 0xcc, sizeof( bmfill)); 3668 hbm1 = CreateBitmap( 10,10,1,1,bmfill); 3669 hbm2 = CreateBitmap( 20,20,1,1,bmfill); 3670 hbm3 = CreateBitmap( 50,6,1,1,bmfill); 3671 ok( hbm1 && hbm2 && hbm3, "Creating bitmaps failed\n"); 3672 menu = CreatePopupMenu(); 3673 ok( menu != NULL, "CreatePopupMenu() failed\n"); 3674 if( pGetMenuInfo) { 3675 mi.fMask = MIM_STYLE; 3676 ret = pGetMenuInfo( menu, &mi); 3677 ok( ret, "GetMenuInfo failed: %d\n", GetLastError()); 3678 ok( menu != NULL, "GetMenuInfo() failed\n"); 3679 ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle); 3680 } 3681 /* test 1 */ 3682 mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; 3683 mii.wID = 1; 3684 mii.hbmpItem = hbm1; 3685 mii.dwTypeData = (LPSTR) " OK: menu texts are correctly left-aligned."; 3686 ret = InsertMenuItemA( menu, -1, TRUE, &mii); 3687 ok( ret, "InsertMenuItem() failed\n"); 3688 mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID ; 3689 mii.wID = 2; 3690 mii.hbmpItem = hbm2; 3691 mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT left-aligned."; 3692 ret = InsertMenuItemA( menu, -1, TRUE, &mii); 3693 ok( ret, "InsertMenuItem() failed\n"); 3694 ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); 3695 ok( ret != 2, "User indicated that menu text alignment test 1 failed %d\n", ret); 3696 /* test 2*/ 3697 mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; 3698 mii.wID = 3; 3699 mii.hbmpItem = hbm3; 3700 mii.dwTypeData = NULL; 3701 ret = InsertMenuItemA( menu, 0, TRUE, &mii); 3702 ok( ret, "InsertMenuItem() failed\n"); 3703 mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; 3704 mii.wID = 1; 3705 mii.hbmpItem = hbm1; 3706 /* make the text a bit longer, to keep it readable */ 3707 /* this bug is on winXP and reproduced on wine */ 3708 mii.dwTypeData = (LPSTR) " OK: menu texts are to the right of the bitmaps........"; 3709 ret = SetMenuItemInfoA( menu, 1, TRUE, &mii); 3710 ok( ret, "SetMenuItemInfo() failed\n"); 3711 mii.wID = 2; 3712 mii.hbmpItem = hbm2; 3713 mii.dwTypeData = (LPSTR) " FAIL: menu texts are below the first bitmap. "; 3714 ret = SetMenuItemInfoA( menu, 2, TRUE, &mii); 3715 ok( ret, "SetMenuItemInfo() failed\n"); 3716 ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); 3717 ok( ret != 2, "User indicated that menu text alignment test 2 failed %d\n", ret); 3718 /* test 3 */ 3719 mii.fMask = MIIM_TYPE | MIIM_ID; 3720 mii.wID = 3; 3721 mii.fType = MFT_BITMAP; 3722 mii.dwTypeData = (LPSTR) hbm3; 3723 ret = SetMenuItemInfoA( menu, 0, TRUE, &mii); 3724 ok( ret, "SetMenuItemInfo() failed\n"); 3725 mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; 3726 mii.wID = 1; 3727 mii.hbmpItem = NULL; 3728 mii.dwTypeData = (LPSTR) " OK: menu texts are below the bitmap."; 3729 ret = SetMenuItemInfoA( menu, 1, TRUE, &mii); 3730 ok( ret, "SetMenuItemInfo() failed\n"); 3731 mii.wID = 2; 3732 mii.hbmpItem = NULL; 3733 mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT below the bitmap."; 3734 ret = SetMenuItemInfoA( menu, 2, TRUE, &mii); 3735 ok( ret, "SetMenuItemInfo() failed\n"); 3736 ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); 3737 ok( ret != 2, "User indicated that menu text alignment test 3 failed %d\n", ret); 3738 /* cleanup */ 3739 DeleteObject( hbm1); 3740 DeleteObject( hbm2); 3741 DeleteObject( hbm3); 3742 DestroyMenu( menu); 3743 DestroyWindow( hwnd); 3744 } 3745 3746 static LRESULT WINAPI menu_fill_in_init(HWND hwnd, UINT msg, 3747 WPARAM wparam, LPARAM lparam) 3748 { 3749 HMENU hmenupopup; 3750 BOOL ret; 3751 switch (msg) 3752 { 3753 case WM_INITMENUPOPUP: 3754 gflag_initmenupopup++; 3755 hmenupopup = (HMENU) wparam; 3756 ret = AppendMenuA(hmenupopup, MF_STRING , 100, "item 1"); 3757 ok(ret, "AppendMenu failed.\n"); 3758 ret = AppendMenuA(hmenupopup, MF_STRING , 101, "item 2"); 3759 ok(ret, "AppendMenu failed.\n"); 3760 break; 3761 case WM_ENTERMENULOOP: 3762 gflag_entermenuloop++; 3763 break; 3764 case WM_INITMENU: 3765 gflag_initmenu++; 3766 break; 3767 case WM_ENTERIDLE: 3768 gflag_enteridle++; 3769 PostMessageA(hwnd, WM_CANCELMODE, 0, 0); 3770 return TRUE; 3771 case WM_MENUSELECT: 3772 selectitem_wp = wparam; 3773 selectitem_lp = lparam; 3774 break; 3775 } 3776 return DefWindowProcA(hwnd, msg, wparam, lparam); 3777 } 3778 3779 static void test_emptypopup(void) 3780 { 3781 BOOL ret; 3782 HMENU hmenu; 3783 3784 HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, 3785 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 3786 NULL, NULL, NULL, NULL); 3787 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); 3788 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); 3789 3790 hmenu = CreatePopupMenu(); 3791 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); 3792 3793 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0; 3794 selectitem_wp = 0xdeadbeef; 3795 selectitem_lp = 0xdeadbeef; 3796 3797 ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); 3798 ok(ret == 0, "got %i\n", ret); 3799 3800 ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup); 3801 ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop); 3802 ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); 3803 ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu); 3804 3805 ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp); 3806 ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp); 3807 3808 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0; 3809 selectitem_wp = 0xdeadbeef; 3810 selectitem_lp = 0xdeadbeef; 3811 3812 ret = TrackPopupMenu( hmenu, 0, 100,100, 0, hwnd, NULL); 3813 ok(ret == 0, "got %i\n", ret); 3814 3815 ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup); 3816 ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop); 3817 ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); 3818 ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu); 3819 3820 ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp); 3821 ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp); 3822 3823 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_fill_in_init); 3824 3825 gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0; 3826 selectitem_wp = 0xdeadbeef; 3827 selectitem_lp = 0xdeadbeef; 3828 3829 ret = TrackPopupMenu( hmenu, 0, 100,100, 0, hwnd, NULL); 3830 ok(ret == 1, "got %i\n", ret); 3831 3832 ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup); 3833 ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop); 3834 ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); 3835 ok(gflag_enteridle == 1, "got %i\n", gflag_initmenu); 3836 3837 ok(selectitem_wp == 0xffff0000, "got %lx\n", selectitem_wp); 3838 ok(selectitem_lp == 0, "got %lx\n", selectitem_lp); 3839 3840 DestroyWindow(hwnd); 3841 3842 ret = DestroyMenu(hmenu); 3843 ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); 3844 } 3845 3846 static HMENU get_bad_hmenu( UINT_PTR id ) 3847 { 3848 while (IsMenu( (HMENU)id )) id++; 3849 return (HMENU)id; 3850 } 3851 3852 static void test_AppendMenu(void) 3853 { 3854 static char string[] = "string"; 3855 MENUITEMINFOA mii; 3856 HMENU hmenu, hsubmenu; 3857 HBITMAP hbmp; 3858 char buf[16]; 3859 BOOL ret; 3860 3861 hmenu = CreateMenu(); 3862 ok(hmenu != 0, "CreateMenu failed\n"); 3863 ret = AppendMenuA(hmenu, MF_OWNERDRAW, 201, "item 1"); 3864 ok(ret, "AppendMenu failed\n"); 3865 check_menu_items(hmenu, 201, MF_OWNERDRAW, 0); 3866 DestroyMenu(hmenu); 3867 3868 hmenu = CreateMenu(); 3869 ok(hmenu != 0, "CreateMenu failed\n"); 3870 hsubmenu = get_bad_hmenu( 202 ); 3871 ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3872 ok(ret, "AppendMenu failed\n"); 3873 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0); 3874 DestroyMenu(hmenu); 3875 3876 hmenu = CreateMenu(); 3877 ok(hmenu != 0, "CreateMenu failed\n"); 3878 hsubmenu = get_bad_hmenu( 203 ); 3879 ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3880 ok(ret, "AppendMenu failed\n"); 3881 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0); 3882 DestroyMenu(hmenu); 3883 3884 hmenu = CreateMenu(); 3885 ok(hmenu != 0, "CreateMenu failed\n"); 3886 hsubmenu = CreateMenu(); 3887 ok(hsubmenu != 0, "CreateMenu failed\n"); 3888 ret = AppendMenuA(hmenu, MF_OWNERDRAW, (UINT_PTR)hsubmenu, "item 1"); 3889 ok(ret, "AppendMenu failed\n"); 3890 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0); 3891 DestroyMenu(hmenu); 3892 DestroyMenu(hsubmenu); 3893 3894 hmenu = CreateMenu(); 3895 ok(hmenu != 0, "CreateMenu failed\n"); 3896 hsubmenu = CreateMenu(); 3897 ok(hsubmenu != 0, "CreateMenu failed\n"); 3898 ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3899 ok(ret, "AppendMenu failed\n"); 3900 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0); 3901 DestroyMenu(hmenu); 3902 DestroyMenu(hsubmenu); 3903 3904 hmenu = CreateMenu(); 3905 ok(hmenu != 0, "CreateMenu failed\n"); 3906 hsubmenu = CreateMenu(); 3907 ok(hsubmenu != 0, "CreateMenu failed\n"); 3908 ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3909 ok(ret, "AppendMenu failed\n"); 3910 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0); 3911 DestroyMenu(hmenu); 3912 DestroyMenu(hsubmenu); 3913 3914 hmenu = CreateMenu(); 3915 ok(hmenu != 0, "CreateMenu failed\n"); 3916 hsubmenu = CreatePopupMenu(); 3917 ok(hsubmenu != 0, "CreatePopupMenu failed\n"); 3918 ret = AppendMenuA(hmenu, MF_OWNERDRAW, (UINT_PTR)hsubmenu, "item 1"); 3919 ok(ret, "AppendMenu failed\n"); 3920 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0); 3921 DestroyMenu(hmenu); 3922 DestroyMenu(hsubmenu); 3923 3924 hmenu = CreateMenu(); 3925 ok(hmenu != 0, "CreateMenu failed\n"); 3926 hsubmenu = CreatePopupMenu(); 3927 ok(hsubmenu != 0, "CreatePopupMenu failed\n"); 3928 ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3929 ok(ret, "AppendMenu failed\n"); 3930 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0); 3931 DestroyMenu(hmenu); 3932 DestroyMenu(hsubmenu); 3933 3934 hmenu = CreateMenu(); 3935 ok(hmenu != 0, "CreateMenu failed\n"); 3936 hsubmenu = CreatePopupMenu(); 3937 ok(hsubmenu != 0, "CreatePopupMenu failed\n"); 3938 ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1"); 3939 ok(ret, "AppendMenu failed\n"); 3940 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0); 3941 DestroyMenu(hmenu); 3942 DestroyMenu(hsubmenu); 3943 3944 hmenu = CreateMenu(); 3945 ok(hmenu != 0, "CreateMenu failed\n"); 3946 ret = AppendMenuA(hmenu, MF_STRING, 204, "item 1"); 3947 ok(ret, "AppendMenu failed\n"); 3948 check_menu_items(hmenu, 204, MF_STRING, 0); 3949 hsubmenu = get_bad_hmenu( 205 ); 3950 ret = ModifyMenuA(hmenu, 0, MF_POPUP | MF_BYPOSITION, (UINT_PTR)hsubmenu, "item 2"); 3951 ok(ret, "ModifyMenu failed\n"); 3952 check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0); 3953 memset(&mii, 0, sizeof(mii)); 3954 mii.cbSize = sizeof(mii); 3955 mii.fMask = MIIM_SUBMENU; 3956 mii.hSubMenu = get_bad_hmenu( 204 ); 3957 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 3958 ok(!ret, "InsertMenuItem should fail\n"); 3959 ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii); 3960 ok(!ret, "SetMenuItemInfo should fail\n"); 3961 mii.fMask = MIIM_ID; 3962 mii.wID = 206; 3963 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 3964 ok(ret, "InsertMenuItem failed\n"); 3965 if (0) /* FIXME: uncomment once Wine is fixed */ { 3966 check_menu_items(hmenu, 206, MF_SEPARATOR, MFS_GRAYED); 3967 } 3968 mii.wID = 207; 3969 ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii); 3970 ok(ret, "SetMenuItemInfo failed\n"); 3971 if (0) /* FIXME: uncomment once Wine is fixed */ { 3972 check_menu_items(hmenu, 207, MF_SEPARATOR, MFS_GRAYED); 3973 } 3974 DestroyMenu(hmenu); 3975 3976 hbmp = CreateBitmap(1, 1, 1, 1, NULL); 3977 hmenu = CreateMenu(); 3978 ok(hmenu != 0, "CreateMenu failed\n"); 3979 3980 /* menu item with a string and a bitmap */ 3981 memset(&mii, 0, sizeof(mii)); 3982 mii.cbSize = sizeof(mii); 3983 mii.fMask = MIIM_STRING | MIIM_BITMAP; 3984 mii.dwTypeData = string; 3985 mii.cch = strlen(string); 3986 mii.hbmpItem = hbmp; 3987 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 3988 ok(ret, "InsertMenuItem failed\n"); 3989 memset(&mii, 0x81, sizeof(mii)); 3990 memset(buf, 0x81, sizeof(buf)); 3991 mii.cbSize = sizeof(mii); 3992 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; 3993 mii.dwTypeData = buf; 3994 mii.cch = sizeof(buf); 3995 mii.dwItemData = 0x81818181; 3996 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 3997 ok(ret, "GetMenuItemInfo failed\n"); 3998 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 3999 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4000 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4001 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4002 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4003 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4004 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4005 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4006 ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); 4007 4008 memset(&mii, 0x81, sizeof(mii)); 4009 mii.cbSize = sizeof(mii); 4010 mii.fMask = MIIM_TYPE; 4011 mii.dwItemData = 0x81818181; 4012 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4013 ok(ret, "GetMenuItemInfo failed\n"); 4014 ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType); 4015 ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); 4016 ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); 4017 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4018 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4019 ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); 4020 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4021 ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); 4022 4023 memset(&mii, 0x81, sizeof(mii)); 4024 memset(buf, 0x81, sizeof(buf)); 4025 mii.cbSize = sizeof(mii); 4026 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA; 4027 mii.dwTypeData = buf; 4028 mii.cch = sizeof(buf); 4029 mii.dwItemData = 0x81818181; 4030 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4031 ok(ret, "GetMenuItemInfo failed\n"); 4032 ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType); 4033 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4034 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4035 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4036 ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); 4037 ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); 4038 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4039 ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); 4040 4041 DestroyMenu(hmenu); 4042 DeleteObject(hbmp); 4043 4044 hmenu = CreateMenu(); 4045 ok(hmenu != 0, "CreateMenu failed\n"); 4046 4047 /* menu item with a string and a "magic" bitmap */ 4048 memset(&mii, 0, sizeof(mii)); 4049 mii.cbSize = sizeof(mii); 4050 mii.fMask = MIIM_STRING | MIIM_BITMAP; 4051 mii.dwTypeData = string; 4052 mii.cch = strlen(string); 4053 mii.hbmpItem = HBMMENU_POPUP_RESTORE; 4054 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 4055 ok(ret, "InsertMenuItem failed\n"); 4056 memset(&mii, 0x81, sizeof(mii)); 4057 memset(buf, 0x81, sizeof(buf)); 4058 mii.cbSize = sizeof(mii); 4059 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; 4060 mii.dwTypeData = buf; 4061 mii.cch = sizeof(buf); 4062 mii.dwItemData = 0x81818181; 4063 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4064 ok(ret, "GetMenuItemInfo failed\n"); 4065 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4066 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4067 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4068 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4069 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4070 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4071 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4072 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4073 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 4074 4075 memset(&mii, 0x81, sizeof(mii)); 4076 mii.cbSize = sizeof(mii); 4077 mii.fMask = MIIM_TYPE; 4078 mii.dwTypeData = buf; 4079 mii.cch = sizeof(buf); 4080 mii.dwItemData = 0x81818181; 4081 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4082 ok(ret, "GetMenuItemInfo failed\n"); 4083 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4084 ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); 4085 ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); 4086 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4087 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4088 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4089 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4090 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4091 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 4092 4093 memset(&mii, 0x81, sizeof(mii)); 4094 memset(buf, 0x81, sizeof(buf)); 4095 mii.cbSize = sizeof(mii); 4096 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA; 4097 mii.dwTypeData = buf; 4098 mii.cch = sizeof(buf); 4099 mii.dwItemData = 0x81818181; 4100 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4101 ok(ret, "GetMenuItemInfo failed\n"); 4102 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4103 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4104 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4105 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4106 ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); 4107 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4108 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4109 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4110 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 4111 4112 DestroyMenu(hmenu); 4113 4114 hbmp = CreateBitmap(1, 1, 1, 1, NULL); 4115 hmenu = CreateMenu(); 4116 ok(hmenu != 0, "CreateMenu failed\n"); 4117 4118 /* menu item with a string */ 4119 memset(&mii, 0, sizeof(mii)); 4120 mii.cbSize = sizeof(mii); 4121 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA; 4122 mii.dwItemData = (ULONG_PTR)hbmp; 4123 mii.dwTypeData = string; 4124 mii.cch = strlen(string); 4125 mii.hbmpItem = hbmp; 4126 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 4127 ok(ret, "InsertMenuItem failed\n"); 4128 memset(&mii, 0x81, sizeof(mii)); 4129 memset(buf, 0x81, sizeof(buf)); 4130 mii.cbSize = sizeof(mii); 4131 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA; 4132 mii.dwTypeData = buf; 4133 mii.cch = sizeof(buf); 4134 mii.dwItemData = 0x81818181; 4135 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4136 ok(ret, "GetMenuItemInfo failed\n"); 4137 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4138 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4139 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4140 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4141 ok(mii.dwItemData == (ULONG_PTR)hbmp, "expected %p, got %#lx\n", hbmp, mii.dwItemData); 4142 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4143 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4144 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4145 ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem); 4146 4147 memset(&mii, 0x81, sizeof(mii)); 4148 memset(buf, 0x81, sizeof(buf)); 4149 mii.cbSize = sizeof(mii); 4150 mii.fMask = MIIM_TYPE; 4151 mii.dwTypeData = buf; 4152 mii.cch = sizeof(buf); 4153 mii.dwItemData = 0x81818181; 4154 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4155 ok(ret, "GetMenuItemInfo failed\n"); 4156 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4157 ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); 4158 ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); 4159 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4160 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4161 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4162 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4163 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4164 ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem); 4165 4166 DestroyMenu(hmenu); 4167 DeleteObject(hbmp); 4168 4169 /* menu item with a string */ 4170 hbmp = CreateBitmap(1, 1, 1, 1, NULL); 4171 hmenu = CreateMenu(); 4172 ok(hmenu != 0, "CreateMenu failed\n"); 4173 memset(&mii, 0, sizeof(mii)); 4174 mii.cbSize = sizeof(mii); 4175 mii.fMask = MIIM_STRING; 4176 mii.dwTypeData = string; 4177 mii.cch = strlen(string); 4178 ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); 4179 ok(ret, "InsertMenuItem failed\n"); 4180 memset(&mii, 0x81, sizeof(mii)); 4181 memset(buf, 0x81, sizeof(buf)); 4182 mii.cbSize = sizeof(mii); 4183 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; 4184 mii.dwTypeData = buf; 4185 mii.cch = sizeof(buf); 4186 mii.dwItemData = 0x81818181; 4187 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4188 ok(ret, "GetMenuItemInfo failed\n"); 4189 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4190 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4191 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4192 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4193 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4194 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4195 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4196 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4197 ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem); 4198 4199 /* add "magic" bitmap to a menu item */ 4200 mii.fMask = MIIM_BITMAP; 4201 mii.hbmpItem = HBMMENU_POPUP_RESTORE; 4202 ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4203 ok(ret, "SetMenuItemInfo failed\n"); 4204 memset(&mii, 0x81, sizeof(mii)); 4205 memset(buf, 0x81, sizeof(buf)); 4206 mii.cbSize = sizeof(mii); 4207 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; 4208 mii.dwTypeData = buf; 4209 mii.cch = sizeof(buf); 4210 mii.dwItemData = 0x81818181; 4211 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4212 ok(ret, "GetMenuItemInfo failed\n"); 4213 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4214 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4215 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4216 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4217 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4218 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4219 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4220 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4221 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 4222 4223 memset(&mii, 0x81, sizeof(mii)); 4224 memset(buf, 0x81, sizeof(buf)); 4225 mii.cbSize = sizeof(mii); 4226 mii.fMask = MIIM_TYPE; 4227 mii.dwTypeData = buf; 4228 mii.cch = sizeof(buf); 4229 mii.dwItemData = 0x81818181; 4230 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4231 ok(ret, "GetMenuItemInfo failed\n"); 4232 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4233 ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); 4234 ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); 4235 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4236 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4237 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4238 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4239 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4240 ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); 4241 4242 /* replace "magic" bitmap by a normal one */ 4243 mii.fMask = MIIM_BITMAP; 4244 mii.hbmpItem = hbmp; 4245 ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4246 ok(ret, "SetMenuItemInfo failed\n"); 4247 memset(&mii, 0x81, sizeof(mii)); 4248 memset(buf, 0x81, sizeof(buf)); 4249 mii.cbSize = sizeof(mii); 4250 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; 4251 mii.dwTypeData = buf; 4252 mii.cch = sizeof(buf); 4253 mii.dwItemData = 0x81818181; 4254 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4255 ok(ret, "GetMenuItemInfo failed\n"); 4256 ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType); 4257 ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); 4258 ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); 4259 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4260 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4261 ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); 4262 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4263 ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); 4264 ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); 4265 4266 memset(&mii, 0x81, sizeof(mii)); 4267 memset(buf, 0x81, sizeof(buf)); 4268 mii.cbSize = sizeof(mii); 4269 mii.fMask = MIIM_TYPE; 4270 mii.dwTypeData = buf; 4271 mii.cch = sizeof(buf); 4272 mii.dwItemData = 0x81818181; 4273 ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii); 4274 ok(ret, "GetMenuItemInfo failed\n"); 4275 ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType); 4276 ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); 4277 ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); 4278 ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); 4279 ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); 4280 ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); 4281 ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); 4282 ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); 4283 4284 DestroyMenu(hmenu); 4285 DeleteObject(hbmp); 4286 } 4287 4288 START_TEST(menu) 4289 { 4290 init_function_pointers(); 4291 register_menu_check_class(); 4292 4293 /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't 4294 * handle that. 4295 */ 4296 if (correct_behavior()) 4297 { 4298 test_menu_add_string(); 4299 test_menu_iteminfo(); 4300 test_menu_search_bycommand(); 4301 test_CheckMenuRadioItem(); 4302 test_menu_resource_layout(); 4303 test_InsertMenu(); 4304 test_menualign(); 4305 test_system_menu(); 4306 } 4307 4308 test_menu_locked_by_window(); 4309 test_subpopup_locked_by_menu(); 4310 test_menu_ownerdraw(); 4311 test_getmenubarinfo(); 4312 test_menu_bmp_and_string(); 4313 test_menu_getmenuinfo(); 4314 test_menu_setmenuinfo(); 4315 test_menu_input(); 4316 test_menu_flags(); 4317 4318 test_menu_hilitemenuitem(); 4319 test_menu_trackpopupmenu(); 4320 test_menu_trackagain(); 4321 test_menu_cancelmode(); 4322 test_menu_maxdepth(); 4323 test_menu_circref(); 4324 test_emptypopup(); 4325 test_AppendMenu(); 4326 } 4327