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