mcicda: Exclude unused headers.
[wine] / dlls / user32 / tests / menu.c
1 /*
2  * Unit tests for menus
3  *
4  * Copyright 2005 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #define OEMRESOURCE         /* For OBM_MNARROW */
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33
34 #include "wine/test.h"
35
36 static ATOM atomMenuCheckClass;
37
38 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
39 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
40
41 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
42 {
43     switch (msg)
44     {
45     case WM_ENTERMENULOOP:
46         /* mark window as having entered menu loop */
47         SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
48         /* exit menu modal loop
49          * ( A SendMessage does not work on NT3.51 here ) */
50         return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
51     }
52     return DefWindowProc(hwnd, msg, wparam, lparam);
53 }
54
55 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
56  * our own type */
57 typedef struct
58 {
59     DWORD type;
60     union
61     {
62         MOUSEINPUT      mi;
63         KEYBDINPUT      ki;
64         HARDWAREINPUT   hi;
65     } u;
66 } TEST_INPUT;
67
68 /* globals to communicate between test and wndproc */
69
70 static BOOL bMenuVisible;
71 static HMENU hMenus[4];
72
73 #define MOD_SIZE 10
74 #define MOD_NRMENUS 8
75
76  /* menu texts with their sizes */
77 static struct {
78     LPCSTR text;
79     SIZE size; /* size of text up to any \t */
80     SIZE sc_size; /* size of the short-cut */
81 } MOD_txtsizes[] = {
82         { "Pinot &Noir" },
83         { "&Merlot\bF4" },
84         { "Shira&z\tAlt+S" },
85         { "" },
86         { NULL }
87 };
88
89 static unsigned int MOD_maxid;
90 static RECT MOD_rc[MOD_NRMENUS];
91 static int MOD_avec, MOD_hic;
92 static int MOD_odheight;
93 static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
94     {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
95 static int MOD_GotDrawItemMsg = FALSE;
96 /* wndproc used by test_menu_ownerdraw() */
97 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
98         WPARAM wparam, LPARAM lparam)
99 {
100     switch (msg)
101     {
102         case WM_MEASUREITEM:
103             {
104                 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
105                 if( winetest_debug)
106                     trace("WM_MEASUREITEM received data %lx size %dx%d\n",
107                             pmis->itemData, pmis->itemWidth, pmis->itemHeight);
108                 MOD_odheight = pmis->itemHeight;
109                 pmis->itemWidth = MODsizes[pmis->itemData].cx;
110                 pmis->itemHeight = MODsizes[pmis->itemData].cy;
111                 return TRUE;
112             }
113         case WM_DRAWITEM:
114             {
115                 DRAWITEMSTRUCT * pdis;
116                 TEXTMETRIC tm;
117                 HPEN oldpen;
118                 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
119                 SIZE sz;
120                 int i;
121                 pdis = (DRAWITEMSTRUCT *) lparam;
122                 if( winetest_debug) {
123                     RECT rc;
124                     GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
125                     trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc:  %d,%d-%d,%d\n",
126                             hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
127                             pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
128                             pdis->rcItem.right,pdis->rcItem.bottom,
129                             rc.left,rc.top,rc.right,rc.bottom);
130                     oldpen=SelectObject( pdis->hDC, GetStockObject(
131                                 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
132                     Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
133                             pdis->rcItem.right,pdis->rcItem.bottom );
134                     SelectObject( pdis->hDC, oldpen);
135                 }
136                 /* calculate widths of some menu texts */
137                 if( ! MOD_txtsizes[0].size.cx)
138                     for(i = 0; MOD_txtsizes[i].text; i++) {
139                         char buf[100], *p;
140                         RECT rc={0,0,0,0};
141                         strcpy( buf, MOD_txtsizes[i].text);
142                         if( ( p = strchr( buf, '\t'))) {
143                             *p = '\0';
144                             DrawText( pdis->hDC, p + 1, -1, &rc,
145                                     DT_SINGLELINE|DT_CALCRECT);
146                             MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
147                             MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
148                         }
149                         DrawText( pdis->hDC, buf, -1, &rc,
150                                 DT_SINGLELINE|DT_CALCRECT);
151                         MOD_txtsizes[i].size.cx= rc.right - rc.left;
152                         MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
153                     }
154
155                 if( pdis->itemData > MOD_maxid) return TRUE;
156                 /* store the rectangl */
157                 MOD_rc[pdis->itemData] = pdis->rcItem;
158                 /* calculate average character width */
159                 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
160                 MOD_avec = (sz.cx + 26)/52;
161                 GetTextMetrics( pdis->hDC, &tm);
162                 MOD_hic = tm.tmHeight;
163                 MOD_GotDrawItemMsg = TRUE;
164                 return TRUE;
165             }
166         case WM_ENTERIDLE:
167             {
168                 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
169                 return TRUE;
170             }
171
172     }
173     return DefWindowProc(hwnd, msg, wparam, lparam);
174 }
175
176 static void register_menu_check_class(void)
177 {
178     WNDCLASS wc =
179     {
180         0,
181         menu_check_wnd_proc,
182         0,
183         0,
184         GetModuleHandle(NULL),
185         NULL,
186         LoadCursor(NULL, IDC_ARROW),
187         (HBRUSH)(COLOR_BTNFACE+1),
188         NULL,
189         TEXT("WineMenuCheck"),
190     };
191     
192     atomMenuCheckClass = RegisterClass(&wc);
193 }
194
195 /* demonstrates that windows locks the menu object so that it is still valid
196  * even after a client calls DestroyMenu on it */
197 static void test_menu_locked_by_window(void)
198 {
199     BOOL ret;
200     HMENU hmenu;
201     HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
202                                WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
203                                NULL, NULL, NULL, NULL);
204     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
205     hmenu = CreateMenu();
206     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
207     ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
208     ok(ret, "InsertMenu failed with error %d\n", GetLastError());
209     ret = SetMenu(hwnd, hmenu);
210     ok(ret, "SetMenu failed with error %d\n", GetLastError());
211     ret = DestroyMenu(hmenu);
212     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
213
214     ret = DrawMenuBar(hwnd);
215     todo_wine {
216     ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
217     }
218     ret = IsMenu(GetMenu(hwnd));
219     ok(!ret, "Menu handle should have been destroyed\n");
220
221     SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
222     /* did we process the WM_INITMENU message? */
223     ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
224     todo_wine {
225     ok(ret, "WM_INITMENU should have been sent\n");
226     }
227
228     DestroyWindow(hwnd);
229 }
230
231 static void test_menu_ownerdraw(void)
232 {
233     int i,j,k;
234     BOOL ret;
235     HMENU hmenu;
236     LONG leftcol;
237     HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
238                                WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
239                                NULL, NULL, NULL, NULL);
240     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
241     if( !hwnd) return;
242     SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
243     hmenu = CreatePopupMenu();
244     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
245     if( !hmenu) { DestroyWindow(hwnd);return;}
246     k=0;
247     for( j=0;j<2;j++) /* create columns */
248         for(i=0;i<2;i++) { /* create rows */
249             ret = AppendMenu( hmenu, MF_OWNERDRAW | 
250                     (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
251             k++;
252             ok( ret, "AppendMenu failed for %d\n", k-1);
253         }
254     MOD_maxid = k-1;
255     assert( k <= sizeof(MOD_rc)/sizeof(RECT));
256     /* display the menu */
257     ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
258
259     /* columns have a 4 pixel gap between them */
260     ok( MOD_rc[0].right + 4 ==  MOD_rc[2].left,
261             "item rectangles are not separated by 4 pixels space\n");
262     /* height should be what the MEASUREITEM message has returned */
263     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
264             "menu item has wrong height: %d should be %d\n",
265             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
266     /* no gaps between the rows */
267     ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
268             "There should not be a space between the rows, gap is %d\n",
269             MOD_rc[0].bottom - MOD_rc[1].top);
270     /* test the correct value of the item height that was sent
271      * by the WM_MEASUREITEM message */
272     ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
273             MOD_odheight == MOD_hic,                     /* Win95,98,ME */
274             "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
275             HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
276     /* test what MF_MENUBREAK did at the first position. Also show
277      * that an MF_SEPARATOR is ignored in the height calculation. */
278     leftcol= MOD_rc[0].left;
279     ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0); 
280     /* display the menu */
281     ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
282     /* left should be 4 pixels less now */
283     ok( leftcol == MOD_rc[0].left + 4, 
284             "columns should be 4 pixels to the left (actual %d).\n",
285             leftcol - MOD_rc[0].left);
286     /* test width */
287     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
288             "width of owner drawn menu item is wrong. Got %d expected %d\n",
289             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
290     /* and height */
291     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
292             "Height is incorrect. Got %d expected %d\n",
293             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
294
295     /* test width/height of an ownerdraw menu bar as well */
296     ret = DestroyMenu(hmenu);
297     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
298     hmenu = CreateMenu();
299     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
300     if( !hmenu) { DestroyWindow(hwnd);return;}
301     MOD_maxid=1;
302     for(i=0;i<2;i++) { 
303         ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
304         ok( ret, "AppendMenu failed for %d\n", i);
305     }
306     ret = SetMenu( hwnd, hmenu);
307     UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
308     ok(ret, "SetMenu failed with error %d\n", GetLastError());
309     /* test width */
310     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
311             "width of owner drawn menu item is wrong. Got %d expected %d\n",
312             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
313     /* test hight */
314     ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
315             "Height of owner drawn menu item is wrong. Got %d expected %d\n",
316             MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
317
318     /* clean up */
319     ret = DestroyMenu(hmenu);
320     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
321     DestroyWindow(hwnd);
322 }
323
324 /* helper for test_menu_bmp_and_string() */
325 static void test_mbs_help( int ispop, int hassub, int mnuopt,
326         HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
327         SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
328 {
329     BOOL ret;
330     HMENU hmenu, submenu;
331     MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
332     MENUINFO mi;
333     RECT rc;
334     CHAR text_copy[16];
335     int hastab,  expect;
336     int failed = 0;
337
338     MOD_GotDrawItemMsg = FALSE;
339     mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
340     mii.fType = 0;
341     mii.fState = MF_CHECKED;
342     mii.dwItemData =0;
343     MODsizes[0] = bmpsize;
344     hastab = 0;
345     if( text ) {
346         char *p;
347         mii.fMask |= MIIM_STRING;
348         strcpy(text_copy, text);
349         mii.dwTypeData = text_copy; /* structure member declared non-const */
350         if( ( p = strchr( text, '\t'))) {
351             hastab = *(p + 1) ? 2 : 1;
352         }
353     }
354     /* tabs don't make sense in menubars */
355     if(hastab && !ispop) return;
356     if( hbmp) {
357         mii.fMask |= MIIM_BITMAP;
358         mii.hbmpItem = hbmp;
359     }
360     submenu = CreateMenu();
361     ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
362     if( ispop)
363         hmenu = CreatePopupMenu();
364     else
365         hmenu = CreateMenu();
366     ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
367     if( hassub) {
368         mii.fMask |= MIIM_SUBMENU;
369         mii.hSubMenu = submenu;
370     }
371     if( mnuopt) {
372         mi.cbSize = sizeof(mi);
373         mi.fMask = MIM_STYLE;
374         pGetMenuInfo( hmenu, &mi);
375         mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
376         ret = pSetMenuInfo( hmenu, &mi);
377         ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
378     }
379     ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
380     ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
381     failed = !ret;
382     if( winetest_debug) {
383         HDC hdc=GetDC(hwnd);
384         RECT rc = {100, 50, 400, 70};
385         char buf[100];
386
387         sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
388         FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
389         TextOut( hdc, 100, 50, buf, strlen( buf));
390         ReleaseDC( hwnd, hdc);
391     }
392     if(ispop)
393         ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
394     else {
395         ret = SetMenu( hwnd, hmenu);
396         ok(ret, "SetMenu failed with error %d\n", GetLastError());
397         DrawMenuBar( hwnd);
398     }
399     ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
400     /* check menu width */
401     if( ispop)
402         expect = ( text || hbmp ?
403                 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
404                 : 0) +
405             arrowwidth  + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
406             (text && hastab ? /* TAB space */
407              MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
408             (text ?  2 + (text[0] ? size.cx :0): 0) ;
409     else
410         expect = !(text || hbmp) ? 0 :
411             ( hbmp ? (text ? 2:0) + bmpsize.cx  : 0 ) +
412             (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
413     ok( rc.right - rc.left == expect,
414             "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
415     failed = failed || !(rc.right - rc.left == expect);
416     /* check menu height */
417     if( ispop)
418         expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
419                 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
420                     (hbmp ? bmpsize.cy + 2 : 0)));
421     else
422         expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
423                 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
424     ok( rc.bottom - rc.top == expect,
425             "menu height wrong, got %d expected %d (%d)\n",
426             rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
427     failed = failed || !(rc.bottom - rc.top == expect);
428     if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
429         /* check the position of the bitmap */
430         /* horizontal */
431         expect = ispop ? (4 + ( mnuopt  ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
432             : 3;
433         ok( expect == MOD_rc[0].left,
434                 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
435         failed = failed || !(expect == MOD_rc[0].left);
436         /* vertical */
437         expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
438         ok( expect == MOD_rc[0].top,
439                 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
440         failed = failed || !(expect == MOD_rc[0].top);
441     }
442     /* if there was a failure, report details */
443     if( failed) {
444         trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
445                 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
446                 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
447         trace("    check %d,%d arrow %d avechar %d\n",
448                 GetSystemMetrics(SM_CXMENUCHECK ),
449                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
450         if( hbmp == HBMMENU_CALLBACK)
451             trace( "    rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
452                 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
453                 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
454     }
455     /* clean up */
456     ret = DestroyMenu(submenu);
457     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
458     ret = DestroyMenu(hmenu);
459     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
460 }
461
462
463 static void test_menu_bmp_and_string(void)
464 {
465     BYTE bmfill[300];
466     HBITMAP hbm_arrow;
467     BITMAP bm;
468     INT arrowwidth;
469     HWND hwnd;
470     int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
471
472     if( !pGetMenuInfo) return;
473
474     memset( bmfill, 0x55, sizeof( bmfill));
475     hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
476                           WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
477                           NULL, NULL, NULL, NULL);
478     hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
479     GetObject( hbm_arrow, sizeof(bm), &bm);
480     arrowwidth = bm.bmWidth;
481
482     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
483     if( !hwnd) return;
484     SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
485
486     if( winetest_debug)
487         trace("    check %d,%d arrow %d avechar %d\n",
488                 GetSystemMetrics(SM_CXMENUCHECK ),
489                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
490     count = 0;
491     MOD_maxid = 0;
492     for( ispop=1; ispop >= 0; ispop--){
493         static SIZE bmsizes[]= {
494             {10,10},{38,38},{1,30},{55,5}};
495         for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
496             HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
497             HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL  };
498             ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError());
499             for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
500                 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
501                     for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
502                         for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
503                             /* no need to test NULL bitmaps of several sizes */
504                             if( !bitmaps[bmpidx] && szidx > 0) continue;
505                             if( !ispop && hassub) continue;
506                             test_mbs_help( ispop, hassub, mnuopt,
507                                     hwnd, arrowwidth, ++count,
508                                     bitmaps[bmpidx],
509                                     bmsizes[szidx],
510                                     MOD_txtsizes[txtidx].text,
511                                     MOD_txtsizes[txtidx].size,
512                                     MOD_txtsizes[txtidx].sc_size);
513                         }
514                     }
515                 }
516             }
517             DeleteObject( hbm);
518         }
519     }
520     /* clean up */
521     DestroyWindow(hwnd);
522 }
523
524 static void test_menu_add_string( void )
525 {
526     HMENU hmenu;
527     MENUITEMINFO info;
528     BOOL rc;
529     int ret;
530
531     char string[0x80];
532     char string2[0x80];
533
534     char strback[0x80];
535     WCHAR strbackW[0x80];
536     static CHAR blah[] = "blah";
537     static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
538
539     hmenu = CreateMenu();
540
541     memset( &info, 0, sizeof info );
542     info.cbSize = sizeof info;
543     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
544     info.dwTypeData = blah;
545     info.cch = 6;
546     info.dwItemData = 0;
547     info.wID = 1;
548     info.fState = 0;
549     InsertMenuItem(hmenu, 0, TRUE, &info );
550
551     memset( &info, 0, sizeof info );
552     info.cbSize = sizeof info;
553     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
554     info.dwTypeData = string;
555     info.cch = sizeof string;
556     string[0] = 0;
557     GetMenuItemInfo( hmenu, 0, TRUE, &info );
558
559     ok( !strcmp( string, "blah" ), "menu item name differed\n");
560
561     /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
562     strcpy(string, "Dummy string");
563     memset(&info, 0x00, sizeof(info));
564     info.cbSize= sizeof(MENUITEMINFO); 
565     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
566     info.fType= MFT_OWNERDRAW;
567     info.dwTypeData= string; 
568     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
569     ok (rc, "InsertMenuItem failed\n");
570
571     strcpy(string,"Garbage");
572     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
573     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
574
575     SetLastError(0xdeadbeef);
576     ret = GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION);
577     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
578         skip("GetMenuStringW is not implemented\n");
579     else
580     {
581         ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
582         ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
583     }
584
585     /* Just change ftype to string and see what text is stored */
586     memset(&info, 0x00, sizeof(info));
587     info.cbSize= sizeof(MENUITEMINFO); 
588     info.fMask= MIIM_FTYPE; /* Set string type */
589     info.fType= MFT_STRING;
590     info.dwTypeData= (char *)0xdeadbeef; 
591     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
592     ok (rc, "SetMenuItemInfo failed\n");
593
594     /* Did we keep the old dwTypeData? */
595     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
596     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
597
598     /* Ensure change to bitmap type fails */
599     memset(&info, 0x00, sizeof(info));
600     info.cbSize= sizeof(MENUITEMINFO); 
601     info.fMask= MIIM_FTYPE; /* Set as bitmap type */
602     info.fType= MFT_BITMAP;
603     info.dwTypeData= (char *)0xdeadbee2; 
604     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
605     ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
606
607     /* Just change ftype back and ensure data hasn't been freed */
608     info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
609     info.dwTypeData= (char *)0xdeadbee3; 
610     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
611     ok (rc, "SetMenuItemInfo failed\n");
612     
613     /* Did we keep the old dwTypeData? */
614     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
615     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
616
617     /* Just change string value (not type) */
618     memset(&info, 0x00, sizeof(info));
619     info.cbSize= sizeof(MENUITEMINFO); 
620     info.fMask= MIIM_STRING; /* Set typeData */
621     strcpy(string2, "string2");
622     info.dwTypeData= string2; 
623     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
624     ok (rc, "SetMenuItemInfo failed\n");
625
626     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
627     ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
628
629     /*  crashes with wine 0.9.5 */
630     memset(&info, 0x00, sizeof(info));
631     info.cbSize= sizeof(MENUITEMINFO); 
632     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
633     info.fType= MFT_OWNERDRAW;
634     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
635     ok (rc, "InsertMenuItem failed\n");
636     ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
637             "GetMenuString on ownerdraw entry succeeded.\n");
638     SetLastError(0xdeadbeef);
639     ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION);
640     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
641         skip("GetMenuStringW is not implemented\n");
642     else
643         ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
644
645     DestroyMenu( hmenu );
646 }
647
648 /* define building blocks for the menu item info tests */
649 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
650 {
651     if (n <= 0) return 0;
652     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
653     return *str1 - *str2;
654 }
655
656 static  WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
657 {
658     WCHAR *p = dst;
659     while ((*p++ = *src++));
660     return dst;
661 }
662
663
664 #define DMIINFF( i, e, field)\
665     ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
666     "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
667
668 #define DUMPMIINF(s,i,e)\
669 {\
670     DMIINFF( i, e, fMask)\
671     DMIINFF( i, e, fType)\
672     DMIINFF( i, e, fState)\
673     DMIINFF( i, e, wID)\
674     DMIINFF( i, e, hSubMenu)\
675     DMIINFF( i, e, hbmpChecked)\
676     DMIINFF( i, e, hbmpUnchecked)\
677     DMIINFF( i, e, dwItemData)\
678     DMIINFF( i, e, dwTypeData)\
679     DMIINFF( i, e, cch)\
680     if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
681 }    
682
683 /* insert menu item */
684 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
685     eret1)\
686 {\
687     MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
688     HMENU hmenu = CreateMenu();\
689     BOOL ret, stop = FALSE;\
690     SetLastError( 0xdeadbeef);\
691     if(ansi)strcpy( string, init);\
692     else strcpyW( (WCHAR*)string, (WCHAR*)init);\
693     if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
694     else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
695     if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
696     {\
697         skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
698         break;\
699     }\
700     if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
701         stop = TRUE;\
702     } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
703
704
705 /* GetMenuItemInfo + GetMenuString  */
706 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
707     a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
708     expname, eret2, eret3)\
709 {\
710   MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
711   MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
712   MENUITEMINFOA *info2 = &info2A;\
713   MENUITEMINFOA *einfo = &einfoA;\
714   MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
715   if( !stop) {\
716     SetLastError( 0xdeadbeef);\
717     ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
718         GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
719     if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
720     {\
721         skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
722         break;\
723     }\
724     if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
725     else { \
726       ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
727       ret = memcmp( info2, einfo, sizeof einfoA);\
728     /*  ok( ret==0, "Got wrong menu item info data\n");*/\
729       if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
730       if( einfo->dwTypeData == string) {\
731         if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
732             einfo->dwTypeData ? einfo->dwTypeData: "");\
733         else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
734             einfo->dwTypeData ? einfo->dwTypeData: "");\
735         ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
736             GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
737         if( (eret3)){\
738             ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
739         }else\
740             ok( !ret, "GetMenuString should have failed\n");\
741       }\
742     }\
743   }\
744 }
745
746 #define TMII_DONE \
747     RemoveMenu(hmenu, 0, TRUE );\
748     DestroyMenu( hmenu );\
749     DestroyMenu( submenu );\
750 submenu = CreateMenu();\
751 }
752 /* modify menu */
753 #define TMII_MODM( flags, id, data, eret  )\
754 if( !stop) {\
755     SetLastError( 0xdeadbeef);\
756     if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
757     else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
758     if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
759     {\
760         skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
761         break;\
762     }\
763     if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
764     else  ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
765 }
766
767 /* SetMenuItemInfo */
768 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
769     eret1)\
770 if( !stop) {\
771     MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
772     SetLastError( 0xdeadbeef);\
773     if(ansi)strcpy( string, init);\
774     else strcpyW( (WCHAR*)string, (WCHAR*)init);\
775     if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
776     else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
777     if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
778     {\
779         skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
780         break;\
781     }\
782     if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
783         stop = TRUE;\
784     } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
785 }
786
787
788
789 #define OK 1
790 #define ER 0
791
792
793 static void test_menu_iteminfo( void )
794 {
795   int S=sizeof( MENUITEMINFOA);
796   int ansi = TRUE;
797   char txtA[]="wine";
798   char initA[]="XYZ";
799   char emptyA[]="";
800   WCHAR txtW[]={'W','i','n','e',0};
801   WCHAR initW[]={'X','Y','Z',0};
802   WCHAR emptyW[]={0};
803   void *txt, *init, *empty, *string;
804   HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
805   char stringA[0x80];
806   HMENU submenu=CreateMenu();
807
808   do {
809     if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
810     else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
811     trace( "%s string %p hbm %p txt %p\n", ansi ?  "ANSI tests:   " : "Unicode tests:", string, hbm, txt);
812     /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
813     /* (since MFT_STRING is zero, there are four of them) */
814     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
815     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
816         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
817         txt, OK, OK )
818     TMII_DONE
819     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
820     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
821         {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
822         empty, OK, ER )
823     TMII_DONE
824     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
825     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
826         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
827         empty, OK, ER )
828     TMII_DONE
829     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
830     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
831         {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
832         empty, OK, ER )
833     TMII_DONE
834     /* not enough space for name*/
835     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
836     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
837         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
838         empty, OK, OK )
839     TMII_DONE
840     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
841     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
842         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
843         txt, OK, OK )
844     TMII_DONE
845     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
846     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
847         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
848         txt, OK, OK )
849     TMII_DONE
850     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
851     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
852         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
853         empty, OK, ER )
854     TMII_DONE
855     /* cannot combine MIIM_TYPE with some other flags */
856     TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
857     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
858         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
859         empty, OK, OK )
860     TMII_DONE
861     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
862     TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
863         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
864         empty, ER, OK )
865     TMII_DONE
866     TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
867     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
868         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
869         empty, OK, OK )
870     TMII_DONE
871     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
872     TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
873         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
874         empty, ER, OK )
875     TMII_DONE
876     TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
877     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
878         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
879         empty, OK, OK )
880     TMII_DONE
881         /* but succeeds with some others */
882     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
883     TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
884         {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
885         txt, OK, OK )
886     TMII_DONE
887     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
888     TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
889         {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
890         txt, OK, OK )
891     TMII_DONE
892     TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
893     TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
894         {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
895         txt, OK, OK )
896     TMII_DONE
897     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
898     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
899         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
900         txt, OK, OK )
901     TMII_DONE
902     /* to be continued */
903     /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ 
904     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
905     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
906         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
907         txt, OK, OK )
908     TMII_DONE
909     /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ 
910     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
911     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
912         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
913         empty, OK, ER )
914     TMII_DONE
915     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
916     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
917         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
918         empty, OK, ER )
919     TMII_DONE
920     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
921     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
922         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
923         init, OK, ER )
924     TMII_DONE
925     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
926     TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
927         {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
928         init, OK, OK )
929     TMII_DONE
930     /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ 
931     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
932     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
933         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
934         txt, OK, OK )
935     TMII_DONE
936     /* same but retrieve with MIIM_TYPE */ 
937     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
938     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
939         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
940         txt, OK, OK )
941     TMII_DONE
942     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
943     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
944         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
945         empty, OK, ER )
946     TMII_DONE
947     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
948     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
949         {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
950         empty, OK, ER )
951     TMII_DONE
952
953     /* How is that with bitmaps? */ 
954     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
955     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
956         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
957         empty, OK, ER )
958     TMII_DONE
959     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
960     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
961         {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
962         init, OK, ER )
963     TMII_DONE
964         /* MIIM_BITMAP does not like MFT_BITMAP */
965     TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
966     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
967         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
968         init, OK, OK )
969     TMII_DONE
970         /* no problem with OWNERDRAWN */
971     TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
972     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
973         {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
974         init, OK, ER )
975     TMII_DONE
976         /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
977     TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
978     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
979         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
980         empty, OK, OK )
981     TMII_DONE
982
983     /* menu with submenu */
984     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
985     TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
986         {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
987         init, OK, ER )
988     TMII_DONE
989     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
990     TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
991         {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
992         init, OK, ER )
993     TMII_DONE
994     /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
995     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
996     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
997         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
998         empty, OK, ER )
999     TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1000         {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
1001         empty, OK, ER )
1002     TMII_DONE
1003     /* menu with invalid submenu */
1004     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
1005     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1006         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1007         init, OK, ER )
1008     TMII_DONE
1009     /* Separator */
1010     TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
1011     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1012         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1013         empty, OK, ER )
1014     TMII_DONE
1015     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
1016     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1017         {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1018         empty, OK, ER )
1019     TMII_DONE
1020      /* SEPARATOR and STRING go well together */
1021     /* BITMAP and STRING go well together */
1022     TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1023     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1024         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1025         txt, OK, OK )
1026     TMII_DONE
1027      /* BITMAP, SEPARATOR and STRING go well together */
1028     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1029     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1030         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1031         txt, OK, OK )
1032     TMII_DONE
1033      /* last two tests, but use MIIM_TYPE to retrieve info */
1034     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1035     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1036         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1037         txt, OK, OK )
1038     TMII_DONE
1039     TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1040     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1041         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1042         txt, OK, OK )
1043     TMII_DONE
1044     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1045     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1046         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1047         txt, OK, OK )
1048     TMII_DONE
1049      /* same three with MFT_OWNERDRAW */
1050     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1051     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1052         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1053         txt, OK, OK )
1054     TMII_DONE
1055     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1056     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1057         {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1058         txt, OK, OK )
1059     TMII_DONE
1060     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1061     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1062         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1063         txt, OK, OK )
1064     TMII_DONE
1065
1066     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1067     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1068         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1069         txt,  OK, OK )
1070     TMII_DONE
1071     /* test with modifymenu: string is preserved after seting OWNERDRAW */
1072     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1073     TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1074     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1075         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1076         txt,  OK, OK )
1077     TMII_DONE
1078     /* same with bitmap: now the text is cleared */
1079     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1080     TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1081     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1082         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1083         empty,  OK, ER )
1084     TMII_DONE
1085     /* start with bitmap: now setting text clears it (though he flag is raised) */
1086     TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1087     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1088         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1089         empty,  OK, ER )
1090     TMII_MODM( MFT_STRING, 545, txt, OK)
1091     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1092         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1093         txt,  OK, OK )
1094     TMII_DONE
1095     /*repeat with text NULL */
1096     TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1097     TMII_MODM( MFT_STRING, 545, NULL, OK)
1098     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1099         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1100         empty,  OK, ER )
1101     TMII_DONE
1102     /* repeat with text "" */
1103     TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1104     TMII_MODM( MFT_STRING, 545, empty, OK)
1105     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1106         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1107         empty,  OK, ER )
1108     TMII_DONE
1109     /* start with bitmap: set ownerdraw */
1110     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1111     TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1112     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1113         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1114         empty,  OK, ER )
1115     TMII_DONE
1116     /* ask nothing */
1117     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1118     TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1119                 {, S, 0, -9, -9, -9,  0, -9, -9, -9, string, 80, -9, },
1120         init, OK, OK )
1121     TMII_DONE
1122     /* some tests with small cbSize: the hbmpItem is to be ignored */ 
1123     TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1124     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1125         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1126         empty, OK, ER )
1127     TMII_DONE
1128     TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1129     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1130         {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1131         init, OK, ER )
1132     TMII_DONE
1133     TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1134     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1135         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1136         txt, OK, OK )
1137     TMII_DONE
1138     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1139     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1140         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1141         txt, OK, OK )
1142     TMII_DONE
1143     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1144     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1145         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1146         txt, OK, OK )
1147     TMII_DONE
1148     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1149     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1150         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1151         txt, OK, OK )
1152     TMII_DONE
1153     /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus  */
1154     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1155     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1156         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1157         empty, OK, ER )
1158     TMII_DONE
1159     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1160     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1161         {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1162         empty, OK, ER )
1163     TMII_DONE
1164     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1165     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1166         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1167         empty, OK, ER )
1168     TMII_DONE
1169     /* set a string menu to ownerdraw with MIIM_TYPE */
1170     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1171     TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1172     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1173         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1174         txt, OK, OK )
1175     TMII_DONE
1176     /* test with modifymenu add submenu */
1177     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1178     TMII_MODM( MF_POPUP, submenu, txt, OK)
1179     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1180         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1181         txt,  OK, OK )
1182     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1183         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1184         txt,  OK, OK )
1185     TMII_DONE
1186     /* MFT_SEPARATOR bit is kept when the text is added */
1187     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1188     TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1189     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1190         {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1191         txt, OK, OK )
1192     TMII_DONE
1193     /* MFT_SEPARATOR bit is kept when bitmap is added */
1194     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1195     TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1196     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1197         {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1198         init, OK, ER )
1199     TMII_DONE
1200     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1201        Only the low word of the dwTypeData is used.
1202        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1203     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1204     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1205         {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1206         empty, OK, OK )
1207     TMII_DONE
1208     /* Type flags */
1209     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1210     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1211         {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1212         empty, OK, OK )
1213     TMII_DONE
1214     /* State flags */
1215     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1216     TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1217     TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1218         {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1219         empty, OK, OK )
1220     TMII_DONE
1221     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1222     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1223     TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1224     TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1225         {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1226         empty, OK, OK )
1227     TMII_DONE
1228     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1229     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1230     TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1231     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1232         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1233         empty, OK, OK )
1234     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1235         {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1236         empty, OK, OK )
1237     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1238         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1239         empty, OK, OK )
1240     TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1241     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1242         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1243         empty, OK, OK )
1244     TMII_DONE
1245     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1246        Only the low word of the dwTypeData is used.
1247        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1248     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1249     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1250         {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1251         empty, OK, OK )
1252     TMII_DONE
1253     /* Type flags */
1254     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1255     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1256         {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1257         empty, OK, OK )
1258     TMII_DONE
1259     /* State flags */
1260     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1261     TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1262     TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1263         {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1264         empty, OK, OK )
1265     TMII_DONE
1266     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1267     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1268     TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1269     TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1270         {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1271         empty, OK, OK )
1272     TMII_DONE
1273     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1274     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1275     TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1276     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1277         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1278         empty, OK, OK )
1279     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1280         {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1281         empty, OK, OK )
1282     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1283         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1284         empty, OK, OK )
1285     TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1286     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1287         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1288         empty, OK, OK )
1289     TMII_DONE
1290   } while( !(ansi = !ansi) );
1291   DeleteObject( hbm);
1292 }
1293
1294 /* 
1295    The following tests try to confirm the algorithm used to return the menu items
1296    when there is a collision between a menu item and a popup menu
1297  */
1298 static void test_menu_search_bycommand( void )
1299 {
1300     HMENU        hmenu, hmenuSub, hmenuSub2;
1301     MENUITEMINFO info;
1302     BOOL         rc;
1303     UINT         id;
1304     char         strback[0x80];
1305     char         strIn[0x80];
1306     static CHAR menuitem[]  = "MenuItem",
1307                 menuitem2[] = "MenuItem 2";
1308
1309     /* Case 1: Menu containing a menu item */
1310     hmenu = CreateMenu();
1311     
1312     memset( &info, 0, sizeof info );
1313     info.cbSize = sizeof info;
1314     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1315     info.fType = MFT_STRING;
1316     strcpy(strIn, "Case 1 MenuItem");
1317     info.dwTypeData = strIn;
1318     info.wID = (UINT) 0x1234;
1319     
1320     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1321     ok (rc, "Inserting the menuitem failed\n");
1322
1323     id = GetMenuItemID(hmenu, 0);
1324     ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1325
1326     /* Confirm the menuitem was given the id supplied (getting by position) */
1327     memset( &info, 0, sizeof info );
1328     strback[0] = 0x00;
1329     info.cbSize = sizeof(MENUITEMINFO);
1330     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1331     info.dwTypeData = strback;
1332     info.cch = sizeof(strback);
1333
1334     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1335     ok (rc, "Getting the menu items info failed\n");
1336     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1337     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1338
1339     /* Search by id - Should return the item */
1340     memset( &info, 0, sizeof info );
1341     strback[0] = 0x00;
1342     info.cbSize = sizeof(MENUITEMINFO);
1343     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1344     info.dwTypeData = strback;
1345     info.cch = sizeof(strback);
1346     rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1347
1348     ok (rc, "Getting the menu items info failed\n");
1349     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1350     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1351
1352     DestroyMenu( hmenu );
1353
1354     /* Case 2: Menu containing a popup menu */
1355     hmenu = CreateMenu();
1356     hmenuSub = CreateMenu();
1357     
1358     strcpy(strIn, "Case 2 SubMenu");
1359     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1360     ok (rc, "Inserting the popup menu into the main menu failed\n");
1361
1362     id = GetMenuItemID(hmenu, 0);
1363     ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1364
1365     /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1366     memset( &info, 0, sizeof info );
1367     strback[0] = 0x00;
1368     info.cbSize = sizeof(MENUITEMINFO);
1369     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1370     info.dwTypeData = strback;
1371     info.cch = sizeof(strback);
1372     info.wID = 0xdeadbeef;
1373
1374     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1375     ok (rc, "Getting the menu items info failed\n");
1376     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1377     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1378
1379     /* Search by id - returns the popup menu itself */
1380     memset( &info, 0, sizeof info );
1381     strback[0] = 0x00;
1382     info.cbSize = sizeof(MENUITEMINFO);
1383     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1384     info.dwTypeData = strback;
1385     info.cch = sizeof(strback);
1386     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1387
1388     ok (rc, "Getting the menu items info failed\n");
1389     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1390     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1391
1392     /* 
1393         Now add an item after it with the same id
1394      */
1395     memset( &info, 0, sizeof info );
1396     info.cbSize = sizeof info;
1397     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1398     info.fType = MFT_STRING;
1399     strcpy(strIn, "Case 2 MenuItem 1");
1400     info.dwTypeData = strIn;
1401     info.wID = (UINT_PTR) hmenuSub;
1402     rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1403     ok (rc, "Inserting the menuitem failed\n");
1404
1405     /* Search by id - returns the item which follows the popup menu */
1406     memset( &info, 0, sizeof info );
1407     strback[0] = 0x00;
1408     info.cbSize = sizeof(MENUITEMINFO);
1409     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1410     info.dwTypeData = strback;
1411     info.cch = sizeof(strback);
1412     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1413
1414     ok (rc, "Getting the menu items info failed\n");
1415     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1416     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1417
1418     /* 
1419         Now add an item before the popup (with the same id)
1420      */
1421     memset( &info, 0, sizeof info );
1422     info.cbSize = sizeof info;
1423     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1424     info.fType = MFT_STRING;
1425     strcpy(strIn, "Case 2 MenuItem 2");
1426     info.dwTypeData = strIn;
1427     info.wID = (UINT_PTR) hmenuSub;
1428     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1429     ok (rc, "Inserting the menuitem failed\n");
1430
1431     /* Search by id - returns the item which precedes the popup menu */
1432     memset( &info, 0, sizeof info );
1433     strback[0] = 0x00;
1434     info.cbSize = sizeof(MENUITEMINFO);
1435     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1436     info.dwTypeData = strback;
1437     info.cch = sizeof(strback);
1438     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1439
1440     ok (rc, "Getting the menu items info failed\n");
1441     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1442     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1443
1444     DestroyMenu( hmenu );
1445     DestroyMenu( hmenuSub );
1446
1447     /* 
1448         Case 3: Menu containing a popup menu which in turn 
1449            contains 2 items with the same id as the popup itself
1450      */
1451
1452     hmenu = CreateMenu();
1453     hmenuSub = CreateMenu();
1454
1455     memset( &info, 0, sizeof info );
1456     info.cbSize = sizeof info;
1457     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1458     info.fType = MFT_STRING;
1459     info.dwTypeData = menuitem;
1460     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1461
1462     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1463     ok (rc, "Inserting the popup menu into the main menu failed\n");
1464
1465     rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1466     ok (rc, "Inserting the sub menu menuitem failed\n");
1467
1468     memset( &info, 0, sizeof info );
1469     info.cbSize = sizeof info;
1470     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1471     info.fType = MFT_STRING;
1472     info.dwTypeData = menuitem2;
1473     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1474
1475     rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1476     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1477
1478     /* Prove that you can't query the id of a popup directly (By position) */
1479     id = GetMenuItemID(hmenu, 0);
1480     ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1481
1482     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1483     memset( &info, 0, sizeof info );
1484     strback[0] = 0x00;
1485     info.cbSize = sizeof(MENUITEMINFO);
1486     info.fMask = MIIM_STRING | MIIM_ID;
1487     info.dwTypeData = strback;
1488     info.cch = sizeof(strback);
1489
1490     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1491     ok (rc, "Getting the menus info failed\n");
1492     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1493     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1494     DestroyMenu( hmenu );
1495     DestroyMenu( hmenuSub );
1496
1497     /* 
1498         Case 4: Menu containing 2 popup menus, the second
1499            contains 2 items with the same id as the first popup menu
1500      */
1501     hmenu = CreateMenu();
1502     hmenuSub = CreateMenu();
1503     hmenuSub2 = CreateMenu();
1504     
1505     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1506     ok (rc, "Inserting the popup menu into the main menu failed\n");
1507     
1508     rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1509     ok (rc, "Inserting the popup menu into the main menu failed\n");
1510
1511     memset( &info, 0, sizeof info );
1512     info.cbSize = sizeof info;
1513     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1514     info.fType = MFT_STRING;
1515     info.dwTypeData = menuitem;
1516     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1517
1518     rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1519     ok (rc, "Inserting the sub menu menuitem failed\n");
1520
1521     memset( &info, 0, sizeof info );
1522     info.cbSize = sizeof info;
1523     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1524     info.fType = MFT_STRING;
1525     info.dwTypeData = menuitem2;
1526     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1527
1528     rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1529     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1530
1531     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1532     memset( &info, 0, sizeof info );
1533     strback[0] = 0x00;
1534     info.cbSize = sizeof(MENUITEMINFO);
1535     info.fMask = MIIM_STRING | MIIM_ID;
1536     info.dwTypeData = strback;
1537     info.cch = sizeof(strback);
1538
1539     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1540     ok (rc, "Getting the menus info failed\n");
1541     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1542     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1543
1544     memset( &info, 0, sizeof info );
1545     strback[0] = 0x00;
1546     info.cbSize = sizeof(MENUITEMINFO);
1547     info.fMask = MIIM_STRING | MIIM_ID;
1548     info.dwTypeData = strback;
1549     info.cch = sizeof(strback);
1550
1551     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1552     ok (rc, "Getting the menus info failed\n");
1553     ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1554     ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1555
1556     DestroyMenu( hmenu );
1557     DestroyMenu( hmenuSub );
1558     DestroyMenu( hmenuSub2 );
1559
1560
1561     /* 
1562         Case 5: Menu containing a popup menu which in turn
1563            contains an item with a different id than the popup menu.
1564            This tests the fallback to a popup menu ID.
1565      */
1566
1567     hmenu = CreateMenu();
1568     hmenuSub = CreateMenu();
1569
1570     rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1571     ok (rc, "Appending the popup menu to the main menu failed\n");
1572
1573     rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1574     ok (rc, "Appending the item to the popup menu failed\n");
1575
1576     /* Set the ID for hmenuSub */
1577     info.cbSize = sizeof(info);
1578     info.fMask = MIIM_ID;
1579     info.wID = 101;
1580
1581     rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1582     ok(rc, "Setting the ID for the popup menu failed\n");
1583
1584     /* Check if the ID has been set */
1585     info.wID = 0;
1586     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1587     ok(rc, "Getting the ID for the popup menu failed\n");
1588     ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1589
1590     /* Prove getting the item info via ID returns the popup menu */
1591     memset( &info, 0, sizeof(info));
1592     strback[0] = 0x00;
1593     info.cbSize = sizeof(MENUITEMINFO);
1594     info.fMask = MIIM_STRING | MIIM_ID;
1595     info.dwTypeData = strback;
1596     info.cch = sizeof(strback);
1597
1598     rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1599     ok (rc, "Getting the menu info failed\n");
1600     ok (info.wID == 101, "IDs differ\n");
1601     ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1602
1603     /* Also look for the menu item  */
1604     memset( &info, 0, sizeof(info));
1605     strback[0] = 0x00;
1606     info.cbSize = sizeof(MENUITEMINFO);
1607     info.fMask = MIIM_STRING | MIIM_ID;
1608     info.dwTypeData = strback;
1609     info.cch = sizeof(strback);
1610
1611     rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1612     ok (rc, "Getting the menu info failed\n");
1613     ok (info.wID == 102, "IDs differ\n");
1614     ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1615
1616     DestroyMenu(hmenu);
1617     DestroyMenu(hmenuSub);
1618 }
1619
1620 struct menu_item_pair_s {
1621     UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1622                  * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1623                  * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1624     UINT uItem;
1625 };
1626
1627 static struct menu_mouse_tests_s {
1628     DWORD type;
1629     struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1630     WORD wVk[5]; /* keys */
1631     BOOL bMenuVisible;
1632     BOOL _todo_wine;
1633 } menu_tests[] = {
1634     /* for each test, send keys or clicks and check for menu visibility */
1635     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1636     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1637     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1638     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1639     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1640     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1641     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1642     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1643     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1644     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1645     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1646     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1647     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1648     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1649     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1650     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1651     { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1652     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1653
1654     { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1655     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1656     { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1657     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1658     { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1659     { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1660     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1661     { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1662     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1663     { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1664     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1665     { -1 }
1666 };
1667
1668 static void send_key(WORD wVk)
1669 {
1670     TEST_INPUT i[2];
1671     memset(&i, 0, 2*sizeof(INPUT));
1672     i[0].type = i[1].type = INPUT_KEYBOARD;
1673     i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1674     i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1675     SendInput(2, (INPUT *) i, sizeof(INPUT));
1676 }
1677
1678 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1679 {
1680     HMENU hMenu = hMenus[mi->uMenu];
1681     TEST_INPUT i[3];
1682     MSG msg;
1683     RECT r;
1684     int screen_w = GetSystemMetrics(SM_CXSCREEN);
1685     int screen_h = GetSystemMetrics(SM_CYSCREEN);
1686
1687     GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1688
1689     memset(&i, 0, 3*sizeof(INPUT));
1690     i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1691     i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1692             = ((r.left + 5) * 65535) / screen_w;
1693     i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1694             = ((r.top + 5) * 65535) / screen_h;
1695     i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1696             = MOUSEEVENTF_ABSOLUTE;
1697     i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1698     i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1699     i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1700     SendInput(3, (INPUT *) i, sizeof(INPUT));
1701
1702     /* hack to prevent mouse message buildup in Wine */
1703     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1704 }
1705
1706 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1707 {
1708     int i, j;
1709     HANDLE hWnd = lpParameter;
1710
1711     Sleep(500);
1712     /* mixed keyboard/mouse test */
1713     for (i = 0; menu_tests[i].type != -1; i++)
1714     {
1715         int elapsed = 0;
1716
1717         if (menu_tests[i].type == INPUT_KEYBOARD)
1718             for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1719                 send_key(menu_tests[i].wVk[j]);
1720         else
1721             for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1722                 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1723
1724         while (menu_tests[i].bMenuVisible != bMenuVisible)
1725         {
1726             if (elapsed > 200)
1727                 break;
1728             elapsed += 20;
1729             Sleep(20);
1730         }
1731
1732         if (menu_tests[i]._todo_wine)
1733         {
1734             todo_wine {
1735                 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1736             }
1737         }
1738         else
1739             ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1740     }
1741     return 0;
1742 }
1743
1744 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1745         LPARAM lParam)
1746 {
1747     switch (msg) {
1748         case WM_ENTERMENULOOP:
1749             bMenuVisible = TRUE;
1750             break;
1751         case WM_EXITMENULOOP:
1752             bMenuVisible = FALSE;
1753             break;
1754         default:
1755             return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1756     }
1757     return 0;
1758 }
1759
1760 static void test_menu_input(void) {
1761     MSG msg;
1762     WNDCLASSA  wclass;
1763     HINSTANCE hInstance = GetModuleHandleA( NULL );
1764     HANDLE hThread, hWnd;
1765
1766     wclass.lpszClassName = "MenuTestClass";
1767     wclass.style         = CS_HREDRAW | CS_VREDRAW;
1768     wclass.lpfnWndProc   = WndProc;
1769     wclass.hInstance     = hInstance;
1770     wclass.hIcon         = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1771     wclass.hCursor       = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1772     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1773     wclass.lpszMenuName  = 0;
1774     wclass.cbClsExtra    = 0;
1775     wclass.cbWndExtra    = 0;
1776     assert (RegisterClassA( &wclass ));
1777     assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1778                                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1779                                   400, 200, NULL, NULL, hInstance, NULL) );
1780
1781     /* fixed menus */
1782     hMenus[3] = CreatePopupMenu();
1783     AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1784     AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1785
1786     hMenus[2] = CreatePopupMenu();
1787     AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1788     AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1789     AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1790
1791     hMenus[1] = CreateMenu();
1792     AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1793     AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1794     AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1795
1796     SetMenu(hWnd, hMenus[1]);
1797     ShowWindow(hWnd, SW_SHOW);
1798     UpdateWindow(hWnd);
1799
1800     hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1801     while(1)
1802     {
1803         if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1804             break;
1805         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1806     }
1807     DestroyWindow(hWnd);
1808 }
1809
1810 static void test_menu_flags( void )
1811 {
1812     HMENU hMenu, hPopupMenu;
1813
1814     hMenu = CreateMenu();
1815     hPopupMenu = CreatePopupMenu();
1816
1817     AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1818
1819     AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
1820     InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
1821     AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1822     ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
1823
1824     ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1825       "AppendMenu should accept MF_HILITE\n");
1826     ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
1827       "InsertMenu should accept MF_HILITE\n");
1828     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1829       "ModifyMenu should accept MF_HILITE\n");
1830
1831     ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
1832       "AppendMenu must not accept MF_DEFAULT\n");
1833     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
1834       "InsertMenu must not accept MF_DEFAULT\n");
1835     ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
1836       "ModifyMenu must not accept MF_DEFAULT\n");
1837
1838     DestroyMenu(hMenu);
1839 }
1840
1841 static void test_menu_hilitemenuitem( void )
1842 {
1843     HMENU hMenu, hPopupMenu;
1844
1845     hMenu = CreateMenu();
1846     hPopupMenu = CreatePopupMenu();
1847
1848     AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
1849
1850     AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
1851     AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
1852     AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
1853
1854     HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
1855     HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
1856     HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
1857     HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
1858
1859     todo_wine
1860     {
1861     ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
1862       "HiliteMenuItem: Item 1 is not hilited\n");
1863     }
1864     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
1865       "HiliteMenuItem: Item 2 is hilited\n");
1866     todo_wine
1867     {
1868     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
1869       "HiliteMenuItem: Item 3 is not hilited\n");
1870     }
1871
1872     DestroyMenu(hMenu);
1873 }
1874
1875 START_TEST(menu)
1876 {
1877     pSetMenuInfo =
1878         (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "SetMenuInfo" );
1879     pGetMenuInfo =
1880         (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetMenuInfo" );
1881
1882     register_menu_check_class();
1883
1884     test_menu_locked_by_window();
1885     test_menu_ownerdraw();
1886     test_menu_add_string();
1887     test_menu_iteminfo();
1888     test_menu_search_bycommand();
1889     test_menu_bmp_and_string();
1890     test_menu_input();
1891     test_menu_flags();
1892     test_menu_hilitemenuitem();
1893 }