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