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