* Sync up to trunk head (r65394).
[reactos.git] / win32ss / user / ntuser / menu.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Menus
5 * FILE: subsys/win32k/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMenu);
11
12 /* INTERNAL ******************************************************************/
13
14 BOOL FASTCALL IntSetMenuItemInfo(PMENU, PITEM, PROSMENUITEMINFO, PUNICODE_STRING);
15
16 /* maximum allowed depth of any branch in the menu tree.
17 * This value is slightly larger than in windows (25) to
18 * stay on the safe side. */
19 #define MAXMENUDEPTH 30
20
21 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
22
23 #define MENUITEMINFO_TYPE_MASK \
24 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
25 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
26 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
27
28 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
29
30 #define STATE_MASK (~TYPE_MASK)
31
32 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
33
34 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
35
36 /* Maximum number of menu items a menu can contain */
37 #define MAX_MENU_ITEMS (0x4000)
38 #define MAX_GOINTOSUBMENU (0x10)
39
40 #define UpdateMenuItemState(state, change) \
41 {\
42 if((change) & MF_GRAYED) { \
43 (state) |= MF_GRAYED; \
44 } else { \
45 (state) &= ~MF_GRAYED; \
46 } /* Separate the two for test_menu_resource_layout.*/ \
47 if((change) & MF_DISABLED) { \
48 (state) |= MF_DISABLED; \
49 } else { \
50 (state) &= ~MF_DISABLED; \
51 } \
52 if((change) & MFS_CHECKED) { \
53 (state) |= MFS_CHECKED; \
54 } else { \
55 (state) &= ~MFS_CHECKED; \
56 } \
57 if((change) & MFS_HILITE) { \
58 (state) |= MFS_HILITE; \
59 } else { \
60 (state) &= ~MFS_HILITE; \
61 } \
62 if((change) & MFS_DEFAULT) { \
63 (state) |= MFS_DEFAULT; \
64 } else { \
65 (state) &= ~MFS_DEFAULT; \
66 } \
67 if((change) & MF_MOUSESELECT) { \
68 (state) |= MF_MOUSESELECT; \
69 } else { \
70 (state) &= ~MF_MOUSESELECT; \
71 } \
72 }
73
74 #if 0
75 void FASTCALL
76 DumpMenuItemList(PMENU Menu, PITEM MenuItem)
77 {
78 UINT cnt = 0, i = Menu->cItems;
79 while(i)
80 {
81 if(MenuItem->lpstr.Length)
82 DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->lpstr);
83 else
84 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->lpstr.Buffer);
85 DbgPrint(" fType=");
86 if(MFT_BITMAP & MenuItem->fType)
87 DbgPrint("MFT_BITMAP ");
88 if(MFT_MENUBARBREAK & MenuItem->fType)
89 DbgPrint("MFT_MENUBARBREAK ");
90 if(MFT_MENUBREAK & MenuItem->fType)
91 DbgPrint("MFT_MENUBREAK ");
92 if(MFT_OWNERDRAW & MenuItem->fType)
93 DbgPrint("MFT_OWNERDRAW ");
94 if(MFT_RADIOCHECK & MenuItem->fType)
95 DbgPrint("MFT_RADIOCHECK ");
96 if(MFT_RIGHTJUSTIFY & MenuItem->fType)
97 DbgPrint("MFT_RIGHTJUSTIFY ");
98 if(MFT_SEPARATOR & MenuItem->fType)
99 DbgPrint("MFT_SEPARATOR ");
100 if(MFT_STRING & MenuItem->fType)
101 DbgPrint("MFT_STRING ");
102 DbgPrint("\n fState=");
103 if(MFS_DISABLED & MenuItem->fState)
104 DbgPrint("MFS_DISABLED ");
105 else
106 DbgPrint("MFS_ENABLED ");
107 if(MFS_CHECKED & MenuItem->fState)
108 DbgPrint("MFS_CHECKED ");
109 else
110 DbgPrint("MFS_UNCHECKED ");
111 if(MFS_HILITE & MenuItem->fState)
112 DbgPrint("MFS_HILITE ");
113 else
114 DbgPrint("MFS_UNHILITE ");
115 if(MFS_DEFAULT & MenuItem->fState)
116 DbgPrint("MFS_DEFAULT ");
117 if(MFS_GRAYED & MenuItem->fState)
118 DbgPrint("MFS_GRAYED ");
119 DbgPrint("\n wId=%d\n", MenuItem->wID);
120 MenuItem++;
121 i--;
122 }
123 DbgPrint("Entries: %d\n", cnt);
124 return;
125 }
126 #endif
127
128 #define FreeMenuText(Menu,MenuItem) \
129 { \
130 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
131 (MenuItem)->lpstr.Length) { \
132 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
133 } \
134 }
135
136 PMENU FASTCALL
137 IntGetMenuObject(HMENU hMenu)
138 {
139 PMENU Menu = UserGetMenuObject(hMenu);
140 if (Menu)
141 Menu->head.cLockObj++;
142
143 return Menu;
144 }
145
146 PMENU FASTCALL VerifyMenu(PMENU pMenu)
147 {
148 HMENU hMenu;
149 PITEM pItem;
150 UINT i;
151 if (!pMenu) return NULL;
152
153 _SEH2_TRY
154 {
155 hMenu = UserHMGetHandle(pMenu);
156 pItem = pMenu->rgItems;
157 if (pItem)
158 {
159 i = pItem[0].wID;
160 pItem[0].wID = i;
161 }
162 }
163 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
164 {
165 ERR("Run away LOOP!\n");
166 _SEH2_YIELD(return NULL);
167 }
168 _SEH2_END
169
170 if ( UserObjectInDestroy(hMenu))
171 {
172 ERR("Menu is marked for destruction!\n");
173 return NULL;
174 }
175
176 return pMenu;
177 }
178
179 BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
180 {
181 PMENU SubMenu;
182
183 if (pMenu->rgItems) /* recursively destroy submenus */
184 {
185 int i;
186 ITEM *item = pMenu->rgItems;
187 for (i = pMenu->cItems; i > 0; i--, item++)
188 {
189 SubMenu = item->spSubMenu;
190 item->spSubMenu = NULL;
191
192 /* Remove Item Text */
193 FreeMenuText(pMenu,item);
194
195 /* Remove Item Bitmap and set it for this process */
196 if (item->hbmp && !(item->fState & MFS_HBMMENUBMP))
197 {
198 GreSetObjectOwner(item->hbmp, GDI_OBJ_HMGR_POWNED);
199 item->hbmp = NULL;
200 }
201
202 /* Remove Item submenu */
203 if (bRecurse && SubMenu)//VerifyMenu(SubMenu))
204 {
205 /* Release submenu since it was referenced when inserted */
206 IntReleaseMenuObject(SubMenu);
207 IntDestroyMenuObject(SubMenu, bRecurse);
208 }
209 }
210 /* Free the Item */
211 DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems );
212 pMenu->rgItems = NULL;
213 pMenu->cItems = 0;
214 }
215 return TRUE;
216 }
217
218 /* Callback for the object manager */
219 BOOLEAN
220 UserDestroyMenuObject(PVOID Object)
221 {
222 return IntDestroyMenuObject(Object, TRUE);
223 }
224
225 BOOL FASTCALL
226 IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
227 {
228 if(Menu)
229 {
230 PWND Window;
231
232 /* Remove all menu items */
233 IntDestroyMenu( Menu, bRecurse);
234
235 if (PsGetCurrentProcessSessionId() == Menu->head.rpdesk->rpwinstaParent->dwSessionId)
236 {
237 BOOL ret;
238 if (Menu->hWnd)
239 {
240 Window = UserGetWindowObject(Menu->hWnd);
241 if (Window)
242 {
243 Window->IDMenu = 0;
244
245 /* DestroyMenu should not destroy system menu popup owner */
246 if ((Menu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP)
247 {
248 // Should we check it to see if it has Class?
249 ERR("FIXME Pop up menu window thing'ie\n");
250 //co_UserDestroyWindow( Window );
251 //Menu->hWnd = 0;
252 }
253 }
254 }
255 ret = UserDeleteObject(Menu->head.h, TYPE_MENU);
256 if (!ret)
257 { // Make sure it is really dead or just marked for deletion.
258 ret = UserObjectInDestroy(Menu->head.h);
259 if (ret && EngGetLastError() == ERROR_INVALID_HANDLE) ret = FALSE;
260 } // See test_subpopup_locked_by_menu tests....
261 return ret;
262 }
263 }
264 return FALSE;
265 }
266
267 /**********************************************************************
268 * MENU_depth
269 *
270 * detect if there are loops in the menu tree (or the depth is too large)
271 */
272 int FASTCALL MENU_depth( PMENU pmenu, int depth)
273 {
274 UINT i;
275 ITEM *item;
276 int subdepth;
277
278 if (!pmenu) return depth;
279
280 depth++;
281 if( depth > MAXMENUDEPTH) return depth;
282 item = pmenu->rgItems;
283 subdepth = depth;
284 for( i = 0; item, i < pmenu->cItems && subdepth <= MAXMENUDEPTH; i++, item++)
285 {
286 if( item->spSubMenu)//VerifyMenu(item->spSubMenu))
287 {
288 int bdepth = MENU_depth( item->spSubMenu, depth);
289 if( bdepth > subdepth) subdepth = bdepth;
290 }
291 if( subdepth > MAXMENUDEPTH)
292 TRACE("<- hmenu %p\n", item->spSubMenu);
293 }
294 return subdepth;
295 }
296
297 /***********************************************************************
298 * MENU_FindItem
299 *
300 * Find a menu item. Return a pointer on the item, and modifies *hmenu
301 * in case the item was in a sub-menu.
302 */
303 PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags )
304 {
305 MENU *menu = *pmenu;
306 ITEM *fallback = NULL;
307 UINT fallback_pos = 0;
308 UINT i;
309
310 if (!menu) return NULL;
311
312 if (wFlags & MF_BYPOSITION)
313 {
314 if (!menu->cItems) return NULL;
315 if (*nPos >= menu->cItems) return NULL;
316 return &menu->rgItems[*nPos];
317 }
318 else
319 {
320 PITEM item = menu->rgItems;
321 for (i = 0; item, i < menu->cItems; i++, item++)
322 {
323 if (item->spSubMenu)
324 {
325 PMENU psubmenu = item->spSubMenu;//VerifyMenu(item->spSubMenu);
326 PITEM subitem = MENU_FindItem( &psubmenu, nPos, wFlags );
327 if (subitem)
328 {
329 *pmenu = psubmenu;
330 return subitem;
331 }
332 else if (item->wID == *nPos)
333 {
334 /* fallback to this item if nothing else found */
335 fallback_pos = i;
336 fallback = item;
337 }
338 }
339 else if (item->wID == *nPos)
340 {
341 *nPos = i;
342 return item;
343 }
344 }
345 }
346
347 if (fallback)
348 *nPos = fallback_pos;
349
350 return fallback;
351 }
352
353 BOOL FASTCALL
354 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
355 {
356 PITEM item;
357
358 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu, nPos, wFlags);
359 if (!(item = MENU_FindItem( &pMenu, &nPos, wFlags ))) return FALSE;
360
361 /* Remove item */
362
363 FreeMenuText(pMenu,item);
364 if (bRecurse && item->spSubMenu)
365 {
366 IntDestroyMenuObject(item->spSubMenu, bRecurse);
367 }
368 ////// Use cAlloced with inc's of 8's....
369 if (--pMenu->cItems == 0)
370 {
371 DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems );
372 pMenu->rgItems = NULL;
373 }
374 else
375 {
376 while(nPos < pMenu->cItems)
377 {
378 *item = *(item+1);
379 item++;
380 nPos++;
381 }
382 pMenu->rgItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
383 }
384 return TRUE;
385 }
386
387 /**********************************************************************
388 * MENU_InsertItem
389 *
390 * Insert (allocate) a new item into a menu.
391 */
392 ITEM *MENU_InsertItem( PMENU menu, UINT pos, UINT flags, PMENU *submenu, UINT *npos )
393 {
394 ITEM *newItems;
395
396 /* Find where to insert new item */
397
398 if (flags & MF_BYPOSITION) {
399 if (pos > menu->cItems)
400 pos = menu->cItems;
401 } else {
402 if (!MENU_FindItem( &menu, &pos, flags ))
403 {
404 if (submenu) *submenu = menu;
405 if (npos) *npos = pos;
406 pos = menu->cItems;
407 }
408 }
409
410 /* Make sure that MDI system buttons stay on the right side.
411 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
412 * regardless of their id.
413 */
414 while ( pos > 0 &&
415 (INT_PTR)menu->rgItems[pos - 1].hbmp >= (INT_PTR)HBMMENU_SYSTEM &&
416 (INT_PTR)menu->rgItems[pos - 1].hbmp <= (INT_PTR)HBMMENU_MBAR_CLOSE_D)
417 pos--;
418
419 TRACE("inserting at %u flags %x\n", pos, flags);
420
421 /* Create new items array */
422
423 newItems = DesktopHeapAlloc(menu->head.rpdesk, sizeof(ITEM) * (menu->cItems+1) );
424 if (!newItems)
425 {
426 WARN("allocation failed\n" );
427 return NULL;
428 }
429 if (menu->cItems > 0)
430 {
431 /* Copy the old array into the new one */
432 if (pos > 0) RtlCopyMemory( newItems, menu->rgItems, pos * sizeof(ITEM) );
433 if (pos < menu->cItems) RtlCopyMemory( &newItems[pos+1], &menu->rgItems[pos], (menu->cItems-pos)*sizeof(ITEM) );
434 DesktopHeapFree(menu->head.rpdesk, menu->rgItems );
435 }
436 menu->rgItems = newItems;
437 menu->cItems++;
438 RtlZeroMemory( &newItems[pos], sizeof(*newItems) );
439 menu->cyMenu = 0; /* force size recalculate */
440 return &newItems[pos];
441 }
442
443 BOOL FASTCALL
444 IntInsertMenuItem(
445 _In_ PMENU MenuObject,
446 UINT uItem,
447 BOOL fByPosition,
448 PROSMENUITEMINFO ItemInfo,
449 PUNICODE_STRING lpstr)
450 {
451 PITEM MenuItem;
452 PMENU SubMenu = NULL;
453
454 NT_ASSERT(MenuObject != NULL);
455
456 if (MAX_MENU_ITEMS <= MenuObject->cItems)
457 {
458 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
459 return FALSE;
460 }
461
462 SubMenu = MenuObject;
463
464 if(!(MenuItem = MENU_InsertItem( SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, &SubMenu, &uItem ))) return FALSE;
465
466 if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo, lpstr))
467 {
468 IntRemoveMenuItem(SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, FALSE);
469 return FALSE;
470 }
471
472 /* Force size recalculation! */
473 SubMenu->cyMenu = 0;
474 MenuItem->hbmpChecked = MenuItem->hbmpUnchecked = 0;
475
476 TRACE("IntInsertMenuItemToList = %i %d\n", uItem, (BOOL)((INT)uItem >= 0));
477
478 return TRUE;
479 }
480
481 PMENU FASTCALL
482 IntCreateMenu(
483 _Out_ PHANDLE Handle,
484 _In_ BOOL IsMenuBar,
485 _In_ PDESKTOP Desktop,
486 _In_ PPROCESSINFO ppi)
487 {
488 PMENU Menu;
489
490 Menu = (PMENU)UserCreateObject( gHandleTable,
491 Desktop,
492 ppi->ptiList,
493 Handle,
494 TYPE_MENU,
495 sizeof(MENU));
496 if(!Menu)
497 {
498 *Handle = 0;
499 return NULL;
500 }
501
502 Menu->cyMax = 0; /* Default */
503 Menu->hbrBack = NULL; /* No brush */
504 Menu->dwContextHelpId = 0; /* Default */
505 Menu->dwMenuData = 0; /* Default */
506 Menu->iItem = NO_SELECTED_ITEM; // Focused item
507 Menu->fFlags = (IsMenuBar ? 0 : MNF_POPUP);
508 Menu->spwndNotify = NULL;
509 Menu->cyMenu = 0; // Height
510 Menu->cxMenu = 0; // Width
511 Menu->cItems = 0; // Item count
512 Menu->iTop = 0;
513 Menu->iMaxTop = 0;
514 Menu->cxTextAlign = 0;
515 Menu->rgItems = NULL;
516
517 Menu->hWnd = NULL;
518 Menu->TimeToHide = FALSE;
519
520 return Menu;
521 }
522
523 BOOL FASTCALL
524 IntCloneMenuItems(PMENU Destination, PMENU Source)
525 {
526 PITEM MenuItem, NewMenuItem = NULL;
527 UINT i;
528
529 if(!Source->cItems)
530 return FALSE;
531
532 NewMenuItem = DesktopHeapAlloc(Destination->head.rpdesk, (Source->cItems+1) * sizeof(ITEM));
533 if(!NewMenuItem) return FALSE;
534
535 RtlZeroMemory(NewMenuItem, (Source->cItems+1) * sizeof(ITEM));
536
537 Destination->rgItems = NewMenuItem;
538
539 MenuItem = Source->rgItems;
540 for (i = 0; i < Source->cItems; i++, MenuItem++, NewMenuItem++)
541 {
542 NewMenuItem->fType = MenuItem->fType;
543 NewMenuItem->fState = MenuItem->fState;
544 NewMenuItem->wID = MenuItem->wID;
545 NewMenuItem->spSubMenu = MenuItem->spSubMenu;
546 NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
547 NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
548 NewMenuItem->dwItemData = MenuItem->dwItemData;
549 if (MenuItem->lpstr.Length)
550 {
551 NewMenuItem->lpstr.Length = 0;
552 NewMenuItem->lpstr.MaximumLength = MenuItem->lpstr.MaximumLength;
553 NewMenuItem->lpstr.Buffer = DesktopHeapAlloc(Destination->head.rpdesk, MenuItem->lpstr.MaximumLength);
554 if (!NewMenuItem->lpstr.Buffer)
555 {
556 DesktopHeapFree(Destination->head.rpdesk, NewMenuItem);
557 break;
558 }
559 RtlCopyUnicodeString(&NewMenuItem->lpstr, &MenuItem->lpstr);
560 NewMenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0;
561 NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
562 }
563 else
564 {
565 NewMenuItem->lpstr.Buffer = MenuItem->lpstr.Buffer;
566 NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
567 }
568 NewMenuItem->hbmp = MenuItem->hbmp;
569 }
570 return TRUE;
571 }
572
573 PMENU FASTCALL
574 IntCloneMenu(PMENU Source)
575 {
576 HANDLE hMenu;
577 PMENU Menu;
578
579 if(!Source)
580 return NULL;
581
582 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
583 Menu = (PMENU)UserCreateObject( gHandleTable,
584 Source->head.rpdesk,
585 ((PPROCESSINFO)Source->head.hTaskWow)->ptiList,
586 &hMenu,
587 TYPE_MENU,
588 sizeof(MENU));
589 if(!Menu)
590 return NULL;
591
592 Menu->fFlags = Source->fFlags;
593 Menu->cyMax = Source->cyMax;
594 Menu->hbrBack = Source->hbrBack;
595 Menu->dwContextHelpId = Source->dwContextHelpId;
596 Menu->dwMenuData = Source->dwMenuData;
597 Menu->iItem = NO_SELECTED_ITEM;
598 Menu->spwndNotify = NULL;
599 Menu->cyMenu = 0;
600 Menu->cxMenu = 0;
601 Menu->cItems = Source->cItems;
602 Menu->iTop = 0;
603 Menu->iMaxTop = 0;
604 Menu->cxTextAlign = 0;
605 Menu->rgItems = NULL;
606
607 Menu->hWnd = NULL;
608 Menu->TimeToHide = FALSE;
609
610 IntCloneMenuItems(Menu, Source);
611
612 return Menu;
613 }
614
615 BOOL FASTCALL
616 IntSetMenuFlagRtoL(PMENU Menu)
617 {
618 Menu->fFlags |= MNF_RTOL;
619 return TRUE;
620 }
621
622 BOOL FASTCALL
623 IntSetMenuContextHelpId(PMENU Menu, DWORD dwContextHelpId)
624 {
625 Menu->dwContextHelpId = dwContextHelpId;
626 return TRUE;
627 }
628
629 BOOL FASTCALL
630 IntGetMenuInfo(PMENU Menu, PROSMENUINFO lpmi)
631 {
632 if(lpmi->fMask & MIM_BACKGROUND)
633 lpmi->hbrBack = Menu->hbrBack;
634 if(lpmi->fMask & MIM_HELPID)
635 lpmi->dwContextHelpID = Menu->dwContextHelpId;
636 if(lpmi->fMask & MIM_MAXHEIGHT)
637 lpmi->cyMax = Menu->cyMax;
638 if(lpmi->fMask & MIM_MENUDATA)
639 lpmi->dwMenuData = Menu->dwMenuData;
640 if(lpmi->fMask & MIM_STYLE)
641 lpmi->dwStyle = Menu->fFlags & MNS_STYLE_MASK;
642
643 if (sizeof(MENUINFO) < lpmi->cbSize)
644 {
645 lpmi->cItems = Menu->cItems;
646
647 lpmi->iItem = Menu->iItem;
648 lpmi->cxMenu = Menu->cxMenu;
649 lpmi->cyMenu = Menu->cyMenu;
650 lpmi->spwndNotify = Menu->spwndNotify;
651 lpmi->cxTextAlign = Menu->cxTextAlign;
652 lpmi->iTop = Menu->iTop;
653 lpmi->iMaxTop = Menu->iMaxTop;
654 lpmi->dwArrowsOn = Menu->dwArrowsOn;
655
656 lpmi->fFlags = Menu->fFlags;
657 lpmi->Self = Menu->head.h;
658 lpmi->TimeToHide = Menu->TimeToHide;
659 lpmi->Wnd = Menu->hWnd;
660 }
661 return TRUE;
662 }
663
664 BOOL FASTCALL
665 IntSetMenuInfo(PMENU Menu, PROSMENUINFO lpmi)
666 {
667 if(lpmi->fMask & MIM_BACKGROUND)
668 Menu->hbrBack = lpmi->hbrBack;
669 if(lpmi->fMask & MIM_HELPID)
670 Menu->dwContextHelpId = lpmi->dwContextHelpID;
671 if(lpmi->fMask & MIM_MAXHEIGHT)
672 Menu->cyMax = lpmi->cyMax;
673 if(lpmi->fMask & MIM_MENUDATA)
674 Menu->dwMenuData = lpmi->dwMenuData;
675 if(lpmi->fMask & MIM_STYLE)
676 Menu->fFlags ^= (Menu->fFlags ^ lpmi->dwStyle) & MNS_STYLE_MASK;
677 if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
678 {
679 int i;
680 PITEM item = Menu->rgItems;
681 for ( i = Menu->cItems; i; i--, item++)
682 {
683 if ( item->spSubMenu )
684 {
685 IntSetMenuInfo( item->spSubMenu, lpmi);
686 }
687 }
688 }
689 if (sizeof(MENUINFO) < lpmi->cbSize)
690 {
691 Menu->iItem = lpmi->iItem;
692 Menu->cyMenu = lpmi->cyMenu;
693 Menu->cxMenu = lpmi->cxMenu;
694 Menu->spwndNotify = lpmi->spwndNotify;
695 Menu->cxTextAlign = lpmi->cxTextAlign;
696 Menu->iTop = lpmi->iTop;
697 Menu->iMaxTop = lpmi->iMaxTop;
698 Menu->dwArrowsOn = lpmi->dwArrowsOn;
699
700 Menu->TimeToHide = lpmi->TimeToHide;
701 Menu->hWnd = lpmi->Wnd;
702 }
703 return TRUE;
704 }
705
706 BOOL FASTCALL
707 IntGetMenuItemInfo(PMENU Menu, /* UNUSED PARAM!! */
708 PITEM MenuItem, PROSMENUITEMINFO lpmii)
709 {
710 NTSTATUS Status;
711
712 if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
713 {
714 lpmii->fType = MenuItem->fType;
715 }
716 if(lpmii->fMask & MIIM_BITMAP)
717 {
718 lpmii->hbmpItem = MenuItem->hbmp;
719 }
720 if(lpmii->fMask & MIIM_CHECKMARKS)
721 {
722 lpmii->hbmpChecked = MenuItem->hbmpChecked;
723 lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked;
724 }
725 if(lpmii->fMask & MIIM_DATA)
726 {
727 lpmii->dwItemData = MenuItem->dwItemData;
728 }
729 if(lpmii->fMask & MIIM_ID)
730 {
731 lpmii->wID = MenuItem->wID;
732 }
733 if(lpmii->fMask & MIIM_STATE)
734 {
735 lpmii->fState = MenuItem->fState;
736 }
737 if(lpmii->fMask & MIIM_SUBMENU)
738 {
739 lpmii->hSubMenu = MenuItem->spSubMenu ? MenuItem->spSubMenu->head.h : NULL;
740 }
741
742 if ((lpmii->fMask & MIIM_STRING) ||
743 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
744 {
745 if (lpmii->dwTypeData == NULL)
746 {
747 lpmii->cch = MenuItem->lpstr.Length / sizeof(WCHAR);
748 }
749 else
750 { //// lpmii->lpstr can be read in user mode!!!!
751 Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->lpstr.Buffer,
752 min(lpmii->cch * sizeof(WCHAR),
753 MenuItem->lpstr.MaximumLength));
754 if (! NT_SUCCESS(Status))
755 {
756 SetLastNtError(Status);
757 return FALSE;
758 }
759 }
760 }
761
762 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
763 {
764 lpmii->Rect.left = MenuItem->xItem;
765 lpmii->Rect.top = MenuItem->yItem;
766 lpmii->Rect.right = MenuItem->cxItem; // Do this for now......
767 lpmii->Rect.bottom = MenuItem->cyItem;
768 lpmii->dxTab = MenuItem->dxTab;
769 lpmii->lpstr = MenuItem->lpstr.Buffer;
770 lpmii->maxBmpSize.cx = MenuItem->cxBmp;
771 lpmii->maxBmpSize.cy = MenuItem->cyBmp;
772 }
773
774 return TRUE;
775 }
776
777 BOOL FASTCALL
778 IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUNICODE_STRING lpstr)
779 {
780 PMENU SubMenuObject;
781 BOOL circref = FALSE;
782
783 if(!MenuItem || !MenuObject || !lpmii)
784 {
785 return FALSE;
786 }
787 if ( lpmii->fMask & MIIM_FTYPE )
788 {
789 MenuItem->fType &= ~MENUITEMINFO_TYPE_MASK;
790 MenuItem->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK;
791 }
792 if (lpmii->fMask & MIIM_TYPE)
793 {
794 #if 0 //// Done in User32.
795 if (lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
796 {
797 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
798 KeRosDumpStackFrames(NULL, 20);
799 /* This does not happen on Win9x/ME */
800 SetLastNtError( ERROR_INVALID_PARAMETER);
801 return FALSE;
802 }
803 #endif
804 /*
805 * Delete the menu item type when changing type from
806 * MF_STRING.
807 */
808 if (MenuItem->fType != lpmii->fType &&
809 MENU_ITEM_TYPE(MenuItem->fType) == MFT_STRING)
810 {
811 FreeMenuText(MenuObject,MenuItem);
812 RtlInitUnicodeString(&MenuItem->lpstr, NULL);
813 MenuItem->Xlpstr = NULL;
814 }
815 if(lpmii->fType & MFT_BITMAP)
816 {
817 if(lpmii->hbmpItem)
818 MenuItem->hbmp = lpmii->hbmpItem;
819 else
820 { /* Win 9x/Me stuff */
821 MenuItem->hbmp = (HBITMAP)((ULONG_PTR)(LOWORD(lpmii->dwTypeData)));
822 }
823 lpmii->dwTypeData = 0;
824 }
825 }
826 if(lpmii->fMask & MIIM_BITMAP)
827 {
828 MenuItem->hbmp = lpmii->hbmpItem;
829 if (MenuItem->hbmp <= HBMMENU_POPUP_MINIMIZE && MenuItem->hbmp >= HBMMENU_CALLBACK)
830 MenuItem->fState |= MFS_HBMMENUBMP;
831 else
832 MenuItem->fState &= ~MFS_HBMMENUBMP;
833 }
834 if(lpmii->fMask & MIIM_CHECKMARKS)
835 {
836 MenuItem->hbmpChecked = lpmii->hbmpChecked;
837 MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked;
838 }
839 if(lpmii->fMask & MIIM_DATA)
840 {
841 MenuItem->dwItemData = lpmii->dwItemData;
842 }
843 if(lpmii->fMask & MIIM_ID)
844 {
845 MenuItem->wID = lpmii->wID;
846 }
847 if(lpmii->fMask & MIIM_STATE)
848 {
849 /* Remove MFS_DEFAULT flag from all other menu items if this item
850 has the MFS_DEFAULT state */
851 if(lpmii->fState & MFS_DEFAULT)
852 UserSetMenuDefaultItem(MenuObject, -1, 0);
853 /* Update the menu item state flags */
854 UpdateMenuItemState(MenuItem->fState, lpmii->fState);
855 }
856
857 if(lpmii->fMask & MIIM_SUBMENU)
858 {
859 if (lpmii->hSubMenu)
860 {
861 SubMenuObject = UserGetMenuObject(lpmii->hSubMenu);
862 if ( SubMenuObject && !(UserObjectInDestroy(lpmii->hSubMenu)) )
863 {
864 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
865 //// CORE-7967.
866 if (MenuObject == SubMenuObject)
867 {
868 HANDLE hMenu;
869 ERR("Pop Up Menu Double Trouble!\n");
870 SubMenuObject = IntCreateMenu(&hMenu,
871 FALSE,
872 MenuObject->head.rpdesk,
873 (PPROCESSINFO)MenuObject->head.hTaskWow); // It will be marked.
874 if (!SubMenuObject) return FALSE;
875 IntReleaseMenuObject(SubMenuObject); // This will be referenced again after insertion.
876 circref = TRUE;
877 }
878 if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH )
879 {
880 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
881 if (circref) IntDestroyMenuObject(SubMenuObject, FALSE);
882 return FALSE;
883 }
884 /* Make sure the submenu is marked as a popup menu */
885 SubMenuObject->fFlags |= MNF_POPUP;
886 // Now fix the test_subpopup_locked_by_menu tests....
887 if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu);
888 MenuItem->spSubMenu = SubMenuObject;
889 UserReferenceObject(SubMenuObject);
890 }
891 else
892 {
893 EngSetLastError( ERROR_INVALID_PARAMETER);
894 return FALSE;
895 }
896 }
897 else
898 { // If submenu just dereference it.
899 if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu);
900 MenuItem->spSubMenu = NULL;
901 }
902 }
903
904 if ((lpmii->fMask & MIIM_STRING) ||
905 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
906 {
907 /* free the string when used */
908 FreeMenuText(MenuObject,MenuItem);
909 RtlInitUnicodeString(&MenuItem->lpstr, NULL);
910 MenuItem->Xlpstr = NULL;
911
912 if(lpmii->dwTypeData && lpmii->cch && lpstr && lpstr->Buffer)
913 {
914 UNICODE_STRING Source;
915
916 Source.Length = Source.MaximumLength = lpmii->cch * sizeof(WCHAR);
917 Source.Buffer = lpmii->dwTypeData;
918
919 MenuItem->lpstr.Buffer = DesktopHeapAlloc( MenuObject->head.rpdesk, Source.Length + sizeof(WCHAR));
920 if(MenuItem->lpstr.Buffer != NULL)
921 {
922 MenuItem->lpstr.Length = 0;
923 MenuItem->lpstr.MaximumLength = Source.Length + sizeof(WCHAR);
924 RtlCopyUnicodeString(&MenuItem->lpstr, &Source);
925 MenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0;
926
927 MenuItem->cch = MenuItem->lpstr.Length / sizeof(WCHAR);
928 MenuItem->Xlpstr = (USHORT*)MenuItem->lpstr.Buffer;
929 }
930 }
931 }
932
933 if( !(MenuObject->fFlags & MNF_SYSMENU) &&
934 !MenuItem->Xlpstr &&
935 !lpmii->dwTypeData &&
936 !(MenuItem->fType & MFT_OWNERDRAW) &&
937 !MenuItem->hbmp)
938 MenuItem->fType |= MFT_SEPARATOR;
939
940 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
941 {
942 MenuItem->xItem = lpmii->Rect.left;
943 MenuItem->yItem = lpmii->Rect.top;
944 MenuItem->cxItem = lpmii->Rect.right; // Do this for now......
945 MenuItem->cyItem = lpmii->Rect.bottom;
946 MenuItem->dxTab = lpmii->dxTab;
947 lpmii->lpstr = MenuItem->lpstr.Buffer; /* Send back new allocated string or zero */
948 MenuItem->cxBmp = lpmii->maxBmpSize.cx;
949 MenuItem->cyBmp = lpmii->maxBmpSize.cy;
950 }
951
952 return TRUE;
953 }
954
955
956 UINT FASTCALL
957 IntEnableMenuItem(PMENU MenuObject, UINT uIDEnableItem, UINT uEnable)
958 {
959 PITEM MenuItem;
960 UINT res;
961
962 if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDEnableItem, uEnable ))) return (UINT)-1;
963
964 res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
965
966 MenuItem->fState ^= (res ^ uEnable) & (MF_GRAYED | MF_DISABLED);
967
968 /* If the close item in the system menu change update the close button */
969 if((MenuItem->wID == SC_CLOSE) && (res != uEnable))
970 {
971 if (MenuObject->fFlags & MNF_SYSSUBMENU && MenuObject->spwndNotify != 0)
972 {
973 RECTL rc = MenuObject->spwndNotify->rcWindow;
974
975 /* Refresh the frame to reflect the change */
976 IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
977 rc.bottom = 0;
978 co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
979 }
980 }
981 return res;
982 }
983
984 DWORD FASTCALL
985 IntCheckMenuItem(PMENU MenuObject, UINT uIDCheckItem, UINT uCheck)
986 {
987 PITEM MenuItem;
988 DWORD res;
989
990 if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDCheckItem, uCheck ))) return -1;
991
992 res = (DWORD)(MenuItem->fState & MF_CHECKED);
993
994 MenuItem->fState ^= (res ^ uCheck) & MF_CHECKED;
995
996 return res;
997 }
998
999 BOOL FASTCALL
1000 IntHiliteMenuItem(PWND WindowObject,
1001 PMENU MenuObject,
1002 UINT uItemHilite,
1003 UINT uHilite)
1004 {
1005 PITEM MenuItem;
1006
1007 if (!(MenuItem = MENU_FindItem( &MenuObject, &uItemHilite, uHilite ))) return FALSE;
1008
1009 if (uHilite & MF_HILITE)
1010 {
1011 MenuItem->fState |= MF_HILITE;
1012 }
1013 else
1014 {
1015 MenuItem->fState &= ~MF_HILITE;
1016 }
1017 /* FIXME: Update the window's menu */
1018
1019 return TRUE; // Always returns true!!!!
1020 }
1021
1022 BOOL FASTCALL
1023 UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos)
1024 {
1025 UINT i;
1026 PITEM MenuItem = MenuObject->rgItems;
1027
1028 if (!MenuItem) return FALSE;
1029
1030 /* reset all default-item flags */
1031 for (i = 0; MenuItem, i < MenuObject->cItems; i++, MenuItem++)
1032 {
1033 MenuItem->fState &= ~MFS_DEFAULT;
1034 }
1035
1036 /* no default item */
1037 if(uItem == (UINT)-1)
1038 {
1039 return TRUE;
1040 }
1041 MenuItem = MenuObject->rgItems;
1042 if ( fByPos )
1043 {
1044 if ( uItem >= MenuObject->cItems ) return FALSE;
1045 MenuItem[uItem].fState |= MFS_DEFAULT;
1046 return TRUE;
1047 }
1048 else
1049 {
1050 for (i = 0; MenuItem, i < MenuObject->cItems; i++, MenuItem++)
1051 {
1052 if (MenuItem->wID == uItem)
1053 {
1054 MenuItem->fState |= MFS_DEFAULT;
1055 return TRUE;
1056 }
1057 }
1058
1059 }
1060 return FALSE;
1061 }
1062
1063
1064 UINT FASTCALL
1065 IntGetMenuDefaultItem(PMENU MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc)
1066 {
1067 UINT i = 0;
1068 PITEM MenuItem = MenuObject->rgItems;
1069
1070 /* empty menu */
1071 if (!MenuItem) return -1;
1072
1073 while ( !( MenuItem->fState & MFS_DEFAULT ) )
1074 {
1075 i++; MenuItem++;
1076 if (i >= MenuObject->cItems ) return -1;
1077 }
1078
1079 /* default: don't return disabled items */
1080 if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (MenuItem->fState & MFS_DISABLED )) return -1;
1081
1082 /* search rekursiv when needed */
1083 if ( (MenuItem->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->spSubMenu)
1084 {
1085 UINT ret;
1086 (*gismc)++;
1087 ret = IntGetMenuDefaultItem( MenuItem->spSubMenu, fByPos, gmdiFlags, gismc );
1088 (*gismc)--;
1089 if ( -1 != ret ) return ret;
1090
1091 /* when item not found in submenu, return the popup item */
1092 }
1093 return ( fByPos ) ? i : MenuItem->wID;
1094 }
1095
1096 VOID FASTCALL
1097 co_IntInitTracking(PWND Window, PMENU Menu, BOOL Popup,
1098 UINT Flags)
1099 {
1100 /* FIXME: Hide caret */
1101
1102 if(!(Flags & TPM_NONOTIFY))
1103 co_IntSendMessage(Window->head.h, WM_SETCURSOR, (WPARAM)Window->head.h, HTCAPTION);
1104
1105 /* FIXME: Send WM_SETCURSOR message */
1106
1107 if(!(Flags & TPM_NONOTIFY))
1108 co_IntSendMessage(Window->head.h, WM_INITMENU, (WPARAM)Menu->head.h, 0);
1109 }
1110
1111 VOID FASTCALL
1112 co_IntExitTracking(PWND Window, PMENU Menu, BOOL Popup,
1113 UINT Flags)
1114 {
1115 if(!(Flags & TPM_NONOTIFY))
1116 co_IntSendMessage(Window->head.h, WM_EXITMENULOOP, 0 /* FIXME */, 0);
1117
1118 /* FIXME: Show caret again */
1119 }
1120
1121 INT FASTCALL
1122 IntTrackMenu(PMENU Menu, PWND Window, INT x, INT y,
1123 RECTL lprect)
1124 {
1125 return 0;
1126 }
1127
1128 BOOL FASTCALL
1129 co_IntTrackPopupMenu(PMENU Menu, PWND Window,
1130 UINT Flags, POINT *Pos, UINT MenuPos, RECTL *ExcludeRect)
1131 {
1132 co_IntInitTracking(Window, Menu, TRUE, Flags);
1133
1134 co_IntExitTracking(Window, Menu, TRUE, Flags);
1135 return FALSE;
1136 }
1137
1138 BOOLEAN APIENTRY
1139 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
1140 {
1141
1142 DWORD dwStyle = 0;
1143 DWORD dwExStyle = 0;
1144 BOOLEAN retValue = TRUE;
1145
1146 if (bti->cbSize == sizeof(TITLEBARINFO))
1147 {
1148 RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1));
1149
1150 bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1151
1152 dwStyle = pWindowObject->style;
1153 dwExStyle = pWindowObject->ExStyle;
1154
1155 bti->rcTitleBar.top = 0;
1156 bti->rcTitleBar.left = 0;
1157 bti->rcTitleBar.right = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left;
1158 bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top;
1159
1160 /* Is it iconiced ? */
1161 if ((dwStyle & WS_ICONIC)!=WS_ICONIC)
1162 {
1163 /* Remove frame from rectangle */
1164 if (HAS_THICKFRAME( dwStyle, dwExStyle ))
1165 {
1166 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
1167 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1168 }
1169 else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
1170 {
1171 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
1172 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1173 }
1174 else if (HAS_THINFRAME( dwStyle, dwExStyle))
1175 {
1176 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1177 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) );
1178 }
1179
1180 /* We have additional border information if the window
1181 * is a child (but not an MDI child) */
1182 if ( (dwStyle & WS_CHILD) &&
1183 ((dwExStyle & WS_EX_MDICHILD) == 0 ) )
1184 {
1185 if (dwExStyle & WS_EX_CLIENTEDGE)
1186 {
1187 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
1188 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
1189 }
1190
1191 if (dwExStyle & WS_EX_STATICEDGE)
1192 {
1193 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1194 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1195 }
1196 }
1197 }
1198
1199 bti->rcTitleBar.top += pWindowObject->rcWindow.top;
1200 bti->rcTitleBar.left += pWindowObject->rcWindow.left;
1201 bti->rcTitleBar.right += pWindowObject->rcWindow.left;
1202
1203 bti->rcTitleBar.bottom = bti->rcTitleBar.top;
1204 if (dwExStyle & WS_EX_TOOLWINDOW)
1205 {
1206 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
1207 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION);
1208 }
1209 else
1210 {
1211 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
1212 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION);
1213 bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE);
1214 }
1215
1216 if (dwStyle & WS_CAPTION)
1217 {
1218 bti->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1219 if (dwStyle & WS_SYSMENU)
1220 {
1221 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
1222 {
1223 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1224 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1225 }
1226 else
1227 {
1228 if (!(dwStyle & WS_MINIMIZEBOX))
1229 {
1230 bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1231 }
1232 if (!(dwStyle & WS_MAXIMIZEBOX))
1233 {
1234 bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1235 }
1236 }
1237
1238 if (!(dwExStyle & WS_EX_CONTEXTHELP))
1239 {
1240 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1241 }
1242 if (pWindowObject->pcls->style & CS_NOCLOSE)
1243 {
1244 bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1245 }
1246 }
1247 else
1248 {
1249 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1250 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1251 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1252 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1253 }
1254 }
1255 else
1256 {
1257 bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1258 }
1259 }
1260 else
1261 {
1262 EngSetLastError(ERROR_INVALID_PARAMETER);
1263 retValue = FALSE;
1264 }
1265
1266 return retValue;
1267 }
1268
1269 DWORD FASTCALL
1270 UserInsertMenuItem(
1271 PMENU Menu,
1272 UINT uItem,
1273 BOOL fByPosition,
1274 LPCMENUITEMINFOW UnsafeItemInfo,
1275 PUNICODE_STRING lpstr)
1276 {
1277 NTSTATUS Status;
1278 ROSMENUITEMINFO ItemInfo;
1279
1280 /* Try to copy the whole MENUITEMINFOW structure */
1281 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
1282 if (NT_SUCCESS(Status))
1283 {
1284 if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
1285 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1286 {
1287 EngSetLastError(ERROR_INVALID_PARAMETER);
1288 return FALSE;
1289 }
1290 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
1291 }
1292
1293 /* Try to copy without last field (not present in older versions) */
1294 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
1295 if (NT_SUCCESS(Status))
1296 {
1297 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1298 {
1299 EngSetLastError(ERROR_INVALID_PARAMETER);
1300 return FALSE;
1301 }
1302 ItemInfo.hbmpItem = (HBITMAP)0;
1303 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
1304 }
1305
1306 SetLastNtError(Status);
1307 return FALSE;
1308 }
1309
1310 UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags)
1311 {
1312 PMENU MenuObject;
1313 PITEM pItem;
1314
1315 if (!(MenuObject = UserGetMenuObject(hMenu)))
1316 {
1317 return (UINT)-1;
1318 }
1319
1320 if (!(pItem = MENU_FindItem( &MenuObject, &uId, uFlags ))) return -1;
1321
1322 if (pItem->spSubMenu)
1323 {
1324 return (pItem->spSubMenu->cItems << 8) | ((pItem->fState|pItem->fType) & 0xff);
1325 }
1326 else
1327 return (pItem->fType | pItem->fState);
1328 }
1329
1330 HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos)
1331 {
1332 PMENU MenuObject;
1333 PITEM pItem;
1334
1335 if (!(MenuObject = UserGetMenuObject(hMenu)))
1336 {
1337 return NULL;
1338 }
1339
1340 if (!(pItem = MENU_FindItem( &MenuObject, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
1341
1342 if (pItem->spSubMenu)
1343 {
1344 HMENU hsubmenu = UserHMGetHandle(pItem->spSubMenu);
1345 return hsubmenu;
1346 }
1347 return NULL;
1348 }
1349
1350 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
1351 {
1352 PMENU menu;
1353 HMENU hSubMenu;
1354 UINT i;
1355 PITEM item;
1356
1357 if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
1358 return NO_SELECTED_ITEM;
1359
1360 item = menu->rgItems;
1361 for (i = 0; i < menu->cItems; i++, item++)
1362 {
1363 if (!item->spSubMenu)
1364 continue;
1365 else
1366 {
1367 hSubMenu = UserHMGetHandle(item->spSubMenu);
1368 if (hSubMenu == hSubTarget)
1369 {
1370 return i;
1371 }
1372 else
1373 {
1374 HMENU hsubmenu = hSubMenu;
1375 UINT pos = IntFindSubMenu( &hsubmenu, hSubTarget );
1376 if (pos != NO_SELECTED_ITEM)
1377 {
1378 *hMenu = hsubmenu;
1379 return pos;
1380 }
1381 }
1382 }
1383 }
1384 return NO_SELECTED_ITEM;
1385 }
1386
1387
1388 HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu)
1389 {
1390 PWINSTATION_OBJECT WinStaObject;
1391 HANDLE Handle;
1392 PMENU Menu;
1393 NTSTATUS Status;
1394 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1395
1396 if (gpepCSRSS != CurrentProcess)
1397 {
1398 /*
1399 * gpepCSRSS does not have a Win32WindowStation
1400 */
1401
1402 Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
1403 KernelMode,
1404 0,
1405 &WinStaObject);
1406
1407 if (!NT_SUCCESS(Status))
1408 {
1409 ERR("Validation of window station handle (%p) failed\n",
1410 CurrentProcess->Win32WindowStation);
1411 SetLastNtError(Status);
1412 return (HMENU)0;
1413 }
1414 Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo());
1415 if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
1416 {
1417 ERR("Desktop Window Station does not match Process one!\n");
1418 }
1419 ObDereferenceObject(WinStaObject);
1420 }
1421 else
1422 {
1423 Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo());
1424 }
1425
1426 if (Menu) UserDereferenceObject(Menu);
1427 return (HMENU)Handle;
1428 }
1429
1430 BOOL FASTCALL
1431 IntMenuItemInfo(
1432 PMENU Menu,
1433 UINT Item,
1434 BOOL ByPosition,
1435 PROSMENUITEMINFO ItemInfo,
1436 BOOL SetOrGet,
1437 PUNICODE_STRING lpstr)
1438 {
1439 PITEM MenuItem;
1440 BOOL Ret;
1441
1442 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
1443 {
1444 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
1445 return( FALSE);
1446 }
1447 if (SetOrGet)
1448 {
1449 Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr);
1450 }
1451 else
1452 {
1453 Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo);
1454 }
1455 return( Ret);
1456 }
1457
1458 BOOL FASTCALL
1459 UserMenuItemInfo(
1460 PMENU Menu,
1461 UINT Item,
1462 BOOL ByPosition,
1463 PROSMENUITEMINFO UnsafeItemInfo,
1464 BOOL SetOrGet,
1465 PUNICODE_STRING lpstr)
1466 {
1467 PITEM MenuItem;
1468 ROSMENUITEMINFO ItemInfo;
1469 NTSTATUS Status;
1470 UINT Size;
1471 BOOL Ret;
1472
1473 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
1474 if (! NT_SUCCESS(Status))
1475 {
1476 SetLastNtError(Status);
1477 return( FALSE);
1478 }
1479 if (sizeof(MENUITEMINFOW) != Size
1480 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
1481 && sizeof(ROSMENUITEMINFO) != Size)
1482 {
1483 EngSetLastError(ERROR_INVALID_PARAMETER);
1484 return( FALSE);
1485 }
1486 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
1487 if (! NT_SUCCESS(Status))
1488 {
1489 SetLastNtError(Status);
1490 return( FALSE);
1491 }
1492 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
1493 set/get hbmpItem */
1494 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
1495 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
1496 {
1497 EngSetLastError(ERROR_INVALID_PARAMETER);
1498 return( FALSE);
1499 }
1500
1501 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
1502 {
1503 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
1504 return( FALSE);
1505 }
1506
1507 if (SetOrGet)
1508 {
1509 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo, lpstr);
1510 }
1511 else
1512 {
1513 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
1514 if (Ret)
1515 {
1516 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
1517 if (! NT_SUCCESS(Status))
1518 {
1519 SetLastNtError(Status);
1520 return( FALSE);
1521 }
1522 }
1523 }
1524
1525 return( Ret);
1526 }
1527
1528 BOOL FASTCALL
1529 UserMenuInfo(
1530 PMENU Menu,
1531 PROSMENUINFO UnsafeMenuInfo,
1532 BOOL SetOrGet)
1533 {
1534 BOOL Res;
1535 DWORD Size;
1536 NTSTATUS Status;
1537 ROSMENUINFO MenuInfo;
1538
1539 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
1540 if (! NT_SUCCESS(Status))
1541 {
1542 SetLastNtError(Status);
1543 return( FALSE);
1544 }
1545 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
1546 {
1547 EngSetLastError(ERROR_INVALID_PARAMETER);
1548 return( FALSE);
1549 }
1550 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
1551 if (! NT_SUCCESS(Status))
1552 {
1553 SetLastNtError(Status);
1554 return( FALSE);
1555 }
1556
1557 if(SetOrGet)
1558 {
1559 /* Set MenuInfo */
1560 Res = IntSetMenuInfo(Menu, &MenuInfo);
1561 }
1562 else
1563 {
1564 /* Get MenuInfo */
1565 Res = IntGetMenuInfo(Menu, &MenuInfo);
1566 if (Res)
1567 {
1568 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
1569 if (! NT_SUCCESS(Status))
1570 {
1571 SetLastNtError(Status);
1572 return( FALSE);
1573 }
1574 }
1575 }
1576
1577 return( Res);
1578 }
1579
1580 VOID FASTCALL
1581 MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
1582 {
1583 if (menu->dwArrowsOn)
1584 {
1585 UINT arrow_bitmap_height;
1586 //BITMAP bmp;
1587 //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
1588 arrow_bitmap_height = gpsi->oembmi[65].cy; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
1589 //arrow_bitmap_height = bmp.bmHeight;
1590 rect->top += arrow_bitmap_height - menu->iTop;
1591 rect->bottom += arrow_bitmap_height - menu->iTop;
1592 }
1593 }
1594
1595 BOOL FASTCALL
1596 IntGetMenuItemRect(
1597 PWND pWnd,
1598 PMENU Menu,
1599 UINT uItem,
1600 PRECTL Rect)
1601 {
1602 LONG XMove, YMove;
1603 PITEM MenuItem;
1604
1605 if (!pWnd)
1606 {
1607 HWND hWnd = Menu->hWnd;
1608 if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
1609 }
1610
1611 if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
1612 {
1613 Rect->left = MenuItem->xItem;
1614 Rect->top = MenuItem->yItem;
1615 Rect->right = MenuItem->cxItem; // Do this for now......
1616 Rect->bottom = MenuItem->cyItem;
1617 }
1618 else
1619 {
1620 ERR("Failed Item Lookup! %d\n", uItem);
1621 return FALSE;
1622 }
1623
1624 if (Menu->fFlags & MNF_POPUP)
1625 {
1626 XMove = pWnd->rcClient.left;
1627 YMove = pWnd->rcClient.top;
1628 }
1629 else
1630 {
1631 XMove = pWnd->rcWindow.left;
1632 YMove = pWnd->rcWindow.top;
1633 }
1634
1635 Rect->left += XMove;
1636 Rect->top += YMove;
1637 Rect->right += XMove;
1638 Rect->bottom += YMove;
1639
1640 return TRUE;
1641 }
1642
1643 PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
1644 {
1645 PMENU Menu, NewMenu = NULL, SysMenu = NULL;
1646 HMENU hSysMenu, hNewMenu = NULL;
1647 ROSMENUITEMINFO ItemInfoSet = {0};
1648 ROSMENUITEMINFO ItemInfo = {0};
1649 UNICODE_STRING MenuName;
1650
1651 hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE);
1652 if (NULL == hSysMenu)
1653 {
1654 return NULL;
1655 }
1656 SysMenu = UserGetMenuObject(hSysMenu);
1657 if (NULL == SysMenu)
1658 {
1659 UserDestroyMenu(hSysMenu);
1660 return NULL;
1661 }
1662
1663 SysMenu->fFlags |= MNF_SYSMENU;
1664 SysMenu->hWnd = Window->head.h;
1665
1666 if (!Popup)
1667 {
1668 //hNewMenu = co_IntLoadSysMenuTemplate();
1669 if ( Window->ExStyle & WS_EX_MDICHILD )
1670 {
1671 RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
1672 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
1673 }
1674 else
1675 {
1676 RtlInitUnicodeString( &MenuName, L"SYSMENU");
1677 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
1678 //ERR("%wZ\n",&MenuName);
1679 }
1680 if (!hNewMenu)
1681 {
1682 ERR("No Menu!!\n");
1683 IntReleaseMenuObject(SysMenu);
1684 UserDestroyMenu(hSysMenu);
1685 return NULL;
1686 }
1687 Menu = UserGetMenuObject(hNewMenu);
1688 if (!Menu)
1689 {
1690 IntReleaseMenuObject(SysMenu);
1691 UserDestroyMenu(hSysMenu);
1692 return NULL;
1693 }
1694
1695 // Do the rest in here.
1696
1697 Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU | MNF_POPUP;
1698
1699 ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
1700 ItemInfoSet.fMask = MIIM_BITMAP;
1701 ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
1702 IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
1703 ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
1704 IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
1705 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
1706 IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
1707 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
1708 IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
1709
1710 NewMenu = IntCloneMenu(Menu);
1711
1712 IntReleaseMenuObject(NewMenu);
1713 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
1714
1715 IntDestroyMenuObject(Menu, FALSE);
1716 }
1717 else
1718 {
1719 NewMenu = Popup;
1720 }
1721 if (NewMenu)
1722 {
1723 NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP;
1724
1725 if (Window->pcls->style & CS_NOCLOSE)
1726 IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
1727
1728 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
1729 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
1730 ItemInfo.fType = 0;
1731 ItemInfo.fState = MFS_ENABLED;
1732 ItemInfo.dwTypeData = NULL;
1733 ItemInfo.cch = 0;
1734 ItemInfo.hSubMenu = UserHMGetHandle(NewMenu);
1735 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
1736
1737 return SysMenu;
1738 }
1739 ERR("failed to load system menu!\n");
1740 return NULL;
1741 }
1742
1743 PMENU FASTCALL
1744 IntGetSystemMenu(PWND Window, BOOL bRevert)
1745 {
1746 PMENU Menu;
1747
1748 if (bRevert)
1749 {
1750 if (Window->SystemMenu)
1751 {
1752 Menu = UserGetMenuObject(Window->SystemMenu);
1753 if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
1754 {
1755 IntDestroyMenuObject(Menu, TRUE);
1756 Window->SystemMenu = NULL;
1757 }
1758 }
1759 }
1760 else
1761 {
1762 Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
1763 if ((!Window->SystemMenu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
1764 {
1765 Menu = MENU_GetSystemMenu(Window, NULL);
1766 Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
1767 }
1768 }
1769
1770 if (Window->SystemMenu)
1771 {
1772 HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0);
1773 /* Store the dummy sysmenu handle to facilitate the refresh */
1774 /* of the close button if the SC_CLOSE item change */
1775 Menu = UserGetMenuObject(hMenu);
1776 if (Menu)
1777 {
1778 Menu->spwndNotify = Window;
1779 Menu->fFlags |= MNF_SYSSUBMENU;
1780 }
1781 return Menu;
1782 }
1783 return NULL;
1784 }
1785
1786 BOOL FASTCALL
1787 IntSetSystemMenu(PWND Window, PMENU Menu)
1788 {
1789 PMENU OldMenu;
1790
1791 if (!(Window->style & WS_SYSMENU)) return FALSE;
1792
1793 if (Window->SystemMenu)
1794 {
1795 OldMenu = UserGetMenuObject(Window->SystemMenu);
1796 if (OldMenu)
1797 {
1798 OldMenu->fFlags &= ~MNF_SYSMENU;
1799 IntDestroyMenuObject(OldMenu, TRUE);
1800 }
1801 }
1802
1803 OldMenu = MENU_GetSystemMenu(Window, Menu);
1804 if (OldMenu)
1805 { // Use spmenuSys too!
1806 Window->SystemMenu = UserHMGetHandle(OldMenu);
1807 }
1808 else
1809 Window->SystemMenu = NULL;
1810
1811 if (Menu && Window != Menu->spwndNotify)
1812 {
1813 Menu->spwndNotify = Window;
1814 }
1815
1816 return TRUE;
1817 }
1818
1819
1820 /* FUNCTIONS *****************************************************************/
1821
1822 /*
1823 * @implemented
1824 */
1825 DWORD APIENTRY
1826 NtUserCheckMenuItem(
1827 HMENU hMenu,
1828 UINT uIDCheckItem,
1829 UINT uCheck)
1830 {
1831 PMENU Menu;
1832 DECLARE_RETURN(DWORD);
1833
1834 TRACE("Enter NtUserCheckMenuItem\n");
1835 UserEnterExclusive();
1836
1837 if(!(Menu = UserGetMenuObject(hMenu)))
1838 {
1839 RETURN( (DWORD)-1);
1840 }
1841
1842 RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
1843
1844 CLEANUP:
1845 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_);
1846 UserLeave();
1847 END_CLEANUP;
1848 }
1849
1850 /*
1851 * @implemented
1852 */
1853 BOOL APIENTRY
1854 NtUserDeleteMenu(
1855 HMENU hMenu,
1856 UINT uPosition,
1857 UINT uFlags)
1858 {
1859 PMENU Menu;
1860 DECLARE_RETURN(BOOL);
1861
1862 TRACE("Enter NtUserDeleteMenu\n");
1863 UserEnterExclusive();
1864
1865 if(!(Menu = UserGetMenuObject(hMenu)))
1866 {
1867 RETURN( FALSE);
1868 }
1869
1870 RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
1871
1872 CLEANUP:
1873 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
1874 UserLeave();
1875 END_CLEANUP;
1876 }
1877
1878 /*
1879 * NtUserGetSystemMenu
1880 *
1881 * The NtUserGetSystemMenu function allows the application to access the
1882 * window menu (also known as the system menu or the control menu) for
1883 * copying and modifying.
1884 *
1885 * Parameters
1886 * hWnd
1887 * Handle to the window that will own a copy of the window menu.
1888 * bRevert
1889 * Specifies the action to be taken. If this parameter is FALSE,
1890 * NtUserGetSystemMenu returns a handle to the copy of the window menu
1891 * currently in use. The copy is initially identical to the window menu
1892 * but it can be modified.
1893 * If this parameter is TRUE, GetSystemMenu resets the window menu back
1894 * to the default state. The previous window menu, if any, is destroyed.
1895 *
1896 * Return Value
1897 * If the bRevert parameter is FALSE, the return value is a handle to a
1898 * copy of the window menu. If the bRevert parameter is TRUE, the return
1899 * value is NULL.
1900 *
1901 * Status
1902 * @implemented
1903 */
1904
1905 HMENU APIENTRY
1906 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
1907 {
1908 PWND Window;
1909 PMENU Menu;
1910 DECLARE_RETURN(HMENU);
1911
1912 TRACE("Enter NtUserGetSystemMenu\n");
1913 UserEnterShared();
1914
1915 if (!(Window = UserGetWindowObject(hWnd)))
1916 {
1917 RETURN(NULL);
1918 }
1919
1920 if (!(Menu = IntGetSystemMenu(Window, bRevert)))
1921 {
1922 RETURN(NULL);
1923 }
1924
1925 RETURN(Menu->head.h);
1926
1927 CLEANUP:
1928 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_);
1929 UserLeave();
1930 END_CLEANUP;
1931 }
1932
1933 /*
1934 * NtUserSetSystemMenu
1935 *
1936 * Status
1937 * @implemented
1938 */
1939
1940 BOOL APIENTRY
1941 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
1942 {
1943 BOOL Result = FALSE;
1944 PWND Window;
1945 PMENU Menu;
1946 DECLARE_RETURN(BOOL);
1947
1948 TRACE("Enter NtUserSetSystemMenu\n");
1949 UserEnterExclusive();
1950
1951 if (!(Window = UserGetWindowObject(hWnd)))
1952 {
1953 RETURN( FALSE);
1954 }
1955
1956 if (hMenu)
1957 {
1958 /*
1959 * Assign new menu handle and Up the Lock Count.
1960 */
1961 if (!(Menu = IntGetMenuObject(hMenu)))
1962 {
1963 RETURN( FALSE);
1964 }
1965
1966 Result = IntSetSystemMenu(Window, Menu);
1967 }
1968 else
1969 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
1970
1971 RETURN( Result);
1972
1973 CLEANUP:
1974 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
1975 UserLeave();
1976 END_CLEANUP;
1977 }
1978
1979 /*
1980 * @implemented
1981 */
1982 BOOLEAN APIENTRY
1983 NtUserGetTitleBarInfo(
1984 HWND hwnd,
1985 PTITLEBARINFO bti)
1986 {
1987 PWND WindowObject;
1988 TITLEBARINFO bartitleinfo;
1989 DECLARE_RETURN(BOOLEAN);
1990 BOOLEAN retValue = TRUE;
1991
1992 TRACE("Enter NtUserGetTitleBarInfo\n");
1993 UserEnterExclusive();
1994
1995 /* Vaildate the windows handle */
1996 if (!(WindowObject = UserGetWindowObject(hwnd)))
1997 {
1998 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1999 retValue = FALSE;
2000 }
2001
2002 _SEH2_TRY
2003 {
2004 /* Copy our usermode buffer bti to local buffer bartitleinfo */
2005 ProbeForRead(bti, sizeof(TITLEBARINFO), 1);
2006 RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO));
2007 }
2008 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2009 {
2010 /* Fail copy the data */
2011 EngSetLastError(ERROR_INVALID_PARAMETER);
2012 retValue = FALSE;
2013 }
2014 _SEH2_END
2015
2016 /* Get the tile bar info */
2017 if (retValue)
2018 {
2019 retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo);
2020 if (retValue)
2021 {
2022 _SEH2_TRY
2023 {
2024 /* Copy our buffer to user mode buffer bti */
2025 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1);
2026 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO));
2027 }
2028 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2029 {
2030 /* Fail copy the data */
2031 EngSetLastError(ERROR_INVALID_PARAMETER);
2032 retValue = FALSE;
2033 }
2034 _SEH2_END
2035 }
2036 }
2037
2038 RETURN( retValue );
2039
2040 CLEANUP:
2041 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_);
2042 UserLeave();
2043 END_CLEANUP;
2044 }
2045
2046 /*
2047 * @implemented
2048 */
2049 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
2050 {
2051 PMENU Menu;
2052 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
2053
2054 if(!(Menu = UserGetMenuObject(hMenu)))
2055 {
2056 return FALSE;
2057 }
2058
2059 if (Menu->head.rpdesk != pti->rpdesk)
2060 {
2061 EngSetLastError(ERROR_ACCESS_DENIED);
2062 return FALSE;
2063 }
2064 return IntDestroyMenuObject(Menu, FALSE);
2065 }
2066
2067 /*
2068 * @implemented
2069 */
2070 BOOL APIENTRY
2071 NtUserDestroyMenu(
2072 HMENU hMenu)
2073 {
2074 PMENU Menu;
2075 DECLARE_RETURN(BOOL);
2076
2077 TRACE("Enter NtUserDestroyMenu\n");
2078 UserEnterExclusive();
2079
2080 if(!(Menu = UserGetMenuObject(hMenu)))
2081 {
2082 RETURN( FALSE);
2083 }
2084 if (Menu->head.rpdesk != gptiCurrent->rpdesk)
2085 {
2086 EngSetLastError(ERROR_ACCESS_DENIED);
2087 RETURN( FALSE);
2088 }
2089 RETURN( IntDestroyMenuObject(Menu, TRUE));
2090
2091 CLEANUP:
2092 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
2093 UserLeave();
2094 END_CLEANUP;
2095 }
2096
2097 /*
2098 * @implemented
2099 */
2100 UINT APIENTRY
2101 NtUserEnableMenuItem(
2102 HMENU hMenu,
2103 UINT uIDEnableItem,
2104 UINT uEnable)
2105 {
2106 PMENU Menu;
2107 DECLARE_RETURN(UINT);
2108
2109 TRACE("Enter NtUserEnableMenuItem\n");
2110 UserEnterExclusive();
2111
2112 if(!(Menu = UserGetMenuObject(hMenu)))
2113 {
2114 RETURN(-1);
2115 }
2116
2117 RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
2118
2119 CLEANUP:
2120 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_);
2121 UserLeave();
2122 END_CLEANUP;
2123 }
2124
2125 /*
2126 * @implemented
2127 */
2128 BOOL APIENTRY
2129 NtUserGetMenuBarInfo(
2130 HWND hwnd,
2131 LONG idObject,
2132 LONG idItem,
2133 PMENUBARINFO pmbi)
2134 {
2135 PWND pWnd;
2136 HMENU hMenu;
2137 MENUBARINFO kmbi;
2138 BOOL Ret;
2139 NTSTATUS Status = STATUS_SUCCESS;
2140 PMENU Menu = NULL;
2141 DECLARE_RETURN(BOOL);
2142
2143 TRACE("Enter NtUserGetMenuBarInfo\n");
2144 UserEnterShared();
2145
2146 if (!(pWnd = UserGetWindowObject(hwnd)))
2147 {
2148 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2149 RETURN(FALSE);
2150 }
2151
2152 switch (idObject)
2153 {
2154 case OBJID_CLIENT:
2155 if (!pWnd->pcls->fnid)
2156 RETURN(FALSE);
2157 if (pWnd->pcls->fnid != FNID_MENU)
2158 {
2159 WARN("called on invalid window: %d\n", pWnd->pcls->fnid);
2160 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2161 RETURN(FALSE);
2162 }
2163 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
2164 hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
2165 break;
2166 case OBJID_MENU:
2167 hMenu = UlongToHandle(pWnd->IDMenu);
2168 break;
2169 case OBJID_SYSMENU:
2170 if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE);
2171 Menu = IntGetSystemMenu(pWnd, FALSE);
2172 hMenu = Menu->head.h;
2173 break;
2174 default:
2175 RETURN(FALSE);
2176 }
2177
2178 if (!hMenu)
2179 RETURN(FALSE);
2180
2181 _SEH2_TRY
2182 {
2183 kmbi.cbSize = pmbi->cbSize;
2184 }
2185 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2186 {
2187 kmbi.cbSize = 0;
2188 }
2189 _SEH2_END
2190
2191 if (kmbi.cbSize != sizeof(MENUBARINFO))
2192 {
2193 EngSetLastError(ERROR_INVALID_PARAMETER);
2194 RETURN(FALSE);
2195 }
2196
2197 if (!Menu) Menu = UserGetMenuObject(hMenu);
2198 if (!Menu)
2199 RETURN(FALSE);
2200
2201 if (idItem < 0 || idItem > Menu->cItems)
2202 RETURN(FALSE);
2203
2204 RECTL_vSetEmptyRect(&kmbi.rcBar);
2205
2206 if (idItem == 0)
2207 {
2208 Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar);
2209 kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu;
2210 kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu;
2211 TRACE("idItem 0 %d\n",Ret);
2212 }
2213 else
2214 {
2215 Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar);
2216 TRACE("idItem X %d\n", Ret);
2217 }
2218
2219 kmbi.hMenu = hMenu;
2220 kmbi.hwndMenu = NULL;
2221 kmbi.fBarFocused = FALSE;
2222 kmbi.fFocused = FALSE;
2223 //kmbi.fBarFocused = top_popup_hmenu == hMenu;
2224 if (idItem)
2225 {
2226 kmbi.fFocused = Menu->iItem == idItem-1;
2227 if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu))
2228 {
2229 kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
2230 }
2231 }
2232 /* else
2233 {
2234 kmbi.fFocused = kmbi.fBarFocused;
2235 }
2236 */
2237 _SEH2_TRY
2238 {
2239 RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO));
2240 }
2241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2242 {
2243 Status = _SEH2_GetExceptionCode();
2244 }
2245 _SEH2_END
2246
2247 if (!NT_SUCCESS(Status))
2248 {
2249 SetLastNtError(Status);
2250 RETURN(FALSE);
2251 }
2252
2253 RETURN(TRUE);
2254
2255 CLEANUP:
2256 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
2257 UserLeave();
2258 END_CLEANUP;
2259 }
2260
2261 /*
2262 * @implemented
2263 */
2264 UINT APIENTRY
2265 NtUserGetMenuIndex(
2266 HMENU hMenu,
2267 HMENU hSubMenu)
2268 {
2269 PMENU Menu, SubMenu;
2270 PITEM MenuItem;
2271 UINT i;
2272 DECLARE_RETURN(UINT);
2273
2274 TRACE("Enter NtUserGetMenuIndex\n");
2275 UserEnterShared();
2276
2277 if ( !(Menu = UserGetMenuObject(hMenu)) ||
2278 !(SubMenu = UserGetMenuObject(hSubMenu)) )
2279 RETURN(0xFFFFFFFF);
2280
2281 MenuItem = Menu->rgItems;
2282 for (i = 0; i < Menu->cItems; i++, MenuItem++)
2283 {
2284 if (MenuItem->spSubMenu == SubMenu)
2285 RETURN(MenuItem->wID);
2286 }
2287 RETURN(0xFFFFFFFF);
2288
2289 CLEANUP:
2290 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_);
2291 UserLeave();
2292 END_CLEANUP;
2293 }
2294
2295 /*
2296 * @implemented
2297 */
2298 BOOL APIENTRY
2299 NtUserGetMenuItemRect(
2300 HWND hWnd,
2301 HMENU hMenu,
2302 UINT uItem,
2303 PRECTL lprcItem)
2304 {
2305 PWND ReferenceWnd;
2306 LONG XMove, YMove;
2307 RECTL Rect;
2308 PMENU Menu;
2309 PITEM MenuItem;
2310 NTSTATUS Status = STATUS_SUCCESS;
2311 DECLARE_RETURN(BOOL);
2312
2313 TRACE("Enter NtUserGetMenuItemRect\n");
2314 UserEnterShared();
2315
2316 if (!(Menu = UserGetMenuObject(hMenu)))
2317 {
2318 RETURN(FALSE);
2319 }
2320
2321 if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
2322 {
2323 Rect.left = MenuItem->xItem;
2324 Rect.top = MenuItem->yItem;
2325 Rect.right = MenuItem->cxItem; // Do this for now......
2326 Rect.bottom = MenuItem->cyItem;
2327 }
2328 else
2329 RETURN(FALSE);
2330
2331 if(!hWnd)
2332 {
2333 hWnd = Menu->hWnd;
2334 }
2335
2336 if (lprcItem == NULL) RETURN( FALSE);
2337
2338 if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE);
2339
2340 if (Menu->fFlags & MNF_POPUP)
2341 {
2342 XMove = ReferenceWnd->rcClient.left;
2343 YMove = ReferenceWnd->rcClient.top;
2344 }
2345 else
2346 {
2347 XMove = ReferenceWnd->rcWindow.left;
2348 YMove = ReferenceWnd->rcWindow.top;
2349 }
2350
2351 Rect.left += XMove;
2352 Rect.top += YMove;
2353 Rect.right += XMove;
2354 Rect.bottom += YMove;
2355
2356 _SEH2_TRY
2357 {
2358 RtlCopyMemory(lprcItem, &Rect, sizeof(RECTL));
2359 }
2360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2361 {
2362 Status = _SEH2_GetExceptionCode();
2363 }
2364 _SEH2_END
2365
2366 if (!NT_SUCCESS(Status))
2367 {
2368 SetLastNtError(Status);
2369 RETURN(FALSE);
2370 }
2371 RETURN(TRUE);
2372
2373 CLEANUP:
2374 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
2375 UserLeave();
2376 END_CLEANUP;
2377 }
2378
2379 /*
2380 * @implemented
2381 */
2382 BOOL APIENTRY
2383 NtUserHiliteMenuItem(
2384 HWND hWnd,
2385 HMENU hMenu,
2386 UINT uItemHilite,
2387 UINT uHilite)
2388 {
2389 PMENU Menu;
2390 PWND Window;
2391 DECLARE_RETURN(BOOLEAN);
2392
2393 TRACE("Enter NtUserHiliteMenuItem\n");
2394 UserEnterExclusive();
2395
2396 if(!(Window = UserGetWindowObject(hWnd)))
2397 {
2398 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2399 RETURN(FALSE);
2400 }
2401
2402 if(!(Menu = UserGetMenuObject(hMenu)))
2403 {
2404 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2405 RETURN(FALSE);
2406 }
2407
2408 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
2409
2410 CLEANUP:
2411 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_);
2412 UserLeave();
2413 END_CLEANUP;
2414 }
2415
2416
2417 /*
2418 * @implemented
2419 */
2420 int APIENTRY
2421 NtUserMenuItemFromPoint(
2422 HWND hWnd,
2423 HMENU hMenu,
2424 DWORD X,
2425 DWORD Y)
2426 {
2427 PMENU Menu;
2428 PWND Window = NULL;
2429 PITEM mi;
2430 int i;
2431 DECLARE_RETURN(int);
2432
2433 TRACE("Enter NtUserMenuItemFromPoint\n");
2434 UserEnterExclusive();
2435
2436 if (!(Menu = UserGetMenuObject(hMenu)))
2437 {
2438 RETURN( -1);
2439 }
2440
2441 if (!(Window = UserGetWindowObject(Menu->hWnd)))
2442 {
2443 RETURN( -1);
2444 }
2445
2446 X -= Window->rcWindow.left;
2447 Y -= Window->rcWindow.top;
2448
2449 mi = Menu->rgItems;
2450 for (i = 0; i < Menu->cItems; i++, mi++)
2451 {
2452 RECTL Rect;
2453 Rect.left = mi->xItem;
2454 Rect.top = mi->yItem;
2455 Rect.right = mi->cxItem; // Do this for now......
2456 Rect.bottom = mi->cyItem;
2457 //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
2458 if (RECTL_bPointInRect(&Rect, X, Y))
2459 {
2460 break;
2461 }
2462 }
2463
2464 RETURN( (mi ? i : NO_SELECTED_ITEM));
2465
2466 CLEANUP:
2467 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
2468 UserLeave();
2469 END_CLEANUP;
2470 }
2471
2472
2473 /*
2474 * @implemented
2475 */
2476 BOOL APIENTRY
2477 NtUserRemoveMenu(
2478 HMENU hMenu,
2479 UINT uPosition,
2480 UINT uFlags)
2481 {
2482 PMENU Menu;
2483 DECLARE_RETURN(BOOL);
2484
2485 TRACE("Enter NtUserRemoveMenu\n");
2486 UserEnterExclusive();
2487
2488 if(!(Menu = UserGetMenuObject(hMenu)))
2489 {
2490 RETURN( FALSE);
2491 }
2492
2493 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
2494
2495 CLEANUP:
2496 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
2497 UserLeave();
2498 END_CLEANUP;
2499
2500 }
2501
2502 /*
2503 * @implemented
2504 */
2505 BOOL APIENTRY
2506 NtUserSetMenuContextHelpId(
2507 HMENU hMenu,
2508 DWORD dwContextHelpId)
2509 {
2510 PMENU Menu;
2511 DECLARE_RETURN(BOOL);
2512
2513 TRACE("Enter NtUserSetMenuContextHelpId\n");
2514 UserEnterExclusive();
2515
2516 if(!(Menu = UserGetMenuObject(hMenu)))
2517 {
2518 RETURN( FALSE);
2519 }
2520
2521 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
2522
2523 CLEANUP:
2524 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
2525 UserLeave();
2526 END_CLEANUP;
2527 }
2528
2529 /*
2530 * @implemented
2531 */
2532 BOOL APIENTRY
2533 NtUserSetMenuDefaultItem(
2534 HMENU hMenu,
2535 UINT uItem,
2536 UINT fByPos)
2537 {
2538 PMENU Menu;
2539 DECLARE_RETURN(BOOL);
2540
2541 TRACE("Enter NtUserSetMenuDefaultItem\n");
2542 UserEnterExclusive();
2543
2544 if(!(Menu = UserGetMenuObject(hMenu)))
2545 {
2546 RETURN( FALSE);
2547 }
2548
2549 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
2550
2551 CLEANUP:
2552 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
2553 UserLeave();
2554 END_CLEANUP;
2555 }
2556
2557 /*
2558 * @implemented
2559 */
2560 BOOL APIENTRY
2561 NtUserSetMenuFlagRtoL(
2562 HMENU hMenu)
2563 {
2564 PMENU Menu;
2565 DECLARE_RETURN(BOOL);
2566
2567 TRACE("Enter NtUserSetMenuFlagRtoL\n");
2568 UserEnterExclusive();
2569
2570 if(!(Menu = UserGetMenuObject(hMenu)))
2571 {
2572 RETURN( FALSE);
2573 }
2574
2575 RETURN(IntSetMenuFlagRtoL(Menu));
2576
2577 CLEANUP:
2578 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
2579 UserLeave();
2580 END_CLEANUP;
2581 }
2582
2583 /*
2584 * @implemented
2585 */
2586 BOOL APIENTRY
2587 NtUserThunkedMenuInfo(
2588 HMENU hMenu,
2589 LPCMENUINFO lpcmi)
2590 {
2591 PMENU Menu;
2592 DECLARE_RETURN(BOOL);
2593
2594 TRACE("Enter NtUserThunkedMenuInfo\n");
2595 UserEnterExclusive();
2596
2597 if (!(Menu = UserGetMenuObject(hMenu)))
2598 {
2599 RETURN(FALSE);
2600 }
2601
2602 RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE));
2603
2604 CLEANUP:
2605 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_);
2606 UserLeave();
2607 END_CLEANUP;
2608 }
2609
2610 /*
2611 * @implemented
2612 */
2613 BOOL APIENTRY
2614 NtUserThunkedMenuItemInfo(
2615 HMENU hMenu,
2616 UINT uItem,
2617 BOOL fByPosition,
2618 BOOL bInsert,
2619 LPMENUITEMINFOW lpmii,
2620 PUNICODE_STRING lpszCaption)
2621 {
2622 PMENU Menu;
2623 NTSTATUS Status;
2624 UNICODE_STRING lstrCaption;
2625 DECLARE_RETURN(BOOL);
2626
2627 TRACE("Enter NtUserThunkedMenuItemInfo\n");
2628 UserEnterExclusive();
2629
2630 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2631 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
2632
2633 if (!(Menu = UserGetMenuObject(hMenu)))
2634 {
2635 RETURN(FALSE);
2636 }
2637
2638 RtlInitUnicodeString(&lstrCaption, 0);
2639
2640 /* Check if we got a Caption */
2641 if (lpszCaption && lpszCaption->Buffer)
2642 {
2643 /* Copy the string to kernel mode */
2644 Status = ProbeAndCaptureUnicodeString( &lstrCaption,
2645 UserMode,
2646 lpszCaption);
2647 if (!NT_SUCCESS(Status))
2648 {
2649 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status);
2650 SetLastNtError(Status);
2651 RETURN(FALSE);
2652 }
2653 }
2654
2655 if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii, &lstrCaption));
2656
2657 RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE, &lstrCaption));
2658
2659 CLEANUP:
2660 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_);
2661 UserLeave();
2662 END_CLEANUP;
2663 }
2664
2665 /* EOF */