- update user32 winetest
[reactos.git] / rostests / winetests / user32 / menu.c
1 /*
2 * Unit tests for menus
3 *
4 * Copyright 2005 Robert Shearman
5 * Copyright 2007 Dmitry Timoshkov
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #define _WIN32_WINNT 0x0501
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #define OEMRESOURCE /* For OBM_MNARROW */
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35
36 #include "wine/test.h"
37
38 static ATOM atomMenuCheckClass;
39
40 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
41 static UINT (WINAPI *pSendInput)(UINT, INPUT*, size_t);
42 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
43
44 static void init_function_pointers(void)
45 {
46 HMODULE hdll = GetModuleHandleA("user32");
47
48 #define GET_PROC(func) \
49 p ## func = (void*)GetProcAddress(hdll, #func); \
50 if(!p ## func) \
51 trace("GetProcAddress(%s) failed\n", #func);
52
53 GET_PROC(GetMenuInfo)
54 GET_PROC(SendInput)
55 GET_PROC(SetMenuInfo)
56
57 #undef GET_PROC
58 }
59
60 static BOOL correct_behavior(void)
61 {
62 HMENU hmenu;
63 MENUITEMINFO info;
64 BOOL rc;
65
66 hmenu = CreateMenu();
67
68 memset(&info, 0, sizeof(MENUITEMINFO));
69 info.cbSize= sizeof(MENUITEMINFO);
70 SetLastError(0xdeadbeef);
71 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
72 /* Win9x : 0xdeadbeef
73 * NT4 : ERROR_INVALID_PARAMETER
74 * >= W2K : ERROR_MENU_ITEM_NOT_FOUND
75 */
76 if (!rc && GetLastError() != ERROR_MENU_ITEM_NOT_FOUND)
77 {
78 win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n");
79 DestroyMenu(hmenu);
80 return FALSE;
81 }
82
83 DestroyMenu(hmenu);
84 return TRUE;
85 }
86
87 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
88 {
89 switch (msg)
90 {
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);
97 }
98 return DefWindowProc(hwnd, msg, wparam, lparam);
99 }
100
101 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
102 * our own type */
103 typedef struct
104 {
105 DWORD type;
106 union
107 {
108 MOUSEINPUT mi;
109 KEYBDINPUT ki;
110 HARDWAREINPUT hi;
111 } u;
112 } TEST_INPUT;
113
114 /* globals to communicate between test and wndproc */
115
116 static BOOL bMenuVisible;
117 static HMENU hMenus[4];
118
119 #define MOD_SIZE 10
120 #define MOD_NRMENUS 8
121
122 /* menu texts with their sizes */
123 static struct {
124 LPCSTR text;
125 SIZE size; /* size of text up to any \t */
126 SIZE sc_size; /* size of the short-cut */
127 } MOD_txtsizes[] = {
128 { "Pinot &Noir" },
129 { "&Merlot\bF4" },
130 { "Shira&z\tAlt+S" },
131 { "" },
132 { NULL }
133 };
134
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)
145 {
146 switch (msg)
147 {
148 case WM_MEASUREITEM:
149 {
150 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
151 if( winetest_debug)
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;
157 return TRUE;
158 }
159 case WM_DRAWITEM:
160 {
161 DRAWITEMSTRUCT * pdis;
162 TEXTMETRIC tm;
163 HPEN oldpen;
164 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
165 SIZE sz;
166 int i;
167 pdis = (DRAWITEMSTRUCT *) lparam;
168 if( winetest_debug) {
169 RECT rc;
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);
181 }
182 /* calculate widths of some menu texts */
183 if( ! MOD_txtsizes[0].size.cx)
184 for(i = 0; MOD_txtsizes[i].text; i++) {
185 char buf[100], *p;
186 RECT rc={0,0,0,0};
187 strcpy( buf, MOD_txtsizes[i].text);
188 if( ( p = strchr( buf, '\t'))) {
189 *p = '\0';
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;
194 }
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;
199 }
200
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;
210 return TRUE;
211 }
212 case WM_ENTERIDLE:
213 {
214 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
215 return TRUE;
216 }
217
218 }
219 return DefWindowProc(hwnd, msg, wparam, lparam);
220 }
221
222 static void register_menu_check_class(void)
223 {
224 WNDCLASS wc =
225 {
226 0,
227 menu_check_wnd_proc,
228 0,
229 0,
230 GetModuleHandle(NULL),
231 NULL,
232 LoadCursor(NULL, IDC_ARROW),
233 (HBRUSH)(COLOR_BTNFACE+1),
234 NULL,
235 TEXT("WineMenuCheck"),
236 };
237
238 atomMenuCheckClass = RegisterClass(&wc);
239 }
240
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)
244 {
245 BOOL ret;
246 HMENU hmenu;
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());
259
260 ret = DrawMenuBar(hwnd);
261 todo_wine {
262 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
263 }
264 ret = IsMenu(GetMenu(hwnd));
265 ok(!ret, "Menu handle should have been destroyed\n");
266
267 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
268 /* did we process the WM_INITMENU message? */
269 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
270 todo_wine {
271 ok(ret, "WM_INITMENU should have been sent\n");
272 }
273
274 DestroyWindow(hwnd);
275 }
276
277 static void test_menu_ownerdraw(void)
278 {
279 int i,j,k;
280 BOOL ret;
281 HMENU hmenu;
282 LONG leftcol;
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());
287 if( !hwnd) return;
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;}
292 k=0;
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);
297 k++;
298 ok( ret, "AppendMenu failed for %d\n", k-1);
299 }
300 MOD_maxid = k-1;
301 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
302 /* display the menu */
303 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
304
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);
332 /* test width */
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);
336 /* and height */
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);
340
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;}
347 MOD_maxid=1;
348 for(i=0;i<2;i++) {
349 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
350 ok( ret, "AppendMenu failed for %d\n", i);
351 }
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());
355 /* test width */
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);
359 /* test hight */
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);
363
364 /* clean up */
365 ret = DestroyMenu(hmenu);
366 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
367 DestroyWindow(hwnd);
368 }
369
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)
374 {
375 BOOL ret;
376 HMENU hmenu, submenu;
377 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
378 MENUINFO mi;
379 RECT rc;
380 CHAR text_copy[16];
381 int hastab, expect;
382 int failed = 0;
383
384 MOD_GotDrawItemMsg = FALSE;
385 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
386 mii.fType = 0;
387 /* check the menu item unless MNS_CHECKORBMP is set */
388 mii.fState = (mnuopt != 2 ? MFS_CHECKED : MFS_UNCHECKED);
389 mii.dwItemData =0;
390 MODsizes[0] = bmpsize;
391 hastab = 0;
392 if( text ) {
393 char *p;
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;
399 }
400 }
401 /* tabs don't make sense in menubars */
402 if(hastab && !ispop) return;
403 if( hbmp) {
404 mii.fMask |= MIIM_BITMAP;
405 mii.hbmpItem = hbmp;
406 }
407 submenu = CreateMenu();
408 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
409 if( ispop)
410 hmenu = CreatePopupMenu();
411 else
412 hmenu = CreateMenu();
413 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
414 if( hassub) {
415 mii.fMask |= MIIM_SUBMENU;
416 mii.hSubMenu = submenu;
417 }
418 if( mnuopt) {
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());
425 }
426 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
427 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
428 failed = !ret;
429 if( winetest_debug) {
430 HDC hdc=GetDC(hwnd);
431 RECT rc = {100, 50, 400, 70};
432 char buf[100];
433
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);
438 }
439 if(ispop)
440 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
441 else {
442 ret = SetMenu( hwnd, hmenu);
443 ok(ret, "SetMenu failed with error %d\n", GetLastError());
444 DrawMenuBar( hwnd);
445 }
446 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
447 /* check menu width */
448 if( ispop)
449 expect = ( text || hbmp ?
450 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
451 : 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) ;
456 else
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 */
464 if( ispop)
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)));
468 else
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 */
477 /* horizontal */
478 if (!ispop)
479 expect = 3;
480 else if (mnuopt == 0)
481 expect = 4 + GetSystemMetrics(SM_CXMENUCHECK);
482 else if (mnuopt == 1)
483 expect = 4;
484 else /* mnuopt == 2 */
485 expect = 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);
489 /* vertical */
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);
494 }
495 /* if there was a failure, report details */
496 if( failed) {
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);
507 }
508 /* clean up */
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());
513 }
514
515
516 static void test_menu_bmp_and_string(void)
517 {
518 BYTE bmfill[300];
519 HBITMAP hbm_arrow;
520 BITMAP bm;
521 INT arrowwidth;
522 HWND hwnd;
523 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
524
525 if( !pGetMenuInfo)
526 {
527 skip("GetMenuInfo is not available\n");
528 return;
529 }
530
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;
538
539 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
540 if( !hwnd) return;
541 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
542
543 if( winetest_debug)
544 trace(" check %d,%d arrow %d avechar %d\n",
545 GetSystemMetrics(SM_CXMENUCHECK ),
546 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
547 count = 0;
548 MOD_maxid = 0;
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,
565 bitmaps[bmpidx],
566 bmsizes[szidx],
567 MOD_txtsizes[txtidx].text,
568 MOD_txtsizes[txtidx].size,
569 MOD_txtsizes[txtidx].sc_size);
570 }
571 }
572 }
573 }
574 DeleteObject( hbm);
575 }
576 }
577 /* clean up */
578 DestroyWindow(hwnd);
579 }
580
581 static void test_menu_add_string( void )
582 {
583 HMENU hmenu;
584 MENUITEMINFO info;
585 BOOL rc;
586 int ret;
587
588 char string[0x80];
589 char string2[0x80];
590
591 char strback[0x80];
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};
595
596 hmenu = CreateMenu();
597
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;
602 info.cch = 6;
603 info.dwItemData = 0;
604 info.wID = 1;
605 info.fState = 0;
606 InsertMenuItem(hmenu, 0, TRUE, &info );
607
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;
613 string[0] = 0;
614 GetMenuItemInfo( hmenu, 0, TRUE, &info );
615
616 ok( !strcmp( string, "blah" ), "menu item name differed\n");
617
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");
627
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");
631
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");
636 else
637 {
638 ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
639 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
640 }
641
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");
650
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");
654
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");
663
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");
669
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");
673
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");
682
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");
685
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");
699 else
700 ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
701
702 DestroyMenu( hmenu );
703 }
704
705 /* define building blocks for the menu item info tests */
706 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
707 {
708 if (n <= 0) return 0;
709 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
710 return *str1 - *str2;
711 }
712
713 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
714 {
715 WCHAR *p = dst;
716 while ((*p++ = *src++));
717 return dst;
718 }
719
720
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));
724
725 #define DUMPMIINF(s,i,e)\
726 {\
727 DMIINFF( i, e, fMask)\
728 DMIINFF( i, e, fType)\
729 DMIINFF( i, e, fState)\
730 DMIINFF( i, e, wID)\
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)\
736 DMIINFF( i, e, cch)\
737 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
738 }
739
740 /* insert menu item */
741 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
742 eret1)\
743 {\
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)\
753 {\
754 skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
755 break;\
756 }\
757 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
758 stop = TRUE;\
759 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
760
761
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)\
766 {\
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;\
772 if( !stop) {\
773 SetLastError( 0xdeadbeef);\
774 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
775 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
776 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
777 {\
778 skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
779 break;\
780 }\
781 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
782 else { \
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);\
794 if( (eret3)){\
795 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
796 }else\
797 ok( !ret, "GetMenuString should have failed\n");\
798 }\
799 }\
800 }\
801 }
802
803 #define TMII_DONE \
804 RemoveMenu(hmenu, 0, TRUE );\
805 DestroyMenu( hmenu );\
806 DestroyMenu( submenu );\
807 submenu = CreateMenu();\
808 }
809 /* modify menu */
810 #define TMII_MODM( flags, id, data, eret )\
811 if( !stop) {\
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)\
816 {\
817 skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
818 break;\
819 }\
820 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
821 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
822 }
823
824 /* SetMenuItemInfo */
825 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
826 eret1)\
827 if( !stop) {\
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)\
835 {\
836 skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
837 break;\
838 }\
839 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
840 stop = TRUE;\
841 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
842 }
843
844
845
846 #define OK 1
847 #define ER 0
848
849
850 static void test_menu_iteminfo( void )
851 {
852 int S=sizeof( MENUITEMINFOA);
853 int ansi = TRUE;
854 char txtA[]="wine";
855 char initA[]="XYZ";
856 char emptyA[]="";
857 WCHAR txtW[]={'W','i','n','e',0};
858 WCHAR initW[]={'X','Y','Z',0};
859 WCHAR emptyW[]={0};
860 void *txt, *init, *empty, *string;
861 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
862 char stringA[0x80];
863 HMENU submenu=CreateMenu();
864
865 do {
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, },
874 txt, OK, OK )
875 TMII_DONE
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, },
879 empty, OK, ER )
880 TMII_DONE
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, },
884 empty, OK, ER )
885 TMII_DONE
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, },
889 empty, OK, ER )
890 TMII_DONE
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, },
895 empty, OK, OK )
896 TMII_DONE
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, },
900 txt, OK, OK )
901 TMII_DONE
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, },
905 txt, OK, OK )
906 TMII_DONE
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, },
910 empty, OK, ER )
911 TMII_DONE
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, },
916 empty, OK, OK )
917 TMII_DONE
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, },
921 empty, ER, OK )
922 TMII_DONE
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, },
926 empty, OK, OK )
927 TMII_DONE
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, },
931 empty, ER, OK )
932 TMII_DONE
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, },
936 empty, OK, OK )
937 TMII_DONE
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, },
942 txt, OK, OK )
943 TMII_DONE
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, },
947 txt, OK, OK )
948 TMII_DONE
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, },
952 txt, OK, OK )
953 TMII_DONE
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, },
957 txt, OK, OK )
958 TMII_DONE
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, },
964 txt, OK, OK )
965 TMII_DONE
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, },
970 empty, OK, ER )
971 TMII_DONE
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, },
975 empty, OK, ER )
976 TMII_DONE
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, },
980 init, OK, ER )
981 TMII_DONE
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, },
985 init, OK, OK )
986 TMII_DONE
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, },
991 txt, OK, OK )
992 TMII_DONE
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, },
997 txt, OK, OK )
998 TMII_DONE
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, },
1002 empty, OK, ER )
1003 TMII_DONE
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, },
1007 empty, OK, ER )
1008 TMII_DONE
1009
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, },
1014 empty, OK, ER )
1015 TMII_DONE
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, },
1019 init, OK, ER )
1020 TMII_DONE
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, },
1025 init, OK, OK )
1026 TMII_DONE
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, },
1031 init, OK, ER )
1032 TMII_DONE
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, },
1037 empty, OK, OK )
1038 TMII_DONE
1039
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, },
1044 init, OK, ER )
1045 TMII_DONE
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, },
1049 init, OK, ER )
1050 TMII_DONE
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, },
1055 empty, OK, ER )
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, },
1058 empty, OK, ER )
1059 TMII_DONE
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, },
1064 init, OK, ER )
1065 TMII_DONE
1066 /* Separator */
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, },
1070 empty, OK, ER )
1071 TMII_DONE
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, },
1075 empty, OK, ER )
1076 TMII_DONE
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, },
1082 txt, OK, OK )
1083 TMII_DONE
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, },
1088 txt, OK, OK )
1089 TMII_DONE
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, },
1094 txt, OK, OK )
1095 TMII_DONE
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, },
1099 txt, OK, OK )
1100 TMII_DONE
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, },
1104 txt, OK, OK )
1105 TMII_DONE
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, },
1110 txt, OK, OK )
1111 TMII_DONE
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, },
1115 txt, OK, OK )
1116 TMII_DONE
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, },
1120 txt, OK, OK )
1121 TMII_DONE
1122
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, },
1126 txt, OK, OK )
1127 TMII_DONE
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, },
1133 txt, OK, OK )
1134 TMII_DONE
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, },
1140 empty, OK, ER )
1141 TMII_DONE
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, },
1146 empty, OK, ER )
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, },
1150 txt, OK, OK )
1151 TMII_DONE
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, },
1157 empty, OK, ER )
1158 TMII_DONE
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, },
1164 empty, OK, ER )
1165 TMII_DONE
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, },
1171 empty, OK, ER )
1172 TMII_DONE
1173 /* ask nothing */
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, },
1177 init, OK, OK )
1178 TMII_DONE
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, },
1183 empty, OK, ER )
1184 TMII_DONE
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, },
1188 init, OK, ER )
1189 TMII_DONE
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, },
1193 txt, OK, OK )
1194 TMII_DONE
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, },
1198 txt, OK, OK )
1199 TMII_DONE
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, },
1203 txt, OK, OK )
1204 TMII_DONE
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, },
1208 txt, OK, OK )
1209 TMII_DONE
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, },
1214 empty, OK, ER )
1215 TMII_DONE
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, },
1219 empty, OK, ER )
1220 TMII_DONE
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, },
1224 empty, OK, ER )
1225 TMII_DONE
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, },
1231 txt, OK, OK )
1232 TMII_DONE
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, },
1238 txt, OK, OK )
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, },
1241 txt, OK, OK )
1242 TMII_DONE
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, },
1248 txt, OK, OK )
1249 TMII_DONE
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, },
1255 init, OK, ER )
1256 TMII_DONE
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, },
1263 empty, OK, OK )
1264 TMII_DONE
1265 /* Type flags */
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, },
1269 empty, OK, OK )
1270 TMII_DONE
1271 /* State flags */
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, },
1276 empty, OK, OK )
1277 TMII_DONE
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, },
1283 empty, OK, OK )
1284 TMII_DONE
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, },
1290 empty, OK, OK )
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, },
1293 empty, OK, OK )
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, },
1296 empty, OK, OK )
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, },
1300 empty, OK, OK )
1301 TMII_DONE
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, },
1308 empty, OK, OK )
1309 TMII_DONE
1310 /* Type flags */
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, },
1314 empty, OK, OK )
1315 TMII_DONE
1316 /* State flags */
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, },
1321 empty, OK, OK )
1322 TMII_DONE
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, },
1328 empty, OK, OK )
1329 TMII_DONE
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, },
1335 empty, OK, OK )
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, },
1338 empty, OK, OK )
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, },
1341 empty, OK, OK )
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, },
1345 empty, OK, OK )
1346 TMII_DONE
1347 } while( !(ansi = !ansi) );
1348 DeleteObject( hbm);
1349 }
1350
1351 /*
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
1354 */
1355 static void test_menu_search_bycommand( void )
1356 {
1357 HMENU hmenu, hmenuSub, hmenuSub2;
1358 MENUITEMINFO info;
1359 BOOL rc;
1360 UINT id;
1361 char strback[0x80];
1362 char strIn[0x80];
1363 static CHAR menuitem[] = "MenuItem",
1364 menuitem2[] = "MenuItem 2";
1365
1366 /* Case 1: Menu containing a menu item */
1367 hmenu = CreateMenu();
1368
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;
1376
1377 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1378 ok (rc, "Inserting the menuitem failed\n");
1379
1380 id = GetMenuItemID(hmenu, 0);
1381 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1382
1383 /* Confirm the menuitem was given the id supplied (getting by position) */
1384 memset( &info, 0, sizeof info );
1385 strback[0] = 0x00;
1386 info.cbSize = sizeof(MENUITEMINFO);
1387 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1388 info.dwTypeData = strback;
1389 info.cch = sizeof(strback);
1390
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");
1395
1396 /* Search by id - Should return the item */
1397 memset( &info, 0, sizeof info );
1398 strback[0] = 0x00;
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 */
1404
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");
1408
1409 DestroyMenu( hmenu );
1410
1411 /* Case 2: Menu containing a popup menu */
1412 hmenu = CreateMenu();
1413 hmenuSub = CreateMenu();
1414
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");
1418
1419 id = GetMenuItemID(hmenu, 0);
1420 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1421
1422 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1423 memset( &info, 0, sizeof info );
1424 strback[0] = 0x00;
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;
1430
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");
1435
1436 /* Search by id - returns the popup menu itself */
1437 memset( &info, 0, sizeof info );
1438 strback[0] = 0x00;
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 */
1444
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");
1448
1449 /*
1450 Now add an item after it with the same id
1451 */
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");
1461
1462 /* Search by id - returns the item which follows the popup menu */
1463 memset( &info, 0, sizeof info );
1464 strback[0] = 0x00;
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 */
1470
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);
1474
1475 /*
1476 Now add an item before the popup (with the same id)
1477 */
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");
1487
1488 /* Search by id - returns the item which precedes the popup menu */
1489 memset( &info, 0, sizeof info );
1490 strback[0] = 0x00;
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 */
1496
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);
1500
1501 DestroyMenu( hmenu );
1502 DestroyMenu( hmenuSub );
1503
1504 /*
1505 Case 3: Menu containing a popup menu which in turn
1506 contains 2 items with the same id as the popup itself
1507 */
1508
1509 hmenu = CreateMenu();
1510 hmenuSub = CreateMenu();
1511
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*/
1518
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");
1521
1522 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1523 ok (rc, "Inserting the sub menu menuitem failed\n");
1524
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*/
1531
1532 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1533 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1534
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);
1538
1539 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1540 memset( &info, 0, sizeof info );
1541 strback[0] = 0x00;
1542 info.cbSize = sizeof(MENUITEMINFO);
1543 info.fMask = MIIM_STRING | MIIM_ID;
1544 info.dwTypeData = strback;
1545 info.cch = sizeof(strback);
1546
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 );
1553
1554 /*
1555 Case 4: Menu containing 2 popup menus, the second
1556 contains 2 items with the same id as the first popup menu
1557 */
1558 hmenu = CreateMenu();
1559 hmenuSub = CreateMenu();
1560 hmenuSub2 = CreateMenu();
1561
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");
1564
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");
1567
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*/
1574
1575 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1576 ok (rc, "Inserting the sub menu menuitem failed\n");
1577
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*/
1584
1585 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1586 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1587
1588 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1589 memset( &info, 0, sizeof info );
1590 strback[0] = 0x00;
1591 info.cbSize = sizeof(MENUITEMINFO);
1592 info.fMask = MIIM_STRING | MIIM_ID;
1593 info.dwTypeData = strback;
1594 info.cch = sizeof(strback);
1595
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);
1600
1601 memset( &info, 0, sizeof info );
1602 strback[0] = 0x00;
1603 info.cbSize = sizeof(MENUITEMINFO);
1604 info.fMask = MIIM_STRING | MIIM_ID;
1605 info.dwTypeData = strback;
1606 info.cch = sizeof(strback);
1607
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);
1612
1613 DestroyMenu( hmenu );
1614 DestroyMenu( hmenuSub );
1615 DestroyMenu( hmenuSub2 );
1616
1617
1618 /*
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.
1622 */
1623
1624 hmenu = CreateMenu();
1625 hmenuSub = CreateMenu();
1626
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");
1629
1630 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1631 ok (rc, "Appending the item to the popup menu failed\n");
1632
1633 /* Set the ID for hmenuSub */
1634 info.cbSize = sizeof(info);
1635 info.fMask = MIIM_ID;
1636 info.wID = 101;
1637
1638 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1639 ok(rc, "Setting the ID for the popup menu failed\n");
1640
1641 /* Check if the ID has been set */
1642 info.wID = 0;
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");
1646
1647 /* Prove getting the item info via ID returns the popup menu */
1648 memset( &info, 0, sizeof(info));
1649 strback[0] = 0x00;
1650 info.cbSize = sizeof(MENUITEMINFO);
1651 info.fMask = MIIM_STRING | MIIM_ID;
1652 info.dwTypeData = strback;
1653 info.cch = sizeof(strback);
1654
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);
1659
1660 /* Also look for the menu item */
1661 memset( &info, 0, sizeof(info));
1662 strback[0] = 0x00;
1663 info.cbSize = sizeof(MENUITEMINFO);
1664 info.fMask = MIIM_STRING | MIIM_ID;
1665 info.dwTypeData = strback;
1666 info.cch = sizeof(strback);
1667
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);
1672
1673 DestroyMenu(hmenu);
1674 DestroyMenu(hmenuSub);
1675 }
1676
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] */
1681 UINT uItem;
1682 };
1683
1684 static struct menu_mouse_tests_s {
1685 DWORD type;
1686 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1687 WORD wVk[5]; /* keys */
1688 BOOL bMenuVisible;
1689 BOOL _todo_wine;
1690 } menu_tests[] = {
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 },
1710
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 },
1722 { -1 }
1723 };
1724
1725 static void send_key(WORD wVk)
1726 {
1727 TEST_INPUT i[2];
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));
1733 }
1734
1735 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1736 {
1737 HMENU hMenu = hMenus[mi->uMenu];
1738 TEST_INPUT i[3];
1739 MSG msg;
1740 RECT r;
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);
1744 if(!ret) return;
1745
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));
1758
1759 /* hack to prevent mouse message buildup in Wine */
1760 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1761 }
1762
1763 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1764 {
1765 int i, j;
1766 HANDLE hWnd = lpParameter;
1767
1768 Sleep(500);
1769 /* mixed keyboard/mouse test */
1770 for (i = 0; menu_tests[i].type != -1; i++)
1771 {
1772 int elapsed = 0;
1773
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]);
1777 else
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]);
1780
1781 while (menu_tests[i].bMenuVisible != bMenuVisible)
1782 {
1783 if (elapsed > 200)
1784 break;
1785 elapsed += 20;
1786 Sleep(20);
1787 }
1788
1789 if (menu_tests[i]._todo_wine)
1790 {
1791 todo_wine {
1792 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1793 }
1794 }
1795 else
1796 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1797 }
1798 return 0;
1799 }
1800
1801 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1802 LPARAM lParam)
1803 {
1804 switch (msg) {
1805 case WM_ENTERMENULOOP:
1806 bMenuVisible = TRUE;
1807 break;
1808 case WM_EXITMENULOOP:
1809 bMenuVisible = FALSE;
1810 break;
1811 default:
1812 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1813 }
1814 return 0;
1815 }
1816
1817 static void test_menu_input(void) {
1818 MSG msg;
1819 WNDCLASSA wclass;
1820 HINSTANCE hInstance = GetModuleHandleA( NULL );
1821 HANDLE hThread, hWnd;
1822 DWORD tid;
1823
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) );
1838
1839 /* fixed menus */
1840 hMenus[3] = CreatePopupMenu();
1841 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1842 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1843
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");
1848
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");
1853
1854 SetMenu(hWnd, hMenus[1]);
1855 ShowWindow(hWnd, SW_SHOW);
1856 UpdateWindow(hWnd);
1857
1858 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid);
1859 while(1)
1860 {
1861 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1862 break;
1863 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1864 }
1865 DestroyWindow(hWnd);
1866 }
1867
1868 static void test_menu_flags( void )
1869 {
1870 HMENU hMenu, hPopupMenu;
1871
1872 hMenu = CreateMenu();
1873 hPopupMenu = CreatePopupMenu();
1874
1875 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1876
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");
1881
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");
1888
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");
1895
1896 DestroyMenu(hMenu);
1897 }
1898
1899 static void test_menu_hilitemenuitem( void )
1900 {
1901 HMENU hMenu, hPopupMenu;
1902 WNDCLASSA wclass;
1903 HWND hWnd;
1904
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) );
1919
1920 hMenu = CreateMenu();
1921 hPopupMenu = CreatePopupMenu();
1922
1923 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1924
1925 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1926 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1927 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1928
1929 SetMenu(hWnd, hMenu);
1930
1931 /* test invalid arguments */
1932
1933 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1934 "HiliteMenuItem: Item 2 is hilited\n");
1935
1936 SetLastError(0xdeadbeef);
1937 todo_wine
1938 {
1939 ok(!HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION),
1940 "HiliteMenuItem: call should have failed.\n");
1941 }
1942 ok(GetLastError() == 0xdeadbeef || /* 9x */
1943 GetLastError() == ERROR_INVALID_WINDOW_HANDLE /* NT */,
1944 "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError());
1945
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());
1952
1953 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1954 "HiliteMenuItem: Item 2 is hilited\n");
1955
1956 /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */
1957
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());
1963
1964 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1965 "HiliteMenuItem: Item 2 is hilited\n");
1966
1967 SetLastError(0xdeadbeef);
1968 todo_wine
1969 {
1970 ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE),
1971 "HiliteMenuItem: call should have succeeded.\n");
1972 }
1973 ok(GetLastError() == 0xdeadbeef,
1974 "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
1975
1976 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1977 "HiliteMenuItem: Item 2 is hilited\n");
1978
1979 /* hilite a menu item (by position) */
1980
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());
1986
1987 todo_wine
1988 {
1989 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1990 "HiliteMenuItem: Item 2 is not hilited\n");
1991 }
1992
1993 /* unhilite a menu item (by position) */
1994
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());
2000
2001 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2002 "HiliteMenuItem: Item 2 is hilited\n");
2003
2004 /* hilite a menu item (by command) */
2005
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());
2011
2012 todo_wine
2013 {
2014 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2015 "HiliteMenuItem: Item 3 is not hilited\n");
2016 }
2017
2018 /* unhilite a menu item (by command) */
2019
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());
2025
2026 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE),
2027 "HiliteMenuItem: Item 3 is hilited\n");
2028
2029 DestroyWindow(hWnd);
2030 }
2031
2032 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
2033 UINT checked_state)
2034 {
2035 INT i, count;
2036
2037 count = GetMenuItemCount(hmenu);
2038 ok (count != -1, "GetMenuItemCount returned -1\n");
2039
2040 for (i = 0; i < count; i++)
2041 {
2042 BOOL ret;
2043 MENUITEMINFO mii;
2044
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);
2050 #if 0
2051 trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2052 i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
2053 #endif
2054 if (mii.hSubMenu)
2055 {
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);
2058 }
2059 else
2060 {
2061 if (mii.wID == checked_cmd)
2062 {
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);
2066 }
2067 else
2068 {
2069 ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID);
2070
2071 if (mii.fType == MFT_SEPARATOR)
2072 {
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);
2075 }
2076 else
2077 {
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);
2080 }
2081 }
2082 }
2083 }
2084 }
2085
2086 static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags)
2087 {
2088 BOOL ret;
2089 MENUITEMINFO mii;
2090
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);
2096 }
2097
2098 static void test_CheckMenuRadioItem(void)
2099 {
2100 BOOL ret;
2101 HMENU hmenu;
2102
2103 hmenu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1));
2104 assert(hmenu != 0);
2105
2106 check_menu_items(hmenu, -1, 0, 0);
2107
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);
2111
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);
2116
2117 /* clear check */
2118 clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND);
2119 check_menu_items(hmenu, -1, 0, 0);
2120
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);
2125
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);
2129
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);
2134
2135 /* clear check */
2136 clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND);
2137 check_menu_items(hmenu, -1, 0, 0);
2138
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);
2143 }
2144
2145 static void test_menu_resource_layout(void)
2146 {
2147 static const struct
2148 {
2149 MENUITEMTEMPLATEHEADER mith;
2150 WORD data[14];
2151 } menu_template =
2152 {
2153 { 0, 0 }, /* versionNumber, offset */
2154 {
2155 /* mtOption, mtID, mtString[] '\0' terminated */
2156 MF_STRING, 1, 'F', 0,
2157 MF_STRING, 2, 0,
2158 MF_SEPARATOR, 3, 0,
2159 /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2160 MF_STRING|MF_GRAYED|MF_END, 5, 'E', 0
2161 }
2162 };
2163 static const struct
2164 {
2165 UINT type, state, id;
2166 const char *str;
2167 } menu_data[] =
2168 {
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, "" }
2177 };
2178 HMENU hmenu;
2179 INT count, i;
2180 BOOL ret;
2181
2182 hmenu = LoadMenuIndirect(&menu_template);
2183 ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError());
2184
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");
2191
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);
2196
2197 for (i = 0; i < count; i++)
2198 {
2199 char buf[20];
2200 MENUITEMINFO mii;
2201
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);
2209 #if 0
2210 trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2211 i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
2212 #endif
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);
2223 }
2224
2225 DestroyMenu(hmenu);
2226 }
2227
2228 struct menu_data
2229 {
2230 UINT type, id;
2231 const char *str;
2232 };
2233
2234 static HMENU create_menu_from_data(const struct menu_data *item, INT item_count)
2235 {
2236 HMENU hmenu;
2237 INT i;
2238 BOOL ret;
2239
2240 hmenu = CreateMenu();
2241 assert(hmenu != 0);
2242
2243 for (i = 0; i < item_count; i++)
2244 {
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());
2249 }
2250 return hmenu;
2251 }
2252
2253 static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count)
2254 {
2255 INT count, i;
2256 BOOL ret;
2257
2258 count = GetMenuItemCount(hmenu);
2259 ok(count == item_count, "expected %d, got %d menu items\n", count, item_count);
2260
2261 for (i = 0; i < count; i++)
2262 {
2263 char buf[20];
2264 MENUITEMINFO mii;
2265
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);
2273 #if 0
2274 trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2275 i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
2276 #endif
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))
2282 {
2283 /* For some reason Windows sets high word to not 0 for
2284 * not "magic" ids.
2285 */
2286 ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str),
2287 "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem);
2288 }
2289 else
2290 {
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);
2295 }
2296 }
2297 }
2298
2299 static void test_InsertMenu(void)
2300 {
2301 /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2302 * regardless of their id.
2303 */
2304 static const struct menu_data in1[] =
2305 {
2306 { MF_STRING, 1, "File" },
2307 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2308 { MF_STRING|MF_HELP, 2, "Help" }
2309 };
2310 static const struct menu_data out1[] =
2311 {
2312 { MF_STRING, 1, "File" },
2313 { MF_STRING|MF_HELP, 2, "Help" },
2314 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) }
2315 };
2316 static const struct menu_data in2[] =
2317 {
2318 { MF_STRING, 1, "File" },
2319 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2320 { MF_STRING|MF_HELP, 2, "Help" }
2321 };
2322 static const struct menu_data out2[] =
2323 {
2324 { MF_STRING, 1, "File" },
2325 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2326 { MF_STRING|MF_HELP, 2, "Help" }
2327 };
2328 static const struct menu_data in3[] =
2329 {
2330 { MF_STRING, 1, "File" },
2331 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2332 { MF_STRING|MF_HELP, 2, "Help" }
2333 };
2334 static const struct menu_data out3[] =
2335 {
2336 { MF_STRING, 1, "File" },
2337 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(0) },
2338 { MF_STRING|MF_HELP, 2, "Help" },
2339 };
2340 static const struct menu_data in4[] =
2341 {
2342 { MF_STRING, 1, "File" },
2343 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) },
2344 { MF_STRING|MF_HELP, 2, "Help" }
2345 };
2346 static const struct menu_data out4[] =
2347 {
2348 { MF_STRING, 1, "File" },
2349 { MF_STRING|MF_HELP, 2, "Help" },
2350 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) }
2351 };
2352 HMENU hmenu;
2353
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]))
2356
2357 hmenu = create_menu(in1);
2358 compare_menu(hmenu, out1);
2359 DestroyMenu(hmenu);
2360
2361 hmenu = create_menu(in2);
2362 compare_menu(hmenu, out2);
2363 DestroyMenu(hmenu);
2364
2365 hmenu = create_menu(in3);
2366 compare_menu(hmenu, out3);
2367 DestroyMenu(hmenu);
2368
2369 hmenu = create_menu(in4);
2370 compare_menu(hmenu, out4);
2371 DestroyMenu(hmenu);
2372
2373 #undef create_menu
2374 #undef compare_menu
2375 }
2376
2377 START_TEST(menu)
2378 {
2379 init_function_pointers();
2380
2381 /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't
2382 * handle that.
2383 */
2384 if (correct_behavior())
2385 {
2386 test_menu_add_string();
2387 test_menu_iteminfo();
2388 test_menu_search_bycommand();
2389 test_CheckMenuRadioItem();
2390 test_menu_resource_layout();
2391 test_InsertMenu();
2392 }
2393
2394 register_menu_check_class();
2395
2396 test_menu_locked_by_window();
2397 test_menu_ownerdraw();
2398 test_menu_bmp_and_string();
2399
2400 if( !pSendInput)
2401 skip("SendInput is not available\n");
2402 else
2403 test_menu_input();
2404 test_menu_flags();
2405
2406 test_menu_hilitemenuitem();
2407 }