kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / user / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <assert.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32
33 #include "wine/test.h"
34
35 static ATOM atomMenuCheckClass;
36
37 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
38 {
39     switch (msg)
40     {
41     case WM_ENTERMENULOOP:
42         /* mark window as having entered menu loop */
43         SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
44         /* exit menu modal loop
45          * ( A SendMessage does not work on NT3.51 here ) */
46         return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
47     }
48     return DefWindowProc(hwnd, msg, wparam, lparam);
49 }
50
51 /* globals to communicate between test and wndproc */
52 unsigned int MOD_maxid;
53 RECT MOD_rc[4];
54 int MOD_avec, MOD_hic;
55 int MOD_odheight;
56 #define MOD_SIZE 10
57 /* wndproc used by test_menu_ownerdraw() */
58 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
59         WPARAM wparam, LPARAM lparam)
60 {
61     switch (msg)
62     {
63         case WM_MEASUREITEM:
64             {
65                 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
66                 if( winetest_debug)
67                     trace("WM_MEASUREITEM received %d,%d\n",
68                             pmis->itemWidth, pmis->itemHeight);
69                 MOD_odheight = pmis->itemHeight;
70                 pmis->itemWidth = MOD_SIZE;
71                 pmis->itemHeight = MOD_SIZE;
72                 return TRUE;
73             }
74         case WM_DRAWITEM:
75             {
76                 DRAWITEMSTRUCT * pdis;
77                 TEXTMETRIC tm;
78                 HPEN oldpen;
79                 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
80                 SIZE sz;
81                 pdis = (DRAWITEMSTRUCT *) lparam;
82                 if( winetest_debug) {
83                     trace("WM_DRAWITEM received itemdata %ld item %d rc %ld,%ld-%ld,%ld\n",
84                             pdis->itemData,
85                             pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
86                             pdis->rcItem.right,pdis->rcItem.bottom );
87                     oldpen=SelectObject( pdis->hDC, GetStockObject(
88                                 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
89                     Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
90                             pdis->rcItem.right,pdis->rcItem.bottom );
91                     SelectObject( pdis->hDC, oldpen);
92                 }
93                 if( pdis->itemData > MOD_maxid) return TRUE;
94                 /* store the rectangl */
95                 MOD_rc[pdis->itemData] = pdis->rcItem;
96                 /* calculate average character width */
97                 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
98                 MOD_avec = (sz.cx + 26)/52;
99                 GetTextMetrics( pdis->hDC, &tm);
100                 MOD_hic = tm.tmHeight;
101                 if( pdis->itemData == MOD_maxid) PostMessage(hwnd, WM_CANCELMODE, 0, 0);
102                 return TRUE;
103             }
104
105     }
106     return DefWindowProc(hwnd, msg, wparam, lparam);
107 }
108
109 static void register_menu_check_class(void)
110 {
111     WNDCLASS wc =
112     {
113         0,
114         menu_check_wnd_proc,
115         0,
116         0,
117         GetModuleHandle(NULL),
118         NULL,
119         LoadCursor(NULL, IDC_ARROW),
120         (HBRUSH)(COLOR_BTNFACE+1),
121         NULL,
122         TEXT("WineMenuCheck"),
123     };
124     
125     atomMenuCheckClass = RegisterClass(&wc);
126 }
127
128 /* demonstrates that windows lock the menu object so that it is still valid
129  * even after a client calls DestroyMenu on it */
130 static void test_menu_locked_by_window(void)
131 {
132     BOOL ret;
133     HMENU hmenu;
134     HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
135         WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
136         NULL, NULL, NULL, NULL);
137     ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
138     hmenu = CreateMenu();
139     ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
140     ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
141     ok(ret, "InsertMenu failed with error %ld\n", GetLastError());
142     ret = SetMenu(hwnd, hmenu);
143     ok(ret, "SetMenu failed with error %ld\n", GetLastError());
144     ret = DestroyMenu(hmenu);
145     ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
146
147     ret = DrawMenuBar(hwnd);
148     todo_wine {
149     ok(ret, "DrawMenuBar failed with error %ld\n", GetLastError());
150     }
151     ret = IsMenu(GetMenu(hwnd));
152     ok(!ret, "Menu handle should have been destroyed\n");
153
154     SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
155     /* did we process the WM_INITMENU message? */
156     ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
157     todo_wine {
158     ok(ret, "WM_INITMENU should have been sent\n");
159     }
160
161     DestroyWindow(hwnd);
162 }
163
164 static void test_menu_ownerdraw(void)
165 {
166     int i,j,k;
167     BOOL ret;
168     HMENU hmenu;
169     LONG leftcol;
170     HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
171             WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
172             NULL, NULL, NULL, NULL);
173     ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
174     if( !hwnd) return;
175     SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
176     hmenu = CreatePopupMenu();
177     ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
178     if( !hmenu) { DestroyWindow(hwnd);return;}
179     k=0;
180     for( j=0;j<2;j++) /* create columns */
181         for(i=0;i<2;i++) { /* create rows */
182             ret = AppendMenu( hmenu, MF_OWNERDRAW | 
183                     (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
184             k++;
185             ok( ret, "AppendMenu failed for %d\n", k-1);
186         }
187     MOD_maxid = k-1;
188     assert( k <= sizeof(MOD_rc)/sizeof(RECT));
189     /* display the menu */
190     ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
191
192     /* columns have a 4 pixel gap between them */
193     ok( MOD_rc[0].right + 4 ==  MOD_rc[2].left,
194             "item rectangles are not separated by 4 pixels space\n");
195     /* height should be what the MEASUREITEM message has returned */
196     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
197             "menu item has wrong height: %ld should be %d\n",
198             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
199     /* no gaps between the rows */
200     ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
201             "There should not be a space between the rows, gap is %ld\n",
202             MOD_rc[0].bottom - MOD_rc[1].top);
203     /* test the correct value of the item height that was sent
204      * by the WM_MEASUREITEM message */
205     ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
206             MOD_odheight == MOD_hic,                     /* Win95,98,ME */
207             "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
208             HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
209     /* test what MF_MENUBREAK did at the first position. Also show
210      * that an MF_SEPARATOR is ignored in the height calculation. */
211     leftcol= MOD_rc[0].left;
212     ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0); 
213     /* display the menu */
214     ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
215     /* left should be 4 pixels less now */
216     ok( leftcol == MOD_rc[0].left + 4, 
217             "columns should be 4 pixels to the left (actual %ld).\n",
218             leftcol - MOD_rc[0].left);
219     /* test width */
220     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
221             "width of owner drawn menu item is wrong. Got %ld expected %d\n",
222             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
223     /* and height */
224     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
225             "Height is incorrect. Got %ld expected %d\n",
226             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
227
228     /* test width/height of a OD menu bar as well */
229     ret = DestroyMenu(hmenu);
230     ok(ret, "DestroyMenu failed with error %ld\n", GetLastError());
231     hmenu = CreateMenu();
232     ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
233     if( !hmenu) { DestroyWindow(hwnd);return;}
234     MOD_maxid=1;
235     for(i=0;i<2;i++) { 
236         ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
237         ok( ret, "AppendMenu failed for %d\n", i);
238     }
239     SetMenu( hwnd, hmenu);
240     UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
241     ok(ret, "SetMenu failed with error %ld\n", GetLastError());
242     /* test width */
243     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
244             "width of owner drawn menu item is wrong. Got %ld expected %d\n",
245             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
246     /* test hight */
247     ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
248             "Height of owner drawn menu item is wrong. Got %ld expected %d\n",
249             MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
250     /* clean up */
251     DestroyWindow(hwnd);
252 }
253
254 static void test_menu_add_string( void )
255 {
256     HMENU hmenu;
257     MENUITEMINFO info;
258     BOOL rc;
259     
260     char string[0x80];
261     char string2[0x80];
262
263     char strback[0x80];
264     WCHAR strbackW[0x80];
265     static const WCHAR expectedString[] = {'D', 'u', 'm', 'm', 'y', ' ', 
266                          's', 't', 'r', 'i', 'n', 'g', 0};
267
268     hmenu = CreateMenu();
269
270     memset( &info, 0, sizeof info );
271     info.cbSize = sizeof info;
272     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
273     info.dwTypeData = "blah";
274     info.cch = 6;
275     info.dwItemData = 0;
276     info.wID = 1;
277     info.fState = 0;
278     InsertMenuItem(hmenu, 0, TRUE, &info );
279
280     memset( &info, 0, sizeof info );
281     info.cbSize = sizeof info;
282     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
283     info.dwTypeData = string;
284     info.cch = sizeof string;
285     string[0] = 0;
286     GetMenuItemInfo( hmenu, 0, TRUE, &info );
287
288     ok( !strcmp( string, "blah" ), "menu item name differed\n");
289
290     /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
291     strcpy(string, "Dummy string");
292     memset(&info, 0x00, sizeof(info));
293     info.cbSize= sizeof(MENUITEMINFO); 
294     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
295     info.fType= MFT_OWNERDRAW;
296     info.dwTypeData= string; 
297     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
298     ok (rc, "InsertMenuItem failed\n");
299
300     strcpy(string,"Garbage");
301     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
302     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
303
304     ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
305     ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
306
307     /* Just change ftype to string and see what text is stored */
308     memset(&info, 0x00, sizeof(info));
309     info.cbSize= sizeof(MENUITEMINFO); 
310     info.fMask= MIIM_FTYPE; /* Set string type */
311     info.fType= MFT_STRING;
312     info.dwTypeData= (char *)0xdeadbeef; 
313     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
314     ok (rc, "SetMenuItemInfo failed\n");
315
316     /* Did we keep the old dwTypeData? */
317     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
318     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
319
320     /* Ensure change to bitmap type fails */
321     memset(&info, 0x00, sizeof(info));
322     info.cbSize= sizeof(MENUITEMINFO); 
323     info.fMask= MIIM_FTYPE; /* Set as bitmap type */
324     info.fType= MFT_BITMAP;
325     info.dwTypeData= (char *)0xdeadbee2; 
326     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
327     ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
328
329     /* Just change ftype back and ensure data hasnt been freed */
330     info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
331     info.dwTypeData= (char *)0xdeadbee3; 
332     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
333     ok (rc, "SetMenuItemInfo failed\n");
334     
335     /* Did we keep the old dwTypeData? */
336     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
337     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
338
339     /* Just change string value (not type) */
340     memset(&info, 0x00, sizeof(info));
341     info.cbSize= sizeof(MENUITEMINFO); 
342     info.fMask= MIIM_STRING; /* Set typeData */
343     strcpy(string2, "string2");
344     info.dwTypeData= string2; 
345     rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
346     ok (rc, "SetMenuItemInfo failed\n");
347
348     ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
349     ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
350
351     /*  crashes with wine 0.9.5 */
352     memset(&info, 0x00, sizeof(info));
353     info.cbSize= sizeof(MENUITEMINFO); 
354     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
355     info.fType= MFT_OWNERDRAW;
356     rc = InsertMenuItem( hmenu, 0, TRUE, &info );
357     ok (rc, "InsertMenuItem failed\n");
358     ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
359             "GetMenuString on ownerdraw entry succeeded.\n");
360     ok (!GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION),
361             "GetMenuStringW on ownerdraw entry succeeded.\n");
362
363
364     DestroyMenu( hmenu );
365 }
366
367 /* define building blocks for the menu item info tests */
368 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
369 {
370     if (n <= 0) return 0;
371     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
372     return *str1 - *str2;
373 }
374
375 static  WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
376 {
377     WCHAR *p = dst;
378     while ((*p++ = *src++));
379     return dst;
380 }
381
382
383 #define DMIINFF( i, e, field)\
384     ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
385     "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
386
387 #define DUMPMIINF(s,i,e)\
388 {\
389     DMIINFF( i, e, fMask)\
390     DMIINFF( i, e, fType)\
391     DMIINFF( i, e, fState)\
392     DMIINFF( i, e, wID)\
393     DMIINFF( i, e, hSubMenu)\
394     DMIINFF( i, e, hbmpChecked)\
395     DMIINFF( i, e, hbmpUnchecked)\
396     DMIINFF( i, e, dwItemData)\
397     DMIINFF( i, e, dwTypeData)\
398     DMIINFF( i, e, cch)\
399     if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
400 }    
401
402 /* insert menu item */
403 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
404     eret1)\
405 {\
406     MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
407     HMENU hmenu = CreateMenu();\
408     BOOL ret, stop = FALSE;\
409     SetLastError( 0xdeadbeef);\
410     if(ansi)strcpy( string, init);\
411     else strcpyW( (WCHAR*)string, (WCHAR*)init);\
412     if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
413     else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
414     if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
415         stop = TRUE;\
416     } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
417
418
419 /* GetMenuItemInfo + GetMenuString  */
420 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
421     a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
422     expname, eret2, eret3)\
423 {\
424   MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
425   MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
426   MENUITEMINFOA *info2 = &info2A;\
427   MENUITEMINFOA *einfo = &einfoA;\
428   MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
429   if( !stop) {\
430     ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
431         GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
432     if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
433     else { \
434       ok( (eret2)==ret,"GetMenuItemInfo failed, err %ld\n",GetLastError());\
435       ret = memcmp( info2, einfo, sizeof einfoA);\
436     /*  ok( ret==0, "Got wrong menu item info data\n");*/\
437       if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
438       if( einfo->dwTypeData == string) {\
439         if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
440             einfo->dwTypeData ? einfo->dwTypeData: "");\
441         else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
442             einfo->dwTypeData ? einfo->dwTypeData: "");\
443         ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
444             GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
445         if( (eret3)){\
446             ok( ret, "GetMenuString failed, err %ld\n",GetLastError());\
447         }else\
448             ok( !ret, "GetMenuString should have failed\n");\
449       }\
450     }\
451   }\
452 }
453
454 #define TMII_DONE \
455     RemoveMenu(hmenu, 0, TRUE );\
456     DestroyMenu( hmenu );\
457     DestroyMenu( submenu );\
458 submenu = CreateMenu();\
459 }
460 /* modify menu */
461 #define TMII_MODM( flags, id, data, eret  )\
462 if( !stop) {\
463     if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
464     else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
465     if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
466     else  ok( (eret)==ret,"ModifyMenuA failed, err %ld\n",GetLastError());\
467 }
468
469 /* SetMenuItemInfo */
470 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
471     eret1)\
472 if( !stop) {\
473     MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
474     SetLastError( 0xdeadbeef);\
475     if(ansi)strcpy( string, init);\
476     else strcpyW( (WCHAR*)string, (WCHAR*)init);\
477     if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
478     else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
479     if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
480         stop = TRUE;\
481     } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
482 }
483
484
485
486 #define OK 1
487 #define ER 0
488
489
490 static void test_menu_iteminfo(  )
491 {
492   int S=sizeof( MENUITEMINFOA);
493   int ansi = TRUE;
494   char txtA[]="wine";
495   char initA[]="XYZ";
496   char emptyA[]="";
497   WCHAR txtW[]={'W','i','n','e',0};
498   WCHAR initW[]={'X','Y','Z',0};
499   WCHAR emptyW[]={0};
500   void *txt, *init, *empty, *string;
501   HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
502   char stringA[0x80];
503   HMENU submenu=CreateMenu();
504
505   do {
506     if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
507     else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
508     trace( "%s string %p hbm %p txt %p\n", ansi ?  "ANSI tests:   " : "Unicode tests:", string, hbm, txt);
509     /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
510     /* (since MFT_STRING is zero, there are four of them) */
511     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
512     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
513         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
514         txt, OK, OK )
515     TMII_DONE
516     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
517     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
518         {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
519         empty, OK, ER )
520     TMII_DONE
521     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
522     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
523         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
524         empty, OK, ER )
525     TMII_DONE
526     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
527     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
528         {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
529         empty, OK, ER )
530     TMII_DONE
531     /* not enough space for name*/
532     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
533     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
534         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
535         empty, OK, OK )
536     TMII_DONE
537     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
538     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
539         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
540         txt, OK, OK )
541     TMII_DONE
542     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
543     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
544         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
545         txt, OK, OK )
546     TMII_DONE
547     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
548     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
549         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
550         empty, OK, ER )
551     TMII_DONE
552     /* can not combine MIIM_TYPE with some other flags */
553     TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
554     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
555         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
556         empty, OK, OK )
557     TMII_DONE
558     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
559     TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
560         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
561         empty, ER, OK )
562     TMII_DONE
563     TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
564     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
565         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
566         empty, OK, OK )
567     TMII_DONE
568     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
569     TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
570         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
571         empty, ER, OK )
572     TMII_DONE
573     TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
574     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
575         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
576         empty, OK, OK )
577     TMII_DONE
578         /* but succeeds with some others */
579     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
580     TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
581         {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
582         txt, OK, OK )
583     TMII_DONE
584     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
585     TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
586         {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
587         txt, OK, OK )
588     TMII_DONE
589     TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
590     TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
591         {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
592         txt, OK, OK )
593     TMII_DONE
594     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
595     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
596         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
597         txt, OK, OK )
598     TMII_DONE
599     /* to be continued */
600     /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ 
601     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
602     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
603         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
604         txt, OK, OK )
605     TMII_DONE
606     /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ 
607     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
608     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
609         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
610         empty, OK, ER )
611     TMII_DONE
612     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
613     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
614         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
615         empty, OK, ER )
616     TMII_DONE
617     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
618     TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
619         {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
620         init, OK, ER )
621     TMII_DONE
622     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
623     TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
624         {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
625         init, OK, OK )
626     TMII_DONE
627     /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ 
628     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
629     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
630         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
631         txt, OK, OK )
632     TMII_DONE
633     /* same but retrieve with MIIM_TYPE */ 
634     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
635     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
636         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
637         txt, OK, OK )
638     TMII_DONE
639     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
640     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
641         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
642         empty, OK, ER )
643     TMII_DONE
644     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
645     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
646         {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
647         empty, OK, ER )
648     TMII_DONE
649
650     /* How is that with bitmaps? */ 
651     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
652     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
653         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
654         empty, OK, ER )
655     TMII_DONE
656     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
657     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
658         {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
659         init, OK, ER )
660     TMII_DONE
661         /* MIIM_BITMAP does not like MFT_BITMAP */
662     TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
663     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
664         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
665         init, OK, OK )
666     TMII_DONE
667         /* no problem with OWNERDRAWN */
668     TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
669     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
670         {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
671         init, OK, ER )
672     TMII_DONE
673         /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
674     TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
675     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
676         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
677         empty, OK, OK )
678     TMII_DONE
679
680     /* menu with submenu */
681     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
682     TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
683         {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
684         init, OK, ER )
685     TMII_DONE
686     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
687     TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
688         {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
689         init, OK, ER )
690     TMII_DONE
691     /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
692     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
693     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
694         {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
695         empty, OK, ER )
696     TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
697         {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
698         empty, OK, ER )
699     TMII_DONE
700     /* menu with invalid submenu */
701     TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
702     TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
703         {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
704         init, OK, ER )
705     TMII_DONE
706  
707     TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
708     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
709         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
710         empty, OK, ER )
711     TMII_DONE
712     TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
713     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
714         {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
715         empty, OK, ER )
716     TMII_DONE
717      /* SEPARATOR and STRING go well together */
718     /* BITMAP and STRING go well together */
719     TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
720     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
721         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
722         txt, OK, OK )
723     TMII_DONE
724      /* BITMAP, SEPARATOR and STRING go well together */
725     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
726     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
727         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
728         txt, OK, OK )
729     TMII_DONE
730      /* last two tests, but use MIIM_TYPE to retrieve info */
731     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
732     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
733         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
734         txt, OK, OK )
735     TMII_DONE
736     TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
737     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
738         {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
739         txt, OK, OK )
740     TMII_DONE
741     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
742     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
743         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
744         txt, OK, OK )
745     TMII_DONE
746      /* same three with MFT_OWNERDRAW */
747     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
748     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
749         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
750         txt, OK, OK )
751     TMII_DONE
752     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
753     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
754         {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
755         txt, OK, OK )
756     TMII_DONE
757     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
758     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
759         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
760         txt, OK, OK )
761     TMII_DONE
762
763     TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
764     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
765         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
766         txt,  OK, OK )
767     TMII_DONE
768     /* test with modifymenu: string is preserved after seting OWNERDRAW */
769     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
770     TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
771     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
772         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
773         txt,  OK, OK )
774     TMII_DONE
775     /* same with bitmap: now the text is cleared */
776     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
777     TMII_MODM( MFT_BITMAP, 545, hbm, OK)
778     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
779         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
780         empty,  OK, ER )
781     TMII_DONE
782     /* start with bitmap: now setting text clears it (though he flag is raised) */
783     TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
784     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
785         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
786         empty,  OK, ER )
787     TMII_MODM( MFT_STRING, 545, txt, OK)
788     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
789         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
790         txt,  OK, OK )
791     TMII_DONE
792     /*repeat with text NULL */
793     TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
794     TMII_MODM( MFT_STRING, 545, NULL, OK)
795     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
796         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
797         empty,  OK, ER )
798     TMII_DONE
799     /* repeat with text "" */
800     TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
801     TMII_MODM( MFT_STRING, 545, empty, OK)
802     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
803         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
804         empty,  OK, ER )
805     TMII_DONE
806     /* start with bitmap: set ownerdraw */
807     TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
808     TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
809     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
810         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
811         empty,  OK, ER )
812     TMII_DONE
813     /* ask nothing */
814     TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
815     TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
816                 {, S, 0, -9, -9, -9,  0, -9, -9, -9, string, 80, -9, },
817         init, OK, OK )
818     TMII_DONE
819     /* some tests with small cbSize: the hbmpItem is to be ignored */ 
820     TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
821     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
822         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
823         empty, OK, ER )
824     TMII_DONE
825     TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
826     TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
827         {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
828         init, OK, ER )
829     TMII_DONE
830     TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
831     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
832         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
833         txt, OK, OK )
834     TMII_DONE
835     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
836     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
837         {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
838         txt, OK, OK )
839     TMII_DONE
840     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
841     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
842         {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
843         txt, OK, OK )
844     TMII_DONE
845     TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
846     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
847         {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
848         txt, OK, OK )
849     TMII_DONE
850     /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus  */
851     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
852     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
853         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
854         empty, OK, ER )
855     TMII_DONE
856     TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
857     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
858         {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
859         empty, OK, ER )
860     TMII_DONE
861     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
862     TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
863         {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
864         empty, OK, ER )
865     TMII_DONE
866     /* set a string menu to ownerdraw with MIIM_TYPE */
867     TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
868     TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
869     TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
870         {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
871         txt, OK, OK )
872     TMII_DONE
873     /* test with modifymenu add submenu */
874     TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
875     TMII_MODM( MF_POPUP, submenu, txt, OK)
876     TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
877         {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
878         txt,  OK, OK )
879     TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
880         {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
881         txt,  OK, OK )
882     TMII_DONE
883
884     ansi = !ansi;
885   } while( !ansi);
886   DeleteObject( hbm);
887 }
888
889 /* 
890    The following tests try to confirm the algorithum used to return the menu items 
891    when there is a collision between a menu item and a popup menu
892  */
893 void test_menu_search_bycommand( void )
894 {
895     HMENU        hmenu, hmenuSub, hmenuSub2;
896     MENUITEMINFO info;
897     BOOL         rc;
898     UINT         id;
899     char         strback[0x80];
900     char         strIn[0x80];
901
902     /* Case 1: Menu containing a menu item */
903     hmenu = CreateMenu();
904     
905     memset( &info, 0, sizeof info );
906     info.cbSize = sizeof info;
907     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
908     info.fType = MFT_STRING;
909     strcpy(strIn, "Case 1 MenuItem");
910     info.dwTypeData = strIn;
911     info.wID = (UINT) 0x1234;
912     
913     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
914     ok (rc, "Inserting the menuitem failed\n");
915
916     id = GetMenuItemID(hmenu, 0);
917     ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
918
919     /* Confirm the menuitem was given the id supplied (getting by position) */
920     memset( &info, 0, sizeof info );
921     strback[0] = 0x00;
922     info.cbSize = sizeof(MENUITEMINFO);
923     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
924     info.dwTypeData = strback;
925     info.cch = sizeof(strback);
926
927     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
928     ok (rc, "Getting the menu items info failed\n");
929     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
930     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
931
932     /* Search by id - Should return the item */
933     memset( &info, 0, sizeof info );
934     strback[0] = 0x00;
935     info.cbSize = sizeof(MENUITEMINFO);
936     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
937     info.dwTypeData = strback;
938     info.cch = sizeof(strback);
939     rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
940
941     ok (rc, "Getting the menu items info failed\n");
942     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
943     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
944
945     DestroyMenu( hmenu );
946
947     /* Case 2: Menu containing a popup menu */
948     hmenu = CreateMenu();
949     hmenuSub = CreateMenu();
950     
951     strcpy(strIn, "Case 2 SubMenu");
952     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
953     ok (rc, "Inserting the popup menu into the main menu failed\n");
954
955     id = GetMenuItemID(hmenu, 0);
956     ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
957
958     /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
959     memset( &info, 0, sizeof info );
960     strback[0] = 0x00;
961     info.cbSize = sizeof(MENUITEMINFO);
962     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
963     info.dwTypeData = strback;
964     info.cch = sizeof(strback);
965     info.wID = 0xdeadbeef;
966
967     rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
968     ok (rc, "Getting the menu items info failed\n");
969     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
970     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
971
972     /* Search by id - returns the popup menu itself */
973     memset( &info, 0, sizeof info );
974     strback[0] = 0x00;
975     info.cbSize = sizeof(MENUITEMINFO);
976     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
977     info.dwTypeData = strback;
978     info.cch = sizeof(strback);
979     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
980
981     ok (rc, "Getting the menu items info failed\n");
982     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
983     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
984
985     /* 
986         Now add an item after it with the same id
987      */
988     memset( &info, 0, sizeof info );
989     info.cbSize = sizeof info;
990     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
991     info.fType = MFT_STRING;
992     strcpy(strIn, "Case 2 MenuItem 1");
993     info.dwTypeData = strIn;
994     info.wID = (UINT_PTR) hmenuSub;
995     rc = InsertMenuItem(hmenu, -1, TRUE, &info );
996     ok (rc, "Inserting the menuitem failed\n");
997
998     /* Search by id - returns the item which follows the popup menu */
999     memset( &info, 0, sizeof info );
1000     strback[0] = 0x00;
1001     info.cbSize = sizeof(MENUITEMINFO);
1002     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1003     info.dwTypeData = strback;
1004     info.cch = sizeof(strback);
1005     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1006
1007     ok (rc, "Getting the menu items info failed\n");
1008     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1009     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1010
1011     /* 
1012         Now add an item before the popup (with the same id)
1013      */
1014     memset( &info, 0, sizeof info );
1015     info.cbSize = sizeof info;
1016     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1017     info.fType = MFT_STRING;
1018     strcpy(strIn, "Case 2 MenuItem 2");
1019     info.dwTypeData = strIn;
1020     info.wID = (UINT_PTR) hmenuSub;
1021     rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1022     ok (rc, "Inserting the menuitem failed\n");
1023
1024     /* Search by id - returns the item which preceeds the popup menu */
1025     memset( &info, 0, sizeof info );
1026     strback[0] = 0x00;
1027     info.cbSize = sizeof(MENUITEMINFO);
1028     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1029     info.dwTypeData = strback;
1030     info.cch = sizeof(strback);
1031     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1032
1033     ok (rc, "Getting the menu items info failed\n");
1034     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1035     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1036
1037     DestroyMenu( hmenu );
1038     DestroyMenu( hmenuSub );
1039
1040     /* 
1041         Case 3: Menu containing a popup menu which in turn 
1042            contains 2 items with the same id as the popup itself
1043      */
1044              
1045     hmenu = CreateMenu();
1046     hmenuSub = CreateMenu();
1047     
1048     memset( &info, 0, sizeof info );
1049     info.cbSize = sizeof info;
1050     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1051     info.fType = MFT_STRING;
1052     info.dwTypeData = "MenuItem";
1053     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1054
1055     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1056     ok (rc, "Inserting the popup menu into the main menu failed\n");
1057
1058     rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1059     ok (rc, "Inserting the sub menu menuitem failed\n");
1060
1061     memset( &info, 0, sizeof info );
1062     info.cbSize = sizeof info;
1063     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1064     info.fType = MFT_STRING;
1065     info.dwTypeData = "MenuItem 2";
1066     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1067     
1068     rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1069     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1070
1071     /* Prove that you cant query the id of a popup directly (By position) */
1072     id = GetMenuItemID(hmenu, 0);
1073     ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1074
1075     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1076     memset( &info, 0, sizeof info );
1077     strback[0] = 0x00;
1078     info.cbSize = sizeof(MENUITEMINFO);
1079     info.fMask = MIIM_STRING | MIIM_ID;
1080     info.dwTypeData = strback;
1081     info.cch = sizeof(strback);
1082
1083     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1084     ok (rc, "Getting the menus info failed\n");
1085     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1086     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1087     DestroyMenu( hmenu );
1088     DestroyMenu( hmenuSub );
1089
1090     /* 
1091         Case 4: Menu containing 2 popup menus, the second
1092            contains 2 items with the same id as the first popup menu
1093      */
1094     hmenu = CreateMenu();
1095     hmenuSub = CreateMenu();
1096     hmenuSub2 = CreateMenu();
1097     
1098     rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1099     ok (rc, "Inserting the popup menu into the main menu failed\n");
1100     
1101     rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1102     ok (rc, "Inserting the popup menu into the main menu failed\n");
1103
1104     memset( &info, 0, sizeof info );
1105     info.cbSize = sizeof info;
1106     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1107     info.fType = MFT_STRING;
1108     info.dwTypeData = "MenuItem";
1109     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1110    
1111     rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1112     ok (rc, "Inserting the sub menu menuitem failed\n");
1113
1114     memset( &info, 0, sizeof info );
1115     info.cbSize = sizeof info;
1116     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1117     info.fType = MFT_STRING;
1118     info.dwTypeData = "MenuItem 2";
1119     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1120     
1121     rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1122     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1123
1124     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1125     memset( &info, 0, sizeof info );
1126     strback[0] = 0x00;
1127     info.cbSize = sizeof(MENUITEMINFO);
1128     info.fMask = MIIM_STRING | MIIM_ID;
1129     info.dwTypeData = strback;
1130     info.cch = sizeof(strback);
1131
1132     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1133     ok (rc, "Getting the menus info failed\n");
1134     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1135     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1136
1137     memset( &info, 0, sizeof info );
1138     strback[0] = 0x00;
1139     info.cbSize = sizeof(MENUITEMINFO);
1140     info.fMask = MIIM_STRING | MIIM_ID;
1141     info.dwTypeData = strback;
1142     info.cch = sizeof(strback);
1143
1144     rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1145     ok (rc, "Getting the menus info failed\n");
1146     ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1147     ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1148 }
1149
1150 START_TEST(menu)
1151 {
1152     register_menu_check_class();
1153
1154     test_menu_locked_by_window();
1155     test_menu_ownerdraw();
1156     test_menu_add_string();
1157     test_menu_iteminfo();
1158     test_menu_search_bycommand();
1159 }