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
35 #include "wine/test.h"
37 static ATOM atomMenuCheckClass;
39 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
40 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
42 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
46 case WM_ENTERMENULOOP:
47 /* mark window as having entered menu loop */
48 SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
49 /* exit menu modal loop
50 * ( A SendMessage does not work on NT3.51 here ) */
51 return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
53 return DefWindowProc(hwnd, msg, wparam, lparam);
56 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
69 /* globals to communicate between test and wndproc */
71 static BOOL bMenuVisible;
72 static HMENU hMenus[4];
77 /* menu texts with their sizes */
80 SIZE size; /* size of text up to any \t */
81 SIZE sc_size; /* size of the short-cut */
90 unsigned int MOD_maxid;
91 RECT MOD_rc[MOD_NRMENUS];
92 int MOD_avec, MOD_hic;
94 SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
95 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
96 int MOD_GotDrawItemMsg = FALSE;
97 /* wndproc used by test_menu_ownerdraw() */
98 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
99 WPARAM wparam, LPARAM lparam)
105 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
107 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
108 pmis->itemData, pmis->itemWidth, pmis->itemHeight);
109 MOD_odheight = pmis->itemHeight;
110 pmis->itemWidth = MODsizes[pmis->itemData].cx;
111 pmis->itemHeight = MODsizes[pmis->itemData].cy;
116 DRAWITEMSTRUCT * pdis;
119 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
122 pdis = (DRAWITEMSTRUCT *) lparam;
123 if( winetest_debug) {
125 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
126 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
127 hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
128 pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
129 pdis->rcItem.right,pdis->rcItem.bottom,
130 rc.left,rc.top,rc.right,rc.bottom);
131 oldpen=SelectObject( pdis->hDC, GetStockObject(
132 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
133 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
134 pdis->rcItem.right,pdis->rcItem.bottom );
135 SelectObject( pdis->hDC, oldpen);
137 /* calculate widths of some menu texts */
138 if( ! MOD_txtsizes[0].size.cx)
139 for(i = 0; MOD_txtsizes[i].text; i++) {
142 strcpy( buf, MOD_txtsizes[i].text);
143 if( ( p = strchr( buf, '\t'))) {
145 DrawText( pdis->hDC, p + 1, -1, &rc,
146 DT_SINGLELINE|DT_CALCRECT);
147 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
148 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
150 DrawText( pdis->hDC, buf, -1, &rc,
151 DT_SINGLELINE|DT_CALCRECT);
152 MOD_txtsizes[i].size.cx= rc.right - rc.left;
153 MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
156 if( pdis->itemData > MOD_maxid) return TRUE;
157 /* store the rectangl */
158 MOD_rc[pdis->itemData] = pdis->rcItem;
159 /* calculate average character width */
160 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
161 MOD_avec = (sz.cx + 26)/52;
162 GetTextMetrics( pdis->hDC, &tm);
163 MOD_hic = tm.tmHeight;
164 MOD_GotDrawItemMsg = TRUE;
169 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
174 return DefWindowProc(hwnd, msg, wparam, lparam);
177 static void register_menu_check_class(void)
185 GetModuleHandle(NULL),
187 LoadCursor(NULL, IDC_ARROW),
188 (HBRUSH)(COLOR_BTNFACE+1),
190 TEXT("WineMenuCheck"),
193 atomMenuCheckClass = RegisterClass(&wc);
196 /* demonstrates that windows locks the menu object so that it is still valid
197 * even after a client calls DestroyMenu on it */
198 static void test_menu_locked_by_window(void)
202 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
203 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
204 NULL, NULL, NULL, NULL);
205 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
206 hmenu = CreateMenu();
207 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
208 ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
209 ok(ret, "InsertMenu failed with error %d\n", GetLastError());
210 ret = SetMenu(hwnd, hmenu);
211 ok(ret, "SetMenu failed with error %d\n", GetLastError());
212 ret = DestroyMenu(hmenu);
213 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
215 ret = DrawMenuBar(hwnd);
217 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
219 ret = IsMenu(GetMenu(hwnd));
220 ok(!ret, "Menu handle should have been destroyed\n");
222 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
223 /* did we process the WM_INITMENU message? */
224 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
226 ok(ret, "WM_INITMENU should have been sent\n");
232 static void test_menu_ownerdraw(void)
238 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
239 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
240 NULL, NULL, NULL, NULL);
241 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
243 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
244 hmenu = CreatePopupMenu();
245 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
246 if( !hmenu) { DestroyWindow(hwnd);return;}
248 for( j=0;j<2;j++) /* create columns */
249 for(i=0;i<2;i++) { /* create rows */
250 ret = AppendMenu( hmenu, MF_OWNERDRAW |
251 (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
253 ok( ret, "AppendMenu failed for %d\n", k-1);
256 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
257 /* display the menu */
258 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
260 /* columns have a 4 pixel gap between them */
261 ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
262 "item rectangles are not separated by 4 pixels space\n");
263 /* height should be what the MEASUREITEM message has returned */
264 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
265 "menu item has wrong height: %d should be %d\n",
266 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
267 /* no gaps between the rows */
268 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
269 "There should not be a space between the rows, gap is %d\n",
270 MOD_rc[0].bottom - MOD_rc[1].top);
271 /* test the correct value of the item height that was sent
272 * by the WM_MEASUREITEM message */
273 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
274 MOD_odheight == MOD_hic, /* Win95,98,ME */
275 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
276 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
277 /* test what MF_MENUBREAK did at the first position. Also show
278 * that an MF_SEPARATOR is ignored in the height calculation. */
279 leftcol= MOD_rc[0].left;
280 ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
281 /* display the menu */
282 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
283 /* left should be 4 pixels less now */
284 ok( leftcol == MOD_rc[0].left + 4,
285 "columns should be 4 pixels to the left (actual %d).\n",
286 leftcol - MOD_rc[0].left);
288 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
289 "width of owner drawn menu item is wrong. Got %d expected %d\n",
290 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
292 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
293 "Height is incorrect. Got %d expected %d\n",
294 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
296 /* test width/height of an ownerdraw menu bar as well */
297 ret = DestroyMenu(hmenu);
298 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
299 hmenu = CreateMenu();
300 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
301 if( !hmenu) { DestroyWindow(hwnd);return;}
304 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
305 ok( ret, "AppendMenu failed for %d\n", i);
307 ret = SetMenu( hwnd, hmenu);
308 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
309 ok(ret, "SetMenu failed with error %d\n", GetLastError());
311 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
312 "width of owner drawn menu item is wrong. Got %d expected %d\n",
313 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
315 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
316 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
317 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
320 ret = DestroyMenu(hmenu);
321 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
325 /* helper for test_menu_bmp_and_string() */
326 static void test_mbs_help( int ispop, int hassub, int mnuopt,
327 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
328 SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
331 HMENU hmenu, submenu;
332 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
339 MOD_GotDrawItemMsg = FALSE;
340 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
342 mii.fState = MF_CHECKED;
344 MODsizes[0] = bmpsize;
348 mii.fMask |= MIIM_STRING;
349 strcpy(text_copy, text);
350 mii.dwTypeData = text_copy; /* structure member declared non-const */
351 if( ( p = strchr( text, '\t'))) {
352 hastab = *(p + 1) ? 2 : 1;
355 /* tabs don't make sense in menubars */
356 if(hastab && !ispop) return;
358 mii.fMask |= MIIM_BITMAP;
361 submenu = CreateMenu();
362 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
364 hmenu = CreatePopupMenu();
366 hmenu = CreateMenu();
367 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
369 mii.fMask |= MIIM_SUBMENU;
370 mii.hSubMenu = submenu;
373 mi.cbSize = sizeof(mi);
374 mi.fMask = MIM_STYLE;
375 pGetMenuInfo( hmenu, &mi);
376 mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
377 ret = pSetMenuInfo( hmenu, &mi);
378 ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
380 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
381 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
383 if( winetest_debug) {
385 RECT rc = {100, 50, 400, 70};
388 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
389 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
390 TextOut( hdc, 100, 50, buf, strlen( buf));
391 ReleaseDC( hwnd, hdc);
394 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
396 ret = SetMenu( hwnd, hmenu);
397 ok(ret, "SetMenu failed with error %d\n", GetLastError());
400 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
401 /* check menu width */
403 expect = ( text || hbmp ?
404 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
406 arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
407 (text && hastab ? /* TAB space */
408 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
409 (text ? 2 + (text[0] ? size.cx :0): 0) ;
411 expect = !(text || hbmp) ? 0 :
412 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) +
413 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
414 ok( rc.right - rc.left == expect,
415 "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
416 failed = failed || !(rc.right - rc.left == expect);
417 /* check menu height */
419 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
420 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
421 (hbmp ? bmpsize.cy + 2 : 0)));
423 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
424 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
425 ok( rc.bottom - rc.top == expect,
426 "menu height wrong, got %d expected %d (%d)\n",
427 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
428 failed = failed || !(rc.bottom - rc.top == expect);
429 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
430 /* check the position of the bitmap */
432 expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
434 ok( expect == MOD_rc[0].left,
435 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
436 failed = failed || !(expect == MOD_rc[0].left);
438 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
439 ok( expect == MOD_rc[0].top,
440 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
441 failed = failed || !(expect == MOD_rc[0].top);
443 /* if there was a failure, report details */
445 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
446 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
447 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
448 trace(" check %d,%d arrow %d avechar %d\n",
449 GetSystemMetrics(SM_CXMENUCHECK ),
450 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
451 if( hbmp == HBMMENU_CALLBACK)
452 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
453 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
454 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
457 ret = DestroyMenu(submenu);
458 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
459 ret = DestroyMenu(hmenu);
460 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
464 static void test_menu_bmp_and_string(void)
471 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
473 if( !pGetMenuInfo) return;
475 memset( bmfill, 0x55, sizeof( bmfill));
476 hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
477 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
478 NULL, NULL, NULL, NULL);
479 hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
480 GetObject( hbm_arrow, sizeof(bm), &bm);
481 arrowwidth = bm.bmWidth;
483 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
485 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
488 trace(" check %d,%d arrow %d avechar %d\n",
489 GetSystemMetrics(SM_CXMENUCHECK ),
490 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
493 for( ispop=1; ispop >= 0; ispop--){
494 static SIZE bmsizes[]= {
495 {10,10},{38,38},{1,30},{55,5}};
496 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
497 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
498 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL };
499 ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError());
500 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
501 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
502 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
503 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
504 /* no need to test NULL bitmaps of several sizes */
505 if( !bitmaps[bmpidx] && szidx > 0) continue;
506 if( !ispop && hassub) continue;
507 test_mbs_help( ispop, hassub, mnuopt,
508 hwnd, arrowwidth, ++count,
511 MOD_txtsizes[txtidx].text,
512 MOD_txtsizes[txtidx].size,
513 MOD_txtsizes[txtidx].sc_size);
525 static void test_menu_add_string( void )
535 WCHAR strbackW[0x80];
536 static CHAR blah[] = "blah";
537 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
539 hmenu = CreateMenu();
541 memset( &info, 0, sizeof info );
542 info.cbSize = sizeof info;
543 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
544 info.dwTypeData = blah;
549 InsertMenuItem(hmenu, 0, TRUE, &info );
551 memset( &info, 0, sizeof info );
552 info.cbSize = sizeof info;
553 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
554 info.dwTypeData = string;
555 info.cch = sizeof string;
557 GetMenuItemInfo( hmenu, 0, TRUE, &info );
559 ok( !strcmp( string, "blah" ), "menu item name differed\n");
561 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
562 strcpy(string, "Dummy string");
563 memset(&info, 0x00, sizeof(info));
564 info.cbSize= sizeof(MENUITEMINFO);
565 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
566 info.fType= MFT_OWNERDRAW;
567 info.dwTypeData= string;
568 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
569 ok (rc, "InsertMenuItem failed\n");
571 strcpy(string,"Garbage");
572 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
573 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
575 ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
576 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
578 /* Just change ftype to string and see what text is stored */
579 memset(&info, 0x00, sizeof(info));
580 info.cbSize= sizeof(MENUITEMINFO);
581 info.fMask= MIIM_FTYPE; /* Set string type */
582 info.fType= MFT_STRING;
583 info.dwTypeData= (char *)0xdeadbeef;
584 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
585 ok (rc, "SetMenuItemInfo failed\n");
587 /* Did we keep the old dwTypeData? */
588 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
589 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
591 /* Ensure change to bitmap type fails */
592 memset(&info, 0x00, sizeof(info));
593 info.cbSize= sizeof(MENUITEMINFO);
594 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
595 info.fType= MFT_BITMAP;
596 info.dwTypeData= (char *)0xdeadbee2;
597 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
598 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
600 /* Just change ftype back and ensure data hasn't been freed */
601 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
602 info.dwTypeData= (char *)0xdeadbee3;
603 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
604 ok (rc, "SetMenuItemInfo failed\n");
606 /* Did we keep the old dwTypeData? */
607 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
608 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
610 /* Just change string value (not type) */
611 memset(&info, 0x00, sizeof(info));
612 info.cbSize= sizeof(MENUITEMINFO);
613 info.fMask= MIIM_STRING; /* Set typeData */
614 strcpy(string2, "string2");
615 info.dwTypeData= string2;
616 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
617 ok (rc, "SetMenuItemInfo failed\n");
619 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
620 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
622 /* crashes with wine 0.9.5 */
623 memset(&info, 0x00, sizeof(info));
624 info.cbSize= sizeof(MENUITEMINFO);
625 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
626 info.fType= MFT_OWNERDRAW;
627 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
628 ok (rc, "InsertMenuItem failed\n");
629 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
630 "GetMenuString on ownerdraw entry succeeded.\n");
631 ok (!GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION),
632 "GetMenuStringW on ownerdraw entry succeeded.\n");
635 DestroyMenu( hmenu );
638 /* define building blocks for the menu item info tests */
639 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
641 if (n <= 0) return 0;
642 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
643 return *str1 - *str2;
646 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
649 while ((*p++ = *src++));
654 #define DMIINFF( i, e, field)\
655 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
656 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
658 #define DUMPMIINF(s,i,e)\
660 DMIINFF( i, e, fMask)\
661 DMIINFF( i, e, fType)\
662 DMIINFF( i, e, fState)\
664 DMIINFF( i, e, hSubMenu)\
665 DMIINFF( i, e, hbmpChecked)\
666 DMIINFF( i, e, hbmpUnchecked)\
667 DMIINFF( i, e, dwItemData)\
668 DMIINFF( i, e, dwTypeData)\
670 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
673 /* insert menu item */
674 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
677 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
678 HMENU hmenu = CreateMenu();\
679 BOOL ret, stop = FALSE;\
680 SetLastError( 0xdeadbeef);\
681 if(ansi)strcpy( string, init);\
682 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
683 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
684 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
685 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
687 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
690 /* GetMenuItemInfo + GetMenuString */
691 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
692 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
693 expname, eret2, eret3)\
695 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
696 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
697 MENUITEMINFOA *info2 = &info2A;\
698 MENUITEMINFOA *einfo = &einfoA;\
699 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
701 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
702 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
703 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
705 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
706 ret = memcmp( info2, einfo, sizeof einfoA);\
707 /* ok( ret==0, "Got wrong menu item info data\n");*/\
708 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
709 if( einfo->dwTypeData == string) {\
710 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
711 einfo->dwTypeData ? einfo->dwTypeData: "");\
712 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
713 einfo->dwTypeData ? einfo->dwTypeData: "");\
714 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
715 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
717 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
719 ok( !ret, "GetMenuString should have failed\n");\
726 RemoveMenu(hmenu, 0, TRUE );\
727 DestroyMenu( hmenu );\
728 DestroyMenu( submenu );\
729 submenu = CreateMenu();\
732 #define TMII_MODM( flags, id, data, eret )\
734 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
735 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
736 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
737 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
740 /* SetMenuItemInfo */
741 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
744 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
745 SetLastError( 0xdeadbeef);\
746 if(ansi)strcpy( string, init);\
747 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
748 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
749 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
750 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
752 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
761 static void test_menu_iteminfo( void )
763 int S=sizeof( MENUITEMINFOA);
768 WCHAR txtW[]={'W','i','n','e',0};
769 WCHAR initW[]={'X','Y','Z',0};
771 void *txt, *init, *empty, *string;
772 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
774 HMENU submenu=CreateMenu();
777 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
778 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
779 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
780 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
781 /* (since MFT_STRING is zero, there are four of them) */
782 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
783 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
784 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
787 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
788 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
789 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
792 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
793 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
794 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
797 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
798 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
799 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
802 /* not enough space for name*/
803 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
804 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
805 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
808 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
809 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
810 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
813 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
814 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
815 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
818 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
819 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
820 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
823 /* cannot combine MIIM_TYPE with some other flags */
824 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
825 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
826 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
829 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
830 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
831 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
834 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
835 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
836 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
839 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
840 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
841 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
844 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
845 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
846 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
849 /* but succeeds with some others */
850 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
851 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
852 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
855 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
856 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
857 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
860 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
861 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
862 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
865 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
866 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
867 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
870 /* to be continued */
871 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
872 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
873 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
874 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
877 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
878 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
879 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
880 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
883 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
884 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
885 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
888 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
889 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
890 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
893 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
894 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
895 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
898 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
899 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
900 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
901 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
904 /* same but retrieve with MIIM_TYPE */
905 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
906 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
907 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
910 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
911 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
912 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
915 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
916 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
917 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
921 /* How is that with bitmaps? */
922 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
923 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
924 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
927 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
928 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
929 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
932 /* MIIM_BITMAP does not like MFT_BITMAP */
933 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
934 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
935 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
938 /* no problem with OWNERDRAWN */
939 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
940 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
941 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
944 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
945 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
946 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
947 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
951 /* menu with submenu */
952 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
953 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
954 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
957 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
958 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
959 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
962 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
963 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
964 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
965 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
967 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
968 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
971 /* menu with invalid submenu */
972 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
973 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
974 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
978 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
979 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
980 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
983 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
984 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
985 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
988 /* SEPARATOR and STRING go well together */
989 /* BITMAP and STRING go well together */
990 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
991 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
992 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
995 /* BITMAP, SEPARATOR and STRING go well together */
996 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
997 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
998 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1001 /* last two tests, but use MIIM_TYPE to retrieve info */
1002 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1003 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1004 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1007 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1008 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1009 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1012 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1013 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1014 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1017 /* same three with MFT_OWNERDRAW */
1018 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1019 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1020 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1023 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1024 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1025 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1028 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1029 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1030 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1034 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1035 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1036 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1039 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1040 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1041 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1042 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1043 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1046 /* same with bitmap: now the text is cleared */
1047 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1048 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1049 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1050 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1053 /* start with bitmap: now setting text clears it (though he flag is raised) */
1054 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1055 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1056 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1058 TMII_MODM( MFT_STRING, 545, txt, OK)
1059 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1060 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1063 /*repeat with text NULL */
1064 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1065 TMII_MODM( MFT_STRING, 545, NULL, OK)
1066 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1067 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1070 /* repeat with text "" */
1071 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1072 TMII_MODM( MFT_STRING, 545, empty, OK)
1073 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1074 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1077 /* start with bitmap: set ownerdraw */
1078 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1079 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1080 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1081 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1085 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1086 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1087 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1090 /* some tests with small cbSize: the hbmpItem is to be ignored */
1091 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1092 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1093 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1096 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1097 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1098 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1101 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1102 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1103 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1106 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1107 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1108 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1111 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1112 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1113 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1116 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1117 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1118 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1121 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1122 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1123 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1124 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1127 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1128 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1129 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1132 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1133 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1134 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1137 /* set a string menu to ownerdraw with MIIM_TYPE */
1138 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1139 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1140 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1141 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1144 /* test with modifymenu add submenu */
1145 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1146 TMII_MODM( MF_POPUP, submenu, txt, OK)
1147 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1148 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1150 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1151 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1154 /* MFT_SEPARATOR bit is kept when the text is added */
1155 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1156 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1157 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1158 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1161 /* MFT_SEPARATOR bit is kept when bitmap is added */
1162 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1163 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1164 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1165 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1168 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1169 Only the low word of the dwTypeData is used.
1170 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1171 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1172 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1173 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1177 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)
1178 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1179 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1183 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1184 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1185 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1186 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1189 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1190 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1191 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1192 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1193 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1196 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1197 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1198 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1199 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1200 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1202 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1203 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1205 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1206 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1208 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1209 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1210 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1213 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1214 Only the low word of the dwTypeData is used.
1215 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1216 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1217 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1218 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1222 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)
1223 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1224 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1228 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1229 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1230 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1231 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1234 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1235 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1236 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1237 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1238 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1241 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1242 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1243 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1244 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1245 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1247 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1248 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1250 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1251 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1253 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1254 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1255 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1258 } while( !(ansi = !ansi) );
1263 The following tests try to confirm the algorithm used to return the menu items
1264 when there is a collision between a menu item and a popup menu
1266 void test_menu_search_bycommand( void )
1268 HMENU hmenu, hmenuSub, hmenuSub2;
1274 static CHAR menuitem[] = "MenuItem",
1275 menuitem2[] = "MenuItem 2";
1277 /* Case 1: Menu containing a menu item */
1278 hmenu = CreateMenu();
1280 memset( &info, 0, sizeof info );
1281 info.cbSize = sizeof info;
1282 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1283 info.fType = MFT_STRING;
1284 strcpy(strIn, "Case 1 MenuItem");
1285 info.dwTypeData = strIn;
1286 info.wID = (UINT) 0x1234;
1288 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1289 ok (rc, "Inserting the menuitem failed\n");
1291 id = GetMenuItemID(hmenu, 0);
1292 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1294 /* Confirm the menuitem was given the id supplied (getting by position) */
1295 memset( &info, 0, sizeof info );
1297 info.cbSize = sizeof(MENUITEMINFO);
1298 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1299 info.dwTypeData = strback;
1300 info.cch = sizeof(strback);
1302 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1303 ok (rc, "Getting the menu items info failed\n");
1304 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1305 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1307 /* Search by id - Should return the item */
1308 memset( &info, 0, sizeof info );
1310 info.cbSize = sizeof(MENUITEMINFO);
1311 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1312 info.dwTypeData = strback;
1313 info.cch = sizeof(strback);
1314 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1316 ok (rc, "Getting the menu items info failed\n");
1317 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1318 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1320 DestroyMenu( hmenu );
1322 /* Case 2: Menu containing a popup menu */
1323 hmenu = CreateMenu();
1324 hmenuSub = CreateMenu();
1326 strcpy(strIn, "Case 2 SubMenu");
1327 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1328 ok (rc, "Inserting the popup menu into the main menu failed\n");
1330 id = GetMenuItemID(hmenu, 0);
1331 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1333 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1334 memset( &info, 0, sizeof info );
1336 info.cbSize = sizeof(MENUITEMINFO);
1337 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1338 info.dwTypeData = strback;
1339 info.cch = sizeof(strback);
1340 info.wID = 0xdeadbeef;
1342 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1343 ok (rc, "Getting the menu items info failed\n");
1344 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1345 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1347 /* Search by id - returns the popup menu itself */
1348 memset( &info, 0, sizeof info );
1350 info.cbSize = sizeof(MENUITEMINFO);
1351 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1352 info.dwTypeData = strback;
1353 info.cch = sizeof(strback);
1354 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1356 ok (rc, "Getting the menu items info failed\n");
1357 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1358 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1361 Now add an item after it with the same id
1363 memset( &info, 0, sizeof info );
1364 info.cbSize = sizeof info;
1365 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1366 info.fType = MFT_STRING;
1367 strcpy(strIn, "Case 2 MenuItem 1");
1368 info.dwTypeData = strIn;
1369 info.wID = (UINT_PTR) hmenuSub;
1370 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1371 ok (rc, "Inserting the menuitem failed\n");
1373 /* Search by id - returns the item which follows the popup menu */
1374 memset( &info, 0, sizeof info );
1376 info.cbSize = sizeof(MENUITEMINFO);
1377 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1378 info.dwTypeData = strback;
1379 info.cch = sizeof(strback);
1380 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1382 ok (rc, "Getting the menu items info failed\n");
1383 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1384 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1387 Now add an item before the popup (with the same id)
1389 memset( &info, 0, sizeof info );
1390 info.cbSize = sizeof info;
1391 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1392 info.fType = MFT_STRING;
1393 strcpy(strIn, "Case 2 MenuItem 2");
1394 info.dwTypeData = strIn;
1395 info.wID = (UINT_PTR) hmenuSub;
1396 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1397 ok (rc, "Inserting the menuitem failed\n");
1399 /* Search by id - returns the item which precedes the popup menu */
1400 memset( &info, 0, sizeof info );
1402 info.cbSize = sizeof(MENUITEMINFO);
1403 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1404 info.dwTypeData = strback;
1405 info.cch = sizeof(strback);
1406 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1408 ok (rc, "Getting the menu items info failed\n");
1409 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1410 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1412 DestroyMenu( hmenu );
1413 DestroyMenu( hmenuSub );
1416 Case 3: Menu containing a popup menu which in turn
1417 contains 2 items with the same id as the popup itself
1420 hmenu = CreateMenu();
1421 hmenuSub = CreateMenu();
1423 memset( &info, 0, sizeof info );
1424 info.cbSize = sizeof info;
1425 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1426 info.fType = MFT_STRING;
1427 info.dwTypeData = menuitem;
1428 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1430 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1431 ok (rc, "Inserting the popup menu into the main menu failed\n");
1433 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1434 ok (rc, "Inserting the sub menu menuitem failed\n");
1436 memset( &info, 0, sizeof info );
1437 info.cbSize = sizeof info;
1438 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1439 info.fType = MFT_STRING;
1440 info.dwTypeData = menuitem2;
1441 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1443 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1444 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1446 /* Prove that you can't query the id of a popup directly (By position) */
1447 id = GetMenuItemID(hmenu, 0);
1448 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1450 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1451 memset( &info, 0, sizeof info );
1453 info.cbSize = sizeof(MENUITEMINFO);
1454 info.fMask = MIIM_STRING | MIIM_ID;
1455 info.dwTypeData = strback;
1456 info.cch = sizeof(strback);
1458 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1459 ok (rc, "Getting the menus info failed\n");
1460 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1461 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1462 DestroyMenu( hmenu );
1463 DestroyMenu( hmenuSub );
1466 Case 4: Menu containing 2 popup menus, the second
1467 contains 2 items with the same id as the first popup menu
1469 hmenu = CreateMenu();
1470 hmenuSub = CreateMenu();
1471 hmenuSub2 = CreateMenu();
1473 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1474 ok (rc, "Inserting the popup menu into the main menu failed\n");
1476 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1477 ok (rc, "Inserting the popup menu into the main menu failed\n");
1479 memset( &info, 0, sizeof info );
1480 info.cbSize = sizeof info;
1481 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1482 info.fType = MFT_STRING;
1483 info.dwTypeData = menuitem;
1484 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1486 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1487 ok (rc, "Inserting the sub menu menuitem failed\n");
1489 memset( &info, 0, sizeof info );
1490 info.cbSize = sizeof info;
1491 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1492 info.fType = MFT_STRING;
1493 info.dwTypeData = menuitem2;
1494 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1496 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1497 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1499 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1500 memset( &info, 0, sizeof info );
1502 info.cbSize = sizeof(MENUITEMINFO);
1503 info.fMask = MIIM_STRING | MIIM_ID;
1504 info.dwTypeData = strback;
1505 info.cch = sizeof(strback);
1507 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1508 ok (rc, "Getting the menus info failed\n");
1509 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1510 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1512 memset( &info, 0, sizeof info );
1514 info.cbSize = sizeof(MENUITEMINFO);
1515 info.fMask = MIIM_STRING | MIIM_ID;
1516 info.dwTypeData = strback;
1517 info.cch = sizeof(strback);
1519 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1520 ok (rc, "Getting the menus info failed\n");
1521 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1522 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1524 DestroyMenu( hmenu );
1525 DestroyMenu( hmenuSub );
1526 DestroyMenu( hmenuSub2 );
1530 Case 5: Menu containing a popup menu which in turn
1531 contains an item with a different id than the popup menu.
1532 This tests the fallback to a popup menu ID.
1535 hmenu = CreateMenu();
1536 hmenuSub = CreateMenu();
1538 rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1539 ok (rc, "Appending the popup menu to the main menu failed\n");
1541 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1542 ok (rc, "Appending the item to the popup menu failed\n");
1544 /* Set the ID for hmenuSub */
1545 info.cbSize = sizeof(info);
1546 info.fMask = MIIM_ID;
1549 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1550 ok(rc, "Setting the ID for the popup menu failed\n");
1552 /* Check if the ID has been set */
1554 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1555 ok(rc, "Getting the ID for the popup menu failed\n");
1556 ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1558 /* Prove getting the item info via ID returns the popup menu */
1559 memset( &info, 0, sizeof(info));
1561 info.cbSize = sizeof(MENUITEMINFO);
1562 info.fMask = MIIM_STRING | MIIM_ID;
1563 info.dwTypeData = strback;
1564 info.cch = sizeof(strback);
1566 rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1567 ok (rc, "Getting the menu info failed\n");
1568 ok (info.wID == 101, "IDs differ\n");
1569 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1571 /* Also look for the menu item */
1572 memset( &info, 0, sizeof(info));
1574 info.cbSize = sizeof(MENUITEMINFO);
1575 info.fMask = MIIM_STRING | MIIM_ID;
1576 info.dwTypeData = strback;
1577 info.cch = sizeof(strback);
1579 rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1580 ok (rc, "Getting the menu info failed\n");
1581 ok (info.wID == 102, "IDs differ\n");
1582 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1585 DestroyMenu(hmenuSub);
1588 struct menu_item_pair_s {
1589 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1590 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1591 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1595 static struct menu_mouse_tests_s {
1597 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1598 WORD wVk[5]; /* keys */
1602 /* for each test, send keys or clicks and check for menu visibility */
1603 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1604 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1605 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1606 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1607 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1608 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1609 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1610 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1611 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1612 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1613 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1614 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1615 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1616 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1617 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1618 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1619 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1620 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1622 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1623 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1624 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1625 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1626 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1627 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1628 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1629 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1630 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1631 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1632 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1636 static void send_key(WORD wVk)
1639 memset(&i, 0, 2*sizeof(INPUT));
1640 i[0].type = i[1].type = INPUT_KEYBOARD;
1641 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1642 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1643 SendInput(2, (INPUT *) i, sizeof(INPUT));
1646 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1648 HMENU hMenu = hMenus[mi->uMenu];
1652 int screen_w = GetSystemMetrics(SM_CXSCREEN);
1653 int screen_h = GetSystemMetrics(SM_CYSCREEN);
1655 GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1657 memset(&i, 0, 3*sizeof(INPUT));
1658 i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1659 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1660 = ((r.left + 5) * 65535) / screen_w;
1661 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1662 = ((r.top + 5) * 65535) / screen_h;
1663 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1664 = MOUSEEVENTF_ABSOLUTE;
1665 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1666 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1667 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1668 SendInput(3, (INPUT *) i, sizeof(INPUT));
1670 /* hack to prevent mouse message buildup in Wine */
1671 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1674 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1677 HANDLE hWnd = lpParameter;
1680 /* mixed keyboard/mouse test */
1681 for (i = 0; menu_tests[i].type != -1; i++)
1685 if (menu_tests[i].type == INPUT_KEYBOARD)
1686 for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1687 send_key(menu_tests[i].wVk[j]);
1689 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1690 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1692 while (menu_tests[i].bMenuVisible != bMenuVisible)
1700 if (menu_tests[i]._todo_wine)
1703 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1707 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1712 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1716 case WM_ENTERMENULOOP:
1717 bMenuVisible = TRUE;
1719 case WM_EXITMENULOOP:
1720 bMenuVisible = FALSE;
1723 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1728 static void test_menu_input(void) {
1731 HINSTANCE hInstance = GetModuleHandleA( NULL );
1732 HANDLE hThread, hWnd;
1734 wclass.lpszClassName = "MenuTestClass";
1735 wclass.style = CS_HREDRAW | CS_VREDRAW;
1736 wclass.lpfnWndProc = WndProc;
1737 wclass.hInstance = hInstance;
1738 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1739 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1740 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1741 wclass.lpszMenuName = 0;
1742 wclass.cbClsExtra = 0;
1743 wclass.cbWndExtra = 0;
1744 assert (RegisterClassA( &wclass ));
1745 assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1746 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1747 400, 200, NULL, NULL, hInstance, NULL) );
1750 hMenus[3] = CreatePopupMenu();
1751 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1752 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1754 hMenus[2] = CreatePopupMenu();
1755 AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1756 AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1757 AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1759 hMenus[1] = CreateMenu();
1760 AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1761 AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1762 AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1764 SetMenu(hWnd, hMenus[1]);
1765 ShowWindow(hWnd, SW_SHOW);
1768 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1771 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1773 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1775 DestroyWindow(hWnd);
1778 void test_menu_flags( void )
1780 HMENU hMenu, hPopupMenu;
1782 hMenu = CreateMenu();
1783 hPopupMenu = CreatePopupMenu();
1785 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1787 AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1788 InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1789 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1790 ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1792 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1793 "AppendMenu should accept MF_HILITE\n");
1794 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1795 "InsertMenu should accept MF_HILITE\n");
1796 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1797 "ModifyMenu should accept MF_HILITE\n");
1799 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1800 "AppendMenu must not accept MF_DEFAULT\n");
1801 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1802 "InsertMenu must not accept MF_DEFAULT\n");
1803 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1804 "ModifyMenu must not accept MF_DEFAULT\n");
1809 void test_menu_hilitemenuitem( void )
1811 HMENU hMenu, hPopupMenu;
1813 hMenu = CreateMenu();
1814 hPopupMenu = CreatePopupMenu();
1816 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1818 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1819 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1820 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1822 HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
1823 HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
1824 HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
1825 HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
1829 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1830 "HiliteMenuItem: Item 1 is not hilited\n");
1832 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1833 "HiliteMenuItem: Item 2 is hilited\n");
1836 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1837 "HiliteMenuItem: Item 3 is not hilited\n");
1846 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1848 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1850 register_menu_check_class();
1852 test_menu_locked_by_window();
1853 test_menu_ownerdraw();
1854 test_menu_add_string();
1855 test_menu_iteminfo();
1856 test_menu_search_bycommand();
1857 test_menu_bmp_and_string();
1860 test_menu_hilitemenuitem();