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
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
30 #define OEMRESOURCE /* For OBM_MNARROW */
37 #include "wine/test.h"
39 static ATOM atomMenuCheckClass;
41 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
42 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
44 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
48 case WM_ENTERMENULOOP:
49 /* mark window as having entered menu loop */
50 SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
51 /* exit menu modal loop
52 * ( A SendMessage does not work on NT3.51 here ) */
53 return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
55 return DefWindowProc(hwnd, msg, wparam, lparam);
58 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
71 /* globals to communicate between test and wndproc */
73 static BOOL bMenuVisible;
74 static HMENU hMenus[4];
79 /* menu texts with their sizes */
82 SIZE size; /* size of text up to any \t */
83 SIZE sc_size; /* size of the short-cut */
92 unsigned int MOD_maxid;
93 RECT MOD_rc[MOD_NRMENUS];
94 int MOD_avec, MOD_hic;
96 SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
97 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
98 int MOD_GotDrawItemMsg = FALSE;
99 /* wndproc used by test_menu_ownerdraw() */
100 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
101 WPARAM wparam, LPARAM lparam)
107 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
109 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
110 pmis->itemData, pmis->itemWidth, pmis->itemHeight);
111 MOD_odheight = pmis->itemHeight;
112 pmis->itemWidth = MODsizes[pmis->itemData].cx;
113 pmis->itemHeight = MODsizes[pmis->itemData].cy;
118 DRAWITEMSTRUCT * pdis;
121 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
124 pdis = (DRAWITEMSTRUCT *) lparam;
125 if( winetest_debug) {
127 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
128 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
129 hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
130 pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
131 pdis->rcItem.right,pdis->rcItem.bottom,
132 rc.left,rc.top,rc.right,rc.bottom);
133 oldpen=SelectObject( pdis->hDC, GetStockObject(
134 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
135 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
136 pdis->rcItem.right,pdis->rcItem.bottom );
137 SelectObject( pdis->hDC, oldpen);
139 /* calculate widths of some menu texts */
140 if( ! MOD_txtsizes[0].size.cx)
141 for(i = 0; MOD_txtsizes[i].text; i++) {
144 strcpy( buf, MOD_txtsizes[i].text);
145 if( ( p = strchr( buf, '\t'))) {
147 DrawText( pdis->hDC, p + 1, -1, &rc,
148 DT_SINGLELINE|DT_CALCRECT);
149 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
150 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
152 DrawText( pdis->hDC, buf, -1, &rc,
153 DT_SINGLELINE|DT_CALCRECT);
154 MOD_txtsizes[i].size.cx= rc.right - rc.left;
155 MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
158 if( pdis->itemData > MOD_maxid) return TRUE;
159 /* store the rectangl */
160 MOD_rc[pdis->itemData] = pdis->rcItem;
161 /* calculate average character width */
162 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
163 MOD_avec = (sz.cx + 26)/52;
164 GetTextMetrics( pdis->hDC, &tm);
165 MOD_hic = tm.tmHeight;
166 MOD_GotDrawItemMsg = TRUE;
171 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
176 return DefWindowProc(hwnd, msg, wparam, lparam);
179 static void register_menu_check_class(void)
187 GetModuleHandle(NULL),
189 LoadCursor(NULL, IDC_ARROW),
190 (HBRUSH)(COLOR_BTNFACE+1),
192 TEXT("WineMenuCheck"),
195 atomMenuCheckClass = RegisterClass(&wc);
198 /* demonstrates that windows locks the menu object so that it is still valid
199 * even after a client calls DestroyMenu on it */
200 static void test_menu_locked_by_window(void)
204 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
205 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
206 NULL, NULL, NULL, NULL);
207 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
208 hmenu = CreateMenu();
209 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
210 ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
211 ok(ret, "InsertMenu failed with error %d\n", GetLastError());
212 ret = SetMenu(hwnd, hmenu);
213 ok(ret, "SetMenu failed with error %d\n", GetLastError());
214 ret = DestroyMenu(hmenu);
215 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
217 ret = DrawMenuBar(hwnd);
219 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
221 ret = IsMenu(GetMenu(hwnd));
222 ok(!ret, "Menu handle should have been destroyed\n");
224 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
225 /* did we process the WM_INITMENU message? */
226 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
228 ok(ret, "WM_INITMENU should have been sent\n");
234 static void test_menu_ownerdraw(void)
240 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
241 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
242 NULL, NULL, NULL, NULL);
243 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
245 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
246 hmenu = CreatePopupMenu();
247 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
248 if( !hmenu) { DestroyWindow(hwnd);return;}
250 for( j=0;j<2;j++) /* create columns */
251 for(i=0;i<2;i++) { /* create rows */
252 ret = AppendMenu( hmenu, MF_OWNERDRAW |
253 (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
255 ok( ret, "AppendMenu failed for %d\n", k-1);
258 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
259 /* display the menu */
260 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
262 /* columns have a 4 pixel gap between them */
263 ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
264 "item rectangles are not separated by 4 pixels space\n");
265 /* height should be what the MEASUREITEM message has returned */
266 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
267 "menu item has wrong height: %d should be %d\n",
268 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
269 /* no gaps between the rows */
270 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
271 "There should not be a space between the rows, gap is %d\n",
272 MOD_rc[0].bottom - MOD_rc[1].top);
273 /* test the correct value of the item height that was sent
274 * by the WM_MEASUREITEM message */
275 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
276 MOD_odheight == MOD_hic, /* Win95,98,ME */
277 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
278 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
279 /* test what MF_MENUBREAK did at the first position. Also show
280 * that an MF_SEPARATOR is ignored in the height calculation. */
281 leftcol= MOD_rc[0].left;
282 ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
283 /* display the menu */
284 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
285 /* left should be 4 pixels less now */
286 ok( leftcol == MOD_rc[0].left + 4,
287 "columns should be 4 pixels to the left (actual %d).\n",
288 leftcol - MOD_rc[0].left);
290 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
291 "width of owner drawn menu item is wrong. Got %d expected %d\n",
292 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
294 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
295 "Height is incorrect. Got %d expected %d\n",
296 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
298 /* test width/height of an ownerdraw menu bar as well */
299 ret = DestroyMenu(hmenu);
300 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
301 hmenu = CreateMenu();
302 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
303 if( !hmenu) { DestroyWindow(hwnd);return;}
306 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
307 ok( ret, "AppendMenu failed for %d\n", i);
309 ret = SetMenu( hwnd, hmenu);
310 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
311 ok(ret, "SetMenu failed with error %d\n", GetLastError());
313 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
314 "width of owner drawn menu item is wrong. Got %d expected %d\n",
315 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
317 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
318 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
319 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
322 ret = DestroyMenu(hmenu);
323 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
327 /* helper for test_menu_bmp_and_string() */
328 static void test_mbs_help( int ispop, int hassub, int mnuopt,
329 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
330 SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
333 HMENU hmenu, submenu;
334 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
341 MOD_GotDrawItemMsg = FALSE;
342 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
344 mii.fState = MF_CHECKED;
346 MODsizes[0] = bmpsize;
350 mii.fMask |= MIIM_STRING;
351 strcpy(text_copy, text);
352 mii.dwTypeData = text_copy; /* structure member declared non-const */
353 if( ( p = strchr( text, '\t'))) {
354 hastab = *(p + 1) ? 2 : 1;
357 /* tabs don't make sense in menubars */
358 if(hastab && !ispop) return;
360 mii.fMask |= MIIM_BITMAP;
363 submenu = CreateMenu();
364 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
366 hmenu = CreatePopupMenu();
368 hmenu = CreateMenu();
369 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
371 mii.fMask |= MIIM_SUBMENU;
372 mii.hSubMenu = submenu;
375 mi.cbSize = sizeof(mi);
376 mi.fMask = MIM_STYLE;
377 pGetMenuInfo( hmenu, &mi);
378 mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
379 ret = pSetMenuInfo( hmenu, &mi);
380 ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
382 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
383 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
385 if( winetest_debug) {
387 RECT rc = {100, 50, 400, 70};
390 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
391 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
392 TextOut( hdc, 100, 50, buf, strlen( buf));
393 ReleaseDC( hwnd, hdc);
396 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
398 ret = SetMenu( hwnd, hmenu);
399 ok(ret, "SetMenu failed with error %d\n", GetLastError());
402 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
403 /* check menu width */
405 expect = ( text || hbmp ?
406 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
408 arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
409 (text && hastab ? /* TAB space */
410 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
411 (text ? 2 + (text[0] ? size.cx :0): 0) ;
413 expect = !(text || hbmp) ? 0 :
414 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) +
415 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
416 ok( rc.right - rc.left == expect,
417 "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
418 failed = failed || !(rc.right - rc.left == expect);
419 /* check menu height */
421 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
422 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
423 (hbmp ? bmpsize.cy + 2 : 0)));
425 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
426 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
427 ok( rc.bottom - rc.top == expect,
428 "menu height wrong, got %d expected %d (%d)\n",
429 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
430 failed = failed || !(rc.bottom - rc.top == expect);
431 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
432 /* check the position of the bitmap */
434 expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
436 ok( expect == MOD_rc[0].left,
437 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
438 failed = failed || !(expect == MOD_rc[0].left);
440 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
441 ok( expect == MOD_rc[0].top,
442 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
443 failed = failed || !(expect == MOD_rc[0].top);
445 /* if there was a failure, report details */
447 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
448 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
449 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
450 trace(" check %d,%d arrow %d avechar %d\n",
451 GetSystemMetrics(SM_CXMENUCHECK ),
452 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
453 if( hbmp == HBMMENU_CALLBACK)
454 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
455 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
456 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
459 ret = DestroyMenu(submenu);
460 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
461 ret = DestroyMenu(hmenu);
462 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
466 static void test_menu_bmp_and_string(void)
473 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
475 if( !pGetMenuInfo) return;
477 memset( bmfill, 0x55, sizeof( bmfill));
478 hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
479 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
480 NULL, NULL, NULL, NULL);
481 hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
482 GetObject( hbm_arrow, sizeof(bm), &bm);
483 arrowwidth = bm.bmWidth;
485 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
487 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
490 trace(" check %d,%d arrow %d avechar %d\n",
491 GetSystemMetrics(SM_CXMENUCHECK ),
492 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
495 for( ispop=1; ispop >= 0; ispop--){
496 static SIZE bmsizes[]= {
497 {10,10},{38,38},{1,30},{55,5}};
498 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
499 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
500 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL };
501 ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError());
502 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
503 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
504 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
505 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
506 /* no need to test NULL bitmaps of several sizes */
507 if( !bitmaps[bmpidx] && szidx > 0) continue;
508 if( !ispop && hassub) continue;
509 test_mbs_help( ispop, hassub, mnuopt,
510 hwnd, arrowwidth, ++count,
513 MOD_txtsizes[txtidx].text,
514 MOD_txtsizes[txtidx].size,
515 MOD_txtsizes[txtidx].sc_size);
527 static void test_menu_add_string( void )
537 WCHAR strbackW[0x80];
538 static CHAR blah[] = "blah";
539 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
541 hmenu = CreateMenu();
543 memset( &info, 0, sizeof info );
544 info.cbSize = sizeof info;
545 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
546 info.dwTypeData = blah;
551 InsertMenuItem(hmenu, 0, TRUE, &info );
553 memset( &info, 0, sizeof info );
554 info.cbSize = sizeof info;
555 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
556 info.dwTypeData = string;
557 info.cch = sizeof string;
559 GetMenuItemInfo( hmenu, 0, TRUE, &info );
561 ok( !strcmp( string, "blah" ), "menu item name differed\n");
563 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
564 strcpy(string, "Dummy string");
565 memset(&info, 0x00, sizeof(info));
566 info.cbSize= sizeof(MENUITEMINFO);
567 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
568 info.fType= MFT_OWNERDRAW;
569 info.dwTypeData= string;
570 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
571 ok (rc, "InsertMenuItem failed\n");
573 strcpy(string,"Garbage");
574 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
575 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
577 ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
578 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
580 /* Just change ftype to string and see what text is stored */
581 memset(&info, 0x00, sizeof(info));
582 info.cbSize= sizeof(MENUITEMINFO);
583 info.fMask= MIIM_FTYPE; /* Set string type */
584 info.fType= MFT_STRING;
585 info.dwTypeData= (char *)0xdeadbeef;
586 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
587 ok (rc, "SetMenuItemInfo failed\n");
589 /* Did we keep the old dwTypeData? */
590 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
591 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
593 /* Ensure change to bitmap type fails */
594 memset(&info, 0x00, sizeof(info));
595 info.cbSize= sizeof(MENUITEMINFO);
596 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
597 info.fType= MFT_BITMAP;
598 info.dwTypeData= (char *)0xdeadbee2;
599 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
600 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
602 /* Just change ftype back and ensure data hasn't been freed */
603 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
604 info.dwTypeData= (char *)0xdeadbee3;
605 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
606 ok (rc, "SetMenuItemInfo failed\n");
608 /* Did we keep the old dwTypeData? */
609 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
610 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
612 /* Just change string value (not type) */
613 memset(&info, 0x00, sizeof(info));
614 info.cbSize= sizeof(MENUITEMINFO);
615 info.fMask= MIIM_STRING; /* Set typeData */
616 strcpy(string2, "string2");
617 info.dwTypeData= string2;
618 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
619 ok (rc, "SetMenuItemInfo failed\n");
621 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
622 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
624 /* crashes with wine 0.9.5 */
625 memset(&info, 0x00, sizeof(info));
626 info.cbSize= sizeof(MENUITEMINFO);
627 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
628 info.fType= MFT_OWNERDRAW;
629 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
630 ok (rc, "InsertMenuItem failed\n");
631 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
632 "GetMenuString on ownerdraw entry succeeded.\n");
633 ok (!GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION),
634 "GetMenuStringW on ownerdraw entry succeeded.\n");
637 DestroyMenu( hmenu );
640 /* define building blocks for the menu item info tests */
641 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
643 if (n <= 0) return 0;
644 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
645 return *str1 - *str2;
648 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
651 while ((*p++ = *src++));
656 #define DMIINFF( i, e, field)\
657 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
658 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
660 #define DUMPMIINF(s,i,e)\
662 DMIINFF( i, e, fMask)\
663 DMIINFF( i, e, fType)\
664 DMIINFF( i, e, fState)\
666 DMIINFF( i, e, hSubMenu)\
667 DMIINFF( i, e, hbmpChecked)\
668 DMIINFF( i, e, hbmpUnchecked)\
669 DMIINFF( i, e, dwItemData)\
670 DMIINFF( i, e, dwTypeData)\
672 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
675 /* insert menu item */
676 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
679 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
680 HMENU hmenu = CreateMenu();\
681 BOOL ret, stop = FALSE;\
682 SetLastError( 0xdeadbeef);\
683 if(ansi)strcpy( string, init);\
684 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
685 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
686 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
687 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
689 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
692 /* GetMenuItemInfo + GetMenuString */
693 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
694 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
695 expname, eret2, eret3)\
697 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
698 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
699 MENUITEMINFOA *info2 = &info2A;\
700 MENUITEMINFOA *einfo = &einfoA;\
701 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
703 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
704 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
705 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
707 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
708 ret = memcmp( info2, einfo, sizeof einfoA);\
709 /* ok( ret==0, "Got wrong menu item info data\n");*/\
710 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
711 if( einfo->dwTypeData == string) {\
712 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
713 einfo->dwTypeData ? einfo->dwTypeData: "");\
714 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
715 einfo->dwTypeData ? einfo->dwTypeData: "");\
716 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
717 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
719 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
721 ok( !ret, "GetMenuString should have failed\n");\
728 RemoveMenu(hmenu, 0, TRUE );\
729 DestroyMenu( hmenu );\
730 DestroyMenu( submenu );\
731 submenu = CreateMenu();\
734 #define TMII_MODM( flags, id, data, eret )\
736 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
737 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
738 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
739 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
742 /* SetMenuItemInfo */
743 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
746 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
747 SetLastError( 0xdeadbeef);\
748 if(ansi)strcpy( string, init);\
749 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
750 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
751 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
752 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
754 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
763 static void test_menu_iteminfo( void )
765 int S=sizeof( MENUITEMINFOA);
770 WCHAR txtW[]={'W','i','n','e',0};
771 WCHAR initW[]={'X','Y','Z',0};
773 void *txt, *init, *empty, *string;
774 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
776 HMENU submenu=CreateMenu();
779 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
780 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
781 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
782 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
783 /* (since MFT_STRING is zero, there are four of them) */
784 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
785 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
786 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
789 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
790 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
791 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
794 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
795 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
796 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
799 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
800 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
801 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
804 /* not enough space for name*/
805 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
806 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
807 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
810 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
811 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
812 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
815 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
816 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
817 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
820 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
821 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
822 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
825 /* cannot combine MIIM_TYPE with some other flags */
826 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
827 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
828 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
831 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
832 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
833 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
836 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
837 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
838 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
841 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
842 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
843 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
846 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
847 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
848 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
851 /* but succeeds with some others */
852 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
853 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
854 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
857 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
858 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
859 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
862 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
863 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
864 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
867 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
868 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
869 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
872 /* to be continued */
873 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
874 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
875 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
876 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
879 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
880 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
881 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
882 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
885 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
886 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
887 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
890 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
891 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
892 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
895 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
896 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
897 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
900 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
901 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
902 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
903 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
906 /* same but retrieve with MIIM_TYPE */
907 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
908 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
909 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
912 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
913 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
914 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
917 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
918 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
919 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
923 /* How is that with bitmaps? */
924 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
925 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
926 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
929 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
930 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
931 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
934 /* MIIM_BITMAP does not like MFT_BITMAP */
935 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
936 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
937 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
940 /* no problem with OWNERDRAWN */
941 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
942 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
943 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
946 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
947 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
948 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
949 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
953 /* menu with submenu */
954 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
955 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
956 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
959 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
960 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
961 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
964 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
965 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
966 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
967 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
969 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
970 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
973 /* menu with invalid submenu */
974 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
975 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
976 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
980 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
981 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
982 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
985 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
986 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
987 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
990 /* SEPARATOR and STRING go well together */
991 /* BITMAP and STRING go well together */
992 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
993 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
994 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
997 /* BITMAP, SEPARATOR and STRING go well together */
998 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
999 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1000 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1003 /* last two tests, but use MIIM_TYPE to retrieve info */
1004 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1005 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1006 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1009 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1010 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1011 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1014 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1015 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1016 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1019 /* same three with MFT_OWNERDRAW */
1020 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1021 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1022 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1025 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1026 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1027 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1030 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1031 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1032 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1036 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1037 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1038 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1041 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1042 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1043 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1044 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1045 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1048 /* same with bitmap: now the text is cleared */
1049 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1050 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1051 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1052 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1055 /* start with bitmap: now setting text clears it (though he flag is raised) */
1056 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1057 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1058 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1060 TMII_MODM( MFT_STRING, 545, txt, OK)
1061 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1062 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1065 /*repeat with text NULL */
1066 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1067 TMII_MODM( MFT_STRING, 545, NULL, OK)
1068 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1069 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1072 /* repeat with text "" */
1073 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1074 TMII_MODM( MFT_STRING, 545, empty, OK)
1075 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1076 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1079 /* start with bitmap: set ownerdraw */
1080 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1081 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1082 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1083 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1087 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1088 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1089 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1092 /* some tests with small cbSize: the hbmpItem is to be ignored */
1093 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1094 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1095 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1098 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1099 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1100 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1103 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1104 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1105 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1108 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1109 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1110 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1113 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1114 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1115 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1118 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1119 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1120 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1123 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1124 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1125 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1126 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1129 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1130 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1131 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1134 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1135 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1136 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1139 /* set a string menu to ownerdraw with MIIM_TYPE */
1140 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1141 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1142 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1143 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1146 /* test with modifymenu add submenu */
1147 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1148 TMII_MODM( MF_POPUP, submenu, txt, OK)
1149 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1150 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1152 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1153 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1156 /* MFT_SEPARATOR bit is kept when the text is added */
1157 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1158 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1159 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1160 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1163 /* MFT_SEPARATOR bit is kept when bitmap is added */
1164 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1165 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1166 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1167 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1170 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1171 Only the low word of the dwTypeData is used.
1172 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1173 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1174 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1175 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1179 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)
1180 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1181 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1185 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1186 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1187 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1188 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1191 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1192 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1193 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1194 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1195 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1198 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1199 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1200 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1201 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1202 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1204 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1205 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1207 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1208 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1210 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1211 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1212 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1215 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1216 Only the low word of the dwTypeData is used.
1217 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1218 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1219 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1220 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1224 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)
1225 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1226 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1230 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1231 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1232 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1233 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1236 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1237 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1238 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1239 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1240 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1243 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1244 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1245 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1246 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1247 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1249 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1250 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1252 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1253 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1255 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1256 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1257 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1260 } while( !(ansi = !ansi) );
1265 The following tests try to confirm the algorithm used to return the menu items
1266 when there is a collision between a menu item and a popup menu
1268 void test_menu_search_bycommand( void )
1270 HMENU hmenu, hmenuSub, hmenuSub2;
1276 static CHAR menuitem[] = "MenuItem",
1277 menuitem2[] = "MenuItem 2";
1279 /* Case 1: Menu containing a menu item */
1280 hmenu = CreateMenu();
1282 memset( &info, 0, sizeof info );
1283 info.cbSize = sizeof info;
1284 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1285 info.fType = MFT_STRING;
1286 strcpy(strIn, "Case 1 MenuItem");
1287 info.dwTypeData = strIn;
1288 info.wID = (UINT) 0x1234;
1290 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1291 ok (rc, "Inserting the menuitem failed\n");
1293 id = GetMenuItemID(hmenu, 0);
1294 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1296 /* Confirm the menuitem was given the id supplied (getting by position) */
1297 memset( &info, 0, sizeof info );
1299 info.cbSize = sizeof(MENUITEMINFO);
1300 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1301 info.dwTypeData = strback;
1302 info.cch = sizeof(strback);
1304 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1305 ok (rc, "Getting the menu items info failed\n");
1306 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1307 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1309 /* Search by id - Should return the item */
1310 memset( &info, 0, sizeof info );
1312 info.cbSize = sizeof(MENUITEMINFO);
1313 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1314 info.dwTypeData = strback;
1315 info.cch = sizeof(strback);
1316 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1318 ok (rc, "Getting the menu items info failed\n");
1319 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1320 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1322 DestroyMenu( hmenu );
1324 /* Case 2: Menu containing a popup menu */
1325 hmenu = CreateMenu();
1326 hmenuSub = CreateMenu();
1328 strcpy(strIn, "Case 2 SubMenu");
1329 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1330 ok (rc, "Inserting the popup menu into the main menu failed\n");
1332 id = GetMenuItemID(hmenu, 0);
1333 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1335 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1336 memset( &info, 0, sizeof info );
1338 info.cbSize = sizeof(MENUITEMINFO);
1339 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1340 info.dwTypeData = strback;
1341 info.cch = sizeof(strback);
1342 info.wID = 0xdeadbeef;
1344 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1345 ok (rc, "Getting the menu items info failed\n");
1346 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1347 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1349 /* Search by id - returns the popup menu itself */
1350 memset( &info, 0, sizeof info );
1352 info.cbSize = sizeof(MENUITEMINFO);
1353 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1354 info.dwTypeData = strback;
1355 info.cch = sizeof(strback);
1356 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1358 ok (rc, "Getting the menu items info failed\n");
1359 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1360 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1363 Now add an item after it with the same id
1365 memset( &info, 0, sizeof info );
1366 info.cbSize = sizeof info;
1367 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1368 info.fType = MFT_STRING;
1369 strcpy(strIn, "Case 2 MenuItem 1");
1370 info.dwTypeData = strIn;
1371 info.wID = (UINT_PTR) hmenuSub;
1372 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1373 ok (rc, "Inserting the menuitem failed\n");
1375 /* Search by id - returns the item which follows the popup menu */
1376 memset( &info, 0, sizeof info );
1378 info.cbSize = sizeof(MENUITEMINFO);
1379 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1380 info.dwTypeData = strback;
1381 info.cch = sizeof(strback);
1382 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1384 ok (rc, "Getting the menu items info failed\n");
1385 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1386 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1389 Now add an item before the popup (with the same id)
1391 memset( &info, 0, sizeof info );
1392 info.cbSize = sizeof info;
1393 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1394 info.fType = MFT_STRING;
1395 strcpy(strIn, "Case 2 MenuItem 2");
1396 info.dwTypeData = strIn;
1397 info.wID = (UINT_PTR) hmenuSub;
1398 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1399 ok (rc, "Inserting the menuitem failed\n");
1401 /* Search by id - returns the item which precedes the popup menu */
1402 memset( &info, 0, sizeof info );
1404 info.cbSize = sizeof(MENUITEMINFO);
1405 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1406 info.dwTypeData = strback;
1407 info.cch = sizeof(strback);
1408 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1410 ok (rc, "Getting the menu items info failed\n");
1411 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1412 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1414 DestroyMenu( hmenu );
1415 DestroyMenu( hmenuSub );
1418 Case 3: Menu containing a popup menu which in turn
1419 contains 2 items with the same id as the popup itself
1422 hmenu = CreateMenu();
1423 hmenuSub = CreateMenu();
1425 memset( &info, 0, sizeof info );
1426 info.cbSize = sizeof info;
1427 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1428 info.fType = MFT_STRING;
1429 info.dwTypeData = menuitem;
1430 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1432 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1433 ok (rc, "Inserting the popup menu into the main menu failed\n");
1435 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1436 ok (rc, "Inserting the sub menu menuitem failed\n");
1438 memset( &info, 0, sizeof info );
1439 info.cbSize = sizeof info;
1440 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1441 info.fType = MFT_STRING;
1442 info.dwTypeData = menuitem2;
1443 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1445 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1446 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1448 /* Prove that you can't query the id of a popup directly (By position) */
1449 id = GetMenuItemID(hmenu, 0);
1450 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1452 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1453 memset( &info, 0, sizeof info );
1455 info.cbSize = sizeof(MENUITEMINFO);
1456 info.fMask = MIIM_STRING | MIIM_ID;
1457 info.dwTypeData = strback;
1458 info.cch = sizeof(strback);
1460 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1461 ok (rc, "Getting the menus info failed\n");
1462 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1463 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1464 DestroyMenu( hmenu );
1465 DestroyMenu( hmenuSub );
1468 Case 4: Menu containing 2 popup menus, the second
1469 contains 2 items with the same id as the first popup menu
1471 hmenu = CreateMenu();
1472 hmenuSub = CreateMenu();
1473 hmenuSub2 = CreateMenu();
1475 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1476 ok (rc, "Inserting the popup menu into the main menu failed\n");
1478 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1479 ok (rc, "Inserting the popup menu into the main menu failed\n");
1481 memset( &info, 0, sizeof info );
1482 info.cbSize = sizeof info;
1483 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1484 info.fType = MFT_STRING;
1485 info.dwTypeData = menuitem;
1486 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1488 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1489 ok (rc, "Inserting the sub menu menuitem failed\n");
1491 memset( &info, 0, sizeof info );
1492 info.cbSize = sizeof info;
1493 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1494 info.fType = MFT_STRING;
1495 info.dwTypeData = menuitem2;
1496 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1498 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1499 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1501 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1502 memset( &info, 0, sizeof info );
1504 info.cbSize = sizeof(MENUITEMINFO);
1505 info.fMask = MIIM_STRING | MIIM_ID;
1506 info.dwTypeData = strback;
1507 info.cch = sizeof(strback);
1509 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1510 ok (rc, "Getting the menus info failed\n");
1511 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1512 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1514 memset( &info, 0, sizeof info );
1516 info.cbSize = sizeof(MENUITEMINFO);
1517 info.fMask = MIIM_STRING | MIIM_ID;
1518 info.dwTypeData = strback;
1519 info.cch = sizeof(strback);
1521 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1522 ok (rc, "Getting the menus info failed\n");
1523 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1524 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1526 DestroyMenu( hmenu );
1527 DestroyMenu( hmenuSub );
1528 DestroyMenu( hmenuSub2 );
1532 Case 5: Menu containing a popup menu which in turn
1533 contains an item with a different id than the popup menu.
1534 This tests the fallback to a popup menu ID.
1537 hmenu = CreateMenu();
1538 hmenuSub = CreateMenu();
1540 rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1541 ok (rc, "Appending the popup menu to the main menu failed\n");
1543 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1544 ok (rc, "Appending the item to the popup menu failed\n");
1546 /* Set the ID for hmenuSub */
1547 info.cbSize = sizeof(info);
1548 info.fMask = MIIM_ID;
1551 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1552 ok(rc, "Setting the ID for the popup menu failed\n");
1554 /* Check if the ID has been set */
1556 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1557 ok(rc, "Getting the ID for the popup menu failed\n");
1558 ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1560 /* Prove getting the item info via ID returns the popup menu */
1561 memset( &info, 0, sizeof(info));
1563 info.cbSize = sizeof(MENUITEMINFO);
1564 info.fMask = MIIM_STRING | MIIM_ID;
1565 info.dwTypeData = strback;
1566 info.cch = sizeof(strback);
1568 rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1569 ok (rc, "Getting the menu info failed\n");
1570 ok (info.wID == 101, "IDs differ\n");
1571 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1573 /* Also look for the menu item */
1574 memset( &info, 0, sizeof(info));
1576 info.cbSize = sizeof(MENUITEMINFO);
1577 info.fMask = MIIM_STRING | MIIM_ID;
1578 info.dwTypeData = strback;
1579 info.cch = sizeof(strback);
1581 rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1582 ok (rc, "Getting the menu info failed\n");
1583 ok (info.wID == 102, "IDs differ\n");
1584 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1587 DestroyMenu(hmenuSub);
1590 struct menu_item_pair_s {
1591 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1592 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1593 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1597 static struct menu_mouse_tests_s {
1599 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1600 WORD wVk[5]; /* keys */
1604 /* for each test, send keys or clicks and check for menu visibility */
1605 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1606 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1607 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1608 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1609 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1610 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1611 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1612 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1613 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1614 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1615 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1616 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1617 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1618 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1619 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1620 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1621 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1622 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1624 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1625 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1626 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1627 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1628 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1629 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1630 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1631 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1632 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1633 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1634 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1638 static void send_key(WORD wVk)
1641 memset(&i, 0, 2*sizeof(INPUT));
1642 i[0].type = i[1].type = INPUT_KEYBOARD;
1643 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1644 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1645 SendInput(2, (INPUT *) i, sizeof(INPUT));
1648 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1650 HMENU hMenu = hMenus[mi->uMenu];
1654 int screen_w = GetSystemMetrics(SM_CXSCREEN);
1655 int screen_h = GetSystemMetrics(SM_CYSCREEN);
1657 GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1659 memset(&i, 0, 3*sizeof(INPUT));
1660 i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1661 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1662 = ((r.left + 5) * 65535) / screen_w;
1663 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1664 = ((r.top + 5) * 65535) / screen_h;
1665 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1666 = MOUSEEVENTF_ABSOLUTE;
1667 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1668 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1669 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1670 SendInput(3, (INPUT *) i, sizeof(INPUT));
1672 /* hack to prevent mouse message buildup in Wine */
1673 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1676 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1679 HANDLE hWnd = lpParameter;
1682 /* mixed keyboard/mouse test */
1683 for (i = 0; menu_tests[i].type != -1; i++)
1687 if (menu_tests[i].type == INPUT_KEYBOARD)
1688 for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1689 send_key(menu_tests[i].wVk[j]);
1691 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1692 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1694 while (menu_tests[i].bMenuVisible != bMenuVisible)
1702 if (menu_tests[i]._todo_wine)
1705 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1709 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1714 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1718 case WM_ENTERMENULOOP:
1719 bMenuVisible = TRUE;
1721 case WM_EXITMENULOOP:
1722 bMenuVisible = FALSE;
1725 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1730 static void test_menu_input(void) {
1733 HINSTANCE hInstance = GetModuleHandleA( NULL );
1734 HANDLE hThread, hWnd;
1736 wclass.lpszClassName = "MenuTestClass";
1737 wclass.style = CS_HREDRAW | CS_VREDRAW;
1738 wclass.lpfnWndProc = WndProc;
1739 wclass.hInstance = hInstance;
1740 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1741 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1742 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1743 wclass.lpszMenuName = 0;
1744 wclass.cbClsExtra = 0;
1745 wclass.cbWndExtra = 0;
1746 assert (RegisterClassA( &wclass ));
1747 assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1748 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1749 400, 200, NULL, NULL, hInstance, NULL) );
1752 hMenus[3] = CreatePopupMenu();
1753 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1754 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1756 hMenus[2] = CreatePopupMenu();
1757 AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1758 AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1759 AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1761 hMenus[1] = CreateMenu();
1762 AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1763 AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1764 AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1766 SetMenu(hWnd, hMenus[1]);
1767 ShowWindow(hWnd, SW_SHOW);
1770 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1773 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1775 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1777 DestroyWindow(hWnd);
1780 void test_menu_flags( void )
1782 HMENU hMenu, hPopupMenu;
1784 hMenu = CreateMenu();
1785 hPopupMenu = CreatePopupMenu();
1787 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1789 AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1790 InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1791 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1792 ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1794 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1795 "AppendMenu should accept MF_HILITE\n");
1796 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1797 "InsertMenu should accept MF_HILITE\n");
1798 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1799 "ModifyMenu should accept MF_HILITE\n");
1801 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1802 "AppendMenu must not accept MF_DEFAULT\n");
1803 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1804 "InsertMenu must not accept MF_DEFAULT\n");
1805 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1806 "ModifyMenu must not accept MF_DEFAULT\n");
1811 void test_menu_hilitemenuitem( void )
1813 HMENU hMenu, hPopupMenu;
1815 hMenu = CreateMenu();
1816 hPopupMenu = CreatePopupMenu();
1818 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1820 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1821 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1822 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1824 HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
1825 HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
1826 HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
1827 HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
1831 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1832 "HiliteMenuItem: Item 1 is not hilited\n");
1834 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1835 "HiliteMenuItem: Item 2 is hilited\n");
1838 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1839 "HiliteMenuItem: Item 3 is not hilited\n");
1848 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1850 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1852 register_menu_check_class();
1854 test_menu_locked_by_window();
1855 test_menu_ownerdraw();
1856 test_menu_add_string();
1857 test_menu_iteminfo();
1858 test_menu_search_bycommand();
1859 test_menu_bmp_and_string();
1862 test_menu_hilitemenuitem();