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