Sync to trunk revision 63922.
[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 PMENU MenuObject;
1147
1148 CurrentProcess = PsGetCurrentProcess();
1149 if (CurrentProcess != Process)
1150 {
1151 KeAttachProcess(&Process->Pcb);
1152 }
1153
1154 while (!IsListEmpty(&Win32Process->MenuListHead))
1155 {
1156 MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU, ListEntry);
1157 TRACE("Menus are stuck on the process list!\n");
1158 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
1159 }
1160
1161 if (CurrentProcess != Process)
1162 {
1163 KeDetachProcess();
1164 }
1165 return TRUE;
1166 }
1167
1168 BOOLEAN APIENTRY
1169 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
1170 {
1171
1172 DWORD dwStyle = 0;
1173 DWORD dwExStyle = 0;
1174 BOOLEAN retValue = TRUE;
1175
1176 if (bti->cbSize == sizeof(TITLEBARINFO))
1177 {
1178 RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1));
1179
1180 bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1181
1182 dwStyle = pWindowObject->style;
1183 dwExStyle = pWindowObject->ExStyle;
1184
1185 bti->rcTitleBar.top = 0;
1186 bti->rcTitleBar.left = 0;
1187 bti->rcTitleBar.right = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left;
1188 bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top;
1189
1190 /* Is it iconiced ? */
1191 if ((dwStyle & WS_ICONIC)!=WS_ICONIC)
1192 {
1193 /* Remove frame from rectangle */
1194 if (HAS_THICKFRAME( dwStyle, dwExStyle ))
1195 {
1196 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
1197 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1198 }
1199 else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
1200 {
1201 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
1202 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1203 }
1204 else if (HAS_THINFRAME( dwStyle, dwExStyle))
1205 {
1206 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1207 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) );
1208 }
1209
1210 /* We have additional border information if the window
1211 * is a child (but not an MDI child) */
1212 if ( (dwStyle & WS_CHILD) &&
1213 ((dwExStyle & WS_EX_MDICHILD) == 0 ) )
1214 {
1215 if (dwExStyle & WS_EX_CLIENTEDGE)
1216 {
1217 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
1218 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
1219 }
1220
1221 if (dwExStyle & WS_EX_STATICEDGE)
1222 {
1223 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1224 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1225 }
1226 }
1227 }
1228
1229 bti->rcTitleBar.top += pWindowObject->rcWindow.top;
1230 bti->rcTitleBar.left += pWindowObject->rcWindow.left;
1231 bti->rcTitleBar.right += pWindowObject->rcWindow.left;
1232
1233 bti->rcTitleBar.bottom = bti->rcTitleBar.top;
1234 if (dwExStyle & WS_EX_TOOLWINDOW)
1235 {
1236 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
1237 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION);
1238 }
1239 else
1240 {
1241 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
1242 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION);
1243 bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE);
1244 }
1245
1246 if (dwStyle & WS_CAPTION)
1247 {
1248 bti->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1249 if (dwStyle & WS_SYSMENU)
1250 {
1251 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
1252 {
1253 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1254 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1255 }
1256 else
1257 {
1258 if (!(dwStyle & WS_MINIMIZEBOX))
1259 {
1260 bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1261 }
1262 if (!(dwStyle & WS_MAXIMIZEBOX))
1263 {
1264 bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1265 }
1266 }
1267
1268 if (!(dwExStyle & WS_EX_CONTEXTHELP))
1269 {
1270 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1271 }
1272 if (pWindowObject->pcls->style & CS_NOCLOSE)
1273 {
1274 bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1275 }
1276 }
1277 else
1278 {
1279 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1280 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1281 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1282 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1283 }
1284 }
1285 else
1286 {
1287 bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1288 }
1289 }
1290 else
1291 {
1292 EngSetLastError(ERROR_INVALID_PARAMETER);
1293 retValue = FALSE;
1294 }
1295
1296 return retValue;
1297 }
1298
1299 DWORD FASTCALL
1300 UserInsertMenuItem(
1301 PMENU Menu,
1302 UINT uItem,
1303 BOOL fByPosition,
1304 LPCMENUITEMINFOW UnsafeItemInfo,
1305 PUNICODE_STRING lpstr)
1306 {
1307 NTSTATUS Status;
1308 ROSMENUITEMINFO ItemInfo;
1309
1310 /* Try to copy the whole MENUITEMINFOW structure */
1311 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
1312 if (NT_SUCCESS(Status))
1313 {
1314 if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
1315 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1316 {
1317 EngSetLastError(ERROR_INVALID_PARAMETER);
1318 return FALSE;
1319 }
1320 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
1321 }
1322
1323 /* Try to copy without last field (not present in older versions) */
1324 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
1325 if (NT_SUCCESS(Status))
1326 {
1327 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1328 {
1329 EngSetLastError(ERROR_INVALID_PARAMETER);
1330 return FALSE;
1331 }
1332 ItemInfo.hbmpItem = (HBITMAP)0;
1333 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
1334 }
1335
1336 SetLastNtError(Status);
1337 return FALSE;
1338 }
1339
1340 UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags)
1341 {
1342 PMENU MenuObject;
1343 PITEM pItem;
1344
1345 if (!(MenuObject = UserGetMenuObject(hMenu)))
1346 {
1347 return (UINT)-1;
1348 }
1349
1350 if (!(pItem = MENU_FindItem( &MenuObject, &uId, uFlags ))) return -1;
1351
1352 if (pItem->spSubMenu)
1353 {
1354 return (pItem->spSubMenu->cItems << 8) | ((pItem->fState|pItem->fType) & 0xff);
1355 }
1356 else
1357 return (pItem->fType | pItem->fState);
1358 }
1359
1360 HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos)
1361 {
1362 PMENU MenuObject;
1363 PITEM pItem;
1364
1365 if (!(MenuObject = UserGetMenuObject(hMenu)))
1366 {
1367 return NULL;
1368 }
1369
1370 if (!(pItem = MENU_FindItem( &MenuObject, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
1371
1372 if (pItem->spSubMenu)
1373 {
1374 HMENU hsubmenu = UserHMGetHandle(pItem->spSubMenu);
1375 return hsubmenu;
1376 }
1377 return NULL;
1378 }
1379
1380 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
1381 {
1382 PMENU menu;
1383 HMENU hSubMenu;
1384 UINT i;
1385 PITEM item;
1386
1387 if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
1388 return NO_SELECTED_ITEM;
1389
1390 item = menu->rgItems;
1391 for (i = 0; i < menu->cItems; i++, item++)
1392 {
1393 if (!item->spSubMenu)
1394 continue;
1395 else
1396 {
1397 hSubMenu = UserHMGetHandle(item->spSubMenu);
1398 if (hSubMenu == hSubTarget)
1399 {
1400 return i;
1401 }
1402 else
1403 {
1404 HMENU hsubmenu = hSubMenu;
1405 UINT pos = IntFindSubMenu( &hsubmenu, hSubTarget );
1406 if (pos != NO_SELECTED_ITEM)
1407 {
1408 *hMenu = hsubmenu;
1409 return pos;
1410 }
1411 }
1412 }
1413 }
1414 return NO_SELECTED_ITEM;
1415 }
1416
1417
1418 HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
1419 {
1420 PWINSTATION_OBJECT WinStaObject;
1421 HANDLE Handle;
1422 PMENU Menu;
1423 NTSTATUS Status;
1424 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1425
1426 if (gpepCSRSS != CurrentProcess)
1427 {
1428 /*
1429 * gpepCSRSS does not have a Win32WindowStation
1430 */
1431
1432 Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
1433 KernelMode,
1434 0,
1435 &WinStaObject);
1436
1437 if (!NT_SUCCESS(Status))
1438 {
1439 ERR("Validation of window station handle (%p) failed\n",
1440 CurrentProcess->Win32WindowStation);
1441 SetLastNtError(Status);
1442 return (HMENU)0;
1443 }
1444 Menu = IntCreateMenu(&Handle, !PopupMenu);
1445 if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
1446 {
1447 ERR("Desktop Window Station does not match Process one!\n");
1448 }
1449 ObDereferenceObject(WinStaObject);
1450 }
1451 else
1452 {
1453 Menu = IntCreateMenu(&Handle, !PopupMenu);
1454 }
1455
1456 if (Menu) UserDereferenceObject(Menu);
1457 return (HMENU)Handle;
1458 }
1459
1460 BOOL FASTCALL
1461 IntMenuItemInfo(
1462 PMENU Menu,
1463 UINT Item,
1464 BOOL ByPosition,
1465 PROSMENUITEMINFO ItemInfo,
1466 BOOL SetOrGet,
1467 PUNICODE_STRING lpstr)
1468 {
1469 PITEM MenuItem;
1470 BOOL Ret;
1471
1472 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
1473 {
1474 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
1475 return( FALSE);
1476 }
1477 if (SetOrGet)
1478 {
1479 Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr);
1480 }
1481 else
1482 {
1483 Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo);
1484 }
1485 return( Ret);
1486 }
1487
1488 BOOL FASTCALL
1489 UserMenuItemInfo(
1490 PMENU Menu,
1491 UINT Item,
1492 BOOL ByPosition,
1493 PROSMENUITEMINFO UnsafeItemInfo,
1494 BOOL SetOrGet,
1495 PUNICODE_STRING lpstr)
1496 {
1497 PITEM MenuItem;
1498 ROSMENUITEMINFO ItemInfo;
1499 NTSTATUS Status;
1500 UINT Size;
1501 BOOL Ret;
1502
1503 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
1504 if (! NT_SUCCESS(Status))
1505 {
1506 SetLastNtError(Status);
1507 return( FALSE);
1508 }
1509 if (sizeof(MENUITEMINFOW) != Size
1510 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
1511 && sizeof(ROSMENUITEMINFO) != Size)
1512 {
1513 EngSetLastError(ERROR_INVALID_PARAMETER);
1514 return( FALSE);
1515 }
1516 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
1517 if (! NT_SUCCESS(Status))
1518 {
1519 SetLastNtError(Status);
1520 return( FALSE);
1521 }
1522 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
1523 set/get hbmpItem */
1524 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
1525 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
1526 {
1527 EngSetLastError(ERROR_INVALID_PARAMETER);
1528 return( FALSE);
1529 }
1530
1531 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
1532 {
1533 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
1534 return( FALSE);
1535 }
1536
1537 if (SetOrGet)
1538 {
1539 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo, lpstr);
1540 }
1541 else
1542 {
1543 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
1544 if (Ret)
1545 {
1546 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
1547 if (! NT_SUCCESS(Status))
1548 {
1549 SetLastNtError(Status);
1550 return( FALSE);
1551 }
1552 }
1553 }
1554
1555 return( Ret);
1556 }
1557
1558 BOOL FASTCALL
1559 UserMenuInfo(
1560 PMENU Menu,
1561 PROSMENUINFO UnsafeMenuInfo,
1562 BOOL SetOrGet)
1563 {
1564 BOOL Res;
1565 DWORD Size;
1566 NTSTATUS Status;
1567 ROSMENUINFO MenuInfo;
1568
1569 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
1570 if (! NT_SUCCESS(Status))
1571 {
1572 SetLastNtError(Status);
1573 return( FALSE);
1574 }
1575 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
1576 {
1577 EngSetLastError(ERROR_INVALID_PARAMETER);
1578 return( FALSE);
1579 }
1580 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
1581 if (! NT_SUCCESS(Status))
1582 {
1583 SetLastNtError(Status);
1584 return( FALSE);
1585 }
1586
1587 if(SetOrGet)
1588 {
1589 /* Set MenuInfo */
1590 Res = IntSetMenuInfo(Menu, &MenuInfo);
1591 }
1592 else
1593 {
1594 /* Get MenuInfo */
1595 Res = IntGetMenuInfo(Menu, &MenuInfo);
1596 if (Res)
1597 {
1598 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
1599 if (! NT_SUCCESS(Status))
1600 {
1601 SetLastNtError(Status);
1602 return( FALSE);
1603 }
1604 }
1605 }
1606
1607 return( Res);
1608 }
1609
1610 VOID FASTCALL
1611 MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
1612 {
1613 if (menu->dwArrowsOn)
1614 {
1615 UINT arrow_bitmap_height;
1616 //BITMAP bmp;
1617 //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
1618 arrow_bitmap_height = gpsi->oembmi[65].cy; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
1619 //arrow_bitmap_height = bmp.bmHeight;
1620 rect->top += arrow_bitmap_height - menu->iTop;
1621 rect->bottom += arrow_bitmap_height - menu->iTop;
1622 }
1623 }
1624
1625 BOOL FASTCALL
1626 IntGetMenuItemRect(
1627 PWND pWnd,
1628 PMENU Menu,
1629 UINT uItem,
1630 PRECTL Rect)
1631 {
1632 LONG XMove, YMove;
1633 PITEM MenuItem;
1634
1635 if (!pWnd)
1636 {
1637 HWND hWnd = Menu->hWnd;
1638 if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
1639 }
1640
1641 if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
1642 {
1643 Rect->left = MenuItem->xItem;
1644 Rect->top = MenuItem->yItem;
1645 Rect->right = MenuItem->cxItem; // Do this for now......
1646 Rect->bottom = MenuItem->cyItem;
1647 }
1648 else
1649 {
1650 ERR("Failed Item Lookup! %d\n", uItem);
1651 return FALSE;
1652 }
1653
1654 if (Menu->fFlags & MNF_POPUP)
1655 {
1656 XMove = pWnd->rcClient.left;
1657 YMove = pWnd->rcClient.top;
1658 }
1659 else
1660 {
1661 XMove = pWnd->rcWindow.left;
1662 YMove = pWnd->rcWindow.top;
1663 }
1664
1665 Rect->left += XMove;
1666 Rect->top += YMove;
1667 Rect->right += XMove;
1668 Rect->bottom += YMove;
1669
1670 return TRUE;
1671 }
1672
1673 PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
1674 {
1675 PMENU Menu, NewMenu = NULL, SysMenu = NULL;
1676 HMENU hSysMenu, hNewMenu = NULL;
1677 ROSMENUITEMINFO ItemInfoSet = {0};
1678 ROSMENUITEMINFO ItemInfo = {0};
1679 UNICODE_STRING MenuName;
1680
1681 hSysMenu = UserCreateMenu(FALSE);
1682 if (NULL == hSysMenu)
1683 {
1684 return NULL;
1685 }
1686 SysMenu = IntGetMenuObject(hSysMenu);
1687 if (NULL == SysMenu)
1688 {
1689 UserDestroyMenu(hSysMenu);
1690 return NULL;
1691 }
1692
1693 SysMenu->fFlags |= MNF_SYSMENU;
1694 SysMenu->hWnd = Window->head.h;
1695
1696 if (!Popup)
1697 {
1698 //hNewMenu = co_IntLoadSysMenuTemplate();
1699 if ( Window->ExStyle & WS_EX_MDICHILD )
1700 {
1701 RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
1702 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
1703 }
1704 else
1705 {
1706 RtlInitUnicodeString( &MenuName, L"SYSMENU");
1707 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
1708 //ERR("%wZ\n",&MenuName);
1709 }
1710 if (!hNewMenu)
1711 {
1712 ERR("No Menu!!\n");
1713 IntReleaseMenuObject(SysMenu);
1714 UserDestroyMenu(hSysMenu);
1715 return NULL;
1716 }
1717 Menu = IntGetMenuObject(hNewMenu);
1718 if (!Menu)
1719 {
1720 IntReleaseMenuObject(SysMenu);
1721 UserDestroyMenu(hSysMenu);
1722 return NULL;
1723 }
1724
1725 // Do the rest in here.
1726
1727 Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU | MNF_POPUP;
1728
1729 ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
1730 ItemInfoSet.fMask = MIIM_BITMAP;
1731 ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
1732 IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
1733 ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
1734 IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
1735 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
1736 IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
1737 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
1738 IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
1739
1740 NewMenu = IntCloneMenu(Menu);
1741
1742 IntReleaseMenuObject(NewMenu);
1743 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
1744
1745 IntDestroyMenuObject(Menu, FALSE, TRUE);
1746 }
1747 else
1748 {
1749 NewMenu = Popup;
1750 }
1751 if (NewMenu)
1752 {
1753 NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP;
1754
1755 if (Window->pcls->style & CS_NOCLOSE)
1756 IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
1757
1758 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
1759 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
1760 ItemInfo.fType = 0;
1761 ItemInfo.fState = MFS_ENABLED;
1762 ItemInfo.dwTypeData = NULL;
1763 ItemInfo.cch = 0;
1764 ItemInfo.hSubMenu = UserHMGetHandle(NewMenu);
1765 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
1766
1767 return SysMenu;
1768 }
1769 ERR("failed to load system menu!\n");
1770 return NULL;
1771 }
1772
1773 PMENU FASTCALL
1774 IntGetSystemMenu(PWND Window, BOOL bRevert)
1775 {
1776 PMENU Menu;
1777
1778 if (bRevert)
1779 {
1780 if (Window->SystemMenu)
1781 {
1782 Menu = UserGetMenuObject(Window->SystemMenu);
1783 if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
1784 {
1785 IntDestroyMenuObject(Menu, TRUE, TRUE);
1786 Window->SystemMenu = NULL;
1787 }
1788 }
1789 }
1790 else
1791 {
1792 Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
1793 if ((!Window->SystemMenu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
1794 {
1795 Menu = MENU_GetSystemMenu(Window, NULL);
1796 Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
1797 }
1798 }
1799
1800 if (Window->SystemMenu)
1801 {
1802 HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0);
1803 /* Store the dummy sysmenu handle to facilitate the refresh */
1804 /* of the close button if the SC_CLOSE item change */
1805 Menu = UserGetMenuObject(hMenu);
1806 if (Menu)
1807 {
1808 Menu->spwndNotify = Window;
1809 Menu->fFlags |= MNF_SYSSUBMENU;
1810 }
1811 return Menu;
1812 }
1813 return NULL;
1814 }
1815
1816 BOOL FASTCALL
1817 IntSetSystemMenu(PWND Window, PMENU Menu)
1818 {
1819 PMENU OldMenu;
1820
1821 if (!(Window->style & WS_SYSMENU)) return FALSE;
1822
1823 if (Window->SystemMenu)
1824 {
1825 OldMenu = UserGetMenuObject(Window->SystemMenu);
1826 if (OldMenu)
1827 {
1828 OldMenu->fFlags &= ~MNF_SYSMENU;
1829 IntDestroyMenuObject(OldMenu, TRUE, TRUE);
1830 }
1831 }
1832
1833 OldMenu = MENU_GetSystemMenu(Window, Menu);
1834 if (OldMenu)
1835 { // Use spmenuSys too!
1836 Window->SystemMenu = UserHMGetHandle(OldMenu);
1837 }
1838 else
1839 Window->SystemMenu = NULL;
1840
1841 if (Menu && Window != Menu->spwndNotify)
1842 {
1843 Menu->spwndNotify = Window;
1844 }
1845
1846 return TRUE;
1847 }
1848
1849
1850 /* FUNCTIONS *****************************************************************/
1851
1852 /*
1853 * @implemented
1854 */
1855 DWORD APIENTRY
1856 NtUserCheckMenuItem(
1857 HMENU hMenu,
1858 UINT uIDCheckItem,
1859 UINT uCheck)
1860 {
1861 PMENU Menu;
1862 DECLARE_RETURN(DWORD);
1863
1864 TRACE("Enter NtUserCheckMenuItem\n");
1865 UserEnterExclusive();
1866
1867 if(!(Menu = UserGetMenuObject(hMenu)))
1868 {
1869 RETURN( (DWORD)-1);
1870 }
1871
1872 RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
1873
1874 CLEANUP:
1875 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_);
1876 UserLeave();
1877 END_CLEANUP;
1878 }
1879
1880 /*
1881 * @implemented
1882 */
1883 BOOL APIENTRY
1884 NtUserDeleteMenu(
1885 HMENU hMenu,
1886 UINT uPosition,
1887 UINT uFlags)
1888 {
1889 PMENU Menu;
1890 DECLARE_RETURN(BOOL);
1891
1892 TRACE("Enter NtUserDeleteMenu\n");
1893 UserEnterExclusive();
1894
1895 if(!(Menu = UserGetMenuObject(hMenu)))
1896 {
1897 RETURN( FALSE);
1898 }
1899
1900 RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
1901
1902 CLEANUP:
1903 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
1904 UserLeave();
1905 END_CLEANUP;
1906 }
1907
1908 /*
1909 * NtUserGetSystemMenu
1910 *
1911 * The NtUserGetSystemMenu function allows the application to access the
1912 * window menu (also known as the system menu or the control menu) for
1913 * copying and modifying.
1914 *
1915 * Parameters
1916 * hWnd
1917 * Handle to the window that will own a copy of the window menu.
1918 * bRevert
1919 * Specifies the action to be taken. If this parameter is FALSE,
1920 * NtUserGetSystemMenu returns a handle to the copy of the window menu
1921 * currently in use. The copy is initially identical to the window menu
1922 * but it can be modified.
1923 * If this parameter is TRUE, GetSystemMenu resets the window menu back
1924 * to the default state. The previous window menu, if any, is destroyed.
1925 *
1926 * Return Value
1927 * If the bRevert parameter is FALSE, the return value is a handle to a
1928 * copy of the window menu. If the bRevert parameter is TRUE, the return
1929 * value is NULL.
1930 *
1931 * Status
1932 * @implemented
1933 */
1934
1935 HMENU APIENTRY
1936 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
1937 {
1938 PWND Window;
1939 PMENU Menu;
1940 DECLARE_RETURN(HMENU);
1941
1942 TRACE("Enter NtUserGetSystemMenu\n");
1943 UserEnterShared();
1944
1945 if (!(Window = UserGetWindowObject(hWnd)))
1946 {
1947 RETURN(NULL);
1948 }
1949
1950 if (!(Menu = IntGetSystemMenu(Window, bRevert)))
1951 {
1952 RETURN(NULL);
1953 }
1954
1955 RETURN(Menu->head.h);
1956
1957 CLEANUP:
1958 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_);
1959 UserLeave();
1960 END_CLEANUP;
1961 }
1962
1963 /*
1964 * NtUserSetSystemMenu
1965 *
1966 * Status
1967 * @implemented
1968 */
1969
1970 BOOL APIENTRY
1971 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
1972 {
1973 BOOL Result = FALSE;
1974 PWND Window;
1975 PMENU Menu;
1976 DECLARE_RETURN(BOOL);
1977
1978 TRACE("Enter NtUserSetSystemMenu\n");
1979 UserEnterExclusive();
1980
1981 if (!(Window = UserGetWindowObject(hWnd)))
1982 {
1983 RETURN( FALSE);
1984 }
1985
1986 if (hMenu)
1987 {
1988 /*
1989 * Assign new menu handle and Up the Lock Count.
1990 */
1991 if (!(Menu = IntGetMenuObject(hMenu)))
1992 {
1993 RETURN( FALSE);
1994 }
1995
1996 Result = IntSetSystemMenu(Window, Menu);
1997 }
1998 else
1999 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2000
2001 RETURN( Result);
2002
2003 CLEANUP:
2004 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
2005 UserLeave();
2006 END_CLEANUP;
2007 }
2008
2009 /*
2010 * @implemented
2011 */
2012 BOOLEAN APIENTRY
2013 NtUserGetTitleBarInfo(
2014 HWND hwnd,
2015 PTITLEBARINFO bti)
2016 {
2017 PWND WindowObject;
2018 TITLEBARINFO bartitleinfo;
2019 DECLARE_RETURN(BOOLEAN);
2020 BOOLEAN retValue = TRUE;
2021
2022 TRACE("Enter NtUserGetTitleBarInfo\n");
2023 UserEnterExclusive();
2024
2025 /* Vaildate the windows handle */
2026 if (!(WindowObject = UserGetWindowObject(hwnd)))
2027 {
2028 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2029 retValue = FALSE;
2030 }
2031
2032 _SEH2_TRY
2033 {
2034 /* Copy our usermode buffer bti to local buffer bartitleinfo */
2035 ProbeForRead(bti, sizeof(TITLEBARINFO), 1);
2036 RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO));
2037 }
2038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2039 {
2040 /* Fail copy the data */
2041 EngSetLastError(ERROR_INVALID_PARAMETER);
2042 retValue = FALSE;
2043 }
2044 _SEH2_END
2045
2046 /* Get the tile bar info */
2047 if (retValue)
2048 {
2049 retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo);
2050 if (retValue)
2051 {
2052 _SEH2_TRY
2053 {
2054 /* Copy our buffer to user mode buffer bti */
2055 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1);
2056 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO));
2057 }
2058 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2059 {
2060 /* Fail copy the data */
2061 EngSetLastError(ERROR_INVALID_PARAMETER);
2062 retValue = FALSE;
2063 }
2064 _SEH2_END
2065 }
2066 }
2067
2068 RETURN( retValue );
2069
2070 CLEANUP:
2071 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_);
2072 UserLeave();
2073 END_CLEANUP;
2074 }
2075
2076 /*
2077 * @implemented
2078 */
2079 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
2080 {
2081 PMENU Menu;
2082 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
2083
2084 if(!(Menu = UserGetMenuObject(hMenu)))
2085 {
2086 return FALSE;
2087 }
2088
2089 if (Menu->head.rpdesk != pti->rpdesk)
2090 {
2091 EngSetLastError(ERROR_ACCESS_DENIED);
2092 return FALSE;
2093 }
2094 return IntDestroyMenuObject(Menu, FALSE, TRUE);
2095 }
2096
2097 /*
2098 * @implemented
2099 */
2100 BOOL APIENTRY
2101 NtUserDestroyMenu(
2102 HMENU hMenu)
2103 {
2104 PMENU Menu;
2105 DECLARE_RETURN(BOOL);
2106
2107 TRACE("Enter NtUserDestroyMenu\n");
2108 UserEnterExclusive();
2109
2110 if(!(Menu = UserGetMenuObject(hMenu)))
2111 {
2112 RETURN( FALSE);
2113 }
2114 if (Menu->head.rpdesk != gptiCurrent->rpdesk)
2115 {
2116 EngSetLastError(ERROR_ACCESS_DENIED);
2117 RETURN( FALSE);
2118 }
2119 RETURN( IntDestroyMenuObject(Menu, TRUE, TRUE));
2120
2121 CLEANUP:
2122 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
2123 UserLeave();
2124 END_CLEANUP;
2125 }
2126
2127 /*
2128 * @implemented
2129 */
2130 UINT APIENTRY
2131 NtUserEnableMenuItem(
2132 HMENU hMenu,
2133 UINT uIDEnableItem,
2134 UINT uEnable)
2135 {
2136 PMENU Menu;
2137 DECLARE_RETURN(UINT);
2138
2139 TRACE("Enter NtUserEnableMenuItem\n");
2140 UserEnterExclusive();
2141
2142 if(!(Menu = UserGetMenuObject(hMenu)))
2143 {
2144 RETURN(-1);
2145 }
2146
2147 RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
2148
2149 CLEANUP:
2150 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_);
2151 UserLeave();
2152 END_CLEANUP;
2153 }
2154
2155 /*
2156 * @implemented
2157 */
2158 BOOL APIENTRY
2159 NtUserGetMenuBarInfo(
2160 HWND hwnd,
2161 LONG idObject,
2162 LONG idItem,
2163 PMENUBARINFO pmbi)
2164 {
2165 PWND pWnd;
2166 HMENU hMenu;
2167 MENUBARINFO kmbi;
2168 BOOL Ret;
2169 NTSTATUS Status = STATUS_SUCCESS;
2170 PMENU Menu = NULL;
2171 DECLARE_RETURN(BOOL);
2172
2173 TRACE("Enter NtUserGetMenuBarInfo\n");
2174 UserEnterShared();
2175
2176 if (!(pWnd = UserGetWindowObject(hwnd)))
2177 {
2178 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2179 RETURN(FALSE);
2180 }
2181
2182 switch (idObject)
2183 {
2184 case OBJID_CLIENT:
2185 if (!pWnd->pcls->fnid)
2186 RETURN(FALSE);
2187 if (pWnd->pcls->fnid != FNID_MENU)
2188 {
2189 WARN("called on invalid window: %d\n", pWnd->pcls->fnid);
2190 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2191 RETURN(FALSE);
2192 }
2193 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
2194 hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
2195 break;
2196 case OBJID_MENU:
2197 hMenu = UlongToHandle(pWnd->IDMenu);
2198 break;
2199 case OBJID_SYSMENU:
2200 if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE);
2201 Menu = IntGetSystemMenu(pWnd, FALSE);
2202 hMenu = Menu->head.h;
2203 break;
2204 default:
2205 RETURN(FALSE);
2206 }
2207
2208 if (!hMenu)
2209 RETURN(FALSE);
2210
2211 _SEH2_TRY
2212 {
2213 kmbi.cbSize = pmbi->cbSize;
2214 }
2215 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2216 {
2217 kmbi.cbSize = 0;
2218 }
2219 _SEH2_END
2220
2221 if (kmbi.cbSize != sizeof(MENUBARINFO))
2222 {
2223 EngSetLastError(ERROR_INVALID_PARAMETER);
2224 RETURN(FALSE);
2225 }
2226
2227 if (!Menu) Menu = UserGetMenuObject(hMenu);
2228 if (!Menu)
2229 RETURN(FALSE);
2230
2231 if (idItem < 0 || idItem > Menu->cItems)
2232 RETURN(FALSE);
2233
2234 RECTL_vSetEmptyRect(&kmbi.rcBar);
2235
2236 if (idItem == 0)
2237 {
2238 Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar);
2239 kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu;
2240 kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu;
2241 TRACE("idItem 0 %d\n",Ret);
2242 }
2243 else
2244 {
2245 Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar);
2246 TRACE("idItem X %d\n", Ret);
2247 }
2248
2249 kmbi.hMenu = hMenu;
2250 kmbi.hwndMenu = NULL;
2251 kmbi.fBarFocused = FALSE;
2252 kmbi.fFocused = FALSE;
2253 //kmbi.fBarFocused = top_popup_hmenu == hMenu;
2254 if (idItem)
2255 {
2256 kmbi.fFocused = Menu->iItem == idItem-1;
2257 if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu))
2258 {
2259 kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
2260 }
2261 }
2262 /* else
2263 {
2264 kmbi.fFocused = kmbi.fBarFocused;
2265 }
2266 */
2267 _SEH2_TRY
2268 {
2269 RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO));
2270 }
2271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2272 {
2273 Status = _SEH2_GetExceptionCode();
2274 }
2275 _SEH2_END
2276
2277 if (!NT_SUCCESS(Status))
2278 {
2279 SetLastNtError(Status);
2280 RETURN(FALSE);
2281 }
2282
2283 RETURN(TRUE);
2284
2285 CLEANUP:
2286 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
2287 UserLeave();
2288 END_CLEANUP;
2289 }
2290
2291 /*
2292 * @implemented
2293 */
2294 UINT APIENTRY
2295 NtUserGetMenuIndex(
2296 HMENU hMenu,
2297 HMENU hSubMenu)
2298 {
2299 PMENU Menu, SubMenu;
2300 PITEM MenuItem;
2301 UINT i;
2302 DECLARE_RETURN(UINT);
2303
2304 TRACE("Enter NtUserGetMenuIndex\n");
2305 UserEnterShared();
2306
2307 if ( !(Menu = UserGetMenuObject(hMenu)) ||
2308 !(SubMenu = UserGetMenuObject(hSubMenu)) )
2309 RETURN(0xFFFFFFFF);
2310
2311 MenuItem = Menu->rgItems;
2312 for (i = 0; i < Menu->cItems; i++, MenuItem++)
2313 {
2314 if (MenuItem->spSubMenu == SubMenu)
2315 RETURN(MenuItem->wID);
2316 }
2317 RETURN(0xFFFFFFFF);
2318
2319 CLEANUP:
2320 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_);
2321 UserLeave();
2322 END_CLEANUP;
2323 }
2324
2325 /*
2326 * @implemented
2327 */
2328 BOOL APIENTRY
2329 NtUserGetMenuItemRect(
2330 HWND hWnd,
2331 HMENU hMenu,
2332 UINT uItem,
2333 PRECTL lprcItem)
2334 {
2335 PWND ReferenceWnd;
2336 LONG XMove, YMove;
2337 RECTL Rect;
2338 PMENU Menu;
2339 PITEM MenuItem;
2340 NTSTATUS Status = STATUS_SUCCESS;
2341 DECLARE_RETURN(BOOL);
2342
2343 TRACE("Enter NtUserGetMenuItemRect\n");
2344 UserEnterShared();
2345
2346 if (!(Menu = UserGetMenuObject(hMenu)))
2347 {
2348 RETURN(FALSE);
2349 }
2350
2351 if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
2352 {
2353 Rect.left = MenuItem->xItem;
2354 Rect.top = MenuItem->yItem;
2355 Rect.right = MenuItem->cxItem; // Do this for now......
2356 Rect.bottom = MenuItem->cyItem;
2357 }
2358 else
2359 RETURN(FALSE);
2360
2361 if(!hWnd)
2362 {
2363 hWnd = Menu->hWnd;
2364 }
2365
2366 if (lprcItem == NULL) RETURN( FALSE);
2367
2368 if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE);
2369
2370 if (Menu->fFlags & MNF_POPUP)
2371 {
2372 XMove = ReferenceWnd->rcClient.left;
2373 YMove = ReferenceWnd->rcClient.top;
2374 }
2375 else
2376 {
2377 XMove = ReferenceWnd->rcWindow.left;
2378 YMove = ReferenceWnd->rcWindow.top;
2379 }
2380
2381 Rect.left += XMove;
2382 Rect.top += YMove;
2383 Rect.right += XMove;
2384 Rect.bottom += YMove;
2385
2386 _SEH2_TRY
2387 {
2388 RtlCopyMemory(lprcItem, &Rect, sizeof(RECTL));
2389 }
2390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2391 {
2392 Status = _SEH2_GetExceptionCode();
2393 }
2394 _SEH2_END
2395
2396 if (!NT_SUCCESS(Status))
2397 {
2398 SetLastNtError(Status);
2399 RETURN(FALSE);
2400 }
2401 RETURN(TRUE);
2402
2403 CLEANUP:
2404 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
2405 UserLeave();
2406 END_CLEANUP;
2407 }
2408
2409 /*
2410 * @implemented
2411 */
2412 BOOL APIENTRY
2413 NtUserHiliteMenuItem(
2414 HWND hWnd,
2415 HMENU hMenu,
2416 UINT uItemHilite,
2417 UINT uHilite)
2418 {
2419 PMENU Menu;
2420 PWND Window;
2421 DECLARE_RETURN(BOOLEAN);
2422
2423 TRACE("Enter NtUserHiliteMenuItem\n");
2424 UserEnterExclusive();
2425
2426 if(!(Window = UserGetWindowObject(hWnd)))
2427 {
2428 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2429 RETURN(FALSE);
2430 }
2431
2432 if(!(Menu = UserGetMenuObject(hMenu)))
2433 {
2434 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2435 RETURN(FALSE);
2436 }
2437
2438 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
2439
2440 CLEANUP:
2441 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_);
2442 UserLeave();
2443 END_CLEANUP;
2444 }
2445
2446
2447 /*
2448 * @implemented
2449 */
2450 int APIENTRY
2451 NtUserMenuItemFromPoint(
2452 HWND hWnd,
2453 HMENU hMenu,
2454 DWORD X,
2455 DWORD Y)
2456 {
2457 PMENU Menu;
2458 PWND Window = NULL;
2459 PITEM mi;
2460 int i;
2461 DECLARE_RETURN(int);
2462
2463 TRACE("Enter NtUserMenuItemFromPoint\n");
2464 UserEnterExclusive();
2465
2466 if (!(Menu = UserGetMenuObject(hMenu)))
2467 {
2468 RETURN( -1);
2469 }
2470
2471 if (!(Window = UserGetWindowObject(Menu->hWnd)))
2472 {
2473 RETURN( -1);
2474 }
2475
2476 X -= Window->rcWindow.left;
2477 Y -= Window->rcWindow.top;
2478
2479 mi = Menu->rgItems;
2480 for (i = 0; i < Menu->cItems; i++, mi++)
2481 {
2482 RECTL Rect;
2483 Rect.left = mi->xItem;
2484 Rect.top = mi->yItem;
2485 Rect.right = mi->cxItem; // Do this for now......
2486 Rect.bottom = mi->cyItem;
2487 //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
2488 if (RECTL_bPointInRect(&Rect, X, Y))
2489 {
2490 break;
2491 }
2492 }
2493
2494 RETURN( (mi ? i : NO_SELECTED_ITEM));
2495
2496 CLEANUP:
2497 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
2498 UserLeave();
2499 END_CLEANUP;
2500 }
2501
2502
2503 /*
2504 * @implemented
2505 */
2506 BOOL APIENTRY
2507 NtUserRemoveMenu(
2508 HMENU hMenu,
2509 UINT uPosition,
2510 UINT uFlags)
2511 {
2512 PMENU Menu;
2513 DECLARE_RETURN(BOOL);
2514
2515 TRACE("Enter NtUserRemoveMenu\n");
2516 UserEnterExclusive();
2517
2518 if(!(Menu = UserGetMenuObject(hMenu)))
2519 {
2520 RETURN( FALSE);
2521 }
2522
2523 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
2524
2525 CLEANUP:
2526 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
2527 UserLeave();
2528 END_CLEANUP;
2529
2530 }
2531
2532 /*
2533 * @implemented
2534 */
2535 BOOL APIENTRY
2536 NtUserSetMenuContextHelpId(
2537 HMENU hMenu,
2538 DWORD dwContextHelpId)
2539 {
2540 PMENU Menu;
2541 DECLARE_RETURN(BOOL);
2542
2543 TRACE("Enter NtUserSetMenuContextHelpId\n");
2544 UserEnterExclusive();
2545
2546 if(!(Menu = UserGetMenuObject(hMenu)))
2547 {
2548 RETURN( FALSE);
2549 }
2550
2551 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
2552
2553 CLEANUP:
2554 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
2555 UserLeave();
2556 END_CLEANUP;
2557 }
2558
2559 /*
2560 * @implemented
2561 */
2562 BOOL APIENTRY
2563 NtUserSetMenuDefaultItem(
2564 HMENU hMenu,
2565 UINT uItem,
2566 UINT fByPos)
2567 {
2568 PMENU Menu;
2569 DECLARE_RETURN(BOOL);
2570
2571 TRACE("Enter NtUserSetMenuDefaultItem\n");
2572 UserEnterExclusive();
2573
2574 if(!(Menu = UserGetMenuObject(hMenu)))
2575 {
2576 RETURN( FALSE);
2577 }
2578
2579 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
2580
2581 CLEANUP:
2582 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
2583 UserLeave();
2584 END_CLEANUP;
2585 }
2586
2587 /*
2588 * @implemented
2589 */
2590 BOOL APIENTRY
2591 NtUserSetMenuFlagRtoL(
2592 HMENU hMenu)
2593 {
2594 PMENU Menu;
2595 DECLARE_RETURN(BOOL);
2596
2597 TRACE("Enter NtUserSetMenuFlagRtoL\n");
2598 UserEnterExclusive();
2599
2600 if(!(Menu = UserGetMenuObject(hMenu)))
2601 {
2602 RETURN( FALSE);
2603 }
2604
2605 RETURN(IntSetMenuFlagRtoL(Menu));
2606
2607 CLEANUP:
2608 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
2609 UserLeave();
2610 END_CLEANUP;
2611 }
2612
2613 /*
2614 * @implemented
2615 */
2616 BOOL APIENTRY
2617 NtUserThunkedMenuInfo(
2618 HMENU hMenu,
2619 LPCMENUINFO lpcmi)
2620 {
2621 PMENU Menu;
2622 DECLARE_RETURN(BOOL);
2623
2624 TRACE("Enter NtUserThunkedMenuInfo\n");
2625 UserEnterExclusive();
2626
2627 if (!(Menu = UserGetMenuObject(hMenu)))
2628 {
2629 RETURN(FALSE);
2630 }
2631
2632 RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE));
2633
2634 CLEANUP:
2635 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_);
2636 UserLeave();
2637 END_CLEANUP;
2638 }
2639
2640 /*
2641 * @implemented
2642 */
2643 BOOL APIENTRY
2644 NtUserThunkedMenuItemInfo(
2645 HMENU hMenu,
2646 UINT uItem,
2647 BOOL fByPosition,
2648 BOOL bInsert,
2649 LPMENUITEMINFOW lpmii,
2650 PUNICODE_STRING lpszCaption)
2651 {
2652 PMENU Menu;
2653 NTSTATUS Status;
2654 UNICODE_STRING lstrCaption;
2655 DECLARE_RETURN(BOOL);
2656
2657 TRACE("Enter NtUserThunkedMenuItemInfo\n");
2658 UserEnterExclusive();
2659
2660 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2661 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
2662
2663 if (!(Menu = UserGetMenuObject(hMenu)))
2664 {
2665 RETURN(FALSE);
2666 }
2667
2668 RtlInitUnicodeString(&lstrCaption, 0);
2669
2670 /* Check if we got a Caption */
2671 if (lpszCaption && lpszCaption->Buffer)
2672 {
2673 /* Copy the string to kernel mode */
2674 Status = ProbeAndCaptureUnicodeString( &lstrCaption,
2675 UserMode,
2676 lpszCaption);
2677 if (!NT_SUCCESS(Status))
2678 {
2679 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status);
2680 SetLastNtError(Status);
2681 RETURN(FALSE);
2682 }
2683 }
2684
2685 if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii, &lstrCaption));
2686
2687 RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE, &lstrCaption));
2688
2689 CLEANUP:
2690 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_);
2691 UserLeave();
2692 END_CLEANUP;
2693 }
2694
2695 /* EOF */