4 * Copyright 2005 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define OEMRESOURCE /* For OBM_MNARROW */
34 #include "wine/test.h"
36 static ATOM atomMenuCheckClass;
38 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
39 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
41 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
45 case WM_ENTERMENULOOP:
46 /* mark window as having entered menu loop */
47 SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
48 /* exit menu modal loop
49 * ( A SendMessage does not work on NT3.51 here ) */
50 return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
52 return DefWindowProc(hwnd, msg, wparam, lparam);
55 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
68 /* globals to communicate between test and wndproc */
70 static BOOL bMenuVisible;
71 static HMENU hMenus[4];
76 /* menu texts with their sizes */
79 SIZE size; /* size of text up to any \t */
80 SIZE sc_size; /* size of the short-cut */
89 static unsigned int MOD_maxid;
90 static RECT MOD_rc[MOD_NRMENUS];
91 static int MOD_avec, MOD_hic;
92 static int MOD_odheight;
93 static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
94 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
95 static int MOD_GotDrawItemMsg = FALSE;
96 /* wndproc used by test_menu_ownerdraw() */
97 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
98 WPARAM wparam, LPARAM lparam)
104 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
106 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
107 pmis->itemData, pmis->itemWidth, pmis->itemHeight);
108 MOD_odheight = pmis->itemHeight;
109 pmis->itemWidth = MODsizes[pmis->itemData].cx;
110 pmis->itemHeight = MODsizes[pmis->itemData].cy;
115 DRAWITEMSTRUCT * pdis;
118 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
121 pdis = (DRAWITEMSTRUCT *) lparam;
122 if( winetest_debug) {
124 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
125 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
126 hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
127 pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
128 pdis->rcItem.right,pdis->rcItem.bottom,
129 rc.left,rc.top,rc.right,rc.bottom);
130 oldpen=SelectObject( pdis->hDC, GetStockObject(
131 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
132 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
133 pdis->rcItem.right,pdis->rcItem.bottom );
134 SelectObject( pdis->hDC, oldpen);
136 /* calculate widths of some menu texts */
137 if( ! MOD_txtsizes[0].size.cx)
138 for(i = 0; MOD_txtsizes[i].text; i++) {
141 strcpy( buf, MOD_txtsizes[i].text);
142 if( ( p = strchr( buf, '\t'))) {
144 DrawText( pdis->hDC, p + 1, -1, &rc,
145 DT_SINGLELINE|DT_CALCRECT);
146 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
147 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
149 DrawText( pdis->hDC, buf, -1, &rc,
150 DT_SINGLELINE|DT_CALCRECT);
151 MOD_txtsizes[i].size.cx= rc.right - rc.left;
152 MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
155 if( pdis->itemData > MOD_maxid) return TRUE;
156 /* store the rectangl */
157 MOD_rc[pdis->itemData] = pdis->rcItem;
158 /* calculate average character width */
159 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
160 MOD_avec = (sz.cx + 26)/52;
161 GetTextMetrics( pdis->hDC, &tm);
162 MOD_hic = tm.tmHeight;
163 MOD_GotDrawItemMsg = TRUE;
168 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
173 return DefWindowProc(hwnd, msg, wparam, lparam);
176 static void register_menu_check_class(void)
184 GetModuleHandle(NULL),
186 LoadCursor(NULL, IDC_ARROW),
187 (HBRUSH)(COLOR_BTNFACE+1),
189 TEXT("WineMenuCheck"),
192 atomMenuCheckClass = RegisterClass(&wc);
195 /* demonstrates that windows locks the menu object so that it is still valid
196 * even after a client calls DestroyMenu on it */
197 static void test_menu_locked_by_window(void)
201 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
202 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
203 NULL, NULL, NULL, NULL);
204 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
205 hmenu = CreateMenu();
206 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
207 ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
208 ok(ret, "InsertMenu failed with error %d\n", GetLastError());
209 ret = SetMenu(hwnd, hmenu);
210 ok(ret, "SetMenu failed with error %d\n", GetLastError());
211 ret = DestroyMenu(hmenu);
212 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
214 ret = DrawMenuBar(hwnd);
216 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
218 ret = IsMenu(GetMenu(hwnd));
219 ok(!ret, "Menu handle should have been destroyed\n");
221 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
222 /* did we process the WM_INITMENU message? */
223 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
225 ok(ret, "WM_INITMENU should have been sent\n");
231 static void test_menu_ownerdraw(void)
237 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
238 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
239 NULL, NULL, NULL, NULL);
240 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
242 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
243 hmenu = CreatePopupMenu();
244 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
245 if( !hmenu) { DestroyWindow(hwnd);return;}
247 for( j=0;j<2;j++) /* create columns */
248 for(i=0;i<2;i++) { /* create rows */
249 ret = AppendMenu( hmenu, MF_OWNERDRAW |
250 (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
252 ok( ret, "AppendMenu failed for %d\n", k-1);
255 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
256 /* display the menu */
257 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
259 /* columns have a 4 pixel gap between them */
260 ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
261 "item rectangles are not separated by 4 pixels space\n");
262 /* height should be what the MEASUREITEM message has returned */
263 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
264 "menu item has wrong height: %d should be %d\n",
265 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
266 /* no gaps between the rows */
267 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
268 "There should not be a space between the rows, gap is %d\n",
269 MOD_rc[0].bottom - MOD_rc[1].top);
270 /* test the correct value of the item height that was sent
271 * by the WM_MEASUREITEM message */
272 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
273 MOD_odheight == MOD_hic, /* Win95,98,ME */
274 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
275 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
276 /* test what MF_MENUBREAK did at the first position. Also show
277 * that an MF_SEPARATOR is ignored in the height calculation. */
278 leftcol= MOD_rc[0].left;
279 ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
280 /* display the menu */
281 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
282 /* left should be 4 pixels less now */
283 ok( leftcol == MOD_rc[0].left + 4,
284 "columns should be 4 pixels to the left (actual %d).\n",
285 leftcol - MOD_rc[0].left);
287 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
288 "width of owner drawn menu item is wrong. Got %d expected %d\n",
289 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
291 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
292 "Height is incorrect. Got %d expected %d\n",
293 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
295 /* test width/height of an ownerdraw menu bar as well */
296 ret = DestroyMenu(hmenu);
297 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
298 hmenu = CreateMenu();
299 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
300 if( !hmenu) { DestroyWindow(hwnd);return;}
303 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
304 ok( ret, "AppendMenu failed for %d\n", i);
306 ret = SetMenu( hwnd, hmenu);
307 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
308 ok(ret, "SetMenu failed with error %d\n", GetLastError());
310 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
311 "width of owner drawn menu item is wrong. Got %d expected %d\n",
312 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
314 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
315 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
316 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
319 ret = DestroyMenu(hmenu);
320 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
324 /* helper for test_menu_bmp_and_string() */
325 static void test_mbs_help( int ispop, int hassub, int mnuopt,
326 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
327 SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
330 HMENU hmenu, submenu;
331 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
338 MOD_GotDrawItemMsg = FALSE;
339 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
341 mii.fState = MF_CHECKED;
343 MODsizes[0] = bmpsize;
347 mii.fMask |= MIIM_STRING;
348 strcpy(text_copy, text);
349 mii.dwTypeData = text_copy; /* structure member declared non-const */
350 if( ( p = strchr( text, '\t'))) {
351 hastab = *(p + 1) ? 2 : 1;
354 /* tabs don't make sense in menubars */
355 if(hastab && !ispop) return;
357 mii.fMask |= MIIM_BITMAP;
360 submenu = CreateMenu();
361 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
363 hmenu = CreatePopupMenu();
365 hmenu = CreateMenu();
366 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
368 mii.fMask |= MIIM_SUBMENU;
369 mii.hSubMenu = submenu;
372 mi.cbSize = sizeof(mi);
373 mi.fMask = MIM_STYLE;
374 pGetMenuInfo( hmenu, &mi);
375 mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
376 ret = pSetMenuInfo( hmenu, &mi);
377 ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
379 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
380 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
382 if( winetest_debug) {
384 RECT rc = {100, 50, 400, 70};
387 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
388 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
389 TextOut( hdc, 100, 50, buf, strlen( buf));
390 ReleaseDC( hwnd, hdc);
393 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
395 ret = SetMenu( hwnd, hmenu);
396 ok(ret, "SetMenu failed with error %d\n", GetLastError());
399 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
400 /* check menu width */
402 expect = ( text || hbmp ?
403 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
405 arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
406 (text && hastab ? /* TAB space */
407 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
408 (text ? 2 + (text[0] ? size.cx :0): 0) ;
410 expect = !(text || hbmp) ? 0 :
411 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) +
412 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
413 ok( rc.right - rc.left == expect,
414 "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
415 failed = failed || !(rc.right - rc.left == expect);
416 /* check menu height */
418 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
419 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
420 (hbmp ? bmpsize.cy + 2 : 0)));
422 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
423 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
424 ok( rc.bottom - rc.top == expect,
425 "menu height wrong, got %d expected %d (%d)\n",
426 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
427 failed = failed || !(rc.bottom - rc.top == expect);
428 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
429 /* check the position of the bitmap */
431 expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
433 ok( expect == MOD_rc[0].left,
434 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
435 failed = failed || !(expect == MOD_rc[0].left);
437 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
438 ok( expect == MOD_rc[0].top,
439 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
440 failed = failed || !(expect == MOD_rc[0].top);
442 /* if there was a failure, report details */
444 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
445 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
446 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
447 trace(" check %d,%d arrow %d avechar %d\n",
448 GetSystemMetrics(SM_CXMENUCHECK ),
449 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
450 if( hbmp == HBMMENU_CALLBACK)
451 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
452 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
453 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
456 ret = DestroyMenu(submenu);
457 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
458 ret = DestroyMenu(hmenu);
459 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
463 static void test_menu_bmp_and_string(void)
470 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
472 if( !pGetMenuInfo) return;
474 memset( bmfill, 0x55, sizeof( bmfill));
475 hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
476 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
477 NULL, NULL, NULL, NULL);
478 hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
479 GetObject( hbm_arrow, sizeof(bm), &bm);
480 arrowwidth = bm.bmWidth;
482 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
484 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
487 trace(" check %d,%d arrow %d avechar %d\n",
488 GetSystemMetrics(SM_CXMENUCHECK ),
489 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
492 for( ispop=1; ispop >= 0; ispop--){
493 static SIZE bmsizes[]= {
494 {10,10},{38,38},{1,30},{55,5}};
495 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
496 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
497 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL };
498 ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError());
499 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
500 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
501 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
502 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
503 /* no need to test NULL bitmaps of several sizes */
504 if( !bitmaps[bmpidx] && szidx > 0) continue;
505 if( !ispop && hassub) continue;
506 test_mbs_help( ispop, hassub, mnuopt,
507 hwnd, arrowwidth, ++count,
510 MOD_txtsizes[txtidx].text,
511 MOD_txtsizes[txtidx].size,
512 MOD_txtsizes[txtidx].sc_size);
524 static void test_menu_add_string( void )
535 WCHAR strbackW[0x80];
536 static CHAR blah[] = "blah";
537 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
539 hmenu = CreateMenu();
541 memset( &info, 0, sizeof info );
542 info.cbSize = sizeof info;
543 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
544 info.dwTypeData = blah;
549 InsertMenuItem(hmenu, 0, TRUE, &info );
551 memset( &info, 0, sizeof info );
552 info.cbSize = sizeof info;
553 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
554 info.dwTypeData = string;
555 info.cch = sizeof string;
557 GetMenuItemInfo( hmenu, 0, TRUE, &info );
559 ok( !strcmp( string, "blah" ), "menu item name differed\n");
561 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
562 strcpy(string, "Dummy string");
563 memset(&info, 0x00, sizeof(info));
564 info.cbSize= sizeof(MENUITEMINFO);
565 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
566 info.fType= MFT_OWNERDRAW;
567 info.dwTypeData= string;
568 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
569 ok (rc, "InsertMenuItem failed\n");
571 strcpy(string,"Garbage");
572 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
573 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
575 SetLastError(0xdeadbeef);
576 ret = GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION);
577 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
578 skip("GetMenuStringW is not implemented\n");
581 ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
582 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
585 /* Just change ftype to string and see what text is stored */
586 memset(&info, 0x00, sizeof(info));
587 info.cbSize= sizeof(MENUITEMINFO);
588 info.fMask= MIIM_FTYPE; /* Set string type */
589 info.fType= MFT_STRING;
590 info.dwTypeData= (char *)0xdeadbeef;
591 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
592 ok (rc, "SetMenuItemInfo failed\n");
594 /* Did we keep the old dwTypeData? */
595 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
596 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
598 /* Ensure change to bitmap type fails */
599 memset(&info, 0x00, sizeof(info));
600 info.cbSize= sizeof(MENUITEMINFO);
601 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
602 info.fType= MFT_BITMAP;
603 info.dwTypeData= (char *)0xdeadbee2;
604 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
605 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
607 /* Just change ftype back and ensure data hasn't been freed */
608 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
609 info.dwTypeData= (char *)0xdeadbee3;
610 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
611 ok (rc, "SetMenuItemInfo failed\n");
613 /* Did we keep the old dwTypeData? */
614 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
615 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
617 /* Just change string value (not type) */
618 memset(&info, 0x00, sizeof(info));
619 info.cbSize= sizeof(MENUITEMINFO);
620 info.fMask= MIIM_STRING; /* Set typeData */
621 strcpy(string2, "string2");
622 info.dwTypeData= string2;
623 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
624 ok (rc, "SetMenuItemInfo failed\n");
626 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
627 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
629 /* crashes with wine 0.9.5 */
630 memset(&info, 0x00, sizeof(info));
631 info.cbSize= sizeof(MENUITEMINFO);
632 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
633 info.fType= MFT_OWNERDRAW;
634 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
635 ok (rc, "InsertMenuItem failed\n");
636 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
637 "GetMenuString on ownerdraw entry succeeded.\n");
638 SetLastError(0xdeadbeef);
639 ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION);
640 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
641 skip("GetMenuStringW is not implemented\n");
643 ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
645 DestroyMenu( hmenu );
648 /* define building blocks for the menu item info tests */
649 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
651 if (n <= 0) return 0;
652 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
653 return *str1 - *str2;
656 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
659 while ((*p++ = *src++));
664 #define DMIINFF( i, e, field)\
665 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
666 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
668 #define DUMPMIINF(s,i,e)\
670 DMIINFF( i, e, fMask)\
671 DMIINFF( i, e, fType)\
672 DMIINFF( i, e, fState)\
674 DMIINFF( i, e, hSubMenu)\
675 DMIINFF( i, e, hbmpChecked)\
676 DMIINFF( i, e, hbmpUnchecked)\
677 DMIINFF( i, e, dwItemData)\
678 DMIINFF( i, e, dwTypeData)\
680 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
683 /* insert menu item */
684 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
687 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
688 HMENU hmenu = CreateMenu();\
689 BOOL ret, stop = FALSE;\
690 SetLastError( 0xdeadbeef);\
691 if(ansi)strcpy( string, init);\
692 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
693 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
694 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
695 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
697 skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
700 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
702 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
705 /* GetMenuItemInfo + GetMenuString */
706 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
707 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
708 expname, eret2, eret3)\
710 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
711 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
712 MENUITEMINFOA *info2 = &info2A;\
713 MENUITEMINFOA *einfo = &einfoA;\
714 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
716 SetLastError( 0xdeadbeef);\
717 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
718 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
719 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
721 skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
724 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
726 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
727 ret = memcmp( info2, einfo, sizeof einfoA);\
728 /* ok( ret==0, "Got wrong menu item info data\n");*/\
729 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
730 if( einfo->dwTypeData == string) {\
731 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
732 einfo->dwTypeData ? einfo->dwTypeData: "");\
733 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
734 einfo->dwTypeData ? einfo->dwTypeData: "");\
735 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
736 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
738 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
740 ok( !ret, "GetMenuString should have failed\n");\
747 RemoveMenu(hmenu, 0, TRUE );\
748 DestroyMenu( hmenu );\
749 DestroyMenu( submenu );\
750 submenu = CreateMenu();\
753 #define TMII_MODM( flags, id, data, eret )\
755 SetLastError( 0xdeadbeef);\
756 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
757 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
758 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
760 skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
763 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
764 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
767 /* SetMenuItemInfo */
768 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
771 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
772 SetLastError( 0xdeadbeef);\
773 if(ansi)strcpy( string, init);\
774 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
775 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
776 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
777 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
779 skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
782 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
784 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
793 static void test_menu_iteminfo( void )
795 int S=sizeof( MENUITEMINFOA);
800 WCHAR txtW[]={'W','i','n','e',0};
801 WCHAR initW[]={'X','Y','Z',0};
803 void *txt, *init, *empty, *string;
804 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
806 HMENU submenu=CreateMenu();
809 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
810 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
811 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
812 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
813 /* (since MFT_STRING is zero, there are four of them) */
814 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
815 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
816 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
819 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
820 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
821 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
824 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
825 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
826 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
829 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
830 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
831 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
834 /* not enough space for name*/
835 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
836 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
837 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
840 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
841 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
842 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
845 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
846 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
847 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
850 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
851 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
852 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
855 /* cannot combine MIIM_TYPE with some other flags */
856 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
857 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
858 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
861 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
862 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
863 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
866 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
867 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
868 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
871 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
872 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
873 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
876 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
877 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
878 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
881 /* but succeeds with some others */
882 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
883 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
884 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
887 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
888 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
889 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
892 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
893 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
894 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
897 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
898 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
899 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
902 /* to be continued */
903 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
904 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
905 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
906 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
909 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
910 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
911 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
912 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
915 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
916 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
917 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
920 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
921 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
922 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
925 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
926 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
927 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
930 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
931 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
932 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
933 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
936 /* same but retrieve with MIIM_TYPE */
937 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
938 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
939 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
942 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
943 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
944 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
947 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
948 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
949 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
953 /* How is that with bitmaps? */
954 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
955 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
956 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
959 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
960 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
961 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
964 /* MIIM_BITMAP does not like MFT_BITMAP */
965 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
966 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
967 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
970 /* no problem with OWNERDRAWN */
971 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
972 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
973 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
976 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
977 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
978 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
979 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
983 /* menu with submenu */
984 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
985 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
986 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
989 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
990 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
991 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
994 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
995 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
996 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
997 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
999 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1000 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
1003 /* menu with invalid submenu */
1004 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
1005 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1006 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1010 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
1011 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1012 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1015 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
1016 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1017 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1020 /* SEPARATOR and STRING go well together */
1021 /* BITMAP and STRING go well together */
1022 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1023 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1024 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1027 /* BITMAP, SEPARATOR and STRING go well together */
1028 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1029 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1030 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1033 /* last two tests, but use MIIM_TYPE to retrieve info */
1034 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1035 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1036 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1039 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1040 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1041 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1044 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1045 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1046 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1049 /* same three with MFT_OWNERDRAW */
1050 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1051 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1052 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1055 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1056 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1057 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1060 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1061 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1062 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1066 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1067 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1068 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1071 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1072 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1073 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1074 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1075 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1078 /* same with bitmap: now the text is cleared */
1079 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1080 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1081 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1082 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1085 /* start with bitmap: now setting text clears it (though he flag is raised) */
1086 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1087 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1088 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1090 TMII_MODM( MFT_STRING, 545, txt, OK)
1091 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1092 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1095 /*repeat with text NULL */
1096 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1097 TMII_MODM( MFT_STRING, 545, NULL, OK)
1098 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1099 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1102 /* repeat with text "" */
1103 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1104 TMII_MODM( MFT_STRING, 545, empty, OK)
1105 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1106 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1109 /* start with bitmap: set ownerdraw */
1110 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1111 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1112 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1113 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1117 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1118 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1119 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1122 /* some tests with small cbSize: the hbmpItem is to be ignored */
1123 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1124 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1125 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1128 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1129 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1130 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1133 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1134 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1135 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1138 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1139 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1140 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1143 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1144 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1145 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1148 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1149 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1150 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1153 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1154 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1155 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1156 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1159 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1160 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1161 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1164 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1165 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1166 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1169 /* set a string menu to ownerdraw with MIIM_TYPE */
1170 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1171 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1172 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1173 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1176 /* test with modifymenu add submenu */
1177 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1178 TMII_MODM( MF_POPUP, submenu, txt, OK)
1179 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1180 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1182 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1183 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1186 /* MFT_SEPARATOR bit is kept when the text is added */
1187 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1188 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1189 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1190 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1193 /* MFT_SEPARATOR bit is kept when bitmap is added */
1194 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1195 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1196 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1197 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1200 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1201 Only the low word of the dwTypeData is used.
1202 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1203 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1204 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1205 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1209 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1210 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1211 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1215 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1216 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1217 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1218 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1221 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1222 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1223 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1224 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1225 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1228 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1229 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1230 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1231 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1232 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1234 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1235 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1237 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1238 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1240 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1241 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1242 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1245 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1246 Only the low word of the dwTypeData is used.
1247 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1248 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1249 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1250 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1254 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1255 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1256 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1260 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1261 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1262 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1263 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1266 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1267 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1268 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1269 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1270 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1273 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1274 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1275 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1276 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1277 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1279 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1280 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1282 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1283 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1285 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1286 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1287 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1290 } while( !(ansi = !ansi) );
1295 The following tests try to confirm the algorithm used to return the menu items
1296 when there is a collision between a menu item and a popup menu
1298 static void test_menu_search_bycommand( void )
1300 HMENU hmenu, hmenuSub, hmenuSub2;
1306 static CHAR menuitem[] = "MenuItem",
1307 menuitem2[] = "MenuItem 2";
1309 /* Case 1: Menu containing a menu item */
1310 hmenu = CreateMenu();
1312 memset( &info, 0, sizeof info );
1313 info.cbSize = sizeof info;
1314 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1315 info.fType = MFT_STRING;
1316 strcpy(strIn, "Case 1 MenuItem");
1317 info.dwTypeData = strIn;
1318 info.wID = (UINT) 0x1234;
1320 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1321 ok (rc, "Inserting the menuitem failed\n");
1323 id = GetMenuItemID(hmenu, 0);
1324 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1326 /* Confirm the menuitem was given the id supplied (getting by position) */
1327 memset( &info, 0, sizeof info );
1329 info.cbSize = sizeof(MENUITEMINFO);
1330 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1331 info.dwTypeData = strback;
1332 info.cch = sizeof(strback);
1334 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1335 ok (rc, "Getting the menu items info failed\n");
1336 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1337 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1339 /* Search by id - Should return the item */
1340 memset( &info, 0, sizeof info );
1342 info.cbSize = sizeof(MENUITEMINFO);
1343 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1344 info.dwTypeData = strback;
1345 info.cch = sizeof(strback);
1346 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1348 ok (rc, "Getting the menu items info failed\n");
1349 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1350 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1352 DestroyMenu( hmenu );
1354 /* Case 2: Menu containing a popup menu */
1355 hmenu = CreateMenu();
1356 hmenuSub = CreateMenu();
1358 strcpy(strIn, "Case 2 SubMenu");
1359 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1360 ok (rc, "Inserting the popup menu into the main menu failed\n");
1362 id = GetMenuItemID(hmenu, 0);
1363 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1365 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1366 memset( &info, 0, sizeof info );
1368 info.cbSize = sizeof(MENUITEMINFO);
1369 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1370 info.dwTypeData = strback;
1371 info.cch = sizeof(strback);
1372 info.wID = 0xdeadbeef;
1374 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1375 ok (rc, "Getting the menu items info failed\n");
1376 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1377 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1379 /* Search by id - returns the popup menu itself */
1380 memset( &info, 0, sizeof info );
1382 info.cbSize = sizeof(MENUITEMINFO);
1383 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1384 info.dwTypeData = strback;
1385 info.cch = sizeof(strback);
1386 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1388 ok (rc, "Getting the menu items info failed\n");
1389 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1390 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1393 Now add an item after it with the same id
1395 memset( &info, 0, sizeof info );
1396 info.cbSize = sizeof info;
1397 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1398 info.fType = MFT_STRING;
1399 strcpy(strIn, "Case 2 MenuItem 1");
1400 info.dwTypeData = strIn;
1401 info.wID = (UINT_PTR) hmenuSub;
1402 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1403 ok (rc, "Inserting the menuitem failed\n");
1405 /* Search by id - returns the item which follows the popup menu */
1406 memset( &info, 0, sizeof info );
1408 info.cbSize = sizeof(MENUITEMINFO);
1409 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1410 info.dwTypeData = strback;
1411 info.cch = sizeof(strback);
1412 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1414 ok (rc, "Getting the menu items info failed\n");
1415 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1416 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1419 Now add an item before the popup (with the same id)
1421 memset( &info, 0, sizeof info );
1422 info.cbSize = sizeof info;
1423 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1424 info.fType = MFT_STRING;
1425 strcpy(strIn, "Case 2 MenuItem 2");
1426 info.dwTypeData = strIn;
1427 info.wID = (UINT_PTR) hmenuSub;
1428 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1429 ok (rc, "Inserting the menuitem failed\n");
1431 /* Search by id - returns the item which precedes the popup menu */
1432 memset( &info, 0, sizeof info );
1434 info.cbSize = sizeof(MENUITEMINFO);
1435 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1436 info.dwTypeData = strback;
1437 info.cch = sizeof(strback);
1438 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1440 ok (rc, "Getting the menu items info failed\n");
1441 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1442 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1444 DestroyMenu( hmenu );
1445 DestroyMenu( hmenuSub );
1448 Case 3: Menu containing a popup menu which in turn
1449 contains 2 items with the same id as the popup itself
1452 hmenu = CreateMenu();
1453 hmenuSub = CreateMenu();
1455 memset( &info, 0, sizeof info );
1456 info.cbSize = sizeof info;
1457 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1458 info.fType = MFT_STRING;
1459 info.dwTypeData = menuitem;
1460 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1462 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1463 ok (rc, "Inserting the popup menu into the main menu failed\n");
1465 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1466 ok (rc, "Inserting the sub menu menuitem failed\n");
1468 memset( &info, 0, sizeof info );
1469 info.cbSize = sizeof info;
1470 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1471 info.fType = MFT_STRING;
1472 info.dwTypeData = menuitem2;
1473 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1475 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1476 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1478 /* Prove that you can't query the id of a popup directly (By position) */
1479 id = GetMenuItemID(hmenu, 0);
1480 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1482 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1483 memset( &info, 0, sizeof info );
1485 info.cbSize = sizeof(MENUITEMINFO);
1486 info.fMask = MIIM_STRING | MIIM_ID;
1487 info.dwTypeData = strback;
1488 info.cch = sizeof(strback);
1490 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1491 ok (rc, "Getting the menus info failed\n");
1492 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1493 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1494 DestroyMenu( hmenu );
1495 DestroyMenu( hmenuSub );
1498 Case 4: Menu containing 2 popup menus, the second
1499 contains 2 items with the same id as the first popup menu
1501 hmenu = CreateMenu();
1502 hmenuSub = CreateMenu();
1503 hmenuSub2 = CreateMenu();
1505 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1506 ok (rc, "Inserting the popup menu into the main menu failed\n");
1508 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1509 ok (rc, "Inserting the popup menu into the main menu failed\n");
1511 memset( &info, 0, sizeof info );
1512 info.cbSize = sizeof info;
1513 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1514 info.fType = MFT_STRING;
1515 info.dwTypeData = menuitem;
1516 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1518 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1519 ok (rc, "Inserting the sub menu menuitem failed\n");
1521 memset( &info, 0, sizeof info );
1522 info.cbSize = sizeof info;
1523 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1524 info.fType = MFT_STRING;
1525 info.dwTypeData = menuitem2;
1526 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1528 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1529 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1531 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1532 memset( &info, 0, sizeof info );
1534 info.cbSize = sizeof(MENUITEMINFO);
1535 info.fMask = MIIM_STRING | MIIM_ID;
1536 info.dwTypeData = strback;
1537 info.cch = sizeof(strback);
1539 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1540 ok (rc, "Getting the menus info failed\n");
1541 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1542 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1544 memset( &info, 0, sizeof info );
1546 info.cbSize = sizeof(MENUITEMINFO);
1547 info.fMask = MIIM_STRING | MIIM_ID;
1548 info.dwTypeData = strback;
1549 info.cch = sizeof(strback);
1551 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1552 ok (rc, "Getting the menus info failed\n");
1553 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1554 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1556 DestroyMenu( hmenu );
1557 DestroyMenu( hmenuSub );
1558 DestroyMenu( hmenuSub2 );
1562 Case 5: Menu containing a popup menu which in turn
1563 contains an item with a different id than the popup menu.
1564 This tests the fallback to a popup menu ID.
1567 hmenu = CreateMenu();
1568 hmenuSub = CreateMenu();
1570 rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1571 ok (rc, "Appending the popup menu to the main menu failed\n");
1573 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1574 ok (rc, "Appending the item to the popup menu failed\n");
1576 /* Set the ID for hmenuSub */
1577 info.cbSize = sizeof(info);
1578 info.fMask = MIIM_ID;
1581 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1582 ok(rc, "Setting the ID for the popup menu failed\n");
1584 /* Check if the ID has been set */
1586 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1587 ok(rc, "Getting the ID for the popup menu failed\n");
1588 ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1590 /* Prove getting the item info via ID returns the popup menu */
1591 memset( &info, 0, sizeof(info));
1593 info.cbSize = sizeof(MENUITEMINFO);
1594 info.fMask = MIIM_STRING | MIIM_ID;
1595 info.dwTypeData = strback;
1596 info.cch = sizeof(strback);
1598 rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1599 ok (rc, "Getting the menu info failed\n");
1600 ok (info.wID == 101, "IDs differ\n");
1601 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1603 /* Also look for the menu item */
1604 memset( &info, 0, sizeof(info));
1606 info.cbSize = sizeof(MENUITEMINFO);
1607 info.fMask = MIIM_STRING | MIIM_ID;
1608 info.dwTypeData = strback;
1609 info.cch = sizeof(strback);
1611 rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1612 ok (rc, "Getting the menu info failed\n");
1613 ok (info.wID == 102, "IDs differ\n");
1614 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1617 DestroyMenu(hmenuSub);
1620 struct menu_item_pair_s {
1621 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1622 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1623 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1627 static struct menu_mouse_tests_s {
1629 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1630 WORD wVk[5]; /* keys */
1634 /* for each test, send keys or clicks and check for menu visibility */
1635 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1636 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1637 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1638 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1639 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1640 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1641 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1642 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1643 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1644 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1645 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1646 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1647 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1648 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1649 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1650 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1651 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1652 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1654 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1655 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1656 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1657 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1658 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1659 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1660 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1661 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1662 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1663 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1664 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1668 static void send_key(WORD wVk)
1671 memset(&i, 0, 2*sizeof(INPUT));
1672 i[0].type = i[1].type = INPUT_KEYBOARD;
1673 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1674 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1675 SendInput(2, (INPUT *) i, sizeof(INPUT));
1678 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1680 HMENU hMenu = hMenus[mi->uMenu];
1684 int screen_w = GetSystemMetrics(SM_CXSCREEN);
1685 int screen_h = GetSystemMetrics(SM_CYSCREEN);
1687 GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1689 memset(&i, 0, 3*sizeof(INPUT));
1690 i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1691 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1692 = ((r.left + 5) * 65535) / screen_w;
1693 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1694 = ((r.top + 5) * 65535) / screen_h;
1695 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1696 = MOUSEEVENTF_ABSOLUTE;
1697 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1698 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1699 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1700 SendInput(3, (INPUT *) i, sizeof(INPUT));
1702 /* hack to prevent mouse message buildup in Wine */
1703 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1706 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1709 HANDLE hWnd = lpParameter;
1712 /* mixed keyboard/mouse test */
1713 for (i = 0; menu_tests[i].type != -1; i++)
1717 if (menu_tests[i].type == INPUT_KEYBOARD)
1718 for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1719 send_key(menu_tests[i].wVk[j]);
1721 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1722 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1724 while (menu_tests[i].bMenuVisible != bMenuVisible)
1732 if (menu_tests[i]._todo_wine)
1735 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1739 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1744 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1748 case WM_ENTERMENULOOP:
1749 bMenuVisible = TRUE;
1751 case WM_EXITMENULOOP:
1752 bMenuVisible = FALSE;
1755 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1760 static void test_menu_input(void) {
1763 HINSTANCE hInstance = GetModuleHandleA( NULL );
1764 HANDLE hThread, hWnd;
1766 wclass.lpszClassName = "MenuTestClass";
1767 wclass.style = CS_HREDRAW | CS_VREDRAW;
1768 wclass.lpfnWndProc = WndProc;
1769 wclass.hInstance = hInstance;
1770 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1771 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1772 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1773 wclass.lpszMenuName = 0;
1774 wclass.cbClsExtra = 0;
1775 wclass.cbWndExtra = 0;
1776 assert (RegisterClassA( &wclass ));
1777 assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1778 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1779 400, 200, NULL, NULL, hInstance, NULL) );
1782 hMenus[3] = CreatePopupMenu();
1783 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1784 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1786 hMenus[2] = CreatePopupMenu();
1787 AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1788 AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1789 AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1791 hMenus[1] = CreateMenu();
1792 AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1793 AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1794 AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1796 SetMenu(hWnd, hMenus[1]);
1797 ShowWindow(hWnd, SW_SHOW);
1800 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1803 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1805 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1807 DestroyWindow(hWnd);
1810 static void test_menu_flags( void )
1812 HMENU hMenu, hPopupMenu;
1814 hMenu = CreateMenu();
1815 hPopupMenu = CreatePopupMenu();
1817 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1819 AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1820 InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1821 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1822 ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1824 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1825 "AppendMenu should accept MF_HILITE\n");
1826 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1827 "InsertMenu should accept MF_HILITE\n");
1828 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1829 "ModifyMenu should accept MF_HILITE\n");
1831 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1832 "AppendMenu must not accept MF_DEFAULT\n");
1833 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1834 "InsertMenu must not accept MF_DEFAULT\n");
1835 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1836 "ModifyMenu must not accept MF_DEFAULT\n");
1841 static void test_menu_hilitemenuitem( void )
1843 HMENU hMenu, hPopupMenu;
1845 hMenu = CreateMenu();
1846 hPopupMenu = CreatePopupMenu();
1848 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1850 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1851 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1852 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1854 HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
1855 HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
1856 HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
1857 HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
1861 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1862 "HiliteMenuItem: Item 1 is not hilited\n");
1864 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1865 "HiliteMenuItem: Item 2 is hilited\n");
1868 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1869 "HiliteMenuItem: Item 3 is not hilited\n");
1878 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1880 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1882 register_menu_check_class();
1884 test_menu_locked_by_window();
1885 test_menu_ownerdraw();
1886 test_menu_add_string();
1887 test_menu_iteminfo();
1888 test_menu_search_bycommand();
1889 test_menu_bmp_and_string();
1892 test_menu_hilitemenuitem();