1 /*
2  * Unit tests for menus
3  *
4  * Copyright 2005 Robert Shearman
5  * Copyright 2007 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #ifndef __REACTOS__
23 #define _WIN32_WINNT 0x0501
24 #endif
25 
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #define OEMRESOURCE         /* For OBM_MNARROW */
32 
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 
38 #include "wine/test.h"
39 
40 static ATOM atomMenuCheckClass;
41 
42 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
43 {
44     switch (msg)
45     {
46     case WM_ENTERMENULOOP:
47         /* mark window as having entered menu loop */
48         SetWindowLongPtrA(hwnd, GWLP_USERDATA, TRUE);
49         /* exit menu modal loop
50          * ( A SendMessage does not work on NT3.51 here ) */
51         return PostMessageA(hwnd, WM_CANCELMODE, 0, 0);
52     }
53     return DefWindowProcA(hwnd, msg, wparam, lparam);
54 }
55 
56 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
57  * our own type */
58 typedef struct
59 {
60     DWORD type;
61     union
62     {
63         MOUSEINPUT      mi;
64         KEYBDINPUT      ki;
65         HARDWAREINPUT   hi;
66     } u;
67 } TEST_INPUT;
68 
69 /* globals to communicate between test and wndproc */
70 
71 static BOOL bMenuVisible;
72 static INT popmenu;
73 static BOOL got_input;
74 static HMENU hMenus[4];
75 
76 #define MOD_SIZE 10
77 #define MOD_NRMENUS 8
78 
79  /* menu texts with their sizes */
80 static struct {
81     LPCSTR text;
82     SIZE size; /* size of text up to any \t */
83     SIZE sc_size; /* size of the short-cut */
84 } MOD_txtsizes[] = {
85         { "Pinot &Noir" },
86         { "&Merlot\bF4" },
87         { "Shira&z\tAlt+S" },
88         { "" },
89         { NULL }
90 };
91 
92 static unsigned int MOD_maxid;
93 static RECT MOD_rc[MOD_NRMENUS];
94 static int MOD_avec, MOD_hic;
95 static int MOD_odheight;
96 static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
97     {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
98 static BOOL MOD_GotDrawItemMsg = FALSE;
99 static int  gflag_initmenupopup,
100             gflag_entermenuloop,
101             gflag_initmenu,
102             gflag_enteridle;
103 static WPARAM selectitem_wp;
104 static LPARAM selectitem_lp;
105 
106 /* wndproc used by test_menu_ownerdraw() */
107 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
108         WPARAM wparam, LPARAM lparam)
109 {
110     static HMENU hmenupopup;
111     switch (msg)
112     {
113         case WM_INITMENUPOPUP:
114             gflag_initmenupopup++;
115             hmenupopup = (HMENU) wparam;
116             break;
117         case WM_ENTERMENULOOP:
118             gflag_entermenuloop++;
119             break;
120         case WM_INITMENU:
121             gflag_initmenu++;
122             break;
123         case WM_MEASUREITEM:
124             {
125                 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
126                 if (winetest_debug > 1)
127                     trace("WM_MEASUREITEM received data %lx size %dx%d\n",
128                             pmis->itemData, pmis->itemWidth, pmis->itemHeight);
129                 ok( !wparam, "wrong wparam %lx\n", wparam );
130                 ok( pmis->CtlType == ODT_MENU, "wrong type %x\n", pmis->CtlType );
131                 MOD_odheight = pmis->itemHeight;
132                 pmis->itemWidth = MODsizes[pmis->itemData].cx;
133                 pmis->itemHeight = MODsizes[pmis->itemData].cy;
134                 return TRUE;
135             }
136         case WM_DRAWITEM:
137             {
138                 DRAWITEMSTRUCT * pdis;
139                 TEXTMETRICA tm;
140                 HPEN oldpen;
141                 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
142                 SIZE sz;
143                 int i;
144                 pdis = (DRAWITEMSTRUCT *) lparam;
145                 if (winetest_debug > 1) {
146                     RECT rc;
147                     GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
148                     trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %s itemrc:  %s\n",
149                             hwnd, pdis->hwndItem, pdis->itemData, pdis->itemID,
150                             wine_dbgstr_rect(&pdis->rcItem), wine_dbgstr_rect(&rc));
151                     oldpen=SelectObject( pdis->hDC, GetStockObject(
152                                 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
153                     Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
154                             pdis->rcItem.right,pdis->rcItem.bottom );
155                     SelectObject( pdis->hDC, oldpen);
156                 }
157                 ok( !wparam, "wrong wparam %lx\n", wparam );
158                 ok( pdis->CtlType == ODT_MENU, "wrong type %x\n", pdis->CtlType );
159                 /* calculate widths of some menu texts */
160                 if( ! MOD_txtsizes[0].size.cx)
161                     for(i = 0; MOD_txtsizes[i].text; i++) {
162                         char buf[100], *p;
163                         RECT rc={0,0,0,0};
164                         strcpy( buf, MOD_txtsizes[i].text);
165                         if( ( p = strchr( buf, '\t'))) {
166                             *p = '\0';
167                             DrawTextA( pdis->hDC, p + 1, -1, &rc,
168                                     DT_SINGLELINE|DT_CALCRECT);
169                             MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
170                             MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
171                         }
172                         DrawTextA( pdis->hDC, buf, -1, &rc,
173                                 DT_SINGLELINE|DT_CALCRECT);
174                         MOD_txtsizes[i].size.cx= rc.right - rc.left;
175                         MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
176                     }
177 
178                 if( pdis->itemData > MOD_maxid) return TRUE;
179                 /* store the rectangle */
180                 MOD_rc[pdis->itemData] = pdis->rcItem;
181                 /* calculate average character width */
182                 GetTextExtentPointA( pdis->hDC, chrs, 52, &sz );
183                 MOD_avec = (sz.cx + 26)/52;
184                 GetTextMetricsA( pdis->hDC, &tm);
185                 MOD_hic = tm.tmHeight;
186                 MOD_GotDrawItemMsg = TRUE;
187                 return TRUE;
188             }
189         case WM_ENTERIDLE:
190             {
191                 gflag_enteridle++;
192                 ok( lparam || broken(!lparam), /* win9x, nt4 */
193                     "Menu window handle is NULL!\n");
194                 if( lparam) {
195                     HMENU hmenu = (HMENU)SendMessageA( (HWND)lparam, MN_GETHMENU, 0, 0);
196                     ok( hmenupopup == hmenu, "MN_GETHMENU returns %p expected %p\n",
197                         hmenu, hmenupopup);
198                 }
199                 PostMessageA(hwnd, WM_CANCELMODE, 0, 0);
200                 return TRUE;
201             }
202         case WM_MENUSELECT:
203             selectitem_wp = wparam;
204             selectitem_lp = lparam;
205             break;
206     }
207     return DefWindowProcA(hwnd, msg, wparam, lparam);
208 }
209 
210 static void register_menu_check_class(void)
211 {
212     WNDCLASSA wc =
213     {
214         0,
215         menu_check_wnd_proc,
216         0,
217         0,
218         GetModuleHandleA(NULL),
219         NULL,
220         LoadCursorA(NULL, (LPCSTR)IDC_ARROW),
221         (HBRUSH)(COLOR_BTNFACE+1),
222         NULL,
223         "WineMenuCheck",
224     };
225 
226     atomMenuCheckClass = RegisterClassA(&wc);
227 }
228 
229 static void test_getmenubarinfo(void)
230 {
231     BOOL ret;
232     HMENU hmenu;
233     MENUBARINFO mbi;
234     RECT rcw, rci;
235     HWND hwnd;
236     INT err;
237 
238     mbi.cbSize = sizeof(MENUBARINFO);
239 
240     hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
241             WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
242             NULL, NULL, NULL, NULL);
243     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
244 
245     /* no menu: getmenubarinfo should fail */
246     SetLastError(0xdeadbeef);
247     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
248     err = GetLastError();
249     ok(ret == FALSE, "GetMenuBarInfo should not have been successful\n");
250     ok(err == 0xdeadbeef, "err = %d\n", err);
251 
252     /* create menubar, no items yet */
253     hmenu = CreateMenu();
254     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
255 
256     ret = SetMenu(hwnd, hmenu);
257     ok(ret, "SetMenu failed with error %d\n", GetLastError());
258 
259     SetLastError(0xdeadbeef);
260     ret = GetMenuBarInfo(NULL, OBJID_CLIENT, 0, &mbi);
261     err = GetLastError();
262     ok(!ret, "GetMenuBarInfo succeeded\n");
263     ok(err == ERROR_INVALID_WINDOW_HANDLE, "err = %d\n", err);
264 
265     SetLastError(0xdeadbeef);
266     ret = GetMenuBarInfo(hwnd, OBJID_CLIENT, 0, &mbi);
267     err = GetLastError();
268     ok(!ret, "GetMenuBarInfo succeeded\n");
269     ok(err==ERROR_INVALID_MENU_HANDLE || broken(err==0xdeadbeef) /* NT, W2K, XP */, "err = %d\n", err);
270 
271     SetLastError(0xdeadbeef);
272     ret = GetMenuBarInfo(hwnd, OBJID_MENU, -1, &mbi);
273     err = GetLastError();
274     ok(ret == FALSE, "GetMenuBarInfo should have failed\n");
275     ok(err == 0xdeadbeef, "err = %d\n", err);
276 
277     mbi.cbSize = 1000;
278     SetLastError(0xdeadbeef);
279     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
280     err = GetLastError();
281     ok(ret == FALSE, "GetMenuBarInfo should have failed\n");
282     ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
283     mbi.cbSize = sizeof(MENUBARINFO);
284 
285     SetLastError(0xdeadbeef);
286     ret = GetMenuBarInfo(hwnd, 123, 0, &mbi);
287     err = GetLastError();
288     ok(ret == FALSE, "GetMenuBarInfo should have failed\n");
289     ok(err == 0xdeadbeef, "err = %d\n", err);
290 
291     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
292     ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError());
293 
294     ok(mbi.rcBar.left == 0 && mbi.rcBar.top == 0 && mbi.rcBar.bottom == 0 && mbi.rcBar.right == 0,
295             "rcBar: Expected (0,0)-(0,0), got: %s\n", wine_dbgstr_rect(&mbi.rcBar));
296     ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n",
297             mbi.hMenu, hmenu);
298     ok(mbi.fBarFocused == 0, "fBarFocused: Got %d instead of 0.\n", mbi.fBarFocused);
299     ok(mbi.fFocused == 0, "fFocused: Got %d instead of 0.\n", mbi.fFocused);
300 
301     /* add some items */
302     ret = AppendMenuA(hmenu, MF_STRING , 100, "item 1");
303     ok(ret, "AppendMenu failed.\n");
304     ret = AppendMenuA(hmenu, MF_STRING , 101, "item 2");
305     ok(ret, "AppendMenu failed.\n");
306     ret = SetMenu(hwnd, hmenu);
307     ok(ret, "SetMenu failed with error %d\n", GetLastError());
308 
309     SetLastError(0xdeadbeef);
310     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 200, &mbi);
311     err = GetLastError();
312     ok(ret == FALSE, "GetMenuBarInfo should have failed\n");
313     ok(err == 0xdeadbeef, "err = %d\n", err);
314 
315     /* get info for the whole menu */
316     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
317     ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError());
318 
319     /* calculate menu rectangle, from window rectangle and the position of the first item  */
320     ret = GetWindowRect(hwnd, &rcw);
321     ok(ret, "GetWindowRect failed.\n");
322     ret = GetMenuItemRect(hwnd, hmenu, 0, &rci);
323     ok(ret, "GetMenuItemRect failed.\n");
324     todo_wine ok(mbi.rcBar.left == rci.left && mbi.rcBar.top == rci.top &&
325             mbi.rcBar.bottom == rci.bottom && mbi.rcBar.right == rcw.right - rci.left + rcw.left,
326             "rcBar: Got %s instead of (%d,%d)-(%d,%d)\n", wine_dbgstr_rect(&mbi.rcBar),
327             rci.left, rci.top, rcw.right - rci.left + rcw.left, rci.bottom);
328     ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", mbi.hMenu, hmenu);
329     ok(mbi.fBarFocused == 0, "fBarFocused: got %d instead of 0\n", mbi.fBarFocused);
330     ok(mbi.fFocused == 0, "fFocused: got %d instead of 0\n", mbi.fFocused);
331 
332     /* get info for item nr.2 */
333     ret = GetMenuBarInfo(hwnd, OBJID_MENU, 2, &mbi);
334     ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError());
335     ret = GetMenuItemRect(hwnd, hmenu, 1, &rci);
336     ok(ret, "GetMenuItemRect failed.\n");
337     ok(EqualRect(&mbi.rcBar, &rci), "rcBar: Got %s instead of %s\n", wine_dbgstr_rect(&mbi.rcBar),
338             wine_dbgstr_rect(&rci));
339     ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", mbi.hMenu, hmenu);
340     ok(mbi.fBarFocused == 0, "fBarFocused: got %d instead of 0\n", mbi.fBarFocused);
341     ok(mbi.fFocused == 0, "fFocused: got %d instead of 0\n", mbi.fFocused);
342 
343     DestroyWindow(hwnd);
344 }
345 
346 static void test_GetMenuItemRect(void)
347 {
348     HWND hwnd;
349     HMENU hmenu;
350     HMENU popup_hmenu;
351     RECT window_rect;
352     RECT item_rect;
353     POINT client_top_left;
354     INT caption_height;
355     BOOL ret;
356 
357     hwnd = CreateWindowW((LPCWSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL,
358                          NULL, NULL, NULL);
359     ok(hwnd != NULL, "CreateWindow failed with error %d\n", GetLastError());
360     hmenu = CreateMenu();
361     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
362     popup_hmenu = CreatePopupMenu();
363     ok(popup_hmenu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError());
364     ret = AppendMenuA(popup_hmenu, MF_STRING, 0, "Popup");
365     ok(ret, "AppendMenu failed with error %d\n", GetLastError());
366     ret = AppendMenuA(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)popup_hmenu, "Menu");
367     ok(ret, "AppendMenu failed with error %d\n", GetLastError());
368     ret = SetMenu(hwnd, hmenu);
369     ok(ret, "SetMenu failed with error %d\n", GetLastError());
370 
371     /* Get the menu item rectangle of the displayed sysmenu item */
372     ret = GetMenuItemRect(hwnd, hmenu, 0, &item_rect);
373     ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError());
374     GetWindowRect(hwnd, &window_rect);
375     /* Get the screen coordinate of the left top corner of the client rectangle */
376     client_top_left.x = 0;
377     client_top_left.y = 0;
378     MapWindowPoints(hwnd, 0, &client_top_left, 1);
379     caption_height = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
380 
381     ok(item_rect.left == client_top_left.x, "Expect item_rect.left %d == %d\n", item_rect.left, client_top_left.x);
382     ok(item_rect.right <= window_rect.right, "Expect item_rect.right %d <= %d\n", item_rect.right, window_rect.right);
383     /* A gap of 1 pixel is added deliberately in commit 75f9e64, so using equal operator would fail on Wine.
384      * Check that top and bottom are correct with 1 pixel margin tolerance */
385     ok(item_rect.top - (window_rect.top + caption_height) <= 1, "Expect item_rect.top %d - %d <= 1\n", item_rect.top,
386        window_rect.top + caption_height);
387     ok(item_rect.bottom - (client_top_left.y - 1) <= 1, "Expect item_rect.bottom %d - %d <= 1\n", item_rect.bottom,
388        client_top_left.y - 1);
389 
390     /* Get the item rectangle of the not yet displayed popup menu item. */
391     ret = GetMenuItemRect(hwnd, popup_hmenu, 0, &item_rect);
392     ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError());
393     ok(item_rect.left == client_top_left.x, "Expect item_rect.left %d == %d\n", item_rect.left, client_top_left.x);
394     ok(item_rect.right == client_top_left.x, "Expect item_rect.right %d == %d\n", item_rect.right, client_top_left.x);
395     ok(item_rect.top == client_top_left.y, "Expect item_rect.top %d == %d\n", item_rect.top, client_top_left.y);
396     ok(item_rect.bottom == client_top_left.y, "Expect item_rect.bottom %d == %d\n", item_rect.bottom,
397        client_top_left.y);
398 
399     DestroyWindow(hwnd);
400 }
401 
402 static void test_system_menu(void)
403 {
404     WCHAR testW[] = {'t','e','s','t',0};
405     BOOL ret;
406     HMENU menu;
407     HWND hwnd;
408     MENUITEMINFOA info;
409     MENUITEMINFOW infoW;
410     char buffer[80];
411     char found[0x200];
412     int i, res;
413 
414     hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
415                            WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
416                            NULL, NULL, NULL, NULL);
417     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
418     menu = GetSystemMenu( hwnd, FALSE );
419     ok( menu != NULL, "no system menu\n" );
420 
421     for (i = 0xf000; i < 0xf200; i++)
422     {
423         memset( &info, 0xcc, sizeof(info) );
424         info.cbSize = sizeof(info);
425         info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
426         info.dwTypeData = buffer;
427         info.cch = sizeof( buffer );
428         ret = GetMenuItemInfoA( menu, i, FALSE, &info );
429         if (ret) trace( "found %x: '%s'\n", i, buffer );
430         switch (i)
431         {
432         case SC_RESTORE:
433         case SC_SIZE:
434         case SC_MOVE:
435         case SC_MINIMIZE:
436         case SC_MAXIMIZE:
437         case SC_CLOSE:
438             ok( ret, "%x menu item not found\n", i );
439             break;
440         case SC_SCREENSAVE+1:  /* used for the 'About Wine' entry, don't test */
441             break;
442         default:
443             ok( !ret, "%x menu item found\n", i );
444             break;
445         }
446         found[i - 0xf000] = ret;
447     }
448 
449     for (i = 0xf000; i < 0xf200; i++)
450     {
451         res = CheckMenuItem( menu, i, 0 );
452         if (res == -1) ok( !found[i - 0xf000], "could not check existent item %x\n", i );
453         else ok( found[i - 0xf000], "could check non-existent item %x\n", i );
454 
455         res = EnableMenuItem( menu, i, 0 );
456         if (res == -1) ok( !found[i - 0xf000], "could not enable existent item %x\n", i );
457         else ok( found[i - 0xf000], "could enable non-existent item %x\n", i );
458 
459         res = GetMenuState( menu, i, 0 );
460         if (res == -1) ok( !found[i - 0xf000], "could not get state existent item %x\n", i );
461         else ok( found[i - 0xf000], "could get state of non-existent item %x\n", i );
462 
463         if (!found[i - 0xf000])  /* don't remove the existing ones */
464         {
465             ret = RemoveMenu( menu, i, 0 );
466             ok( !ret, "could remove non-existent item %x\n", i );
467         }
468 
469         ret = ModifyMenuA( menu, i, 0, i, "test" );
470         if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" );
471         else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i );
472         else ok( found[i - 0xf000], "could modify non-existent item %x\n", i );
473 
474         ret = ModifyMenuW( menu, i, 0, i, testW );
475         if (i == SC_TASKLIST) ok( ret, "failed to modify SC_TASKLIST\n" );
476         else if (!ret) ok( !found[i - 0xf000], "could not modify existent item %x\n", i );
477         else ok( found[i - 0xf000], "could modify non-existent item %x\n", i );
478 
479         ret = ModifyMenuA( menu, i, MF_BYPOSITION, i, "test" );
480         ok( !ret, "could modify non-existent item %x\n", i );
481 
482         strcpy( buffer, "test" );
483         memset( &info, 0xcc, sizeof(info) );
484         info.cbSize = sizeof(info);
485         info.fMask = MIIM_STRING | MIIM_ID;
486         info.wID = i;
487         info.dwTypeData = buffer;
488         info.cch = strlen( buffer );
489         ret = SetMenuItemInfoA( menu, i, FALSE, &info );
490         if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" );
491         else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i );
492         else ok( found[i - 0xf000], "could set non-existent item %x\n", i );
493         ret = SetMenuItemInfoA( menu, i, TRUE, &info );
494         ok( !ret, "could modify non-existent item %x\n", i );
495 
496         memset( &infoW, 0xcc, sizeof(infoW) );
497         infoW.cbSize = sizeof(infoW);
498         infoW.fMask = MIIM_STRING | MIIM_ID;
499         infoW.wID = i;
500         infoW.dwTypeData = testW;
501         infoW.cch = lstrlenW( testW );
502         ret = SetMenuItemInfoW( menu, i, FALSE, &infoW );
503         if (i == SC_TASKLIST) ok( ret, "failed to set SC_TASKLIST\n" );
504         else if (!ret) ok( !found[i - 0xf000], "could not set existent item %x\n", i );
505         else ok( found[i - 0xf000], "could set non-existent item %x\n", i );
506         ret = SetMenuItemInfoW( menu, i, TRUE, &infoW );
507         ok( !ret, "could modify non-existent item %x\n", i );
508     }
509 
510     /* confirm that SC_TASKLIST still does not exist */
511     for (i = 0xf000; i < 0xf200; i++)
512     {
513         memset( &info, 0xcc, sizeof(info) );
514         info.cbSize = sizeof(info);
515         info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
516         info.dwTypeData = buffer;
517         info.cch = sizeof( buffer );
518         ret = GetMenuItemInfoA( menu, i, FALSE, &info );
519         switch (i)
520         {
521         case SC_RESTORE:
522         case SC_SIZE:
523         case SC_MOVE:
524         case SC_MINIMIZE:
525         case SC_MAXIMIZE:
526         case SC_CLOSE:
527             ok( ret, "%x menu item not found\n", i );
528             break;
529         case SC_SCREENSAVE+1:  /* used for the 'About Wine' entry, don't test */
530             break;
531         default:
532             ok( !ret, "%x menu item found\n", i );
533             break;
534         }
535     }
536 
537     /* now a normal (non-system) menu */
538 
539     menu = CreateMenu();
540     ok( menu != NULL, "CreateMenu failed with error %d\n", GetLastError() );
541 
542     res = CheckMenuItem( menu, SC_TASKLIST, 0 );
543     ok( res == -1, "CheckMenuItem succeeded\n" );
544     res = EnableMenuItem( menu, SC_TASKLIST, 0 );
545     ok( res == -1, "EnableMenuItem succeeded\n" );
546     res = GetMenuState( menu, SC_TASKLIST, 0 );
547     ok( res == -1, "GetMenuState succeeded\n" );
548     ret = RemoveMenu( menu, SC_TASKLIST, 0 );
549     ok( !ret, "RemoveMenu succeeded\n" );
550     ret = ModifyMenuA( menu, SC_TASKLIST, 0, SC_TASKLIST, "test" );
551     ok( ret, "ModifyMenuA failed err %d\n", GetLastError() );
552     ret = ModifyMenuW( menu, SC_TASKLIST, 0, SC_TASKLIST, testW );
553     ok( ret, "ModifyMenuW failed err %d\n", GetLastError() );
554     ret = ModifyMenuA( menu, SC_TASKLIST-1, 0, SC_TASKLIST, "test" );
555     ok( !ret, "ModifyMenu succeeded on SC_TASKLIST-1\n" );
556     strcpy( buffer, "test" );
557     memset( &info, 0xcc, sizeof(info) );
558     info.cbSize = sizeof(info);
559     info.fMask = MIIM_STRING | MIIM_ID;
560     info.wID = SC_TASKLIST;
561     info.dwTypeData = buffer;
562     info.cch = strlen( buffer );
563     ret = SetMenuItemInfoA( menu, SC_TASKLIST, FALSE, &info );
564     ok( ret, "failed to set SC_TASKLIST\n" );
565     ret = SetMenuItemInfoA( menu, SC_TASKLIST+1, FALSE, &info );
566     ok( !ret, "succeeded setting SC_TASKLIST+1\n" );
567     ret = SetMenuItemInfoA( menu, SC_TASKLIST, TRUE, &info );
568     ok( !ret, "succeeded setting by position\n" );
569 
570     memset( &infoW, 0xcc, sizeof(infoW) );
571     infoW.cbSize = sizeof(infoW);
572     infoW.fMask = MIIM_STRING | MIIM_ID;
573     infoW.wID = SC_TASKLIST;
574     infoW.dwTypeData = testW;
575     infoW.cch = lstrlenW( testW );
576     ret = SetMenuItemInfoW( menu, SC_TASKLIST, FALSE, &infoW );
577     ok( ret, "failed to set SC_TASKLIST\n" );
578     ret = SetMenuItemInfoW( menu, SC_TASKLIST+1, FALSE, &infoW );
579     ok( !ret, "succeeded setting SC_TASKLIST+1\n" );
580     ret = SetMenuItemInfoW( menu, SC_TASKLIST, TRUE, &infoW );
581     ok( !ret, "succeeded setting by position\n" );
582 
583     DestroyMenu( menu );
584     DestroyWindow( hwnd );
585 }
586 
587 /* demonstrates that windows locks the menu object so that it is still valid
588  * even after a client calls DestroyMenu on it */
589 static void test_menu_locked_by_window(void)
590 {
591     BOOL ret;
592     HMENU hmenu;
593     HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
594                                WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
595                                NULL, NULL, NULL, NULL);
596     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
597     hmenu = CreateMenu();
598     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
599     ret = InsertMenuA(hmenu, 0, MF_STRING, 0, "&Test");
600     ok(ret, "InsertMenu failed with error %d\n", GetLastError());
601     ret = SetMenu(hwnd, hmenu);
602     ok(ret, "SetMenu failed with error %d\n", GetLastError());
603     ret = DestroyMenu(hmenu);
604     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
605 
606     ret = DrawMenuBar(hwnd);
607     ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
608     ret = IsMenu(GetMenu(hwnd));
609     ok(!ret || broken(ret) /* nt4 */, "Menu handle should have been destroyed\n");
610 
611     SendMessageA(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
612     /* did we process the WM_INITMENU message? */
613     ret = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
614     todo_wine {
615     ok(ret, "WM_INITMENU should have been sent\n");
616     }
617 
618     DestroyWindow(hwnd);
619 }
620 
621 /* demonstrates that subpopup's are locked
622  * even after a client calls DestroyMenu on it */
623 static LRESULT WINAPI subpopuplocked_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
624 {
625     HWND hwndmenu;
626     switch (msg)
627     {
628     case WM_ENTERIDLE:
629         hwndmenu = GetCapture();
630         if( hwndmenu) {
631             PostMessageA( hwndmenu, WM_KEYDOWN, VK_DOWN, 0);
632             PostMessageA( hwndmenu, WM_KEYDOWN, VK_RIGHT, 0);
633             PostMessageA( hwndmenu, WM_KEYDOWN, VK_RETURN, 0);
634         }
635     }
636     return DefWindowProcA(hwnd, msg, wparam, lparam);
637 }
638 
639 static void test_subpopup_locked_by_menu(void)
640 {
641     BOOL ret;
642     HMENU hmenu, hsubmenu;
643     MENUINFO mi = { sizeof( MENUINFO)};
644     MENUITEMINFOA mii = { sizeof( MENUITEMINFOA)};
645     HWND hwnd;
646     const int itemid = 0x1234567;
647 
648     /* create window, popupmenu with one subpopup */
649     hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
650             WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
651             NULL, NULL, NULL, NULL);
652     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
653     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR) subpopuplocked_wnd_proc);
654     hmenu = CreatePopupMenu();
655     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
656     hsubmenu = CreatePopupMenu();
657     ok(hsubmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
658     ret = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hsubmenu,
659             "PopUpLockTest");
660     ok(ret, "InsertMenu failed with error %d\n", GetLastError());
661     ret = InsertMenuA(hsubmenu, 0, MF_BYPOSITION | MF_STRING, itemid, "PopUpMenu");
662     ok(ret, "InsertMenu failed with error %d\n", GetLastError());
663     /* first some tests that all this functions properly */
664     mii.fMask = MIIM_SUBMENU;
665     ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii);
666     ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError());
667     ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu);
668     mi.fMask |= MIM_STYLE;
669     ret = GetMenuInfo( hsubmenu, &mi);
670     ok( ret , "GetMenuInfo returned 0 with error %d\n", GetLastError());
671     ret = IsMenu( hsubmenu);
672     ok( ret , "Menu handle is not valid\n");
673 
674     ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
675     ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError());
676 
677     /* then destroy the sub-popup */
678     ret = DestroyMenu( hsubmenu);
679     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
680     /* and repeat the tests */
681     mii.fMask = MIIM_SUBMENU;
682     ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii);
683     ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError());
684     /* GetMenuInfo fails now */
685     ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu);
686     mi.fMask |= MIM_STYLE;
687     ret = GetMenuInfo( hsubmenu, &mi);
688     ok( !ret , "GetMenuInfo should have failed\n");
689     /* IsMenu says it is not */
690     ret = IsMenu( hsubmenu);
691     ok( !ret , "Menu handle should be invalid\n");
692 
693     /* but TrackPopupMenu still works! */
694     ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
695     todo_wine {
696         ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError());
697     }
698 
699     /* clean up */
700     DestroyMenu( hmenu);
701     DestroyWindow(hwnd);
702 }
703 
704 static void test_menu_ownerdraw(void)
705 {
706     int i,j,k;
707     BOOL ret;
708     HMENU hmenu;
709     MENUITEMINFOA mii;
710     LONG leftcol;
711     HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
712                                WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
713                                NULL, NULL, NULL, NULL);
714     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
715     if( !hwnd) return;
716     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc);
717     hmenu = CreatePopupMenu();
718     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
719     if( !hmenu) { DestroyWindow(hwnd);return;}
720     k=0;
721     for( j=0;j<2;j++) /* create columns */
722         for(i=0;i<2;i++) { /* create rows */
723             ret = AppendMenuA( hmenu, MF_OWNERDRAW |
724                               (i==0 ? MF_MENUBREAK : 0), k, (LPCSTR)MAKEINTRESOURCE(k));
725             k++;
726             ok( ret, "AppendMenu failed for %d\n", k-1);
727         }
728     MOD_maxid = k-1;
729     assert( k <= ARRAY_SIZE(MOD_rc));
730     /* display the menu */
731     TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
732 
733     /* columns have a 4 pixel gap between them */
734     ok( MOD_rc[0].right + 4 ==  MOD_rc[2].left,
735             "item rectangles are not separated by 4 pixels space\n");
736     /* height should be what the MEASUREITEM message has returned */
737     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
738             "menu item has wrong height: %d should be %d\n",
739             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
740     /* no gaps between the rows */
741     ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
742             "There should not be a space between the rows, gap is %d\n",
743             MOD_rc[0].bottom - MOD_rc[1].top);
744     /* test the correct value of the item height that was sent
745      * by the WM_MEASUREITEM message */
746     ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
747             MOD_odheight == MOD_hic,                     /* Win95,98,ME */
748             "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
749             HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
750     /* test what MF_MENUBREAK did at the first position. Also show
751      * that an MF_SEPARATOR is ignored in the height calculation. */
752     leftcol= MOD_rc[0].left;
753     ModifyMenuA( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
754     /* display the menu */
755     TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
756     /* left should be 4 pixels less now */
757     ok( leftcol == MOD_rc[0].left + 4,
758             "columns should be 4 pixels to the left (actual %d).\n",
759             leftcol - MOD_rc[0].left);
760     /* test width */
761     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
762             "width of owner drawn menu item is wrong. Got %d expected %d\n",
763             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
764     /* and height */
765     ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
766             "Height is incorrect. Got %d expected %d\n",
767             MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
768 
769     /* test owner-drawn callback bitmap */
770     ModifyMenuA( hmenu, 1, MF_BYPOSITION | MFT_BITMAP, 1, (LPCSTR)HBMMENU_CALLBACK );
771     mii.cbSize = sizeof(mii);
772     mii.fMask = MIIM_BITMAP | MIIM_FTYPE | MIIM_ID;
773     if (GetMenuItemInfoA( hmenu, 1, TRUE, &mii ))
774     {
775         ok( mii.fType == MFT_BITMAP, "wrong type %x\n", mii.fType );
776         ok( mii.wID == 1, "wrong id %x\n", mii.wID );
777         ok( mii.hbmpItem == HBMMENU_CALLBACK, "wrong data %p\n", mii.hbmpItem );
778     }
779     TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
780 
781     /* test width/height of an ownerdraw menu bar as well */
782     ret = DestroyMenu(hmenu);
783     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
784     hmenu = CreateMenu();
785     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
786     if( !hmenu) { DestroyWindow(hwnd);return;}
787     MOD_maxid=1;
788     for(i=0;i<2;i++) {
789         ret = AppendMenuA( hmenu, MF_OWNERDRAW, i, 0 );
790         ok( ret, "AppendMenu failed for %d\n", i);
791     }
792     ret = SetMenu( hwnd, hmenu);
793     UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
794     ok(ret, "SetMenu failed with error %d\n", GetLastError());
795     /* test width */
796     ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
797             "width of owner drawn menu item is wrong. Got %d expected %d\n",
798             MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
799     /* test height */
800     ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
801             "Height of owner drawn menu item is wrong. Got %d expected %d\n",
802             MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
803 
804     /* clean up */
805     ret = DestroyMenu(hmenu);
806     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
807     DestroyWindow(hwnd);
808 }
809 
810 /* helper for test_menu_bmp_and_string() */
811 static void test_mbs_help( int ispop, int hassub, int mnuopt,
812         HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
813         SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
814 {
815     BOOL ret;
816     HMENU hmenu, submenu;
817     MENUITEMINFOA mii={ sizeof( MENUITEMINFOA )};
818     MENUINFO mi;
819     RECT rc;
820     CHAR text_copy[16];
821     int hastab,  expect;
822     BOOL failed = FALSE;
823 
824     MOD_GotDrawItemMsg = FALSE;
825     mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
826     mii.fType = 0;
827     /* check the menu item unless MNS_CHECKORBMP is set */
828     mii.fState = (mnuopt != 2 ? MFS_CHECKED : MFS_UNCHECKED);
829     mii.dwItemData =0;
830     MODsizes[0] = bmpsize;
831     hastab = 0;
832     if( text ) {
833         char *p;
834         mii.fMask |= MIIM_STRING;
835         strcpy(text_copy, text);
836         mii.dwTypeData = text_copy; /* structure member declared non-const */
837         if( ( p = strchr( text, '\t'))) {
838             hastab = *(p + 1) ? 2 : 1;
839         }
840     }
841     /* tabs don't make sense in menubars */
842     if(hastab && !ispop) return;
843     if( hbmp) {
844         mii.fMask |= MIIM_BITMAP;
845         mii.hbmpItem = hbmp;
846     }
847     submenu = CreateMenu();
848     ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
849     if( ispop)
850         hmenu = CreatePopupMenu();
851     else
852         hmenu = CreateMenu();
853     ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
854     if( hassub) {
855         mii.fMask |= MIIM_SUBMENU;
856         mii.hSubMenu = submenu;
857     }
858     if( mnuopt) {
859         mi.cbSize = sizeof(mi);
860         mi.fMask = MIM_STYLE;
861         GetMenuInfo( hmenu, &mi);
862         if( mnuopt) mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
863         ret = SetMenuInfo( hmenu, &mi);
864         ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
865     }
866     ret = InsertMenuItemA( hmenu, 0, FALSE, &mii);
867     ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
868     failed = !ret;
869     if( winetest_debug) {
870         HDC hdc=GetDC(hwnd);
871         RECT rc = {100, 50, 400, 70};
872         char buf[100];
873 
874         sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
875         FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
876         TextOutA( hdc, 10, 50, buf, strlen( buf));
877         ReleaseDC( hwnd, hdc);
878     }
879     if(ispop)
880         TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
881     else {
882         ret = SetMenu( hwnd, hmenu);
883         ok(ret, "SetMenu failed with error %d\n", GetLastError());
884         DrawMenuBar( hwnd);
885     }
886     ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
887     ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError());
888 
889     if (0)  /* comment out menu size checks, behavior is different in almost every Windows version */
890             /* the tests should however succeed on win2000, XP and Wine (at least up to 1.1.15) */
891             /* with a variety of dpis and desktop font sizes */
892     {
893         /* check menu width */
894         if( ispop)
895             expect = ( text || hbmp ?
896                        4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
897                        : 0) +
898                        arrowwidth  + MOD_avec + (hbmp ?
899                                     ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ? bmpsize.cx + 2 : GetSystemMetrics( SM_CXMENUSIZE) + 2)
900                                     : 0) +
901                 (text && hastab ? /* TAB space */
902                  MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
903                 (text ?  2 + (text[0] ? size.cx :0): 0) ;
904         else
905             expect = !(text || hbmp) ? 0 :
906                 ( hbmp ? (text ? 2:0) + bmpsize.cx  : 0 ) +
907                 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
908         ok( rc.right - rc.left == expect,
909             "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
910         failed = failed || !(rc.right - rc.left == expect);
911         /* check menu height */
912         if( ispop)
913             expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
914                           max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
915                                (hbmp ?
916                                    ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ?
917                                        bmpsize.cy + 2
918                                      : GetSystemMetrics( SM_CYMENUSIZE) + 2)
919                                  : 0)));
920         else
921             expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
922                        max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
923         ok( rc.bottom - rc.top == expect,
924             "menu height wrong, got %d expected %d (%d)\n",
925             rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
926         failed = failed || !(rc.bottom - rc.top == expect);
927         if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
928             /* check the position of the bitmap */
929             /* horizontal */
930             if (!ispop)
931                 expect = 3;
932             else if (mnuopt == 0)
933                 expect = 4 + GetSystemMetrics(SM_CXMENUCHECK);
934             else if (mnuopt == 1)
935                 expect = 4;
936             else /* mnuopt == 2 */
937                 expect = 2;
938             ok( expect == MOD_rc[0].left,
939                 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
940             failed = failed || !(expect == MOD_rc[0].left);
941             /* vertical */
942             expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
943             ok( expect == MOD_rc[0].top,
944                 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
945             failed = failed || !(expect == MOD_rc[0].top);
946         }
947     }
948     /* if there was a failure, report details */
949     if( failed) {
950         trace("*** count %d %s text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
951                 count, (ispop? "POPUP": "MENUBAR"),text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
952                 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
953         trace("    check %d,%d arrow %d avechar %d\n",
954                 GetSystemMetrics(SM_CXMENUCHECK ),
955                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
956         if( hbmp == HBMMENU_CALLBACK)
957             trace( "    rc %s bmp.rc %s\n", wine_dbgstr_rect(&rc), wine_dbgstr_rect(&MOD_rc[0]));
958     }
959     /* clean up */
960     ret = DestroyMenu(submenu);
961     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
962     ret = DestroyMenu(hmenu);
963     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
964 }
965 
966 
967 static void test_menu_bmp_and_string(void)
968 {
969     BYTE bmfill[300];
970     HBITMAP hbm_arrow;
971     BITMAP bm;
972     INT arrowwidth;
973     HWND hwnd;
974     HMENU hsysmenu;
975     MENUINFO mi= {sizeof(MENUINFO)};
976     MENUITEMINFOA mii= {sizeof(MENUITEMINFOA)};
977     int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
978     BOOL got;
979 
980     memset( bmfill, 0xcc, sizeof( bmfill));
981     hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU |
982                           WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
983                           NULL, NULL, NULL, NULL);
984     hbm_arrow = LoadBitmapA( 0, (LPCSTR)OBM_MNARROW);
985     GetObjectA( hbm_arrow, sizeof(bm), &bm);
986     arrowwidth = bm.bmWidth;
987     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
988     if( !hwnd) return;
989     /* test system menu */
990     hsysmenu = GetSystemMenu( hwnd, FALSE);
991     ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError());
992     mi.fMask = MIM_STYLE;
993     mi.dwStyle = 0;
994     got = GetMenuInfo( hsysmenu, &mi);
995     ok( got, "GetMenuInfo failed gle=%d\n", GetLastError());
996     ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08x, without the bit %08x\n",
997         mi.dwStyle, MNS_CHECKORBMP);
998     mii.fMask = MIIM_BITMAP;
999     mii.hbmpItem = NULL;
1000     got = GetMenuItemInfoA( hsysmenu, SC_CLOSE, FALSE, &mii);
1001     ok( got, "GetMenuItemInfoA failed gle=%d\n", GetLastError());
1002     ok( HBMMENU_POPUP_CLOSE == mii.hbmpItem, "Item info did not get the right hbitmap: got %p  expected %p\n",
1003         mii.hbmpItem, HBMMENU_POPUP_CLOSE);
1004 
1005     memset(&mii, 0x81, sizeof(mii));
1006     mii.cbSize = sizeof(mii);
1007     mii.fMask  = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA;
1008     mii.dwTypeData = (LPSTR)bmfill;
1009     mii.cch = sizeof(bmfill);
1010     mii.dwItemData = 0x81818181;
1011     got = GetMenuItemInfoA(hsysmenu, SC_RESTORE, FALSE, &mii);
1012     ok(got, "GetMenuItemInfo failed\n");
1013     ok((mii.fType & ~(MFT_RIGHTJUSTIFY|MFT_RIGHTORDER)) == MFT_STRING, "expected MFT_STRING, got %#x\n", mii.fType);
1014     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
1015     ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID);
1016     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
1017     ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData);
1018     ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData);
1019     ok(mii.cch != 0, "cch should not be 0\n");
1020     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
1021 
1022     mii.cbSize = sizeof(mii);
1023     mii.fMask = MIIM_TYPE;
1024     mii.hbmpItem = (HBITMAP)0x81818181;
1025     got = GetMenuItemInfoA(hsysmenu, SC_CLOSE, FALSE, &mii);
1026     ok(got, "GetMenuItemInfo failed\n");
1027     ok((mii.fType & ~(MFT_RIGHTJUSTIFY|MFT_RIGHTORDER)) == MFT_STRING, "expected MFT_STRING, got %#x\n", mii.fType);
1028     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
1029     ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID);
1030     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
1031     ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData);
1032     ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData);
1033     ok(mii.cch != 0, "cch should not be 0\n");
1034     ok(mii.hbmpItem == HBMMENU_POPUP_CLOSE, "expected HBMMENU_POPUP_CLOSE, got %p\n", mii.hbmpItem);
1035 
1036     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc);
1037 
1038     if( winetest_debug)
1039         trace("    check %d,%d arrow %d avechar %d\n",
1040                 GetSystemMetrics(SM_CXMENUCHECK ),
1041                 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
1042     count = 0;
1043     MOD_maxid = 0;
1044     for( ispop=1; ispop >= 0; ispop--){
1045         static SIZE bmsizes[]= {
1046             {10,10},{38,38},{1,30},{55,5}};
1047         for( szidx=0; szidx < ARRAY_SIZE(bmsizes); szidx++) {
1048             HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
1049             HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, HBMMENU_POPUP_CLOSE, NULL  };
1050             ok( hbm != 0, "CreateBitmap failed err %d\n", GetLastError());
1051             for( txtidx = 0; txtidx < ARRAY_SIZE(MOD_txtsizes); txtidx++) {
1052                 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
1053                     for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
1054                         for( bmpidx = 0; bmpidx <ARRAY_SIZE(bitmaps); bmpidx++) {
1055                             /* no need to test NULL bitmaps of several sizes */
1056                             if( !bitmaps[bmpidx] && szidx > 0) continue;
1057                             /* the HBMMENU_POPUP not to test for menu bars */
1058                             if( !ispop &&
1059                                 bitmaps[bmpidx] >= HBMMENU_POPUP_CLOSE &&
1060                                 bitmaps[bmpidx] <= HBMMENU_POPUP_MINIMIZE) continue;
1061                             if( !ispop && hassub) continue;
1062                             test_mbs_help( ispop, hassub, mnuopt,
1063                                     hwnd, arrowwidth, ++count,
1064                                     bitmaps[bmpidx],
1065                                     bmsizes[szidx],
1066                                     MOD_txtsizes[txtidx].text,
1067                                     MOD_txtsizes[txtidx].size,
1068                                     MOD_txtsizes[txtidx].sc_size);
1069                         }
1070                     }
1071                 }
1072             }
1073             DeleteObject( hbm);
1074         }
1075     }
1076     /* clean up */
1077     DestroyWindow(hwnd);
1078 }
1079 
1080 static void test_menu_add_string( void )
1081 {
1082     HMENU hmenu;
1083     MENUITEMINFOA info;
1084     BOOL rc;
1085     int ret;
1086 
1087     char string[0x80];
1088     char string2[0x80];
1089 
1090     char strback[0x80];
1091     WCHAR strbackW[0x80];
1092     static CHAR blah[] = "blah";
1093     static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
1094 
1095     hmenu = CreateMenu();
1096 
1097     memset( &info, 0, sizeof info );
1098     info.cbSize = sizeof info;
1099     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
1100     info.dwTypeData = blah;
1101     info.cch = 6;
1102     info.dwItemData = 0;
1103     info.wID = 1;
1104     info.fState = 0;
1105     InsertMenuItemA(hmenu, 0, TRUE, &info );
1106 
1107     memset( &info, 0, sizeof info );
1108     info.cbSize = sizeof info;
1109     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
1110     info.dwTypeData = string;
1111     info.cch = sizeof string;
1112     string[0] = 0;
1113     GetMenuItemInfoA( hmenu, 0, TRUE, &info );
1114 
1115     ok( !strcmp( string, "blah" ), "menu item name differed\n");
1116 
1117     /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
1118     strcpy(string, "Dummy string");
1119     memset(&info, 0x00, sizeof(info));
1120     info.cbSize= sizeof(MENUITEMINFOA);
1121     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
1122     info.fType= MFT_OWNERDRAW;
1123     info.dwTypeData= string;
1124     rc = InsertMenuItemA( hmenu, 0, TRUE, &info );
1125     ok (rc, "InsertMenuItem failed\n");
1126 
1127     strcpy(string,"Garbage");
1128     ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
1129     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
1130 
1131     ret = GetMenuStringW( hmenu, 0, strbackW, 99, MF_BYPOSITION );
1132     ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
1133     ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
1134 
1135     /* Just try some invalid parameter tests */
1136     SetLastError(0xdeadbeef);
1137     rc = SetMenuItemInfoA( hmenu, 0, TRUE, NULL );
1138     ret = GetLastError();
1139     ok (!rc, "SetMenuItemInfoA succeeded unexpectedly\n");
1140     ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %d\n", ret);
1141 
1142     SetLastError(0xdeadbeef);
1143     rc = SetMenuItemInfoA( hmenu, 0, FALSE, NULL );
1144     ret = GetLastError();
1145     ok (!rc, "SetMenuItemInfoA succeeded unexpectedly\n");
1146     ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %d\n", ret);
1147 
1148     /* Just change ftype to string and see what text is stored */
1149     memset(&info, 0x00, sizeof(info));
1150     info.cbSize= sizeof(MENUITEMINFOA);
1151     info.fMask= MIIM_FTYPE; /* Set string type */
1152     info.fType= MFT_STRING;
1153     info.dwTypeData= (char *)0xdeadbeef;
1154     rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
1155     ok (rc, "SetMenuItemInfo failed\n");
1156 
1157     /* Did we keep the old dwTypeData? */
1158     ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
1159     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
1160 
1161     /* Ensure change to bitmap type fails */
1162     memset(&info, 0x00, sizeof(info));
1163     info.cbSize= sizeof(MENUITEMINFOA);
1164     info.fMask= MIIM_FTYPE; /* Set as bitmap type */
1165     info.fType= MFT_BITMAP;
1166     info.dwTypeData= (char *)0xdeadbee2;
1167     rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
1168     ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
1169 
1170     /* Just change ftype back and ensure data hasn't been freed */
1171     info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
1172     info.dwTypeData= (char *)0xdeadbee3;
1173     rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
1174     ok (rc, "SetMenuItemInfo failed\n");
1175 
1176     /* Did we keep the old dwTypeData? */
1177     ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
1178     ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
1179 
1180     /* Just change string value (not type) */
1181     memset(&info, 0x00, sizeof(info));
1182     info.cbSize= sizeof(MENUITEMINFOA);
1183     info.fMask= MIIM_STRING; /* Set typeData */
1184     strcpy(string2, "string2");
1185     info.dwTypeData= string2;
1186     rc = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
1187     ok (rc, "SetMenuItemInfo failed\n");
1188 
1189     ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
1190     ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
1191 
1192     /*  crashes with wine 0.9.5 */
1193     memset(&info, 0x00, sizeof(info));
1194     info.cbSize= sizeof(MENUITEMINFOA);
1195     info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
1196     info.fType= MFT_OWNERDRAW;
1197     rc = InsertMenuItemA( hmenu, 0, TRUE, &info );
1198     ok (rc, "InsertMenuItem failed\n");
1199     ok (!GetMenuStringA( hmenu, 0, NULL, 0, MF_BYPOSITION),
1200             "GetMenuString on ownerdraw entry succeeded.\n");
1201     ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION);
1202     ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
1203 
1204     DestroyMenu( hmenu );
1205 }
1206 
1207 /* define building blocks for the menu item info tests */
1208 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
1209 {
1210     if (n <= 0) return 0;
1211     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
1212     return *str1 - *str2;
1213 }
1214 
1215 static  WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
1216 {
1217     WCHAR *p = dst;
1218     while ((*p++ = *src++));
1219     return dst;
1220 }
1221 
1222 static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, UINT id,
1223                               HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data,
1224                               void *type_data, UINT len, HBITMAP item, BOOL expect )
1225 {
1226     MENUITEMINFOA info;
1227     BOOL ret;
1228 
1229     /* magic bitmap handle to test smaller cbSize */
1230     if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef)
1231         info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem);
1232     else
1233         info.cbSize = sizeof(info);
1234     info.fMask = mask;
1235     info.fType = type;
1236     info.fState = state;
1237     info.wID = id;
1238     info.hSubMenu = submenu;
1239     info.hbmpChecked = checked;
1240     info.hbmpUnchecked = unchecked;
1241     info.dwItemData = data;
1242     info.dwTypeData = type_data;
1243     info.cch = len;
1244     info.hbmpItem = item;
1245     SetLastError( 0xdeadbeef );
1246     if (ansi) ret = InsertMenuItemA( hmenu, 0, TRUE, &info );
1247     else ret = InsertMenuItemW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info );
1248     if (!expect) ok_(__FILE__, line)( !ret, "InsertMenuItem should have failed.\n" );
1249     else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %u\n", GetLastError());
1250 }
1251 
1252 static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state,
1253                                   UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked,
1254                                   ULONG_PTR data, void *type_data, UINT in_len, UINT out_len,
1255                                   HBITMAP item, LPCSTR expname, BOOL expect, BOOL expstring )
1256 {
1257     MENUITEMINFOA info;
1258     BOOL ret;
1259     WCHAR buffer[80];
1260 
1261     SetLastError( 0xdeadbeef );
1262     memset( &info, 0xcc, sizeof(info) );
1263     info.cbSize = sizeof(info);
1264     info.fMask = mask;
1265     info.dwTypeData = type_data;
1266     info.cch = in_len;
1267 
1268     ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, &info ) :
1269                  GetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW *)&info );
1270     if (!expect)
1271     {
1272         ok_(__FILE__, line)( !ret, "GetMenuItemInfo should have failed.\n" );
1273         return;
1274     }
1275     ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %u\n", GetLastError());
1276     if (mask & MIIM_TYPE)
1277         ok_(__FILE__, line)( info.fType == type || info.fType == LOWORD(type),
1278                              "wrong type %x/%x\n", info.fType, type );
1279     if (mask & MIIM_STATE)
1280         ok_(__FILE__, line)( info.fState == state || info.fState == LOWORD(state),
1281                              "wrong state %x/%x\n", info.fState, state );
1282     if (mask & MIIM_ID)
1283         ok_(__FILE__, line)( info.wID == id || info.wID == LOWORD(id),
1284                              "wrong id %x/%x\n", info.wID, id );
1285     if (mask & MIIM_SUBMENU)
1286         ok_(__FILE__, line)( info.hSubMenu == submenu || (ULONG_PTR)info.hSubMenu == LOWORD(submenu),
1287                              "wrong submenu %p/%p\n", info.hSubMenu, submenu );
1288     if (mask & MIIM_CHECKMARKS)
1289     {
1290         ok_(__FILE__, line)( info.hbmpChecked == checked || (ULONG_PTR)info.hbmpChecked == LOWORD(checked),
1291                              "wrong bmpchecked %p/%p\n", info.hbmpChecked, checked );
1292         ok_(__FILE__, line)( info.hbmpUnchecked == unchecked || (ULONG_PTR)info.hbmpUnchecked == LOWORD(unchecked),
1293                              "wrong bmpunchecked %p/%p\n", info.hbmpUnchecked, unchecked );
1294     }
1295     if (mask & MIIM_DATA)
1296         ok_(__FILE__, line)( info.dwItemData == data || info.dwItemData == LOWORD(data),
1297                              "wrong item data %lx/%lx\n", info.dwItemData, data );
1298     if (mask & MIIM_BITMAP)
1299         ok_(__FILE__, line)( info.hbmpItem == item || (ULONG_PTR)info.hbmpItem == LOWORD(item),
1300                              "wrong bmpitem %p/%p\n", info.hbmpItem, item );
1301     ok_(__FILE__, line)( info.dwTypeData == type_data || (ULONG_PTR)info.dwTypeData == LOWORD(type_data),
1302                          "wrong type data %p/%p\n", info.dwTypeData, type_data );
1303     ok_(__FILE__, line)( info.cch == out_len ||
1304                          broken(! ansi && info.cch == 2 * out_len) /* East-Asian */,
1305                          "wrong len %x/%x\n", info.cch, out_len );
1306     if (expname)
1307     {
1308         if(ansi)
1309             ok_(__FILE__, line)( !strncmp( expname, info.dwTypeData, out_len ),
1310                                  "menu item name differed from '%s' '%s'\n", expname, info.dwTypeData );
1311         else
1312             ok_(__FILE__, line)( !strncmpW( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ),
1313                                  "menu item name wrong\n" );
1314 
1315         SetLastError( 0xdeadbeef );
1316         ret = ansi ? GetMenuStringA( hmenu, 0, (char *)buffer, 80, MF_BYPOSITION ) :
1317             GetMenuStringW( hmenu, 0, buffer, 80, MF_BYPOSITION );
1318         if (expstring)
1319             ok_(__FILE__, line)( ret, "GetMenuString failed, err %u\n", GetLastError());
1320         else
1321             ok_(__FILE__, line)( !ret, "GetMenuString should have failed\n" );
1322     }
1323 }
1324 
1325 static void modify_menu( int line, HMENU hmenu, BOOL ansi, UINT flags, UINT_PTR id, void *data )
1326 {
1327     BOOL ret;
1328 
1329     SetLastError( 0xdeadbeef );
1330     if (ansi) ret = ModifyMenuA( hmenu, 0, flags, id, data );
1331     else ret = ModifyMenuW( hmenu, 0, flags, id, data );
1332     ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %u\n", GetLastError());
1333 }
1334 
1335 static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state,
1336                                 UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data,
1337                                 void *type_data, UINT len, HBITMAP item )
1338 
1339 {
1340     MENUITEMINFOA info;
1341     BOOL ret;
1342 
1343     /* magic bitmap handle to test smaller cbSize */
1344     if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef)
1345         info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem);
1346     else
1347         info.cbSize = sizeof(info);
1348     info.fMask = mask;
1349     info.fType = type;
1350     info.fState = state;
1351     info.wID = id;
1352     info.hSubMenu = submenu;
1353     info.hbmpChecked = checked;
1354     info.hbmpUnchecked = unchecked;
1355     info.dwItemData = data;
1356     info.dwTypeData = type_data;
1357     info.cch = len;
1358     info.hbmpItem = item;
1359     SetLastError( 0xdeadbeef );
1360     if (ansi) ret = SetMenuItemInfoA( hmenu, 0, TRUE, &info );
1361     else ret = SetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info );
1362     ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %u\n", GetLastError());
1363 }
1364 
1365 #define TMII_INSMI( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,eret1 )\
1366     hmenu = CreateMenu();\
1367     submenu = CreateMenu();\
1368     if(ansi)strcpy( string, init );\
1369     else strcpyW( string, init );\
1370     insert_menu_item( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, eret1 )
1371 
1372 /* GetMenuItemInfo + GetMenuString  */
1373 #define TMII_GMII( c2,l2,\
1374     d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,\
1375     expname, eret2, eret3)\
1376     check_menu_item_info( __LINE__, hmenu, ansi, c2, d3, e3, f3, g3, h3, i3, j3, k3, l2, l3, m3, \
1377                           expname, eret2, eret3 )
1378 
1379 #define TMII_DONE \
1380     RemoveMenu(hmenu, 0, TRUE );\
1381     DestroyMenu( hmenu );\
1382     DestroyMenu( submenu );
1383 
1384 /* modify menu */
1385 #define TMII_MODM( flags, id, data ) \
1386     modify_menu( __LINE__, hmenu, ansi, flags, id, data )
1387 
1388 /* SetMenuItemInfo */
1389 #define TMII_SMII( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1 ) \
1390     set_menu_item_info( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1 )
1391 
1392 
1393 #define OK 1
1394 #define ER 0
1395 
1396 
1397 static void test_menu_iteminfo( void )
1398 {
1399   BOOL ansi = TRUE;
1400   char txtA[]="wine";
1401   char initA[]="XYZ";
1402   char emptyA[]="";
1403   WCHAR txtW[]={'W','i','n','e',0};
1404   WCHAR initW[]={'X','Y','Z',0};
1405   WCHAR emptyW[]={0};
1406   void *txt, *init, *empty, *string;
1407   HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
1408   char stringA[0x80];
1409   HMENU hmenu, submenu;
1410   HBITMAP dummy_hbm = (HBITMAP)(ULONG_PTR)0xdeadbeef;
1411 
1412   do {
1413     if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
1414     else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
1415     trace( "%s string %p hbm %p txt %p\n", ansi ?  "ANSI tests:   " : "Unicode tests:", string, hbm, txt);
1416     /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
1417     /* (since MFT_STRING is zero, there are four of them) */
1418     TMII_INSMI( MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK );
1419     TMII_GMII ( MIIM_TYPE, 80,
1420         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1421         txt, OK, OK );
1422     TMII_DONE
1423     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1424     TMII_GMII ( MIIM_TYPE, 80,
1425         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1426         NULL, OK, ER );
1427     TMII_DONE
1428     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
1429     TMII_GMII ( MIIM_TYPE, 80,
1430         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1431         NULL, OK, ER );
1432     TMII_DONE
1433     TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
1434     TMII_GMII ( MIIM_TYPE, 80,
1435         MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1436         NULL, OK, ER );
1437     TMII_DONE
1438     /* not enough space for name*/
1439     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1440     TMII_GMII ( MIIM_TYPE, 0,
1441         MFT_STRING, 0, 0, 0, 0, 0, 0, NULL, 4, 0,
1442         NULL, OK, OK );
1443     TMII_DONE
1444     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1445     TMII_GMII ( MIIM_TYPE, 5,
1446         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1447         txt, OK, OK );
1448     TMII_DONE
1449     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1450     TMII_GMII ( MIIM_TYPE, 4,
1451         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 3, 0,
1452         txt, OK, OK );
1453     TMII_DONE
1454     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1455     TMII_GMII ( MIIM_TYPE, 0,
1456         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, 0,
1457         NULL, OK, ER );
1458     TMII_DONE
1459     /* cannot combine MIIM_TYPE with some other flags */
1460     TMII_INSMI( MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER );
1461     TMII_DONE
1462     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1463     TMII_GMII ( MIIM_TYPE|MIIM_STRING, 80,
1464         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1465         NULL, ER, OK );
1466     TMII_DONE
1467     TMII_INSMI( MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER );
1468     TMII_DONE
1469     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1470     TMII_GMII ( MIIM_TYPE|MIIM_FTYPE, 80,
1471         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1472         NULL, ER, OK );
1473     TMII_DONE
1474     TMII_INSMI( MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, hbm, ER );
1475     TMII_DONE
1476         /* but succeeds with some others */
1477     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1478     TMII_GMII ( MIIM_TYPE|MIIM_SUBMENU, 80,
1479         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1480         txt, OK, OK );
1481     TMII_DONE
1482     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1483     TMII_GMII ( MIIM_TYPE|MIIM_STATE, 80,
1484         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1485         txt, OK, OK );
1486     TMII_DONE
1487     TMII_INSMI( MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, 0, 0, 0, -1, txt, 6, 0, OK );
1488     TMII_GMII ( MIIM_TYPE|MIIM_ID, 80,
1489         MFT_STRING, 0, 888, 0, 0, 0, 0, string, 4, 0,
1490         txt, OK, OK );
1491     TMII_DONE
1492     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, 0, 0, 0, 999, txt, 6, 0, OK );
1493     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1494         MFT_STRING, 0, 0, 0, 0, 0, 999, string, 4, 0,
1495         txt, OK, OK );
1496     TMII_DONE
1497     /* to be continued */
1498     /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
1499     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1500     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1501         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1502         txt, OK, OK );
1503     TMII_DONE
1504     /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
1505     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1506     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1507         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1508         empty, OK, ER );
1509     TMII_DONE
1510     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1511     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1512         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1513         empty, OK, ER );
1514     TMII_DONE
1515     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1516     TMII_GMII ( MIIM_FTYPE, 80,
1517         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, 0,
1518         init, OK, ER );
1519     TMII_DONE
1520     TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1521     TMII_GMII ( 0, 80,
1522         0, 0, 0, 0, 0, 0, 0, string, 80, 0,
1523         init, OK, OK );
1524     TMII_DONE
1525     /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
1526     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1527     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1528         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0,
1529         txt, OK, OK );
1530     TMII_DONE
1531     /* same but retrieve with MIIM_TYPE */
1532     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1533     TMII_GMII ( MIIM_TYPE, 80,
1534         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1535         NULL, OK, OK );
1536     TMII_DONE
1537     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1538     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1539         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0,
1540         empty, OK, ER );
1541     TMII_DONE
1542     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1543     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1544         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0,
1545         empty, OK, ER );
1546     TMII_DONE
1547     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1548     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1549         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, 0,
1550         NULL, OK, ER );
1551     TMII_DONE
1552 
1553     /* How is that with bitmaps? */
1554     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1555     TMII_GMII ( MIIM_TYPE, 80,
1556         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1557         NULL, OK, ER );
1558     TMII_DONE
1559     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1560     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1561         0, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1562         init, OK, ER );
1563     TMII_DONE
1564         /* MIIM_BITMAP does not like MFT_BITMAP */
1565     TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, hbm, ER );
1566     TMII_DONE
1567         /* no problem with OWNERDRAWN */
1568     TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1569     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1570         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1571         init, OK, ER );
1572     TMII_DONE
1573         /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
1574     TMII_INSMI( MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, 0, ER );
1575     TMII_DONE
1576 
1577     /* menu with submenu */
1578     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK );
1579     TMII_GMII ( MIIM_SUBMENU, 80,
1580         0, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1581         init, OK, ER );
1582     TMII_DONE
1583     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, empty, 0, 0, OK );
1584     TMII_GMII ( MIIM_SUBMENU, 80,
1585         0, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1586         init, OK, ER );
1587     TMII_DONE
1588     /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
1589     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK );
1590     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1591         MFT_STRING|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0,
1592         empty, OK, ER );
1593     TMII_GMII ( MIIM_SUBMENU|MIIM_FTYPE, 80,
1594         MFT_SEPARATOR, 0, 0, submenu, 0, 0, 0, string, 80, 0,
1595         empty, OK, ER );
1596     TMII_DONE
1597     /* menu with invalid submenu */
1598     TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, (HMENU)999, 0, 0, -1, txt, 0, 0, ER );
1599     TMII_DONE
1600     /* Separator */
1601     TMII_INSMI( MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK );
1602     TMII_GMII ( MIIM_TYPE, 80,
1603         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1604         NULL, OK, ER );
1605     TMII_DONE
1606     TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK );
1607     TMII_GMII ( MIIM_TYPE, 80,
1608         MFT_BITMAP|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1609         NULL, OK, ER );
1610     TMII_DONE
1611      /* SEPARATOR and STRING go well together */
1612     /* BITMAP and STRING go well together */
1613     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1614     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80,
1615         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, hbm,
1616         txt, OK, OK );
1617     TMII_DONE
1618      /* BITMAP, SEPARATOR and STRING go well together */
1619     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1620     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80,
1621         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, hbm,
1622         txt, OK, OK );
1623     TMII_DONE
1624      /* last two tests, but use MIIM_TYPE to retrieve info */
1625     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1626     TMII_GMII ( MIIM_TYPE, 80,
1627         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1628         NULL, OK, OK );
1629     TMII_DONE
1630     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1631     TMII_GMII ( MIIM_TYPE, 80,
1632         MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1633         NULL, OK, OK );
1634     TMII_DONE
1635     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1636     TMII_GMII ( MIIM_TYPE, 80,
1637         MFT_SEPARATOR|MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1638         NULL, OK, OK );
1639     TMII_DONE
1640      /* same three with MFT_OWNERDRAW */
1641     TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK );
1642     TMII_GMII ( MIIM_TYPE, 80,
1643         MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1644         NULL, OK, OK );
1645     TMII_DONE
1646     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1647     TMII_GMII ( MIIM_TYPE, 80,
1648         MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1649         NULL, OK, OK );
1650     TMII_DONE
1651     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1652     TMII_GMII ( MIIM_TYPE, 80,
1653         MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm,
1654         NULL, OK, OK );
1655     TMII_DONE
1656 
1657     TMII_INSMI( MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1658     TMII_GMII ( MIIM_TYPE, 80,
1659         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1660         NULL,  OK, OK );
1661     TMII_DONE
1662     /* test with modifymenu: string is preserved after setting OWNERDRAW */
1663     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1664     TMII_MODM( MFT_OWNERDRAW, -1, (void*)787 );
1665     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_DATA, 80,
1666         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 787, string, 4, 0,
1667         txt,  OK, OK );
1668     TMII_DONE
1669     /* same with bitmap: now the text is cleared */
1670     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1671     TMII_MODM( MFT_BITMAP, 545, hbm );
1672     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1673         MFT_BITMAP, 0, 545, 0, 0, 0, 0, string, 0, hbm,
1674         empty,  OK, ER );
1675     TMII_DONE
1676     /* start with bitmap: now setting text clears it (though he flag is raised) */
1677     TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1678     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1679         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 0, hbm,
1680         empty,  OK, ER );
1681     TMII_MODM( MFT_STRING, 545, txt );
1682     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1683         MFT_STRING, 0, 545, 0, 0, 0, 0, string, 4, 0,
1684         txt,  OK, OK );
1685     TMII_DONE
1686     /*repeat with text NULL */
1687     TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1688     TMII_MODM( MFT_STRING, 545, NULL );
1689     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1690         MFT_SEPARATOR, 0, 545, 0, 0, 0, 0, string, 0, 0,
1691         empty,  OK, ER );
1692     TMII_DONE
1693     /* repeat with text "" */
1694     TMII_INSMI( MIIM_BITMAP, -1 , -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1695     TMII_MODM( MFT_STRING, 545, empty );
1696     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80,
1697         MFT_STRING, 0, 545, 0, 0, 0, 0, string, 0, 0,
1698         empty,  OK, ER );
1699     TMII_DONE
1700     /* start with bitmap: set ownerdraw */
1701     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK );
1702     TMII_MODM( MFT_OWNERDRAW, -1, (void *)232 );
1703     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, 80,
1704         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 232, string, 0, hbm,
1705         empty,  OK, ER );
1706     TMII_DONE
1707     /* ask nothing */
1708     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK );
1709     TMII_GMII ( 0, 80,
1710                 0, 0, 0,  0, 0, 0, 0, string, 80, 0,
1711         init, OK, OK );
1712     TMII_DONE
1713     /* some tests with small cbSize: the hbmpItem is to be ignored */
1714     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK );
1715     TMII_GMII ( MIIM_TYPE, 80,
1716         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1717         NULL, OK, ER );
1718     TMII_DONE
1719     TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK );
1720     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1721         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, NULL,
1722         init, OK, ER );
1723     TMII_DONE
1724     TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1725     TMII_GMII ( MIIM_TYPE, 80,
1726         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, NULL,
1727         txt, OK, OK );
1728     TMII_DONE
1729     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1730     TMII_GMII ( MIIM_TYPE, 80,
1731         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1732         NULL, OK, OK );
1733     TMII_DONE
1734     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1735     TMII_GMII ( MIIM_TYPE, 80,
1736         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1737         NULL, OK, OK );
1738     TMII_DONE
1739     TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK );
1740     TMII_GMII ( MIIM_TYPE, 80,
1741         MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL,
1742         NULL, OK, OK );
1743     TMII_DONE
1744     /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus  */
1745     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1746     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1747         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 343, 0, 0, 0,
1748         NULL, OK, ER );
1749     TMII_DONE
1750     TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1751     TMII_GMII ( MIIM_TYPE, 80,
1752         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1753         NULL, OK, ER );
1754     TMII_DONE
1755     TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK );
1756     TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80,
1757         MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1758         NULL, OK, ER );
1759     TMII_DONE
1760     /* set a string menu to ownerdraw with MIIM_TYPE */
1761     TMII_INSMI( MIIM_TYPE, MFT_STRING, -2, -2, 0, 0, 0, -2, txt, -2, 0, OK );
1762     TMII_SMII ( MIIM_TYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1763     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1764         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0,
1765         txt, OK, OK );
1766     TMII_DONE
1767     /* test with modifymenu add submenu */
1768     TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK );
1769     TMII_MODM( MF_POPUP, (UINT_PTR)submenu, txt );
1770     TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, 80,
1771         MFT_STRING, 0, 0, submenu, 0, 0, 0, string, 4, 0,
1772         txt,  OK, OK );
1773     TMII_GMII ( MIIM_TYPE, 80,
1774         MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0,
1775         txt,  OK, OK );
1776     TMII_DONE
1777     /* MFT_SEPARATOR bit is kept when the text is added */
1778     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1779     TMII_SMII( MIIM_STRING, 0, 0, 0, 0, 0, 0, 0, txt, 0, 0 );
1780     TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80,
1781         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, 0,
1782         txt, OK, OK );
1783     TMII_DONE
1784     /* MFT_SEPARATOR bit is kept when bitmap is added */
1785     TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK );
1786     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, hbm );
1787     TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80,
1788         MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, hbm,
1789         init, OK, ER );
1790     TMII_DONE
1791     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1792        Only the low word of the dwTypeData is used.
1793        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1794     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1,
1795                 (HMENU)MAKELPARAM(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK );
1796     TMII_GMII ( MIIM_TYPE, 80,
1797         MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE,
1798         NULL, OK, OK );
1799     TMII_DONE
1800     /* Type flags */
1801     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1802     TMII_GMII ( MIIM_TYPE, 80,
1803         MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1804         NULL, OK, OK );
1805     TMII_DONE
1806     /* State flags */
1807     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1808     TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 );
1809     TMII_GMII ( MIIM_STATE, 80,
1810         0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0,
1811         NULL, OK, OK );
1812     TMII_DONE
1813     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1814     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1815     TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 );
1816     TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80,
1817         MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm,
1818         NULL, OK, OK );
1819     TMII_DONE
1820     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1821     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1822     TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 );
1823     TMII_GMII ( MIIM_FTYPE, 80,
1824         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1825         NULL, OK, OK );
1826     TMII_GMII ( MIIM_TYPE, 80,
1827         MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1828         NULL, OK, OK );
1829     TMII_GMII ( MIIM_FTYPE, 80,
1830         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1831         NULL, OK, OK );
1832     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL );
1833     TMII_GMII ( MIIM_TYPE, 80,
1834         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1835         NULL, OK, OK );
1836     TMII_DONE
1837     /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1838        Only the low word of the dwTypeData is used.
1839        Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1840     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1,
1841                 (HMENU)MAKELPARAM(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK );
1842     TMII_GMII ( MIIM_TYPE, 80,
1843         MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE,
1844         NULL, OK, OK );
1845     TMII_DONE
1846     /* Type flags */
1847     TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1848     TMII_GMII ( MIIM_TYPE, 80,
1849         MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1850         NULL, OK, OK );
1851     TMII_DONE
1852     /* State flags */
1853     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1854     TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 );
1855     TMII_GMII ( MIIM_STATE, 80,
1856         0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0,
1857         NULL, OK, OK );
1858     TMII_DONE
1859     /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1860     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1861     TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 );
1862     TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80,
1863         MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm,
1864         NULL, OK, OK );
1865     TMII_DONE
1866     /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1867     TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK );
1868     TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 );
1869     TMII_GMII ( MIIM_FTYPE, 80,
1870         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1871         NULL, OK, OK );
1872     TMII_GMII ( MIIM_TYPE, 80,
1873         MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm,
1874         NULL, OK, OK );
1875     TMII_GMII ( MIIM_FTYPE, 80,
1876         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0,
1877         NULL, OK, OK );
1878     TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL );
1879     TMII_GMII ( MIIM_TYPE, 80,
1880         MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL,
1881         NULL, OK, OK );
1882     TMII_DONE
1883   } while( !(ansi = !ansi) );
1884   DeleteObject( hbm);
1885 }
1886 
1887 /*
1888    The following tests try to confirm the algorithm used to return the menu items
1889    when there is a collision between a menu item and a popup menu
1890  */
1891 static void test_menu_search_bycommand( void )
1892 {
1893     HMENU        hmenu, hmenuSub, hmenuSub2;
1894     MENUITEMINFOA info;
1895     BOOL         rc;
1896     UINT         id;
1897     char         strback[0x80];
1898     char         strIn[0x80];
1899     static CHAR menuitem[]  = "MenuItem",
1900                 menuitem2[] = "MenuItem 2";
1901 
1902     /* Case 1: Menu containing a menu item */
1903     hmenu = CreateMenu();
1904 
1905     memset( &info, 0, sizeof info );
1906     info.cbSize = sizeof info;
1907     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1908     info.fType = MFT_STRING;
1909     strcpy(strIn, "Case 1 MenuItem");
1910     info.dwTypeData = strIn;
1911     info.wID = (UINT) 0x1234;
1912 
1913     rc = InsertMenuItemA(hmenu, 0, TRUE, &info );
1914     ok (rc, "Inserting the menuitem failed\n");
1915 
1916     id = GetMenuItemID(hmenu, 0);
1917     ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1918 
1919     /* Confirm the menuitem was given the id supplied (getting by position) */
1920     memset( &info, 0, sizeof info );
1921     strback[0] = 0x00;
1922     info.cbSize = sizeof(MENUITEMINFOA);
1923     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1924     info.dwTypeData = strback;
1925     info.cch = sizeof(strback);
1926 
1927     rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); /* Get by position */
1928     ok (rc, "Getting the menu items info failed\n");
1929     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1930     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1931 
1932     /* Search by id - Should return the item */
1933     memset( &info, 0, sizeof info );
1934     strback[0] = 0x00;
1935     info.cbSize = sizeof(MENUITEMINFOA);
1936     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1937     info.dwTypeData = strback;
1938     info.cch = sizeof(strback);
1939     rc = GetMenuItemInfoA(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1940 
1941     ok (rc, "Getting the menu items info failed\n");
1942     ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1943     ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1944 
1945     DestroyMenu( hmenu );
1946 
1947     /* Case 2: Menu containing a popup menu */
1948     hmenu = CreateMenu();
1949     hmenuSub = CreateMenu();
1950 
1951     strcpy(strIn, "Case 2 SubMenu");
1952     rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1953     ok (rc, "Inserting the popup menu into the main menu failed\n");
1954 
1955     id = GetMenuItemID(hmenu, 0);
1956     ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1957 
1958     /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1959     memset( &info, 0, sizeof info );
1960     strback[0] = 0x00;
1961     info.cbSize = sizeof(MENUITEMINFOA);
1962     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1963     info.dwTypeData = strback;
1964     info.cch = sizeof(strback);
1965     info.wID = 0xdeadbeef;
1966 
1967     rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); /* Get by position */
1968     ok (rc, "Getting the menu items info failed\n");
1969     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1970     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1971 
1972     /* Search by id - returns the popup menu itself */
1973     memset( &info, 0, sizeof info );
1974     strback[0] = 0x00;
1975     info.cbSize = sizeof(MENUITEMINFOA);
1976     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1977     info.dwTypeData = strback;
1978     info.cch = sizeof(strback);
1979     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1980 
1981     ok (rc, "Getting the menu items info failed\n");
1982     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1983     ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1984 
1985     /*
1986         Now add an item after it with the same id
1987      */
1988     memset( &info, 0, sizeof info );
1989     info.cbSize = sizeof info;
1990     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1991     info.fType = MFT_STRING;
1992     strcpy(strIn, "Case 2 MenuItem 1");
1993     info.dwTypeData = strIn;
1994     info.wID = (UINT_PTR) hmenuSub;
1995     rc = InsertMenuItemA(hmenu, -1, TRUE, &info );
1996     ok (rc, "Inserting the menuitem failed\n");
1997 
1998     /* Search by id - returns the item which follows the popup menu */
1999     memset( &info, 0, sizeof info );
2000     strback[0] = 0x00;
2001     info.cbSize = sizeof(MENUITEMINFOA);
2002     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
2003     info.dwTypeData = strback;
2004     info.cch = sizeof(strback);
2005     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
2006 
2007     ok (rc, "Getting the menu items info failed\n");
2008     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
2009     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2010 
2011     /*
2012         Now add an item before the popup (with the same id)
2013      */
2014     memset( &info, 0, sizeof info );
2015     info.cbSize = sizeof info;
2016     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
2017     info.fType = MFT_STRING;
2018     strcpy(strIn, "Case 2 MenuItem 2");
2019     info.dwTypeData = strIn;
2020     info.wID = (UINT_PTR) hmenuSub;
2021     rc = InsertMenuItemA(hmenu, 0, TRUE, &info );
2022     ok (rc, "Inserting the menuitem failed\n");
2023 
2024     /* Search by id - returns the item which precedes the popup menu */
2025     memset( &info, 0, sizeof info );
2026     strback[0] = 0x00;
2027     info.cbSize = sizeof(MENUITEMINFOA);
2028     info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
2029     info.dwTypeData = strback;
2030     info.cch = sizeof(strback);
2031     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
2032 
2033     ok (rc, "Getting the menu items info failed\n");
2034     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
2035     ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2036 
2037     DestroyMenu( hmenu );
2038     DestroyMenu( hmenuSub );
2039 
2040     /*
2041         Case 3: Menu containing a popup menu which in turn
2042            contains 2 items with the same id as the popup itself
2043      */
2044 
2045     hmenu = CreateMenu();
2046     hmenuSub = CreateMenu();
2047 
2048     memset( &info, 0, sizeof info );
2049     info.cbSize = sizeof info;
2050     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
2051     info.fType = MFT_STRING;
2052     info.dwTypeData = menuitem;
2053     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
2054 
2055     rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
2056     ok (rc, "Inserting the popup menu into the main menu failed\n");
2057 
2058     rc = InsertMenuItemA(hmenuSub, 0, TRUE, &info );
2059     ok (rc, "Inserting the sub menu menuitem failed\n");
2060 
2061     memset( &info, 0, sizeof info );
2062     info.cbSize = sizeof info;
2063     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
2064     info.fType = MFT_STRING;
2065     info.dwTypeData = menuitem2;
2066     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
2067 
2068     rc = InsertMenuItemA(hmenuSub, 1, TRUE, &info );
2069     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
2070 
2071     /* Prove that you can't query the id of a popup directly (By position) */
2072     id = GetMenuItemID(hmenu, 0);
2073     ok (id == -1, "Getting the sub menu id should have failed because it's a popup (gave %x)\n", id);
2074 
2075     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
2076     memset( &info, 0, sizeof info );
2077     strback[0] = 0x00;
2078     info.cbSize = sizeof(MENUITEMINFOA);
2079     info.fMask = MIIM_STRING | MIIM_ID;
2080     info.dwTypeData = strback;
2081     info.cch = sizeof(strback);
2082 
2083     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
2084     ok (rc, "Getting the menus info failed\n");
2085     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
2086     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2087     DestroyMenu( hmenu );
2088     DestroyMenu( hmenuSub );
2089 
2090     /*
2091         Case 4: Menu containing 2 popup menus, the second
2092            contains 2 items with the same id as the first popup menu
2093      */
2094     hmenu = CreateMenu();
2095     hmenuSub = CreateMenu();
2096     hmenuSub2 = CreateMenu();
2097 
2098     rc = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
2099     ok (rc, "Inserting the popup menu into the main menu failed\n");
2100 
2101     rc = InsertMenuA(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
2102     ok (rc, "Inserting the popup menu into the main menu failed\n");
2103 
2104     memset( &info, 0, sizeof info );
2105     info.cbSize = sizeof info;
2106     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
2107     info.fType = MFT_STRING;
2108     info.dwTypeData = menuitem;
2109     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
2110 
2111     rc = InsertMenuItemA(hmenuSub2, 0, TRUE, &info );
2112     ok (rc, "Inserting the sub menu menuitem failed\n");
2113 
2114     memset( &info, 0, sizeof info );
2115     info.cbSize = sizeof info;
2116     info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
2117     info.fType = MFT_STRING;
2118     info.dwTypeData = menuitem2;
2119     info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
2120 
2121     rc = InsertMenuItemA(hmenuSub2, 1, TRUE, &info );
2122     ok (rc, "Inserting the sub menu menuitem 2 failed\n");
2123 
2124     /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
2125     memset( &info, 0, sizeof info );
2126     strback[0] = 0x00;
2127     info.cbSize = sizeof(MENUITEMINFOA);
2128     info.fMask = MIIM_STRING | MIIM_ID;
2129     info.dwTypeData = strback;
2130     info.cch = sizeof(strback);
2131 
2132     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
2133     ok (rc, "Getting the menus info failed\n");
2134     ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
2135     ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2136 
2137     memset( &info, 0, sizeof info );
2138     strback[0] = 0x00;
2139     info.cbSize = sizeof(MENUITEMINFOA);
2140     info.fMask = MIIM_STRING | MIIM_ID;
2141     info.dwTypeData = strback;
2142     info.cch = sizeof(strback);
2143 
2144     rc = GetMenuItemInfoA(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
2145     ok (rc, "Getting the menus info failed\n");
2146     ok (info.wID == (UINT_PTR)hmenuSub2, "IDs differ for popup menu\n");
2147     ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2148 
2149     DestroyMenu( hmenu );
2150     DestroyMenu( hmenuSub );
2151     DestroyMenu( hmenuSub2 );
2152 
2153 
2154     /*
2155         Case 5: Menu containing a popup menu which in turn
2156            contains an item with a different id than the popup menu.
2157            This tests the fallback to a popup menu ID.
2158      */
2159 
2160     hmenu = CreateMenu();
2161     hmenuSub = CreateMenu();
2162 
2163     rc = AppendMenuA(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
2164     ok (rc, "Appending the popup menu to the main menu failed\n");
2165 
2166     rc = AppendMenuA(hmenuSub, MF_STRING, 102, "Item");
2167     ok (rc, "Appending the item to the popup menu failed\n");
2168 
2169     /* Set the ID for hmenuSub */
2170     info.cbSize = sizeof(info);
2171     info.fMask = MIIM_ID;
2172     info.wID = 101;
2173 
2174     rc = SetMenuItemInfoA(hmenu, 0, TRUE, &info);
2175     ok(rc, "Setting the ID for the popup menu failed\n");
2176 
2177     /* Check if the ID has been set */
2178     info.wID = 0;
2179     rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info);
2180     ok(rc, "Getting the ID for the popup menu failed\n");
2181     ok(info.wID == 101, "The ID for the popup menu has not been set\n");
2182 
2183     /* Prove getting the item info via ID returns the popup menu */
2184     memset( &info, 0, sizeof(info));
2185     strback[0] = 0x00;
2186     info.cbSize = sizeof(MENUITEMINFOA);
2187     info.fMask = MIIM_STRING | MIIM_ID;
2188     info.dwTypeData = strback;
2189     info.cch = sizeof(strback);
2190 
2191     rc = GetMenuItemInfoA(hmenu, 101, FALSE, &info);
2192     ok (rc, "Getting the menu info failed\n");
2193     ok (info.wID == 101, "IDs differ\n");
2194     ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2195 
2196     /* Also look for the menu item  */
2197     memset( &info, 0, sizeof(info));
2198     strback[0] = 0x00;
2199     info.cbSize = sizeof(MENUITEMINFOA);
2200     info.fMask = MIIM_STRING | MIIM_ID;
2201     info.dwTypeData = strback;
2202     info.cch = sizeof(strback);
2203 
2204     rc = GetMenuItemInfoA(hmenu, 102, FALSE, &info);
2205     ok (rc, "Getting the menu info failed\n");
2206     ok (info.wID == 102, "IDs differ\n");
2207     ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
2208 
2209     DestroyMenu(hmenu);
2210     DestroyMenu(hmenuSub);
2211 }
2212 
2213 struct menu_item_pair_s {
2214     UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
2215                  * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
2216                  * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
2217     UINT uItem;
2218 };
2219 
2220 static struct menu_mouse_tests_s {
2221     DWORD type;
2222     struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
2223     WORD wVk[5]; /* keys */
2224     BOOL bMenuVisible;
2225     BOOL _todo_wine;
2226 } menu_tests[] = {
2227     /* for each test, send keys or clicks and check for menu visibility */
2228     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, /* test 0 */
2229     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
2230     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE },
2231     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
2232     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE },
2233     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
2234     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE },
2235     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
2236     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
2237     { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
2238     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE },
2239     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
2240     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE },
2241     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
2242     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE },
2243     { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
2244     { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE },
2245     { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
2246     { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, TRUE, FALSE },
2247     { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, FALSE, FALSE },
2248 
2249     { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, FALSE }, /* test 20 */
2250     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
2251     { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, FALSE },
2252     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
2253     { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, FALSE },
2254     { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
2255     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, FALSE },
2256     { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
2257     { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, FALSE },
2258     { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, FALSE },
2259     { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
2260     { -1 }
2261 };
2262 
2263 static void send_key(WORD wVk)
2264 {
2265     TEST_INPUT i[2];
2266     memset(i, 0, sizeof(i));
2267     i[0].type = i[1].type = INPUT_KEYBOARD;
2268     i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
2269     i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
2270     SendInput(2, (INPUT *) i, sizeof(INPUT));
2271 }
2272 
2273 static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
2274 {
2275     HMENU hMenu = hMenus[mi->uMenu];
2276     TEST_INPUT i[3];
2277     MSG msg;
2278     RECT r;
2279     int screen_w = GetSystemMetrics(SM_CXSCREEN);
2280     int screen_h = GetSystemMetrics(SM_CYSCREEN);
2281     BOOL ret = GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
2282     if(!ret) return FALSE;
2283 
2284     memset(i, 0, sizeof(i));
2285     i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
2286     i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
2287             = ((r.left + 5) * 65535) / screen_w;
2288     i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
2289             = ((r.top + 5) * 65535) / screen_h;
2290     i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
2291             = MOUSEEVENTF_ABSOLUTE;
2292     i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
2293     i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
2294     i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
2295     ret = SendInput(3, (INPUT *) i, sizeof(INPUT));
2296 
2297     /* hack to prevent mouse message buildup in Wine */
2298     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2299     return ret;
2300 }
2301 
2302 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
2303 {
2304     int i, j;
2305     HANDLE hWnd = lpParameter;
2306 
2307     Sleep(500);
2308     /* mixed keyboard/mouse test */
2309     for (i = 0; menu_tests[i].type != -1; i++)
2310     {
2311         BOOL ret = TRUE;
2312         int elapsed;
2313 
2314         got_input = i && menu_tests[i-1].bMenuVisible;
2315 
2316         if (menu_tests[i].type == INPUT_KEYBOARD)
2317             for (j = 0; menu_tests[i].wVk[j] != 0; j++)
2318                 send_key(menu_tests[i].wVk[j]);
2319         else
2320             for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
2321             {
2322                 /* Maybe clicking too fast before menu is initialized. Sleep 100 ms and retry */
2323                 elapsed = 0;
2324                 while (!(ret = click_menu(hWnd, &menu_tests[i].menu_item_pairs[j])))
2325                 {
2326                     if (elapsed > 1000) break;
2327                     elapsed += 100;
2328                     Sleep(100);
2329                 }
2330             }
2331 
2332         if (!ret)
2333         {
2334             skip( "test %u: failed to send input\n", i );
2335             PostMessageA( hWnd, WM_CANCELMODE, 0, 0 );
2336             return 0;
2337         }
2338 
2339         elapsed = 0;
2340         while (menu_tests[i].bMenuVisible != bMenuVisible)
2341         {
2342             if (elapsed > 200)
2343                 break;
2344             elapsed += 20;
2345             Sleep(20);
2346         }
2347 
2348         if (!got_input)
2349         {
2350             skip( "test %u: didn't receive input\n", i );
2351             PostMessageA( hWnd, WM_CANCELMODE, 0, 0 );
2352             return 0;
2353         }
2354 
2355         todo_wine_if (menu_tests[i]._todo_wine)
2356             ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
2357     }
2358     return 0;
2359 }
2360 
2361 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
2362         LPARAM lParam)
2363 {
2364     MENUBARINFO mbi;
2365     HMENU hmenu;
2366     UINT state;
2367     BOOL br;
2368 
2369     switch (msg) {
2370         case WM_ENTERMENULOOP:
2371             bMenuVisible = TRUE;
2372             break;
2373         case WM_INITMENUPOPUP:
2374         case WM_UNINITMENUPOPUP:
2375         case WM_EXITMENULOOP:
2376         case WM_MENUSELECT:
2377             break;
2378 
2379         case WM_KEYDOWN:
2380         case WM_SYSKEYDOWN:
2381         case WM_MOUSEMOVE:
2382         case WM_LBUTTONDOWN:
2383         case WM_LBUTTONUP:
2384         case WM_NCMOUSEMOVE:
2385         case WM_NCLBUTTONDOWN:
2386         case WM_NCLBUTTONUP:
2387             got_input = TRUE;
2388             /* fall through */
2389         default:
2390             return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
2391     }
2392 
2393     mbi.cbSize = sizeof(MENUBARINFO);
2394 
2395     /* get info for the menu */
2396     br = GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi);
2397     ok(br, "msg %x: GetMenuBarInfo failed\n", msg);
2398     hmenu = GetMenu(hWnd);
2399     ok(!mbi.hwndMenu, "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected NULL\n",
2400             msg, mbi.hwndMenu);
2401     ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n",
2402             msg, mbi.hMenu, hmenu);
2403     ok(!bMenuVisible == !mbi.fBarFocused, "msg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n",
2404             msg, mbi.fBarFocused != 0);
2405     ok(!bMenuVisible == !mbi.fFocused, "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n",
2406             msg, mbi.fFocused != 0);
2407 
2408     /* get info for the menu's first item */
2409     br = GetMenuBarInfo(hWnd, OBJID_MENU, 1, &mbi);
2410     ok(br, "msg %x: GetMenuBarInfo failed\n", msg);
2411     state = GetMenuState(hmenu, 0, MF_BYPOSITION);
2412     /* Native returns handle to destroyed window */
2413     todo_wine_if (msg==WM_UNINITMENUPOPUP && popmenu==1)
2414         ok(!mbi.hwndMenu == !popmenu,
2415             "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected %sNULL\n",
2416             msg, mbi.hwndMenu, popmenu ? "not " : "");
2417     ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n",
2418             msg, mbi.hMenu, hmenu);
2419     ok(!bMenuVisible == !mbi.fBarFocused, "nsg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n",
2420             msg, mbi.fBarFocused != 0);
2421     ok(!(bMenuVisible && (state & MF_HILITE)) == !mbi.fFocused,
2422             "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", msg, mbi.fFocused != 0);
2423 
2424     if (msg == WM_EXITMENULOOP)
2425         bMenuVisible = FALSE;
2426     else if (msg == WM_INITMENUPOPUP)
2427         popmenu++;
2428     else if (msg == WM_UNINITMENUPOPUP)
2429         popmenu--;
2430     return 0;
2431 }
2432 
2433 static void test_menu_input(void) {
2434     MSG msg;
2435     WNDCLASSA  wclass;
2436     HINSTANCE hInstance = GetModuleHandleA( NULL );
2437     HANDLE hThread, hWnd;
2438     DWORD tid;
2439     ATOM aclass;
2440     POINT orig_pos;
2441 
2442     wclass.lpszClassName = "MenuTestClass";
2443     wclass.style         = CS_HREDRAW | CS_VREDRAW;
2444     wclass.lpfnWndProc   = WndProc;
2445     wclass.hInstance     = hInstance;
2446     wclass.hIcon         = LoadIconA( 0, (LPCSTR)IDI_APPLICATION );
2447     wclass.hCursor       = LoadCursorA( 0, (LPCSTR)IDC_ARROW );
2448     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
2449     wclass.lpszMenuName  = 0;
2450     wclass.cbClsExtra    = 0;
2451     wclass.cbWndExtra    = 0;
2452     aclass = RegisterClassA( &wclass );
2453     ok (aclass, "MenuTest class not created\n");
2454     if (!aclass) return;
2455     hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
2456                           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
2457                           400, 200, NULL, NULL, hInstance, NULL);
2458     ok (hWnd != NULL, "MenuTest window not created\n");
2459     if (!hWnd) return;
2460     /* fixed menus */
2461     hMenus[3] = CreatePopupMenu();
2462     AppendMenuA(hMenus[3], MF_STRING, 0, "&Enabled");
2463     AppendMenuA(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
2464 
2465     hMenus[2] = CreatePopupMenu();
2466     AppendMenuA(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
2467     AppendMenuA(hMenus[2], MF_STRING, 0, "&Enabled");
2468     AppendMenuA(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
2469 
2470     hMenus[1] = CreateMenu();
2471     AppendMenuA(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
2472     AppendMenuA(hMenus[1], MF_STRING, 0, "&Enabled");
2473     AppendMenuA(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
2474 
2475     SetMenu(hWnd, hMenus[1]);
2476     ShowWindow(hWnd, SW_SHOW);
2477     UpdateWindow(hWnd);
2478 
2479     GetCursorPos(&orig_pos);
2480 
2481     hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid);
2482     while(1)
2483     {
2484         if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
2485             break;
2486         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2487     }
2488     SetCursorPos(orig_pos.x, orig_pos.y);
2489     DestroyWindow(hWnd);
2490 }
2491 
2492 static void test_menu_flags( void )
2493 {
2494     HMENU hMenu, hPopupMenu;
2495 
2496     hMenu = CreateMenu();
2497     hPopupMenu = CreatePopupMenu();
2498 
2499     AppendMenuA(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup");
2500 
2501     AppendMenuA(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
2502     InsertMenuA(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
2503     AppendMenuA(hPopupMenu, MF_STRING, 103, "Item 3");
2504     ModifyMenuA(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
2505 
2506     ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
2507       "AppendMenu should accept MF_HILITE\n");
2508     ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
2509       "InsertMenu should accept MF_HILITE\n");
2510     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2511       "ModifyMenu should accept MF_HILITE\n");
2512 
2513     ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
2514       "AppendMenu must not accept MF_DEFAULT\n");
2515     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
2516       "InsertMenu must not accept MF_DEFAULT\n");
2517     ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
2518       "ModifyMenu must not accept MF_DEFAULT\n");
2519 
2520     DestroyMenu(hMenu);
2521 }
2522 
2523 static void test_menu_hilitemenuitem( void )
2524 {
2525     HMENU hMenu, hPopupMenu;
2526     WNDCLASSA wclass;
2527     HWND hWnd;
2528     ATOM aclass;
2529 
2530     wclass.lpszClassName = "HiliteMenuTestClass";
2531     wclass.style         = CS_HREDRAW | CS_VREDRAW;
2532     wclass.lpfnWndProc   = WndProc;
2533     wclass.hInstance     = GetModuleHandleA( NULL );
2534     wclass.hIcon         = LoadIconA( 0, (LPCSTR)IDI_APPLICATION );
2535     wclass.hCursor       = LoadCursorA( 0, (LPCSTR)IDC_ARROW );
2536     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
2537     wclass.lpszMenuName  = 0;
2538     wclass.cbClsExtra    = 0;
2539     wclass.cbWndExtra    = 0;
2540     aclass = RegisterClassA( &wclass );
2541     ok (aclass, "HiliteMenuTest class could not be created\n");
2542     if (!aclass) return;
2543     hWnd = CreateWindowA( wclass.lpszClassName, "HiliteMenuTest",
2544                           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
2545                           400, 200, NULL, NULL, wclass.hInstance, NULL);
2546     ok (hWnd != NULL, "HiliteMenuTest window could not be created\n");
2547     if (!hWnd) return;
2548 
2549     hMenu = CreateMenu();
2550     hPopupMenu = CreatePopupMenu();
2551 
2552     AppendMenuA(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup");
2553 
2554     AppendMenuA(hPopupMenu, MF_STRING, 101, "Item 1");
2555     AppendMenuA(hPopupMenu, MF_STRING, 102, "Item 2");
2556     AppendMenuA(hPopupMenu, MF_STRING, 103, "Item 3");
2557 
2558     SetMenu(hWnd, hMenu);
2559 
2560     /* test invalid arguments */
2561 
2562     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2563       "HiliteMenuItem: Item 2 is hilited\n");
2564 
2565     SetLastError(0xdeadbeef);
2566     todo_wine
2567     {
2568     ok(!HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION),
2569       "HiliteMenuItem: call should have failed.\n");
2570     }
2571     ok(GetLastError() == 0xdeadbeef || /* 9x */
2572        GetLastError() == ERROR_INVALID_WINDOW_HANDLE /* NT */,
2573       "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError());
2574 
2575     SetLastError(0xdeadbeef);
2576     ok(!HiliteMenuItem(hWnd, NULL, 1, MF_HILITE | MF_BYPOSITION),
2577       "HiliteMenuItem: call should have failed.\n");
2578     ok(GetLastError() == 0xdeadbeef || /* 9x */
2579        GetLastError() == ERROR_INVALID_MENU_HANDLE /* NT */,
2580       "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError());
2581 
2582     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2583       "HiliteMenuItem: Item 2 is hilited\n");
2584 
2585     /* either MF_HILITE or MF_UNHILITE *and* MF_BYCOMMAND or MF_BYPOSITION need to be set */
2586 
2587     SetLastError(0xdeadbeef);
2588     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_BYPOSITION),
2589       "HiliteMenuItem: call should have succeeded.\n");
2590     ok(GetLastError() == 0xdeadbeef,
2591       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2592 
2593     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2594       "HiliteMenuItem: Item 2 is hilited\n");
2595 
2596     SetLastError(0xdeadbeef);
2597     todo_wine
2598     {
2599     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE),
2600       "HiliteMenuItem: call should have succeeded.\n");
2601     }
2602     ok(GetLastError() == 0xdeadbeef,
2603       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2604 
2605     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2606       "HiliteMenuItem: Item 2 is hilited\n");
2607 
2608     /* hilite a menu item (by position) */
2609 
2610     SetLastError(0xdeadbeef);
2611     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION),
2612       "HiliteMenuItem: call should not have failed.\n");
2613     ok(GetLastError() == 0xdeadbeef,
2614       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2615 
2616     todo_wine
2617     {
2618     ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
2619       "HiliteMenuItem: Item 2 is not hilited\n");
2620     }
2621 
2622     /* unhilite a menu item (by position) */
2623 
2624     SetLastError(0xdeadbeef);
2625     ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_UNHILITE | MF_BYPOSITION),
2626       "HiliteMenuItem: call should not have failed.\n");
2627     ok(GetLastError() == 0xdeadbeef,
2628       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2629 
2630     ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2631       "HiliteMenuItem: Item 2 is hilited\n");
2632 
2633     /* hilite a menu item (by command) */
2634 
2635     SetLastError(0xdeadbeef);
2636     ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_HILITE | MF_BYCOMMAND),
2637       "HiliteMenuItem: call should not have failed.\n");
2638     ok(GetLastError() == 0xdeadbeef,
2639       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2640 
2641     todo_wine
2642     {
2643     ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2644       "HiliteMenuItem: Item 3 is not hilited\n");
2645     }
2646 
2647     /* unhilite a menu item (by command) */
2648 
2649     SetLastError(0xdeadbeef);
2650     ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_UNHILITE | MF_BYCOMMAND),
2651       "HiliteMenuItem: call should not have failed.\n");
2652     ok(GetLastError() == 0xdeadbeef,
2653       "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError());
2654 
2655     ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE),
2656       "HiliteMenuItem: Item 3 is hilited\n");
2657 
2658     DestroyWindow(hWnd);
2659 }
2660 
2661 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
2662                              UINT checked_state)
2663 {
2664     INT i, count;
2665 
2666     count = GetMenuItemCount(hmenu);
2667     ok (count != -1, "GetMenuItemCount returned -1\n");
2668 
2669     for (i = 0; i < count; i++)
2670     {
2671         BOOL ret;
2672         MENUITEMINFOA mii;
2673 
2674         memset(&mii, 0, sizeof(mii));
2675         mii.cbSize = sizeof(mii);
2676         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
2677         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
2678         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2679 
2680         if (winetest_debug > 1)
2681             trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2682                   i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
2683 
2684         if (mii.hSubMenu)
2685         {
2686             ok(mii.wID == (UINT_PTR)mii.hSubMenu, "id %u: wID %x should be equal to hSubMenu %p\n",
2687                checked_cmd, mii.wID, mii.hSubMenu);
2688             if (!GetMenuItemCount(mii.hSubMenu))
2689             {
2690                 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType);
2691                 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState);
2692             }
2693             check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state);
2694         }
2695         else
2696         {
2697             if (mii.wID == checked_cmd)
2698             {
2699                 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType);
2700                 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState);
2701                 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2702             }
2703             else
2704             {
2705                 ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID);
2706 
2707                 if (mii.fType == MFT_SEPARATOR)
2708                 {
2709                     ok(mii.fState == MFS_GRAYED, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd, mii.fState);
2710                     ok(mii.wID == 0, "id %u: expected wID 0, got %u\n", checked_cmd, mii.wID);
2711                 }
2712                 else
2713                 {
2714                     ok(mii.fState == 0, "id %u: expected fState 0, got %04x\n", checked_cmd, mii.fState);
2715                     ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2716                 }
2717             }
2718         }
2719     }
2720 }
2721 
2722 static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags)
2723 {
2724     BOOL ret;
2725     MENUITEMINFOA mii;
2726 
2727     memset(&mii, 0, sizeof(mii));
2728     mii.cbSize = sizeof(mii);
2729     mii.fMask  = MIIM_FTYPE | MIIM_STATE;
2730     ret = SetMenuItemInfoA(hmenu, id, (flags & MF_BYPOSITION) != 0, &mii);
2731     ok(ret, "SetMenuItemInfo(%u) failed\n", id);
2732 }
2733 
2734 static void test_CheckMenuRadioItem(void)
2735 {
2736     BOOL ret;
2737     HMENU hmenu;
2738 
2739     hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
2740     assert(hmenu != 0);
2741 
2742     check_menu_items(hmenu, -1, 0, 0);
2743 
2744     ret = CheckMenuRadioItem(hmenu, 100, 100, 100, MF_BYCOMMAND);
2745     ok(ret, "CheckMenuRadioItem failed\n");
2746     check_menu_items(hmenu, 100, MFT_RADIOCHECK, MFS_CHECKED);
2747 
2748     /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2749     ret = CheckMenuRadioItem(hmenu, 100, 100, -1, MF_BYCOMMAND);
2750     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2751     check_menu_items(hmenu, 100, MFT_RADIOCHECK, 0);
2752 
2753     /* clear check */
2754     clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND);
2755     check_menu_items(hmenu, -1, 0, 0);
2756 
2757     /* first and checked items are on different menus */
2758     ret = CheckMenuRadioItem(hmenu, 0, 300, 202, MF_BYCOMMAND);
2759     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2760     check_menu_items(hmenu, -1, 0, 0);
2761 
2762     ret = CheckMenuRadioItem(hmenu, 200, 300, 202, MF_BYCOMMAND);
2763     ok(ret, "CheckMenuRadioItem failed\n");
2764     check_menu_items(hmenu, 202, MFT_RADIOCHECK, MFS_CHECKED);
2765 
2766     /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2767     ret = CheckMenuRadioItem(hmenu, 202, 202, -1, MF_BYCOMMAND);
2768     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2769     check_menu_items(hmenu, 202, MFT_RADIOCHECK, 0);
2770 
2771     /* clear check */
2772     clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND);
2773     check_menu_items(hmenu, -1, 0, 0);
2774 
2775     /* just for fun, try to check separator */
2776     ret = CheckMenuRadioItem(hmenu, 0, 300, 0, MF_BYCOMMAND);
2777     ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2778     check_menu_items(hmenu, -1, 0, 0);
2779 }
2780 
2781 static void test_menu_resource_layout(void)
2782 {
2783     static const struct
2784     {
2785         MENUITEMTEMPLATEHEADER mith;
2786         WORD data[14];
2787     } menu_template =
2788     {
2789         { 0, 0 }, /* versionNumber, offset */
2790         {
2791             /* mtOption, mtID, mtString[] '\0' terminated */
2792             MF_STRING, 1, 'F', 0,
2793             MF_STRING, 2, 0,
2794             MF_SEPARATOR, 3, 0,
2795             /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2796             MF_STRING|MF_GRAYED|MF_END, 5, 'E', 0
2797         }
2798     };
2799     static const struct
2800     {
2801         UINT type, state, id;
2802         const char *str;
2803     } menu_data[] =
2804     {
2805         { MF_STRING, MF_ENABLED, 1, "F" },
2806         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 2, "" },
2807         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 3, "" },
2808         /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/
2809         { MF_STRING, MF_GRAYED, 5, "E" },
2810         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 6, "" },
2811         { MF_STRING, MF_ENABLED, 7, "" },
2812         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" }
2813     };
2814     HMENU hmenu;
2815     INT count, i;
2816     BOOL ret;
2817 
2818     hmenu = LoadMenuIndirectA(&menu_template);
2819     ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError());
2820 
2821     ret = AppendMenuA(hmenu, MF_STRING, 6, NULL);
2822     ok(ret, "AppendMenu failed\n");
2823     ret = AppendMenuA(hmenu, MF_STRING, 7, "\0");
2824     ok(ret, "AppendMenu failed\n");
2825     ret = AppendMenuA(hmenu, MF_SEPARATOR, 8, "separator");
2826     ok(ret, "AppendMenu failed\n");
2827 
2828     count = GetMenuItemCount(hmenu);
2829     ok(count == ARRAY_SIZE(menu_data), "expected %u menu items, got %u\n",
2830        (UINT) ARRAY_SIZE(menu_data), count);
2831 
2832     for (i = 0; i < count; i++)
2833     {
2834         char buf[20];
2835         MENUITEMINFOA mii;
2836 
2837         memset(&mii, 0, sizeof(mii));
2838         mii.cbSize = sizeof(mii);
2839         mii.dwTypeData = buf;
2840         mii.cch = sizeof(buf);
2841         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_STRING;
2842         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
2843         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2844         if (winetest_debug > 1)
2845             trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2846                   i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
2847 
2848         ok(mii.fType == menu_data[i].type,
2849            "%u: expected fType %04x, got %04x\n", i, menu_data[i].type, mii.fType);
2850         ok(mii.fState == menu_data[i].state,
2851            "%u: expected fState %04x, got %04x\n", i, menu_data[i].state, mii.fState);
2852         ok(mii.wID == menu_data[i].id,
2853            "%u: expected wID %04x, got %04x\n", i, menu_data[i].id, mii.wID);
2854         ok(mii.cch == strlen(menu_data[i].str),
2855            "%u: expected cch %u, got %u\n", i, (UINT)strlen(menu_data[i].str), mii.cch);
2856         ok(!strcmp(mii.dwTypeData, menu_data[i].str),
2857            "%u: expected dwTypeData %s, got %s\n", i, menu_data[i].str, (LPCSTR)mii.dwTypeData);
2858     }
2859 
2860     DestroyMenu(hmenu);
2861 }
2862 
2863 struct menu_data
2864 {
2865     UINT type, id;
2866     const char *str;
2867 };
2868 
2869 static HMENU create_menu_from_data(const struct menu_data *item, INT item_count)
2870 {
2871     HMENU hmenu;
2872     INT i;
2873     BOOL ret;
2874 
2875     hmenu = CreateMenu();
2876     assert(hmenu != 0);
2877 
2878     for (i = 0; i < item_count; i++)
2879     {
2880         SetLastError(0xdeadbeef);
2881         ret = AppendMenuA(hmenu, item[i].type, item[i].id, item[i].str);
2882         ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %u\n",
2883            i, item[i].type, item[i].id, item[i].str, GetLastError());
2884     }
2885     return hmenu;
2886 }
2887 
2888 /* use InsertMenuItem: does not set the MFT_BITMAP flag,
2889  * and does not accept non-magic bitmaps with invalid
2890  * bitmap handles */
2891 static HMENU create_menuitem_from_data(const struct menu_data *item, INT item_count)
2892 {
2893     HMENU hmenu;
2894     INT i;
2895     BOOL ret;
2896     MENUITEMINFOA mii = { sizeof( MENUITEMINFOA) };
2897 
2898     hmenu = CreateMenu();
2899     assert(hmenu != 0);
2900 
2901     for (i = 0; i < item_count; i++)
2902     {
2903         SetLastError(0xdeadbeef);
2904 
2905         mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE;
2906         mii.fType = 0;
2907         if(  item[i].type & MFT_BITMAP)
2908         {
2909             mii.fMask |= MIIM_BITMAP;
2910             mii.hbmpItem =  (HBITMAP)item[i].str;
2911         }
2912         else if(  item[i].type & MFT_SEPARATOR)
2913             mii.fType = MFT_SEPARATOR;
2914         else
2915         {
2916             mii.fMask |= MIIM_STRING;
2917             mii.dwTypeData =  (LPSTR)item[i].str;
2918             mii.cch = strlen(  item[i].str);
2919         }
2920         mii.fState = 0;
2921         if(  item[i].type & MF_HELP) mii.fType |= MF_HELP;
2922         mii.wID = item[i].id;
2923         ret = InsertMenuItemA( hmenu, -1, TRUE, &mii);
2924         ok(ret, "%d: InsertMenuItem(%04x, %04x, %p) error %u\n",
2925            i, item[i].type, item[i].id, item[i].str, GetLastError());
2926     }
2927     return hmenu;
2928 }
2929 
2930 static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count)
2931 {
2932     INT count, i;
2933     BOOL ret;
2934 
2935     count = GetMenuItemCount(hmenu);
2936     ok(count == item_count, "expected %d, got %d menu items\n", count, item_count);
2937 
2938     for (i = 0; i < count; i++)
2939     {
2940         char buf[20];
2941         MENUITEMINFOA mii;
2942 
2943         memset(&mii, 0, sizeof(mii));
2944         mii.cbSize = sizeof(mii);
2945         mii.dwTypeData = buf;
2946         mii.cch = sizeof(buf);
2947         mii.fMask  = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_BITMAP;
2948         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
2949         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2950 
2951         if (winetest_debug > 1)
2952             trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2953                   i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
2954 
2955         ok(mii.fType == item[i].type,
2956            "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType);
2957         ok(mii.wID == item[i].id,
2958            "%u: expected wID %04x, got %04x\n", i, item[i].id, mii.wID);
2959         if (mii.hbmpItem || !item[i].str)
2960             /* For some reason Windows sets high word to not 0 for
2961              * not "magic" ids.
2962              */
2963             ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str),
2964                "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem);
2965         else
2966         {
2967             ok(mii.cch == strlen(item[i].str),
2968                "%u: expected cch %u, got %u\n", i, (UINT)strlen(item[i].str), mii.cch);
2969             ok(!strcmp(mii.dwTypeData, item[i].str),
2970                "%u: expected dwTypeData %s, got %s\n", i, item[i].str, (LPCSTR)mii.dwTypeData);
2971         }
2972     }
2973 }
2974 
2975 static void test_InsertMenu(void)
2976 {
2977     HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
2978     /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2979      * regardless of their id.
2980      */
2981     static const struct menu_data in1[] =
2982     {
2983         { MF_STRING, 1, "File" },
2984         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) },
2985         { MF_STRING|MF_HELP, 2, "Help" }
2986     };
2987     static const struct menu_data out1[] =
2988     {
2989         { MF_STRING, 1, "File" },
2990         { MF_STRING|MF_HELP, 2, "Help" },
2991         { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) }
2992     };
2993     static const struct menu_data out1a[] =
2994     {
2995         { MF_STRING, 1, "File" },
2996         { MF_STRING|MF_HELP, 2, "Help" },
2997         { MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) }
2998     };
2999     const struct menu_data in2[] =
3000     {
3001         { MF_STRING, 1, "File" },
3002         { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm },
3003         { MF_STRING|MF_HELP, 2, "Help" }
3004     };
3005     const struct menu_data out2[] =
3006     {
3007         { MF_STRING, 1, "File" },
3008         { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm },
3009         { MF_STRING|MF_HELP, 2, "Help" }
3010     };
3011     const struct menu_data out2a[] =
3012     {
3013         { MF_STRING, 1, "File" },
3014         { MF_HELP, SC_CLOSE, (char*)hbm },
3015         { MF_STRING|MF_HELP, 2, "Help" }
3016     };
3017     static const struct menu_data in3[] =
3018     {
3019         { MF_STRING, 1, "File" },
3020         { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(1) },
3021         { MF_STRING|MF_HELP, 2, "Help" }
3022     };
3023     static const struct menu_data out3[] =
3024     {
3025         { MF_STRING, 1, "File" },
3026         { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCEA(0) },
3027         { MF_STRING|MF_HELP, 2, "Help" },
3028     };
3029     static const struct menu_data in4[] =
3030     {
3031         { MF_STRING, 1, "File" },
3032         { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCEA(1) },
3033         { MF_STRING|MF_HELP, 2, "Help" }
3034     };
3035     static const struct menu_data out4[] =
3036     {
3037         { MF_STRING, 1, "File" },
3038         { MF_STRING|MF_HELP, 2, "Help" },
3039         { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCEA(1) }
3040     };
3041     static const struct menu_data out4a[] =
3042     {
3043         { MF_STRING, 1, "File" },
3044         { MF_STRING|MF_HELP, 2, "Help" },
3045         { MF_HELP, 1, MAKEINTRESOURCEA(1) }
3046     };
3047     HMENU hmenu;
3048 
3049 #define create_menu(a) create_menu_from_data((a), ARRAY_SIZE(a))
3050 #define create_menuitem(a) create_menuitem_from_data((a), ARRAY_SIZE(a))
3051 #define compare_menu(h, a) compare_menu_data((h), (a), ARRAY_SIZE(a))
3052 
3053     hmenu = create_menu(in1);
3054     compare_menu(hmenu, out1);
3055     DestroyMenu(hmenu);
3056 
3057     hmenu = create_menu(in2);
3058     compare_menu(hmenu, out2);
3059     DestroyMenu(hmenu);
3060 
3061     hmenu = create_menu(in3);
3062     compare_menu(hmenu, out3);
3063     DestroyMenu(hmenu);
3064 
3065     hmenu = create_menu(in4);
3066     compare_menu(hmenu, out4);
3067     DestroyMenu(hmenu);
3068 
3069     /* now using InsertMenuItemInfo */
3070     hmenu = create_menuitem(in1);
3071     compare_menu(hmenu, out1a);
3072     DestroyMenu(hmenu);
3073 
3074     hmenu = create_menuitem(in2);
3075     compare_menu(hmenu, out2a);
3076     DestroyMenu(hmenu);
3077 
3078     hmenu = create_menuitem(in3);
3079     compare_menu(hmenu, out3);
3080     DestroyMenu(hmenu);
3081 
3082     hmenu = create_menuitem(in4);
3083     compare_menu(hmenu, out4a);
3084     DestroyMenu(hmenu);
3085 
3086 #undef create_menu
3087 #undef create_menuitem
3088 #undef compare_menu
3089 }
3090 
3091 static void test_menu_getmenuinfo(void)
3092 {
3093     HMENU hmenu;
3094     MENUINFO mi = {0};
3095     BOOL ret;
3096     DWORD gle;
3097 
3098     /* create a menu */
3099     hmenu = CreateMenu();
3100     assert( hmenu);
3101     /* test some parameter errors */
3102     SetLastError(0xdeadbeef);
3103     ret = GetMenuInfo( hmenu, NULL);
3104     gle= GetLastError();
3105     ok( !ret, "GetMenuInfo() should have failed\n");
3106     ok( gle == ERROR_INVALID_PARAMETER ||
3107         broken(gle == 0xdeadbeef), /* Win98, WinME */
3108         "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3109     SetLastError(0xdeadbeef);
3110     mi.cbSize = 0;
3111     ret = GetMenuInfo( hmenu, &mi);
3112     gle= GetLastError();
3113     ok( !ret, "GetMenuInfo() should have failed\n");
3114     ok( gle == ERROR_INVALID_PARAMETER ||
3115         broken(gle == 0xdeadbeef), /* Win98, WinME */
3116         "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3117     SetLastError(0xdeadbeef);
3118     mi.cbSize = sizeof( MENUINFO);
3119     ret = GetMenuInfo( hmenu, &mi);
3120     gle= GetLastError();
3121     ok( ret, "GetMenuInfo() should have succeeded\n");
3122     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3123     SetLastError(0xdeadbeef);
3124     mi.cbSize = 0;
3125     ret = GetMenuInfo( NULL, &mi);
3126     gle= GetLastError();
3127     ok( !ret, "GetMenuInfo() should have failed\n");
3128     ok( gle == ERROR_INVALID_PARAMETER ||
3129         broken(gle == 0xdeadbeef), /* Win98, WinME */
3130         "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3131     /* clean up */
3132     DestroyMenu( hmenu);
3133     return;
3134 }
3135 
3136 static void test_menu_setmenuinfo(void)
3137 {
3138     HMENU hmenu, hsubmenu;
3139     MENUINFO mi = {0};
3140     MENUITEMINFOA mii = { sizeof(MENUITEMINFOA) };
3141     BOOL ret;
3142     DWORD gle;
3143     HBRUSH brush;
3144 
3145     /* create a menu with a submenu */
3146     hmenu = CreateMenu();
3147     hsubmenu = CreateMenu();
3148     assert( hmenu && hsubmenu);
3149     mii.fMask = MIIM_SUBMENU;
3150     mii.hSubMenu = hsubmenu;
3151     ret = InsertMenuItemA( hmenu, 0, FALSE, &mii);
3152     ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
3153     /* test some parameter errors */
3154     SetLastError(0xdeadbeef);
3155     ret = SetMenuInfo( hmenu, NULL);
3156     gle= GetLastError();
3157     ok( !ret, "SetMenuInfo() should have failed\n");
3158     ok( gle == ERROR_INVALID_PARAMETER ||
3159         broken(gle == 0xdeadbeef), /* Win98, WinME */
3160         "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3161     SetLastError(0xdeadbeef);
3162     mi.cbSize = 0;
3163     ret = SetMenuInfo( hmenu, &mi);
3164     gle= GetLastError();
3165     ok( !ret, "SetMenuInfo() should have failed\n");
3166     ok( gle == ERROR_INVALID_PARAMETER ||
3167         broken(gle == 0xdeadbeef), /* Win98, WinME */
3168         "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3169     SetLastError(0xdeadbeef);
3170     mi.cbSize = sizeof( MENUINFO);
3171     ret = SetMenuInfo( hmenu, &mi);
3172     gle= GetLastError();
3173     ok( ret, "SetMenuInfo() should have succeeded\n");
3174     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
3175     SetLastError(0xdeadbeef);
3176     mi.cbSize = 0;
3177     ret = SetMenuInfo( NULL, &mi);
3178     gle= GetLastError();
3179     ok( !ret, "SetMenuInfo() should have failed\n");
3180     ok( gle == ERROR_INVALID_PARAMETER ||
3181         broken(gle == 0xdeadbeef), /* Win98, WinME */
3182         "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER);
3183     /* functional tests */
3184     /* menu and submenu should have the CHECKORBMP style bit cleared */
3185     SetLastError(0xdeadbeef);
3186     mi.cbSize = sizeof( MENUINFO);
3187     mi.fMask = MIM_STYLE;
3188     ret = GetMenuInfo( hmenu, &mi);
3189     gle= GetLastError();
3190     ok( ret, "GetMenuInfo() should have succeeded\n");
3191     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3192     ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n");
3193     SetLastError(0xdeadbeef);
3194     mi.cbSize = sizeof( MENUINFO);
3195     mi.fMask = MIM_STYLE;
3196     ret = GetMenuInfo( hsubmenu, &mi);
3197     gle= GetLastError();
3198     ok( ret, "GetMenuInfo() should have succeeded\n");
3199     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3200     ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n");
3201     /* SetMenuInfo() */
3202     SetLastError(0xdeadbeef);
3203     mi.cbSize = sizeof( MENUINFO);
3204     mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS;
3205     mi.dwStyle = MNS_CHECKORBMP;
3206     ret = SetMenuInfo( hmenu, &mi);
3207     gle= GetLastError();
3208     ok( ret, "SetMenuInfo() should have succeeded\n");
3209     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
3210     /* Now both menus should have the MNS_CHECKORBMP style bit set */
3211     SetLastError(0xdeadbeef);
3212     mi.cbSize = sizeof( MENUINFO);
3213     mi.fMask = MIM_STYLE;
3214     ret = GetMenuInfo( hmenu, &mi);
3215     gle= GetLastError();
3216     ok( ret, "GetMenuInfo() should have succeeded\n");
3217     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3218     ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n");
3219     SetLastError(0xdeadbeef);
3220     mi.cbSize = sizeof( MENUINFO);
3221     mi.fMask = MIM_STYLE;
3222     ret = GetMenuInfo( hsubmenu, &mi);
3223     gle= GetLastError();
3224     ok( ret, "GetMenuInfo() should have succeeded\n");
3225     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3226     ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n");
3227     /* now repeat that without the APPLYTOSUBMENUS flag and another style bit */
3228     SetLastError(0xdeadbeef);
3229     mi.cbSize = sizeof( MENUINFO);
3230     mi.fMask = MIM_STYLE ;
3231     mi.dwStyle = MNS_NOCHECK;
3232     ret = SetMenuInfo( hmenu, &mi);
3233     gle= GetLastError();
3234     ok( ret, "SetMenuInfo() should have succeeded\n");
3235     ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle);
3236     /* Now only the top menu should have the MNS_NOCHECK style bit set */
3237     SetLastError(0xdeadbeef);
3238     mi.cbSize = sizeof( MENUINFO);
3239     mi.fMask = MIM_STYLE;
3240     ret = GetMenuInfo( hmenu, &mi);
3241     gle= GetLastError();
3242     ok( ret, "GetMenuInfo() should have succeeded\n");
3243     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3244     ok( mi.dwStyle & MNS_NOCHECK, "menustyle was expected to have the MNS_NOCHECK flag\n");
3245     SetLastError(0xdeadbeef);
3246     mi.cbSize = sizeof( MENUINFO);
3247     mi.fMask = MIM_STYLE;
3248     ret = GetMenuInfo( hsubmenu, &mi);
3249     gle= GetLastError();
3250     ok( ret, "GetMenuInfo() should have succeeded\n");
3251     ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle);
3252     ok( !(mi.dwStyle & MNS_NOCHECK), "menustyle was not expected to have the MNS_NOCHECK flag\n");
3253 
3254     /* test background brush */
3255     mi.cbSize = sizeof(mi);
3256     mi.fMask = MIM_BACKGROUND;
3257     ret = GetMenuInfo( hmenu, &mi );
3258     ok( ret, "GetMenuInfo() should have succeeded\n" );
3259     ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack );
3260 
3261     brush = CreateSolidBrush( RGB(0xff, 0, 0) );
3262     mi.hbrBack = brush;
3263     ret = SetMenuInfo( hmenu, &mi );
3264     ok( ret, "SetMenuInfo() should have succeeded\n" );
3265     mi.hbrBack = NULL;
3266     ret = GetMenuInfo( hmenu, &mi );
3267     ok( ret, "GetMenuInfo() should have succeeded\n" );
3268     ok( mi.hbrBack == brush, "got %p original %p\n", mi.hbrBack, brush );
3269 
3270     mi.hbrBack = NULL;
3271     ret = SetMenuInfo( hmenu, &mi );
3272     ok( ret, "SetMenuInfo() should have succeeded\n" );
3273     ret = GetMenuInfo( hmenu, &mi );
3274     ok( ret, "GetMenuInfo() should have succeeded\n" );
3275     ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack );
3276     DeleteObject( brush );
3277 
3278     /* clean up */
3279     DestroyMenu( hsubmenu);
3280     DestroyMenu( hmenu);
3281     return;
3282 }
3283 
3284 /* little func to easy switch either TrackPopupMenu() or TrackPopupMenuEx() */
3285 static DWORD MyTrackPopupMenu( int ex, HMENU hmenu, UINT flags, INT x, INT y, HWND hwnd, LPTPMPARAMS ptpm)
3286 {
3287     return ex
3288         ? TrackPopupMenuEx( hmenu, flags, x, y, hwnd, ptpm)
3289         : TrackPopupMenu( hmenu, flags, x, y, 0, hwnd, NULL);
3290 }
3291 
3292 /* some TrackPopupMenu and TrackPopupMenuEx tests */
3293 /* the LastError values differ between NO_ERROR and invalid handle */
3294 /* between all windows versions tested. The first value is that valid on XP  */
3295 /* Vista was the only that made returned different error values */
3296 /* between the TrackPopupMenu and TrackPopupMenuEx functions */
3297 static void test_menu_trackpopupmenu(void)
3298 {
3299     BOOL ret;
3300     HMENU hmenu;
3301     DWORD gle;
3302     int Ex;
3303     HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
3304             WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
3305             NULL, NULL, NULL, NULL);
3306     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
3307     if (!hwnd) return;
3308     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc);
3309     for( Ex = 0; Ex < 2; Ex++)
3310     {
3311         hmenu = CreatePopupMenu();
3312         ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
3313         if (!hmenu)
3314         {
3315             DestroyWindow(hwnd);
3316             return;
3317         }
3318         /* display the menu */
3319         /* start with an invalid menu handle */
3320         SetLastError(0xdeadbeef);
3321 
3322         gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
3323         ret = MyTrackPopupMenu( Ex, NULL, TPM_RETURNCMD, 100,100, hwnd, NULL);
3324         gle = GetLastError();
3325         ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : "");
3326         ok( gle == ERROR_INVALID_MENU_HANDLE
3327             || broken (gle == 0xdeadbeef) /* win95 */
3328             || broken (gle == NO_ERROR) /* win98/ME */
3329             ,"TrackPopupMenu%s error got %u expected %u\n",
3330             Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE);
3331         ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu),
3332                 "got unexpected message(s)%s%s%s\n",
3333                 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ",
3334                 gflag_entermenuloop ? "WM_INITMENULOOP ": "",
3335                 gflag_initmenu ? "WM_INITMENU": "");
3336         /* another one but not NULL */
3337         SetLastError(0xdeadbeef);
3338         gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
3339         ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, TPM_RETURNCMD, 100,100, hwnd, NULL);
3340         gle = GetLastError();
3341         ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : "");
3342         ok( gle == ERROR_INVALID_MENU_HANDLE
3343             || broken (gle == 0xdeadbeef) /* win95 */
3344             || broken (gle == NO_ERROR) /* win98/ME */
3345             ,"TrackPopupMenu%s error got %u expected %u\n",
3346             Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE);
3347         ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu),
3348                 "got unexpected message(s)%s%s%s\n",
3349                 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ",
3350                 gflag_entermenuloop ? "WM_INITMENULOOP ": "",
3351                 gflag_initmenu ? "WM_INITMENU": "");
3352 
3353         /* invalid window */
3354         SetLastError(0xdeadbeef);
3355         gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
3356         ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, 0, NULL);
3357         gle = GetLastError();
3358         ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : "");
3359         ok( gle == ERROR_INVALID_WINDOW_HANDLE, "TrackPopupMenu%s error got %u\n", Ex ? "Ex" : "", gle );
3360         ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu),
3361                 "got unexpected message(s)%s%s%s\n",
3362                 gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ",
3363                 gflag_entermenuloop ? "WM_INITMENULOOP ": "",
3364                 gflag_initmenu ? "WM_INITMENU": "");
3365 
3366         /* now a somewhat successful call */
3367         SetLastError(0xdeadbeef);
3368         gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
3369         ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL);
3370         gle = GetLastError();
3371         ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret);
3372         ok( gle == NO_ERROR
3373             || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k */
3374             || broken (gle == 0xdeadbeef) /* win95 */
3375             ,"TrackPopupMenu%s error got %u expected %u or %u\n",
3376             Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE);
3377         ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu,
3378                 "missed expected message(s)%s%s%s\n",
3379                 !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ",
3380                 !gflag_entermenuloop ? "WM_INITMENULOOP ": "",
3381                 !gflag_initmenu ? "WM_INITMENU": "");
3382         /* and another */
3383         ret = AppendMenuA( hmenu, MF_STRING, 1, "winetest");
3384         ok( ret, "AppendMenA has failed!\n");
3385         SetLastError(0xdeadbeef);
3386         gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0;
3387         ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, hwnd, NULL);
3388         gle = GetLastError();
3389         ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret);
3390         ok( gle == NO_ERROR
3391             || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k and Vista in the TrackPopupMenuEx case */
3392             || broken (gle == 0xdeadbeef) /* win95 */
3393             ,"TrackPopupMenu%s error got %u expected %u or %u\n",
3394             Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE);
3395         ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu,
3396                 "missed expected message(s)%s%s%s\n",
3397                 !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ",
3398                 !gflag_entermenuloop ? "WM_INITMENULOOP ": "",
3399                 !gflag_initmenu ? "WM_INITMENU": "");
3400         DestroyMenu(hmenu);
3401     }
3402     /* clean up */
3403     DestroyWindow(hwnd);
3404 }
3405 
3406 static HMENU g_hmenu;
3407 
3408 static LRESULT WINAPI menu_track_again_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3409 {
3410     switch (msg)
3411     {
3412     case WM_ENTERMENULOOP:
3413     {
3414         BOOL ret;
3415 
3416         /* try a recursive call */
3417         SetLastError(0xdeadbeef);
3418         ret = TrackPopupMenu(g_hmenu, 0, 100, 100, 0, hwnd, NULL);
3419         ok(ret == FALSE, "got %d\n", ret);
3420         ok(GetLastError() == ERROR_POPUP_ALREADY_ACTIVE ||
3421            broken(GetLastError() == 0xdeadbeef) /* W9x */, "got %d\n", GetLastError());
3422 
3423         /* exit menu modal loop
3424          * ( A SendMessage does not work on NT3.51 here ) */
3425         return PostMessageA(hwnd, WM_CANCELMODE, 0, 0);
3426     }
3427     }
3428     return DefWindowProcA(hwnd, msg, wparam, lparam);
3429 }
3430 
3431 static void test_menu_trackagain(void)
3432 {
3433     HWND hwnd;
3434     BOOL ret;
3435 
3436     hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
3437             WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
3438             NULL, NULL, NULL, NULL);
3439     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
3440     if (!hwnd) return;
3441     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_track_again_wnd_proc);
3442 
3443     g_hmenu = CreatePopupMenu();
3444     ok(g_hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
3445 
3446     ret = AppendMenuA(g_hmenu, MF_STRING , 100, "item 1");
3447     ok(ret, "AppendMenu failed.\n");
3448     ret = AppendMenuA(g_hmenu, MF_STRING , 101, "item 2");
3449     ok(ret, "AppendMenu failed.\n");
3450 
3451     ret = TrackPopupMenu( g_hmenu, 0, 100, 100, 0, hwnd, NULL);
3452     ok(ret == TRUE, "got %d\n", ret);
3453 
3454     DestroyMenu(g_hmenu);
3455     DestroyWindow(hwnd);
3456 }
3457 
3458 /* test handling of WM_CANCELMODE messages */
3459 static int g_got_enteridle;
3460 static HWND g_hwndtosend;
3461 static LRESULT WINAPI menu_cancelmode_wnd_proc(HWND hwnd, UINT msg,
3462         WPARAM wparam, LPARAM lparam)
3463 {
3464     switch (msg)
3465     {
3466         case WM_ENTERMENULOOP:
3467             g_got_enteridle = 0;
3468             return SendMessageA( g_hwndtosend, WM_CANCELMODE, 0, 0);
3469         case WM_ENTERIDLE:
3470             {
3471                 if( g_got_enteridle++ == 0) {
3472                     /* little hack to get another WM_ENTERIDLE message */
3473                     PostMessageA( hwnd, WM_MOUSEMOVE, 0, 0);
3474                     return SendMessageA( g_hwndtosend, WM_CANCELMODE, 0, 0);
3475                 }
3476                 EndMenu();
3477                 return TRUE;
3478             }
3479     }
3480     return DefWindowProcA( hwnd, msg, wparam, lparam);
3481 }
3482 
3483 static void test_menu_cancelmode(void)
3484 {
3485     DWORD ret;
3486     HWND hwnd, hwndchild;
3487     HMENU menu, menubar;
3488     MSG msg;
3489 
3490     hwnd = CreateWindowExA( 0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
3491             WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
3492             NULL, NULL, NULL, NULL);
3493     hwndchild = CreateWindowExA( 0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
3494             WS_VISIBLE | WS_CHILD, 10, 10, 20, 20,
3495             hwnd, NULL, NULL, NULL);
3496     ok( hwnd != NULL && hwndchild != NULL,
3497             "CreateWindowEx failed with error %d\n", GetLastError());
3498     g_hwndtosend = hwnd;
3499     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc);
3500     SetWindowLongPtrA( hwndchild, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc);
3501     menu = CreatePopupMenu();
3502     ok( menu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError());
3503     ret = AppendMenuA( menu, MF_STRING, 1, "winetest");
3504     ok( ret, "Functie failed lasterror is %u\n", GetLastError());
3505     /* seems to be needed only on wine :( */
3506     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3507         DispatchMessageA(&msg);
3508     /* test the effect of sending a WM_CANCELMODE message in the WM_INITMENULOOP
3509      * handler of the menu owner */
3510     /* test results is extracted from variable g_got_enteridle. Possible values:
3511      * 0 : complete conformance. Sending WM_CANCELMODE cancels a menu initializing tracking
3512      * 1 : Sending WM_CANCELMODE cancels a menu that is in tracking state
3513      * 2 : Sending WM_CANCELMODE does not work
3514      */
3515     /* menu owner is top level window */
3516     g_hwndtosend = hwnd;
3517     TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
3518     ok( g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
3519     /* menu owner is child window */
3520     g_hwndtosend = hwndchild;
3521     TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL);
3522     ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
3523     /* now send the WM_CANCELMODE messages to the WRONG window */
3524     /* those should fail ( to have any effect) */
3525     g_hwndtosend = hwnd;
3526     TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL);
3527     ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle);
3528 
3529     /* test canceling tracking in a window's menu bar */
3530     menubar = CreateMenu();
3531     ok( menubar != NULL, "CreateMenu failed with error %d\n", GetLastError());
3532     ret = AppendMenuA( menubar, MF_POPUP|MF_STRING, (UINT_PTR)menu, "winetest");
3533     ok( ret, "AppendMenuA failed lasterror is %u\n", GetLastError());
3534     ret = SetMenu( hwnd, menubar );
3535     ok( ret, "SetMenu failed lasterror is %u\n", GetLastError());
3536     /* initiate tracking */
3537     g_hwndtosend = hwnd;
3538     ret = SendMessageA( hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0 );
3539     ok( ret == 0, "Sending WM_SYSCOMMAND/SC_KEYMENU failed lasterror is %u\n", GetLastError());
3540     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3541         DispatchMessageA(&msg);
3542     ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
3543 
3544     /* cleanup */
3545     DestroyMenu( menubar );
3546     DestroyMenu( menu);
3547     DestroyWindow( hwndchild);
3548     DestroyWindow( hwnd);
3549 }
3550 
3551 /* show menu trees have a maximum depth */
3552 static void test_menu_maxdepth(void)
3553 {
3554 #define NR_MENUS 100
3555     HMENU hmenus[ NR_MENUS];
3556     int i;
3557     DWORD ret;
3558 
3559     SetLastError(12345678);
3560     for( i = 0; i < NR_MENUS; i++) {
3561         hmenus[i] = CreatePopupMenu();
3562         if( !hmenus[i]) break;
3563     }
3564     ok( i == NR_MENUS, "could not create more than %d menu's\n", i);
3565     for( i = 1; i < NR_MENUS; i++) {
3566         ret = AppendMenuA( hmenus[i], MF_POPUP, (UINT_PTR)hmenus[i-1],"test");
3567         if( !ret) break;
3568     }
3569     trace("Maximum depth is %d\n", i);
3570     ok( GetLastError() == 12345678, "unexpected error %d\n",  GetLastError());
3571     ok( i < NR_MENUS ||
3572            broken( i == NR_MENUS), /* win98, NT */
3573            "no ( or very large) limit on menu depth!\n");
3574 
3575     for( i = 0; i < NR_MENUS; i++)
3576         DestroyMenu( hmenus[i]);
3577 }
3578 
3579 /* bug #12171 */
3580 static void test_menu_circref(void)
3581 {
3582     HMENU menu1, menu2;
3583     DWORD ret;
3584 
3585     menu1 = CreatePopupMenu();
3586     menu2 = CreatePopupMenu();
3587     ok( menu1 && menu2, "error creating menus.\n");
3588     ret = AppendMenuA( menu1, MF_POPUP, (UINT_PTR)menu2, "winetest");
3589     ok( ret, "AppendMenu failed, error is %d\n", GetLastError());
3590     ret = AppendMenuA( menu1, MF_STRING | MF_HILITE, 123, "winetest");
3591     ok( ret, "AppendMenu failed, error is %d\n", GetLastError());
3592     /* app chooses an id that happens to clash with its own hmenu */
3593     ret = AppendMenuA( menu2, MF_STRING, (UINT_PTR)menu2, "winetest");
3594     ok( ret, "AppendMenu failed, error is %d\n", GetLastError());
3595     /* now attempt to change the string of the first item of menu1 */
3596     ret = ModifyMenuA( menu1, (UINT_PTR)menu2, MF_POPUP, (UINT_PTR)menu2, "menu 2");
3597     ok( !ret ||
3598             broken( ret), /* win98, NT */
3599             "ModifyMenu should have failed.\n");
3600     if( !ret) { /* will probably stack fault if the ModifyMenu succeeded */
3601         ret = GetMenuState( menu1, 123, 0);
3602         ok( ret == MF_HILITE, "GetMenuState returned %x\n",ret);
3603     }
3604     DestroyMenu( menu2);
3605     DestroyMenu( menu1);
3606 }
3607 
3608 /* test how the menu texts are aligned when the menu items have
3609  * different combinations of text and bitmaps (bug #13350) */
3610 static void test_menualign(void)
3611 {
3612     BYTE bmfill[300];
3613     HMENU menu;
3614     HBITMAP hbm1, hbm2, hbm3;
3615     MENUITEMINFOA mii = { sizeof(MENUITEMINFOA) };
3616     DWORD ret;
3617     HWND hwnd;
3618     MENUINFO mi = { sizeof( MENUINFO)};
3619 
3620     if( !winetest_interactive) {
3621         skip( "interactive alignment tests.\n");
3622         return;
3623     }
3624     hwnd = CreateWindowExA(0,
3625             "STATIC",
3626             "Menu text alignment Test\nPlease make a selection.",
3627             WS_OVERLAPPEDWINDOW,
3628             100, 100,
3629             300, 300,
3630             NULL, NULL, 0, NULL);
3631     ShowWindow( hwnd, SW_SHOW);
3632     /* create bitmaps */
3633     memset( bmfill, 0xcc, sizeof( bmfill));
3634     hbm1 = CreateBitmap( 10,10,1,1,bmfill);
3635     hbm2 = CreateBitmap( 20,20,1,1,bmfill);
3636     hbm3 = CreateBitmap( 50,6,1,1,bmfill);
3637     ok( hbm1 && hbm2 && hbm3, "Creating bitmaps failed\n");
3638     menu = CreatePopupMenu();
3639     ok( menu != NULL, "CreatePopupMenu() failed\n");
3640 
3641     mi.fMask = MIM_STYLE;
3642     ret = GetMenuInfo( menu, &mi);
3643     ok( ret, "GetMenuInfo failed: %d\n", GetLastError());
3644     ok( menu != NULL, "GetMenuInfo() failed\n");
3645     ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle);
3646 
3647     /* test 1 */
3648     mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID;
3649     mii.wID = 1;
3650     mii.hbmpItem = hbm1;
3651     mii.dwTypeData = (LPSTR) " OK: menu texts are correctly left-aligned.";
3652     ret = InsertMenuItemA( menu, -1, TRUE, &mii);
3653     ok( ret, "InsertMenuItem() failed\n");
3654     mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID ;
3655     mii.wID = 2;
3656     mii.hbmpItem = hbm2;
3657     mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT left-aligned.";
3658     ret = InsertMenuItemA( menu, -1, TRUE, &mii);
3659     ok( ret, "InsertMenuItem() failed\n");
3660     ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL);
3661     ok( ret != 2, "User indicated that menu text alignment test 1 failed %d\n", ret);
3662     /* test 2*/
3663     mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID;
3664     mii.wID = 3;
3665     mii.hbmpItem = hbm3;
3666     mii.dwTypeData = NULL;
3667     ret = InsertMenuItemA( menu, 0, TRUE, &mii);
3668     ok( ret, "InsertMenuItem() failed\n");
3669     mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID;
3670     mii.wID = 1;
3671     mii.hbmpItem = hbm1;
3672     /* make the text a bit longer, to keep it readable */
3673     /* this bug is on winXP and reproduced on wine */
3674     mii.dwTypeData = (LPSTR) " OK: menu texts are to the right of the bitmaps........";
3675     ret = SetMenuItemInfoA( menu, 1, TRUE, &mii);
3676     ok( ret, "SetMenuItemInfo() failed\n");
3677     mii.wID = 2;
3678     mii.hbmpItem = hbm2;
3679     mii.dwTypeData = (LPSTR) " FAIL: menu texts are below the first bitmap.  ";
3680     ret = SetMenuItemInfoA( menu, 2, TRUE, &mii);
3681     ok( ret, "SetMenuItemInfo() failed\n");
3682     ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL);
3683     ok( ret != 2, "User indicated that menu text alignment test 2 failed %d\n", ret);
3684     /* test 3 */
3685     mii.fMask = MIIM_TYPE | MIIM_ID;
3686     mii.wID = 3;
3687     mii.fType = MFT_BITMAP;
3688     mii.dwTypeData = (LPSTR) hbm3;
3689     ret = SetMenuItemInfoA( menu, 0, TRUE, &mii);
3690     ok( ret, "SetMenuItemInfo() failed\n");
3691     mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID;
3692     mii.wID = 1;
3693     mii.hbmpItem = NULL;
3694     mii.dwTypeData = (LPSTR) " OK: menu texts are below the bitmap.";
3695     ret = SetMenuItemInfoA( menu, 1, TRUE, &mii);
3696     ok( ret, "SetMenuItemInfo() failed\n");
3697     mii.wID = 2;
3698     mii.hbmpItem = NULL;
3699     mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT below the bitmap.";
3700     ret = SetMenuItemInfoA( menu, 2, TRUE, &mii);
3701     ok( ret, "SetMenuItemInfo() failed\n");
3702     ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL);
3703     ok( ret != 2, "User indicated that menu text alignment test 3 failed %d\n", ret);
3704     /* cleanup */
3705     DeleteObject( hbm1);
3706     DeleteObject( hbm2);
3707     DeleteObject( hbm3);
3708     DestroyMenu( menu);
3709     DestroyWindow( hwnd);
3710 }
3711 
3712 static LRESULT WINAPI menu_fill_in_init(HWND hwnd, UINT msg,
3713         WPARAM wparam, LPARAM lparam)
3714 {
3715     HMENU hmenupopup;
3716     BOOL ret;
3717     switch (msg)
3718     {
3719         case WM_INITMENUPOPUP:
3720             gflag_initmenupopup++;
3721             hmenupopup = (HMENU) wparam;
3722             ret = AppendMenuA(hmenupopup, MF_STRING , 100, "item 1");
3723             ok(ret, "AppendMenu failed.\n");
3724             ret = AppendMenuA(hmenupopup, MF_STRING , 101, "item 2");
3725             ok(ret, "AppendMenu failed.\n");
3726             break;
3727         case WM_ENTERMENULOOP:
3728             gflag_entermenuloop++;
3729             break;
3730         case WM_INITMENU:
3731             gflag_initmenu++;
3732             break;
3733         case WM_ENTERIDLE:
3734             gflag_enteridle++;
3735             PostMessageA(hwnd, WM_CANCELMODE, 0, 0);
3736             return TRUE;
3737         case WM_MENUSELECT:
3738             selectitem_wp = wparam;
3739             selectitem_lp = lparam;
3740             break;
3741     }
3742     return DefWindowProcA(hwnd, msg, wparam, lparam);
3743 }
3744 
3745 static void test_emptypopup(void)
3746 {
3747     BOOL ret;
3748     HMENU hmenu;
3749 
3750     HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL,
3751                                WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
3752                                NULL, NULL, NULL, NULL);
3753     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
3754     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc);
3755 
3756     hmenu = CreatePopupMenu();
3757     ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
3758 
3759     gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0;
3760     selectitem_wp = 0xdeadbeef;
3761     selectitem_lp = 0xdeadbeef;
3762 
3763     ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL);
3764     ok(ret == 0, "got %i\n", ret);
3765 
3766     ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup);
3767     ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop);
3768     ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu);
3769     ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu);
3770 
3771     ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp);
3772     ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp);
3773 
3774     gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0;
3775     selectitem_wp = 0xdeadbeef;
3776     selectitem_lp = 0xdeadbeef;
3777 
3778     ret = TrackPopupMenu( hmenu, 0, 100,100, 0, hwnd, NULL);
3779     ok(ret == 0, "got %i\n", ret);
3780 
3781     ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup);
3782     ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop);
3783     ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu);
3784     ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu);
3785 
3786     ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp);
3787     ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp);
3788 
3789     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_fill_in_init);
3790 
3791     gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0;
3792     selectitem_wp = 0xdeadbeef;
3793     selectitem_lp = 0xdeadbeef;
3794 
3795     ret = TrackPopupMenu( hmenu, 0, 100,100, 0, hwnd, NULL);
3796     ok(ret == 1, "got %i\n", ret);
3797 
3798     ok(gflag_initmenupopup == 1, "got %i\n", gflag_initmenupopup);
3799     ok(gflag_entermenuloop == 1, "got %i\n", gflag_entermenuloop);
3800     ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu);
3801     ok(gflag_enteridle == 1, "got %i\n", gflag_initmenu);
3802 
3803     ok(selectitem_wp == 0xffff0000, "got %lx\n", selectitem_wp);
3804     ok(selectitem_lp == 0, "got %lx\n", selectitem_lp);
3805 
3806     DestroyWindow(hwnd);
3807 
3808     ret = DestroyMenu(hmenu);
3809     ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
3810 }
3811 
3812 static HMENU get_bad_hmenu( UINT_PTR id )
3813 {
3814     while (IsMenu( (HMENU)id )) id++;
3815     return (HMENU)id;
3816 }
3817 
3818 static void test_AppendMenu(void)
3819 {
3820     static char string[] = "string";
3821     MENUITEMINFOA mii;
3822     HMENU hmenu, hsubmenu;
3823     HBITMAP hbmp;
3824     char buf[16];
3825     BOOL ret;
3826 
3827     hmenu = CreateMenu();
3828     ok(hmenu != 0, "CreateMenu failed\n");
3829     ret = AppendMenuA(hmenu, MF_OWNERDRAW, 201, "item 1");
3830     ok(ret, "AppendMenu failed\n");
3831     check_menu_items(hmenu, 201, MF_OWNERDRAW, 0);
3832     DestroyMenu(hmenu);
3833 
3834     hmenu = CreateMenu();
3835     ok(hmenu != 0, "CreateMenu failed\n");
3836     hsubmenu = get_bad_hmenu( 202 );
3837     ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3838     ok(ret, "AppendMenu failed\n");
3839     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0);
3840     DestroyMenu(hmenu);
3841 
3842     hmenu = CreateMenu();
3843     ok(hmenu != 0, "CreateMenu failed\n");
3844     hsubmenu = get_bad_hmenu( 203 );
3845     ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3846     ok(ret, "AppendMenu failed\n");
3847     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0);
3848     DestroyMenu(hmenu);
3849 
3850     hmenu = CreateMenu();
3851     ok(hmenu != 0, "CreateMenu failed\n");
3852     hsubmenu = CreateMenu();
3853     ok(hsubmenu != 0, "CreateMenu failed\n");
3854     ret = AppendMenuA(hmenu, MF_OWNERDRAW, (UINT_PTR)hsubmenu, "item 1");
3855     ok(ret, "AppendMenu failed\n");
3856     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0);
3857     DestroyMenu(hmenu);
3858     DestroyMenu(hsubmenu);
3859 
3860     hmenu = CreateMenu();
3861     ok(hmenu != 0, "CreateMenu failed\n");
3862     hsubmenu = CreateMenu();
3863     ok(hsubmenu != 0, "CreateMenu failed\n");
3864     ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3865     ok(ret, "AppendMenu failed\n");
3866     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0);
3867     DestroyMenu(hmenu);
3868     DestroyMenu(hsubmenu);
3869 
3870     hmenu = CreateMenu();
3871     ok(hmenu != 0, "CreateMenu failed\n");
3872     hsubmenu = CreateMenu();
3873     ok(hsubmenu != 0, "CreateMenu failed\n");
3874     ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3875     ok(ret, "AppendMenu failed\n");
3876     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0);
3877     DestroyMenu(hmenu);
3878     DestroyMenu(hsubmenu);
3879 
3880     hmenu = CreateMenu();
3881     ok(hmenu != 0, "CreateMenu failed\n");
3882     hsubmenu = CreatePopupMenu();
3883     ok(hsubmenu != 0, "CreatePopupMenu failed\n");
3884     ret = AppendMenuA(hmenu, MF_OWNERDRAW, (UINT_PTR)hsubmenu, "item 1");
3885     ok(ret, "AppendMenu failed\n");
3886     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0);
3887     DestroyMenu(hmenu);
3888     DestroyMenu(hsubmenu);
3889 
3890     hmenu = CreateMenu();
3891     ok(hmenu != 0, "CreateMenu failed\n");
3892     hsubmenu = CreatePopupMenu();
3893     ok(hsubmenu != 0, "CreatePopupMenu failed\n");
3894     ret = AppendMenuA(hmenu, MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3895     ok(ret, "AppendMenu failed\n");
3896     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0);
3897     DestroyMenu(hmenu);
3898     DestroyMenu(hsubmenu);
3899 
3900     hmenu = CreateMenu();
3901     ok(hmenu != 0, "CreateMenu failed\n");
3902     hsubmenu = CreatePopupMenu();
3903     ok(hsubmenu != 0, "CreatePopupMenu failed\n");
3904     ret = AppendMenuA(hmenu, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)hsubmenu, "item 1");
3905     ok(ret, "AppendMenu failed\n");
3906     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_OWNERDRAW, 0);
3907     DestroyMenu(hmenu);
3908     DestroyMenu(hsubmenu);
3909 
3910     hmenu = CreateMenu();
3911     ok(hmenu != 0, "CreateMenu failed\n");
3912     ret = AppendMenuA(hmenu, MF_STRING, 204, "item 1");
3913     ok(ret, "AppendMenu failed\n");
3914     check_menu_items(hmenu, 204, MF_STRING, 0);
3915     hsubmenu = get_bad_hmenu( 205 );
3916     ret = ModifyMenuA(hmenu, 0, MF_POPUP | MF_BYPOSITION, (UINT_PTR)hsubmenu, "item 2");
3917     ok(ret, "ModifyMenu failed\n");
3918     check_menu_items(hmenu, (UINT_PTR)hsubmenu, MF_STRING, 0);
3919     memset(&mii, 0, sizeof(mii));
3920     mii.cbSize = sizeof(mii);
3921     mii.fMask = MIIM_SUBMENU;
3922     mii.hSubMenu = get_bad_hmenu( 204 );
3923     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
3924     ok(!ret, "InsertMenuItem should fail\n");
3925     ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii);
3926     ok(!ret, "SetMenuItemInfo should fail\n");
3927     mii.fMask = MIIM_ID;
3928     mii.wID = 206;
3929     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
3930     ok(ret, "InsertMenuItem failed\n");
3931 if (0) /* FIXME: uncomment once Wine is fixed */ {
3932     check_menu_items(hmenu, 206, MF_SEPARATOR, MFS_GRAYED);
3933 }
3934     mii.wID = 207;
3935     ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii);
3936     ok(ret, "SetMenuItemInfo failed\n");
3937 if (0) /* FIXME: uncomment once Wine is fixed */ {
3938     check_menu_items(hmenu, 207, MF_SEPARATOR, MFS_GRAYED);
3939 }
3940     DestroyMenu(hmenu);
3941 
3942     hbmp = CreateBitmap(1, 1, 1, 1, NULL);
3943     hmenu = CreateMenu();
3944     ok(hmenu != 0, "CreateMenu failed\n");
3945 
3946     /* menu item with a string and a bitmap */
3947     memset(&mii, 0, sizeof(mii));
3948     mii.cbSize = sizeof(mii);
3949     mii.fMask = MIIM_STRING | MIIM_BITMAP;
3950     mii.dwTypeData = string;
3951     mii.cch = strlen(string);
3952     mii.hbmpItem = hbmp;
3953     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
3954     ok(ret, "InsertMenuItem failed\n");
3955     memset(&mii, 0x81, sizeof(mii));
3956     memset(buf, 0x81, sizeof(buf));
3957     mii.cbSize = sizeof(mii);
3958     mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
3959     mii.dwTypeData = buf;
3960     mii.cch = sizeof(buf);
3961     mii.dwItemData = 0x81818181;
3962     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
3963     ok(ret, "GetMenuItemInfo failed\n");
3964     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
3965     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
3966     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
3967     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
3968     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
3969     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
3970     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
3971     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
3972     ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem);
3973 
3974     memset(&mii, 0x81, sizeof(mii));
3975     mii.cbSize = sizeof(mii);
3976     mii.fMask  = MIIM_TYPE;
3977     mii.dwItemData = 0x81818181;
3978     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
3979     ok(ret, "GetMenuItemInfo failed\n");
3980     ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType);
3981     ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState);
3982     ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID);
3983     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
3984     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
3985     ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData);
3986     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
3987     ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem);
3988 
3989     memset(&mii, 0x81, sizeof(mii));
3990     memset(buf, 0x81, sizeof(buf));
3991     mii.cbSize = sizeof(mii);
3992     mii.fMask  = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA;
3993     mii.dwTypeData = buf;
3994     mii.cch = sizeof(buf);
3995     mii.dwItemData = 0x81818181;
3996     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
3997     ok(ret, "GetMenuItemInfo failed\n");
3998     ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType);
3999     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4000     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4001     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4002     ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData);
4003     ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData);
4004     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4005     ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem);
4006 
4007     DestroyMenu(hmenu);
4008     DeleteObject(hbmp);
4009 
4010     hmenu = CreateMenu();
4011     ok(hmenu != 0, "CreateMenu failed\n");
4012 
4013     /* menu item with a string and a "magic" bitmap */
4014     memset(&mii, 0, sizeof(mii));
4015     mii.cbSize = sizeof(mii);
4016     mii.fMask = MIIM_STRING | MIIM_BITMAP;
4017     mii.dwTypeData = string;
4018     mii.cch = strlen(string);
4019     mii.hbmpItem = HBMMENU_POPUP_RESTORE;
4020     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
4021     ok(ret, "InsertMenuItem failed\n");
4022     memset(&mii, 0x81, sizeof(mii));
4023     memset(buf, 0x81, sizeof(buf));
4024     mii.cbSize = sizeof(mii);
4025     mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
4026     mii.dwTypeData = buf;
4027     mii.cch = sizeof(buf);
4028     mii.dwItemData = 0x81818181;
4029     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4030     ok(ret, "GetMenuItemInfo failed\n");
4031     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4032     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4033     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4034     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4035     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4036     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4037     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4038     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4039     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
4040 
4041     memset(&mii, 0x81, sizeof(mii));
4042     mii.cbSize = sizeof(mii);
4043     mii.fMask  = MIIM_TYPE;
4044     mii.dwTypeData = buf;
4045     mii.cch = sizeof(buf);
4046     mii.dwItemData = 0x81818181;
4047     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4048     ok(ret, "GetMenuItemInfo failed\n");
4049     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4050     ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState);
4051     ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID);
4052     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4053     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4054     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4055     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4056     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4057     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
4058 
4059     memset(&mii, 0x81, sizeof(mii));
4060     memset(buf, 0x81, sizeof(buf));
4061     mii.cbSize = sizeof(mii);
4062     mii.fMask  = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA;
4063     mii.dwTypeData = buf;
4064     mii.cch = sizeof(buf);
4065     mii.dwItemData = 0x81818181;
4066     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4067     ok(ret, "GetMenuItemInfo failed\n");
4068     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4069     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4070     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4071     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4072     ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData);
4073     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4074     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4075     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4076     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
4077 
4078     DestroyMenu(hmenu);
4079 
4080     hbmp = CreateBitmap(1, 1, 1, 1, NULL);
4081     hmenu = CreateMenu();
4082     ok(hmenu != 0, "CreateMenu failed\n");
4083 
4084     /* menu item with a string */
4085     memset(&mii, 0, sizeof(mii));
4086     mii.cbSize = sizeof(mii);
4087     mii.fMask  = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA;
4088     mii.dwItemData = (ULONG_PTR)hbmp;
4089     mii.dwTypeData = string;
4090     mii.cch = strlen(string);
4091     mii.hbmpItem = hbmp;
4092     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
4093     ok(ret, "InsertMenuItem failed\n");
4094     memset(&mii, 0x81, sizeof(mii));
4095     memset(buf, 0x81, sizeof(buf));
4096     mii.cbSize = sizeof(mii);
4097     mii.fMask  = MIIM_STATE | MIIM_ID | MIIM_TYPE | MIIM_DATA;
4098     mii.dwTypeData = buf;
4099     mii.cch = sizeof(buf);
4100     mii.dwItemData = 0x81818181;
4101     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4102     ok(ret, "GetMenuItemInfo failed\n");
4103     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4104     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4105     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4106     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4107     ok(mii.dwItemData == (ULONG_PTR)hbmp, "expected %p, got %#lx\n", hbmp, mii.dwItemData);
4108     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4109     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4110     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4111     ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem);
4112 
4113     memset(&mii, 0x81, sizeof(mii));
4114     memset(buf, 0x81, sizeof(buf));
4115     mii.cbSize = sizeof(mii);
4116     mii.fMask  = MIIM_TYPE;
4117     mii.dwTypeData = buf;
4118     mii.cch = sizeof(buf);
4119     mii.dwItemData = 0x81818181;
4120     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4121     ok(ret, "GetMenuItemInfo failed\n");
4122     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4123     ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState);
4124     ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID);
4125     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4126     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4127     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4128     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4129     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4130     ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem);
4131 
4132     DestroyMenu(hmenu);
4133     DeleteObject(hbmp);
4134 
4135     /* menu item with a string */
4136     hbmp = CreateBitmap(1, 1, 1, 1, NULL);
4137     hmenu = CreateMenu();
4138     ok(hmenu != 0, "CreateMenu failed\n");
4139     memset(&mii, 0, sizeof(mii));
4140     mii.cbSize = sizeof(mii);
4141     mii.fMask = MIIM_STRING;
4142     mii.dwTypeData = string;
4143     mii.cch = strlen(string);
4144     ret = InsertMenuItemA(hmenu, 0, TRUE, &mii);
4145     ok(ret, "InsertMenuItem failed\n");
4146     memset(&mii, 0x81, sizeof(mii));
4147     memset(buf, 0x81, sizeof(buf));
4148     mii.cbSize = sizeof(mii);
4149     mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
4150     mii.dwTypeData = buf;
4151     mii.cch = sizeof(buf);
4152     mii.dwItemData = 0x81818181;
4153     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4154     ok(ret, "GetMenuItemInfo failed\n");
4155     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4156     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4157     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4158     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4159     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4160     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4161     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4162     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4163     ok(mii.hbmpItem == 0, "expected 0, got %p\n", mii.hbmpItem);
4164 
4165     /* add "magic" bitmap to a menu item */
4166     mii.fMask = MIIM_BITMAP;
4167     mii.hbmpItem = HBMMENU_POPUP_RESTORE;
4168     ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4169     ok(ret, "SetMenuItemInfo failed\n");
4170     memset(&mii, 0x81, sizeof(mii));
4171     memset(buf, 0x81, sizeof(buf));
4172     mii.cbSize = sizeof(mii);
4173     mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
4174     mii.dwTypeData = buf;
4175     mii.cch = sizeof(buf);
4176     mii.dwItemData = 0x81818181;
4177     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4178     ok(ret, "GetMenuItemInfo failed\n");
4179     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4180     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4181     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4182     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4183     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4184     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4185     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4186     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4187     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
4188 
4189     memset(&mii, 0x81, sizeof(mii));
4190     memset(buf, 0x81, sizeof(buf));
4191     mii.cbSize = sizeof(mii);
4192     mii.fMask  = MIIM_TYPE;
4193     mii.dwTypeData = buf;
4194     mii.cch = sizeof(buf);
4195     mii.dwItemData = 0x81818181;
4196     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4197     ok(ret, "GetMenuItemInfo failed\n");
4198     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4199     ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState);
4200     ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID);
4201     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4202     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4203     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4204     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4205     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4206     ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem);
4207 
4208     /* replace "magic" bitmap by a normal one */
4209     mii.fMask = MIIM_BITMAP;
4210     mii.hbmpItem = hbmp;
4211     ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4212     ok(ret, "SetMenuItemInfo failed\n");
4213     memset(&mii, 0x81, sizeof(mii));
4214     memset(buf, 0x81, sizeof(buf));
4215     mii.cbSize = sizeof(mii);
4216     mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
4217     mii.dwTypeData = buf;
4218     mii.cch = sizeof(buf);
4219     mii.dwItemData = 0x81818181;
4220     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4221     ok(ret, "GetMenuItemInfo failed\n");
4222     ok(mii.fType == MF_STRING, "expected MF_STRING, got %#x\n", mii.fType);
4223     ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState);
4224     ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID);
4225     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4226     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4227     ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData);
4228     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4229     ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf);
4230     ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem);
4231 
4232     memset(&mii, 0x81, sizeof(mii));
4233     memset(buf, 0x81, sizeof(buf));
4234     mii.cbSize = sizeof(mii);
4235     mii.fMask  = MIIM_TYPE;
4236     mii.dwTypeData = buf;
4237     mii.cch = sizeof(buf);
4238     mii.dwItemData = 0x81818181;
4239     ret = GetMenuItemInfoA(hmenu, 0, TRUE, &mii);
4240     ok(ret, "GetMenuItemInfo failed\n");
4241     ok(mii.fType == MF_BITMAP, "expected MF_BITMAP, got %#x\n", mii.fType);
4242     ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState);
4243     ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID);
4244     ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu);
4245     ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData);
4246     ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData);
4247     ok(mii.cch == 6, "expected 6, got %u\n", mii.cch);
4248     ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem);
4249 
4250     DestroyMenu(hmenu);
4251     DeleteObject(hbmp);
4252 }
4253 
4254 START_TEST(menu)
4255 {
4256     register_menu_check_class();
4257 
4258     test_menu_add_string();
4259     test_menu_iteminfo();
4260     test_menu_search_bycommand();
4261     test_CheckMenuRadioItem();
4262     test_menu_resource_layout();
4263     test_InsertMenu();
4264     test_menualign();
4265     test_system_menu();
4266 
4267     test_menu_locked_by_window();
4268     test_subpopup_locked_by_menu();
4269     test_menu_ownerdraw();
4270     test_getmenubarinfo();
4271     test_GetMenuItemRect();
4272     test_menu_bmp_and_string();
4273     test_menu_getmenuinfo();
4274     test_menu_setmenuinfo();
4275     test_menu_input();
4276     test_menu_flags();
4277 
4278     test_menu_hilitemenuitem();
4279     test_menu_trackpopupmenu();
4280     test_menu_trackagain();
4281     test_menu_cancelmode();
4282     test_menu_maxdepth();
4283     test_menu_circref();
4284     test_emptypopup();
4285     test_AppendMenu();
4286 }
4287