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