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