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 )
534 WCHAR strbackW[0x80];
535 static CHAR blah[] = "blah";
536 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
538 hmenu = CreateMenu();
540 memset( &info, 0, sizeof info );
541 info.cbSize = sizeof info;
542 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
543 info.dwTypeData = blah;
548 InsertMenuItem(hmenu, 0, TRUE, &info );
550 memset( &info, 0, sizeof info );
551 info.cbSize = sizeof info;
552 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
553 info.dwTypeData = string;
554 info.cch = sizeof string;
556 GetMenuItemInfo( hmenu, 0, TRUE, &info );
558 ok( !strcmp( string, "blah" ), "menu item name differed\n");
560 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
561 strcpy(string, "Dummy string");
562 memset(&info, 0x00, sizeof(info));
563 info.cbSize= sizeof(MENUITEMINFO);
564 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
565 info.fType= MFT_OWNERDRAW;
566 info.dwTypeData= string;
567 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
568 ok (rc, "InsertMenuItem failed\n");
570 strcpy(string,"Garbage");
571 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
572 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
574 ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
575 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
577 /* Just change ftype to string and see what text is stored */
578 memset(&info, 0x00, sizeof(info));
579 info.cbSize= sizeof(MENUITEMINFO);
580 info.fMask= MIIM_FTYPE; /* Set string type */
581 info.fType= MFT_STRING;
582 info.dwTypeData= (char *)0xdeadbeef;
583 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
584 ok (rc, "SetMenuItemInfo failed\n");
586 /* Did we keep the old dwTypeData? */
587 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
588 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
590 /* Ensure change to bitmap type fails */
591 memset(&info, 0x00, sizeof(info));
592 info.cbSize= sizeof(MENUITEMINFO);
593 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
594 info.fType= MFT_BITMAP;
595 info.dwTypeData= (char *)0xdeadbee2;
596 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
597 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
599 /* Just change ftype back and ensure data hasn't been freed */
600 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
601 info.dwTypeData= (char *)0xdeadbee3;
602 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
603 ok (rc, "SetMenuItemInfo failed\n");
605 /* Did we keep the old dwTypeData? */
606 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
607 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
609 /* Just change string value (not type) */
610 memset(&info, 0x00, sizeof(info));
611 info.cbSize= sizeof(MENUITEMINFO);
612 info.fMask= MIIM_STRING; /* Set typeData */
613 strcpy(string2, "string2");
614 info.dwTypeData= string2;
615 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
616 ok (rc, "SetMenuItemInfo failed\n");
618 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
619 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
621 /* crashes with wine 0.9.5 */
622 memset(&info, 0x00, sizeof(info));
623 info.cbSize= sizeof(MENUITEMINFO);
624 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
625 info.fType= MFT_OWNERDRAW;
626 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
627 ok (rc, "InsertMenuItem failed\n");
628 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
629 "GetMenuString on ownerdraw entry succeeded.\n");
630 ok (!GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION),
631 "GetMenuStringW on ownerdraw entry succeeded.\n");
634 DestroyMenu( hmenu );
637 /* define building blocks for the menu item info tests */
638 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
640 if (n <= 0) return 0;
641 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
642 return *str1 - *str2;
645 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
648 while ((*p++ = *src++));
653 #define DMIINFF( i, e, field)\
654 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
655 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
657 #define DUMPMIINF(s,i,e)\
659 DMIINFF( i, e, fMask)\
660 DMIINFF( i, e, fType)\
661 DMIINFF( i, e, fState)\
663 DMIINFF( i, e, hSubMenu)\
664 DMIINFF( i, e, hbmpChecked)\
665 DMIINFF( i, e, hbmpUnchecked)\
666 DMIINFF( i, e, dwItemData)\
667 DMIINFF( i, e, dwTypeData)\
669 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
672 /* insert menu item */
673 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
676 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
677 HMENU hmenu = CreateMenu();\
678 BOOL ret, stop = FALSE;\
679 SetLastError( 0xdeadbeef);\
680 if(ansi)strcpy( string, init);\
681 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
682 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
683 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
684 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
686 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
689 /* GetMenuItemInfo + GetMenuString */
690 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
691 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
692 expname, eret2, eret3)\
694 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
695 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
696 MENUITEMINFOA *info2 = &info2A;\
697 MENUITEMINFOA *einfo = &einfoA;\
698 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
700 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
701 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
702 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
704 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
705 ret = memcmp( info2, einfo, sizeof einfoA);\
706 /* ok( ret==0, "Got wrong menu item info data\n");*/\
707 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
708 if( einfo->dwTypeData == string) {\
709 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
710 einfo->dwTypeData ? einfo->dwTypeData: "");\
711 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
712 einfo->dwTypeData ? einfo->dwTypeData: "");\
713 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
714 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
716 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
718 ok( !ret, "GetMenuString should have failed\n");\
725 RemoveMenu(hmenu, 0, TRUE );\
726 DestroyMenu( hmenu );\
727 DestroyMenu( submenu );\
728 submenu = CreateMenu();\
731 #define TMII_MODM( flags, id, data, eret )\
733 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
734 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
735 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
736 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
739 /* SetMenuItemInfo */
740 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
743 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
744 SetLastError( 0xdeadbeef);\
745 if(ansi)strcpy( string, init);\
746 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
747 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
748 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
749 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
751 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
760 static void test_menu_iteminfo( void )
762 int S=sizeof( MENUITEMINFOA);
767 WCHAR txtW[]={'W','i','n','e',0};
768 WCHAR initW[]={'X','Y','Z',0};
770 void *txt, *init, *empty, *string;
771 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
773 HMENU submenu=CreateMenu();
776 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
777 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
778 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
779 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
780 /* (since MFT_STRING is zero, there are four of them) */
781 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
782 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
783 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
786 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
787 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
788 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
791 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
792 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
793 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
796 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
797 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
798 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
801 /* not enough space for name*/
802 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
803 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
804 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
807 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
808 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
809 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
812 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
813 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
814 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
817 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
818 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
819 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
822 /* cannot combine MIIM_TYPE with some other flags */
823 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
824 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
825 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
828 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
829 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
830 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
833 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
834 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
835 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
838 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
839 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
840 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
843 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
844 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
845 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
848 /* but succeeds with some others */
849 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
850 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
851 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
854 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
855 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
856 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
859 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
860 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
861 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
864 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
865 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
866 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
869 /* to be continued */
870 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
871 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
872 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
873 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
876 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
877 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
878 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
879 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
882 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
883 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
884 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
887 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
888 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
889 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
892 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
893 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
894 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
897 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
898 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
899 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
900 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
903 /* same but retrieve with MIIM_TYPE */
904 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
905 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
906 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
909 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
910 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
911 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
914 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
915 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
916 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
920 /* How is that with bitmaps? */
921 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
922 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
923 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
926 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
927 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
928 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
931 /* MIIM_BITMAP does not like MFT_BITMAP */
932 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
933 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
934 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
937 /* no problem with OWNERDRAWN */
938 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
939 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
940 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
943 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
944 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
945 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
946 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
950 /* menu with submenu */
951 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
952 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
953 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
956 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
957 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
958 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
961 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
962 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
963 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
964 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
966 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
967 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
970 /* menu with invalid submenu */
971 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
972 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
973 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
977 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
978 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
979 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
982 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
983 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
984 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
987 /* SEPARATOR and STRING go well together */
988 /* BITMAP and STRING go well together */
989 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
990 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
991 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
994 /* BITMAP, SEPARATOR and STRING go well together */
995 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
996 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
997 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1000 /* last two tests, but use MIIM_TYPE to retrieve info */
1001 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1002 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1003 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1006 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1007 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1008 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1011 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1012 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1013 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1016 /* same three with MFT_OWNERDRAW */
1017 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1018 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1019 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1022 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1023 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1024 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1027 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1028 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1029 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1033 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1034 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1035 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1038 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1039 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1040 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1041 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1042 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1045 /* same with bitmap: now the text is cleared */
1046 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1047 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1048 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1049 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1052 /* start with bitmap: now setting text clears it (though he flag is raised) */
1053 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1054 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1055 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1057 TMII_MODM( MFT_STRING, 545, txt, OK)
1058 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1059 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1062 /*repeat with text NULL */
1063 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1064 TMII_MODM( MFT_STRING, 545, NULL, OK)
1065 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1066 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1069 /* repeat with text "" */
1070 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1071 TMII_MODM( MFT_STRING, 545, empty, OK)
1072 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1073 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1076 /* start with bitmap: set ownerdraw */
1077 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1078 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1079 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1080 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1084 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1085 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1086 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1089 /* some tests with small cbSize: the hbmpItem is to be ignored */
1090 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1091 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1092 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1095 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1096 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1097 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1100 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1101 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1102 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1105 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1106 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1107 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1110 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1111 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1112 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1115 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1116 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1117 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1120 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1121 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1122 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1123 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1126 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1127 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1128 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1131 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1132 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1133 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1136 /* set a string menu to ownerdraw with MIIM_TYPE */
1137 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1138 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1139 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1140 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1143 /* test with modifymenu add submenu */
1144 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1145 TMII_MODM( MF_POPUP, submenu, txt, OK)
1146 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1147 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1149 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1150 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1153 /* MFT_SEPARATOR bit is kept when the text is added */
1154 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1155 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1156 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1157 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1160 /* MFT_SEPARATOR bit is kept when bitmap is added */
1161 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1162 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1163 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1164 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1167 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1168 Only the low word of the dwTypeData is used.
1169 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1170 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1171 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1172 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1176 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)
1177 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1178 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1182 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1183 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1184 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1185 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1188 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1189 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1190 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1191 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1192 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1195 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1196 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1197 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1198 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1199 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1201 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1202 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1204 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1205 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1207 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1208 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1209 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1212 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1213 Only the low word of the dwTypeData is used.
1214 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1215 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1216 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1217 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1221 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)
1222 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1223 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1227 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1228 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1229 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1230 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1233 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1234 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1235 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1236 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1237 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1240 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1241 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1242 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1243 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1244 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1246 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1247 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1249 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1250 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1252 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1253 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1254 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1257 } while( !(ansi = !ansi) );
1262 The following tests try to confirm the algorithm used to return the menu items
1263 when there is a collision between a menu item and a popup menu
1265 static void test_menu_search_bycommand( void )
1267 HMENU hmenu, hmenuSub, hmenuSub2;
1273 static CHAR menuitem[] = "MenuItem",
1274 menuitem2[] = "MenuItem 2";
1276 /* Case 1: Menu containing a menu item */
1277 hmenu = CreateMenu();
1279 memset( &info, 0, sizeof info );
1280 info.cbSize = sizeof info;
1281 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1282 info.fType = MFT_STRING;
1283 strcpy(strIn, "Case 1 MenuItem");
1284 info.dwTypeData = strIn;
1285 info.wID = (UINT) 0x1234;
1287 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1288 ok (rc, "Inserting the menuitem failed\n");
1290 id = GetMenuItemID(hmenu, 0);
1291 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1293 /* Confirm the menuitem was given the id supplied (getting by position) */
1294 memset( &info, 0, sizeof info );
1296 info.cbSize = sizeof(MENUITEMINFO);
1297 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1298 info.dwTypeData = strback;
1299 info.cch = sizeof(strback);
1301 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1302 ok (rc, "Getting the menu items info failed\n");
1303 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1304 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1306 /* Search by id - Should return the item */
1307 memset( &info, 0, sizeof info );
1309 info.cbSize = sizeof(MENUITEMINFO);
1310 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1311 info.dwTypeData = strback;
1312 info.cch = sizeof(strback);
1313 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1315 ok (rc, "Getting the menu items info failed\n");
1316 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1317 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1319 DestroyMenu( hmenu );
1321 /* Case 2: Menu containing a popup menu */
1322 hmenu = CreateMenu();
1323 hmenuSub = CreateMenu();
1325 strcpy(strIn, "Case 2 SubMenu");
1326 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1327 ok (rc, "Inserting the popup menu into the main menu failed\n");
1329 id = GetMenuItemID(hmenu, 0);
1330 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1332 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1333 memset( &info, 0, sizeof info );
1335 info.cbSize = sizeof(MENUITEMINFO);
1336 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1337 info.dwTypeData = strback;
1338 info.cch = sizeof(strback);
1339 info.wID = 0xdeadbeef;
1341 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1342 ok (rc, "Getting the menu items info failed\n");
1343 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1344 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1346 /* Search by id - returns the popup menu itself */
1347 memset( &info, 0, sizeof info );
1349 info.cbSize = sizeof(MENUITEMINFO);
1350 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1351 info.dwTypeData = strback;
1352 info.cch = sizeof(strback);
1353 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1355 ok (rc, "Getting the menu items info failed\n");
1356 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1357 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1360 Now add an item after it with the same id
1362 memset( &info, 0, sizeof info );
1363 info.cbSize = sizeof info;
1364 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1365 info.fType = MFT_STRING;
1366 strcpy(strIn, "Case 2 MenuItem 1");
1367 info.dwTypeData = strIn;
1368 info.wID = (UINT_PTR) hmenuSub;
1369 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1370 ok (rc, "Inserting the menuitem failed\n");
1372 /* Search by id - returns the item which follows the popup menu */
1373 memset( &info, 0, sizeof info );
1375 info.cbSize = sizeof(MENUITEMINFO);
1376 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1377 info.dwTypeData = strback;
1378 info.cch = sizeof(strback);
1379 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1381 ok (rc, "Getting the menu items info failed\n");
1382 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1383 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1386 Now add an item before the popup (with the same id)
1388 memset( &info, 0, sizeof info );
1389 info.cbSize = sizeof info;
1390 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1391 info.fType = MFT_STRING;
1392 strcpy(strIn, "Case 2 MenuItem 2");
1393 info.dwTypeData = strIn;
1394 info.wID = (UINT_PTR) hmenuSub;
1395 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1396 ok (rc, "Inserting the menuitem failed\n");
1398 /* Search by id - returns the item which precedes the popup menu */
1399 memset( &info, 0, sizeof info );
1401 info.cbSize = sizeof(MENUITEMINFO);
1402 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1403 info.dwTypeData = strback;
1404 info.cch = sizeof(strback);
1405 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1407 ok (rc, "Getting the menu items info failed\n");
1408 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1409 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1411 DestroyMenu( hmenu );
1412 DestroyMenu( hmenuSub );
1415 Case 3: Menu containing a popup menu which in turn
1416 contains 2 items with the same id as the popup itself
1419 hmenu = CreateMenu();
1420 hmenuSub = CreateMenu();
1422 memset( &info, 0, sizeof info );
1423 info.cbSize = sizeof info;
1424 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1425 info.fType = MFT_STRING;
1426 info.dwTypeData = menuitem;
1427 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1429 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1430 ok (rc, "Inserting the popup menu into the main menu failed\n");
1432 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1433 ok (rc, "Inserting the sub menu menuitem failed\n");
1435 memset( &info, 0, sizeof info );
1436 info.cbSize = sizeof info;
1437 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1438 info.fType = MFT_STRING;
1439 info.dwTypeData = menuitem2;
1440 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1442 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1443 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1445 /* Prove that you can't query the id of a popup directly (By position) */
1446 id = GetMenuItemID(hmenu, 0);
1447 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1449 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1450 memset( &info, 0, sizeof info );
1452 info.cbSize = sizeof(MENUITEMINFO);
1453 info.fMask = MIIM_STRING | MIIM_ID;
1454 info.dwTypeData = strback;
1455 info.cch = sizeof(strback);
1457 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1458 ok (rc, "Getting the menus info failed\n");
1459 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1460 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1461 DestroyMenu( hmenu );
1462 DestroyMenu( hmenuSub );
1465 Case 4: Menu containing 2 popup menus, the second
1466 contains 2 items with the same id as the first popup menu
1468 hmenu = CreateMenu();
1469 hmenuSub = CreateMenu();
1470 hmenuSub2 = CreateMenu();
1472 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1473 ok (rc, "Inserting the popup menu into the main menu failed\n");
1475 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1476 ok (rc, "Inserting the popup menu into the main menu failed\n");
1478 memset( &info, 0, sizeof info );
1479 info.cbSize = sizeof info;
1480 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1481 info.fType = MFT_STRING;
1482 info.dwTypeData = menuitem;
1483 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1485 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1486 ok (rc, "Inserting the sub menu menuitem failed\n");
1488 memset( &info, 0, sizeof info );
1489 info.cbSize = sizeof info;
1490 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1491 info.fType = MFT_STRING;
1492 info.dwTypeData = menuitem2;
1493 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1495 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1496 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1498 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1499 memset( &info, 0, sizeof info );
1501 info.cbSize = sizeof(MENUITEMINFO);
1502 info.fMask = MIIM_STRING | MIIM_ID;
1503 info.dwTypeData = strback;
1504 info.cch = sizeof(strback);
1506 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1507 ok (rc, "Getting the menus info failed\n");
1508 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1509 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1511 memset( &info, 0, sizeof info );
1513 info.cbSize = sizeof(MENUITEMINFO);
1514 info.fMask = MIIM_STRING | MIIM_ID;
1515 info.dwTypeData = strback;
1516 info.cch = sizeof(strback);
1518 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1519 ok (rc, "Getting the menus info failed\n");
1520 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1521 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1523 DestroyMenu( hmenu );
1524 DestroyMenu( hmenuSub );
1525 DestroyMenu( hmenuSub2 );
1529 Case 5: Menu containing a popup menu which in turn
1530 contains an item with a different id than the popup menu.
1531 This tests the fallback to a popup menu ID.
1534 hmenu = CreateMenu();
1535 hmenuSub = CreateMenu();
1537 rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1538 ok (rc, "Appending the popup menu to the main menu failed\n");
1540 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1541 ok (rc, "Appending the item to the popup menu failed\n");
1543 /* Set the ID for hmenuSub */
1544 info.cbSize = sizeof(info);
1545 info.fMask = MIIM_ID;
1548 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1549 ok(rc, "Setting the ID for the popup menu failed\n");
1551 /* Check if the ID has been set */
1553 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1554 ok(rc, "Getting the ID for the popup menu failed\n");
1555 ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1557 /* Prove getting the item info via ID returns the popup menu */
1558 memset( &info, 0, sizeof(info));
1560 info.cbSize = sizeof(MENUITEMINFO);
1561 info.fMask = MIIM_STRING | MIIM_ID;
1562 info.dwTypeData = strback;
1563 info.cch = sizeof(strback);
1565 rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1566 ok (rc, "Getting the menu info failed\n");
1567 ok (info.wID == 101, "IDs differ\n");
1568 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1570 /* Also look for the menu item */
1571 memset( &info, 0, sizeof(info));
1573 info.cbSize = sizeof(MENUITEMINFO);
1574 info.fMask = MIIM_STRING | MIIM_ID;
1575 info.dwTypeData = strback;
1576 info.cch = sizeof(strback);
1578 rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1579 ok (rc, "Getting the menu info failed\n");
1580 ok (info.wID == 102, "IDs differ\n");
1581 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1584 DestroyMenu(hmenuSub);
1587 struct menu_item_pair_s {
1588 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1589 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1590 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1594 static struct menu_mouse_tests_s {
1596 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1597 WORD wVk[5]; /* keys */
1601 /* for each test, send keys or clicks and check for menu visibility */
1602 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1603 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1604 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1605 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1606 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1607 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1608 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1609 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1610 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1611 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1612 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1613 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1614 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1615 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1616 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1617 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1618 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1619 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1621 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1622 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1623 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1624 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1625 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1626 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1627 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1628 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1629 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1630 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1631 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1635 static void send_key(WORD wVk)
1638 memset(&i, 0, 2*sizeof(INPUT));
1639 i[0].type = i[1].type = INPUT_KEYBOARD;
1640 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1641 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1642 SendInput(2, (INPUT *) i, sizeof(INPUT));
1645 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1647 HMENU hMenu = hMenus[mi->uMenu];
1651 int screen_w = GetSystemMetrics(SM_CXSCREEN);
1652 int screen_h = GetSystemMetrics(SM_CYSCREEN);
1654 GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1656 memset(&i, 0, 3*sizeof(INPUT));
1657 i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1658 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1659 = ((r.left + 5) * 65535) / screen_w;
1660 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1661 = ((r.top + 5) * 65535) / screen_h;
1662 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1663 = MOUSEEVENTF_ABSOLUTE;
1664 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1665 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1666 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1667 SendInput(3, (INPUT *) i, sizeof(INPUT));
1669 /* hack to prevent mouse message buildup in Wine */
1670 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1673 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1676 HANDLE hWnd = lpParameter;
1679 /* mixed keyboard/mouse test */
1680 for (i = 0; menu_tests[i].type != -1; i++)
1684 if (menu_tests[i].type == INPUT_KEYBOARD)
1685 for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1686 send_key(menu_tests[i].wVk[j]);
1688 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1689 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1691 while (menu_tests[i].bMenuVisible != bMenuVisible)
1699 if (menu_tests[i]._todo_wine)
1702 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1706 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1711 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1715 case WM_ENTERMENULOOP:
1716 bMenuVisible = TRUE;
1718 case WM_EXITMENULOOP:
1719 bMenuVisible = FALSE;
1722 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1727 static void test_menu_input(void) {
1730 HINSTANCE hInstance = GetModuleHandleA( NULL );
1731 HANDLE hThread, hWnd;
1733 wclass.lpszClassName = "MenuTestClass";
1734 wclass.style = CS_HREDRAW | CS_VREDRAW;
1735 wclass.lpfnWndProc = WndProc;
1736 wclass.hInstance = hInstance;
1737 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1738 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1739 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1740 wclass.lpszMenuName = 0;
1741 wclass.cbClsExtra = 0;
1742 wclass.cbWndExtra = 0;
1743 assert (RegisterClassA( &wclass ));
1744 assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1745 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1746 400, 200, NULL, NULL, hInstance, NULL) );
1749 hMenus[3] = CreatePopupMenu();
1750 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1751 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1753 hMenus[2] = CreatePopupMenu();
1754 AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1755 AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1756 AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1758 hMenus[1] = CreateMenu();
1759 AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1760 AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1761 AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1763 SetMenu(hWnd, hMenus[1]);
1764 ShowWindow(hWnd, SW_SHOW);
1767 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1770 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1772 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1774 DestroyWindow(hWnd);
1777 static void test_menu_flags( void )
1779 HMENU hMenu, hPopupMenu;
1781 hMenu = CreateMenu();
1782 hPopupMenu = CreatePopupMenu();
1784 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1786 AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1787 InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1788 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1789 ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1791 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1792 "AppendMenu should accept MF_HILITE\n");
1793 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1794 "InsertMenu should accept MF_HILITE\n");
1795 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1796 "ModifyMenu should accept MF_HILITE\n");
1798 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1799 "AppendMenu must not accept MF_DEFAULT\n");
1800 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1801 "InsertMenu must not accept MF_DEFAULT\n");
1802 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1803 "ModifyMenu must not accept MF_DEFAULT\n");
1808 static void test_menu_hilitemenuitem( void )
1810 HMENU hMenu, hPopupMenu;
1812 hMenu = CreateMenu();
1813 hPopupMenu = CreatePopupMenu();
1815 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1817 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1818 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1819 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1821 HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
1822 HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
1823 HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
1824 HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
1828 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1829 "HiliteMenuItem: Item 1 is not hilited\n");
1831 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1832 "HiliteMenuItem: Item 2 is hilited\n");
1835 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1836 "HiliteMenuItem: Item 3 is not hilited\n");
1845 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1847 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1849 register_menu_check_class();
1851 test_menu_locked_by_window();
1852 test_menu_ownerdraw();
1853 test_menu_add_string();
1854 test_menu_iteminfo();
1855 test_menu_search_bycommand();
1856 test_menu_bmp_and_string();
1859 test_menu_hilitemenuitem();