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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
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 /* globals to communicate between test and wndproc */
60 /* menu texts with their sizes */
63 SIZE size; /* size of text up to any \t */
64 SIZE sc_size; /* size of the short-cut */
73 unsigned int MOD_maxid;
74 RECT MOD_rc[MOD_NRMENUS];
75 int MOD_avec, MOD_hic;
77 SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
78 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
79 int MOD_GotDrawItemMsg = FALSE;
80 /* wndproc used by test_menu_ownerdraw() */
81 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
82 WPARAM wparam, LPARAM lparam)
88 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
90 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
91 pmis->itemData, pmis->itemWidth, pmis->itemHeight);
92 MOD_odheight = pmis->itemHeight;
93 pmis->itemWidth = MODsizes[pmis->itemData].cx;
94 pmis->itemHeight = MODsizes[pmis->itemData].cy;
99 DRAWITEMSTRUCT * pdis;
102 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
105 pdis = (DRAWITEMSTRUCT *) lparam;
106 if( winetest_debug) {
108 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
109 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %ld,%ld-%ld,%ld itemrc: %ld,%ld-%ld,%ld\n",
110 hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
111 pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
112 pdis->rcItem.right,pdis->rcItem.bottom,
113 rc.left,rc.top,rc.right,rc.bottom);
114 oldpen=SelectObject( pdis->hDC, GetStockObject(
115 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
116 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
117 pdis->rcItem.right,pdis->rcItem.bottom );
118 SelectObject( pdis->hDC, oldpen);
120 /* calculate widths of some menu texts */
121 if( ! MOD_txtsizes[0].size.cx)
122 for(i = 0; MOD_txtsizes[i].text; i++) {
125 strcpy( buf, MOD_txtsizes[i].text);
126 if( ( p = strchr( buf, '\t'))) {
128 DrawText( pdis->hDC, p + 1, -1, &rc,
129 DT_SINGLELINE|DT_CALCRECT);
130 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
131 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
133 DrawText( pdis->hDC, buf, -1, &rc,
134 DT_SINGLELINE|DT_CALCRECT);
135 MOD_txtsizes[i].size.cx= rc.right - rc.left;
136 MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
139 if( pdis->itemData > MOD_maxid) return TRUE;
140 /* store the rectangl */
141 MOD_rc[pdis->itemData] = pdis->rcItem;
142 /* calculate average character width */
143 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
144 MOD_avec = (sz.cx + 26)/52;
145 GetTextMetrics( pdis->hDC, &tm);
146 MOD_hic = tm.tmHeight;
147 MOD_GotDrawItemMsg = TRUE;
152 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
157 return DefWindowProc(hwnd, msg, wparam, lparam);
160 static void register_menu_check_class(void)
168 GetModuleHandle(NULL),
170 LoadCursor(NULL, IDC_ARROW),
171 (HBRUSH)(COLOR_BTNFACE+1),
173 TEXT("WineMenuCheck"),
176 atomMenuCheckClass = RegisterClass(&wc);
179 /* demonstrates that windows locks the menu object so that it is still valid
180 * even after a client calls DestroyMenu on it */
181 static void test_menu_locked_by_window(void)
185 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
186 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
187 NULL, NULL, NULL, NULL);
188 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
189 hmenu = CreateMenu();
190 ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
191 ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
192 ok(ret, "InsertMenu failed with error %ld\n", GetLastError());
193 ret = SetMenu(hwnd, hmenu);
194 ok(ret, "SetMenu failed with error %ld\n", GetLastError());
195 ret = DestroyMenu(hmenu);
196 ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
198 ret = DrawMenuBar(hwnd);
200 ok(ret, "DrawMenuBar failed with error %ld\n", GetLastError());
202 ret = IsMenu(GetMenu(hwnd));
203 ok(!ret, "Menu handle should have been destroyed\n");
205 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
206 /* did we process the WM_INITMENU message? */
207 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
209 ok(ret, "WM_INITMENU should have been sent\n");
215 static void test_menu_ownerdraw(void)
221 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
222 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
223 NULL, NULL, NULL, NULL);
224 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
226 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
227 hmenu = CreatePopupMenu();
228 ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
229 if( !hmenu) { DestroyWindow(hwnd);return;}
231 for( j=0;j<2;j++) /* create columns */
232 for(i=0;i<2;i++) { /* create rows */
233 ret = AppendMenu( hmenu, MF_OWNERDRAW |
234 (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
236 ok( ret, "AppendMenu failed for %d\n", k-1);
239 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
240 /* display the menu */
241 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
243 /* columns have a 4 pixel gap between them */
244 ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
245 "item rectangles are not separated by 4 pixels space\n");
246 /* height should be what the MEASUREITEM message has returned */
247 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
248 "menu item has wrong height: %ld should be %d\n",
249 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
250 /* no gaps between the rows */
251 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
252 "There should not be a space between the rows, gap is %ld\n",
253 MOD_rc[0].bottom - MOD_rc[1].top);
254 /* test the correct value of the item height that was sent
255 * by the WM_MEASUREITEM message */
256 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
257 MOD_odheight == MOD_hic, /* Win95,98,ME */
258 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
259 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
260 /* test what MF_MENUBREAK did at the first position. Also show
261 * that an MF_SEPARATOR is ignored in the height calculation. */
262 leftcol= MOD_rc[0].left;
263 ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
264 /* display the menu */
265 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
266 /* left should be 4 pixels less now */
267 ok( leftcol == MOD_rc[0].left + 4,
268 "columns should be 4 pixels to the left (actual %ld).\n",
269 leftcol - MOD_rc[0].left);
271 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
272 "width of owner drawn menu item is wrong. Got %ld expected %d\n",
273 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
275 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
276 "Height is incorrect. Got %ld expected %d\n",
277 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
279 /* test width/height of an ownerdraw menu bar as well */
280 ret = DestroyMenu(hmenu);
281 ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
282 hmenu = CreateMenu();
283 ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
284 if( !hmenu) { DestroyWindow(hwnd);return;}
287 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
288 ok( ret, "AppendMenu failed for %d\n", i);
290 ret = SetMenu( hwnd, hmenu);
291 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
292 ok(ret, "SetMenu failed with error %ld\n", GetLastError());
294 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
295 "width of owner drawn menu item is wrong. Got %ld expected %d\n",
296 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
298 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
299 "Height of owner drawn menu item is wrong. Got %ld expected %d\n",
300 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
303 ret = DestroyMenu(hmenu);
304 ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
308 /* helper for test_menu_bmp_and_string() */
309 static void test_mbs_help( int ispop, int hassub, int mnuopt,
310 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
311 SIZE bmpsize, char *text, SIZE size, SIZE sc_size)
314 HMENU hmenu, submenu;
315 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
321 MOD_GotDrawItemMsg = FALSE;
322 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
324 mii.fState = MF_CHECKED;
326 MODsizes[0] = bmpsize;
330 mii.fMask |= MIIM_STRING;
331 mii.dwTypeData = text;
332 if( ( p = strchr( text, '\t'))) {
333 hastab = *(p + 1) ? 2 : 1;
336 /* tabs don't make sense in menubars */
337 if(hastab && !ispop) return;
339 mii.fMask |= MIIM_BITMAP;
342 submenu = CreateMenu();
343 ok( submenu != 0, "CreateMenu failed with error %ld\n", GetLastError());
345 hmenu = CreatePopupMenu();
347 hmenu = CreateMenu();
348 ok( hmenu != 0, "Create{Popup}Menu failed with error %ld\n", GetLastError());
350 mii.fMask |= MIIM_SUBMENU;
351 mii.hSubMenu = submenu;
354 mi.cbSize = sizeof(mi);
355 mi.fMask = MIM_STYLE;
356 pGetMenuInfo( hmenu, &mi);
357 mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
358 ret = pSetMenuInfo( hmenu, &mi);
359 ok( ret, "SetMenuInfo failed with error %ld\n", GetLastError());
361 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
362 ok( ret, "InsertMenuItem failed with error %ld\n", GetLastError());
364 if( winetest_debug) {
366 RECT rc = {100, 50, 400, 70};
369 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
370 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
371 TextOut( hdc, 100, 50, buf, strlen( buf));
372 ReleaseDC( hwnd, hdc);
375 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
377 ret = SetMenu( hwnd, hmenu);
378 ok(ret, "SetMenu failed with error %ld\n", GetLastError());
381 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
382 /* check menu width */
384 expect = ( text || hbmp ?
385 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
387 arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
388 (text && hastab ? /* TAB space */
389 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
390 (text ? 2 + (text[0] ? size.cx :0): 0) ;
392 expect = !(text || hbmp) ? 0 :
393 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) +
394 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
395 ok( rc.right - rc.left == expect,
396 "menu width wrong, got %ld expected %d\n", rc.right - rc.left, expect);
397 failed = failed || !(rc.right - rc.left == expect);
398 /* check menu height */
400 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
401 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
402 (hbmp ? bmpsize.cy + 2 : 0)));
404 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
405 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
406 ok( rc.bottom - rc.top == expect,
407 "menu height wrong, got %ld expected %d (%d)\n",
408 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
409 failed = failed || !(rc.bottom - rc.top == expect);
410 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
411 /* check the position of the bitmap */
413 expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
415 ok( expect == MOD_rc[0].left,
416 "bitmap left is %ld expected %d\n", MOD_rc[0].left, expect);
417 failed = failed || !(expect == MOD_rc[0].left);
419 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
420 ok( expect == MOD_rc[0].top,
421 "bitmap top is %ld expected %d\n", MOD_rc[0].top, expect);
422 failed = failed || !(expect == MOD_rc[0].top);
424 /* if there was a failure, report details */
426 trace("*** count %d text \"%s\" bitmap %p bmsize %ld,%ld textsize %ld+%ld,%ld mnuopt %d hastab %d\n",
427 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
428 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
429 trace(" check %d,%d arrow %d avechar %d\n",
430 GetSystemMetrics(SM_CXMENUCHECK ),
431 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
432 if( hbmp == HBMMENU_CALLBACK)
433 trace( " rc %ld,%ld-%ld,%ld bmp.rc %ld,%ld-%ld,%ld\n",
434 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
435 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
438 ret = DestroyMenu(submenu);
439 ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
440 ret = DestroyMenu(hmenu);
441 ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
445 static void test_menu_bmp_and_string(void)
452 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
454 if( !pGetMenuInfo) return;
456 memset( bmfill, 0x55, sizeof( bmfill));
457 hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
458 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
459 NULL, NULL, NULL, NULL);
460 hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
461 GetObject( hbm_arrow, sizeof(bm), &bm);
462 arrowwidth = bm.bmWidth;
464 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
466 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
469 trace(" check %d,%d arrow %d avechar %d\n",
470 GetSystemMetrics(SM_CXMENUCHECK ),
471 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
474 for( ispop=1; ispop >= 0; ispop--){
475 static SIZE bmsizes[]= {
476 {10,10},{38,38},{1,30},{55,5}};
477 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
478 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
479 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL };
480 ok( (int)hbm, "CreateBitmap failed err %ld\n", GetLastError());
481 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
482 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
483 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
484 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
485 /* no need to test NULL bitmaps of several sizes */
486 if( !bitmaps[bmpidx] && szidx > 0) continue;
487 if( !ispop && hassub) continue;
488 test_mbs_help( ispop, hassub, mnuopt,
489 hwnd, arrowwidth, ++count,
492 MOD_txtsizes[txtidx].text,
493 MOD_txtsizes[txtidx].size,
494 MOD_txtsizes[txtidx].sc_size);
506 static void test_menu_add_string( void )
516 WCHAR strbackW[0x80];
517 static const WCHAR expectedString[] = {'D', 'u', 'm', 'm', 'y', ' ',
518 's', 't', 'r', 'i', 'n', 'g', 0};
520 hmenu = CreateMenu();
522 memset( &info, 0, sizeof info );
523 info.cbSize = sizeof info;
524 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
525 info.dwTypeData = "blah";
530 InsertMenuItem(hmenu, 0, TRUE, &info );
532 memset( &info, 0, sizeof info );
533 info.cbSize = sizeof info;
534 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
535 info.dwTypeData = string;
536 info.cch = sizeof string;
538 GetMenuItemInfo( hmenu, 0, TRUE, &info );
540 ok( !strcmp( string, "blah" ), "menu item name differed\n");
542 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
543 strcpy(string, "Dummy string");
544 memset(&info, 0x00, sizeof(info));
545 info.cbSize= sizeof(MENUITEMINFO);
546 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
547 info.fType= MFT_OWNERDRAW;
548 info.dwTypeData= string;
549 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
550 ok (rc, "InsertMenuItem failed\n");
552 strcpy(string,"Garbage");
553 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
554 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
556 ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
557 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
559 /* Just change ftype to string and see what text is stored */
560 memset(&info, 0x00, sizeof(info));
561 info.cbSize= sizeof(MENUITEMINFO);
562 info.fMask= MIIM_FTYPE; /* Set string type */
563 info.fType= MFT_STRING;
564 info.dwTypeData= (char *)0xdeadbeef;
565 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
566 ok (rc, "SetMenuItemInfo failed\n");
568 /* Did we keep the old dwTypeData? */
569 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
570 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
572 /* Ensure change to bitmap type fails */
573 memset(&info, 0x00, sizeof(info));
574 info.cbSize= sizeof(MENUITEMINFO);
575 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
576 info.fType= MFT_BITMAP;
577 info.dwTypeData= (char *)0xdeadbee2;
578 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
579 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
581 /* Just change ftype back and ensure data hasn't been freed */
582 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
583 info.dwTypeData= (char *)0xdeadbee3;
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 /* Just change string value (not type) */
592 memset(&info, 0x00, sizeof(info));
593 info.cbSize= sizeof(MENUITEMINFO);
594 info.fMask= MIIM_STRING; /* Set typeData */
595 strcpy(string2, "string2");
596 info.dwTypeData= string2;
597 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
598 ok (rc, "SetMenuItemInfo failed\n");
600 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
601 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
603 /* crashes with wine 0.9.5 */
604 memset(&info, 0x00, sizeof(info));
605 info.cbSize= sizeof(MENUITEMINFO);
606 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
607 info.fType= MFT_OWNERDRAW;
608 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
609 ok (rc, "InsertMenuItem failed\n");
610 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
611 "GetMenuString on ownerdraw entry succeeded.\n");
612 ok (!GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION),
613 "GetMenuStringW on ownerdraw entry succeeded.\n");
616 DestroyMenu( hmenu );
619 /* define building blocks for the menu item info tests */
620 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
622 if (n <= 0) return 0;
623 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
624 return *str1 - *str2;
627 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
630 while ((*p++ = *src++));
635 #define DMIINFF( i, e, field)\
636 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
637 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
639 #define DUMPMIINF(s,i,e)\
641 DMIINFF( i, e, fMask)\
642 DMIINFF( i, e, fType)\
643 DMIINFF( i, e, fState)\
645 DMIINFF( i, e, hSubMenu)\
646 DMIINFF( i, e, hbmpChecked)\
647 DMIINFF( i, e, hbmpUnchecked)\
648 DMIINFF( i, e, dwItemData)\
649 DMIINFF( i, e, dwTypeData)\
651 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
654 /* insert menu item */
655 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
658 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
659 HMENU hmenu = CreateMenu();\
660 BOOL ret, stop = FALSE;\
661 SetLastError( 0xdeadbeef);\
662 if(ansi)strcpy( string, init);\
663 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
664 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
665 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
666 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
668 } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
671 /* GetMenuItemInfo + GetMenuString */
672 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
673 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
674 expname, eret2, eret3)\
676 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
677 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
678 MENUITEMINFOA *info2 = &info2A;\
679 MENUITEMINFOA *einfo = &einfoA;\
680 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
682 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
683 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
684 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
686 ok( (eret2)==ret,"GetMenuItemInfo failed, err %ld\n",GetLastError());\
687 ret = memcmp( info2, einfo, sizeof einfoA);\
688 /* ok( ret==0, "Got wrong menu item info data\n");*/\
689 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
690 if( einfo->dwTypeData == string) {\
691 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
692 einfo->dwTypeData ? einfo->dwTypeData: "");\
693 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
694 einfo->dwTypeData ? einfo->dwTypeData: "");\
695 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
696 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
698 ok( ret, "GetMenuString failed, err %ld\n",GetLastError());\
700 ok( !ret, "GetMenuString should have failed\n");\
707 RemoveMenu(hmenu, 0, TRUE );\
708 DestroyMenu( hmenu );\
709 DestroyMenu( submenu );\
710 submenu = CreateMenu();\
713 #define TMII_MODM( flags, id, data, eret )\
715 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
716 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
717 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
718 else ok( (eret)==ret,"ModifyMenuA failed, err %ld\n",GetLastError());\
721 /* SetMenuItemInfo */
722 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
725 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
726 SetLastError( 0xdeadbeef);\
727 if(ansi)strcpy( string, init);\
728 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
729 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
730 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
731 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
733 } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
742 static void test_menu_iteminfo( void )
744 int S=sizeof( MENUITEMINFOA);
749 WCHAR txtW[]={'W','i','n','e',0};
750 WCHAR initW[]={'X','Y','Z',0};
752 void *txt, *init, *empty, *string;
753 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
755 HMENU submenu=CreateMenu();
758 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
759 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
760 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
761 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
762 /* (since MFT_STRING is zero, there are four of them) */
763 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
764 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
765 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
768 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
769 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
770 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
773 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
774 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
775 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
778 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
779 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
780 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
783 /* not enough space for name*/
784 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
785 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
786 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
789 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
790 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
791 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
794 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
795 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
796 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
799 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
800 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
801 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
804 /* cannot combine MIIM_TYPE with some other flags */
805 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
806 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
807 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
810 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
811 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
812 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
815 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
816 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
817 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
820 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
821 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
822 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
825 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
826 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
827 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
830 /* but succeeds with some others */
831 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
832 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
833 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
836 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
837 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
838 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
841 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
842 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
843 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
846 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
847 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
848 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
851 /* to be continued */
852 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
853 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
854 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
855 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
858 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
859 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
860 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
861 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
864 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
865 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
866 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
869 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
870 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
871 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
874 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
875 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
876 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
879 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
880 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
881 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
882 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
885 /* same but retrieve with MIIM_TYPE */
886 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
887 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
888 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
891 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
892 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
893 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
896 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
897 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
898 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
902 /* How is that with bitmaps? */
903 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
904 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
905 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
908 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
909 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
910 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
913 /* MIIM_BITMAP does not like MFT_BITMAP */
914 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
915 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
916 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
919 /* no problem with OWNERDRAWN */
920 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
921 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
922 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
925 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
926 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
927 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
928 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
932 /* menu with submenu */
933 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
934 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
935 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
938 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
939 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
940 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
943 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
944 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
945 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
946 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
948 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
949 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
952 /* menu with invalid submenu */
953 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
954 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
955 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
959 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
960 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
961 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
964 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
965 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
966 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
969 /* SEPARATOR and STRING go well together */
970 /* BITMAP and STRING go well together */
971 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
972 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
973 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
976 /* BITMAP, SEPARATOR and STRING go well together */
977 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
978 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
979 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
982 /* last two tests, but use MIIM_TYPE to retrieve info */
983 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
984 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
985 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
988 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
989 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
990 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
993 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
994 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
995 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
998 /* same three with MFT_OWNERDRAW */
999 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1000 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1001 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1004 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1005 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1006 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1009 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1010 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1011 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1015 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1016 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1017 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1020 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1021 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1022 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1023 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1024 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1027 /* same with bitmap: now the text is cleared */
1028 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1029 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1030 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1031 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1034 /* start with bitmap: now setting text clears it (though he flag is raised) */
1035 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1036 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1037 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1039 TMII_MODM( MFT_STRING, 545, txt, OK)
1040 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1041 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1044 /*repeat with text NULL */
1045 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1046 TMII_MODM( MFT_STRING, 545, NULL, OK)
1047 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1048 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1051 /* repeat with text "" */
1052 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1053 TMII_MODM( MFT_STRING, 545, empty, 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, 545, 0, -9, -9, -9, string, 0, 0, },
1058 /* start with bitmap: set ownerdraw */
1059 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1060 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1061 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1062 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1066 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1067 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1068 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1071 /* some tests with small cbSize: the hbmpItem is to be ignored */
1072 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1073 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1074 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1077 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1078 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1079 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1082 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1083 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1084 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1087 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1088 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1089 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1092 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1093 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1094 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1097 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1098 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1099 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1102 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1103 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1104 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1105 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1108 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1109 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1110 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1113 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1114 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1115 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1118 /* set a string menu to ownerdraw with MIIM_TYPE */
1119 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1120 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1121 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1122 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1125 /* test with modifymenu add submenu */
1126 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1127 TMII_MODM( MF_POPUP, submenu, txt, OK)
1128 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1129 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1131 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1132 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1135 /* MFT_SEPARATOR bit is kept when the text is added */
1136 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1137 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1138 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1139 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1142 /* MFT_SEPARATOR bit is kept when bitmap is added */
1143 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1144 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1145 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1146 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1150 } while( !(ansi = !ansi) );
1155 The following tests try to confirm the algorithm used to return the menu items
1156 when there is a collision between a menu item and a popup menu
1158 void test_menu_search_bycommand( void )
1160 HMENU hmenu, hmenuSub, hmenuSub2;
1167 /* Case 1: Menu containing a menu item */
1168 hmenu = CreateMenu();
1170 memset( &info, 0, sizeof info );
1171 info.cbSize = sizeof info;
1172 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1173 info.fType = MFT_STRING;
1174 strcpy(strIn, "Case 1 MenuItem");
1175 info.dwTypeData = strIn;
1176 info.wID = (UINT) 0x1234;
1178 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1179 ok (rc, "Inserting the menuitem failed\n");
1181 id = GetMenuItemID(hmenu, 0);
1182 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1184 /* Confirm the menuitem was given the id supplied (getting by position) */
1185 memset( &info, 0, sizeof info );
1187 info.cbSize = sizeof(MENUITEMINFO);
1188 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1189 info.dwTypeData = strback;
1190 info.cch = sizeof(strback);
1192 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1193 ok (rc, "Getting the menu items info failed\n");
1194 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1195 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1197 /* Search by id - Should return the item */
1198 memset( &info, 0, sizeof info );
1200 info.cbSize = sizeof(MENUITEMINFO);
1201 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1202 info.dwTypeData = strback;
1203 info.cch = sizeof(strback);
1204 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1206 ok (rc, "Getting the menu items info failed\n");
1207 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1208 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1210 DestroyMenu( hmenu );
1212 /* Case 2: Menu containing a popup menu */
1213 hmenu = CreateMenu();
1214 hmenuSub = CreateMenu();
1216 strcpy(strIn, "Case 2 SubMenu");
1217 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1218 ok (rc, "Inserting the popup menu into the main menu failed\n");
1220 id = GetMenuItemID(hmenu, 0);
1221 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1223 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1224 memset( &info, 0, sizeof info );
1226 info.cbSize = sizeof(MENUITEMINFO);
1227 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1228 info.dwTypeData = strback;
1229 info.cch = sizeof(strback);
1230 info.wID = 0xdeadbeef;
1232 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1233 ok (rc, "Getting the menu items info failed\n");
1234 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1235 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1237 /* Search by id - returns the popup menu itself */
1238 memset( &info, 0, sizeof info );
1240 info.cbSize = sizeof(MENUITEMINFO);
1241 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1242 info.dwTypeData = strback;
1243 info.cch = sizeof(strback);
1244 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1246 ok (rc, "Getting the menu items info failed\n");
1247 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1248 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1251 Now add an item after it with the same id
1253 memset( &info, 0, sizeof info );
1254 info.cbSize = sizeof info;
1255 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1256 info.fType = MFT_STRING;
1257 strcpy(strIn, "Case 2 MenuItem 1");
1258 info.dwTypeData = strIn;
1259 info.wID = (UINT_PTR) hmenuSub;
1260 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1261 ok (rc, "Inserting the menuitem failed\n");
1263 /* Search by id - returns the item which follows the popup menu */
1264 memset( &info, 0, sizeof info );
1266 info.cbSize = sizeof(MENUITEMINFO);
1267 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1268 info.dwTypeData = strback;
1269 info.cch = sizeof(strback);
1270 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1272 ok (rc, "Getting the menu items info failed\n");
1273 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1274 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1277 Now add an item before the popup (with the same id)
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 2 MenuItem 2");
1284 info.dwTypeData = strIn;
1285 info.wID = (UINT_PTR) hmenuSub;
1286 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1287 ok (rc, "Inserting the menuitem failed\n");
1289 /* Search by id - returns the item which precedes the popup menu */
1290 memset( &info, 0, sizeof info );
1292 info.cbSize = sizeof(MENUITEMINFO);
1293 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1294 info.dwTypeData = strback;
1295 info.cch = sizeof(strback);
1296 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1298 ok (rc, "Getting the menu items info failed\n");
1299 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1300 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1302 DestroyMenu( hmenu );
1303 DestroyMenu( hmenuSub );
1306 Case 3: Menu containing a popup menu which in turn
1307 contains 2 items with the same id as the popup itself
1310 hmenu = CreateMenu();
1311 hmenuSub = CreateMenu();
1313 memset( &info, 0, sizeof info );
1314 info.cbSize = sizeof info;
1315 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1316 info.fType = MFT_STRING;
1317 info.dwTypeData = "MenuItem";
1318 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1320 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1321 ok (rc, "Inserting the popup menu into the main menu failed\n");
1323 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1324 ok (rc, "Inserting the sub menu menuitem failed\n");
1326 memset( &info, 0, sizeof info );
1327 info.cbSize = sizeof info;
1328 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1329 info.fType = MFT_STRING;
1330 info.dwTypeData = "MenuItem 2";
1331 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1333 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1334 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1336 /* Prove that you can't query the id of a popup directly (By position) */
1337 id = GetMenuItemID(hmenu, 0);
1338 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1340 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1341 memset( &info, 0, sizeof info );
1343 info.cbSize = sizeof(MENUITEMINFO);
1344 info.fMask = MIIM_STRING | MIIM_ID;
1345 info.dwTypeData = strback;
1346 info.cch = sizeof(strback);
1348 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1349 ok (rc, "Getting the menus info failed\n");
1350 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1351 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1352 DestroyMenu( hmenu );
1353 DestroyMenu( hmenuSub );
1356 Case 4: Menu containing 2 popup menus, the second
1357 contains 2 items with the same id as the first popup menu
1359 hmenu = CreateMenu();
1360 hmenuSub = CreateMenu();
1361 hmenuSub2 = CreateMenu();
1363 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1364 ok (rc, "Inserting the popup menu into the main menu failed\n");
1366 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1367 ok (rc, "Inserting the popup menu into the main menu failed\n");
1369 memset( &info, 0, sizeof info );
1370 info.cbSize = sizeof info;
1371 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1372 info.fType = MFT_STRING;
1373 info.dwTypeData = "MenuItem";
1374 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1376 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1377 ok (rc, "Inserting the sub menu menuitem failed\n");
1379 memset( &info, 0, sizeof info );
1380 info.cbSize = sizeof info;
1381 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1382 info.fType = MFT_STRING;
1383 info.dwTypeData = "MenuItem 2";
1384 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1386 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1387 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1389 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1390 memset( &info, 0, sizeof info );
1392 info.cbSize = sizeof(MENUITEMINFO);
1393 info.fMask = MIIM_STRING | MIIM_ID;
1394 info.dwTypeData = strback;
1395 info.cch = sizeof(strback);
1397 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1398 ok (rc, "Getting the menus info failed\n");
1399 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1400 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1402 memset( &info, 0, sizeof info );
1404 info.cbSize = sizeof(MENUITEMINFO);
1405 info.fMask = MIIM_STRING | MIIM_ID;
1406 info.dwTypeData = strback;
1407 info.cch = sizeof(strback);
1409 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1410 ok (rc, "Getting the menus info failed\n");
1411 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1412 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1418 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1420 (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1422 register_menu_check_class();
1424 test_menu_locked_by_window();
1425 test_menu_ownerdraw();
1426 test_menu_add_string();
1427 test_menu_iteminfo();
1428 test_menu_search_bycommand();
1429 test_menu_bmp_and_string();