add some interactive user32 menu tests
[wine/kumbayo.git] / dlls / user32 / tests / menu.c
blobafb1c208615ef0b9cc3aa4256204ae0e224861c2
1 /*
2 * Unit tests for menus
4 * Copyright 2005 Robert Shearman
5 * Copyright 2007 Dmitry Timoshkov
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.
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.
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
22 #define _WIN32_WINNT 0x0501
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
29 #define OEMRESOURCE /* For OBM_MNARROW */
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
36 #include "wine/test.h"
38 static ATOM atomMenuCheckClass;
40 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
41 static UINT (WINAPI *pSendInput)(UINT, INPUT*, size_t);
42 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
44 static void init_function_pointers(void)
46 HMODULE hdll = GetModuleHandleA("user32");
48 #define GET_PROC(func) \
49 p ## func = (void*)GetProcAddress(hdll, #func); \
50 if(!p ## func) \
51 trace("GetProcAddress(%s) failed\n", #func);
53 GET_PROC(GetMenuInfo)
54 GET_PROC(SendInput)
55 GET_PROC(SetMenuInfo)
57 #undef GET_PROC
60 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
62 switch (msg)
64 case WM_ENTERMENULOOP:
65 /* mark window as having entered menu loop */
66 SetWindowLongPtr(hwnd, GWLP_USERDATA, TRUE);
67 /* exit menu modal loop
68 * ( A SendMessage does not work on NT3.51 here ) */
69 return PostMessage(hwnd, WM_CANCELMODE, 0, 0);
71 return DefWindowProc(hwnd, msg, wparam, lparam);
74 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define
75 * our own type */
76 typedef struct
78 DWORD type;
79 union
81 MOUSEINPUT mi;
82 KEYBDINPUT ki;
83 HARDWAREINPUT hi;
84 } u;
85 } TEST_INPUT;
87 /* globals to communicate between test and wndproc */
89 static BOOL bMenuVisible;
90 static HMENU hMenus[4];
92 #define MOD_SIZE 10
93 #define MOD_NRMENUS 8
95 /* menu texts with their sizes */
96 static struct {
97 LPCSTR text;
98 SIZE size; /* size of text up to any \t */
99 SIZE sc_size; /* size of the short-cut */
100 } MOD_txtsizes[] = {
101 { "Pinot &Noir" },
102 { "&Merlot\bF4" },
103 { "Shira&z\tAlt+S" },
104 { "" },
105 { NULL }
108 static unsigned int MOD_maxid;
109 static RECT MOD_rc[MOD_NRMENUS];
110 static int MOD_avec, MOD_hic;
111 static int MOD_odheight;
112 static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE},
113 {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}};
114 static int MOD_GotDrawItemMsg = FALSE;
115 /* wndproc used by test_menu_ownerdraw() */
116 static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg,
117 WPARAM wparam, LPARAM lparam)
119 switch (msg)
121 case WM_MEASUREITEM:
123 MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam;
124 if( winetest_debug)
125 trace("WM_MEASUREITEM received data %lx size %dx%d\n",
126 pmis->itemData, pmis->itemWidth, pmis->itemHeight);
127 MOD_odheight = pmis->itemHeight;
128 pmis->itemWidth = MODsizes[pmis->itemData].cx;
129 pmis->itemHeight = MODsizes[pmis->itemData].cy;
130 return TRUE;
132 case WM_DRAWITEM:
134 DRAWITEMSTRUCT * pdis;
135 TEXTMETRIC tm;
136 HPEN oldpen;
137 char chrs[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
138 SIZE sz;
139 int i;
140 pdis = (DRAWITEMSTRUCT *) lparam;
141 if( winetest_debug) {
142 RECT rc;
143 GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc);
144 trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n",
145 hwnd, (HMENU)pdis->hwndItem, pdis->itemData,
146 pdis->itemID, pdis->rcItem.left, pdis->rcItem.top,
147 pdis->rcItem.right,pdis->rcItem.bottom,
148 rc.left,rc.top,rc.right,rc.bottom);
149 oldpen=SelectObject( pdis->hDC, GetStockObject(
150 pdis->itemState & ODS_SELECTED ? WHITE_PEN :BLACK_PEN));
151 Rectangle( pdis->hDC, pdis->rcItem.left,pdis->rcItem.top,
152 pdis->rcItem.right,pdis->rcItem.bottom );
153 SelectObject( pdis->hDC, oldpen);
155 /* calculate widths of some menu texts */
156 if( ! MOD_txtsizes[0].size.cx)
157 for(i = 0; MOD_txtsizes[i].text; i++) {
158 char buf[100], *p;
159 RECT rc={0,0,0,0};
160 strcpy( buf, MOD_txtsizes[i].text);
161 if( ( p = strchr( buf, '\t'))) {
162 *p = '\0';
163 DrawText( pdis->hDC, p + 1, -1, &rc,
164 DT_SINGLELINE|DT_CALCRECT);
165 MOD_txtsizes[i].sc_size.cx= rc.right - rc.left;
166 MOD_txtsizes[i].sc_size.cy= rc.bottom - rc.top;
168 DrawText( pdis->hDC, buf, -1, &rc,
169 DT_SINGLELINE|DT_CALCRECT);
170 MOD_txtsizes[i].size.cx= rc.right - rc.left;
171 MOD_txtsizes[i].size.cy= rc.bottom - rc.top;
174 if( pdis->itemData > MOD_maxid) return TRUE;
175 /* store the rectangl */
176 MOD_rc[pdis->itemData] = pdis->rcItem;
177 /* calculate average character width */
178 GetTextExtentPoint( pdis->hDC, chrs, 52, &sz );
179 MOD_avec = (sz.cx + 26)/52;
180 GetTextMetrics( pdis->hDC, &tm);
181 MOD_hic = tm.tmHeight;
182 MOD_GotDrawItemMsg = TRUE;
183 return TRUE;
185 case WM_ENTERIDLE:
187 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
188 return TRUE;
192 return DefWindowProc(hwnd, msg, wparam, lparam);
195 static void register_menu_check_class(void)
197 WNDCLASS wc =
200 menu_check_wnd_proc,
203 GetModuleHandle(NULL),
204 NULL,
205 LoadCursor(NULL, IDC_ARROW),
206 (HBRUSH)(COLOR_BTNFACE+1),
207 NULL,
208 TEXT("WineMenuCheck"),
211 atomMenuCheckClass = RegisterClass(&wc);
214 /* demonstrates that windows locks the menu object so that it is still valid
215 * even after a client calls DestroyMenu on it */
216 static void test_menu_locked_by_window(void)
218 BOOL ret;
219 HMENU hmenu;
220 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
221 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
222 NULL, NULL, NULL, NULL);
223 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
224 hmenu = CreateMenu();
225 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
226 ret = InsertMenu(hmenu, 0, MF_STRING, 0, TEXT("&Test"));
227 ok(ret, "InsertMenu failed with error %d\n", GetLastError());
228 ret = SetMenu(hwnd, hmenu);
229 ok(ret, "SetMenu failed with error %d\n", GetLastError());
230 ret = DestroyMenu(hmenu);
231 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
233 ret = DrawMenuBar(hwnd);
234 todo_wine {
235 ok(ret, "DrawMenuBar failed with error %d\n", GetLastError());
237 ret = IsMenu(GetMenu(hwnd));
238 ok(!ret, "Menu handle should have been destroyed\n");
240 SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
241 /* did we process the WM_INITMENU message? */
242 ret = GetWindowLongPtr(hwnd, GWLP_USERDATA);
243 todo_wine {
244 ok(ret, "WM_INITMENU should have been sent\n");
247 DestroyWindow(hwnd);
250 static void test_menu_ownerdraw(void)
252 int i,j,k;
253 BOOL ret;
254 HMENU hmenu;
255 LONG leftcol;
256 HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
257 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
258 NULL, NULL, NULL, NULL);
259 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
260 if( !hwnd) return;
261 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
262 hmenu = CreatePopupMenu();
263 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
264 if( !hmenu) { DestroyWindow(hwnd);return;}
265 k=0;
266 for( j=0;j<2;j++) /* create columns */
267 for(i=0;i<2;i++) { /* create rows */
268 ret = AppendMenu( hmenu, MF_OWNERDRAW |
269 (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k);
270 k++;
271 ok( ret, "AppendMenu failed for %d\n", k-1);
273 MOD_maxid = k-1;
274 assert( k <= sizeof(MOD_rc)/sizeof(RECT));
275 /* display the menu */
276 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
278 /* columns have a 4 pixel gap between them */
279 ok( MOD_rc[0].right + 4 == MOD_rc[2].left,
280 "item rectangles are not separated by 4 pixels space\n");
281 /* height should be what the MEASUREITEM message has returned */
282 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
283 "menu item has wrong height: %d should be %d\n",
284 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
285 /* no gaps between the rows */
286 ok( MOD_rc[0].bottom - MOD_rc[1].top == 0,
287 "There should not be a space between the rows, gap is %d\n",
288 MOD_rc[0].bottom - MOD_rc[1].top);
289 /* test the correct value of the item height that was sent
290 * by the WM_MEASUREITEM message */
291 ok( MOD_odheight == HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
292 MOD_odheight == MOD_hic, /* Win95,98,ME */
293 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
294 HIWORD( GetDialogBaseUnits()), MOD_hic, MOD_odheight);
295 /* test what MF_MENUBREAK did at the first position. Also show
296 * that an MF_SEPARATOR is ignored in the height calculation. */
297 leftcol= MOD_rc[0].left;
298 ModifyMenu( hmenu, 0, MF_BYCOMMAND| MF_OWNERDRAW| MF_SEPARATOR, 0, 0);
299 /* display the menu */
300 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
301 /* left should be 4 pixels less now */
302 ok( leftcol == MOD_rc[0].left + 4,
303 "columns should be 4 pixels to the left (actual %d).\n",
304 leftcol - MOD_rc[0].left);
305 /* test width */
306 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
307 "width of owner drawn menu item is wrong. Got %d expected %d\n",
308 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
309 /* and height */
310 ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE,
311 "Height is incorrect. Got %d expected %d\n",
312 MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE);
314 /* test width/height of an ownerdraw menu bar as well */
315 ret = DestroyMenu(hmenu);
316 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
317 hmenu = CreateMenu();
318 ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
319 if( !hmenu) { DestroyWindow(hwnd);return;}
320 MOD_maxid=1;
321 for(i=0;i<2;i++) {
322 ret = AppendMenu( hmenu, MF_OWNERDRAW , i, 0);
323 ok( ret, "AppendMenu failed for %d\n", i);
325 ret = SetMenu( hwnd, hmenu);
326 UpdateWindow( hwnd); /* hack for wine to draw the window + menu */
327 ok(ret, "SetMenu failed with error %d\n", GetLastError());
328 /* test width */
329 ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE,
330 "width of owner drawn menu item is wrong. Got %d expected %d\n",
331 MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE);
332 /* test hight */
333 ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1,
334 "Height of owner drawn menu item is wrong. Got %d expected %d\n",
335 MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1);
337 /* clean up */
338 ret = DestroyMenu(hmenu);
339 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
340 DestroyWindow(hwnd);
343 /* helper for test_menu_bmp_and_string() */
344 static void test_mbs_help( int ispop, int hassub, int mnuopt,
345 HWND hwnd, int arrowwidth, int count, HBITMAP hbmp,
346 SIZE bmpsize, LPCSTR text, SIZE size, SIZE sc_size)
348 BOOL ret;
349 HMENU hmenu, submenu;
350 MENUITEMINFO mii={ sizeof( MENUITEMINFO )};
351 MENUINFO mi;
352 RECT rc;
353 CHAR text_copy[16];
354 int hastab, expect;
355 int failed = 0;
357 MOD_GotDrawItemMsg = FALSE;
358 mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
359 mii.fType = 0;
360 mii.fState = MF_CHECKED;
361 mii.dwItemData =0;
362 MODsizes[0] = bmpsize;
363 hastab = 0;
364 if( text ) {
365 char *p;
366 mii.fMask |= MIIM_STRING;
367 strcpy(text_copy, text);
368 mii.dwTypeData = text_copy; /* structure member declared non-const */
369 if( ( p = strchr( text, '\t'))) {
370 hastab = *(p + 1) ? 2 : 1;
373 /* tabs don't make sense in menubars */
374 if(hastab && !ispop) return;
375 if( hbmp) {
376 mii.fMask |= MIIM_BITMAP;
377 mii.hbmpItem = hbmp;
379 submenu = CreateMenu();
380 ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError());
381 if( ispop)
382 hmenu = CreatePopupMenu();
383 else
384 hmenu = CreateMenu();
385 ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError());
386 if( hassub) {
387 mii.fMask |= MIIM_SUBMENU;
388 mii.hSubMenu = submenu;
390 if( mnuopt) {
391 mi.cbSize = sizeof(mi);
392 mi.fMask = MIM_STYLE;
393 pGetMenuInfo( hmenu, &mi);
394 mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP;
395 ret = pSetMenuInfo( hmenu, &mi);
396 ok( ret, "SetMenuInfo failed with error %d\n", GetLastError());
398 ret = InsertMenuItem( hmenu, 0, FALSE, &mii);
399 ok( ret, "InsertMenuItem failed with error %d\n", GetLastError());
400 failed = !ret;
401 if( winetest_debug) {
402 HDC hdc=GetDC(hwnd);
403 RECT rc = {100, 50, 400, 70};
404 char buf[100];
406 sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt);
407 FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW);
408 TextOut( hdc, 100, 50, buf, strlen( buf));
409 ReleaseDC( hwnd, hdc);
411 if(ispop)
412 ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL);
413 else {
414 ret = SetMenu( hwnd, hmenu);
415 ok(ret, "SetMenu failed with error %d\n", GetLastError());
416 DrawMenuBar( hwnd);
418 ret = GetMenuItemRect( hwnd, hmenu, 0, &rc);
419 /* check menu width */
420 if( ispop)
421 expect = ( text || hbmp ?
422 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0)
423 : 0) +
424 arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) +
425 (text && hastab ? /* TAB space */
426 MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) +
427 (text ? 2 + (text[0] ? size.cx :0): 0) ;
428 else
429 expect = !(text || hbmp) ? 0 :
430 ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) +
431 (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ;
432 ok( rc.right - rc.left == expect,
433 "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect);
434 failed = failed || !(rc.right - rc.left == expect);
435 /* check menu height */
436 if( ispop)
437 expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0),
438 max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0),
439 (hbmp ? bmpsize.cy + 2 : 0)));
440 else
441 expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 :
442 max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0)));
443 ok( rc.bottom - rc.top == expect,
444 "menu height wrong, got %d expected %d (%d)\n",
445 rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU));
446 failed = failed || !(rc.bottom - rc.top == expect);
447 if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
448 /* check the position of the bitmap */
449 /* horizontal */
450 expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
451 : 3;
452 ok( expect == MOD_rc[0].left,
453 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
454 failed = failed || !(expect == MOD_rc[0].left);
455 /* vertical */
456 expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2;
457 ok( expect == MOD_rc[0].top,
458 "bitmap top is %d expected %d\n", MOD_rc[0].top, expect);
459 failed = failed || !(expect == MOD_rc[0].top);
461 /* if there was a failure, report details */
462 if( failed) {
463 trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n",
464 count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy,
465 size.cx, size.cy, sc_size.cx, mnuopt, hastab);
466 trace(" check %d,%d arrow %d avechar %d\n",
467 GetSystemMetrics(SM_CXMENUCHECK ),
468 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
469 if( hbmp == HBMMENU_CALLBACK)
470 trace( " rc %d,%d-%d,%d bmp.rc %d,%d-%d,%d\n",
471 rc.left, rc.top, rc.top, rc.bottom, MOD_rc[0].left,
472 MOD_rc[0].top,MOD_rc[0].right, MOD_rc[0].bottom);
474 /* clean up */
475 ret = DestroyMenu(submenu);
476 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
477 ret = DestroyMenu(hmenu);
478 ok(ret, "DestroyMenu failed with error %d\n", GetLastError());
482 static void test_menu_bmp_and_string(void)
484 BYTE bmfill[300];
485 HBITMAP hbm_arrow;
486 BITMAP bm;
487 INT arrowwidth;
488 HWND hwnd;
489 int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop;
491 if( !pGetMenuInfo)
493 skip("GetMenuInfo is not available\n");
494 return;
497 memset( bmfill, 0x55, sizeof( bmfill));
498 hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL,
499 WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
500 NULL, NULL, NULL, NULL);
501 hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW);
502 GetObject( hbm_arrow, sizeof(bm), &bm);
503 arrowwidth = bm.bmWidth;
505 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
506 if( !hwnd) return;
507 SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc);
509 if( winetest_debug)
510 trace(" check %d,%d arrow %d avechar %d\n",
511 GetSystemMetrics(SM_CXMENUCHECK ),
512 GetSystemMetrics(SM_CYMENUCHECK ),arrowwidth, MOD_avec);
513 count = 0;
514 MOD_maxid = 0;
515 for( ispop=1; ispop >= 0; ispop--){
516 static SIZE bmsizes[]= {
517 {10,10},{38,38},{1,30},{55,5}};
518 for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) {
519 HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill);
520 HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL };
521 ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError());
522 for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) {
523 for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */
524 for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */
525 for( bmpidx = 0; bmpidx <sizeof(bitmaps)/sizeof(HBITMAP); bmpidx++) {
526 /* no need to test NULL bitmaps of several sizes */
527 if( !bitmaps[bmpidx] && szidx > 0) continue;
528 if( !ispop && hassub) continue;
529 test_mbs_help( ispop, hassub, mnuopt,
530 hwnd, arrowwidth, ++count,
531 bitmaps[bmpidx],
532 bmsizes[szidx],
533 MOD_txtsizes[txtidx].text,
534 MOD_txtsizes[txtidx].size,
535 MOD_txtsizes[txtidx].sc_size);
540 DeleteObject( hbm);
543 /* clean up */
544 DestroyWindow(hwnd);
547 static void test_menu_add_string( void )
549 HMENU hmenu;
550 MENUITEMINFO info;
551 BOOL rc;
552 int ret;
554 char string[0x80];
555 char string2[0x80];
557 char strback[0x80];
558 WCHAR strbackW[0x80];
559 static CHAR blah[] = "blah";
560 static const WCHAR expectedString[] = {'D','u','m','m','y',' ','s','t','r','i','n','g', 0};
562 hmenu = CreateMenu();
564 memset( &info, 0, sizeof info );
565 info.cbSize = sizeof info;
566 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_ID;
567 info.dwTypeData = blah;
568 info.cch = 6;
569 info.dwItemData = 0;
570 info.wID = 1;
571 info.fState = 0;
572 InsertMenuItem(hmenu, 0, TRUE, &info );
574 memset( &info, 0, sizeof info );
575 info.cbSize = sizeof info;
576 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
577 info.dwTypeData = string;
578 info.cch = sizeof string;
579 string[0] = 0;
580 GetMenuItemInfo( hmenu, 0, TRUE, &info );
582 ok( !strcmp( string, "blah" ), "menu item name differed\n");
584 /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
585 strcpy(string, "Dummy string");
586 memset(&info, 0x00, sizeof(info));
587 info.cbSize= sizeof(MENUITEMINFO);
588 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
589 info.fType= MFT_OWNERDRAW;
590 info.dwTypeData= string;
591 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
592 ok (rc, "InsertMenuItem failed\n");
594 strcpy(string,"Garbage");
595 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
596 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
598 SetLastError(0xdeadbeef);
599 ret = GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION);
600 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
601 skip("GetMenuStringW is not implemented\n");
602 else
604 ok (ret, "GetMenuStringW on ownerdraw entry failed\n");
605 ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
608 /* Just change ftype to string and see what text is stored */
609 memset(&info, 0x00, sizeof(info));
610 info.cbSize= sizeof(MENUITEMINFO);
611 info.fMask= MIIM_FTYPE; /* Set string type */
612 info.fType= MFT_STRING;
613 info.dwTypeData= (char *)0xdeadbeef;
614 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
615 ok (rc, "SetMenuItemInfo failed\n");
617 /* Did we keep the old dwTypeData? */
618 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
619 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
621 /* Ensure change to bitmap type fails */
622 memset(&info, 0x00, sizeof(info));
623 info.cbSize= sizeof(MENUITEMINFO);
624 info.fMask= MIIM_FTYPE; /* Set as bitmap type */
625 info.fType= MFT_BITMAP;
626 info.dwTypeData= (char *)0xdeadbee2;
627 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
628 ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
630 /* Just change ftype back and ensure data hasn't been freed */
631 info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
632 info.dwTypeData= (char *)0xdeadbee3;
633 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
634 ok (rc, "SetMenuItemInfo failed\n");
636 /* Did we keep the old dwTypeData? */
637 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
638 ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
640 /* Just change string value (not type) */
641 memset(&info, 0x00, sizeof(info));
642 info.cbSize= sizeof(MENUITEMINFO);
643 info.fMask= MIIM_STRING; /* Set typeData */
644 strcpy(string2, "string2");
645 info.dwTypeData= string2;
646 rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
647 ok (rc, "SetMenuItemInfo failed\n");
649 ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
650 ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
652 /* crashes with wine 0.9.5 */
653 memset(&info, 0x00, sizeof(info));
654 info.cbSize= sizeof(MENUITEMINFO);
655 info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
656 info.fType= MFT_OWNERDRAW;
657 rc = InsertMenuItem( hmenu, 0, TRUE, &info );
658 ok (rc, "InsertMenuItem failed\n");
659 ok (!GetMenuString( hmenu, 0, NULL, 0, MF_BYPOSITION),
660 "GetMenuString on ownerdraw entry succeeded.\n");
661 SetLastError(0xdeadbeef);
662 ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION);
663 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
664 skip("GetMenuStringW is not implemented\n");
665 else
666 ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n");
668 DestroyMenu( hmenu );
671 /* define building blocks for the menu item info tests */
672 static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
674 if (n <= 0) return 0;
675 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
676 return *str1 - *str2;
679 static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
681 WCHAR *p = dst;
682 while ((*p++ = *src++));
683 return dst;
687 #define DMIINFF( i, e, field)\
688 ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
689 "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
691 #define DUMPMIINF(s,i,e)\
693 DMIINFF( i, e, fMask)\
694 DMIINFF( i, e, fType)\
695 DMIINFF( i, e, fState)\
696 DMIINFF( i, e, wID)\
697 DMIINFF( i, e, hSubMenu)\
698 DMIINFF( i, e, hbmpChecked)\
699 DMIINFF( i, e, hbmpUnchecked)\
700 DMIINFF( i, e, dwItemData)\
701 DMIINFF( i, e, dwTypeData)\
702 DMIINFF( i, e, cch)\
703 if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
706 /* insert menu item */
707 #define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
708 eret1)\
710 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
711 HMENU hmenu = CreateMenu();\
712 BOOL ret, stop = FALSE;\
713 SetLastError( 0xdeadbeef);\
714 if(ansi)strcpy( string, init);\
715 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
716 if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
717 else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
718 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
720 skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\
721 break;\
723 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
724 stop = TRUE;\
725 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
728 /* GetMenuItemInfo + GetMenuString */
729 #define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
730 a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
731 expname, eret2, eret3)\
733 MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
734 MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
735 MENUITEMINFOA *info2 = &info2A;\
736 MENUITEMINFOA *einfo = &einfoA;\
737 MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
738 if( !stop) {\
739 SetLastError( 0xdeadbeef);\
740 ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
741 GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
742 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
744 skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
745 break;\
747 if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
748 else { \
749 ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\
750 ret = memcmp( info2, einfo, sizeof einfoA);\
751 /* ok( ret==0, "Got wrong menu item info data\n");*/\
752 if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
753 if( einfo->dwTypeData == string) {\
754 if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
755 einfo->dwTypeData ? einfo->dwTypeData: "");\
756 else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
757 einfo->dwTypeData ? einfo->dwTypeData: "");\
758 ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
759 GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
760 if( (eret3)){\
761 ok( ret, "GetMenuString failed, err %d\n",GetLastError());\
762 }else\
763 ok( !ret, "GetMenuString should have failed\n");\
769 #define TMII_DONE \
770 RemoveMenu(hmenu, 0, TRUE );\
771 DestroyMenu( hmenu );\
772 DestroyMenu( submenu );\
773 submenu = CreateMenu();\
775 /* modify menu */
776 #define TMII_MODM( flags, id, data, eret )\
777 if( !stop) {\
778 SetLastError( 0xdeadbeef);\
779 if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
780 else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
781 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
783 skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\
784 break;\
786 if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
787 else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\
790 /* SetMenuItemInfo */
791 #define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
792 eret1)\
793 if( !stop) {\
794 MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
795 SetLastError( 0xdeadbeef);\
796 if(ansi)strcpy( string, init);\
797 else strcpyW( (WCHAR*)string, (WCHAR*)init);\
798 if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
799 else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
800 if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\
802 skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\
803 break;\
805 if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
806 stop = TRUE;\
807 } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\
812 #define OK 1
813 #define ER 0
816 static void test_menu_iteminfo( void )
818 int S=sizeof( MENUITEMINFOA);
819 int ansi = TRUE;
820 char txtA[]="wine";
821 char initA[]="XYZ";
822 char emptyA[]="";
823 WCHAR txtW[]={'W','i','n','e',0};
824 WCHAR initW[]={'X','Y','Z',0};
825 WCHAR emptyW[]={0};
826 void *txt, *init, *empty, *string;
827 HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
828 char stringA[0x80];
829 HMENU submenu=CreateMenu();
831 do {
832 if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
833 else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
834 trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt);
835 /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
836 /* (since MFT_STRING is zero, there are four of them) */
837 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
838 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
839 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
840 txt, OK, OK )
841 TMII_DONE
842 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
843 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
844 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
845 empty, OK, ER )
846 TMII_DONE
847 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
848 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
849 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
850 empty, OK, ER )
851 TMII_DONE
852 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
853 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
854 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
855 empty, OK, ER )
856 TMII_DONE
857 /* not enough space for name*/
858 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
859 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
860 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
861 empty, OK, OK )
862 TMII_DONE
863 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
864 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
865 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
866 txt, OK, OK )
867 TMII_DONE
868 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
869 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
870 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
871 txt, OK, OK )
872 TMII_DONE
873 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
874 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
875 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
876 empty, OK, ER )
877 TMII_DONE
878 /* cannot combine MIIM_TYPE with some other flags */
879 TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
880 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
881 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
882 empty, OK, OK )
883 TMII_DONE
884 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
885 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
886 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
887 empty, ER, OK )
888 TMII_DONE
889 TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
890 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
891 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
892 empty, OK, OK )
893 TMII_DONE
894 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
895 TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
896 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
897 empty, ER, OK )
898 TMII_DONE
899 TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
900 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
901 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
902 empty, OK, OK )
903 TMII_DONE
904 /* but succeeds with some others */
905 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
906 TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
907 {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
908 txt, OK, OK )
909 TMII_DONE
910 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
911 TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
912 {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
913 txt, OK, OK )
914 TMII_DONE
915 TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
916 TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
917 {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
918 txt, OK, OK )
919 TMII_DONE
920 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
921 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
922 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
923 txt, OK, OK )
924 TMII_DONE
925 /* to be continued */
926 /* set text with MIIM_TYPE and retrieve with MIIM_STRING */
927 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
928 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
929 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
930 txt, OK, OK )
931 TMII_DONE
932 /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */
933 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
934 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
935 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
936 empty, OK, ER )
937 TMII_DONE
938 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
939 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
940 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
941 empty, OK, ER )
942 TMII_DONE
943 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
944 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
945 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
946 init, OK, ER )
947 TMII_DONE
948 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
949 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
950 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
951 init, OK, OK )
952 TMII_DONE
953 /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */
954 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
955 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
956 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
957 txt, OK, OK )
958 TMII_DONE
959 /* same but retrieve with MIIM_TYPE */
960 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
961 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
962 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
963 txt, OK, OK )
964 TMII_DONE
965 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
966 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
967 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
968 empty, OK, ER )
969 TMII_DONE
970 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
971 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
972 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
973 empty, OK, ER )
974 TMII_DONE
976 /* How is that with bitmaps? */
977 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
978 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
979 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
980 empty, OK, ER )
981 TMII_DONE
982 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
983 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
984 {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
985 init, OK, ER )
986 TMII_DONE
987 /* MIIM_BITMAP does not like MFT_BITMAP */
988 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
989 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
990 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
991 init, OK, OK )
992 TMII_DONE
993 /* no problem with OWNERDRAWN */
994 TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
995 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
996 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
997 init, OK, ER )
998 TMII_DONE
999 /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
1000 TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
1001 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1002 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1003 empty, OK, OK )
1004 TMII_DONE
1006 /* menu with submenu */
1007 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
1008 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1009 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
1010 init, OK, ER )
1011 TMII_DONE
1012 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
1013 TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1014 {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
1015 init, OK, ER )
1016 TMII_DONE
1017 /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
1018 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
1019 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1020 {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
1021 empty, OK, ER )
1022 TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1023 {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
1024 empty, OK, ER )
1025 TMII_DONE
1026 /* menu with invalid submenu */
1027 TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
1028 TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1029 {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
1030 init, OK, ER )
1031 TMII_DONE
1032 /* Separator */
1033 TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
1034 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1035 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1036 empty, OK, ER )
1037 TMII_DONE
1038 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
1039 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1040 {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1041 empty, OK, ER )
1042 TMII_DONE
1043 /* SEPARATOR and STRING go well together */
1044 /* BITMAP and STRING go well together */
1045 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1046 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1047 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1048 txt, OK, OK )
1049 TMII_DONE
1050 /* BITMAP, SEPARATOR and STRING go well together */
1051 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1052 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1053 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
1054 txt, OK, OK )
1055 TMII_DONE
1056 /* last two tests, but use MIIM_TYPE to retrieve info */
1057 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1058 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1059 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1060 txt, OK, OK )
1061 TMII_DONE
1062 TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1063 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1064 {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1065 txt, OK, OK )
1066 TMII_DONE
1067 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1068 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1069 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1070 txt, OK, OK )
1071 TMII_DONE
1072 /* same three with MFT_OWNERDRAW */
1073 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
1074 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1075 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1076 txt, OK, OK )
1077 TMII_DONE
1078 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1079 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1080 {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1081 txt, OK, OK )
1082 TMII_DONE
1083 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1084 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1085 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
1086 txt, OK, OK )
1087 TMII_DONE
1089 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1090 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1091 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1092 txt, OK, OK )
1093 TMII_DONE
1094 /* test with modifymenu: string is preserved after seting OWNERDRAW */
1095 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1096 TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
1097 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1098 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
1099 txt, OK, OK )
1100 TMII_DONE
1101 /* same with bitmap: now the text is cleared */
1102 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1103 TMII_MODM( MFT_BITMAP, 545, hbm, OK)
1104 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1105 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
1106 empty, OK, ER )
1107 TMII_DONE
1108 /* start with bitmap: now setting text clears it (though he flag is raised) */
1109 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1110 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1111 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
1112 empty, OK, ER )
1113 TMII_MODM( MFT_STRING, 545, txt, OK)
1114 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1115 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
1116 txt, OK, OK )
1117 TMII_DONE
1118 /*repeat with text NULL */
1119 TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1120 TMII_MODM( MFT_STRING, 545, NULL, OK)
1121 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1122 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1123 empty, OK, ER )
1124 TMII_DONE
1125 /* repeat with text "" */
1126 TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1127 TMII_MODM( MFT_STRING, 545, empty, OK)
1128 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1129 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
1130 empty, OK, ER )
1131 TMII_DONE
1132 /* start with bitmap: set ownerdraw */
1133 TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1134 TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
1135 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1136 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
1137 empty, OK, ER )
1138 TMII_DONE
1139 /* ask nothing */
1140 TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1141 TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1142 {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
1143 init, OK, OK )
1144 TMII_DONE
1145 /* some tests with small cbSize: the hbmpItem is to be ignored */
1146 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1147 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1148 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1149 empty, OK, ER )
1150 TMII_DONE
1151 TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1152 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1153 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
1154 init, OK, ER )
1155 TMII_DONE
1156 TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1157 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1158 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
1159 txt, OK, OK )
1160 TMII_DONE
1161 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1162 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1163 {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1164 txt, OK, OK )
1165 TMII_DONE
1166 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1167 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1168 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1169 txt, OK, OK )
1170 TMII_DONE
1171 TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
1172 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1173 {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
1174 txt, OK, OK )
1175 TMII_DONE
1176 /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */
1177 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1178 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1179 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
1180 empty, OK, ER )
1181 TMII_DONE
1182 TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1183 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1184 {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
1185 empty, OK, ER )
1186 TMII_DONE
1187 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
1188 TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1189 {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
1190 empty, OK, ER )
1191 TMII_DONE
1192 /* set a string menu to ownerdraw with MIIM_TYPE */
1193 TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
1194 TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1195 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1196 {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1197 txt, OK, OK )
1198 TMII_DONE
1199 /* test with modifymenu add submenu */
1200 TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
1201 TMII_MODM( MF_POPUP, submenu, txt, OK)
1202 TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1203 {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
1204 txt, OK, OK )
1205 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1206 {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
1207 txt, OK, OK )
1208 TMII_DONE
1209 /* MFT_SEPARATOR bit is kept when the text is added */
1210 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1211 TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK)
1212 TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1213 {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, },
1214 txt, OK, OK )
1215 TMII_DONE
1216 /* MFT_SEPARATOR bit is kept when bitmap is added */
1217 TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
1218 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
1219 TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
1220 {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
1221 init, OK, ER )
1222 TMII_DONE
1223 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1224 Only the low word of the dwTypeData is used.
1225 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1226 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1227 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1228 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1229 empty, OK, OK )
1230 TMII_DONE
1231 /* Type flags */
1232 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1233 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1234 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1235 empty, OK, OK )
1236 TMII_DONE
1237 /* State flags */
1238 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1239 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1240 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1241 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1242 empty, OK, OK )
1243 TMII_DONE
1244 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1245 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1246 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1247 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1248 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1249 empty, OK, OK )
1250 TMII_DONE
1251 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1252 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1253 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1254 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1255 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1256 empty, OK, OK )
1257 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1258 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1259 empty, OK, OK )
1260 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1261 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1262 empty, OK, OK )
1263 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1264 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1265 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1266 empty, OK, OK )
1267 TMII_DONE
1268 /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
1269 Only the low word of the dwTypeData is used.
1270 Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
1271 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
1272 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1273 {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
1274 empty, OK, OK )
1275 TMII_DONE
1276 /* Type flags */
1277 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1278 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1279 {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1280 empty, OK, OK )
1281 TMII_DONE
1282 /* State flags */
1283 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1284 TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
1285 TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1286 {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
1287 empty, OK, OK )
1288 TMII_DONE
1289 /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
1290 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1291 TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
1292 TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1293 {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
1294 empty, OK, OK )
1295 TMII_DONE
1296 /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
1297 TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
1298 TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
1299 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1300 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1301 empty, OK, OK )
1302 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1303 {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
1304 empty, OK, OK )
1305 TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1306 {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
1307 empty, OK, OK )
1308 TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
1309 TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
1310 {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
1311 empty, OK, OK )
1312 TMII_DONE
1313 } while( !(ansi = !ansi) );
1314 DeleteObject( hbm);
1318 The following tests try to confirm the algorithm used to return the menu items
1319 when there is a collision between a menu item and a popup menu
1321 static void test_menu_search_bycommand( void )
1323 HMENU hmenu, hmenuSub, hmenuSub2;
1324 MENUITEMINFO info;
1325 BOOL rc;
1326 UINT id;
1327 char strback[0x80];
1328 char strIn[0x80];
1329 static CHAR menuitem[] = "MenuItem",
1330 menuitem2[] = "MenuItem 2";
1332 /* Case 1: Menu containing a menu item */
1333 hmenu = CreateMenu();
1335 memset( &info, 0, sizeof info );
1336 info.cbSize = sizeof info;
1337 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1338 info.fType = MFT_STRING;
1339 strcpy(strIn, "Case 1 MenuItem");
1340 info.dwTypeData = strIn;
1341 info.wID = (UINT) 0x1234;
1343 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1344 ok (rc, "Inserting the menuitem failed\n");
1346 id = GetMenuItemID(hmenu, 0);
1347 ok (id == 0x1234, "Getting the menuitem id failed(gave %x)\n", id);
1349 /* Confirm the menuitem was given the id supplied (getting by position) */
1350 memset( &info, 0, sizeof info );
1351 strback[0] = 0x00;
1352 info.cbSize = sizeof(MENUITEMINFO);
1353 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1354 info.dwTypeData = strback;
1355 info.cch = sizeof(strback);
1357 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1358 ok (rc, "Getting the menu items info failed\n");
1359 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1360 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1362 /* Search by id - Should return the item */
1363 memset( &info, 0, sizeof info );
1364 strback[0] = 0x00;
1365 info.cbSize = sizeof(MENUITEMINFO);
1366 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1367 info.dwTypeData = strback;
1368 info.cch = sizeof(strback);
1369 rc = GetMenuItemInfo(hmenu, 0x1234, FALSE, &info); /* Get by ID */
1371 ok (rc, "Getting the menu items info failed\n");
1372 ok (info.wID == 0x1234, "IDs differ for the menuitem\n");
1373 ok (!strcmp(info.dwTypeData, "Case 1 MenuItem"), "Returned item has wrong label\n");
1375 DestroyMenu( hmenu );
1377 /* Case 2: Menu containing a popup menu */
1378 hmenu = CreateMenu();
1379 hmenuSub = CreateMenu();
1381 strcpy(strIn, "Case 2 SubMenu");
1382 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, strIn);
1383 ok (rc, "Inserting the popup menu into the main menu failed\n");
1385 id = GetMenuItemID(hmenu, 0);
1386 ok (id == -1, "Getting the menuitem id unexpectedly worked (gave %x)\n", id);
1388 /* Confirm the menuitem itself was given an id the same as the HMENU, (getting by position) */
1389 memset( &info, 0, sizeof info );
1390 strback[0] = 0x00;
1391 info.cbSize = sizeof(MENUITEMINFO);
1392 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1393 info.dwTypeData = strback;
1394 info.cch = sizeof(strback);
1395 info.wID = 0xdeadbeef;
1397 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); /* Get by position */
1398 ok (rc, "Getting the menu items info failed\n");
1399 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the menuitem\n");
1400 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1402 /* Search by id - returns the popup menu itself */
1403 memset( &info, 0, sizeof info );
1404 strback[0] = 0x00;
1405 info.cbSize = sizeof(MENUITEMINFO);
1406 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1407 info.dwTypeData = strback;
1408 info.cch = sizeof(strback);
1409 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1411 ok (rc, "Getting the menu items info failed\n");
1412 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1413 ok (!strcmp(info.dwTypeData, "Case 2 SubMenu"), "Returned item has wrong label\n");
1416 Now add an item after it with the same id
1418 memset( &info, 0, sizeof info );
1419 info.cbSize = sizeof info;
1420 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1421 info.fType = MFT_STRING;
1422 strcpy(strIn, "Case 2 MenuItem 1");
1423 info.dwTypeData = strIn;
1424 info.wID = (UINT_PTR) hmenuSub;
1425 rc = InsertMenuItem(hmenu, -1, TRUE, &info );
1426 ok (rc, "Inserting the menuitem failed\n");
1428 /* Search by id - returns the item which follows the popup menu */
1429 memset( &info, 0, sizeof info );
1430 strback[0] = 0x00;
1431 info.cbSize = sizeof(MENUITEMINFO);
1432 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1433 info.dwTypeData = strback;
1434 info.cch = sizeof(strback);
1435 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1437 ok (rc, "Getting the menu items info failed\n");
1438 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1439 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 1"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1442 Now add an item before the popup (with the same id)
1444 memset( &info, 0, sizeof info );
1445 info.cbSize = sizeof info;
1446 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1447 info.fType = MFT_STRING;
1448 strcpy(strIn, "Case 2 MenuItem 2");
1449 info.dwTypeData = strIn;
1450 info.wID = (UINT_PTR) hmenuSub;
1451 rc = InsertMenuItem(hmenu, 0, TRUE, &info );
1452 ok (rc, "Inserting the menuitem failed\n");
1454 /* Search by id - returns the item which precedes the popup menu */
1455 memset( &info, 0, sizeof info );
1456 strback[0] = 0x00;
1457 info.cbSize = sizeof(MENUITEMINFO);
1458 info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
1459 info.dwTypeData = strback;
1460 info.cch = sizeof(strback);
1461 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info); /* Get by ID */
1463 ok (rc, "Getting the menu items info failed\n");
1464 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for the popup menu\n");
1465 ok (!strcmp(info.dwTypeData, "Case 2 MenuItem 2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1467 DestroyMenu( hmenu );
1468 DestroyMenu( hmenuSub );
1471 Case 3: Menu containing a popup menu which in turn
1472 contains 2 items with the same id as the popup itself
1475 hmenu = CreateMenu();
1476 hmenuSub = CreateMenu();
1478 memset( &info, 0, sizeof info );
1479 info.cbSize = sizeof info;
1480 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1481 info.fType = MFT_STRING;
1482 info.dwTypeData = menuitem;
1483 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1485 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1486 ok (rc, "Inserting the popup menu into the main menu failed\n");
1488 rc = InsertMenuItem(hmenuSub, 0, TRUE, &info );
1489 ok (rc, "Inserting the sub menu menuitem failed\n");
1491 memset( &info, 0, sizeof info );
1492 info.cbSize = sizeof info;
1493 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1494 info.fType = MFT_STRING;
1495 info.dwTypeData = menuitem2;
1496 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1498 rc = InsertMenuItem(hmenuSub, 1, TRUE, &info );
1499 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1501 /* Prove that you can't query the id of a popup directly (By position) */
1502 id = GetMenuItemID(hmenu, 0);
1503 ok (id == -1, "Getting the sub menu id should have failed because its a popup (gave %x)\n", id);
1505 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1506 memset( &info, 0, sizeof info );
1507 strback[0] = 0x00;
1508 info.cbSize = sizeof(MENUITEMINFO);
1509 info.fMask = MIIM_STRING | MIIM_ID;
1510 info.dwTypeData = strback;
1511 info.cch = sizeof(strback);
1513 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1514 ok (rc, "Getting the menus info failed\n");
1515 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1516 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1517 DestroyMenu( hmenu );
1518 DestroyMenu( hmenuSub );
1521 Case 4: Menu containing 2 popup menus, the second
1522 contains 2 items with the same id as the first popup menu
1524 hmenu = CreateMenu();
1525 hmenuSub = CreateMenu();
1526 hmenuSub2 = CreateMenu();
1528 rc = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1529 ok (rc, "Inserting the popup menu into the main menu failed\n");
1531 rc = InsertMenu(hmenu, 1, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub2, "Submenu2");
1532 ok (rc, "Inserting the popup menu into the main menu failed\n");
1534 memset( &info, 0, sizeof info );
1535 info.cbSize = sizeof info;
1536 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1537 info.fType = MFT_STRING;
1538 info.dwTypeData = menuitem;
1539 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1541 rc = InsertMenuItem(hmenuSub2, 0, TRUE, &info );
1542 ok (rc, "Inserting the sub menu menuitem failed\n");
1544 memset( &info, 0, sizeof info );
1545 info.cbSize = sizeof info;
1546 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
1547 info.fType = MFT_STRING;
1548 info.dwTypeData = menuitem2;
1549 info.wID = (UINT_PTR) hmenuSub; /* Enforce id collisions with the hmenu of the popup submenu*/
1551 rc = InsertMenuItem(hmenuSub2, 1, TRUE, &info );
1552 ok (rc, "Inserting the sub menu menuitem 2 failed\n");
1554 /* Prove getting the item info via ID returns the first item (not the popup or 2nd item)*/
1555 memset( &info, 0, sizeof info );
1556 strback[0] = 0x00;
1557 info.cbSize = sizeof(MENUITEMINFO);
1558 info.fMask = MIIM_STRING | MIIM_ID;
1559 info.dwTypeData = strback;
1560 info.cch = sizeof(strback);
1562 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub, FALSE, &info);
1563 ok (rc, "Getting the menus info failed\n");
1564 ok (info.wID == (UINT_PTR)hmenuSub, "IDs differ for popup menu\n");
1565 ok (!strcmp(info.dwTypeData, "MenuItem"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1567 memset( &info, 0, sizeof info );
1568 strback[0] = 0x00;
1569 info.cbSize = sizeof(MENUITEMINFO);
1570 info.fMask = MIIM_STRING | MIIM_ID;
1571 info.dwTypeData = strback;
1572 info.cch = sizeof(strback);
1574 rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info);
1575 ok (rc, "Getting the menus info failed\n");
1576 ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n");
1577 ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1579 DestroyMenu( hmenu );
1580 DestroyMenu( hmenuSub );
1581 DestroyMenu( hmenuSub2 );
1585 Case 5: Menu containing a popup menu which in turn
1586 contains an item with a different id than the popup menu.
1587 This tests the fallback to a popup menu ID.
1590 hmenu = CreateMenu();
1591 hmenuSub = CreateMenu();
1593 rc = AppendMenu(hmenu, MF_POPUP | MF_STRING, (UINT_PTR)hmenuSub, "Submenu");
1594 ok (rc, "Appending the popup menu to the main menu failed\n");
1596 rc = AppendMenu(hmenuSub, MF_STRING, 102, "Item");
1597 ok (rc, "Appending the item to the popup menu failed\n");
1599 /* Set the ID for hmenuSub */
1600 info.cbSize = sizeof(info);
1601 info.fMask = MIIM_ID;
1602 info.wID = 101;
1604 rc = SetMenuItemInfo(hmenu, 0, TRUE, &info);
1605 ok(rc, "Setting the ID for the popup menu failed\n");
1607 /* Check if the ID has been set */
1608 info.wID = 0;
1609 rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
1610 ok(rc, "Getting the ID for the popup menu failed\n");
1611 ok(info.wID == 101, "The ID for the popup menu has not been set\n");
1613 /* Prove getting the item info via ID returns the popup menu */
1614 memset( &info, 0, sizeof(info));
1615 strback[0] = 0x00;
1616 info.cbSize = sizeof(MENUITEMINFO);
1617 info.fMask = MIIM_STRING | MIIM_ID;
1618 info.dwTypeData = strback;
1619 info.cch = sizeof(strback);
1621 rc = GetMenuItemInfo(hmenu, 101, FALSE, &info);
1622 ok (rc, "Getting the menu info failed\n");
1623 ok (info.wID == 101, "IDs differ\n");
1624 ok (!strcmp(info.dwTypeData, "Submenu"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1626 /* Also look for the menu item */
1627 memset( &info, 0, sizeof(info));
1628 strback[0] = 0x00;
1629 info.cbSize = sizeof(MENUITEMINFO);
1630 info.fMask = MIIM_STRING | MIIM_ID;
1631 info.dwTypeData = strback;
1632 info.cch = sizeof(strback);
1634 rc = GetMenuItemInfo(hmenu, 102, FALSE, &info);
1635 ok (rc, "Getting the menu info failed\n");
1636 ok (info.wID == 102, "IDs differ\n");
1637 ok (!strcmp(info.dwTypeData, "Item"), "Returned item has wrong label (%s)\n", info.dwTypeData);
1639 DestroyMenu(hmenu);
1640 DestroyMenu(hmenuSub);
1643 struct menu_item_pair_s {
1644 UINT uMenu; /* 1 - top level menu, [0-Menu 1-Enabled 2-Disabled]
1645 * 2 - 2nd level menu, [0-Popup 1-Enabled 2-Disabled]
1646 * 3 - 3rd level menu, [0-Enabled 1-Disabled] */
1647 UINT uItem;
1650 static struct menu_mouse_tests_s {
1651 DWORD type;
1652 struct menu_item_pair_s menu_item_pairs[5]; /* for mousing */
1653 WORD wVk[5]; /* keys */
1654 BOOL bMenuVisible;
1655 BOOL _todo_wine;
1656 } menu_tests[] = {
1657 /* for each test, send keys or clicks and check for menu visibility */
1658 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */
1659 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1660 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1661 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1662 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE },
1663 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1664 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1665 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE },
1666 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE },
1667 { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE },
1668 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1669 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1670 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE },
1671 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1672 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1673 { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE },
1674 { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE },
1675 { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE },
1677 { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */
1678 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1679 { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE },
1680 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1681 { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE },
1682 { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE },
1683 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1684 { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE },
1685 { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE },
1686 { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE },
1687 { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE },
1688 { -1 }
1691 static void send_key(WORD wVk)
1693 TEST_INPUT i[2];
1694 memset(&i, 0, 2*sizeof(INPUT));
1695 i[0].type = i[1].type = INPUT_KEYBOARD;
1696 i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
1697 i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
1698 pSendInput(2, (INPUT *) i, sizeof(INPUT));
1701 static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
1703 HMENU hMenu = hMenus[mi->uMenu];
1704 TEST_INPUT i[3];
1705 MSG msg;
1706 RECT r;
1707 int screen_w = GetSystemMetrics(SM_CXSCREEN);
1708 int screen_h = GetSystemMetrics(SM_CYSCREEN);
1710 GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
1712 memset(&i, 0, 3*sizeof(INPUT));
1713 i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
1714 i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
1715 = ((r.left + 5) * 65535) / screen_w;
1716 i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy
1717 = ((r.top + 5) * 65535) / screen_h;
1718 i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags
1719 = MOUSEEVENTF_ABSOLUTE;
1720 i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE;
1721 i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
1722 i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
1723 pSendInput(3, (INPUT *) i, sizeof(INPUT));
1725 /* hack to prevent mouse message buildup in Wine */
1726 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1729 static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter)
1731 int i, j;
1732 HANDLE hWnd = lpParameter;
1734 Sleep(500);
1735 /* mixed keyboard/mouse test */
1736 for (i = 0; menu_tests[i].type != -1; i++)
1738 int elapsed = 0;
1740 if (menu_tests[i].type == INPUT_KEYBOARD)
1741 for (j = 0; menu_tests[i].wVk[j] != 0; j++)
1742 send_key(menu_tests[i].wVk[j]);
1743 else
1744 for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++)
1745 click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]);
1747 while (menu_tests[i].bMenuVisible != bMenuVisible)
1749 if (elapsed > 200)
1750 break;
1751 elapsed += 20;
1752 Sleep(20);
1755 if (menu_tests[i]._todo_wine)
1757 todo_wine {
1758 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1761 else
1762 ok(menu_tests[i].bMenuVisible == bMenuVisible, "test %d\n", i);
1764 return 0;
1767 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam,
1768 LPARAM lParam)
1770 switch (msg) {
1771 case WM_ENTERMENULOOP:
1772 bMenuVisible = TRUE;
1773 break;
1774 case WM_EXITMENULOOP:
1775 bMenuVisible = FALSE;
1776 break;
1777 default:
1778 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
1780 return 0;
1783 static void test_menu_input(void) {
1784 MSG msg;
1785 WNDCLASSA wclass;
1786 HINSTANCE hInstance = GetModuleHandleA( NULL );
1787 HANDLE hThread, hWnd;
1789 wclass.lpszClassName = "MenuTestClass";
1790 wclass.style = CS_HREDRAW | CS_VREDRAW;
1791 wclass.lpfnWndProc = WndProc;
1792 wclass.hInstance = hInstance;
1793 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
1794 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
1795 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
1796 wclass.lpszMenuName = 0;
1797 wclass.cbClsExtra = 0;
1798 wclass.cbWndExtra = 0;
1799 assert (RegisterClassA( &wclass ));
1800 assert (hWnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
1801 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
1802 400, 200, NULL, NULL, hInstance, NULL) );
1804 /* fixed menus */
1805 hMenus[3] = CreatePopupMenu();
1806 AppendMenu(hMenus[3], MF_STRING, 0, "&Enabled");
1807 AppendMenu(hMenus[3], MF_STRING|MF_DISABLED, 0, "&Disabled");
1809 hMenus[2] = CreatePopupMenu();
1810 AppendMenu(hMenus[2], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[3], "&Popup");
1811 AppendMenu(hMenus[2], MF_STRING, 0, "&Enabled");
1812 AppendMenu(hMenus[2], MF_STRING|MF_DISABLED, 0, "&Disabled");
1814 hMenus[1] = CreateMenu();
1815 AppendMenu(hMenus[1], MF_STRING|MF_POPUP, (UINT_PTR) hMenus[2], "&Menu");
1816 AppendMenu(hMenus[1], MF_STRING, 0, "&Enabled");
1817 AppendMenu(hMenus[1], MF_STRING|MF_DISABLED, 0, "&Disabled");
1819 SetMenu(hWnd, hMenus[1]);
1820 ShowWindow(hWnd, SW_SHOW);
1821 UpdateWindow(hWnd);
1823 hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
1824 while(1)
1826 if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
1827 break;
1828 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
1830 DestroyWindow(hWnd);
1834 int state = 0;
1835 static void do_system_menu_change(HWND hWnd)
1837 HMENU new, back;
1838 BOOL ret;
1839 state++;
1840 if (state >=10)
1841 state = 0;
1842 switch (state)
1844 case 0:
1845 trace("0-------> GetSystemMenu reset\n");
1846 GetSystemMenu(hWnd, TRUE);
1847 break;
1848 case 1:
1850 // fails to set the system menu
1851 new = CreateMenu();
1852 trace("1-------> new CreateMenu: %p\n", new);
1853 ret = AppendMenuA(new, MF_STRING, 0, "&Baz");
1854 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1855 ret = AppendMenuA(new, MF_STRING, 0, "&Boo");
1856 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1857 ret = SetSystemMenu(hWnd, new);
1858 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1859 back = GetSystemMenu(hWnd, FALSE);
1860 trace("set menu:%p get menu:%p\n", new, back);
1861 todo_wine ok(back == NULL, "GetSystemMenu should return null menu not %p\n", back);
1862 break;
1864 case 2:
1866 new = CreatePopupMenu();
1867 trace("2-------> new CreatePopupMenu: %p\n", new);
1868 ret = AppendMenuA(new, MF_STRING, 0, "&Foo");
1869 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1870 ret = AppendMenuA(new, MF_STRING, 0, "&Bar");
1871 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1872 ret = SetSystemMenu(hWnd, new);
1873 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1874 back = GetSystemMenu(hWnd, FALSE);
1875 trace("set menu:%p get menu:%p\n", new, back);
1876 todo_wine ok(back == NULL, "GetSystemMenu should return null menu not %p\n", back);
1877 break;
1879 case 3:
1881 static const WCHAR sysmenuW[] = {'S','Y','S','M','E','N','U',0};
1882 HMODULE user32 = GetModuleHandleA("user32");
1883 /* wine and windows save the system memu different resource name */
1884 new = LoadMenuW(user32, MAKEINTRESOURCEW(16));
1885 if(!new)
1886 new = LoadMenuW(user32, sysmenuW);
1887 trace("3------->LoadMenuW %p\n", new);
1888 ret = SetSystemMenu(hWnd, new);
1889 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1890 back = GetSystemMenu(hWnd, FALSE);
1891 trace("set menu:%p get menu:%p\n", new, back);
1892 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1893 break;
1895 case 4:
1897 HMENU new2;
1898 new = CreatePopupMenu();
1899 new2 = CreatePopupMenu();
1900 trace("4-------> new CreatePopupMenu nested popup: %p/%p\n", new, new2);
1901 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "&Foo");
1902 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1903 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1904 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1905 ret = SetSystemMenu(hWnd, new);
1906 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1907 back = GetSystemMenu(hWnd, FALSE);
1908 trace("set menu:%p get menu:%p\n", new, back);
1909 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1910 break;
1912 case 5:
1914 HMENU new2;
1915 new = CreatePopupMenu();
1916 new2 = CreatePopupMenu();
1917 trace("5-------> new CreatePopupMenu nested popup with a -: %p/%p\n", new, new2);
1918 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "-");
1919 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1920 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1921 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1922 ret = SetSystemMenu(hWnd, new);
1923 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1924 back = GetSystemMenu(hWnd, FALSE);
1925 trace("set menu:%p get menu:%p\n", new, back);
1926 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1927 break;
1929 case 6:
1931 HMENU new2;
1932 new = CreatePopupMenu();
1933 new2 = CreatePopupMenu();
1934 trace("6-------> new CreatePopupMenu nested popup empty: %p/%p\n", new, new2);
1935 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "");
1936 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1937 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1938 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1939 ret = SetSystemMenu(hWnd, new);
1940 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1941 back = GetSystemMenu(hWnd, FALSE);
1942 trace("set menu:%p get menu:%p\n", new, back);
1943 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1944 break;
1946 case 7:
1948 // this seems to be the right behavior on windows
1949 // if the first menu is a popup menu it will corrupt the space below with a popup menu image
1950 HMENU new2;
1951 new = CreateMenu();
1952 new2 = CreatePopupMenu();
1953 trace("7-------> new CreateMenu nested popup empty: %p/%p\n", new, new2);
1954 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "");
1955 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1956 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1957 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1958 ret = SetSystemMenu(hWnd, new);
1959 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1960 back = GetSystemMenu(hWnd, FALSE);
1961 trace("set menu:%p get menu:%p\n", new, back);
1962 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1963 break;
1965 case 8:
1967 // this seems to be the right behavior on windows
1968 // if the first menu is a popup menu it will corrupt the space below with a popup menu image
1969 HMENU new2;
1970 new = CreateMenu();
1971 new2 = CreatePopupMenu();
1972 trace("8-------> new CreateMenu nested popup asdf text: %p/%p\n", new, new2);
1973 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "asdf");
1974 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1975 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1976 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1977 ret = SetSystemMenu(hWnd, new);
1978 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
1979 back = GetSystemMenu(hWnd, FALSE);
1980 trace("set menu:%p get menu:%p\n", new, back);
1981 todo_wine ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
1982 break;
1984 case 9:
1986 // this one prooves windows takes the first submenu and checks if it is a popup menu(MF_POPUP)
1987 // if not it return failure
1988 // hmm above does not seem to be true
1989 HMENU new2;
1990 new = CreateMenu();
1991 new2 = CreatePopupMenu();
1992 trace("9-------> new CreateMenu nested popup asdf text and leading entry: %p/%p\n", new, new2);
1993 ret = AppendMenuA(new, MF_STRING, 0, "&another one");
1994 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1995 ret = AppendMenuA(new, MF_STRING|MF_POPUP, (UINT_PTR)new2, "asdf");
1996 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
1997 ret = AppendMenuA(new2, MF_STRING, 0, "&Bar");
1998 ok(ret, "AppendMenuA failed GLE:%d\n", GetLastError());
2000 ret = SetSystemMenu(hWnd, new);
2001 trace("SetSystemMenu %d, %d\n", ret, GetLastError());
2002 ok(ret, "SetSystemMenu failed GLE:%d\n", GetLastError());
2003 back = GetSystemMenu(hWnd, FALSE);
2004 trace("set menu:%p get menu:%p, GLE:%d\n", new, back, GetLastError());
2005 // ok(back != new, "GetSystemMenu should return a different menu than set by SetSystemMenu %p\n", back);
2006 todo_wine ok(back == NULL, "GetSystemMenu should return null menu not %p\n", back);
2007 break;
2013 static LRESULT CALLBACK SystemMenuTestWndProc(HWND hWnd, UINT msg, WPARAM wParam,
2014 LPARAM lParam)
2016 switch (msg) {
2017 case WM_RBUTTONDOWN:
2018 trace("-----------------WM_RBUTTONDOWN pressed\n");
2019 do_system_menu_change(hWnd);
2020 break;
2021 case WM_DESTROY:
2022 PostQuitMessage (0);
2023 break;
2024 default:
2025 return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
2027 return 0;
2030 static void test_system_menu(void) {
2031 MSG msg;
2032 WNDCLASSA wclass;
2033 HINSTANCE hInstance = GetModuleHandleA( NULL );
2034 HANDLE hWnd;
2035 HMENU hSysMenu, hSysMenu2;
2036 MENUITEMINFOW infoW;
2037 BOOL ret;
2038 UINT default_item;
2040 wclass.lpszClassName = "SystemMenuTestClass";
2041 wclass.style = CS_HREDRAW | CS_VREDRAW;
2042 wclass.lpfnWndProc = SystemMenuTestWndProc;
2043 wclass.hInstance = hInstance;
2044 wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION );
2045 wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW);
2046 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);
2047 wclass.lpszMenuName = 0;
2048 wclass.cbClsExtra = 0;
2049 wclass.cbWndExtra = 0;
2050 assert (RegisterClassA( &wclass ));
2051 assert (hWnd = CreateWindowA( wclass.lpszClassName, "SystemMenuTest",
2052 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
2053 400, 200, NULL, NULL, hInstance, NULL) );
2055 ShowWindow(hWnd, SW_SHOW);
2057 memset(&infoW, 0, sizeof(infoW));
2058 infoW.cbSize = sizeof(infoW);
2059 infoW.fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE | MIIM_ID | MIIM_STATE /*| MIIM_STRING*/ | MIIM_SUBMENU;
2060 hSysMenu = GetSystemMenu(hWnd, FALSE);
2061 hSysMenu2 = GetSystemMenu(hWnd, FALSE);
2062 ok(hSysMenu == hSysMenu2, "GetSystemMenu should return the same menu %p/%p\n", hSysMenu, hSysMenu2);
2064 trace("sysmenu: %p\n", hSysMenu);
2066 ret = GetMenuItemInfoW(hSysMenu, SC_RESTORE, FALSE, &infoW);
2067 trace("SC_RESTORE re:%d fType:%x, fState:%x, wID:%x hSubMenu:%p, hbmpChecked:%p, hbmpUnchecked:%p, dwItemData:%08lx, dwTypeData:%p, cch:%d, hbmpItem:%p\n",
2068 ret, infoW.fType, infoW.fState, infoW.wID, infoW.hSubMenu, infoW.hbmpChecked,
2069 infoW.hbmpUnchecked, infoW.dwItemData, infoW.dwTypeData, infoW.cch, infoW.hbmpItem);
2070 todo_wine{
2071 ok(infoW.hbmpItem == HBMMENU_POPUP_RESTORE, "bitmap for SC_RESTORE wrong (%p)\n", infoW.hbmpItem);
2074 ret = GetMenuItemInfoW(hSysMenu, SC_MINIMIZE, FALSE, &infoW);
2075 trace("SC_MINIMIZE re:%d fType:%x, fState:%x, wID:%x hSubMenu:%p, hbmpChecked:%p, hbmpUnchecked:%p, dwItemData:%08lx, dwTypeData:%p, cch:%d, hbmpItem:%p\n",
2076 ret, infoW.fType, infoW.fState, infoW.wID, infoW.hSubMenu, infoW.hbmpChecked,
2077 infoW.hbmpUnchecked, infoW.dwItemData, infoW.dwTypeData, infoW.cch, infoW.hbmpItem);
2078 todo_wine{
2079 ok(infoW.hbmpItem == HBMMENU_POPUP_MINIMIZE, "bitmap for SC_MINIMIZE wrong (%p)\n", infoW.hbmpItem);
2082 ret = GetMenuItemInfoW(hSysMenu, SC_MAXIMIZE, FALSE, &infoW);
2083 trace("SC_MAXIMIZE re:%d fType:%x, fState:%x, wID:%x hSubMenu:%p, hbmpChecked:%p, hbmpUnchecked:%p, dwItemData:%08lx, dwTypeData:%p, cch:%d, hbmpItem:%p\n",
2084 ret, infoW.fType, infoW.fState, infoW.wID, infoW.hSubMenu, infoW.hbmpChecked,
2085 infoW.hbmpUnchecked, infoW.dwItemData, infoW.dwTypeData, infoW.cch, infoW.hbmpItem);
2086 todo_wine{
2087 ok(infoW.hbmpItem == HBMMENU_POPUP_MAXIMIZE, "bitmap for SC_MAXIMIZE wrong (%p)\n", infoW.hbmpItem);
2090 // WCHAR asdf[128];
2091 // infoW.dwTypeData = asdf;
2092 ret = GetMenuItemInfoW(hSysMenu, SC_CLOSE, FALSE, &infoW);
2093 trace("SC_CLOSE re:%d fType:%x, fState:%x, wID:%x hSubMenu:%p, hbmpChecked:%p, hbmpUnchecked:%p, dwItemData:%08lx, dwTypeData:%p, cch:%d, hbmpItem:%p\n",
2094 ret, infoW.fType, infoW.fState, infoW.wID, infoW.hSubMenu, infoW.hbmpChecked,
2095 infoW.hbmpUnchecked, infoW.dwItemData, infoW.dwTypeData, infoW.cch, infoW.hbmpItem);
2097 ok(ret, "failed to get info for SC_CLOSE GLE:%d\n", GetLastError());
2098 todo_wine{
2099 ok(infoW.hbmpItem == HBMMENU_POPUP_CLOSE, "bitmap for SC_CLOSE wrong (%p)\n", infoW.hbmpItem);
2101 ok(!infoW.fType , "fType should be 0 not %x\n", infoW.fType);
2102 todo_wine{
2103 ok(!infoW.fState , "fState should be 0 not %x\n", infoW.fState);
2105 ok(!infoW.hSubMenu , "hSubMenu should be 0 not %p\n", infoW.hSubMenu);
2106 ok(!infoW.hbmpChecked , "hbmpChecked should be 0 not %p\n", infoW.hbmpChecked);
2107 ok(!infoW.hbmpUnchecked , "hbmpUnchecked should be 0 not %p\n", infoW.hbmpUnchecked);
2108 ok(!infoW.dwItemData , "dwItemData should be 0 not %08lx\n", infoW.dwItemData);
2109 ok(!infoW.dwTypeData , "dwTypeData should be 0 not %p\n", infoW.dwTypeData);
2112 default_item = GetMenuDefaultItem(hSysMenu, FALSE, GMDI_GOINTOPOPUPS|GMDI_USEDISABLED);
2113 todo_wine{
2114 ok(default_item == -1, "default menu item should be -1 not %x\n", default_item);
2116 // trace("%ls\n", asdf);
2118 /* TODO: create a MDI window and test GetSystemMenu on the MDI child */
2119 /* also check the bitmaps/default entry on MDI menu */
2121 while (GetMessage (&msg, 0, 0, 0))
2123 TranslateMessage (&msg);
2124 DispatchMessage (&msg);
2127 DestroyWindow(hWnd);
2130 static void test_menu_flags( void )
2132 HMENU hMenu, hPopupMenu;
2134 hMenu = CreateMenu();
2135 hPopupMenu = CreatePopupMenu();
2137 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
2139 AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
2140 InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
2141 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
2142 ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
2144 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
2145 "AppendMenu should accept MF_HILITE\n");
2146 ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
2147 "InsertMenu should accept MF_HILITE\n");
2148 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2149 "ModifyMenu should accept MF_HILITE\n");
2151 ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
2152 "AppendMenu must not accept MF_DEFAULT\n");
2153 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
2154 "InsertMenu must not accept MF_DEFAULT\n");
2155 ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
2156 "ModifyMenu must not accept MF_DEFAULT\n");
2158 DestroyMenu(hMenu);
2161 static void test_menu_hilitemenuitem( void )
2163 HMENU hMenu, hPopupMenu;
2165 hMenu = CreateMenu();
2166 hPopupMenu = CreatePopupMenu();
2168 AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
2170 AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
2171 AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
2172 AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
2174 HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
2175 HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
2176 HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
2177 HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
2179 todo_wine
2181 ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
2182 "HiliteMenuItem: Item 1 is not hilited\n");
2184 ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
2185 "HiliteMenuItem: Item 2 is hilited\n");
2186 todo_wine
2188 ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
2189 "HiliteMenuItem: Item 3 is not hilited\n");
2192 DestroyMenu(hMenu);
2195 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
2196 UINT checked_state)
2198 UINT i, count;
2200 count = GetMenuItemCount(hmenu);
2202 for (i = 0; i < count; i++)
2204 BOOL ret;
2205 MENUITEMINFO mii;
2207 memset(&mii, 0, sizeof(mii));
2208 mii.cbSize = sizeof(mii);
2209 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
2210 ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2211 ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2212 #if 0
2213 trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
2214 i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
2215 #endif
2216 if (mii.hSubMenu)
2218 ok((HMENU)mii.wID == mii.hSubMenu, "id %u: wID should be equal to hSubMenu\n", checked_cmd);
2219 check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state);
2221 else
2223 if (mii.wID == checked_cmd)
2225 ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType);
2226 ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState);
2227 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2229 else
2231 ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID);
2233 if (mii.fType == MFT_SEPARATOR)
2235 ok(mii.fState == MFS_GRAYED, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd, mii.fState);
2236 ok(mii.wID == 0, "id %u: expected wID 0, got %u\n", checked_cmd, mii.wID);
2238 else
2240 ok(mii.fState == 0, "id %u: expected fState 0, got %04x\n", checked_cmd, mii.fState);
2241 ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd);
2248 static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags)
2250 BOOL ret;
2251 MENUITEMINFO mii;
2253 memset(&mii, 0, sizeof(mii));
2254 mii.cbSize = sizeof(mii);
2255 mii.fMask = MIIM_FTYPE | MIIM_STATE;
2256 ret = SetMenuItemInfo(hmenu, id, (flags & MF_BYPOSITION) != 0, &mii);
2257 ok(ret, "SetMenuItemInfo(%u) failed\n", id);
2260 static void test_CheckMenuRadioItem(void)
2262 BOOL ret;
2263 HMENU hmenu;
2265 hmenu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1));
2266 assert(hmenu != 0);
2268 check_menu_items(hmenu, -1, 0, 0);
2270 ret = CheckMenuRadioItem(hmenu, 100, 100, 100, MF_BYCOMMAND);
2271 ok(ret, "CheckMenuRadioItem failed\n");
2272 check_menu_items(hmenu, 100, MFT_RADIOCHECK, MFS_CHECKED);
2274 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2275 ret = CheckMenuRadioItem(hmenu, 100, 100, -1, MF_BYCOMMAND);
2276 ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2277 check_menu_items(hmenu, 100, MFT_RADIOCHECK, 0);
2279 /* clear check */
2280 clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND);
2281 check_menu_items(hmenu, -1, 0, 0);
2283 /* first and checked items are on different menus */
2284 ret = CheckMenuRadioItem(hmenu, 0, 300, 202, MF_BYCOMMAND);
2285 ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2286 check_menu_items(hmenu, -1, 0, 0);
2288 ret = CheckMenuRadioItem(hmenu, 200, 300, 202, MF_BYCOMMAND);
2289 ok(ret, "CheckMenuRadioItem failed\n");
2290 check_menu_items(hmenu, 202, MFT_RADIOCHECK, MFS_CHECKED);
2292 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
2293 ret = CheckMenuRadioItem(hmenu, 202, 202, -1, MF_BYCOMMAND);
2294 ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2295 check_menu_items(hmenu, 202, MFT_RADIOCHECK, 0);
2297 /* clear check */
2298 clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND);
2299 check_menu_items(hmenu, -1, 0, 0);
2301 /* just for fun, try to check separator */
2302 ret = CheckMenuRadioItem(hmenu, 0, 300, 0, MF_BYCOMMAND);
2303 ok(!ret, "CheckMenuRadioItem should return FALSE\n");
2304 check_menu_items(hmenu, -1, 0, 0);
2307 static void test_menu_resource_layout(void)
2309 static const struct
2311 MENUITEMTEMPLATEHEADER mith;
2312 WORD data[14];
2313 } menu_template =
2315 { 0, 0 }, /* versionNumber, offset */
2317 /* mtOption, mtID, mtString[] '\0' terminated */
2318 MF_STRING, 1, 'F', 0,
2319 MF_STRING, 2, 0,
2320 MF_SEPARATOR, 3, 0,
2321 /* MF_SEPARATOR, 4, 'S', 0, FIXME: Wine ignores 'S' */
2322 MF_STRING|MF_GRAYED|MF_END, 5, 'E', 0
2325 static const struct
2327 UINT type, state, id;
2328 const char *str;
2329 } menu_data[] =
2331 { MF_STRING, MF_ENABLED, 1, "F" },
2332 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 2, "" },
2333 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 3, "" },
2334 /*{ MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 4, "S" }, FIXME: Wine ignores 'S'*/
2335 { MF_STRING, MF_GRAYED, 5, "E" },
2336 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 6, "" },
2337 { MF_STRING, MF_ENABLED, 7, "" },
2338 { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" }
2340 HMENU hmenu;
2341 UINT count, i;
2342 BOOL ret;
2344 hmenu = LoadMenuIndirect(&menu_template);
2345 ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError());
2347 ret = AppendMenu(hmenu, MF_STRING, 6, NULL);
2348 ok(ret, "AppendMenu failed\n");
2349 ret = AppendMenu(hmenu, MF_STRING, 7, "\0");
2350 ok(ret, "AppendMenu failed\n");
2351 ret = AppendMenu(hmenu, MF_SEPARATOR, 8, "separator");
2352 ok(ret, "AppendMenu failed\n");
2354 count = GetMenuItemCount(hmenu);
2355 ok(count == sizeof(menu_data)/sizeof(menu_data[0]),
2356 "expected %u menu items, got %u\n",
2357 (UINT)(sizeof(menu_data)/sizeof(menu_data[0])), count);
2359 for (i = 0; i < count; i++)
2361 char buf[20];
2362 MENUITEMINFO mii;
2364 memset(&mii, 0, sizeof(mii));
2365 mii.cbSize = sizeof(mii);
2366 mii.dwTypeData = buf;
2367 mii.cch = sizeof(buf);
2368 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_STRING;
2369 ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2370 ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2371 #if 0
2372 trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
2373 i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
2374 #endif
2375 ok(mii.fType == menu_data[i].type,
2376 "%u: expected fType %04x, got %04x\n", i, menu_data[i].type, mii.fType);
2377 ok(mii.fState == menu_data[i].state,
2378 "%u: expected fState %04x, got %04x\n", i, menu_data[i].state, mii.fState);
2379 ok(mii.wID == menu_data[i].id,
2380 "%u: expected wID %04x, got %04x\n", i, menu_data[i].id, mii.wID);
2381 ok(mii.cch == strlen(menu_data[i].str),
2382 "%u: expected cch %u, got %u\n", i, (UINT)strlen(menu_data[i].str), mii.cch);
2383 ok(!strcmp((LPCSTR)mii.dwTypeData, menu_data[i].str),
2384 "%u: expected dwTypeData %s, got %s\n", i, menu_data[i].str, (LPCSTR)mii.dwTypeData);
2387 DestroyMenu(hmenu);
2390 struct menu_data
2392 UINT type, id;
2393 const char *str;
2396 static HMENU create_menu_from_data(const struct menu_data *item, INT item_count)
2398 HMENU hmenu;
2399 INT i;
2400 BOOL ret;
2402 hmenu = CreateMenu();
2403 assert(hmenu != 0);
2405 for (i = 0; i < item_count; i++)
2407 SetLastError(0xdeadbeef);
2408 ret = AppendMenu(hmenu, item[i].type, item[i].id, item[i].str);
2409 ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %u\n",
2410 i, item[i].type, item[i].id, item[i].str, GetLastError());
2412 return hmenu;
2415 static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count)
2417 INT count, i;
2418 BOOL ret;
2420 count = GetMenuItemCount(hmenu);
2421 ok(count == item_count, "expected %d, got %d menu items\n", count, item_count);
2423 for (i = 0; i < count; i++)
2425 char buf[20];
2426 MENUITEMINFO mii;
2428 memset(&mii, 0, sizeof(mii));
2429 mii.cbSize = sizeof(mii);
2430 mii.dwTypeData = buf;
2431 mii.cch = sizeof(buf);
2432 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_BITMAP;
2433 ret = GetMenuItemInfo(hmenu, i, TRUE, &mii);
2434 ok(ret, "GetMenuItemInfo(%u) failed\n", i);
2435 #if 0
2436 trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
2437 i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
2438 #endif
2439 ok(mii.fType == item[i].type,
2440 "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType);
2441 ok(mii.wID == item[i].id,
2442 "%u: expected wID %04x, got %04x\n", i, item[i].id, mii.wID);
2443 if (item[i].type & (MF_BITMAP | MF_SEPARATOR))
2445 /* For some reason Windows sets high word to not 0 for
2446 * not "magic" ids.
2448 ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str),
2449 "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem);
2451 else
2453 ok(mii.cch == strlen(item[i].str),
2454 "%u: expected cch %u, got %u\n", i, (UINT)strlen(item[i].str), mii.cch);
2455 ok(!strcmp((LPCSTR)mii.dwTypeData, item[i].str),
2456 "%u: expected dwTypeData %s, got %s\n", i, item[i].str, (LPCSTR)mii.dwTypeData);
2461 static void test_InsertMenu(void)
2463 /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2464 * regardless of their id.
2466 static const struct menu_data in1[] =
2468 { MF_STRING, 1, "File" },
2469 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2470 { MF_STRING|MF_HELP, 2, "Help" }
2472 static const struct menu_data out1[] =
2474 { MF_STRING, 1, "File" },
2475 { MF_STRING|MF_HELP, 2, "Help" },
2476 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) }
2478 static const struct menu_data in2[] =
2480 { MF_STRING, 1, "File" },
2481 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2482 { MF_STRING|MF_HELP, 2, "Help" }
2484 static const struct menu_data out2[] =
2486 { MF_STRING, 1, "File" },
2487 { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) },
2488 { MF_STRING|MF_HELP, 2, "Help" }
2490 static const struct menu_data in3[] =
2492 { MF_STRING, 1, "File" },
2493 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) },
2494 { MF_STRING|MF_HELP, 2, "Help" }
2496 static const struct menu_data out3[] =
2498 { MF_STRING, 1, "File" },
2499 { MF_SEPARATOR|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(0) },
2500 { MF_STRING|MF_HELP, 2, "Help" },
2502 static const struct menu_data in4[] =
2504 { MF_STRING, 1, "File" },
2505 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) },
2506 { MF_STRING|MF_HELP, 2, "Help" }
2508 static const struct menu_data out4[] =
2510 { MF_STRING, 1, "File" },
2511 { MF_STRING|MF_HELP, 2, "Help" },
2512 { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) }
2514 HMENU hmenu;
2516 #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0]))
2517 #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0]))
2519 hmenu = create_menu(in1);
2520 compare_menu(hmenu, out1);
2521 DestroyMenu(hmenu);
2523 hmenu = create_menu(in2);
2524 compare_menu(hmenu, out2);
2525 DestroyMenu(hmenu);
2527 hmenu = create_menu(in3);
2528 compare_menu(hmenu, out3);
2529 DestroyMenu(hmenu);
2531 hmenu = create_menu(in4);
2532 compare_menu(hmenu, out4);
2533 DestroyMenu(hmenu);
2535 #undef create_menu
2536 #undef compare_menu
2539 START_TEST(menu)
2541 init_function_pointers();
2543 register_menu_check_class();
2545 if(winetest_interactive)
2547 test_system_menu();
2548 return;
2551 test_menu_locked_by_window();
2552 test_menu_ownerdraw();
2553 test_menu_add_string();
2554 test_menu_iteminfo();
2555 test_menu_search_bycommand();
2556 test_menu_bmp_and_string();
2558 if( !pSendInput)
2559 skip("SendInput is not available\n");
2560 else
2561 test_menu_input();
2562 test_menu_flags();
2564 test_menu_hilitemenuitem();
2565 test_CheckMenuRadioItem();
2566 test_menu_resource_layout();
2567 test_InsertMenu();