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 BOOL
correct_behavior(void)
68 memset(&info
, 0, sizeof(MENUITEMINFO
));
69 info
.cbSize
= sizeof(MENUITEMINFO
);
70 SetLastError(0xdeadbeef);
71 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
);
73 * NT4 : ERROR_INVALID_PARAMETER
74 * >= W2K : ERROR_MENU_ITEM_NOT_FOUND
76 if (!rc
&& GetLastError() != ERROR_MENU_ITEM_NOT_FOUND
)
78 win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n");
87 static LRESULT WINAPI
menu_check_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
91 case WM_ENTERMENULOOP
:
92 /* mark window as having entered menu loop */
93 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, TRUE
);
94 /* exit menu modal loop
95 * ( A SendMessage does not work on NT3.51 here ) */
96 return PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
98 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
101 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
114 /* globals to communicate between test and wndproc */
116 static BOOL bMenuVisible
;
117 static HMENU hMenus
[4];
120 #define MOD_NRMENUS 8
122 /* menu texts with their sizes */
125 SIZE size
; /* size of text up to any \t */
126 SIZE sc_size
; /* size of the short-cut */
130 { "Shira&z\tAlt+S" },
135 static unsigned int MOD_maxid
;
136 static RECT MOD_rc
[MOD_NRMENUS
];
137 static int MOD_avec
, MOD_hic
;
138 static int MOD_odheight
;
139 static SIZE MODsizes
[MOD_NRMENUS
]= { {MOD_SIZE
, MOD_SIZE
},{MOD_SIZE
, MOD_SIZE
},
140 {MOD_SIZE
, MOD_SIZE
},{MOD_SIZE
, MOD_SIZE
}};
141 static int MOD_GotDrawItemMsg
= FALSE
;
142 /* wndproc used by test_menu_ownerdraw() */
143 static LRESULT WINAPI
menu_ownerdraw_wnd_proc(HWND hwnd
, UINT msg
,
144 WPARAM wparam
, LPARAM lparam
)
150 MEASUREITEMSTRUCT
* pmis
= (MEASUREITEMSTRUCT
*)lparam
;
152 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
153 pmis
->itemData
, pmis
->itemWidth
, pmis
->itemHeight
);
154 MOD_odheight
= pmis
->itemHeight
;
155 pmis
->itemWidth
= MODsizes
[pmis
->itemData
].cx
;
156 pmis
->itemHeight
= MODsizes
[pmis
->itemData
].cy
;
161 DRAWITEMSTRUCT
* pdis
;
164 char chrs
[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
167 pdis
= (DRAWITEMSTRUCT
*) lparam
;
168 if( winetest_debug
) {
170 GetMenuItemRect( hwnd
, (HMENU
)pdis
->hwndItem
, pdis
->itemData
,&rc
);
171 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
172 hwnd
, (HMENU
)pdis
->hwndItem
, pdis
->itemData
,
173 pdis
->itemID
, pdis
->rcItem
.left
, pdis
->rcItem
.top
,
174 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
,
175 rc
.left
,rc
.top
,rc
.right
,rc
.bottom
);
176 oldpen
=SelectObject( pdis
->hDC
, GetStockObject(
177 pdis
->itemState
& ODS_SELECTED
? WHITE_PEN
:BLACK_PEN
));
178 Rectangle( pdis
->hDC
, pdis
->rcItem
.left
,pdis
->rcItem
.top
,
179 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
);
180 SelectObject( pdis
->hDC
, oldpen
);
182 /* calculate widths of some menu texts */
183 if( ! MOD_txtsizes
[0].size
.cx
)
184 for(i
= 0; MOD_txtsizes
[i
].text
; i
++) {
187 strcpy( buf
, MOD_txtsizes
[i
].text
);
188 if( ( p
= strchr( buf
, '\t'))) {
190 DrawText( pdis
->hDC
, p
+ 1, -1, &rc
,
191 DT_SINGLELINE
|DT_CALCRECT
);
192 MOD_txtsizes
[i
].sc_size
.cx
= rc
.right
- rc
.left
;
193 MOD_txtsizes
[i
].sc_size
.cy
= rc
.bottom
- rc
.top
;
195 DrawText( pdis
->hDC
, buf
, -1, &rc
,
196 DT_SINGLELINE
|DT_CALCRECT
);
197 MOD_txtsizes
[i
].size
.cx
= rc
.right
- rc
.left
;
198 MOD_txtsizes
[i
].size
.cy
= rc
.bottom
- rc
.top
;
201 if( pdis
->itemData
> MOD_maxid
) return TRUE
;
202 /* store the rectangl */
203 MOD_rc
[pdis
->itemData
] = pdis
->rcItem
;
204 /* calculate average character width */
205 GetTextExtentPoint( pdis
->hDC
, chrs
, 52, &sz
);
206 MOD_avec
= (sz
.cx
+ 26)/52;
207 GetTextMetrics( pdis
->hDC
, &tm
);
208 MOD_hic
= tm
.tmHeight
;
209 MOD_GotDrawItemMsg
= TRUE
;
214 PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
219 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
222 static void register_menu_check_class(void)
230 GetModuleHandle(NULL
),
232 LoadCursor(NULL
, IDC_ARROW
),
233 (HBRUSH
)(COLOR_BTNFACE
+1),
235 TEXT("WineMenuCheck"),
238 atomMenuCheckClass
= RegisterClass(&wc
);
241 /* demonstrates that windows locks the menu object so that it is still valid
242 * even after a client calls DestroyMenu on it */
243 static void test_menu_locked_by_window(void)
247 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
248 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
249 NULL
, NULL
, NULL
, NULL
);
250 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
251 hmenu
= CreateMenu();
252 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
253 ret
= InsertMenu(hmenu
, 0, MF_STRING
, 0, TEXT("&Test"));
254 ok(ret
, "InsertMenu failed with error %d\n", GetLastError());
255 ret
= SetMenu(hwnd
, hmenu
);
256 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
257 ret
= DestroyMenu(hmenu
);
258 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
260 ret
= DrawMenuBar(hwnd
);
262 ok(ret
, "DrawMenuBar failed with error %d\n", GetLastError());
264 ret
= IsMenu(GetMenu(hwnd
));
265 ok(!ret
, "Menu handle should have been destroyed\n");
267 SendMessage(hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, 0);
268 /* did we process the WM_INITMENU message? */
269 ret
= GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
271 ok(ret
, "WM_INITMENU should have been sent\n");
277 static void test_menu_ownerdraw(void)
283 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
284 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
285 NULL
, NULL
, NULL
, NULL
);
286 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
288 SetWindowLongPtr( hwnd
, GWLP_WNDPROC
, (LONG
)menu_ownerdraw_wnd_proc
);
289 hmenu
= CreatePopupMenu();
290 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
291 if( !hmenu
) { DestroyWindow(hwnd
);return;}
293 for( j
=0;j
<2;j
++) /* create columns */
294 for(i
=0;i
<2;i
++) { /* create rows */
295 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
|
296 (i
==0 ? MF_MENUBREAK
: 0), k
, (LPCTSTR
) k
);
298 ok( ret
, "AppendMenu failed for %d\n", k
-1);
301 assert( k
<= sizeof(MOD_rc
)/sizeof(RECT
));
302 /* display the menu */
303 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
305 /* columns have a 4 pixel gap between them */
306 ok( MOD_rc
[0].right
+ 4 == MOD_rc
[2].left
,
307 "item rectangles are not separated by 4 pixels space\n");
308 /* height should be what the MEASUREITEM message has returned */
309 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
310 "menu item has wrong height: %d should be %d\n",
311 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
312 /* no gaps between the rows */
313 ok( MOD_rc
[0].bottom
- MOD_rc
[1].top
== 0,
314 "There should not be a space between the rows, gap is %d\n",
315 MOD_rc
[0].bottom
- MOD_rc
[1].top
);
316 /* test the correct value of the item height that was sent
317 * by the WM_MEASUREITEM message */
318 ok( MOD_odheight
== HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
319 MOD_odheight
== MOD_hic
, /* Win95,98,ME */
320 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
321 HIWORD( GetDialogBaseUnits()), MOD_hic
, MOD_odheight
);
322 /* test what MF_MENUBREAK did at the first position. Also show
323 * that an MF_SEPARATOR is ignored in the height calculation. */
324 leftcol
= MOD_rc
[0].left
;
325 ModifyMenu( hmenu
, 0, MF_BYCOMMAND
| MF_OWNERDRAW
| MF_SEPARATOR
, 0, 0);
326 /* display the menu */
327 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
328 /* left should be 4 pixels less now */
329 ok( leftcol
== MOD_rc
[0].left
+ 4,
330 "columns should be 4 pixels to the left (actual %d).\n",
331 leftcol
- MOD_rc
[0].left
);
333 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
334 "width of owner drawn menu item is wrong. Got %d expected %d\n",
335 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
337 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
338 "Height is incorrect. Got %d expected %d\n",
339 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
341 /* test width/height of an ownerdraw menu bar as well */
342 ret
= DestroyMenu(hmenu
);
343 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
344 hmenu
= CreateMenu();
345 ok(hmenu
!= NULL
, "CreateMenu failed with error %d\n", GetLastError());
346 if( !hmenu
) { DestroyWindow(hwnd
);return;}
349 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
, i
, 0);
350 ok( ret
, "AppendMenu failed for %d\n", i
);
352 ret
= SetMenu( hwnd
, hmenu
);
353 UpdateWindow( hwnd
); /* hack for wine to draw the window + menu */
354 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
356 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
357 "width of owner drawn menu item is wrong. Got %d expected %d\n",
358 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
360 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== GetSystemMetrics( SM_CYMENU
) - 1,
361 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
362 MOD_rc
[0].bottom
- MOD_rc
[0].top
, GetSystemMetrics( SM_CYMENU
) - 1);
365 ret
= DestroyMenu(hmenu
);
366 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
370 /* helper for test_menu_bmp_and_string() */
371 static void test_mbs_help( int ispop
, int hassub
, int mnuopt
,
372 HWND hwnd
, int arrowwidth
, int count
, HBITMAP hbmp
,
373 SIZE bmpsize
, LPCSTR text
, SIZE size
, SIZE sc_size
)
376 HMENU hmenu
, submenu
;
377 MENUITEMINFO mii
={ sizeof( MENUITEMINFO
)};
384 MOD_GotDrawItemMsg
= FALSE
;
385 mii
.fMask
= MIIM_FTYPE
| MIIM_DATA
| MIIM_STATE
;
387 /* check the menu item unless MNS_CHECKORBMP is set */
388 mii
.fState
= (mnuopt
!= 2 ? MFS_CHECKED
: MFS_UNCHECKED
);
390 MODsizes
[0] = bmpsize
;
394 mii
.fMask
|= MIIM_STRING
;
395 strcpy(text_copy
, text
);
396 mii
.dwTypeData
= text_copy
; /* structure member declared non-const */
397 if( ( p
= strchr( text
, '\t'))) {
398 hastab
= *(p
+ 1) ? 2 : 1;
401 /* tabs don't make sense in menubars */
402 if(hastab
&& !ispop
) return;
404 mii
.fMask
|= MIIM_BITMAP
;
407 submenu
= CreateMenu();
408 ok( submenu
!= 0, "CreateMenu failed with error %d\n", GetLastError());
410 hmenu
= CreatePopupMenu();
412 hmenu
= CreateMenu();
413 ok( hmenu
!= 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
415 mii
.fMask
|= MIIM_SUBMENU
;
416 mii
.hSubMenu
= submenu
;
419 mi
.cbSize
= sizeof(mi
);
420 mi
.fMask
= MIM_STYLE
;
421 pGetMenuInfo( hmenu
, &mi
);
422 mi
.dwStyle
|= mnuopt
== 1 ? MNS_NOCHECK
: MNS_CHECKORBMP
;
423 ret
= pSetMenuInfo( hmenu
, &mi
);
424 ok( ret
, "SetMenuInfo failed with error %d\n", GetLastError());
426 ret
= InsertMenuItem( hmenu
, 0, FALSE
, &mii
);
427 ok( ret
, "InsertMenuItem failed with error %d\n", GetLastError());
429 if( winetest_debug
) {
431 RECT rc
= {100, 50, 400, 70};
434 sprintf( buf
,"%d text \"%s\" mnuopt %d", count
, text
? text
: "(nil)", mnuopt
);
435 FillRect( hdc
, &rc
, (HBRUSH
) COLOR_WINDOW
);
436 TextOut( hdc
, 100, 50, buf
, strlen( buf
));
437 ReleaseDC( hwnd
, hdc
);
440 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
442 ret
= SetMenu( hwnd
, hmenu
);
443 ok(ret
, "SetMenu failed with error %d\n", GetLastError());
446 ret
= GetMenuItemRect( hwnd
, hmenu
, 0, &rc
);
447 /* check menu width */
449 expect
= ( text
|| hbmp
?
450 4 + (mnuopt
!= 1 ? GetSystemMetrics(SM_CXMENUCHECK
) : 0)
452 arrowwidth
+ MOD_avec
+ (hbmp
? bmpsize
.cx
+ 2 : 0) +
453 (text
&& hastab
? /* TAB space */
454 MOD_avec
+ ( hastab
==2 ? sc_size
.cx
: 0) : 0) +
455 (text
? 2 + (text
[0] ? size
.cx
:0): 0) ;
457 expect
= !(text
|| hbmp
) ? 0 :
458 ( hbmp
? (text
? 2:0) + bmpsize
.cx
: 0 ) +
459 (text
? 2 * MOD_avec
+ (text
[0] ? size
.cx
:0): 0) ;
460 ok( rc
.right
- rc
.left
== expect
,
461 "menu width wrong, got %d expected %d\n", rc
.right
- rc
.left
, expect
);
462 failed
= failed
|| !(rc
.right
- rc
.left
== expect
);
463 /* check menu height */
465 expect
= max( ( !(text
|| hbmp
) ? GetSystemMetrics( SM_CYMENUSIZE
)/2 : 0),
466 max( (text
? max( 2 + size
.cy
, MOD_hic
+ 4) : 0),
467 (hbmp
? bmpsize
.cy
+ 2 : 0)));
469 expect
= ( !(text
|| hbmp
) ? GetSystemMetrics( SM_CYMENUSIZE
)/2 :
470 max( GetSystemMetrics( SM_CYMENU
) - 1, (hbmp
? bmpsize
.cy
: 0)));
471 ok( rc
.bottom
- rc
.top
== expect
,
472 "menu height wrong, got %d expected %d (%d)\n",
473 rc
.bottom
- rc
.top
, expect
, GetSystemMetrics( SM_CYMENU
));
474 failed
= failed
|| !(rc
.bottom
- rc
.top
== expect
);
475 if( hbmp
== HBMMENU_CALLBACK
&& MOD_GotDrawItemMsg
) {
476 /* check the position of the bitmap */
480 else if (mnuopt
== 0)
481 expect
= 4 + GetSystemMetrics(SM_CXMENUCHECK
);
482 else if (mnuopt
== 1)
484 else /* mnuopt == 2 */
486 ok( expect
== MOD_rc
[0].left
,
487 "bitmap left is %d expected %d\n", MOD_rc
[0].left
, expect
);
488 failed
= failed
|| !(expect
== MOD_rc
[0].left
);
490 expect
= (rc
.bottom
- rc
.top
- MOD_rc
[0].bottom
+ MOD_rc
[0].top
) / 2;
491 ok( expect
== MOD_rc
[0].top
,
492 "bitmap top is %d expected %d\n", MOD_rc
[0].top
, expect
);
493 failed
= failed
|| !(expect
== MOD_rc
[0].top
);
495 /* if there was a failure, report details */
497 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
498 count
, text
? text
: "(nil)", hbmp
, bmpsize
.cx
, bmpsize
.cy
,
499 size
.cx
, size
.cy
, sc_size
.cx
, mnuopt
, hastab
);
500 trace(" check %d,%d arrow %d avechar %d\n",
501 GetSystemMetrics(SM_CXMENUCHECK
),
502 GetSystemMetrics(SM_CYMENUCHECK
),arrowwidth
, MOD_avec
);
503 if( hbmp
== HBMMENU_CALLBACK
)
504 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
505 rc
.left
, rc
.top
, rc
.top
, rc
.bottom
, MOD_rc
[0].left
,
506 MOD_rc
[0].top
,MOD_rc
[0].right
, MOD_rc
[0].bottom
);
509 ret
= DestroyMenu(submenu
);
510 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
511 ret
= DestroyMenu(hmenu
);
512 ok(ret
, "DestroyMenu failed with error %d\n", GetLastError());
516 static void test_menu_bmp_and_string(void)
523 int count
, szidx
, txtidx
, bmpidx
, hassub
, mnuopt
, ispop
;
527 skip("GetMenuInfo is not available\n");
531 memset( bmfill
, 0xcc, sizeof( bmfill
));
532 hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
533 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, 200, 200,
534 NULL
, NULL
, NULL
, NULL
);
535 hbm_arrow
=LoadBitmap( 0, (CHAR
*)OBM_MNARROW
);
536 GetObject( hbm_arrow
, sizeof(bm
), &bm
);
537 arrowwidth
= bm
.bmWidth
;
539 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %d\n", GetLastError());
541 SetWindowLongPtr( hwnd
, GWLP_WNDPROC
, (LONG
)menu_ownerdraw_wnd_proc
);
544 trace(" check %d,%d arrow %d avechar %d\n",
545 GetSystemMetrics(SM_CXMENUCHECK
),
546 GetSystemMetrics(SM_CYMENUCHECK
),arrowwidth
, MOD_avec
);
549 for( ispop
=1; ispop
>= 0; ispop
--){
550 static SIZE bmsizes
[]= {
551 {10,10},{38,38},{1,30},{55,5}};
552 for( szidx
=0; szidx
< sizeof( bmsizes
) / sizeof( SIZE
); szidx
++) {
553 HBITMAP hbm
= CreateBitmap( bmsizes
[szidx
].cx
, bmsizes
[szidx
].cy
,1,1,bmfill
);
554 HBITMAP bitmaps
[] = { HBMMENU_CALLBACK
, hbm
, NULL
};
555 ok( (int)hbm
, "CreateBitmap failed err %d\n", GetLastError());
556 for( txtidx
= 0; txtidx
< sizeof(MOD_txtsizes
)/sizeof(MOD_txtsizes
[0]); txtidx
++) {
557 for( hassub
= 0; hassub
< 2 ; hassub
++) { /* add submenu item */
558 for( mnuopt
= 0; mnuopt
< 3 ; mnuopt
++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
559 for( bmpidx
= 0; bmpidx
<sizeof(bitmaps
)/sizeof(HBITMAP
); bmpidx
++) {
560 /* no need to test NULL bitmaps of several sizes */
561 if( !bitmaps
[bmpidx
] && szidx
> 0) continue;
562 if( !ispop
&& hassub
) continue;
563 test_mbs_help( ispop
, hassub
, mnuopt
,
564 hwnd
, arrowwidth
, ++count
,
567 MOD_txtsizes
[txtidx
].text
,
568 MOD_txtsizes
[txtidx
].size
,
569 MOD_txtsizes
[txtidx
].sc_size
);
581 static void test_menu_add_string( void )
592 WCHAR strbackW
[0x80];
593 static CHAR blah
[] = "blah";
594 static const WCHAR expectedString
[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
596 hmenu
= CreateMenu();
598 memset( &info
, 0, sizeof info
);
599 info
.cbSize
= sizeof info
;
600 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_ID
;
601 info
.dwTypeData
= blah
;
606 InsertMenuItem(hmenu
, 0, TRUE
, &info
);
608 memset( &info
, 0, sizeof info
);
609 info
.cbSize
= sizeof info
;
610 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_DATA
| MIIM_ID
;
611 info
.dwTypeData
= string
;
612 info
.cch
= sizeof string
;
614 GetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
616 ok( !strcmp( string
, "blah" ), "menu item name differed\n");
618 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
619 strcpy(string
, "Dummy string");
620 memset(&info
, 0x00, sizeof(info
));
621 info
.cbSize
= sizeof(MENUITEMINFO
);
622 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
; /* Set OwnerDraw + typeData */
623 info
.fType
= MFT_OWNERDRAW
;
624 info
.dwTypeData
= string
;
625 rc
= InsertMenuItem( hmenu
, 0, TRUE
, &info
);
626 ok (rc
, "InsertMenuItem failed\n");
628 strcpy(string
,"Garbage");
629 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
630 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
632 SetLastError(0xdeadbeef);
633 ret
= GetMenuStringW( hmenu
, 0, (WCHAR
*)strbackW
, 99, MF_BYPOSITION
);
634 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
635 skip("GetMenuStringW is not implemented\n");
638 ok (ret
, "GetMenuStringW on ownerdraw entry failed\n");
639 ok (!lstrcmpW( strbackW
, expectedString
), "Menu text from Unicode version incorrect\n");
642 /* Just change ftype to string and see what text is stored */
643 memset(&info
, 0x00, sizeof(info
));
644 info
.cbSize
= sizeof(MENUITEMINFO
);
645 info
.fMask
= MIIM_FTYPE
; /* Set string type */
646 info
.fType
= MFT_STRING
;
647 info
.dwTypeData
= (char *)0xdeadbeef;
648 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
649 ok (rc
, "SetMenuItemInfo failed\n");
651 /* Did we keep the old dwTypeData? */
652 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
653 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
655 /* Ensure change to bitmap type fails */
656 memset(&info
, 0x00, sizeof(info
));
657 info
.cbSize
= sizeof(MENUITEMINFO
);
658 info
.fMask
= MIIM_FTYPE
; /* Set as bitmap type */
659 info
.fType
= MFT_BITMAP
;
660 info
.dwTypeData
= (char *)0xdeadbee2;
661 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
662 ok (!rc
, "SetMenuItemInfo unexpectedly worked\n");
664 /* Just change ftype back and ensure data hasn't been freed */
665 info
.fType
= MFT_OWNERDRAW
; /* Set as ownerdraw type */
666 info
.dwTypeData
= (char *)0xdeadbee3;
667 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
668 ok (rc
, "SetMenuItemInfo failed\n");
670 /* Did we keep the old dwTypeData? */
671 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
672 ok (!strcmp( strback
, "Dummy string" ), "Menu text from Ansi version incorrect\n");
674 /* Just change string value (not type) */
675 memset(&info
, 0x00, sizeof(info
));
676 info
.cbSize
= sizeof(MENUITEMINFO
);
677 info
.fMask
= MIIM_STRING
; /* Set typeData */
678 strcpy(string2
, "string2");
679 info
.dwTypeData
= string2
;
680 rc
= SetMenuItemInfo( hmenu
, 0, TRUE
, &info
);
681 ok (rc
, "SetMenuItemInfo failed\n");
683 ok (GetMenuString( hmenu
, 0, strback
, 99, MF_BYPOSITION
), "GetMenuString on ownerdraw entry failed\n");
684 ok (!strcmp( strback
, "string2" ), "Menu text from Ansi version incorrect\n");
686 /* crashes with wine 0.9.5 */
687 memset(&info
, 0x00, sizeof(info
));
688 info
.cbSize
= sizeof(MENUITEMINFO
);
689 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
; /* Set OwnerDraw + typeData */
690 info
.fType
= MFT_OWNERDRAW
;
691 rc
= InsertMenuItem( hmenu
, 0, TRUE
, &info
);
692 ok (rc
, "InsertMenuItem failed\n");
693 ok (!GetMenuString( hmenu
, 0, NULL
, 0, MF_BYPOSITION
),
694 "GetMenuString on ownerdraw entry succeeded.\n");
695 SetLastError(0xdeadbeef);
696 ret
= GetMenuStringW( hmenu
, 0, NULL
, 0, MF_BYPOSITION
);
697 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
698 skip("GetMenuStringW is not implemented\n");
700 ok (!ret
, "GetMenuStringW on ownerdraw entry succeeded.\n");
702 DestroyMenu( hmenu
);
705 /* define building blocks for the menu item info tests */
706 static int strncmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
708 if (n
<= 0) return 0;
709 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
710 return *str1
- *str2
;
713 static WCHAR
*strcpyW( WCHAR
*dst
, const WCHAR
*src
)
716 while ((*p
++ = *src
++));
721 #define DMIINFF( i, e, field)\
722 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
723 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
725 #define DUMPMIINF(s,i,e)\
727 DMIINFF( i, e, fMask)\
728 DMIINFF( i, e, fType)\
729 DMIINFF( i, e, fState)\
731 DMIINFF( i, e, hSubMenu)\
732 DMIINFF( i, e, hbmpChecked)\
733 DMIINFF( i, e, hbmpUnchecked)\
734 DMIINFF( i, e, dwItemData)\
735 DMIINFF( i, e, dwTypeData)\
737 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
740 /* insert menu item */
741 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
744 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
745 HMENU hmenu = CreateMenu();\
746 BOOL ret, stop = FALSE;\
747 SetLastError( 0xdeadbeef);\
748 if(ansi)strcpy( string, init);\
749 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
750 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
751 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
752 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
754 skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
757 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
759 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
762 /* GetMenuItemInfo + GetMenuString */
763 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
764 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
765 expname, eret2, eret3)\
767 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
768 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
769 MENUITEMINFOA *info2 = &info2A;\
770 MENUITEMINFOA *einfo = &einfoA;\
771 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
773 SetLastError( 0xdeadbeef);\
774 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
775 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
776 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
778 skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
781 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
783 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
784 ret = memcmp( info2, einfo, sizeof einfoA);\
785 /* ok( ret==0, "Got wrong menu item info data\n");*/\
786 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
787 if( einfo->dwTypeData == string) {\
788 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
789 einfo->dwTypeData ? einfo->dwTypeData: "");\
790 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
791 einfo->dwTypeData ? einfo->dwTypeData: "");\
792 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
793 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
795 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
797 ok( !ret, "GetMenuString should have failed\n");\
804 RemoveMenu(hmenu, 0, TRUE );\
805 DestroyMenu( hmenu );\
806 DestroyMenu( submenu );\
807 submenu = CreateMenu();\
810 #define TMII_MODM( flags, id, data, eret )\
812 SetLastError( 0xdeadbeef);\
813 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
814 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
815 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
817 skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
820 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
821 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
824 /* SetMenuItemInfo */
825 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
828 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
829 SetLastError( 0xdeadbeef);\
830 if(ansi)strcpy( string, init);\
831 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
832 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
833 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
834 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
836 skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
839 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
841 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
850 static void test_menu_iteminfo( void )
852 int S
=sizeof( MENUITEMINFOA
);
857 WCHAR txtW
[]={'W','i','n','e',0};
858 WCHAR initW
[]={'X','Y','Z',0};
860 void *txt
, *init
, *empty
, *string
;
861 HBITMAP hbm
= CreateBitmap(1,1,1,1,NULL
);
863 HMENU submenu
=CreateMenu();
866 if( ansi
) {txt
=txtA
;init
=initA
;empty
=emptyA
;string
=stringA
;}
867 else {txt
=txtW
;init
=initW
;empty
=emptyW
;string
=stringA
;}
868 trace( "%s string %p hbm %p txt %p\n", ansi
? "ANSI tests: " : "Unicode tests:", string
, hbm
, txt
);
869 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
870 /* (since MFT_STRING is zero, there are four of them) */
871 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, 0, 0, 0, 0, 0, 0, txt
, 0, 0, }, OK
)
872 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
873 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
876 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
877 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
878 {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
881 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
882 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
883 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
886 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
887 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
888 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
891 /* not enough space for name*/
892 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
893 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, NULL
, 0, -9, },
894 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, NULL
, 4, 0, },
897 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
898 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 5, -9, },
899 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
902 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
903 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 4, -9, },
904 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 3, 0, },
907 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
908 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, NULL
, 0, -9, },
909 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, 0, },
912 /* cannot combine MIIM_TYPE with some other flags */
913 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, ER
)
914 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
915 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
918 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
919 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_STRING
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
920 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
923 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, ER
)
924 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
925 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
928 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
929 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
930 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
933 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_BITMAP
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, 6, hbm
, }, ER
)
934 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
935 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
938 /* but succeeds with some others */
939 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
940 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
941 {, S
, MIIM_TYPE
|MIIM_SUBMENU
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
944 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
945 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
946 {, S
, MIIM_TYPE
|MIIM_STATE
, MFT_STRING
, 0, -9, 0, -9, -9, -9, string
, 4, 0, },
949 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_ID
, MFT_STRING
, -1, 888, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
950 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
951 {, S
, MIIM_TYPE
|MIIM_ID
, MFT_STRING
, -9, 888, 0, -9, -9, -9, string
, 4, 0, },
954 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
, -1, -1, -1, -1, -1, 999, txt
, 6, -1, }, OK
)
955 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
956 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
, -9, -9, 0, -9, -9, 999, string
, 4, 0, },
959 /* to be continued */
960 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
961 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
962 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
963 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
966 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
967 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
968 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
969 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
972 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
973 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
974 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
977 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
978 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
979 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
982 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
983 TMII_GMII ( {, S
, 0, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
984 {, S
, 0, -9, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
987 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
988 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
989 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
990 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
993 /* same but retrieve with MIIM_TYPE */
994 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
995 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
996 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
999 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1000 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1001 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
1004 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1005 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1006 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
1010 /* How is that with bitmaps? */
1011 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1012 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1013 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1016 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1017 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1018 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, 0, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
1021 /* MIIM_BITMAP does not like MFT_BITMAP */
1022 TMII_INSMI( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, ER
)
1023 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1024 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1027 /* no problem with OWNERDRAWN */
1028 TMII_INSMI( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1029 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1030 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
1033 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
1034 TMII_INSMI( {, S
, MIIM_FTYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER
)
1035 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1036 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1040 /* menu with submenu */
1041 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, txt
, 0, -1, }, OK
)
1042 TMII_GMII ( {, S
, MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1043 {, S
, MIIM_SUBMENU
, -9, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1046 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, empty
, 0, -1, }, OK
)
1047 TMII_GMII ( {, S
, MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1048 {, S
, MIIM_SUBMENU
, -9, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1051 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
1052 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, submenu
, -1, -1, -1, txt
, 0, -1, }, OK
)
1053 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1054 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
|MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 0, -9, },
1056 TMII_GMII ( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1057 {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, submenu
, -9, -9, -9, string
, 80, -9, },
1060 /* menu with invalid submenu */
1061 TMII_INSMI( {, S
, MIIM_SUBMENU
|MIIM_FTYPE
, MFT_STRING
, -1, -1, 999, -1, -1, -1, txt
, 0, -1, }, ER
)
1062 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1063 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1067 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_SEPARATOR
, 0, 0, 0, 0, 0, 0, txt
, 0, 0, }, OK
)
1068 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1069 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1072 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, hbm
, 6, -1, }, OK
)
1073 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1074 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1077 /* SEPARATOR and STRING go well together */
1078 /* BITMAP and STRING go well together */
1079 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1080 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1081 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, hbm
, },
1084 /* BITMAP, SEPARATOR and STRING go well together */
1085 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1086 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1087 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 4, hbm
, },
1090 /* last two tests, but use MIIM_TYPE to retrieve info */
1091 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
1092 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1093 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1096 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1097 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1098 {, S
, MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1101 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1102 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1103 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_BITMAP
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1106 /* same three with MFT_OWNERDRAW */
1107 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, -1, }, OK
)
1108 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1109 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1112 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1113 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1114 {, S
, MIIM_TYPE
, MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1117 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1118 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1119 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_BITMAP
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 4, hbm
, },
1123 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
|MIIM_ID
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1124 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1125 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1128 /* test with modifymenu: string is preserved after setting OWNERDRAW */
1129 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1130 TMII_MODM( MFT_OWNERDRAW
, -1, 787, OK
)
1131 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1132 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_DATA
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 787, string
, 4, -9, },
1135 /* same with bitmap: now the text is cleared */
1136 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1137 TMII_MODM( MFT_BITMAP
, 545, hbm
, OK
)
1138 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1139 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_BITMAP
, -9, 545, 0, -9, -9, -9, string
, 0, hbm
, },
1142 /* start with bitmap: now setting text clears it (though he flag is raised) */
1143 TMII_INSMI( {, S
, MIIM_BITMAP
, MFT_STRING
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1144 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1145 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 0, 0, -9, -9, -9, string
, 0, hbm
, },
1147 TMII_MODM( MFT_STRING
, 545, txt
, OK
)
1148 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1149 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 545, 0, -9, -9, -9, string
, 4, 0, },
1152 /*repeat with text NULL */
1153 TMII_INSMI( {, S
, MIIM_BITMAP
, MFT_STRING
, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1154 TMII_MODM( MFT_STRING
, 545, NULL
, OK
)
1155 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1156 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_SEPARATOR
, -9, 545, 0, -9, -9, -9, string
, 0, 0, },
1159 /* repeat with text "" */
1160 TMII_INSMI( {, S
, MIIM_BITMAP
, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1161 TMII_MODM( MFT_STRING
, 545, empty
, OK
)
1162 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1163 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_ID
, MFT_STRING
, -9, 545, 0, -9, -9, -9, string
, 0, 0, },
1166 /* start with bitmap: set ownerdraw */
1167 TMII_INSMI( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1168 TMII_MODM( MFT_OWNERDRAW
, -1, 232, OK
)
1169 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1170 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
|MIIM_DATA
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 232, string
, 0, hbm
, },
1174 TMII_INSMI( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1175 TMII_GMII ( {, S
, 0, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1176 {, S
, 0, -9, -9, -9, 0, -9, -9, -9, string
, 80, -9, },
1179 /* some tests with small cbSize: the hbmpItem is to be ignored */
1180 TMII_INSMI( {, S
- 4, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1181 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1182 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1185 TMII_INSMI( {, S
- 4, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1186 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1187 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 80, NULL
, },
1190 TMII_INSMI( {, S
- 4, MIIM_STRING
|MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1191 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1192 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, NULL
, },
1195 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1196 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1197 {, S
, MIIM_TYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1200 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1201 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1202 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1205 TMII_INSMI( {, S
- 4, MIIM_FTYPE
|MIIM_STRING
|MIIM_BITMAP
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, txt
, 6, hbm
, }, OK
)
1206 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1207 {, S
, MIIM_TYPE
, MFT_SEPARATOR
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 4, NULL
, },
1210 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1211 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1212 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1213 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1216 TMII_INSMI( {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1217 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1218 {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1221 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
|MFT_OWNERDRAW
, -1, -1, -1, -1, -1, 343, txt
, 0, -1, }, OK
)
1222 TMII_GMII ( {, S
, MIIM_TYPE
|MIIM_DATA
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1223 {, S
, MIIM_TYPE
|MIIM_DATA
, MFT_STRING
|MFT_OWNERDRAW
, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1226 /* set a string menu to ownerdraw with MIIM_TYPE */
1227 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_STRING
, -2, -2, -2, -2, -2, -2, txt
, -2, -2, }, OK
)
1228 TMII_SMII( {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1229 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1230 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
1233 /* test with modifymenu add submenu */
1234 TMII_INSMI( {, S
, MIIM_STRING
, MFT_STRING
, -1, -1, -1, -1, -1, -1, txt
, 0, -1, }, OK
)
1235 TMII_MODM( MF_POPUP
, submenu
, txt
, OK
)
1236 TMII_GMII ( {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_SUBMENU
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1237 {, S
, MIIM_FTYPE
|MIIM_STRING
|MIIM_SUBMENU
, MFT_STRING
, -9, -9, submenu
, -9, -9, -9, string
, 4, -9, },
1239 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1240 {, S
, MIIM_TYPE
, MFT_STRING
, -9, -9, 0, -9, -9, -9, string
, 4, 0, },
1243 /* MFT_SEPARATOR bit is kept when the text is added */
1244 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1245 TMII_SMII( {, S
, MIIM_STRING
, -1, -1, -1, -1, -1, -1, -1, txt
, -1, -1, }, OK
)
1246 TMII_GMII ( {, S
, MIIM_STRING
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1247 {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 4, -9, },
1250 /* MFT_SEPARATOR bit is kept when bitmap is added */
1251 TMII_INSMI( {, S
, MIIM_STRING
|MIIM_FTYPE
, MFT_STRING
, -1, -1, -1, -1, -1, -1, NULL
, 0, -1, }, OK
)
1252 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm
, }, OK
)
1253 TMII_GMII ( {, S
, MIIM_BITMAP
|MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, string
, 80, -9, },
1254 {, S
, MIIM_BITMAP
|MIIM_FTYPE
, MFT_SEPARATOR
, -9, -9, 0, -9, -9, -9, string
, 80, hbm
, },
1257 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1258 Only the low word of the dwTypeData is used.
1259 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1260 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE
, 0x1234), -1, -1, }, OK
)
1261 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1262 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE
, 0, HBMMENU_MBAR_CLOSE
, },
1266 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
)
1267 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1268 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_MENUBARBREAK
| MFT_RADIOCHECK
| MFT_RIGHTJUSTIFY
| MFT_RIGHTORDER
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1272 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1273 TMII_SMII( {, S
, MIIM_STATE
, -1, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1274 TMII_GMII ( {, S
, MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1275 {, S
, MIIM_STATE
, -9, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -9, 0, -9, -9, -9, -9, -9, -9, },
1278 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1279 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1280 TMII_SMII( {, S
, MIIM_CHECKMARKS
, MFT_RADIOCHECK
, -1, -1, -1, hbm
, hbm
, -1, -1, -1, -1, }, OK
)
1281 TMII_GMII ( {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1282 {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, hbm
, hbm
, -9, hbm
, 0, hbm
, },
1285 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1286 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1287 TMII_SMII( {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK
)
1288 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1289 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1291 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1292 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1294 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1295 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1297 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL
, }, OK
)
1298 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1299 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1302 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1303 Only the low word of the dwTypeData is used.
1304 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1305 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE
, 0x1234), -1, -1, }, OK
)
1306 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1307 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_RIGHTJUSTIFY
, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE
, 0, HBMMENU_MBAR_CLOSE
, },
1311 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
)
1312 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1313 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_MENUBARBREAK
| MFT_RADIOCHECK
| MFT_RIGHTJUSTIFY
| MFT_RIGHTORDER
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1317 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1318 TMII_SMII( {, S
, MIIM_STATE
, -1, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -1, -1, -1, -1, -1, -1, -1, -1, }, OK
)
1319 TMII_GMII ( {, S
, MIIM_STATE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1320 {, S
, MIIM_STATE
, -9, MFS_CHECKED
| MFS_DEFAULT
| MFS_GRAYED
| MFS_HILITE
, -9, 0, -9, -9, -9, -9, -9, -9, },
1323 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1324 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1325 TMII_SMII( {, S
, MIIM_CHECKMARKS
, MFT_RADIOCHECK
, -1, -1, -1, hbm
, hbm
, -1, -1, -1, -1, }, OK
)
1326 TMII_GMII ( {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1327 {, S
, MIIM_CHECKMARKS
| MIIM_TYPE
, MFT_BITMAP
, -9, -9, 0, hbm
, hbm
, -9, hbm
, 0, hbm
, },
1330 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1331 TMII_INSMI( {, S
, MIIM_TYPE
, MFT_BITMAP
, -1, -1, -1, -1, -1, -1, hbm
, -1, -1, }, OK
)
1332 TMII_SMII( {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK
)
1333 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1334 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1336 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1337 {, S
, MIIM_TYPE
, MFT_BITMAP
| MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, hbm
, 0, hbm
, },
1339 TMII_GMII ( {, S
, MIIM_FTYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1340 {, S
, MIIM_FTYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1342 TMII_SMII( {, S
, MIIM_BITMAP
, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL
, }, OK
)
1343 TMII_GMII ( {, S
, MIIM_TYPE
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1344 {, S
, MIIM_TYPE
, MFT_OWNERDRAW
, -9, -9, 0, -9, -9, -9, NULL
, 0, NULL
, },
1347 } while( !(ansi
= !ansi
) );
1352 The following tests try to confirm the algorithm used to return the menu items
1353 when there is a collision between a menu item and a popup menu
1355 static void test_menu_search_bycommand( void )
1357 HMENU hmenu
, hmenuSub
, hmenuSub2
;
1363 static CHAR menuitem
[] = "MenuItem",
1364 menuitem2
[] = "MenuItem 2";
1366 /* Case 1: Menu containing a menu item */
1367 hmenu
= CreateMenu();
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 strcpy(strIn
, "Case 1 MenuItem");
1374 info
.dwTypeData
= strIn
;
1375 info
.wID
= (UINT
) 0x1234;
1377 rc
= InsertMenuItem(hmenu
, 0, TRUE
, &info
);
1378 ok (rc
, "Inserting the menuitem failed\n");
1380 id
= GetMenuItemID(hmenu
, 0);
1381 ok (id
== 0x1234, "Getting the menuitem id failed(gave %x)\n", id
);
1383 /* Confirm the menuitem was given the id supplied (getting by position) */
1384 memset( &info
, 0, sizeof info
);
1386 info
.cbSize
= sizeof(MENUITEMINFO
);
1387 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1388 info
.dwTypeData
= strback
;
1389 info
.cch
= sizeof(strback
);
1391 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
); /* Get by position */
1392 ok (rc
, "Getting the menu items info failed\n");
1393 ok (info
.wID
== 0x1234, "IDs differ for the menuitem\n");
1394 ok (!strcmp(info
.dwTypeData
, "Case 1 MenuItem"), "Returned item has wrong label\n");
1396 /* Search by id - Should return the item */
1397 memset( &info
, 0, sizeof info
);
1399 info
.cbSize
= sizeof(MENUITEMINFO
);
1400 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1401 info
.dwTypeData
= strback
;
1402 info
.cch
= sizeof(strback
);
1403 rc
= GetMenuItemInfo(hmenu
, 0x1234, FALSE
, &info
); /* Get by ID */
1405 ok (rc
, "Getting the menu items info failed\n");
1406 ok (info
.wID
== 0x1234, "IDs differ for the menuitem\n");
1407 ok (!strcmp(info
.dwTypeData
, "Case 1 MenuItem"), "Returned item has wrong label\n");
1409 DestroyMenu( hmenu
);
1411 /* Case 2: Menu containing a popup menu */
1412 hmenu
= CreateMenu();
1413 hmenuSub
= CreateMenu();
1415 strcpy(strIn
, "Case 2 SubMenu");
1416 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, strIn
);
1417 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1419 id
= GetMenuItemID(hmenu
, 0);
1420 ok (id
== -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id
);
1422 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1423 memset( &info
, 0, sizeof info
);
1425 info
.cbSize
= sizeof(MENUITEMINFO
);
1426 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1427 info
.dwTypeData
= strback
;
1428 info
.cch
= sizeof(strback
);
1429 info
.wID
= 0xdeadbeef;
1431 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
); /* Get by position */
1432 ok (rc
, "Getting the menu items info failed\n");
1433 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the menuitem\n");
1434 ok (!strcmp(info
.dwTypeData
, "Case 2 SubMenu"), "Returned item has wrong label\n");
1436 /* Search by id - returns the popup menu itself */
1437 memset( &info
, 0, sizeof info
);
1439 info
.cbSize
= sizeof(MENUITEMINFO
);
1440 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1441 info
.dwTypeData
= strback
;
1442 info
.cch
= sizeof(strback
);
1443 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1445 ok (rc
, "Getting the menu items info failed\n");
1446 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1447 ok (!strcmp(info
.dwTypeData
, "Case 2 SubMenu"), "Returned item has wrong label\n");
1450 Now add an item after it with the same id
1452 memset( &info
, 0, sizeof info
);
1453 info
.cbSize
= sizeof info
;
1454 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1455 info
.fType
= MFT_STRING
;
1456 strcpy(strIn
, "Case 2 MenuItem 1");
1457 info
.dwTypeData
= strIn
;
1458 info
.wID
= (UINT_PTR
) hmenuSub
;
1459 rc
= InsertMenuItem(hmenu
, -1, TRUE
, &info
);
1460 ok (rc
, "Inserting the menuitem failed\n");
1462 /* Search by id - returns the item which follows the popup menu */
1463 memset( &info
, 0, sizeof info
);
1465 info
.cbSize
= sizeof(MENUITEMINFO
);
1466 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1467 info
.dwTypeData
= strback
;
1468 info
.cch
= sizeof(strback
);
1469 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1471 ok (rc
, "Getting the menu items info failed\n");
1472 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1473 ok (!strcmp(info
.dwTypeData
, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1476 Now add an item before the popup (with the same id)
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 strcpy(strIn
, "Case 2 MenuItem 2");
1483 info
.dwTypeData
= strIn
;
1484 info
.wID
= (UINT_PTR
) hmenuSub
;
1485 rc
= InsertMenuItem(hmenu
, 0, TRUE
, &info
);
1486 ok (rc
, "Inserting the menuitem failed\n");
1488 /* Search by id - returns the item which precedes the popup menu */
1489 memset( &info
, 0, sizeof info
);
1491 info
.cbSize
= sizeof(MENUITEMINFO
);
1492 info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
1493 info
.dwTypeData
= strback
;
1494 info
.cch
= sizeof(strback
);
1495 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
); /* Get by ID */
1497 ok (rc
, "Getting the menu items info failed\n");
1498 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for the popup menu\n");
1499 ok (!strcmp(info
.dwTypeData
, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1501 DestroyMenu( hmenu
);
1502 DestroyMenu( hmenuSub
);
1505 Case 3: Menu containing a popup menu which in turn
1506 contains 2 items with the same id as the popup itself
1509 hmenu
= CreateMenu();
1510 hmenuSub
= CreateMenu();
1512 memset( &info
, 0, sizeof info
);
1513 info
.cbSize
= sizeof info
;
1514 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1515 info
.fType
= MFT_STRING
;
1516 info
.dwTypeData
= menuitem
;
1517 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1519 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1520 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1522 rc
= InsertMenuItem(hmenuSub
, 0, TRUE
, &info
);
1523 ok (rc
, "Inserting the sub menu menuitem failed\n");
1525 memset( &info
, 0, sizeof info
);
1526 info
.cbSize
= sizeof info
;
1527 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1528 info
.fType
= MFT_STRING
;
1529 info
.dwTypeData
= menuitem2
;
1530 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1532 rc
= InsertMenuItem(hmenuSub
, 1, TRUE
, &info
);
1533 ok (rc
, "Inserting the sub menu menuitem 2 failed\n");
1535 /* Prove that you can't query the id of a popup directly (By position) */
1536 id
= GetMenuItemID(hmenu
, 0);
1537 ok (id
== -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id
);
1539 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1540 memset( &info
, 0, sizeof info
);
1542 info
.cbSize
= sizeof(MENUITEMINFO
);
1543 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1544 info
.dwTypeData
= strback
;
1545 info
.cch
= sizeof(strback
);
1547 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
);
1548 ok (rc
, "Getting the menus info failed\n");
1549 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for popup menu\n");
1550 ok (!strcmp(info
.dwTypeData
, "MenuItem"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1551 DestroyMenu( hmenu
);
1552 DestroyMenu( hmenuSub
);
1555 Case 4: Menu containing 2 popup menus, the second
1556 contains 2 items with the same id as the first popup menu
1558 hmenu
= CreateMenu();
1559 hmenuSub
= CreateMenu();
1560 hmenuSub2
= CreateMenu();
1562 rc
= InsertMenu(hmenu
, 0, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1563 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1565 rc
= InsertMenu(hmenu
, 1, MF_BYPOSITION
| MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub2
, "Submenu2");
1566 ok (rc
, "Inserting the popup menu into the main menu failed\n");
1568 memset( &info
, 0, sizeof info
);
1569 info
.cbSize
= sizeof info
;
1570 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1571 info
.fType
= MFT_STRING
;
1572 info
.dwTypeData
= menuitem
;
1573 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1575 rc
= InsertMenuItem(hmenuSub2
, 0, TRUE
, &info
);
1576 ok (rc
, "Inserting the sub menu menuitem failed\n");
1578 memset( &info
, 0, sizeof info
);
1579 info
.cbSize
= sizeof info
;
1580 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_ID
;
1581 info
.fType
= MFT_STRING
;
1582 info
.dwTypeData
= menuitem2
;
1583 info
.wID
= (UINT_PTR
) hmenuSub
; /* Enforce id collisions with the hmenu of the popup submenu*/
1585 rc
= InsertMenuItem(hmenuSub2
, 1, TRUE
, &info
);
1586 ok (rc
, "Inserting the sub menu menuitem 2 failed\n");
1588 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1589 memset( &info
, 0, sizeof info
);
1591 info
.cbSize
= sizeof(MENUITEMINFO
);
1592 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1593 info
.dwTypeData
= strback
;
1594 info
.cch
= sizeof(strback
);
1596 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub
, FALSE
, &info
);
1597 ok (rc
, "Getting the menus info failed\n");
1598 ok (info
.wID
== (UINT_PTR
)hmenuSub
, "IDs differ for popup menu\n");
1599 ok (!strcmp(info
.dwTypeData
, "MenuItem"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1601 memset( &info
, 0, sizeof info
);
1603 info
.cbSize
= sizeof(MENUITEMINFO
);
1604 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1605 info
.dwTypeData
= strback
;
1606 info
.cch
= sizeof(strback
);
1608 rc
= GetMenuItemInfo(hmenu
, (UINT_PTR
)hmenuSub2
, FALSE
, &info
);
1609 ok (rc
, "Getting the menus info failed\n");
1610 ok (info
.wID
== (UINT
)hmenuSub2
, "IDs differ for popup menu\n");
1611 ok (!strcmp(info
.dwTypeData
, "Submenu2"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1613 DestroyMenu( hmenu
);
1614 DestroyMenu( hmenuSub
);
1615 DestroyMenu( hmenuSub2
);
1619 Case 5: Menu containing a popup menu which in turn
1620 contains an item with a different id than the popup menu.
1621 This tests the fallback to a popup menu ID.
1624 hmenu
= CreateMenu();
1625 hmenuSub
= CreateMenu();
1627 rc
= AppendMenu(hmenu
, MF_POPUP
| MF_STRING
, (UINT_PTR
)hmenuSub
, "Submenu");
1628 ok (rc
, "Appending the popup menu to the main menu failed\n");
1630 rc
= AppendMenu(hmenuSub
, MF_STRING
, 102, "Item");
1631 ok (rc
, "Appending the item to the popup menu failed\n");
1633 /* Set the ID for hmenuSub */
1634 info
.cbSize
= sizeof(info
);
1635 info
.fMask
= MIIM_ID
;
1638 rc
= SetMenuItemInfo(hmenu
, 0, TRUE
, &info
);
1639 ok(rc
, "Setting the ID for the popup menu failed\n");
1641 /* Check if the ID has been set */
1643 rc
= GetMenuItemInfo(hmenu
, 0, TRUE
, &info
);
1644 ok(rc
, "Getting the ID for the popup menu failed\n");
1645 ok(info
.wID
== 101, "The ID for the popup menu has not been set\n");
1647 /* Prove getting the item info via ID returns the popup menu */
1648 memset( &info
, 0, sizeof(info
));
1650 info
.cbSize
= sizeof(MENUITEMINFO
);
1651 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1652 info
.dwTypeData
= strback
;
1653 info
.cch
= sizeof(strback
);
1655 rc
= GetMenuItemInfo(hmenu
, 101, FALSE
, &info
);
1656 ok (rc
, "Getting the menu info failed\n");
1657 ok (info
.wID
== 101, "IDs differ\n");
1658 ok (!strcmp(info
.dwTypeData
, "Submenu"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1660 /* Also look for the menu item */
1661 memset( &info
, 0, sizeof(info
));
1663 info
.cbSize
= sizeof(MENUITEMINFO
);
1664 info
.fMask
= MIIM_STRING
| MIIM_ID
;
1665 info
.dwTypeData
= strback
;
1666 info
.cch
= sizeof(strback
);
1668 rc
= GetMenuItemInfo(hmenu
, 102, FALSE
, &info
);
1669 ok (rc
, "Getting the menu info failed\n");
1670 ok (info
.wID
== 102, "IDs differ\n");
1671 ok (!strcmp(info
.dwTypeData
, "Item"), "Returned item has wrong label (%s)\n", info
.dwTypeData
);
1674 DestroyMenu(hmenuSub
);
1677 struct menu_item_pair_s
{
1678 UINT uMenu
; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1679 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1680 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1684 static struct menu_mouse_tests_s
{
1686 struct menu_item_pair_s menu_item_pairs
[5]; /* for mousing */
1687 WORD wVk
[5]; /* keys */
1691 /* for each test, send keys or clicks and check for menu visibility */
1692 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
}, /* test 0 */
1693 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, 0}, FALSE
, FALSE
},
1694 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
},
1695 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1696 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 0}, TRUE
, FALSE
},
1697 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1698 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1699 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, VK_ESCAPE
, 0}, FALSE
, FALSE
},
1700 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', VK_ESCAPE
, 0}, TRUE
, FALSE
},
1701 { INPUT_KEYBOARD
, {{0}}, {VK_ESCAPE
, 0}, FALSE
, FALSE
},
1702 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1703 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1704 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 0}, TRUE
, FALSE
},
1705 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1706 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 'P', 0}, TRUE
, FALSE
},
1707 { INPUT_KEYBOARD
, {{0}}, {'D', 0}, FALSE
, FALSE
},
1708 { INPUT_KEYBOARD
, {{0}}, {VK_LMENU
, 'M', 'P', 0}, TRUE
, FALSE
},
1709 { INPUT_KEYBOARD
, {{0}}, {'E', 0}, FALSE
, FALSE
},
1711 { INPUT_MOUSE
, {{1, 2}, {0}}, {0}, TRUE
, TRUE
}, /* test 18 */
1712 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1713 { INPUT_MOUSE
, {{1, 0}, {0}}, {0}, TRUE
, TRUE
},
1714 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1715 { INPUT_MOUSE
, {{1, 0}, {2, 2}, {0}}, {0}, TRUE
, TRUE
},
1716 { INPUT_MOUSE
, {{2, 1}, {0}}, {0}, FALSE
, FALSE
},
1717 { INPUT_MOUSE
, {{1, 0}, {2, 0}, {0}}, {0}, TRUE
, TRUE
},
1718 { INPUT_MOUSE
, {{3, 0}, {0}}, {0}, FALSE
, FALSE
},
1719 { INPUT_MOUSE
, {{1, 0}, {2, 0}, {0}}, {0}, TRUE
, TRUE
},
1720 { INPUT_MOUSE
, {{3, 1}, {0}}, {0}, TRUE
, TRUE
},
1721 { INPUT_MOUSE
, {{1, 1}, {0}}, {0}, FALSE
, FALSE
},
1725 static void send_key(WORD wVk
)
1728 memset(i
, 0, sizeof(i
));
1729 i
[0].type
= i
[1].type
= INPUT_KEYBOARD
;
1730 i
[0].u
.ki
.wVk
= i
[1].u
.ki
.wVk
= wVk
;
1731 i
[1].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1732 pSendInput(2, (INPUT
*) i
, sizeof(INPUT
));
1735 static void click_menu(HANDLE hWnd
, struct menu_item_pair_s
*mi
)
1737 HMENU hMenu
= hMenus
[mi
->uMenu
];
1741 int screen_w
= GetSystemMetrics(SM_CXSCREEN
);
1742 int screen_h
= GetSystemMetrics(SM_CYSCREEN
);
1743 BOOL ret
= GetMenuItemRect(mi
->uMenu
> 2 ? NULL
: hWnd
, hMenu
, mi
->uItem
, &r
);
1746 memset(i
, 0, sizeof(i
));
1747 i
[0].type
= i
[1].type
= i
[2].type
= INPUT_MOUSE
;
1748 i
[0].u
.mi
.dx
= i
[1].u
.mi
.dx
= i
[2].u
.mi
.dx
1749 = ((r
.left
+ 5) * 65535) / screen_w
;
1750 i
[0].u
.mi
.dy
= i
[1].u
.mi
.dy
= i
[2].u
.mi
.dy
1751 = ((r
.top
+ 5) * 65535) / screen_h
;
1752 i
[0].u
.mi
.dwFlags
= i
[1].u
.mi
.dwFlags
= i
[2].u
.mi
.dwFlags
1753 = MOUSEEVENTF_ABSOLUTE
;
1754 i
[0].u
.mi
.dwFlags
|= MOUSEEVENTF_MOVE
;
1755 i
[1].u
.mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
1756 i
[2].u
.mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
1757 pSendInput(3, (INPUT
*) i
, sizeof(INPUT
));
1759 /* hack to prevent mouse message buildup in Wine */
1760 while (PeekMessage( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
1763 static DWORD WINAPI
test_menu_input_thread(LPVOID lpParameter
)
1766 HANDLE hWnd
= lpParameter
;
1769 /* mixed keyboard/mouse test */
1770 for (i
= 0; menu_tests
[i
].type
!= -1; i
++)
1774 if (menu_tests
[i
].type
== INPUT_KEYBOARD
)
1775 for (j
= 0; menu_tests
[i
].wVk
[j
] != 0; j
++)
1776 send_key(menu_tests
[i
].wVk
[j
]);
1778 for (j
= 0; menu_tests
[i
].menu_item_pairs
[j
].uMenu
!= 0; j
++)
1779 click_menu(hWnd
, &menu_tests
[i
].menu_item_pairs
[j
]);
1781 while (menu_tests
[i
].bMenuVisible
!= bMenuVisible
)
1789 if (menu_tests
[i
]._todo_wine
)
1792 ok(menu_tests
[i
].bMenuVisible
== bMenuVisible
, "test %d\n", i
);
1796 ok(menu_tests
[i
].bMenuVisible
== bMenuVisible
, "test %d\n", i
);
1801 static LRESULT CALLBACK
WndProc(HWND hWnd
, UINT msg
, WPARAM wParam
,
1805 case WM_ENTERMENULOOP
:
1806 bMenuVisible
= TRUE
;
1808 case WM_EXITMENULOOP
:
1809 bMenuVisible
= FALSE
;
1812 return( DefWindowProcA( hWnd
, msg
, wParam
, lParam
) );
1817 static void test_menu_input(void) {
1820 HINSTANCE hInstance
= GetModuleHandleA( NULL
);
1821 HANDLE hThread
, hWnd
;
1824 wclass
.lpszClassName
= "MenuTestClass";
1825 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1826 wclass
.lpfnWndProc
= WndProc
;
1827 wclass
.hInstance
= hInstance
;
1828 wclass
.hIcon
= LoadIconA( 0, (LPSTR
)IDI_APPLICATION
);
1829 wclass
.hCursor
= LoadCursorA( NULL
, (LPSTR
)IDC_ARROW
);
1830 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1);
1831 wclass
.lpszMenuName
= 0;
1832 wclass
.cbClsExtra
= 0;
1833 wclass
.cbWndExtra
= 0;
1834 assert (RegisterClassA( &wclass
));
1835 assert (hWnd
= CreateWindowA( wclass
.lpszClassName
, "MenuTest",
1836 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0,
1837 400, 200, NULL
, NULL
, hInstance
, NULL
) );
1840 hMenus
[3] = CreatePopupMenu();
1841 AppendMenu(hMenus
[3], MF_STRING
, 0, "&Enabled");
1842 AppendMenu(hMenus
[3], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1844 hMenus
[2] = CreatePopupMenu();
1845 AppendMenu(hMenus
[2], MF_STRING
|MF_POPUP
, (UINT_PTR
) hMenus
[3], "&Popup");
1846 AppendMenu(hMenus
[2], MF_STRING
, 0, "&Enabled");
1847 AppendMenu(hMenus
[2], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1849 hMenus
[1] = CreateMenu();
1850 AppendMenu(hMenus
[1], MF_STRING
|MF_POPUP
, (UINT_PTR
) hMenus
[2], "&Menu");
1851 AppendMenu(hMenus
[1], MF_STRING
, 0, "&Enabled");
1852 AppendMenu(hMenus
[1], MF_STRING
|MF_DISABLED
, 0, "&Disabled");
1854 SetMenu(hWnd
, hMenus
[1]);
1855 ShowWindow(hWnd
, SW_SHOW
);
1858 hThread
= CreateThread(NULL
, 0, test_menu_input_thread
, hWnd
, 0, &tid
);
1861 if (WAIT_TIMEOUT
!= WaitForSingleObject(hThread
, 50))
1863 while (PeekMessage(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
1865 DestroyWindow(hWnd
);
1868 static void test_menu_flags( void )
1870 HMENU hMenu
, hPopupMenu
;
1872 hMenu
= CreateMenu();
1873 hPopupMenu
= CreatePopupMenu();
1875 AppendMenu(hMenu
, MF_POPUP
| MF_STRING
, (UINT
)hPopupMenu
, "Popup");
1877 AppendMenu(hPopupMenu
, MF_STRING
| MF_HILITE
| MF_DEFAULT
, 101, "Item 1");
1878 InsertMenu(hPopupMenu
, 1, MF_BYPOSITION
| MF_STRING
| MF_HILITE
| MF_DEFAULT
, 102, "Item 2");
1879 AppendMenu(hPopupMenu
, MF_STRING
, 103, "Item 3");
1880 ModifyMenu(hPopupMenu
, 2, MF_BYPOSITION
| MF_STRING
| MF_HILITE
| MF_DEFAULT
, 103, "Item 3");
1882 ok(GetMenuState(hPopupMenu
, 0, MF_BYPOSITION
) & MF_HILITE
,
1883 "AppendMenu should accept MF_HILITE\n");
1884 ok(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
,
1885 "InsertMenu should accept MF_HILITE\n");
1886 ok(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
,
1887 "ModifyMenu should accept MF_HILITE\n");
1889 ok(!(GetMenuState(hPopupMenu
, 0, MF_BYPOSITION
) & MF_DEFAULT
),
1890 "AppendMenu must not accept MF_DEFAULT\n");
1891 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_DEFAULT
),
1892 "InsertMenu must not accept MF_DEFAULT\n");
1893 ok(!(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_DEFAULT
),
1894 "ModifyMenu must not accept MF_DEFAULT\n");
1899 static void test_menu_hilitemenuitem( void )
1901 HMENU hMenu
, hPopupMenu
;
1905 wclass
.lpszClassName
= "HiliteMenuTestClass";
1906 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1907 wclass
.lpfnWndProc
= WndProc
;
1908 wclass
.hInstance
= GetModuleHandleA( NULL
);
1909 wclass
.hIcon
= LoadIconA( 0, (LPSTR
)IDI_APPLICATION
);
1910 wclass
.hCursor
= LoadCursorA( NULL
, (LPSTR
)IDC_ARROW
);
1911 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1);
1912 wclass
.lpszMenuName
= 0;
1913 wclass
.cbClsExtra
= 0;
1914 wclass
.cbWndExtra
= 0;
1915 assert (RegisterClassA( &wclass
));
1916 assert (hWnd
= CreateWindowA( wclass
.lpszClassName
, "HiliteMenuTest",
1917 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0,
1918 400, 200, NULL
, NULL
, wclass
.hInstance
, NULL
) );
1920 hMenu
= CreateMenu();
1921 hPopupMenu
= CreatePopupMenu();
1923 AppendMenu(hMenu
, MF_POPUP
| MF_STRING
, (UINT
)hPopupMenu
, "Popup");
1925 AppendMenu(hPopupMenu
, MF_STRING
, 101, "Item 1");
1926 AppendMenu(hPopupMenu
, MF_STRING
, 102, "Item 2");
1927 AppendMenu(hPopupMenu
, MF_STRING
, 103, "Item 3");
1929 SetMenu(hWnd
, hMenu
);
1931 /* test invalid arguments */
1933 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1934 "HiliteMenuItem: Item 2 is hilited\n");
1936 SetLastError(0xdeadbeef);
1939 ok(!HiliteMenuItem(NULL
, hPopupMenu
, 1, MF_HILITE
| MF_BYPOSITION
),
1940 "HiliteMenuItem: call should have failed.\n");
1942 ok(GetLastError() == 0xdeadbeef || /* 9x */
1943 GetLastError() == ERROR_INVALID_WINDOW_HANDLE
/* NT */,
1944 "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError());
1946 SetLastError(0xdeadbeef);
1947 ok(!HiliteMenuItem(hWnd
, NULL
, 1, MF_HILITE
| MF_BYPOSITION
),
1948 "HiliteMenuItem: call should have failed.\n");
1949 ok(GetLastError() == 0xdeadbeef || /* 9x */
1950 GetLastError() == ERROR_INVALID_MENU_HANDLE
/* NT */,
1951 "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError());
1953 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1954 "HiliteMenuItem: Item 2 is hilited\n");
1956 /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */
1958 SetLastError(0xdeadbeef);
1959 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_BYPOSITION
),
1960 "HiliteMenuItem: call should have succeeded.\n");
1961 ok(GetLastError() == 0xdeadbeef,
1962 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1964 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1965 "HiliteMenuItem: Item 2 is hilited\n");
1967 SetLastError(0xdeadbeef);
1970 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_HILITE
),
1971 "HiliteMenuItem: call should have succeeded.\n");
1973 ok(GetLastError() == 0xdeadbeef,
1974 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1976 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
1977 "HiliteMenuItem: Item 2 is hilited\n");
1979 /* hilite a menu item (by position) */
1981 SetLastError(0xdeadbeef);
1982 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_HILITE
| MF_BYPOSITION
),
1983 "HiliteMenuItem: call should not have failed.\n");
1984 ok(GetLastError() == 0xdeadbeef,
1985 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1989 ok(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
,
1990 "HiliteMenuItem: Item 2 is not hilited\n");
1993 /* unhilite a menu item (by position) */
1995 SetLastError(0xdeadbeef);
1996 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 1, MF_UNHILITE
| MF_BYPOSITION
),
1997 "HiliteMenuItem: call should not have failed.\n");
1998 ok(GetLastError() == 0xdeadbeef,
1999 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2001 ok(!(GetMenuState(hPopupMenu
, 1, MF_BYPOSITION
) & MF_HILITE
),
2002 "HiliteMenuItem: Item 2 is hilited\n");
2004 /* hilite a menu item (by command) */
2006 SetLastError(0xdeadbeef);
2007 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 103, MF_HILITE
| MF_BYCOMMAND
),
2008 "HiliteMenuItem: call should not have failed.\n");
2009 ok(GetLastError() == 0xdeadbeef,
2010 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2014 ok(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
,
2015 "HiliteMenuItem: Item 3 is not hilited\n");
2018 /* unhilite a menu item (by command) */
2020 SetLastError(0xdeadbeef);
2021 ok(HiliteMenuItem(hWnd
, hPopupMenu
, 103, MF_UNHILITE
| MF_BYCOMMAND
),
2022 "HiliteMenuItem: call should not have failed.\n");
2023 ok(GetLastError() == 0xdeadbeef,
2024 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2026 ok(!(GetMenuState(hPopupMenu
, 2, MF_BYPOSITION
) & MF_HILITE
),
2027 "HiliteMenuItem: Item 3 is hilited\n");
2029 DestroyWindow(hWnd
);
2032 static void check_menu_items(HMENU hmenu
, UINT checked_cmd
, UINT checked_type
,
2037 count
= GetMenuItemCount(hmenu
);
2038 ok (count
!= -1, "GetMenuItemCount returned -1\n");
2040 for (i
= 0; i
< count
; i
++)
2045 memset(&mii
, 0, sizeof(mii
));
2046 mii
.cbSize
= sizeof(mii
);
2047 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
;
2048 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2049 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2051 trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2052 i
, mii
.fType
, mii
.fState
, mii
.wID
, mii
.hSubMenu
);
2056 ok((HMENU
)mii
.wID
== mii
.hSubMenu
, "id %u: wID should be equal to hSubMenu\n", checked_cmd
);
2057 check_menu_items(mii
.hSubMenu
, checked_cmd
, checked_type
, checked_state
);
2061 if (mii
.wID
== checked_cmd
)
2063 ok(mii
.fType
== checked_type
, "id %u: expected fType %04x, got %04x\n", checked_cmd
, checked_type
, mii
.fType
);
2064 ok(mii
.fState
== checked_state
, "id %u: expected fState %04x, got %04x\n", checked_cmd
, checked_state
, mii
.fState
);
2065 ok(mii
.wID
!= 0, "id %u: not expected wID 0\n", checked_cmd
);
2069 ok(mii
.fType
!= MFT_RADIOCHECK
, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd
, mii
.wID
);
2071 if (mii
.fType
== MFT_SEPARATOR
)
2073 ok(mii
.fState
== MFS_GRAYED
, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd
, mii
.fState
);
2074 ok(mii
.wID
== 0, "id %u: expected wID 0, got %u\n", checked_cmd
, mii
.wID
);
2078 ok(mii
.fState
== 0, "id %u: expected fState 0, got %04x\n", checked_cmd
, mii
.fState
);
2079 ok(mii
.wID
!= 0, "id %u: not expected wID 0\n", checked_cmd
);
2086 static void clear_ftype_and_state(HMENU hmenu
, UINT id
, UINT flags
)
2091 memset(&mii
, 0, sizeof(mii
));
2092 mii
.cbSize
= sizeof(mii
);
2093 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
2094 ret
= SetMenuItemInfo(hmenu
, id
, (flags
& MF_BYPOSITION
) != 0, &mii
);
2095 ok(ret
, "SetMenuItemInfo(%u) failed\n", id
);
2098 static void test_CheckMenuRadioItem(void)
2103 hmenu
= LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1));
2106 check_menu_items(hmenu
, -1, 0, 0);
2108 ret
= CheckMenuRadioItem(hmenu
, 100, 100, 100, MF_BYCOMMAND
);
2109 ok(ret
, "CheckMenuRadioItem failed\n");
2110 check_menu_items(hmenu
, 100, MFT_RADIOCHECK
, MFS_CHECKED
);
2112 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2113 ret
= CheckMenuRadioItem(hmenu
, 100, 100, -1, MF_BYCOMMAND
);
2114 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2115 check_menu_items(hmenu
, 100, MFT_RADIOCHECK
, 0);
2118 clear_ftype_and_state(hmenu
, 100, MF_BYCOMMAND
);
2119 check_menu_items(hmenu
, -1, 0, 0);
2121 /* first and checked items are on different menus */
2122 ret
= CheckMenuRadioItem(hmenu
, 0, 300, 202, MF_BYCOMMAND
);
2123 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2124 check_menu_items(hmenu
, -1, 0, 0);
2126 ret
= CheckMenuRadioItem(hmenu
, 200, 300, 202, MF_BYCOMMAND
);
2127 ok(ret
, "CheckMenuRadioItem failed\n");
2128 check_menu_items(hmenu
, 202, MFT_RADIOCHECK
, MFS_CHECKED
);
2130 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2131 ret
= CheckMenuRadioItem(hmenu
, 202, 202, -1, MF_BYCOMMAND
);
2132 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2133 check_menu_items(hmenu
, 202, MFT_RADIOCHECK
, 0);
2136 clear_ftype_and_state(hmenu
, 202, MF_BYCOMMAND
);
2137 check_menu_items(hmenu
, -1, 0, 0);
2139 /* just for fun, try to check separator */
2140 ret
= CheckMenuRadioItem(hmenu
, 0, 300, 0, MF_BYCOMMAND
);
2141 ok(!ret
, "CheckMenuRadioItem should return FALSE\n");
2142 check_menu_items(hmenu
, -1, 0, 0);
2145 static void test_menu_resource_layout(void)
2149 MENUITEMTEMPLATEHEADER mith
;
2153 { 0, 0 }, /* versionNumber, offset */
2155 /* mtOption, mtID, mtString[] '\0' terminated */
2156 MF_STRING
, 1, 'F', 0,
2159 /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2160 MF_STRING
|MF_GRAYED
|MF_END
, 5, 'E', 0
2165 UINT type
, state
, id
;
2169 { MF_STRING
, MF_ENABLED
, 1, "F" },
2170 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 2, "" },
2171 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 3, "" },
2172 /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/
2173 { MF_STRING
, MF_GRAYED
, 5, "E" },
2174 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 6, "" },
2175 { MF_STRING
, MF_ENABLED
, 7, "" },
2176 { MF_SEPARATOR
, MF_GRAYED
|MF_DISABLED
, 8, "" }
2182 hmenu
= LoadMenuIndirect(&menu_template
);
2183 ok(hmenu
!= 0, "LoadMenuIndirect error %u\n", GetLastError());
2185 ret
= AppendMenu(hmenu
, MF_STRING
, 6, NULL
);
2186 ok(ret
, "AppendMenu failed\n");
2187 ret
= AppendMenu(hmenu
, MF_STRING
, 7, "\0");
2188 ok(ret
, "AppendMenu failed\n");
2189 ret
= AppendMenu(hmenu
, MF_SEPARATOR
, 8, "separator");
2190 ok(ret
, "AppendMenu failed\n");
2192 count
= GetMenuItemCount(hmenu
);
2193 ok(count
== sizeof(menu_data
)/sizeof(menu_data
[0]),
2194 "expected %u menu items, got %u\n",
2195 (UINT
)(sizeof(menu_data
)/sizeof(menu_data
[0])), count
);
2197 for (i
= 0; i
< count
; i
++)
2202 memset(&mii
, 0, sizeof(mii
));
2203 mii
.cbSize
= sizeof(mii
);
2204 mii
.dwTypeData
= buf
;
2205 mii
.cch
= sizeof(buf
);
2206 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_ID
| MIIM_STRING
;
2207 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2208 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2210 trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2211 i
, mii
.fType
, mii
.fState
, mii
.wID
, (LPCSTR
)mii
.dwTypeData
);
2213 ok(mii
.fType
== menu_data
[i
].type
,
2214 "%u: expected fType %04x, got %04x\n", i
, menu_data
[i
].type
, mii
.fType
);
2215 ok(mii
.fState
== menu_data
[i
].state
,
2216 "%u: expected fState %04x, got %04x\n", i
, menu_data
[i
].state
, mii
.fState
);
2217 ok(mii
.wID
== menu_data
[i
].id
,
2218 "%u: expected wID %04x, got %04x\n", i
, menu_data
[i
].id
, mii
.wID
);
2219 ok(mii
.cch
== strlen(menu_data
[i
].str
),
2220 "%u: expected cch %u, got %u\n", i
, (UINT
)strlen(menu_data
[i
].str
), mii
.cch
);
2221 ok(!strcmp((LPCSTR
)mii
.dwTypeData
, menu_data
[i
].str
),
2222 "%u: expected dwTypeData %s, got %s\n", i
, menu_data
[i
].str
, (LPCSTR
)mii
.dwTypeData
);
2234 static HMENU
create_menu_from_data(const struct menu_data
*item
, INT item_count
)
2240 hmenu
= CreateMenu();
2243 for (i
= 0; i
< item_count
; i
++)
2245 SetLastError(0xdeadbeef);
2246 ret
= AppendMenu(hmenu
, item
[i
].type
, item
[i
].id
, item
[i
].str
);
2247 ok(ret
, "%d: AppendMenu(%04x, %04x, %p) error %u\n",
2248 i
, item
[i
].type
, item
[i
].id
, item
[i
].str
, GetLastError());
2253 static void compare_menu_data(HMENU hmenu
, const struct menu_data
*item
, INT item_count
)
2258 count
= GetMenuItemCount(hmenu
);
2259 ok(count
== item_count
, "expected %d, got %d menu items\n", count
, item_count
);
2261 for (i
= 0; i
< count
; i
++)
2266 memset(&mii
, 0, sizeof(mii
));
2267 mii
.cbSize
= sizeof(mii
);
2268 mii
.dwTypeData
= buf
;
2269 mii
.cch
= sizeof(buf
);
2270 mii
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
| MIIM_BITMAP
;
2271 ret
= GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
);
2272 ok(ret
, "GetMenuItemInfo(%u) failed\n", i
);
2274 trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2275 i
, mii
.fType
, mii
.fState
, mii
.wID
, mii
.hbmpItem
);
2277 ok(mii
.fType
== item
[i
].type
,
2278 "%u: expected fType %04x, got %04x\n", i
, item
[i
].type
, mii
.fType
);
2279 ok(mii
.wID
== item
[i
].id
,
2280 "%u: expected wID %04x, got %04x\n", i
, item
[i
].id
, mii
.wID
);
2281 if (item
[i
].type
& (MF_BITMAP
| MF_SEPARATOR
))
2283 /* For some reason Windows sets high word to not 0 for
2286 ok(LOWORD(mii
.hbmpItem
) == LOWORD(item
[i
].str
),
2287 "%u: expected hbmpItem %p, got %p\n", i
, item
[i
].str
, mii
.hbmpItem
);
2291 ok(mii
.cch
== strlen(item
[i
].str
),
2292 "%u: expected cch %u, got %u\n", i
, (UINT
)strlen(item
[i
].str
), mii
.cch
);
2293 ok(!strcmp((LPCSTR
)mii
.dwTypeData
, item
[i
].str
),
2294 "%u: expected dwTypeData %s, got %s\n", i
, item
[i
].str
, (LPCSTR
)mii
.dwTypeData
);
2299 static void test_InsertMenu(void)
2301 /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2302 * regardless of their id.
2304 static const struct menu_data in1
[] =
2306 { MF_STRING
, 1, "File" },
2307 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) },
2308 { MF_STRING
|MF_HELP
, 2, "Help" }
2310 static const struct menu_data out1
[] =
2312 { MF_STRING
, 1, "File" },
2313 { MF_STRING
|MF_HELP
, 2, "Help" },
2314 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) }
2316 static const struct menu_data in2
[] =
2318 { MF_STRING
, 1, "File" },
2319 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(100) },
2320 { MF_STRING
|MF_HELP
, 2, "Help" }
2322 static const struct menu_data out2
[] =
2324 { MF_STRING
, 1, "File" },
2325 { MF_BITMAP
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(100) },
2326 { MF_STRING
|MF_HELP
, 2, "Help" }
2328 static const struct menu_data in3
[] =
2330 { MF_STRING
, 1, "File" },
2331 { MF_SEPARATOR
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(1) },
2332 { MF_STRING
|MF_HELP
, 2, "Help" }
2334 static const struct menu_data out3
[] =
2336 { MF_STRING
, 1, "File" },
2337 { MF_SEPARATOR
|MF_HELP
, SC_CLOSE
, MAKEINTRESOURCE(0) },
2338 { MF_STRING
|MF_HELP
, 2, "Help" },
2340 static const struct menu_data in4
[] =
2342 { MF_STRING
, 1, "File" },
2343 { MF_BITMAP
|MF_HELP
, 1, MAKEINTRESOURCE(1) },
2344 { MF_STRING
|MF_HELP
, 2, "Help" }
2346 static const struct menu_data out4
[] =
2348 { MF_STRING
, 1, "File" },
2349 { MF_STRING
|MF_HELP
, 2, "Help" },
2350 { MF_BITMAP
|MF_HELP
, 1, MAKEINTRESOURCE(1) }
2354 #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0]))
2355 #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0]))
2357 hmenu
= create_menu(in1
);
2358 compare_menu(hmenu
, out1
);
2361 hmenu
= create_menu(in2
);
2362 compare_menu(hmenu
, out2
);
2365 hmenu
= create_menu(in3
);
2366 compare_menu(hmenu
, out3
);
2369 hmenu
= create_menu(in4
);
2370 compare_menu(hmenu
, out4
);
2379 init_function_pointers();
2381 /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't
2384 if (correct_behavior())
2386 test_menu_add_string();
2387 test_menu_iteminfo();
2388 test_menu_search_bycommand();
2389 test_CheckMenuRadioItem();
2390 test_menu_resource_layout();
2394 register_menu_check_class();
2396 test_menu_locked_by_window();
2397 test_menu_ownerdraw();
2398 test_menu_bmp_and_string();
2401 skip("SendInput is not available\n");
2406 test_menu_hilitemenuitem();