user32: In SetMenuInfo() implement the MIM_APPLYTOSUBMENUS. Also set last error if...
[wine] / dlls / user32 / tests / 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, pdis->hwndItem, pdis->itemData, pdis->itemID,
173                             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_PTR)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, MAKEINTRESOURCE(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, 10, 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     if (0)  /* comment out menu size checks, behavior is different in almost every Windows version */
448             /* the tests should however succeed on win2000, XP and Wine (at least upto 1.1.15) */
449             /* with a variety of dpi's and desktop font sizes */
450     {
451         /* check menu width */
452         if( ispop)
453             expect = ( text || hbmp ?
454                        4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
455                        : 0) +
456                        arrowwidth  + MOD_avec + (hbmp ?
457                                     ((int)hbmp<0||(int)hbmp>12 ? bmpsize.cx + 2 : GetSystemMetrics( SM_CXMENUSIZE) + 2)
458                                     : 0) +
459                 (text && hastab ? /* TAB space */
460                  MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
461                 (text ?  2 + (text[0] ? size.cx :0): 0) ;
462         else
463             expect = !(text || hbmp) ? 0 :
464                 ( hbmp ? (text ? 2:0) + bmpsize.cx  : 0 ) +
465                 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
466         ok( rc.right - rc.left == expect,
467             "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
468         failed = failed || !(rc.right - rc.left == expect);
469         /* check menu height */
470         if( ispop)
471             expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
472                           max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
473                                (hbmp ?
474                                    ((int)hbmp<0||(int)hbmp>12 ?
475                                        bmpsize.cy + 2
476                                      : GetSystemMetrics( SM_CYMENUSIZE) + 2)
477                                  : 0)));
478         else
479             expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
480                        max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
481         ok( rc.bottom - rc.top == expect,
482             "menu height wrong, got %d expected %d (%d)\n",
483             rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
484         failed = failed || !(rc.bottom - rc.top == expect);
485         if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
486             /* check the position of the bitmap */
487             /* horizontal */
488             if (!ispop)
489                 expect = 3;
490             else if (mnuopt == 0)
491                 expect = 4 + GetSystemMetrics(SM_CXMENUCHECK);
492             else if (mnuopt == 1)
493                 expect = 4;
494             else /* mnuopt == 2 */
495                 expect = 2;
496             ok( expect == MOD_rc[0].left,
497                 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
498             failed = failed || !(expect == MOD_rc[0].left);
499             /* vertical */
500             expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
501             ok( expect == MOD_rc[0].top,
502                 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
503             failed = failed || !(expect == MOD_rc[0].top);
504         }
505     }
506     /* if there was a failure, report details */
507     if( failed) {
508         trace("*** count %d %s text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
509                 count, (ispop? "POPUP": "MENUBAR"),text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
510                 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
511         trace("    check %d,%d arrow %d avechar %d\n",
512                 GetSystemMetrics(SM_CXMENUCHECK ),
513                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
514         if( hbmp == HBMMENU_CALLBACK)
515             trace( "    rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
516                 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
517                 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
518     }
519     /* clean up */
520     ret = DestroyMenu(submenu);
521     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
522     ret = DestroyMenu(hmenu);
523     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
524 }
525
526
527 static void test_menu_bmp_and_string(void)
528 {
529     BYTE bmfill[300];
530     HBITMAP hbm_arrow;
531     BITMAP bm;
532     INT arrowwidth;
533     HWND hwnd;
534     HMENU hsysmenu;
535     MENUINFO mi= {sizeof(MENUINFO)};
536     MENUITEMINFOA mii= {sizeof(MENUITEMINFOA)};
537     int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
538
539     if( !pGetMenuInfo)
540     {
541         win_skip("GetMenuInfo is not available\n");
542         return;
543     }
544
545     memset( bmfill, 0xcc, sizeof( bmfill));
546     hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU |
547                           WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
548                           NULL, NULL, NULL, NULL);
549     hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
550     GetObject( hbm_arrow, sizeof(bm), &bm);
551     arrowwidth = bm.bmWidth;
552     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
553     if( !hwnd) return;
554     /* test system menu */
555     hsysmenu = GetSystemMenu( hwnd, FALSE);
556     ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError());
557     mi.fMask = MIM_STYLE;
558     mi.dwStyle = 0;
559     ok( pGetMenuInfo( hsysmenu, &mi), "GetMenuInfo failed gle=%d\n", GetLastError());
560     ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08x, without the bit %08x\n",
561         mi.dwStyle, MNS_CHECKORBMP);
562     mii.fMask = MIIM_BITMAP;
563     mii.hbmpItem = NULL;
564     ok( GetMenuItemInfoA( hsysmenu, SC_CLOSE, FALSE, &mii), "GetMenuItemInfoA failed gle=%d\n", GetLastError());
565     ok( HBMMENU_POPUP_CLOSE == mii.hbmpItem, "Item info did not get the right hbitmap: got %p  expected %p\n",
566         mii.hbmpItem, HBMMENU_POPUP_CLOSE);
567
568     SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc);
569
570     if( winetest_debug)
571         trace("    check %d,%d arrow %d avechar %d\n",
572                 GetSystemMetrics(SM_CXMENUCHECK ),
573                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
574     count = 0;
575     MOD_maxid = 0;
576     for( ispop=1; ispop >= 0; ispop--){
577         static SIZE bmsizes[]= {
578             {10,10},{38,38},{1,30},{55,5}};
579         for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
580             HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
581             HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, HBMMENU_POPUP_CLOSE, NULL  };
582             ok( hbm != 0, "CreateBitmap failed err %d\n", GetLastError());
583             for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
584                 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
585                     for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
586                         for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
587                             /* no need to test NULL bitmaps of several sizes */
588                             if( !bitmaps[bmpidx] && szidx > 0) continue;
589                             /* the HBMMENU_POPUP not to test for menu bars */
590                             if( !ispop &&
591                                 bitmaps[bmpidx] >= HBMMENU_POPUP_CLOSE &&
592                                 bitmaps[bmpidx] <= HBMMENU_POPUP_MINIMIZE) continue;
593                             if( !ispop && hassub) continue;
594                             test_mbs_help( ispop, hassub, mnuopt,
595                                     hwnd, arrowwidth, ++count,
596                                     bitmaps[bmpidx],
597                                     bmsizes[szidx],
598                                     MOD_txtsizes[txtidx].text,
599                                     MOD_txtsizes[txtidx].size,
600                                     MOD_txtsizes[txtidx].sc_size);
601                         }
602                     }
603                 }
604             }
605             DeleteObject( hbm);
606         }
607     }
608     /* clean up */
609     DestroyWindow(hwnd);
610 }
611
612 static void test_menu_add_string( void )
613 {
614     HMENU hmenu;
615     MENUITEMINFO info;
616     BOOL rc;
617     int ret;
618
619     char string[0x80];
620     char string2[0x80];
621
622     char strback[0x80];
623     WCHAR strbackW[0x80];
624     static CHAR blah[] = "blah";
625     static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
626
627     hmenu = CreateMenu();
628
629     memset( &info, 0, sizeof info );
630     info.cbSize = sizeof info;
631     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
632     info.dwTypeData = blah;
633     info.cch = 6;
634     info.dwItemData = 0;
635     info.wID = 1;
636     info.fState = 0;
637     InsertMenuItem(hmenu, 0, TRUE, &info );
638
639     memset( &info, 0, sizeof info );
640     info.cbSize = sizeof info;
641     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
642     info.dwTypeData = string;
643     info.cch = sizeof string;
644     string[0] = 0;
645     GetMenuItemInfo( hmenu, 0, TRUE, &info );
646
647     ok( !strcmp( string, "blah" ), "menu item name differed\n");
648
649     /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
650     strcpy(string, "Dummy string");
651     memset(&info, 0x00, sizeof(info));
652     info.cbSize= sizeof(MENUITEMINFO); 
653     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
654     info.fType= MFT_OWNERDRAW;
655     info.dwTypeData= string; 
656     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
657     ok (rc, "InsertMenuItem failed\n");
658
659     strcpy(string,"Garbage");
660     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
661     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
662
663     SetLastError(0xdeadbeef);
664     ret = GetMenuStringW( hmenu, 0, strbackW, 99, MF_BYPOSITION );
665     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
666         win_skip("GetMenuStringW is not implemented\n");
667     else
668     {
669         ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
670         ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
671     }
672
673     /* Just change ftype to string and see what text is stored */
674     memset(&info, 0x00, sizeof(info));
675     info.cbSize= sizeof(MENUITEMINFO); 
676     info.fMask= MIIM_FTYPE; /* Set string type */
677     info.fType= MFT_STRING;
678     info.dwTypeData= (char *)0xdeadbeef; 
679     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
680     ok (rc, "SetMenuItemInfo failed\n");
681
682     /* Did we keep the old dwTypeData? */
683     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
684     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
685
686     /* Ensure change to bitmap type fails */
687     memset(&info, 0x00, sizeof(info));
688     info.cbSize= sizeof(MENUITEMINFO); 
689     info.fMask= MIIM_FTYPE; /* Set as bitmap type */
690     info.fType= MFT_BITMAP;
691     info.dwTypeData= (char *)0xdeadbee2; 
692     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
693     ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
694
695     /* Just change ftype back and ensure data hasn't been freed */
696     info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
697     info.dwTypeData= (char *)0xdeadbee3; 
698     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
699     ok (rc, "SetMenuItemInfo failed\n");
700     
701     /* Did we keep the old dwTypeData? */
702     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
703     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
704
705     /* Just change string value (not type) */
706     memset(&info, 0x00, sizeof(info));
707     info.cbSize= sizeof(MENUITEMINFO); 
708     info.fMask= MIIM_STRING; /* Set typeData */
709     strcpy(string2, "string2");
710     info.dwTypeData= string2; 
711     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
712     ok (rc, "SetMenuItemInfo failed\n");
713
714     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
715     ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
716
717     /*  crashes with wine 0.9.5 */
718     memset(&info, 0x00, sizeof(info));
719     info.cbSize= sizeof(MENUITEMINFO); 
720     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
721     info.fType= MFT_OWNERDRAW;
722     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
723     ok (rc, "InsertMenuItem failed\n");
724     ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
725             "GetMenuString on ownerdraw entry succeeded.\n");
726     SetLastError(0xdeadbeef);
727     ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION);
728     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
729         win_skip("GetMenuStringW is not implemented\n");
730     else
731         ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
732
733     DestroyMenu( hmenu );
734 }
735
736 /* define building blocks for the menu item info tests */
737 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
738 {
739     if (n <= 0) return 0;
740     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
741     return *str1 - *str2;
742 }
743
744 static  WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
745 {
746     WCHAR *p = dst;
747     while ((*p++ = *src++));
748     return dst;
749 }
750
751 static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, UINT id,
752                               HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data,
753                               void *type_data, UINT len, HBITMAP item, BOOL expect )
754 {
755     MENUITEMINFOA info;
756     BOOL ret;
757
758     /* magic bitmap handle to test smaller cbSize */
759     if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef)
760         info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem);
761     else
762         info.cbSize = sizeof(info);
763     info.fMask = mask;
764     info.fType = type;
765     info.fState = state;
766     info.wID = id;
767     info.hSubMenu = submenu;
768     info.hbmpChecked = checked;
769     info.hbmpUnchecked = unchecked;
770     info.dwItemData = data;
771     info.dwTypeData = type_data;
772     info.cch = len;
773     info.hbmpItem = item;
774     SetLastError( 0xdeadbeef );
775     if (ansi) ret = InsertMenuItemA( hmenu, 0, TRUE, &info );
776     else ret = InsertMenuItemW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info );
777     if (!expect) ok_(__FILE__, line)( !ret, "InsertMenuItem should have failed.\n" );
778     else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %u\n", GetLastError());
779 }
780
781 static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state,
782                                   UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked,
783                                   ULONG_PTR data, void *type_data, UINT in_len, UINT out_len,
784                                   HBITMAP item, LPCSTR expname, BOOL expect, BOOL expstring )
785 {
786     MENUITEMINFOA info;
787     BOOL ret;
788     WCHAR buffer[80];
789
790     SetLastError( 0xdeadbeef );
791     memset( &info, 0xcc, sizeof(info) );
792     info.cbSize = sizeof(info);
793     info.fMask = mask;
794     info.dwTypeData = type_data;
795     info.cch = in_len;
796
797     ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, &info ) :
798                  GetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW *)&info );
799     if (!expect)
800     {
801         ok_(__FILE__, line)( !ret, "GetMenuItemInfo should have failed.\n" );
802         return;
803     }
804     ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %u\n", GetLastError());
805     if (mask & MIIM_TYPE)
806         ok_(__FILE__, line)( info.fType == type || info.fType == LOWORD(type),
807                              "wrong type %x/%x\n", info.fType, type );
808     if (mask & MIIM_STATE)
809         ok_(__FILE__, line)( info.fState == state || info.fState == LOWORD(state),
810                              "wrong state %x/%x\n", info.fState, state );
811     if (mask & MIIM_ID)
812         ok_(__FILE__, line)( info.wID == id || info.wID == LOWORD(id),
813                              "wrong id %x/%x\n", info.wID, id );
814     if (mask & MIIM_SUBMENU)
815         ok_(__FILE__, line)( info.hSubMenu == submenu || (ULONG_PTR)info.hSubMenu == LOWORD(submenu),
816                              "wrong submenu %p/%p\n", info.hSubMenu, submenu );
817     if (mask & MIIM_CHECKMARKS)
818     {
819         ok_(__FILE__, line)( info.hbmpChecked == checked || (ULONG_PTR)info.hbmpChecked == LOWORD(checked),
820                              "wrong bmpchecked %p/%p\n", info.hbmpChecked, checked );
821         ok_(__FILE__, line)( info.hbmpUnchecked == unchecked || (ULONG_PTR)info.hbmpUnchecked == LOWORD(unchecked),
822                              "wrong bmpunchecked %p/%p\n", info.hbmpUnchecked, unchecked );
823     }
824     if (mask & MIIM_DATA)
825         ok_(__FILE__, line)( info.dwItemData == data || info.dwItemData == LOWORD(data),
826                              "wrong item data %lx/%lx\n", info.dwItemData, data );
827     if (mask & MIIM_BITMAP)
828         ok_(__FILE__, line)( info.hbmpItem == item || (ULONG_PTR)info.hbmpItem == LOWORD(item),
829                              "wrong bmpitem %p/%p\n", info.hbmpItem, item );
830     ok_(__FILE__, line)( info.dwTypeData == type_data || (ULONG_PTR)info.dwTypeData == LOWORD(type_data),
831                          "wrong type data %p/%p\n", info.dwTypeData, type_data );
832     ok_(__FILE__, line)( info.cch == out_len, "wrong len %x/%x\n", info.cch, out_len );
833     if (expname)
834     {
835         if(ansi)
836             ok_(__FILE__, line)( !strncmp( expname, info.dwTypeData, out_len ),
837                                  "menu item name differed from '%s' '%s'\n", expname, info.dwTypeData );
838         else
839             ok_(__FILE__, line)( !strncmpW( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ),
840                                  "menu item name wrong\n" );
841
842         SetLastError( 0xdeadbeef );
843         ret = ansi ? GetMenuStringA( hmenu, 0, (char *)buffer, 80, MF_BYPOSITION ) :
844             GetMenuStringW( hmenu, 0, buffer, 80, MF_BYPOSITION );
845         if (expstring)
846             ok_(__FILE__, line)( ret, "GetMenuString failed, err %u\n", GetLastError());
847         else
848             ok_(__FILE__, line)( !ret, "GetMenuString should have failed\n" );
849     }
850 }
851
852 static void modify_menu( int line, HMENU hmenu, BOOL ansi, UINT flags, UINT_PTR id, void *data )
853 {
854     BOOL ret;
855
856     SetLastError( 0xdeadbeef );
857     if (ansi) ret = ModifyMenuA( hmenu, 0, flags, id, data );
858     else ret = ModifyMenuW( hmenu, 0, flags, id, data );
859     ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %u\n", GetLastError());
860 }
861
862 static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state,
863                                 UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data,
864                                 void *type_data, UINT len, HBITMAP item )
865
866 {
867     MENUITEMINFOA info;
868     BOOL ret;
869
870     /* magic bitmap handle to test smaller cbSize */
871     if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef)
872         info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem);
873     else
874         info.cbSize = sizeof(info);
875     info.fMask = mask;
876     info.fType = type;
877     info.fState = state;
878     info.wID = id;
879     info.hSubMenu = submenu;
880     info.hbmpChecked = checked;
881     info.hbmpUnchecked = unchecked;
882     info.dwItemData = data;
883     info.dwTypeData = type_data;
884     info.cch = len;
885     info.hbmpItem = item;
886     SetLastError( 0xdeadbeef );
887     if (ansi) ret = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
888     else ret = SetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info );
889     ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %u\n", GetLastError());
890 }
891
892 #define TMII_INSMI( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,eret1 )\
893     hmenu = CreateMenu();\
894     submenu = CreateMenu();\
895     if(ansi)strcpy( string, init );\
896     else strcpyW( string, init );\
897     insert_menu_item( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, eret1 )
898
899 /* GetMenuItemInfo + GetMenuString  */
900 #define TMII_GMII( c2,l2,\
901     d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,\
902     expname, eret2, eret3)\
903     check_menu_item_info( __LINE__, hmenu, ansi, c2, d3, e3, f3, g3, h3, i3, j3, k3, l2, l3, m3, \
904                           expname, eret2, eret3 )
905
906 #define TMII_DONE \
907     RemoveMenu(hmenu, 0, TRUE );\
908     DestroyMenu( hmenu );\
909     DestroyMenu( submenu );
910
911 /* modify menu */
912 #define TMII_MODM( flags, id, data ) \
913     modify_menu( __LINE__, hmenu, ansi, flags, id, data )
914
915 /* SetMenuItemInfo */
916 #define TMII_SMII( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1 ) \
917     set_menu_item_info( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1 )
918
919
920 #define OK 1
921 #define ER 0
922
923
924 static void test_menu_iteminfo( void )
925 {
926   int ansi = TRUE;
927   char txtA[]="wine";
928   char initA[]="XYZ";
929   char emptyA[]="";
930   WCHAR txtW[]={'W','i','n','e',0};
931   WCHAR initW[]={'X','Y','Z',0};
932   WCHAR emptyW[]={0};
933   void *txt, *init, *empty, *string;
934   HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
935   char stringA[0x80];
936   HMENU hmenu, submenu=CreateMenu();
937   HBITMAP dummy_hbm = (HBITMAP)(ULONG_PTR)0xdeadbeef;
938
939   do {
940     if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
941     else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
942     trace( "%s string %p hbm %p txt %p\n", ansi ?  "ANSI tests:   " : "Unicode tests:", string, hbm, txt);
943     /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
944     /* (since MFT_STRING is zero, there are four of them) */
945     TMII_INSMI( MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK );
946     TMII_GMII ( MIIM_TYPE, 80,
947         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
948         txt, OK, OK );
949     TMII_DONE
950     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
951     TMII_GMII ( MIIM_TYPE, 80,
952         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
953         NULL, OK, ER );
954     TMII_DONE
955     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
956     TMII_GMII ( MIIM_TYPE, 80,
957         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
958         NULL, OK, ER );
959     TMII_DONE
960     TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
961     TMII_GMII ( MIIM_TYPE, 80,
962         MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
963         NULL, OK, ER );
964     TMII_DONE
965     /* not enough space for name*/
966     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
967     TMII_GMII ( MIIM_TYPE, 0,
968         MFT_STRING, 0, 0, 0, 0, 0, 0, NULL, 4, 0,
969         NULL, OK, OK );
970     TMII_DONE
971     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
972     TMII_GMII ( MIIM_TYPE, 5,
973         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
974         txt, OK, OK );
975     TMII_DONE
976     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
977     TMII_GMII ( MIIM_TYPE, 4,
978         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 3, 0,
979         txt, OK, OK );
980     TMII_DONE
981     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
982     TMII_GMII ( MIIM_TYPE, 0,
983         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, 0,
984         NULL, OK, ER );
985     TMII_DONE
986     /* cannot combine MIIM_TYPE with some other flags */
987     TMII_INSMI( MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER );
988     TMII_DONE
989     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
990     TMII_GMII ( MIIM_TYPE|MIIM_STRING, 80,
991         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
992         NULL, ER, OK );
993     TMII_DONE
994     TMII_INSMI( MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER );
995     TMII_DONE
996     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
997     TMII_GMII ( MIIM_TYPE|MIIM_FTYPE, 80,
998         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
999         NULL, ER, OK );
1000     TMII_DONE
1001     TMII_INSMI( MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, hbm, ER );
1002     TMII_DONE
1003         /* but succeeds with some others */
1004     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1005     TMII_GMII ( MIIM_TYPE|MIIM_SUBMENU, 80,
1006         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1007         txt, OK, OK );
1008     TMII_DONE
1009     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1010     TMII_GMII ( MIIM_TYPE|MIIM_STATE, 80,
1011         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1012         txt, OK, OK );
1013     TMII_DONE
1014     TMII_INSMI( MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, 0, 0, 0, -1, txt, 6, 0, OK );
1015     TMII_GMII ( MIIM_TYPE|MIIM_ID, 80,
1016         MFT_STRING, 0, 888, 0, 0, 0, 0, string, 4, 0,
1017         txt, OK, OK );
1018     TMII_DONE
1019     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, 0, 0, 0, 999, txt, 6, 0, OK );
1020     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1021         MFT_STRING, 0, 0, 0, 0, 0, 999, string, 4, 0,
1022         txt, OK, OK );
1023     TMII_DONE
1024     /* to be continued */
1025     /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ 
1026     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1027     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1028         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1029         txt, OK, OK );
1030     TMII_DONE
1031     /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ 
1032     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1033     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1034         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1035         empty, OK, ER );
1036     TMII_DONE
1037     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1038     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1039         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1040         empty, OK, ER );
1041     TMII_DONE
1042     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1043     TMII_GMII ( MIIM_FTYPE, 80,
1044         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, 0,
1045         init, OK, ER );
1046     TMII_DONE
1047     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1048     TMII_GMII ( 0, 80,
1049         0, 0, 0, 0, 0, 0, 0, string, 80, 0,
1050         init, OK, OK );
1051     TMII_DONE
1052     /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ 
1053     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1054     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1055         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0,
1056         txt, OK, OK );
1057     TMII_DONE
1058     /* same but retrieve with MIIM_TYPE */ 
1059     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1060     TMII_GMII ( MIIM_TYPE, 80,
1061         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1062         NULL, OK, OK );
1063     TMII_DONE
1064     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1065     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1066         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1067         empty, OK, ER );
1068     TMII_DONE
1069     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1070     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1071         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0,
1072         empty, OK, ER );
1073     TMII_DONE
1074
1075     /* How is that with bitmaps? */ 
1076     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1077     TMII_GMII ( MIIM_TYPE, 80,
1078         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1079         NULL, OK, ER );
1080     TMII_DONE
1081     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1082     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1083         0, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1084         init, OK, ER );
1085     TMII_DONE
1086         /* MIIM_BITMAP does not like MFT_BITMAP */
1087     TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, hbm, ER );
1088     TMII_DONE
1089         /* no problem with OWNERDRAWN */
1090     TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1091     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1092         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1093         init, OK, ER );
1094     TMII_DONE
1095         /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
1096     TMII_INSMI( MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, 0, ER );
1097     TMII_DONE
1098
1099     /* menu with submenu */
1100     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK );
1101     TMII_GMII ( MIIM_SUBMENU, 80,
1102         0, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1103         init, OK, ER );
1104     TMII_DONE
1105     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, empty, 0, 0, OK );
1106     TMII_GMII ( MIIM_SUBMENU, 80,
1107         0, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1108         init, OK, ER );
1109     TMII_DONE
1110     /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
1111     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK );
1112     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1113         MFT_STRING|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0,
1114         empty, OK, ER );
1115     TMII_GMII ( MIIM_SUBMENU|MIIM_FTYPE, 80,
1116         MFT_SEPARATOR, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1117         empty, OK, ER );
1118     TMII_DONE
1119     /* menu with invalid submenu */
1120     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, (HMENU)999, 0, 0, -1, txt, 0, 0, ER );
1121     TMII_DONE
1122     /* Separator */
1123     TMII_INSMI( MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK );
1124     TMII_GMII ( MIIM_TYPE, 80,
1125         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1126         NULL, OK, ER );
1127     TMII_DONE
1128     TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
1129     TMII_GMII ( MIIM_TYPE, 80,
1130         MFT_BITMAP|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1131         NULL, OK, ER );
1132     TMII_DONE
1133      /* SEPARATOR and STRING go well together */
1134     /* BITMAP and STRING go well together */
1135     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1136     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80,
1137         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, hbm,
1138         txt, OK, OK );
1139     TMII_DONE
1140      /* BITMAP, SEPARATOR and STRING go well together */
1141     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1142     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80,
1143         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, hbm,
1144         txt, OK, OK );
1145     TMII_DONE
1146      /* last two tests, but use MIIM_TYPE to retrieve info */
1147     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1148     TMII_GMII ( MIIM_TYPE, 80,
1149         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1150         NULL, OK, OK );
1151     TMII_DONE
1152     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1153     TMII_GMII ( MIIM_TYPE, 80,
1154         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1155         NULL, OK, OK );
1156     TMII_DONE
1157     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1158     TMII_GMII ( MIIM_TYPE, 80,
1159         MFT_SEPARATOR|MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1160         NULL, OK, OK );
1161     TMII_DONE
1162      /* same three with MFT_OWNERDRAW */
1163     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1164     TMII_GMII ( MIIM_TYPE, 80,
1165         MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1166         NULL, OK, OK );
1167     TMII_DONE
1168     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1169     TMII_GMII ( MIIM_TYPE, 80,
1170         MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1171         NULL, OK, OK );
1172     TMII_DONE
1173     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1174     TMII_GMII ( MIIM_TYPE, 80,
1175         MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1176         NULL, OK, OK );
1177     TMII_DONE
1178
1179     TMII_INSMI( MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1180     TMII_GMII ( MIIM_TYPE, 80,
1181         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1182         NULL,  OK, OK );
1183     TMII_DONE
1184     /* test with modifymenu: string is preserved after setting OWNERDRAW */
1185     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1186     TMII_MODM( MFT_OWNERDRAW, -1, (void*)787 );
1187     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_DATA, 80,
1188         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 787, string, 4, 0,
1189         txt,  OK, OK );
1190     TMII_DONE
1191     /* same with bitmap: now the text is cleared */
1192     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1193     TMII_MODM( MFT_BITMAP, 545, hbm );
1194     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1195         MFT_BITMAP, 0, 545, 0, 0, 0, 0, string, 0, hbm,
1196         empty,  OK, ER );
1197     TMII_DONE
1198     /* start with bitmap: now setting text clears it (though he flag is raised) */
1199     TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1200     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1201         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 0, hbm,
1202         empty,  OK, ER );
1203     TMII_MODM( MFT_STRING, 545, txt );
1204     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1205         MFT_STRING, 0, 545, 0, 0, 0, 0, string, 4, 0,
1206         txt,  OK, OK );
1207     TMII_DONE
1208     /*repeat with text NULL */
1209     TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1210     TMII_MODM( MFT_STRING, 545, NULL );
1211     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1212         MFT_SEPARATOR, 0, 545, 0, 0, 0, 0, string, 0, 0,
1213         empty,  OK, ER );
1214     TMII_DONE
1215     /* repeat with text "" */
1216     TMII_INSMI( MIIM_BITMAP, -1 , -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1217     TMII_MODM( MFT_STRING, 545, empty );
1218     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1219         MFT_STRING, 0, 545, 0, 0, 0, 0, string, 0, 0,
1220         empty,  OK, ER );
1221     TMII_DONE
1222     /* start with bitmap: set ownerdraw */
1223     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1224     TMII_MODM( MFT_OWNERDRAW, -1, (void *)232 );
1225     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, 80,
1226         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 232, string, 0, hbm,
1227         empty,  OK, ER );
1228     TMII_DONE
1229     /* ask nothing */
1230     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1231     TMII_GMII ( 0, 80,
1232                 0, 0, 0,  0, 0, 0, 0, string, 80, 0,
1233         init, OK, OK );
1234     TMII_DONE
1235     /* some tests with small cbSize: the hbmpItem is to be ignored */
1236     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK );
1237     TMII_GMII ( MIIM_TYPE, 80,
1238         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1239         NULL, OK, ER );
1240     TMII_DONE
1241     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK );
1242     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1243         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, NULL,
1244         init, OK, ER );
1245     TMII_DONE
1246     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1247     TMII_GMII ( MIIM_TYPE, 80,
1248         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, NULL,
1249         txt, OK, OK );
1250     TMII_DONE
1251     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1252     TMII_GMII ( MIIM_TYPE, 80,
1253         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1254         NULL, OK, OK );
1255     TMII_DONE
1256     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1257     TMII_GMII ( MIIM_TYPE, 80,
1258         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1259         NULL, OK, OK );
1260     TMII_DONE
1261     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1262     TMII_GMII ( MIIM_TYPE, 80,
1263         MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1264         NULL, OK, OK );
1265     TMII_DONE
1266     /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus  */
1267     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1268     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1269         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 343, 0, 0, 0,
1270         NULL, OK, ER );
1271     TMII_DONE
1272     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1273     TMII_GMII ( MIIM_TYPE, 80,
1274         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1275         NULL, OK, ER );
1276     TMII_DONE
1277     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1278     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1279         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1280         NULL, OK, ER );
1281     TMII_DONE
1282     /* set a string menu to ownerdraw with MIIM_TYPE */
1283     TMII_INSMI( MIIM_TYPE, MFT_STRING, -2, -2, 0, 0, 0, -2, txt, -2, 0, OK );
1284     TMII_SMII ( MIIM_TYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1285     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1286         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0,
1287         txt, OK, OK );
1288     TMII_DONE
1289     /* test with modifymenu add submenu */
1290     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1291     TMII_MODM( MF_POPUP, (UINT_PTR)submenu, txt );
1292     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, 80,
1293         MFT_STRING, 0, 0, submenu, 0, 0, 0, string, 4, 0,
1294         txt,  OK, OK );
1295     TMII_GMII ( MIIM_TYPE, 80,
1296         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1297         txt,  OK, OK );
1298     TMII_DONE
1299     /* MFT_SEPARATOR bit is kept when the text is added */
1300     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1301     TMII_SMII( MIIM_STRING, 0, 0, 0, 0, 0, 0, 0, txt, 0, 0 );
1302     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1303         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, 0,
1304         txt, OK, OK );
1305     TMII_DONE
1306     /* MFT_SEPARATOR bit is kept when bitmap is added */
1307     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1308     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, hbm );
1309     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1310         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1311         init, OK, ER );
1312     TMII_DONE
1313     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1314        Only the low word of the dwTypeData is used.
1315        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1316     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1,
1317                 (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK );
1318     TMII_GMII ( MIIM_TYPE, 80,
1319         MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE,
1320         NULL, OK, OK );
1321     TMII_DONE
1322     /* Type flags */
1323     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1324     TMII_GMII ( MIIM_TYPE, 80,
1325         MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1326         NULL, OK, OK );
1327     TMII_DONE
1328     /* State flags */
1329     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1330     TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 );
1331     TMII_GMII ( MIIM_STATE, 80,
1332         0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0,
1333         NULL, OK, OK );
1334     TMII_DONE
1335     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1336     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1337     TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 );
1338     TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80,
1339         MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm,
1340         NULL, OK, OK );
1341     TMII_DONE
1342     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1343     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1344     TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 );
1345     TMII_GMII ( MIIM_FTYPE, 80,
1346         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1347         NULL, OK, OK );
1348     TMII_GMII ( MIIM_TYPE, 80,
1349         MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1350         NULL, OK, OK );
1351     TMII_GMII ( MIIM_FTYPE, 80,
1352         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1353         NULL, OK, OK );
1354     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL );
1355     TMII_GMII ( MIIM_TYPE, 80,
1356         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1357         NULL, OK, OK );
1358     TMII_DONE
1359     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1360        Only the low word of the dwTypeData is used.
1361        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1362     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1,
1363                 (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK );
1364     TMII_GMII ( MIIM_TYPE, 80,
1365         MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE,
1366         NULL, OK, OK );
1367     TMII_DONE
1368     /* Type flags */
1369     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1370     TMII_GMII ( MIIM_TYPE, 80,
1371         MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1372         NULL, OK, OK );
1373     TMII_DONE
1374     /* State flags */
1375     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1376     TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 );
1377     TMII_GMII ( MIIM_STATE, 80,
1378         0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0,
1379         NULL, OK, OK );
1380     TMII_DONE
1381     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1382     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1383     TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 );
1384     TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80,
1385         MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm,
1386         NULL, OK, OK );
1387     TMII_DONE
1388     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1389     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1390     TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 );
1391     TMII_GMII ( MIIM_FTYPE, 80,
1392         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1393         NULL, OK, OK );
1394     TMII_GMII ( MIIM_TYPE, 80,
1395         MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1396         NULL, OK, OK );
1397     TMII_GMII ( MIIM_FTYPE, 80,
1398         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1399         NULL, OK, OK );
1400     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL );
1401     TMII_GMII ( MIIM_TYPE, 80,
1402         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1403         NULL, OK, OK );
1404     TMII_DONE
1405   } while( !(ansi = !ansi) );
1406   DeleteObject( hbm);
1407 }
1408
1409 /* 
1410    The following tests try to confirm the algorithm used to return the menu items
1411    when there is a collision between a menu item and a popup menu
1412  */
1413 static void test_menu_search_bycommand( void )
1414 {
1415     HMENU        hmenu, hmenuSub, hmenuSub2;
1416     MENUITEMINFO info;
1417     BOOL         rc;
1418     UINT         id;
1419     char         strback[0x80];
1420     char         strIn[0x80];
1421     static CHAR menuitem[]  = "MenuItem",
1422                 menuitem2[] = "MenuItem 2";
1423
1424     /* Case 1: Menu containing a menu item */
1425     hmenu = CreateMenu();
1426     
1427     memset( &info, 0, sizeof info );
1428     info.cbSize = sizeof info;
1429     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1430     info.fType = MFT_STRING;
1431     strcpy(strIn, "Case 1 MenuItem");
1432     info.dwTypeData = strIn;
1433     info.wID = (UINT) 0x1234;
1434     
1435     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1436     ok (rc, "Inserting the menuitem failed\n");
1437
1438     id = GetMenuItemID(hmenu, 0);
1439     ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1440
1441     /* Confirm the menuitem was given the id supplied (getting by position) */
1442     memset( &info, 0, sizeof info );
1443     strback[0] = 0x00;
1444     info.cbSize = sizeof(MENUITEMINFO);
1445     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1446     info.dwTypeData = strback;
1447     info.cch = sizeof(strback);
1448
1449     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1450     ok (rc, "Getting the menu items info failed\n");
1451     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1452     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1453
1454     /* Search by id - Should return the item */
1455     memset( &info, 0, sizeof info );
1456     strback[0] = 0x00;
1457     info.cbSize = sizeof(MENUITEMINFO);
1458     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1459     info.dwTypeData = strback;
1460     info.cch = sizeof(strback);
1461     rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1462
1463     ok (rc, "Getting the menu items info failed\n");
1464     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1465     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1466
1467     DestroyMenu( hmenu );
1468
1469     /* Case 2: Menu containing a popup menu */
1470     hmenu = CreateMenu();
1471     hmenuSub = CreateMenu();
1472     
1473     strcpy(strIn, "Case 2 SubMenu");
1474     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1475     ok (rc, "Inserting the popup menu into the main menu failed\n");
1476
1477     id = GetMenuItemID(hmenu, 0);
1478     ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1479
1480     /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1481     memset( &info, 0, sizeof info );
1482     strback[0] = 0x00;
1483     info.cbSize = sizeof(MENUITEMINFO);
1484     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1485     info.dwTypeData = strback;
1486     info.cch = sizeof(strback);
1487     info.wID = 0xdeadbeef;
1488
1489     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1490     ok (rc, "Getting the menu items info failed\n");
1491     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1492     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1493
1494     /* Search by id - returns the popup menu itself */
1495     memset( &info, 0, sizeof info );
1496     strback[0] = 0x00;
1497     info.cbSize = sizeof(MENUITEMINFO);
1498     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1499     info.dwTypeData = strback;
1500     info.cch = sizeof(strback);
1501     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1502
1503     ok (rc, "Getting the menu items info failed\n");
1504     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1505     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1506
1507     /* 
1508         Now add an item after it with the same id
1509      */
1510     memset( &info, 0, sizeof info );
1511     info.cbSize = sizeof info;
1512     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1513     info.fType = MFT_STRING;
1514     strcpy(strIn, "Case 2 MenuItem 1");
1515     info.dwTypeData = strIn;
1516     info.wID = (UINT_PTR) hmenuSub;
1517     rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1518     ok (rc, "Inserting the menuitem failed\n");
1519
1520     /* Search by id - returns the item which follows the popup menu */
1521     memset( &info, 0, sizeof info );
1522     strback[0] = 0x00;
1523     info.cbSize = sizeof(MENUITEMINFO);
1524     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1525     info.dwTypeData = strback;
1526     info.cch = sizeof(strback);
1527     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1528
1529     ok (rc, "Getting the menu items info failed\n");
1530     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1531     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1532
1533     /* 
1534         Now add an item before the popup (with the same id)
1535      */
1536     memset( &info, 0, sizeof info );
1537     info.cbSize = sizeof info;
1538     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1539     info.fType = MFT_STRING;
1540     strcpy(strIn, "Case 2 MenuItem 2");
1541     info.dwTypeData = strIn;
1542     info.wID = (UINT_PTR) hmenuSub;
1543     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1544     ok (rc, "Inserting the menuitem failed\n");
1545
1546     /* Search by id - returns the item which precedes the popup menu */
1547     memset( &info, 0, sizeof info );
1548     strback[0] = 0x00;
1549     info.cbSize = sizeof(MENUITEMINFO);
1550     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1551     info.dwTypeData = strback;
1552     info.cch = sizeof(strback);
1553     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1554
1555     ok (rc, "Getting the menu items info failed\n");
1556     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1557     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1558
1559     DestroyMenu( hmenu );
1560     DestroyMenu( hmenuSub );
1561
1562     /* 
1563         Case 3: Menu containing a popup menu which in turn 
1564            contains 2 items with the same id as the popup itself
1565      */
1566
1567     hmenu = CreateMenu();
1568     hmenuSub = CreateMenu();
1569
1570     memset( &info, 0, sizeof info );
1571     info.cbSize = sizeof info;
1572     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1573     info.fType = MFT_STRING;
1574     info.dwTypeData = menuitem;
1575     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1576
1577     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1578     ok (rc, "Inserting the popup menu into the main menu failed\n");
1579
1580     rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1581     ok (rc, "Inserting the sub menu menuitem failed\n");
1582
1583     memset( &info, 0, sizeof info );
1584     info.cbSize = sizeof info;
1585     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1586     info.fType = MFT_STRING;
1587     info.dwTypeData = menuitem2;
1588     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1589
1590     rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1591     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1592
1593     /* Prove that you can't query the id of a popup directly (By position) */
1594     id = GetMenuItemID(hmenu, 0);
1595     ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1596
1597     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1598     memset( &info, 0, sizeof info );
1599     strback[0] = 0x00;
1600     info.cbSize = sizeof(MENUITEMINFO);
1601     info.fMask = MIIM_STRING | MIIM_ID;
1602     info.dwTypeData = strback;
1603     info.cch = sizeof(strback);
1604
1605     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1606     ok (rc, "Getting the menus info failed\n");
1607     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1608     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1609     DestroyMenu( hmenu );
1610     DestroyMenu( hmenuSub );
1611
1612     /* 
1613         Case 4: Menu containing 2 popup menus, the second
1614            contains 2 items with the same id as the first popup menu
1615      */
1616     hmenu = CreateMenu();
1617     hmenuSub = CreateMenu();
1618     hmenuSub2 = CreateMenu();
1619     
1620     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1621     ok (rc, "Inserting the popup menu into the main menu failed\n");
1622     
1623     rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1624     ok (rc, "Inserting the popup menu into the main menu failed\n");
1625
1626     memset( &info, 0, sizeof info );
1627     info.cbSize = sizeof info;
1628     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1629     info.fType = MFT_STRING;
1630     info.dwTypeData = menuitem;
1631     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1632
1633     rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1634     ok (rc, "Inserting the sub menu menuitem failed\n");
1635
1636     memset( &info, 0, sizeof info );
1637     info.cbSize = sizeof info;
1638     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1639     info.fType = MFT_STRING;
1640     info.dwTypeData = menuitem2;
1641     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1642
1643     rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1644     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1645
1646     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1647     memset( &info, 0, sizeof info );
1648     strback[0] = 0x00;
1649     info.cbSize = sizeof(MENUITEMINFO);
1650     info.fMask = MIIM_STRING | MIIM_ID;
1651     info.dwTypeData = strback;
1652     info.cch = sizeof(strback);
1653
1654     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1655     ok (rc, "Getting the menus info failed\n");
1656     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1657     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1658
1659     memset( &info, 0, sizeof info );
1660     strback[0] = 0x00;
1661     info.cbSize = sizeof(MENUITEMINFO);
1662     info.fMask = MIIM_STRING | MIIM_ID;
1663     info.dwTypeData = strback;
1664     info.cch = sizeof(strback);
1665
1666     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1667     ok (rc, "Getting the menus info failed\n");
1668     ok (info.wID == (UINT_PTR)hmenuSub2, "IDs differ for popup menu\n");
1669     ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1670
1671     DestroyMenu( hmenu );
1672     DestroyMenu( hmenuSub );
1673     DestroyMenu( hmenuSub2 );
1674
1675
1676     /* 
1677         Case 5: Menu containing a popup menu which in turn
1678            contains an item with a different id than the popup menu.
1679            This tests the fallback to a popup menu ID.
1680      */
1681
1682     hmenu = CreateMenu();
1683     hmenuSub = CreateMenu();
1684
1685     rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1686     ok (rc, "Appending the popup menu to the main menu failed\n");
1687
1688     rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1689     ok (rc, "Appending the item to the popup menu failed\n");
1690
1691     /* Set the ID for hmenuSub */
1692     info.cbSize = sizeof(info);
1693     info.fMask = MIIM_ID;
1694     info.wID = 101;
1695
1696     rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1697     ok(rc, "Setting the ID for the popup menu failed\n");
1698
1699     /* Check if the ID has been set */
1700     info.wID = 0;
1701     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1702     ok(rc, "Getting the ID for the popup menu failed\n");
1703     ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1704
1705     /* Prove getting the item info via ID returns the popup menu */
1706     memset( &info, 0, sizeof(info));
1707     strback[0] = 0x00;
1708     info.cbSize = sizeof(MENUITEMINFO);
1709     info.fMask = MIIM_STRING | MIIM_ID;
1710     info.dwTypeData = strback;
1711     info.cch = sizeof(strback);
1712
1713     rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1714     ok (rc, "Getting the menu info failed\n");
1715     ok (info.wID == 101, "IDs differ\n");
1716     ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1717
1718     /* Also look for the menu item  */
1719     memset( &info, 0, sizeof(info));
1720     strback[0] = 0x00;
1721     info.cbSize = sizeof(MENUITEMINFO);
1722     info.fMask = MIIM_STRING | MIIM_ID;
1723     info.dwTypeData = strback;
1724     info.cch = sizeof(strback);
1725
1726     rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1727     ok (rc, "Getting the menu info failed\n");
1728     ok (info.wID == 102, "IDs differ\n");
1729     ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1730
1731     DestroyMenu(hmenu);
1732     DestroyMenu(hmenuSub);
1733 }
1734
1735 struct menu_item_pair_s {
1736     UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1737                  * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1738                  * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1739     UINT uItem;
1740 };
1741
1742 static struct menu_mouse_tests_s {
1743     DWORD type;
1744     struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1745     WORD wVk[5]; /* keys */
1746     BOOL bMenuVisible;
1747     BOOL _todo_wine;
1748 } menu_tests[] = {
1749     /* for each test, send keys or clicks and check for menu visibility */
1750     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1751     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1752     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1753     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1754     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1755     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1756     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1757     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1758     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1759     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1760     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1761     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1762     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1763     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1764     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1765     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1766     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1767     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1768
1769     { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1770     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1771     { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1772     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1773     { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1774     { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1775     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1776     { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1777     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1778     { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1779     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1780     { -1 }
1781 };
1782
1783 static void send_key(WORD wVk)
1784 {
1785     TEST_INPUT i[2];
1786     memset(i, 0, sizeof(i));
1787     i[0].type = i[1].type = INPUT_KEYBOARD;
1788     i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1789     i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1790     pSendInput(2, (INPUT *) i, sizeof(INPUT));
1791 }
1792
1793 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1794 {
1795     HMENU hMenu = hMenus[mi->uMenu];
1796     TEST_INPUT i[3];
1797     MSG msg;
1798     RECT r;
1799     int screen_w = GetSystemMetrics(SM_CXSCREEN);
1800     int screen_h = GetSystemMetrics(SM_CYSCREEN);
1801     BOOL ret = GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1802     if(!ret) return;
1803
1804     memset(i, 0, sizeof(i));
1805     i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1806     i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1807             = ((r.left + 5) * 65535) / screen_w;
1808     i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1809             = ((r.top + 5) * 65535) / screen_h;
1810     i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1811             = MOUSEEVENTF_ABSOLUTE;
1812     i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1813     i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1814     i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1815     pSendInput(3, (INPUT *) i, sizeof(INPUT));
1816
1817     /* hack to prevent mouse message buildup in Wine */
1818     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1819 }
1820
1821 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1822 {
1823     int i, j;
1824     HANDLE hWnd = lpParameter;
1825
1826     Sleep(500);
1827     /* mixed keyboard/mouse test */
1828     for (i = 0; menu_tests[i].type != -1; i++)
1829     {
1830         int elapsed = 0;
1831
1832         if (menu_tests[i].type == INPUT_KEYBOARD)
1833             for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1834                 send_key(menu_tests[i].wVk[j]);
1835         else
1836             for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1837                 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1838
1839         while (menu_tests[i].bMenuVisible != bMenuVisible)
1840         {
1841             if (elapsed > 200)
1842                 break;
1843             elapsed += 20;
1844             Sleep(20);
1845         }
1846
1847         if (menu_tests[i]._todo_wine)
1848         {
1849             todo_wine {
1850                 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1851             }
1852         }
1853         else
1854             ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1855     }
1856     return 0;
1857 }
1858
1859 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1860         LPARAM lParam)
1861 {
1862     switch (msg) {
1863         case WM_ENTERMENULOOP:
1864             bMenuVisible = TRUE;
1865             break;
1866         case WM_EXITMENULOOP:
1867             bMenuVisible = FALSE;
1868             break;
1869         default:
1870             return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1871     }
1872     return 0;
1873 }
1874
1875 static void test_menu_input(void) {
1876     MSG msg;
1877     WNDCLASSA  wclass;
1878     HINSTANCE hInstance = GetModuleHandleA( NULL );
1879     HANDLE hThread, hWnd;
1880     DWORD tid;
1881
1882     wclass.lpszClassName = "MenuTestClass";
1883     wclass.style         = CS_HREDRAW | CS_VREDRAW;
1884     wclass.lpfnWndProc   = WndProc;
1885     wclass.hInstance     = hInstance;
1886     wclass.hIcon         = LoadIconA( 0, IDI_APPLICATION );
1887     wclass.hCursor       = LoadCursorA( NULL, IDC_ARROW );
1888     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
1889     wclass.lpszMenuName  = 0;
1890     wclass.cbClsExtra    = 0;
1891     wclass.cbWndExtra    = 0;
1892     assert (RegisterClassA( &wclass ));
1893     assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1894                                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1895                                   400, 200, NULL, NULL, hInstance, NULL) );
1896
1897     /* fixed menus */
1898     hMenus[3] = CreatePopupMenu();
1899     AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1900     AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1901
1902     hMenus[2] = CreatePopupMenu();
1903     AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1904     AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1905     AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1906
1907     hMenus[1] = CreateMenu();
1908     AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1909     AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1910     AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1911
1912     SetMenu(hWnd, hMenus[1]);
1913     ShowWindow(hWnd, SW_SHOW);
1914     UpdateWindow(hWnd);
1915
1916     hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid);
1917     while(1)
1918     {
1919         if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1920             break;
1921         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1922     }
1923     DestroyWindow(hWnd);
1924 }
1925
1926 static void test_menu_flags( void )
1927 {
1928     HMENU hMenu, hPopupMenu;
1929
1930     hMenu = CreateMenu();
1931     hPopupMenu = CreatePopupMenu();
1932
1933     AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup");
1934
1935     AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1936     InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1937     AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1938     ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1939
1940     ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1941       "AppendMenu should accept MF_HILITE\n");
1942     ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1943       "InsertMenu should accept MF_HILITE\n");
1944     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1945       "ModifyMenu should accept MF_HILITE\n");
1946
1947     ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1948       "AppendMenu must not accept MF_DEFAULT\n");
1949     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1950       "InsertMenu must not accept MF_DEFAULT\n");
1951     ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1952       "ModifyMenu must not accept MF_DEFAULT\n");
1953
1954     DestroyMenu(hMenu);
1955 }
1956
1957 static void test_menu_hilitemenuitem( void )
1958 {
1959     HMENU hMenu, hPopupMenu;
1960     WNDCLASSA wclass;
1961     HWND hWnd;
1962
1963     wclass.lpszClassName = "HiliteMenuTestClass";
1964     wclass.style         = CS_HREDRAW | CS_VREDRAW;
1965     wclass.lpfnWndProc   = WndProc;
1966     wclass.hInstance     = GetModuleHandleA( NULL );
1967     wclass.hIcon         = LoadIconA( 0, IDI_APPLICATION );
1968     wclass.hCursor       = LoadCursorA( NULL, IDC_ARROW );
1969     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
1970     wclass.lpszMenuName  = 0;
1971     wclass.cbClsExtra    = 0;
1972     wclass.cbWndExtra    = 0;
1973     assert (RegisterClassA( &wclass ));
1974     assert (hWnd = CreateWindowA( wclass.lpszClassName, "HiliteMenuTest",
1975                                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1976                                   400, 200, NULL, NULL, wclass.hInstance, NULL) );
1977
1978     hMenu = CreateMenu();
1979     hPopupMenu = CreatePopupMenu();
1980
1981     AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup");
1982
1983     AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1984     AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1985     AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1986
1987     SetMenu(hWnd, hMenu);
1988
1989     /* test invalid arguments */
1990
1991     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1992       "HiliteMenuItem: Item 2 is hilited\n");
1993
1994     SetLastError(0xdeadbeef);
1995     todo_wine
1996     {
1997     ok(!HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION),
1998       "HiliteMenuItem: call should have failed.\n");
1999     }
2000     ok(GetLastError() == 0xdeadbeef || /* 9x */
2001        GetLastError() == ERROR_INVALID_WINDOW_HANDLE /* NT */,
2002       "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError());
2003
2004     SetLastError(0xdeadbeef);
2005     ok(!HiliteMenuItem(hWnd, NULL, 1, MF_HILITE | MF_BYPOSITION),
2006       "HiliteMenuItem: call should have failed.\n");
2007     ok(GetLastError() == 0xdeadbeef || /* 9x */
2008        GetLastError() == ERROR_INVALID_MENU_HANDLE /* NT */,
2009       "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError());
2010
2011     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2012       "HiliteMenuItem: Item 2 is hilited\n");
2013
2014     /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */
2015
2016     SetLastError(0xdeadbeef);
2017     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_BYPOSITION),
2018       "HiliteMenuItem: call should have succeeded.\n");
2019     ok(GetLastError() == 0xdeadbeef,
2020       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2021
2022     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2023       "HiliteMenuItem: Item 2 is hilited\n");
2024
2025     SetLastError(0xdeadbeef);
2026     todo_wine
2027     {
2028     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE),
2029       "HiliteMenuItem: call should have succeeded.\n");
2030     }
2031     ok(GetLastError() == 0xdeadbeef,
2032       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2033
2034     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2035       "HiliteMenuItem: Item 2 is hilited\n");
2036
2037     /* hilite a menu item (by position) */
2038
2039     SetLastError(0xdeadbeef);
2040     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION),
2041       "HiliteMenuItem: call should not have failed.\n");
2042     ok(GetLastError() == 0xdeadbeef,
2043       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2044
2045     todo_wine
2046     {
2047     ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
2048       "HiliteMenuItem: Item 2 is not hilited\n");
2049     }
2050
2051     /* unhilite a menu item (by position) */
2052
2053     SetLastError(0xdeadbeef);
2054     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_UNHILITE | MF_BYPOSITION),
2055       "HiliteMenuItem: call should not have failed.\n");
2056     ok(GetLastError() == 0xdeadbeef,
2057       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2058
2059     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2060       "HiliteMenuItem: Item 2 is hilited\n");
2061
2062     /* hilite a menu item (by command) */
2063
2064     SetLastError(0xdeadbeef);
2065     ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_HILITE | MF_BYCOMMAND),
2066       "HiliteMenuItem: call should not have failed.\n");
2067     ok(GetLastError() == 0xdeadbeef,
2068       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2069
2070     todo_wine
2071     {
2072     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2073       "HiliteMenuItem: Item 3 is not hilited\n");
2074     }
2075
2076     /* unhilite a menu item (by command) */
2077
2078     SetLastError(0xdeadbeef);
2079     ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_UNHILITE | MF_BYCOMMAND),
2080       "HiliteMenuItem: call should not have failed.\n");
2081     ok(GetLastError() == 0xdeadbeef,
2082       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2083
2084     ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE),
2085       "HiliteMenuItem: Item 3 is hilited\n");
2086
2087     DestroyWindow(hWnd);
2088 }
2089
2090 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
2091                              UINT checked_state)
2092 {
2093     INT i, count;
2094
2095     count = GetMenuItemCount(hmenu);
2096     ok (count != -1, "GetMenuItemCount returned -1\n");
2097
2098     for (i = 0; i < count; i++)
2099     {
2100         BOOL ret;
2101         MENUITEMINFO mii;
2102
2103         memset(&mii, 0, sizeof(mii));
2104         mii.cbSize = sizeof(mii);
2105         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
2106         ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2107         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2108 #if 0
2109         trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2110                i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
2111 #endif
2112         if (mii.hSubMenu)
2113         {
2114             ok(mii.wID == (UINT_PTR)mii.hSubMenu, "id %u: wID should be equal to hSubMenu\n", checked_cmd);
2115             check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state);
2116         }
2117         else
2118         {
2119             if (mii.wID == checked_cmd)
2120             {
2121                 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType);
2122                 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState);
2123                 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2124             }
2125             else
2126             {
2127                 ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID);
2128
2129                 if (mii.fType == MFT_SEPARATOR)
2130                 {
2131                     ok(mii.fState == MFS_GRAYED, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd, mii.fState);
2132                     ok(mii.wID == 0, "id %u: expected wID 0, got %u\n", checked_cmd, mii.wID);
2133                 }
2134                 else
2135                 {
2136                     ok(mii.fState == 0, "id %u: expected fState 0, got %04x\n", checked_cmd, mii.fState);
2137                     ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2138                 }
2139             }
2140         }
2141     }
2142 }
2143
2144 static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags)
2145 {
2146     BOOL ret;
2147     MENUITEMINFO mii;
2148
2149     memset(&mii, 0, sizeof(mii));
2150     mii.cbSize = sizeof(mii);
2151     mii.fMask  = MIIM_FTYPE | MIIM_STATE;
2152     ret = SetMenuItemInfo(hmenu, id, (flags & MF_BYPOSITION) != 0, &mii);
2153     ok(ret, "SetMenuItemInfo(%u) failed\n", id);
2154 }
2155
2156 static void test_CheckMenuRadioItem(void)
2157 {
2158     BOOL ret;
2159     HMENU hmenu;
2160
2161     hmenu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1));
2162     assert(hmenu != 0);
2163
2164     check_menu_items(hmenu, -1, 0, 0);
2165
2166     ret = CheckMenuRadioItem(hmenu, 100, 100, 100, MF_BYCOMMAND);
2167     ok(ret, "CheckMenuRadioItem failed\n");
2168     check_menu_items(hmenu, 100, MFT_RADIOCHECK, MFS_CHECKED);
2169
2170     /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2171     ret = CheckMenuRadioItem(hmenu, 100, 100, -1, MF_BYCOMMAND);
2172     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2173     check_menu_items(hmenu, 100, MFT_RADIOCHECK, 0);
2174
2175     /* clear check */
2176     clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND);
2177     check_menu_items(hmenu, -1, 0, 0);
2178
2179     /* first and checked items are on different menus */
2180     ret = CheckMenuRadioItem(hmenu, 0, 300, 202, MF_BYCOMMAND);
2181     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2182     check_menu_items(hmenu, -1, 0, 0);
2183
2184     ret = CheckMenuRadioItem(hmenu, 200, 300, 202, MF_BYCOMMAND);
2185     ok(ret, "CheckMenuRadioItem failed\n");
2186     check_menu_items(hmenu, 202, MFT_RADIOCHECK, MFS_CHECKED);
2187
2188     /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2189     ret = CheckMenuRadioItem(hmenu, 202, 202, -1, MF_BYCOMMAND);
2190     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2191     check_menu_items(hmenu, 202, MFT_RADIOCHECK, 0);
2192
2193     /* clear check */
2194     clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND);
2195     check_menu_items(hmenu, -1, 0, 0);
2196
2197     /* just for fun, try to check separator */
2198     ret = CheckMenuRadioItem(hmenu, 0, 300, 0, MF_BYCOMMAND);
2199     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2200     check_menu_items(hmenu, -1, 0, 0);
2201 }
2202
2203 static void test_menu_resource_layout(void)
2204 {
2205     static const struct
2206     {
2207         MENUITEMTEMPLATEHEADER mith;
2208         WORD data[14];
2209     } menu_template =
2210     {
2211         { 0, 0 }, /* versionNumber, offset */
2212         {
2213             /* mtOption, mtID, mtString[] '\0' terminated */
2214             MF_STRING, 1, 'F', 0,
2215             MF_STRING, 2, 0,
2216             MF_SEPARATOR, 3, 0,
2217             /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2218             MF_STRING|MF_GRAYED|MF_END, 5, 'E', 0
2219         }
2220     };
2221     static const struct
2222     {
2223         UINT type, state, id;
2224         const char *str;
2225     } menu_data[] =
2226     {
2227         { MF_STRING, MF_ENABLED, 1, "F" },
2228         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 2, "" },
2229         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 3, "" },
2230         /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/
2231         { MF_STRING, MF_GRAYED, 5, "E" },
2232         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 6, "" },
2233         { MF_STRING, MF_ENABLED, 7, "" },
2234         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" }
2235     };
2236     HMENU hmenu;
2237     INT count, i;
2238     BOOL ret;
2239
2240     hmenu = LoadMenuIndirect(&menu_template);
2241     ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError());
2242
2243     ret = AppendMenu(hmenu, MF_STRING, 6, NULL);
2244     ok(ret, "AppendMenu failed\n");
2245     ret = AppendMenu(hmenu, MF_STRING, 7, "\0");
2246     ok(ret, "AppendMenu failed\n");
2247     ret = AppendMenu(hmenu, MF_SEPARATOR, 8, "separator");
2248     ok(ret, "AppendMenu failed\n");
2249
2250     count = GetMenuItemCount(hmenu);
2251     ok(count == sizeof(menu_data)/sizeof(menu_data[0]),
2252        "expected %u menu items, got %u\n",
2253        (UINT)(sizeof(menu_data)/sizeof(menu_data[0])), count);
2254
2255     for (i = 0; i < count; i++)
2256     {
2257         char buf[20];
2258         MENUITEMINFO mii;
2259
2260         memset(&mii, 0, sizeof(mii));
2261         mii.cbSize = sizeof(mii);
2262         mii.dwTypeData = buf;
2263         mii.cch = sizeof(buf);
2264         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_STRING;
2265         ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2266         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2267 #if 0
2268         trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2269                i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
2270 #endif
2271         ok(mii.fType == menu_data[i].type,
2272            "%u: expected fType %04x, got %04x\n", i, menu_data[i].type, mii.fType);
2273         ok(mii.fState == menu_data[i].state,
2274            "%u: expected fState %04x, got %04x\n", i, menu_data[i].state, mii.fState);
2275         ok(mii.wID == menu_data[i].id,
2276            "%u: expected wID %04x, got %04x\n", i, menu_data[i].id, mii.wID);
2277         ok(mii.cch == strlen(menu_data[i].str),
2278            "%u: expected cch %u, got %u\n", i, (UINT)strlen(menu_data[i].str), mii.cch);
2279         ok(!strcmp(mii.dwTypeData, menu_data[i].str),
2280            "%u: expected dwTypeData %s, got %s\n", i, menu_data[i].str, (LPCSTR)mii.dwTypeData);
2281     }
2282
2283     DestroyMenu(hmenu);
2284 }
2285
2286 struct menu_data
2287 {
2288     UINT type, id;
2289     const char *str;
2290 };
2291
2292 static HMENU create_menu_from_data(const struct menu_data *item, INT item_count)
2293 {
2294     HMENU hmenu;
2295     INT i;
2296     BOOL ret;
2297
2298     hmenu = CreateMenu();
2299     assert(hmenu != 0);
2300
2301     for (i = 0; i < item_count; i++)
2302     {
2303         SetLastError(0xdeadbeef);
2304         ret = AppendMenu(hmenu, item[i].type, item[i].id, item[i].str);
2305         ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %u\n",
2306            i, item[i].type, item[i].id, item[i].str, GetLastError());
2307     }
2308     return hmenu;
2309 }
2310
2311 static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count)
2312 {
2313     INT count, i;
2314     BOOL ret;
2315
2316     count = GetMenuItemCount(hmenu);
2317     ok(count == item_count, "expected %d, got %d menu items\n", count, item_count);
2318
2319     for (i = 0; i < count; i++)
2320     {
2321         char buf[20];
2322         MENUITEMINFO mii;
2323
2324         memset(&mii, 0, sizeof(mii));
2325         mii.cbSize = sizeof(mii);
2326         mii.dwTypeData = buf;
2327         mii.cch = sizeof(buf);
2328         mii.fMask  = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_BITMAP;
2329         ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2330         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2331 #if 0
2332         trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2333                i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
2334 #endif
2335         ok(mii.fType == item[i].type,
2336            "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType);
2337         ok(mii.wID == item[i].id,
2338            "%u: expected wID %04x, got %04x\n", i, item[i].id, mii.wID);
2339         if (item[i].type & (MF_BITMAP | MF_SEPARATOR))
2340         {
2341             /* For some reason Windows sets high word to not 0 for
2342              * not "magic" ids.
2343              */
2344             ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str),
2345                "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem);
2346         }
2347         else
2348         {
2349             ok(mii.cch == strlen(item[i].str),
2350                "%u: expected cch %u, got %u\n", i, (UINT)strlen(item[i].str), mii.cch);
2351             ok(!strcmp(mii.dwTypeData, item[i].str),
2352                "%u: expected dwTypeData %s, got %s\n", i, item[i].str, (LPCSTR)mii.dwTypeData);
2353         }
2354     }
2355 }
2356
2357 static void test_InsertMenu(void)
2358 {
2359     /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2360      * regardless of their id.
2361      */
2362     static const struct menu_data in1[] =
2363     {
2364         { MF_STRING, 1, "File" },
2365         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2366         { MF_STRING|MF_HELP, 2, "Help" }
2367     };
2368     static const struct menu_data out1[] =
2369     {
2370         { MF_STRING, 1, "File" },
2371         { MF_STRING|MF_HELP, 2, "Help" },
2372         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) }
2373     };
2374     static const struct menu_data in2[] =
2375     {
2376         { MF_STRING, 1, "File" },
2377         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2378         { MF_STRING|MF_HELP, 2, "Help" }
2379     };
2380     static const struct menu_data out2[] =
2381     {
2382         { MF_STRING, 1, "File" },
2383         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2384         { MF_STRING|MF_HELP, 2, "Help" }
2385     };
2386     static const struct menu_data in3[] =
2387     {
2388         { MF_STRING, 1, "File" },
2389         { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2390         { MF_STRING|MF_HELP, 2, "Help" }
2391     };
2392     static const struct menu_data out3[] =
2393     {
2394         { MF_STRING, 1, "File" },
2395         { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(0) },
2396         { MF_STRING|MF_HELP, 2, "Help" },
2397     };
2398     static const struct menu_data in4[] =
2399     {
2400         { MF_STRING, 1, "File" },
2401         { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) },
2402         { MF_STRING|MF_HELP, 2, "Help" }
2403     };
2404     static const struct menu_data out4[] =
2405     {
2406         { MF_STRING, 1, "File" },
2407         { MF_STRING|MF_HELP, 2, "Help" },
2408         { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) }
2409     };
2410     HMENU hmenu;
2411
2412 #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0]))
2413 #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0]))
2414
2415     hmenu = create_menu(in1);
2416     compare_menu(hmenu, out1);
2417     DestroyMenu(hmenu);
2418
2419     hmenu = create_menu(in2);
2420     compare_menu(hmenu, out2);
2421     DestroyMenu(hmenu);
2422
2423     hmenu = create_menu(in3);
2424     compare_menu(hmenu, out3);
2425     DestroyMenu(hmenu);
2426
2427     hmenu = create_menu(in4);
2428     compare_menu(hmenu, out4);
2429     DestroyMenu(hmenu);
2430
2431 #undef create_menu
2432 #undef compare_menu
2433 }
2434
2435 static void test_menu_getmenuinfo(void)
2436 {
2437     HMENU hmenu;
2438     MENUINFO mi = {0};
2439     BOOL ret;
2440     DWORD gle;
2441
2442     /* create a menu */
2443     hmenu = CreateMenu();
2444     assert( hmenu);
2445     /* test some parameter errors */
2446     SetLastError(0xdeadbeef);
2447     ret = pGetMenuInfo( hmenu, NULL);
2448     gle= GetLastError();
2449     ok( !ret, "GetMenuInfo() should have failed\n");
2450     ok( gle == ERROR_INVALID_PARAMETER, "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2451     SetLastError(0xdeadbeef);
2452     mi.cbSize = 0;
2453     ret = pGetMenuInfo( hmenu, &mi);
2454     gle= GetLastError();
2455     ok( !ret, "GetMenuInfo() should have failed\n");
2456     ok( gle == ERROR_INVALID_PARAMETER, "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2457     SetLastError(0xdeadbeef);
2458     mi.cbSize = sizeof( MENUINFO);
2459     ret = pGetMenuInfo( hmenu, &mi);
2460     gle= GetLastError();
2461     ok( ret, "GetMenuInfo() should have succeeded\n");
2462     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2463     SetLastError(0xdeadbeef);
2464     mi.cbSize = 0;
2465     ret = pGetMenuInfo( NULL, &mi);
2466     gle= GetLastError();
2467     ok( !ret, "GetMenuInfo() should have failed\n");
2468     ok( gle == ERROR_INVALID_PARAMETER, "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2469         /* clean up */
2470     DestroyMenu( hmenu);
2471     return;
2472 }
2473
2474 static void test_menu_setmenuinfo(void)
2475 {
2476     HMENU hmenu, hsubmenu;
2477     MENUINFO mi = {0};
2478     MENUITEMINFOA mii = {sizeof( MENUITEMINFOA)};
2479     BOOL ret;
2480     DWORD gle;
2481
2482     /* create a menu with a submenu */
2483     hmenu = CreateMenu();
2484     hsubmenu = CreateMenu();
2485     assert( hmenu && hsubmenu);
2486     mii.fMask = MIIM_SUBMENU;
2487     mii.hSubMenu = hsubmenu;
2488     ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
2489     ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
2490     /* test some parameter errors */
2491     SetLastError(0xdeadbeef);
2492     ret = pSetMenuInfo( hmenu, NULL);
2493     gle= GetLastError();
2494     ok( !ret, "SetMenuInfo() should have failed\n");
2495     ok( gle == ERROR_INVALID_PARAMETER, "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2496     SetLastError(0xdeadbeef);
2497     mi.cbSize = 0;
2498     ret = pSetMenuInfo( hmenu, &mi);
2499     gle= GetLastError();
2500     ok( !ret, "SetMenuInfo() should have failed\n");
2501     ok( gle == ERROR_INVALID_PARAMETER, "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2502     SetLastError(0xdeadbeef);
2503     mi.cbSize = sizeof( MENUINFO);
2504     ret = pSetMenuInfo( hmenu, &mi);
2505     gle= GetLastError();
2506     ok( ret, "SetMenuInfo() should have succeeded\n");
2507     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
2508     SetLastError(0xdeadbeef);
2509     mi.cbSize = 0;
2510     ret = pSetMenuInfo( NULL, &mi);
2511     gle= GetLastError();
2512     ok( !ret, "SetMenuInfo() should have failed\n");
2513     ok( gle == ERROR_INVALID_PARAMETER, "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
2514     /* functional tests */
2515     /* menu and submenu should have the CHECKORBMP style bit cleared */
2516     SetLastError(0xdeadbeef);
2517     mi.cbSize = sizeof( MENUINFO);
2518     mi.fMask = MIM_STYLE;
2519     ret = pGetMenuInfo( hmenu, &mi);
2520     gle= GetLastError();
2521     ok( ret, "GetMenuInfo() should have succeeded\n");
2522     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2523     ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n");
2524     SetLastError(0xdeadbeef);
2525     mi.cbSize = sizeof( MENUINFO);
2526     mi.fMask = MIM_STYLE;
2527     ret = pGetMenuInfo( hsubmenu, &mi);
2528     gle= GetLastError();
2529     ok( ret, "GetMenuInfo() should have succeeded\n");
2530     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2531     ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n");
2532     /* SetMenuInfo() */
2533     SetLastError(0xdeadbeef);
2534     mi.cbSize = sizeof( MENUINFO);
2535     mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS;
2536     mi.dwStyle = MNS_CHECKORBMP;
2537     ret = pSetMenuInfo( hmenu, &mi);
2538     gle= GetLastError();
2539     ok( ret, "SetMenuInfo() should have succeeded\n");
2540     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
2541     /* Now both menus should have the MNS_CHECKORBMP style bit set */
2542     SetLastError(0xdeadbeef);
2543     mi.cbSize = sizeof( MENUINFO);
2544     mi.fMask = MIM_STYLE;
2545     ret = pGetMenuInfo( hmenu, &mi);
2546     gle= GetLastError();
2547     ok( ret, "GetMenuInfo() should have succeeded\n");
2548     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2549     ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n");
2550     SetLastError(0xdeadbeef);
2551     mi.cbSize = sizeof( MENUINFO);
2552     mi.fMask = MIM_STYLE;
2553     ret = pGetMenuInfo( hsubmenu, &mi);
2554     gle= GetLastError();
2555     ok( ret, "GetMenuInfo() should have succeeded\n");
2556     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2557     ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n");
2558     /* now repeat that without the APPLYTOSUBMENUS flag and another style bit */
2559     SetLastError(0xdeadbeef);
2560     mi.cbSize = sizeof( MENUINFO);
2561     mi.fMask = MIM_STYLE ;
2562     mi.dwStyle = MNS_NOCHECK;
2563     ret = pSetMenuInfo( hmenu, &mi);
2564     gle= GetLastError();
2565     ok( ret, "SetMenuInfo() should have succeeded\n");
2566     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
2567     /* Now only the top menu should have the MNS_NOCHECK style bit set */
2568     SetLastError(0xdeadbeef);
2569     mi.cbSize = sizeof( MENUINFO);
2570     mi.fMask = MIM_STYLE;
2571     ret = pGetMenuInfo( hmenu, &mi);
2572     gle= GetLastError();
2573     ok( ret, "GetMenuInfo() should have succeeded\n");
2574     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2575     ok( mi.dwStyle & MNS_NOCHECK, "menustyle was expected to have the MNS_NOCHECK flag\n");
2576     SetLastError(0xdeadbeef);
2577     mi.cbSize = sizeof( MENUINFO);
2578     mi.fMask = MIM_STYLE;
2579     ret = pGetMenuInfo( hsubmenu, &mi);
2580     gle= GetLastError();
2581     ok( ret, "GetMenuInfo() should have succeeded\n");
2582     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
2583     ok( !(mi.dwStyle & MNS_NOCHECK), "menustyle was not expected to have the MNS_NOCHECK flag\n");
2584     /* clean up */
2585     DestroyMenu( hsubmenu);
2586     DestroyMenu( hmenu);
2587     return;
2588 }
2589
2590 START_TEST(menu)
2591 {
2592     init_function_pointers();
2593
2594     /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't
2595      * handle that.
2596      */
2597     if (correct_behavior())
2598     {
2599         test_menu_add_string();
2600         test_menu_iteminfo();
2601         test_menu_search_bycommand();
2602         test_CheckMenuRadioItem();
2603         test_menu_resource_layout();
2604         test_InsertMenu();
2605     }
2606
2607     register_menu_check_class();
2608
2609     test_menu_locked_by_window();
2610     test_menu_ownerdraw();
2611     test_menu_bmp_and_string();
2612     /* test Get/SetMenuInfo if available */
2613     if( pGetMenuInfo && pSetMenuInfo) {
2614         test_menu_getmenuinfo();
2615         test_menu_setmenuinfo();
2616     } else
2617         win_skip("Get/SetMenuInfo are not available\n");
2618     if( !pSendInput)
2619         win_skip("SendInput is not available\n");
2620     else
2621         test_menu_input();
2622     test_menu_flags();
2623
2624     test_menu_hilitemenuitem();
2625 }