4 * Copyright 2005 Robert Shearman
5 * Copyright 2007 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define _WIN32_WINNT 0x0501
29 #define OEMRESOURCE /* For OBM_MNARROW */
36 #include "wine/test.h"
38 static ATOM atomMenuCheckClass
;
40 static BOOL (WINAPI
*pGetMenuInfo
)(HMENU
,LPCMENUINFO
);
41 static UINT (WINAPI
*pSendInput
)(UINT
, INPUT
*, size_t);
42 static BOOL (WINAPI
*pSetMenuInfo
)(HMENU
,LPCMENUINFO
);
44 static void init_function_pointers(void)
46 HMODULE hdll
= GetModuleHandleA("user32");
48 #define GET_PROC(func) \
49 p ## func = (void*)GetProcAddress(hdll, #func); \
51 trace("GetProcAddress(%s) failed\n", #func);
60 static LRESULT WINAPI
menu_check_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
64 case WM_ENTERMENULOOP
:
65 /* mark window as having entered menu loop */
66 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, TRUE
);
67 /* exit menu modal loop
68 * ( A SendMessage does not work on NT3.51 here ) */
69 return PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
71 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
74 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
87 /* globals to communicate between test and wndproc */
89 static BOOL bMenuVisible
;
90 static HMENU hMenus
[4];
95 /* menu texts with their sizes */
98 SIZE size
; /* size of text up to any \t */
99 SIZE sc_size
; /* size of the short-cut */
103 { "Shira&z\tAlt+S" },
108 static unsigned int MOD_maxid
;
109 static RECT MOD_rc
[MOD_NRMENUS
];
110 static int MOD_avec
, MOD_hic
;
111 static int MOD_odheight
;
112 static SIZE MODsizes
[MOD_NRMENUS
]= { {MOD_SIZE
, MOD_SIZE
},{MOD_SIZE
, MOD_SIZE
},
113 {MOD_SIZE
, MOD_SIZE
},{MOD_SIZE
, MOD_SIZE
}};
114 static int MOD_GotDrawItemMsg
= FALSE
;
115 /* wndproc used by test_menu_ownerdraw() */
116 static LRESULT WINAPI
menu_ownerdraw_wnd_proc(HWND hwnd
, UINT msg
,
117 WPARAM wparam
, LPARAM lparam
)
123 MEASUREITEMSTRUCT
* pmis
= (MEASUREITEMSTRUCT
*)lparam
;
125 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
126 pmis
->itemData
, pmis
->itemWidth
, pmis
->itemHeight
);
127 MOD_odheight
= pmis
->itemHeight
;
128 pmis
->itemWidth
= MODsizes
[pmis
->itemData
].cx
;
129 pmis
->itemHeight
= MODsizes
[pmis
->itemData
].cy
;
134 DRAWITEMSTRUCT
* pdis
;
137 char chrs
[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
140 pdis
= (DRAWITEMSTRUCT
*) lparam
;
141 if( winetest_debug
) {
143 GetMenuItemRect( hwnd
, (HMENU
)pdis
->hwndItem
, pdis
->itemData
,&rc
);
144 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
145 hwnd
, (HMENU
)pdis
->hwndItem
, pdis
->itemData
,
146 pdis
->itemID
, pdis
->rcItem
.left
, pdis
->rcItem
.top
,
147 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
,
148 rc
.left
,rc
.top
,rc
.right
,rc
.bottom
);
149 oldpen
=SelectObject( pdis
->hDC
, GetStockObject(
150 pdis
->itemState
& ODS_SELECTED
? WHITE_PEN
:BLACK_PEN
));
151 Rectangle( pdis
->hDC
, pdis
->rcItem
.left
,pdis
->rcItem
.top
,
152 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
);
153 SelectObject( pdis
->hDC
, oldpen
);
155 /* calculate widths of some menu texts */
156 if( ! MOD_txtsizes
[0].size
.cx
)
157 for(i
= 0; MOD_txtsizes
[i
].text
; i
++) {
160 strcpy( buf
, MOD_txtsizes
[i
].text
);
161 if( ( p
= strchr( buf
, '\t'))) {
163 DrawText( pdis
->hDC
, p
+ 1, -1, &rc
,
164 DT_SINGLELINE
|DT_CALCRECT
);
165 MOD_txtsizes
[i
].sc_size
.cx
= rc
.right
- rc
.left
;
166 MOD_txtsizes
[i
].sc_size
.cy
= rc
.bottom
- rc
.top
;
168 DrawText( pdis
->hDC
, buf
, -1, &rc
,
169 DT_SINGLELINE
|DT_CALCRECT
);
170 MOD_txtsizes
[i
].size
.cx
= rc
.right
- rc
.left
;
171 MOD_txtsizes
[i
].size
.cy
= rc
.bottom
- rc
.top
;
174 if( pdis
->itemData
> MOD_maxid
) return TRUE
;
175 /* store the rectangl */
176 MOD_rc
[pdis
->itemData
] = pdis
->rcItem
;
177 /* calculate average character width */
178 GetTextExtentPoint( pdis
->hDC
, chrs
, 52, &sz
);
179 MOD_avec
= (sz
.cx
+ 26)/52;
180 GetTextMetrics( pdis
->hDC
, &tm
);
181 MOD_hic
= tm
.tmHeight
;
182 MOD_GotDrawItemMsg
= TRUE
;
187 PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
192 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
195 static void register_menu_check_class(void)
203 GetModuleHandle(NULL
),
205 LoadCursor(NULL
, IDC_ARROW
),
206 (HBRUSH
)(COLOR_BTNFACE
+1),
208 TEXT("WineMenuCheck"),
211 atomMenuCheckClass
= RegisterClass(&wc
);
214 /* demonstrates that windows locks the menu object so that it is still valid
215 * even after a client calls DestroyMenu on it */
216 static void test_menu_locked_by_window(void)
220 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
221 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
222 NULL
, NULL
, NULL
, NULL
);
223 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
224 hmenu
= CreateMenu();
225 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
226 ret
= InsertMenu(hmenu
, 0, MF_STRING
, 0, TEXT("&Test"));
227 ok(ret
, "InsertMenu failed with error %d\n", GetLastError());
228 ret
= SetMenu(hwnd
, hmenu
);
229 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
230 ret
= DestroyMenu(hmenu
);
231 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
233 ret
= DrawMenuBar(hwnd
);
235 ok(ret
, "DrawMenuBar failed with error %d\n", GetLastError());
237 ret
= IsMenu(GetMenu(hwnd
));
238 ok(!ret
, "Menu handle should have been destroyed\n");
240 SendMessage(hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, 0);
241 /* did we process the WM_INITMENU message? */
242 ret
= GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
244 ok(ret
, "WM_INITMENU should have been sent\n");
250 static void test_menu_ownerdraw(void)
256 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
257 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
258 NULL
, NULL
, NULL
, NULL
);
259 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
261 SetWindowLongPtr( hwnd
, GWLP_WNDPROC
, (LONG
)menu_ownerdraw_wnd_proc
);
262 hmenu
= CreatePopupMenu();
263 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
264 if( !hmenu
) { DestroyWindow(hwnd
);return;}
266 for( j
=0;j
<2;j
++) /* create columns */
267 for(i
=0;i
<2;i
++) { /* create rows */
268 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
|
269 (i
==0 ? MF_MENUBREAK
: 0), k
, (LPCTSTR
) k
);
271 ok( ret
, "AppendMenu failed for %d\n", k
-1);
274 assert( k
<= sizeof(MOD_rc
)/sizeof(RECT
));
275 /* display the menu */
276 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
278 /* columns have a 4 pixel gap between them */
279 ok( MOD_rc
[0].right
+ 4 == MOD_rc
[2].left
,
280 "item rectangles are not separated by 4 pixels space\n");
281 /* height should be what the MEASUREITEM message has returned */
282 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
283 "menu item has wrong height: %d should be %d\n",
284 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
285 /* no gaps between the rows */
286 ok( MOD_rc
[0].bottom
- MOD_rc
[1].top
== 0,
287 "There should not be a space between the rows, gap is %d\n",
288 MOD_rc
[0].bottom
- MOD_rc
[1].top
);
289 /* test the correct value of the item height that was sent
290 * by the WM_MEASUREITEM message */
291 ok( MOD_odheight
== HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
292 MOD_odheight
== MOD_hic
, /* Win95,98,ME */
293 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
294 HIWORD( GetDialogBaseUnits()), MOD_hic
, MOD_odheight
);
295 /* test what MF_MENUBREAK did at the first position. Also show
296 * that an MF_SEPARATOR is ignored in the height calculation. */
297 leftcol
= MOD_rc
[0].left
;
298 ModifyMenu( hmenu
, 0, MF_BYCOMMAND
| MF_OWNERDRAW
| MF_SEPARATOR
, 0, 0);
299 /* display the menu */
300 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
301 /* left should be 4 pixels less now */
302 ok( leftcol
== MOD_rc
[0].left
+ 4,
303 "columns should be 4 pixels to the left (actual %d).\n",
304 leftcol
- MOD_rc
[0].left
);
306 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
307 "width of owner drawn menu item is wrong. Got %d expected %d\n",
308 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
310 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
311 "Height is incorrect. Got %d expected %d\n",
312 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
314 /* test width/height of an ownerdraw menu bar as well */
315 ret
= DestroyMenu(hmenu
);
316 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
317 hmenu
= CreateMenu();
318 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
319 if( !hmenu
) { DestroyWindow(hwnd
);return;}
322 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
, i
, 0);
323 ok( ret
, "AppendMenu failed for %d\n", i
);
325 ret
= SetMenu( hwnd
, hmenu
);
326 UpdateWindow( hwnd
); /* hack for wine to draw the window + menu */
327 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
329 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
330 "width of owner drawn menu item is wrong. Got %d expected %d\n",
331 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
333 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== GetSystemMetrics( SM_CYMENU
) - 1,
334 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
335 MOD_rc
[0].bottom
- MOD_rc
[0].top
, GetSystemMetrics( SM_CYMENU
) - 1);
338 ret
= DestroyMenu(hmenu
);
339 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
343 /* helper for test_menu_bmp_and_string() */
344 static void test_mbs_help( int ispop
, int hassub
, int mnuopt
,
345 HWND hwnd
, int arrowwidth
, int count
, HBITMAP hbmp
,
346 SIZE bmpsize
, LPCSTR text
, SIZE size
, SIZE sc_size
)
349 HMENU hmenu
, submenu
;
350 MENUITEMINFO mii
={ sizeof( MENUITEMINFO
)};
357 MOD_GotDrawItemMsg
= FALSE
;
358 mii
.fMask
= MIIM_FTYPE
| MIIM_DATA
| MIIM_STATE
;
360 mii
.fState
= MF_CHECKED
;
362 MODsizes
[0] = bmpsize
;
366 mii
.fMask
|= MIIM_STRING
;
367 strcpy(text_copy
, text
);
368 mii
.dwTypeData
= text_copy
; /* structure member declared non-const */
369 if( ( p
= strchr( text
, '\t'))) {
370 hastab
= *(p
+ 1) ? 2 : 1;
373 /* tabs don't make sense in menubars */
374 if(hastab
&& !ispop
) return;
376 mii
.fMask
|= MIIM_BITMAP
;
379 submenu
= CreateMenu();
380 ok( submenu
!= 0, "CreateMenu failed with error %d\n", GetLastError());
382 hmenu
= CreatePopupMenu();
384 hmenu
= CreateMenu();
385 ok( hmenu
!= 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
387 mii
.fMask
|= MIIM_SUBMENU
;
388 mii
.hSubMenu
= submenu
;
391 mi
.cbSize
= sizeof(mi
);
392 mi
.fMask
= MIM_STYLE
;
393 pGetMenuInfo( hmenu
, &mi
);
394 mi
.dwStyle
|= mnuopt
== 1 ? MNS_NOCHECK
: MNS_CHECKORBMP
;
395 ret
= pSetMenuInfo( hmenu
, &mi
);
396 ok( ret
, "SetMenuInfo failed with error %d\n", GetLastError());
398 ret
= InsertMenuItem( hmenu
, 0, FALSE
, &mii
);
399 ok( ret
, "InsertMenuItem failed with error %d\n", GetLastError());
401 if( winetest_debug
) {
403 RECT rc
= {100, 50, 400, 70};
406 sprintf( buf
,"%d text \"%s\" mnuopt %d", count
, text
? text
: "(nil)", mnuopt
);
407 FillRect( hdc
, &rc
, (HBRUSH
) COLOR_WINDOW
);
408 TextOut( hdc
, 100, 50, buf
, strlen( buf
));
409 ReleaseDC( hwnd
, hdc
);
412 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
414 ret
= SetMenu( hwnd
, hmenu
);
415 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
418 ret
= GetMenuItemRect( hwnd
, hmenu
, 0, &rc
);
419 /* check menu width */
421 expect
= ( text
|| hbmp
?
422 4 + (mnuopt
!= 1 ? GetSystemMetrics(SM_CXMENUCHECK
) : 0)
424 arrowwidth
+ MOD_avec
+ (hbmp
? bmpsize
.cx
+ 2 : 0) +
425 (text
&& hastab
? /* TAB space */
426 MOD_avec
+ ( hastab
==2 ? sc_size
.cx
: 0) : 0) +
427 (text
? 2 + (text
[0] ? size
.cx
:0): 0) ;
429 expect
= !(text
|| hbmp
) ? 0 :
430 ( hbmp
? (text
? 2:0) + bmpsize
.cx
: 0 ) +
431 (text
? 2 * MOD_avec
+ (text
[0] ? size
.cx
:0): 0) ;
432 ok( rc
.right
- rc
.left
== expect
,
433 "menu width wrong, got %d expected %d\n", rc
.right
- rc
.left
, expect
);
434 failed
= failed
|| !(rc
.right
- rc
.left
== expect
);
435 /* check menu height */
437 expect
= max( ( !(text
|| hbmp
) ? GetSystemMetrics( SM_CYMENUSIZE
)/2 : 0),
438 max( (text
? max( 2 + size
.cy
, MOD_hic
+ 4) : 0),
439 (hbmp
? bmpsize
.cy
+ 2 : 0)));
441 expect
= ( !(text
|| hbmp
) ? GetSystemMetrics( SM_CYMENUSIZE
)/2 :
442 max( GetSystemMetrics( SM_CYMENU
) - 1, (hbmp
? bmpsize
.cy
: 0)));
443 ok( rc
.bottom
- rc
.top
== expect
,
444 "menu height wrong, got %d expected %d (%d)\n",
445 rc
.bottom
- rc
.top
, expect
, GetSystemMetrics( SM_CYMENU
));
446 failed
= failed
|| !(rc
.bottom
- rc
.top
== expect
);
447 if( hbmp
== HBMMENU_CALLBACK
&& MOD_GotDrawItemMsg
) {
448 /* check the position of the bitmap */
450 expect
= ispop
? (4 + ( mnuopt
? 0 : GetSystemMetrics(SM_CXMENUCHECK
)))
452 ok( expect
== MOD_rc
[0].left
,
453 "bitmap left is %d expected %d\n", MOD_rc
[0].left
, expect
);
454 failed
= failed
|| !(expect
== MOD_rc
[0].left
);
456 expect
= (rc
.bottom
- rc
.top
- MOD_rc
[0].bottom
+ MOD_rc
[0].top
) / 2;
457 ok( expect
== MOD_rc
[0].top
,
458 "bitmap top is %d expected %d\n", MOD_rc
[0].top
, expect
);
459 failed
= failed
|| !(expect
== MOD_rc
[0].top
);
461 /* if there was a failure, report details */
463 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
464 count
, text
? text
: "(nil)", hbmp
, bmpsize
.cx
, bmpsize
.cy
,
465 size
.cx
, size
.cy
, sc_size
.cx
, mnuopt
, hastab
);
466 trace(" check %d,%d arrow %d avechar %d\n",
467 GetSystemMetrics(SM_CXMENUCHECK
),
468 GetSystemMetrics(SM_CYMENUCHECK
),arrowwidth
, MOD_avec
);
469 if( hbmp
== HBMMENU_CALLBACK
)
470 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
471 rc
.left
, rc
.top
, rc
.top
, rc
.bottom
, MOD_rc
[0].left
,
472 MOD_rc
[0].top
,MOD_rc
[0].right
, MOD_rc
[0].bottom
);
475 ret
= DestroyMenu(submenu
);
476 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
477 ret
= DestroyMenu(hmenu
);
478 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
482 static void test_menu_bmp_and_string(void)
489 int count
, szidx
, txtidx
, bmpidx
, hassub
, mnuopt
, ispop
;
493 skip("GetMenuInfo is not available\n");
497 memset( bmfill
, 0xcc, sizeof( bmfill
));
498 hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
499 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
500 NULL
, NULL
, NULL
, NULL
);
501 hbm_arrow
=LoadBitmap( 0, (CHAR
*)OBM_MNARROW
);
502 GetObject( hbm_arrow
, sizeof(bm
), &bm
);
503 arrowwidth
= bm
.bmWidth
;
505 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
507 SetWindowLongPtr( hwnd
, GWLP_WNDPROC
, (LONG
)menu_ownerdraw_wnd_proc
);
510 trace(" check %d,%d arrow %d avechar %d\n",
511 GetSystemMetrics(SM_CXMENUCHECK
),
512 GetSystemMetrics(SM_CYMENUCHECK
),arrowwidth
, MOD_avec
);
515 for( ispop
=1; ispop
>= 0; ispop
--){
516 static SIZE bmsizes
[]= {
517 {10,10},{38,38},{1,30},{55,5}};
518 for( szidx
=0; szidx
< sizeof( bmsizes
) / sizeof( SIZE
); szidx
++) {
519 HBITMAP hbm
= CreateBitmap( bmsizes
[szidx
].cx
, bmsizes
[szidx
].cy
,1,1,bmfill
);
520 HBITMAP bitmaps
[] = { HBMMENU_CALLBACK
, hbm
, NULL
};
521 ok( (int)hbm
, "CreateBitmap failed err %d\n", GetLastError());
522 for( txtidx
= 0; txtidx
< sizeof(MOD_txtsizes
)/sizeof(MOD_txtsizes
[0]); txtidx
++) {
523 for( hassub
= 0; hassub
< 2 ; hassub
++) { /* add submenu item */
524 for( mnuopt
= 0; mnuopt
< 3 ; mnuopt
++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
525 for( bmpidx
= 0; bmpidx
<sizeof(bitmaps
)/sizeof(HBITMAP
); bmpidx
++) {
526 /* no need to test NULL bitmaps of several sizes */
527 if( !bitmaps
[bmpidx
] && szidx
> 0) continue;
528 if( !ispop
&& hassub
) continue;
529 test_mbs_help( ispop
, hassub
, mnuopt
,
530 hwnd
, arrowwidth
, ++count
,
533 MOD_txtsizes
[txtidx
].text
,
534 MOD_txtsizes
[txtidx
].size
,
535 MOD_txtsizes
[txtidx
].sc_size
);
547 static void test_menu_add_string( void )
558 WCHAR strbackW
[0x80];
559 static CHAR blah
[] = "blah";
560 static const WCHAR expectedString
[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
562 hmenu
= CreateMenu();
564 memset( &info
, 0, sizeof info
);
565 info
.cbSize
= sizeof info
;
566 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_ID
;
567 info
.dwTypeData
= blah
;
572 InsertMenuItem(hmenu
, 0, TRUE
, &info
);
574 memset( &info
, 0, sizeof info
);
575 info
.cbSize
= sizeof info
;
576 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_DATA
| MIIM_ID
;
577 info
.dwTypeData
= string
;
578 info
.cch
= sizeof string
;
580 GetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
582 ok( !strcmp( string
, "blah" ), "menu item name differed\n");
584 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
585 strcpy(string
, "Dummy string");
586 memset(&info
, 0x00, sizeof(info
));
587 info
.cbSize
= sizeof(MENUITEMINFO
);
588 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
; /* Set OwnerDraw + typeData */
589 info
.fType
= MFT_OWNERDRAW
;
590 info
.dwTypeData
= string
;
591 rc
= InsertMenuItem( hmenu
, 0, TRUE
, &info
);
592 ok (rc
, "InsertMenuItem failed\n");
594 strcpy(string
,"Garbage");
595 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
596 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
598 SetLastError(0xdeadbeef);
599 ret
= GetMenuStringW( hmenu
, 0, (WCHAR
*)strbackW
, 99, MF_BYPOSITION
);
600 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
601 skip("GetMenuStringW is not implemented\n");
604 ok (ret
, "GetMenuStringW on ownerdraw entry failed\n");
605 ok (!lstrcmpW( strbackW
, expectedString
), "Menu text from Unicode version incorrect\n");
608 /* Just change ftype to string and see what text is stored */
609 memset(&info
, 0x00, sizeof(info
));
610 info
.cbSize
= sizeof(MENUITEMINFO
);
611 info
.fMask
= MIIM_FTYPE
; /* Set string type */
612 info
.fType
= MFT_STRING
;
613 info
.dwTypeData
= (char *)0xdeadbeef;
614 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
615 ok (rc
, "SetMenuItemInfo failed\n");
617 /* Did we keep the old dwTypeData? */
618 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
619 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
621 /* Ensure change to bitmap type fails */
622 memset(&info
, 0x00, sizeof(info
));
623 info
.cbSize
= sizeof(MENUITEMINFO
);
624 info
.fMask
= MIIM_FTYPE
; /* Set as bitmap type */
625 info
.fType
= MFT_BITMAP
;
626 info
.dwTypeData
= (char *)0xdeadbee2;
627 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
628 ok (!rc
, "SetMenuItemInfo unexpectedly worked\n");
630 /* Just change ftype back and ensure data hasn't been freed */
631 info
.fType
= MFT_OWNERDRAW
; /* Set as ownerdraw type */
632 info
.dwTypeData
= (char *)0xdeadbee3;
633 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
634 ok (rc
, "SetMenuItemInfo failed\n");
636 /* Did we keep the old dwTypeData? */
637 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
638 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
640 /* Just change string value (not type) */
641 memset(&info
, 0x00, sizeof(info
));
642 info
.cbSize
= sizeof(MENUITEMINFO
);
643 info
.fMask
= MIIM_STRING
; /* Set typeData */
644 strcpy(string2
, "string2");
645 info
.dwTypeData
= string2
;
646 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
647 ok (rc
, "SetMenuItemInfo failed\n");
649 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
650 ok (!strcmp( strback
, "string2" ), "Menu text from Ansi version incorrect\n");
652 /* crashes with wine 0.9.5 */
653 memset(&info
, 0x00, sizeof(info
));
654 info
.cbSize
= sizeof(MENUITEMINFO
);
655 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
; /* Set OwnerDraw + typeData */
656 info
.fType
= MFT_OWNERDRAW
;
657 rc
= InsertMenuItem( hmenu
, 0, TRUE
, &info
);
658 ok (rc
, "InsertMenuItem failed\n");
659 ok (!GetMenuString( hmenu
, 0, NULL
, 0, MF_BYPOSITION
),
660 "GetMenuString on ownerdraw entry succeeded.\n");
661 SetLastError(0xdeadbeef);
662 ret
= GetMenuStringW( hmenu
, 0, NULL
, 0, MF_BYPOSITION
);
663 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
664 skip("GetMenuStringW is not implemented\n");
666 ok (!ret
, "GetMenuStringW on ownerdraw entry succeeded.\n");
668 DestroyMenu( hmenu
);
671 /* define building blocks for the menu item info tests */
672 static int strncmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
674 if (n
<= 0) return 0;
675 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
676 return *str1
- *str2
;
679 static WCHAR
*strcpyW( WCHAR
*dst
, const WCHAR
*src
)
682 while ((*p
++ = *src
++));
687 #define DMIINFF( i, e, field)\
688 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
689 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
691 #define DUMPMIINF(s,i,e)\
693 DMIINFF( i, e, fMask)\
694 DMIINFF( i, e, fType)\
695 DMIINFF( i, e, fState)\
697 DMIINFF( i, e, hSubMenu)\
698 DMIINFF( i, e, hbmpChecked)\
699 DMIINFF( i, e, hbmpUnchecked)\
700 DMIINFF( i, e, dwItemData)\
701 DMIINFF( i, e, dwTypeData)\
703 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
706 /* insert menu item */
707 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
710 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
711 HMENU hmenu = CreateMenu();\
712 BOOL ret, stop = FALSE;\
713 SetLastError( 0xdeadbeef);\
714 if(ansi)strcpy( string, init);\
715 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
716 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
717 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
718 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
720 skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
723 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
725 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
728 /* GetMenuItemInfo + GetMenuString */
729 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
730 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
731 expname, eret2, eret3)\
733 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
734 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
735 MENUITEMINFOA *info2 = &info2A;\
736 MENUITEMINFOA *einfo = &einfoA;\
737 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
739 SetLastError( 0xdeadbeef);\
740 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
741 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
742 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
744 skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
747 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
749 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
750 ret = memcmp( info2, einfo, sizeof einfoA);\
751 /* ok( ret==0, "Got wrong menu item info data\n");*/\
752 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
753 if( einfo->dwTypeData == string) {\
754 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
755 einfo->dwTypeData ? einfo->dwTypeData: "");\
756 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
757 einfo->dwTypeData ? einfo->dwTypeData: "");\
758 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
759 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
761 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
763 ok( !ret, "GetMenuString should have failed\n");\
770 RemoveMenu(hmenu, 0, TRUE );\
771 DestroyMenu( hmenu );\
772 DestroyMenu( submenu );\
773 submenu = CreateMenu();\
776 #define TMII_MODM( flags, id, data, eret )\
778 SetLastError( 0xdeadbeef);\
779 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
780 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
781 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
783 skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
786 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
787 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
790 /* SetMenuItemInfo */
791 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
794 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
795 SetLastError( 0xdeadbeef);\
796 if(ansi)strcpy( string, init);\
797 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
798 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
799 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
800 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
802 skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
805 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
807 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
816 static void test_menu_iteminfo( void )
818 int S
=sizeof( MENUITEMINFOA
);
823 WCHAR txtW
[]={'W','i','n','e',0};
824 WCHAR initW
[]={'X','Y','Z',0};
826 void *txt
, *init
, *empty
, *string
;
827 HBITMAP hbm
= CreateBitmap(1,1,1,1,NULL
);
829 HMENU submenu
=CreateMenu();
832 if( ansi
) {txt
=txtA
;init
=initA
;empty
=emptyA
;string
=stringA
;}
833 else {txt
=txtW
;init
=initW
;empty
=emptyW
;string
=stringA
;}
834 trace( "%s string %p hbm %p txt %p\n", ansi
? "ANSI tests: " : "Unicode tests:", string
, hbm
, txt
);
835 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
836 /* (since MFT_STRING is zero, there are four of them) */
837 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, 0, 0, 0, 0, 0, 0, txt
, 0, 0, }, OK
)
838 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
839 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
842 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
843 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
844 {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
847 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
848 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
849 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
852 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
853 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
854 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
857 /* not enough space for name*/
858 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
859 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, NULL
, 0, -9, },
860 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, NULL
, 4, 0, },
863 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
864 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 5, -9, },
865 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
868 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
869 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 4, -9, },
870 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 3, 0, },
873 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
874 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, NULL
, 0, -9, },
875 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, 0, },
878 /* cannot combine MIIM_TYPE with some other flags */
879 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, ER
)
880 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
881 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
884 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
885 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_STRING
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
886 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
889 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, ER
)
890 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
891 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
894 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
895 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
896 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
899 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_BITMAP
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, 6, hbm
, }, ER
)
900 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
901 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
904 /* but succeeds with some others */
905 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
906 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
907 {, S
, MIIM_TYPE
|MIIM_SUBMENU
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
910 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
911 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
912 {, S
, MIIM_TYPE
|MIIM_STATE
, MFT_STRING
, 0, -9, 0, -9, -9, -9, string
, 4, 0, },
915 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_ID
, MFT_STRING
, -1, 888, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
916 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
917 {, S
, MIIM_TYPE
|MIIM_ID
, MFT_STRING
, -9, 888, 0, -9, -9, -9, string
, 4, 0, },
920 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
, -1, -1, -1, -1, -1, 999, txt
, 6, -1, }, OK
)
921 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
922 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
, -9, -9, 0, -9, -9, 999, string
, 4, 0, },
925 /* to be continued */
926 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
927 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
928 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
929 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
932 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
933 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
934 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
935 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
938 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
939 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
940 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
943 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
944 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
945 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
948 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
949 TMII_GMII ( {, S
, 0, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
950 {, S
, 0, -9, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
953 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
954 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
955 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
956 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
959 /* same but retrieve with MIIM_TYPE */
960 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
961 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
962 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
965 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
966 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
967 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
970 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
971 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
972 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
976 /* How is that with bitmaps? */
977 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
978 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
979 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
982 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
983 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
984 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, 0, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
987 /* MIIM_BITMAP does not like MFT_BITMAP */
988 TMII_INSMI( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, ER
)
989 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
990 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
993 /* no problem with OWNERDRAWN */
994 TMII_INSMI( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
995 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
996 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
999 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
1000 TMII_INSMI( {, S
, MIIM_FTYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER
)
1001 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1002 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1006 /* menu with submenu */
1007 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, txt
, 0, -1, }, OK
)
1008 TMII_GMII ( {, S
, MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1009 {, S
, MIIM_SUBMENU
, -9, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1012 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, empty
, 0, -1, }, OK
)
1013 TMII_GMII ( {, S
, MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1014 {, S
, MIIM_SUBMENU
, -9, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1017 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
1018 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, txt
, 0, -1, }, OK
)
1019 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1020 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
1022 TMII_GMII ( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1023 {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1026 /* menu with invalid submenu */
1027 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, 999, -1, -1, -1, txt
, 0, -1, }, ER
)
1028 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1029 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1033 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_SEPARATOR
, 0, 0, 0, 0, 0, 0, txt
, 0, 0, }, OK
)
1034 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1035 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1038 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
1039 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1040 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1043 /* SEPARATOR and STRING go well together */
1044 /* BITMAP and STRING go well together */
1045 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1046 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1047 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, hbm
, },
1050 /* BITMAP, SEPARATOR and STRING go well together */
1051 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1052 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1053 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 4, hbm
, },
1056 /* last two tests, but use MIIM_TYPE to retrieve info */
1057 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
1058 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1059 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1062 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1063 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1064 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1067 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1068 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1069 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1072 /* same three with MFT_OWNERDRAW */
1073 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
1074 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1075 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1078 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1079 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1080 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1083 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1084 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1085 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1089 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
|MIIM_ID
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1090 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1091 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1094 /* test with modifymenu: string is preserved after setting OWNERDRAW */
1095 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1096 TMII_MODM( MFT_OWNERDRAW
, -1, 787, OK
)
1097 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1098 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_DATA
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 787, string
, 4, -9, },
1101 /* same with bitmap: now the text is cleared */
1102 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1103 TMII_MODM( MFT_BITMAP
, 545, hbm
, OK
)
1104 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1105 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_BITMAP
, -9, 545, 0, -9, -9, -9, string
, 0, hbm
, },
1108 /* start with bitmap: now setting text clears it (though he flag is raised) */
1109 TMII_INSMI( {, S
, MIIM_BITMAP
, MFT_STRING
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1110 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1111 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 0, 0, -9, -9, -9, string
, 0, hbm
, },
1113 TMII_MODM( MFT_STRING
, 545, txt
, OK
)
1114 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1115 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 545, 0, -9, -9, -9, string
, 4, 0, },
1118 /*repeat with text NULL */
1119 TMII_INSMI( {, S
, MIIM_BITMAP
, MFT_STRING
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1120 TMII_MODM( MFT_STRING
, 545, NULL
, OK
)
1121 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1122 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_SEPARATOR
, -9, 545, 0, -9, -9, -9, string
, 0, 0, },
1125 /* repeat with text "" */
1126 TMII_INSMI( {, S
, MIIM_BITMAP
, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1127 TMII_MODM( MFT_STRING
, 545, empty
, OK
)
1128 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1129 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 545, 0, -9, -9, -9, string
, 0, 0, },
1132 /* start with bitmap: set ownerdraw */
1133 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1134 TMII_MODM( MFT_OWNERDRAW
, -1, 232, OK
)
1135 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1136 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_DATA
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 232, string
, 0, hbm
, },
1140 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1141 TMII_GMII ( {, S
, 0, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1142 {, S
, 0, -9, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
1145 /* some tests with small cbSize: the hbmpItem is to be ignored */
1146 TMII_INSMI( {, S
- 4, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1147 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1148 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1151 TMII_INSMI( {, S
- 4, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1152 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1153 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 80, NULL
, },
1156 TMII_INSMI( {, S
- 4, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1157 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1158 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, NULL
, },
1161 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1162 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1163 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1166 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1167 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1168 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1171 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1172 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1173 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1176 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1177 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1178 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1179 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1182 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1183 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1184 {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1187 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1188 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1189 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1192 /* set a string menu to ownerdraw with MIIM_TYPE */
1193 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -2, -2, -2, -2, -2, -2, txt
, -2, -2, }, OK
)
1194 TMII_SMII( {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1195 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1196 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
1199 /* test with modifymenu add submenu */
1200 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1201 TMII_MODM( MF_POPUP
, submenu
, txt
, OK
)
1202 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1203 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_SUBMENU
, MFT_STRING
, -9, -9, submenu
, -9, -9, -9, string
, 4, -9, },
1205 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1206 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
1209 /* MFT_SEPARATOR bit is kept when the text is added */
1210 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1211 TMII_SMII( {, S
, MIIM_STRING
, -1, -1, -1, -1, -1, -1, -1, txt
, -1, -1, }, OK
)
1212 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1213 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
1216 /* MFT_SEPARATOR bit is kept when bitmap is added */
1217 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1218 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1219 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1220 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
1223 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1224 Only the low word of the dwTypeData is used.
1225 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1226 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE
, 0x1234), -1, -1, }, OK
)
1227 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1228 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE
, 0, HBMMENU_MBAR_CLOSE
, },
1232 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
)
1233 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1234 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_MENUBARBREAK
| MFT_RADIOCHECK
| MFT_RIGHTJUSTIFY
| MFT_RIGHTORDER
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1238 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1239 TMII_SMII( {, S
, MIIM_STATE
, -1, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1240 TMII_GMII ( {, S
, MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1241 {, S
, MIIM_STATE
, -9, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -9, 0, -9, -9, -9, -9, -9, -9, },
1244 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1245 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1246 TMII_SMII( {, S
, MIIM_CHECKMARKS
, MFT_RADIOCHECK
, -1, -1, -1, hbm
, hbm
, -1, -1, -1, -1, }, OK
)
1247 TMII_GMII ( {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1248 {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, hbm
, hbm
, -9, hbm
, 0, hbm
, },
1251 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1252 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1253 TMII_SMII( {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK
)
1254 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1255 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1257 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1258 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1260 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1261 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1263 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL
, }, OK
)
1264 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1265 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1268 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1269 Only the low word of the dwTypeData is used.
1270 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1271 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE
, 0x1234), -1, -1, }, OK
)
1272 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1273 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE
, 0, HBMMENU_MBAR_CLOSE
, },
1277 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
)
1278 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1279 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_MENUBARBREAK
| MFT_RADIOCHECK
| MFT_RIGHTJUSTIFY
| MFT_RIGHTORDER
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1283 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1284 TMII_SMII( {, S
, MIIM_STATE
, -1, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1285 TMII_GMII ( {, S
, MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1286 {, S
, MIIM_STATE
, -9, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -9, 0, -9, -9, -9, -9, -9, -9, },
1289 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1290 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1291 TMII_SMII( {, S
, MIIM_CHECKMARKS
, MFT_RADIOCHECK
, -1, -1, -1, hbm
, hbm
, -1, -1, -1, -1, }, OK
)
1292 TMII_GMII ( {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1293 {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, hbm
, hbm
, -9, hbm
, 0, hbm
, },
1296 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1297 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1298 TMII_SMII( {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK
)
1299 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1300 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1302 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1303 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1305 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1306 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1308 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL
, }, OK
)
1309 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1310 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1313 } while( !(ansi
= !ansi
) );
1318 The following tests try to confirm the algorithm used to return the menu items
1319 when there is a collision between a menu item and a popup menu
1321 static void test_menu_search_bycommand( void )
1323 HMENU hmenu
, hmenuSub
, hmenuSub2
;
1329 static CHAR menuitem
[] = "MenuItem",
1330 menuitem2
[] = "MenuItem 2";
1332 /* Case 1: Menu containing a menu item */
1333 hmenu
= CreateMenu();
1335 memset( &info
, 0, sizeof info
);
1336 info
.cbSize
= sizeof info
;
1337 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1338 info
.fType
= MFT_STRING
;
1339 strcpy(strIn
, "Case 1 MenuItem");
1340 info
.dwTypeData
= strIn
;
1341 info
.wID
= (UINT
) 0x1234;
1343 rc
= InsertMenuItem(hmenu
, 0, TRUE
, &info
);
1344 ok (rc
, "Inserting the menuitem failed\n");
1346 id
= GetMenuItemID(hmenu
, 0);
1347 ok (id
== 0x1234, "Getting the menuitem id failed(gave %x)\n", id
);
1349 /* Confirm the menuitem was given the id supplied (getting by position) */
1350 memset( &info
, 0, sizeof info
);
1352 info
.cbSize
= sizeof(MENUITEMINFO
);
1353 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1354 info
.dwTypeData
= strback
;
1355 info
.cch
= sizeof(strback
);
1357 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
); /* Get by position */
1358 ok (rc
, "Getting the menu items info failed\n");
1359 ok (info
.wID
== 0x1234, "IDs differ for the menuitem\n");
1360 ok (!strcmp(info
.dwTypeData
, "Case 1 MenuItem"), "Returned item has wrong label\n");
1362 /* Search by id - Should return the item */
1363 memset( &info
, 0, sizeof info
);
1365 info
.cbSize
= sizeof(MENUITEMINFO
);
1366 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1367 info
.dwTypeData
= strback
;
1368 info
.cch
= sizeof(strback
);
1369 rc
= GetMenuItemInfo(hmenu
, 0x1234, FALSE
, &info
); /* Get by ID */
1371 ok (rc
, "Getting the menu items info failed\n");
1372 ok (info
.wID
== 0x1234, "IDs differ for the menuitem\n");
1373 ok (!strcmp(info
.dwTypeData
, "Case 1 MenuItem"), "Returned item has wrong label\n");
1375 DestroyMenu( hmenu
);
1377 /* Case 2: Menu containing a popup menu */
1378 hmenu
= CreateMenu();
1379 hmenuSub
= CreateMenu();
1381 strcpy(strIn
, "Case 2 SubMenu");
1382 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, strIn
);
1383 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1385 id
= GetMenuItemID(hmenu
, 0);
1386 ok (id
== -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id
);
1388 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1389 memset( &info
, 0, sizeof info
);
1391 info
.cbSize
= sizeof(MENUITEMINFO
);
1392 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1393 info
.dwTypeData
= strback
;
1394 info
.cch
= sizeof(strback
);
1395 info
.wID
= 0xdeadbeef;
1397 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
); /* Get by position */
1398 ok (rc
, "Getting the menu items info failed\n");
1399 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the menuitem\n");
1400 ok (!strcmp(info
.dwTypeData
, "Case 2 SubMenu"), "Returned item has wrong label\n");
1402 /* Search by id - returns the popup menu itself */
1403 memset( &info
, 0, sizeof info
);
1405 info
.cbSize
= sizeof(MENUITEMINFO
);
1406 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1407 info
.dwTypeData
= strback
;
1408 info
.cch
= sizeof(strback
);
1409 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1411 ok (rc
, "Getting the menu items info failed\n");
1412 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1413 ok (!strcmp(info
.dwTypeData
, "Case 2 SubMenu"), "Returned item has wrong label\n");
1416 Now add an item after it with the same id
1418 memset( &info
, 0, sizeof info
);
1419 info
.cbSize
= sizeof info
;
1420 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1421 info
.fType
= MFT_STRING
;
1422 strcpy(strIn
, "Case 2 MenuItem 1");
1423 info
.dwTypeData
= strIn
;
1424 info
.wID
= (UINT_PTR
) hmenuSub
;
1425 rc
= InsertMenuItem(hmenu
, -1, TRUE
, &info
);
1426 ok (rc
, "Inserting the menuitem failed\n");
1428 /* Search by id - returns the item which follows the popup menu */
1429 memset( &info
, 0, sizeof info
);
1431 info
.cbSize
= sizeof(MENUITEMINFO
);
1432 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1433 info
.dwTypeData
= strback
;
1434 info
.cch
= sizeof(strback
);
1435 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1437 ok (rc
, "Getting the menu items info failed\n");
1438 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1439 ok (!strcmp(info
.dwTypeData
, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1442 Now add an item before the popup (with the same id)
1444 memset( &info
, 0, sizeof info
);
1445 info
.cbSize
= sizeof info
;
1446 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1447 info
.fType
= MFT_STRING
;
1448 strcpy(strIn
, "Case 2 MenuItem 2");
1449 info
.dwTypeData
= strIn
;
1450 info
.wID
= (UINT_PTR
) hmenuSub
;
1451 rc
= InsertMenuItem(hmenu
, 0, TRUE
, &info
);
1452 ok (rc
, "Inserting the menuitem failed\n");
1454 /* Search by id - returns the item which precedes the popup menu */
1455 memset( &info
, 0, sizeof info
);
1457 info
.cbSize
= sizeof(MENUITEMINFO
);
1458 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1459 info
.dwTypeData
= strback
;
1460 info
.cch
= sizeof(strback
);
1461 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1463 ok (rc
, "Getting the menu items info failed\n");
1464 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1465 ok (!strcmp(info
.dwTypeData
, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1467 DestroyMenu( hmenu
);
1468 DestroyMenu( hmenuSub
);
1471 Case 3: Menu containing a popup menu which in turn
1472 contains 2 items with the same id as the popup itself
1475 hmenu
= CreateMenu();
1476 hmenuSub
= CreateMenu();
1478 memset( &info
, 0, sizeof info
);
1479 info
.cbSize
= sizeof info
;
1480 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1481 info
.fType
= MFT_STRING
;
1482 info
.dwTypeData
= menuitem
;
1483 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1485 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1486 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1488 rc
= InsertMenuItem(hmenuSub
, 0, TRUE
, &info
);
1489 ok (rc
, "Inserting the sub menu menuitem failed\n");
1491 memset( &info
, 0, sizeof info
);
1492 info
.cbSize
= sizeof info
;
1493 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1494 info
.fType
= MFT_STRING
;
1495 info
.dwTypeData
= menuitem2
;
1496 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1498 rc
= InsertMenuItem(hmenuSub
, 1, TRUE
, &info
);
1499 ok (rc
, "Inserting the sub menu menuitem 2 failed\n");
1501 /* Prove that you can't query the id of a popup directly (By position) */
1502 id
= GetMenuItemID(hmenu
, 0);
1503 ok (id
== -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id
);
1505 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1506 memset( &info
, 0, sizeof info
);
1508 info
.cbSize
= sizeof(MENUITEMINFO
);
1509 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1510 info
.dwTypeData
= strback
;
1511 info
.cch
= sizeof(strback
);
1513 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
);
1514 ok (rc
, "Getting the menus info failed\n");
1515 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for popup menu\n");
1516 ok (!strcmp(info
.dwTypeData
, "MenuItem"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1517 DestroyMenu( hmenu
);
1518 DestroyMenu( hmenuSub
);
1521 Case 4: Menu containing 2 popup menus, the second
1522 contains 2 items with the same id as the first popup menu
1524 hmenu
= CreateMenu();
1525 hmenuSub
= CreateMenu();
1526 hmenuSub2
= CreateMenu();
1528 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1529 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1531 rc
= InsertMenu(hmenu
, 1, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub2
, "Submenu2");
1532 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1534 memset( &info
, 0, sizeof info
);
1535 info
.cbSize
= sizeof info
;
1536 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1537 info
.fType
= MFT_STRING
;
1538 info
.dwTypeData
= menuitem
;
1539 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1541 rc
= InsertMenuItem(hmenuSub2
, 0, TRUE
, &info
);
1542 ok (rc
, "Inserting the sub menu menuitem failed\n");
1544 memset( &info
, 0, sizeof info
);
1545 info
.cbSize
= sizeof info
;
1546 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1547 info
.fType
= MFT_STRING
;
1548 info
.dwTypeData
= menuitem2
;
1549 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1551 rc
= InsertMenuItem(hmenuSub2
, 1, TRUE
, &info
);
1552 ok (rc
, "Inserting the sub menu menuitem 2 failed\n");
1554 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1555 memset( &info
, 0, sizeof info
);
1557 info
.cbSize
= sizeof(MENUITEMINFO
);
1558 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1559 info
.dwTypeData
= strback
;
1560 info
.cch
= sizeof(strback
);
1562 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
);
1563 ok (rc
, "Getting the menus info failed\n");
1564 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for popup menu\n");
1565 ok (!strcmp(info
.dwTypeData
, "MenuItem"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1567 memset( &info
, 0, sizeof info
);
1569 info
.cbSize
= sizeof(MENUITEMINFO
);
1570 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1571 info
.dwTypeData
= strback
;
1572 info
.cch
= sizeof(strback
);
1574 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub2
, FALSE
, &info
);
1575 ok (rc
, "Getting the menus info failed\n");
1576 ok (info
.wID
== (UINT
)hmenuSub2
, "IDs differ for popup menu\n");
1577 ok (!strcmp(info
.dwTypeData
, "Submenu2"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1579 DestroyMenu( hmenu
);
1580 DestroyMenu( hmenuSub
);
1581 DestroyMenu( hmenuSub2
);
1585 Case 5: Menu containing a popup menu which in turn
1586 contains an item with a different id than the popup menu.
1587 This tests the fallback to a popup menu ID.
1590 hmenu
= CreateMenu();
1591 hmenuSub
= CreateMenu();
1593 rc
= AppendMenu(hmenu
, MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1594 ok (rc
, "Appending the popup menu to the main menu failed\n");
1596 rc
= AppendMenu(hmenuSub
, MF_STRING
, 102, "Item");
1597 ok (rc
, "Appending the item to the popup menu failed\n");
1599 /* Set the ID for hmenuSub */
1600 info
.cbSize
= sizeof(info
);
1601 info
.fMask
= MIIM_ID
;
1604 rc
= SetMenuItemInfo(hmenu
, 0, TRUE
, &info
);
1605 ok(rc
, "Setting the ID for the popup menu failed\n");
1607 /* Check if the ID has been set */
1609 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
);
1610 ok(rc
, "Getting the ID for the popup menu failed\n");
1611 ok(info
.wID
== 101, "The ID for the popup menu has not been set\n");
1613 /* Prove getting the item info via ID returns the popup menu */
1614 memset( &info
, 0, sizeof(info
));
1616 info
.cbSize
= sizeof(MENUITEMINFO
);
1617 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1618 info
.dwTypeData
= strback
;
1619 info
.cch
= sizeof(strback
);
1621 rc
= GetMenuItemInfo(hmenu
, 101, FALSE
, &info
);
1622 ok (rc
, "Getting the menu info failed\n");
1623 ok (info
.wID
== 101, "IDs differ\n");
1624 ok (!strcmp(info
.dwTypeData
, "Submenu"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1626 /* Also look for the menu item */
1627 memset( &info
, 0, sizeof(info
));
1629 info
.cbSize
= sizeof(MENUITEMINFO
);
1630 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1631 info
.dwTypeData
= strback
;
1632 info
.cch
= sizeof(strback
);
1634 rc
= GetMenuItemInfo(hmenu
, 102, FALSE
, &info
);
1635 ok (rc
, "Getting the menu info failed\n");
1636 ok (info
.wID
== 102, "IDs differ\n");
1637 ok (!strcmp(info
.dwTypeData
, "Item"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1640 DestroyMenu(hmenuSub
);
1643 struct menu_item_pair_s
{
1644 UINT uMenu
; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1645 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1646 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1650 static struct menu_mouse_tests_s
{
1652 struct menu_item_pair_s menu_item_pairs
[5]; /* for mousing */
1653 WORD wVk
[5]; /* keys */
1657 /* for each test, send keys or clicks and check for menu visibility */
1658 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
}, /* test 0 */
1659 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, 0}, FALSE
, FALSE
},
1660 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
},
1661 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1662 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
},
1663 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1664 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1665 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, VK_ESCAPE
, 0}, FALSE
, FALSE
},
1666 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', VK_ESCAPE
, 0}, TRUE
, FALSE
},
1667 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, 0}, FALSE
, FALSE
},
1668 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1669 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1670 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1671 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1672 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 'P', 0}, TRUE
, FALSE
},
1673 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1674 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 'P', 0}, TRUE
, FALSE
},
1675 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1677 { INPUT_MOUSE
, {{1, 2}, {0}}, {0}, TRUE
, TRUE
}, /* test 18 */
1678 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1679 { INPUT_MOUSE
, {{1, 0}, {0}}, {0}, TRUE
, TRUE
},
1680 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1681 { INPUT_MOUSE
, {{1, 0}, {2, 2}, {0}}, {0}, TRUE
, TRUE
},
1682 { INPUT_MOUSE
, {{2, 1}, {0}}, {0}, FALSE
, FALSE
},
1683 { INPUT_MOUSE
, {{1, 0}, {2, 0}, {0}}, {0}, TRUE
, TRUE
},
1684 { INPUT_MOUSE
, {{3, 0}, {0}}, {0}, FALSE
, FALSE
},
1685 { INPUT_MOUSE
, {{1, 0}, {2, 0}, {0}}, {0}, TRUE
, TRUE
},
1686 { INPUT_MOUSE
, {{3, 1}, {0}}, {0}, TRUE
, TRUE
},
1687 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1691 static void send_key(WORD wVk
)
1694 memset(i
, 0, sizeof(i
));
1695 i
[0].type
= i
[1].type
= INPUT_KEYBOARD
;
1696 i
[0].u
.ki
.wVk
= i
[1].u
.ki
.wVk
= wVk
;
1697 i
[1].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1698 pSendInput(2, (INPUT
*) i
, sizeof(INPUT
));
1701 static void click_menu(HANDLE hWnd
, struct menu_item_pair_s
*mi
)
1703 HMENU hMenu
= hMenus
[mi
->uMenu
];
1707 int screen_w
= GetSystemMetrics(SM_CXSCREEN
);
1708 int screen_h
= GetSystemMetrics(SM_CYSCREEN
);
1709 BOOL ret
= GetMenuItemRect(mi
->uMenu
> 2 ? NULL
: hWnd
, hMenu
, mi
->uItem
, &r
);
1712 memset(i
, 0, sizeof(i
));
1713 i
[0].type
= i
[1].type
= i
[2].type
= INPUT_MOUSE
;
1714 i
[0].u
.mi
.dx
= i
[1].u
.mi
.dx
= i
[2].u
.mi
.dx
1715 = ((r
.left
+ 5) * 65535) / screen_w
;
1716 i
[0].u
.mi
.dy
= i
[1].u
.mi
.dy
= i
[2].u
.mi
.dy
1717 = ((r
.top
+ 5) * 65535) / screen_h
;
1718 i
[0].u
.mi
.dwFlags
= i
[1].u
.mi
.dwFlags
= i
[2].u
.mi
.dwFlags
1719 = MOUSEEVENTF_ABSOLUTE
;
1720 i
[0].u
.mi
.dwFlags
|= MOUSEEVENTF_MOVE
;
1721 i
[1].u
.mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
1722 i
[2].u
.mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
1723 pSendInput(3, (INPUT
*) i
, sizeof(INPUT
));
1725 /* hack to prevent mouse message buildup in Wine */
1726 while (PeekMessage( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
1729 static DWORD WINAPI
test_menu_input_thread(LPVOID lpParameter
)
1732 HANDLE hWnd
= lpParameter
;
1735 /* mixed keyboard/mouse test */
1736 for (i
= 0; menu_tests
[i
].type
!= -1; i
++)
1740 if (menu_tests
[i
].type
== INPUT_KEYBOARD
)
1741 for (j
= 0; menu_tests
[i
].wVk
[j
] != 0; j
++)
1742 send_key(menu_tests
[i
].wVk
[j
]);
1744 for (j
= 0; menu_tests
[i
].menu_item_pairs
[j
].uMenu
!= 0; j
++)
1745 click_menu(hWnd
, &menu_tests
[i
].menu_item_pairs
[j
]);
1747 while (menu_tests
[i
].bMenuVisible
!= bMenuVisible
)
1755 if (menu_tests
[i
]._todo_wine
)
1758 ok(menu_tests
[i
].bMenuVisible
== bMenuVisible
, "test %d\n", i
);
1762 ok(menu_tests
[i
].bMenuVisible
== bMenuVisible
, "test %d\n", i
);
1767 static LRESULT CALLBACK
WndProc(HWND hWnd
, UINT msg
, WPARAM wParam
,
1771 case WM_ENTERMENULOOP
:
1772 bMenuVisible
= TRUE
;
1774 case WM_EXITMENULOOP
:
1775 bMenuVisible
= FALSE
;
1778 return( DefWindowProcA( hWnd
, msg
, wParam
, lParam
) );
1783 static void test_menu_input(void) {
1786 HINSTANCE hInstance
= GetModuleHandleA( NULL
);
1787 HANDLE hThread
, hWnd
;
1789 wclass
.lpszClassName
= "MenuTestClass";
1790 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1791 wclass
.lpfnWndProc
= WndProc
;
1792 wclass
.hInstance
= hInstance
;
1793 wclass
.hIcon
= LoadIconA( 0, (LPSTR
)IDI_APPLICATION
);
1794 wclass
.hCursor
= LoadCursorA( NULL
, (LPSTR
)IDC_ARROW
);
1795 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1);
1796 wclass
.lpszMenuName
= 0;
1797 wclass
.cbClsExtra
= 0;
1798 wclass
.cbWndExtra
= 0;
1799 assert (RegisterClassA( &wclass
));
1800 assert (hWnd
= CreateWindowA( wclass
.lpszClassName
, "MenuTest",
1801 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0,
1802 400, 200, NULL
, NULL
, hInstance
, NULL
) );
1805 hMenus
[3] = CreatePopupMenu();
1806 AppendMenu(hMenus
[3], MF_STRING
, 0, "&Enabled");
1807 AppendMenu(hMenus
[3], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1809 hMenus
[2] = CreatePopupMenu();
1810 AppendMenu(hMenus
[2], MF_STRING
|MF_POPUP
, (UINT_PTR
) hMenus
[3], "&Popup");
1811 AppendMenu(hMenus
[2], MF_STRING
, 0, "&Enabled");
1812 AppendMenu(hMenus
[2], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1814 hMenus
[1] = CreateMenu();
1815 AppendMenu(hMenus
[1], MF_STRING
|MF_POPUP
, (UINT_PTR
) hMenus
[2], "&Menu");
1816 AppendMenu(hMenus
[1], MF_STRING
, 0, "&Enabled");
1817 AppendMenu(hMenus
[1], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1819 SetMenu(hWnd
, hMenus
[1]);
1820 ShowWindow(hWnd
, SW_SHOW
);
1823 hThread
= CreateThread(NULL
, 0, test_menu_input_thread
, hWnd
, 0, NULL
);
1826 if (WAIT_TIMEOUT
!= WaitForSingleObject(hThread
, 50))
1828 while (PeekMessage(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
1830 DestroyWindow(hWnd
);
1833 static void test_menu_flags( void )
1835 HMENU hMenu
, hPopupMenu
;
1837 hMenu
= CreateMenu();
1838 hPopupMenu
= CreatePopupMenu();
1840 AppendMenu(hMenu
, MF_POPUP
| MF_STRING
, (UINT
)hPopupMenu
, "Popup");
1842 AppendMenu(hPopupMenu
, MF_STRING
| MF_HILITE
| MF_DEFAULT
, 101, "Item 1");
1843 InsertMenu(hPopupMenu
, 1, MF_BYPOSITION
| MF_STRING
| MF_HILITE
| MF_DEFAULT
, 102, "Item 2");
1844 AppendMenu(hPopupMenu
, MF_STRING
, 103, "Item 3");
1845 ModifyMenu(hPopupMenu
, 2, MF_BYPOSITION
| MF_STRING
| MF_HILITE
| MF_DEFAULT
, 103, "Item 3");
1847 ok(GetMenuState(hPopupMenu
, 0, MF_BYPOSITION
) & MF_HILITE
,
1848 "AppendMenu should accept MF_HILITE\n");
1849 ok(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
,
1850 "InsertMenu should accept MF_HILITE\n");
1851 ok(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
,
1852 "ModifyMenu should accept MF_HILITE\n");
1854 ok(!(GetMenuState(hPopupMenu
, 0, MF_BYPOSITION
) & MF_DEFAULT
),
1855 "AppendMenu must not accept MF_DEFAULT\n");
1856 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_DEFAULT
),
1857 "InsertMenu must not accept MF_DEFAULT\n");
1858 ok(!(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_DEFAULT
),
1859 "ModifyMenu must not accept MF_DEFAULT\n");
1864 static void test_menu_hilitemenuitem( void )
1866 HMENU hMenu
, hPopupMenu
;
1870 wclass
.lpszClassName
= "HiliteMenuTestClass";
1871 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1872 wclass
.lpfnWndProc
= WndProc
;
1873 wclass
.hInstance
= GetModuleHandleA( NULL
);
1874 wclass
.hIcon
= LoadIconA( 0, (LPSTR
)IDI_APPLICATION
);
1875 wclass
.hCursor
= LoadCursorA( NULL
, (LPSTR
)IDC_ARROW
);
1876 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1);
1877 wclass
.lpszMenuName
= 0;
1878 wclass
.cbClsExtra
= 0;
1879 wclass
.cbWndExtra
= 0;
1880 assert (RegisterClassA( &wclass
));
1881 assert (hWnd
= CreateWindowA( wclass
.lpszClassName
, "HiliteMenuTest",
1882 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0,
1883 400, 200, NULL
, NULL
, wclass
.hInstance
, NULL
) );
1885 hMenu
= CreateMenu();
1886 hPopupMenu
= CreatePopupMenu();
1888 AppendMenu(hMenu
, MF_POPUP
| MF_STRING
, (UINT
)hPopupMenu
, "Popup");
1890 AppendMenu(hPopupMenu
, MF_STRING
, 101, "Item 1");
1891 AppendMenu(hPopupMenu
, MF_STRING
, 102, "Item 2");
1892 AppendMenu(hPopupMenu
, MF_STRING
, 103, "Item 3");
1894 SetMenu(hWnd
, hMenu
);
1896 /* test invalid arguments */
1898 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1899 "HiliteMenuItem: Item 2 is hilited\n");
1901 SetLastError(0xdeadbeef);
1904 ok(!HiliteMenuItem(NULL
, hPopupMenu
, 1, MF_HILITE
| MF_BYPOSITION
),
1905 "HiliteMenuItem: call should have failed.\n");
1907 ok(GetLastError() == 0xdeadbeef || /* 9x */
1908 GetLastError() == ERROR_INVALID_WINDOW_HANDLE
/* NT */,
1909 "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError());
1911 SetLastError(0xdeadbeef);
1912 ok(!HiliteMenuItem(hWnd
, NULL
, 1, MF_HILITE
| MF_BYPOSITION
),
1913 "HiliteMenuItem: call should have failed.\n");
1914 ok(GetLastError() == 0xdeadbeef || /* 9x */
1915 GetLastError() == ERROR_INVALID_MENU_HANDLE
/* NT */,
1916 "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError());
1918 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1919 "HiliteMenuItem: Item 2 is hilited\n");
1921 /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */
1923 SetLastError(0xdeadbeef);
1924 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_BYPOSITION
),
1925 "HiliteMenuItem: call should have succeeded.\n");
1926 ok(GetLastError() == 0xdeadbeef,
1927 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1929 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1930 "HiliteMenuItem: Item 2 is hilited\n");
1932 SetLastError(0xdeadbeef);
1935 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_HILITE
),
1936 "HiliteMenuItem: call should have succeeded.\n");
1938 ok(GetLastError() == 0xdeadbeef,
1939 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1941 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1942 "HiliteMenuItem: Item 2 is hilited\n");
1944 /* hilite a menu item (by position) */
1946 SetLastError(0xdeadbeef);
1947 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_HILITE
| MF_BYPOSITION
),
1948 "HiliteMenuItem: call should not have failed.\n");
1949 ok(GetLastError() == 0xdeadbeef,
1950 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1954 ok(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
,
1955 "HiliteMenuItem: Item 2 is not hilited\n");
1958 /* unhilite a menu item (by position) */
1960 SetLastError(0xdeadbeef);
1961 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_UNHILITE
| MF_BYPOSITION
),
1962 "HiliteMenuItem: call should not have failed.\n");
1963 ok(GetLastError() == 0xdeadbeef,
1964 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1966 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1967 "HiliteMenuItem: Item 2 is hilited\n");
1969 /* hilite a menu item (by command) */
1971 SetLastError(0xdeadbeef);
1972 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 103, MF_HILITE
| MF_BYCOMMAND
),
1973 "HiliteMenuItem: call should not have failed.\n");
1974 ok(GetLastError() == 0xdeadbeef,
1975 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1979 ok(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
,
1980 "HiliteMenuItem: Item 3 is not hilited\n");
1983 /* unhilite a menu item (by command) */
1985 SetLastError(0xdeadbeef);
1986 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 103, MF_UNHILITE
| MF_BYCOMMAND
),
1987 "HiliteMenuItem: call should not have failed.\n");
1988 ok(GetLastError() == 0xdeadbeef,
1989 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1991 ok(!(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
),
1992 "HiliteMenuItem: Item 3 is hilited\n");
1994 DestroyWindow(hWnd
);
1997 static void check_menu_items(HMENU hmenu
, UINT checked_cmd
, UINT checked_type
,
2002 count
= GetMenuItemCount(hmenu
);
2004 for (i
= 0; i
< count
; i
++)
2009 memset(&mii
, 0, sizeof(mii
));
2010 mii
.cbSize
= sizeof(mii
);
2011 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
;
2012 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2013 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2015 trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2016 i
, mii
.fType
, mii
.fState
, mii
.wID
, mii
.hSubMenu
);
2020 ok((HMENU
)mii
.wID
== mii
.hSubMenu
, "id %u: wID should be equal to hSubMenu\n", checked_cmd
);
2021 check_menu_items(mii
.hSubMenu
, checked_cmd
, checked_type
, checked_state
);
2025 if (mii
.wID
== checked_cmd
)
2027 ok(mii
.fType
== checked_type
, "id %u: expected fType %04x, got %04x\n", checked_cmd
, checked_type
, mii
.fType
);
2028 ok(mii
.fState
== checked_state
, "id %u: expected fState %04x, got %04x\n", checked_cmd
, checked_state
, mii
.fState
);
2029 ok(mii
.wID
!= 0, "id %u: not expected wID 0\n", checked_cmd
);
2033 ok(mii
.fType
!= MFT_RADIOCHECK
, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd
, mii
.wID
);
2035 if (mii
.fType
== MFT_SEPARATOR
)
2037 ok(mii
.fState
== MFS_GRAYED
, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd
, mii
.fState
);
2038 ok(mii
.wID
== 0, "id %u: expected wID 0, got %u\n", checked_cmd
, mii
.wID
);
2042 ok(mii
.fState
== 0, "id %u: expected fState 0, got %04x\n", checked_cmd
, mii
.fState
);
2043 ok(mii
.wID
!= 0, "id %u: not expected wID 0\n", checked_cmd
);
2050 static void clear_ftype_and_state(HMENU hmenu
, UINT id
, UINT flags
)
2055 memset(&mii
, 0, sizeof(mii
));
2056 mii
.cbSize
= sizeof(mii
);
2057 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
2058 ret
= SetMenuItemInfo(hmenu
, id
, (flags
& MF_BYPOSITION
) != 0, &mii
);
2059 ok(ret
, "SetMenuItemInfo(%u) failed\n", id
);
2062 static void test_CheckMenuRadioItem(void)
2067 hmenu
= LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1));
2070 check_menu_items(hmenu
, -1, 0, 0);
2072 ret
= CheckMenuRadioItem(hmenu
, 100, 100, 100, MF_BYCOMMAND
);
2073 ok(ret
, "CheckMenuRadioItem failed\n");
2074 check_menu_items(hmenu
, 100, MFT_RADIOCHECK
, MFS_CHECKED
);
2076 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2077 ret
= CheckMenuRadioItem(hmenu
, 100, 100, -1, MF_BYCOMMAND
);
2078 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2079 check_menu_items(hmenu
, 100, MFT_RADIOCHECK
, 0);
2082 clear_ftype_and_state(hmenu
, 100, MF_BYCOMMAND
);
2083 check_menu_items(hmenu
, -1, 0, 0);
2085 /* first and checked items are on different menus */
2086 ret
= CheckMenuRadioItem(hmenu
, 0, 300, 202, MF_BYCOMMAND
);
2087 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2088 check_menu_items(hmenu
, -1, 0, 0);
2090 ret
= CheckMenuRadioItem(hmenu
, 200, 300, 202, MF_BYCOMMAND
);
2091 ok(ret
, "CheckMenuRadioItem failed\n");
2092 check_menu_items(hmenu
, 202, MFT_RADIOCHECK
, MFS_CHECKED
);
2094 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2095 ret
= CheckMenuRadioItem(hmenu
, 202, 202, -1, MF_BYCOMMAND
);
2096 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2097 check_menu_items(hmenu
, 202, MFT_RADIOCHECK
, 0);
2100 clear_ftype_and_state(hmenu
, 202, MF_BYCOMMAND
);
2101 check_menu_items(hmenu
, -1, 0, 0);
2103 /* just for fun, try to check separator */
2104 ret
= CheckMenuRadioItem(hmenu
, 0, 300, 0, MF_BYCOMMAND
);
2105 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2106 check_menu_items(hmenu
, -1, 0, 0);
2109 static void test_menu_resource_layout(void)
2113 MENUITEMTEMPLATEHEADER mith
;
2117 { 0, 0 }, /* versionNumber, offset */
2119 /* mtOption, mtID, mtString[] '\0' terminated */
2120 MF_STRING
, 1, 'F', 0,
2123 /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2124 MF_STRING
|MF_GRAYED
|MF_END
, 5, 'E', 0
2129 UINT type
, state
, id
;
2133 { MF_STRING
, MF_ENABLED
, 1, "F" },
2134 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 2, "" },
2135 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 3, "" },
2136 /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/
2137 { MF_STRING
, MF_GRAYED
, 5, "E" },
2138 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 6, "" },
2139 { MF_STRING
, MF_ENABLED
, 7, "" },
2140 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 8, "" }
2146 hmenu
= LoadMenuIndirect(&menu_template
);
2147 ok(hmenu
!= 0, "LoadMenuIndirect error %u\n", GetLastError());
2149 ret
= AppendMenu(hmenu
, MF_STRING
, 6, NULL
);
2150 ok(ret
, "AppendMenu failed\n");
2151 ret
= AppendMenu(hmenu
, MF_STRING
, 7, "\0");
2152 ok(ret
, "AppendMenu failed\n");
2153 ret
= AppendMenu(hmenu
, MF_SEPARATOR
, 8, "separator");
2154 ok(ret
, "AppendMenu failed\n");
2156 count
= GetMenuItemCount(hmenu
);
2157 ok(count
== sizeof(menu_data
)/sizeof(menu_data
[0]),
2158 "expected %u menu items, got %u\n",
2159 (UINT
)(sizeof(menu_data
)/sizeof(menu_data
[0])), count
);
2161 for (i
= 0; i
< count
; i
++)
2166 memset(&mii
, 0, sizeof(mii
));
2167 mii
.cbSize
= sizeof(mii
);
2168 mii
.dwTypeData
= buf
;
2169 mii
.cch
= sizeof(buf
);
2170 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_ID
| MIIM_STRING
;
2171 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2172 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2174 trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2175 i
, mii
.fType
, mii
.fState
, mii
.wID
, (LPCSTR
)mii
.dwTypeData
);
2177 ok(mii
.fType
== menu_data
[i
].type
,
2178 "%u: expected fType %04x, got %04x\n", i
, menu_data
[i
].type
, mii
.fType
);
2179 ok(mii
.fState
== menu_data
[i
].state
,
2180 "%u: expected fState %04x, got %04x\n", i
, menu_data
[i
].state
, mii
.fState
);
2181 ok(mii
.wID
== menu_data
[i
].id
,
2182 "%u: expected wID %04x, got %04x\n", i
, menu_data
[i
].id
, mii
.wID
);
2183 ok(mii
.cch
== strlen(menu_data
[i
].str
),
2184 "%u: expected cch %u, got %u\n", i
, (UINT
)strlen(menu_data
[i
].str
), mii
.cch
);
2185 ok(!strcmp((LPCSTR
)mii
.dwTypeData
, menu_data
[i
].str
),
2186 "%u: expected dwTypeData %s, got %s\n", i
, menu_data
[i
].str
, (LPCSTR
)mii
.dwTypeData
);
2198 static HMENU
create_menu_from_data(const struct menu_data
*item
, INT item_count
)
2204 hmenu
= CreateMenu();
2207 for (i
= 0; i
< item_count
; i
++)
2209 SetLastError(0xdeadbeef);
2210 ret
= AppendMenu(hmenu
, item
[i
].type
, item
[i
].id
, item
[i
].str
);
2211 ok(ret
, "%d: AppendMenu(%04x, %04x, %p) error %u\n",
2212 i
, item
[i
].type
, item
[i
].id
, item
[i
].str
, GetLastError());
2217 static void compare_menu_data(HMENU hmenu
, const struct menu_data
*item
, INT item_count
)
2222 count
= GetMenuItemCount(hmenu
);
2223 ok(count
== item_count
, "expected %d, got %d menu items\n", count
, item_count
);
2225 for (i
= 0; i
< count
; i
++)
2230 memset(&mii
, 0, sizeof(mii
));
2231 mii
.cbSize
= sizeof(mii
);
2232 mii
.dwTypeData
= buf
;
2233 mii
.cch
= sizeof(buf
);
2234 mii
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
| MIIM_BITMAP
;
2235 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2236 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2238 trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2239 i
, mii
.fType
, mii
.fState
, mii
.wID
, mii
.hbmpItem
);
2241 ok(mii
.fType
== item
[i
].type
,
2242 "%u: expected fType %04x, got %04x\n", i
, item
[i
].type
, mii
.fType
);
2243 ok(mii
.wID
== item
[i
].id
,
2244 "%u: expected wID %04x, got %04x\n", i
, item
[i
].id
, mii
.wID
);
2245 if (item
[i
].type
& (MF_BITMAP
| MF_SEPARATOR
))
2247 /* For some reason Windows sets high word to not 0 for
2250 ok(LOWORD(mii
.hbmpItem
) == LOWORD(item
[i
].str
),
2251 "%u: expected hbmpItem %p, got %p\n", i
, item
[i
].str
, mii
.hbmpItem
);
2255 ok(mii
.cch
== strlen(item
[i
].str
),
2256 "%u: expected cch %u, got %u\n", i
, (UINT
)strlen(item
[i
].str
), mii
.cch
);
2257 ok(!strcmp((LPCSTR
)mii
.dwTypeData
, item
[i
].str
),
2258 "%u: expected dwTypeData %s, got %s\n", i
, item
[i
].str
, (LPCSTR
)mii
.dwTypeData
);
2263 static void test_InsertMenu(void)
2265 /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2266 * regardless of their id.
2268 static const struct menu_data in1
[] =
2270 { MF_STRING
, 1, "File" },
2271 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) },
2272 { MF_STRING
|MF_HELP
, 2, "Help" }
2274 static const struct menu_data out1
[] =
2276 { MF_STRING
, 1, "File" },
2277 { MF_STRING
|MF_HELP
, 2, "Help" },
2278 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) }
2280 static const struct menu_data in2
[] =
2282 { MF_STRING
, 1, "File" },
2283 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(100) },
2284 { MF_STRING
|MF_HELP
, 2, "Help" }
2286 static const struct menu_data out2
[] =
2288 { MF_STRING
, 1, "File" },
2289 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(100) },
2290 { MF_STRING
|MF_HELP
, 2, "Help" }
2292 static const struct menu_data in3
[] =
2294 { MF_STRING
, 1, "File" },
2295 { MF_SEPARATOR
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) },
2296 { MF_STRING
|MF_HELP
, 2, "Help" }
2298 static const struct menu_data out3
[] =
2300 { MF_STRING
, 1, "File" },
2301 { MF_SEPARATOR
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(0) },
2302 { MF_STRING
|MF_HELP
, 2, "Help" },
2304 static const struct menu_data in4
[] =
2306 { MF_STRING
, 1, "File" },
2307 { MF_BITMAP
|MF_HELP
, 1, MAKEINTRESOURCE(1) },
2308 { MF_STRING
|MF_HELP
, 2, "Help" }
2310 static const struct menu_data out4
[] =
2312 { MF_STRING
, 1, "File" },
2313 { MF_STRING
|MF_HELP
, 2, "Help" },
2314 { MF_BITMAP
|MF_HELP
, 1, MAKEINTRESOURCE(1) }
2318 #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0]))
2319 #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0]))
2321 hmenu
= create_menu(in1
);
2322 compare_menu(hmenu
, out1
);
2325 hmenu
= create_menu(in2
);
2326 compare_menu(hmenu
, out2
);
2329 hmenu
= create_menu(in3
);
2330 compare_menu(hmenu
, out3
);
2333 hmenu
= create_menu(in4
);
2334 compare_menu(hmenu
, out4
);
2343 init_function_pointers();
2345 register_menu_check_class();
2347 test_menu_locked_by_window();
2348 test_menu_ownerdraw();
2349 test_menu_add_string();
2350 test_menu_iteminfo();
2351 test_menu_search_bycommand();
2352 test_menu_bmp_and_string();
2355 skip("SendInput is not available\n");
2360 test_menu_hilitemenuitem();
2361 test_CheckMenuRadioItem();
2362 test_menu_resource_layout();