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