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