- Remove KeAttachProcess and KeDetachProcess prototypes from winddk.h.
[reactos.git] / reactos / subsys / win32k / ntuser / menu.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Menus
24 * FILE: subsys/win32k/ntuser/menu.c
25 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 07/30/2003 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* INTERNAL ******************************************************************/
37
38 /* maximum number of menu items a menu can contain */
39 #define MAX_MENU_ITEMS (0x4000)
40 #define MAX_GOINTOSUBMENU (0x10)
41
42 #define UpdateMenuItemState(state, change) \
43 {\
44 if((change) & MFS_DISABLED) { \
45 (state) |= MFS_DISABLED; \
46 } else { \
47 (state) &= ~MFS_DISABLED; \
48 } \
49 if((change) & MFS_CHECKED) { \
50 (state) |= MFS_CHECKED; \
51 } else { \
52 (state) &= ~MFS_CHECKED; \
53 } \
54 if((change) & MFS_HILITE) { \
55 (state) |= MFS_HILITE; \
56 } else { \
57 (state) &= ~MFS_HILITE; \
58 } \
59 if((change) & MFS_DEFAULT) { \
60 (state) |= MFS_DEFAULT; \
61 } else { \
62 (state) &= ~MFS_DEFAULT; \
63 } \
64 if((change) & MF_MOUSESELECT) { \
65 (state) |= MF_MOUSESELECT; \
66 } else { \
67 (state) &= ~MF_MOUSESELECT; \
68 } \
69 }
70
71 #define FreeMenuText(MenuItem) \
72 { \
73 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
74 (MenuItem)->Text.Length) { \
75 RtlFreeUnicodeString(&(MenuItem)->Text); \
76 } \
77 }
78
79 #define InRect(r, x, y) \
80 ( ( ((r).right >= x)) && \
81 ( ((r).left <= x)) && \
82 ( ((r).bottom >= y)) && \
83 ( ((r).top <= y)) )
84
85 NTSTATUS FASTCALL
86 InitMenuImpl(VOID)
87 {
88 return(STATUS_SUCCESS);
89 }
90
91 NTSTATUS FASTCALL
92 CleanupMenuImpl(VOID)
93 {
94 return(STATUS_SUCCESS);
95 }
96
97 #if 0
98 void FASTCALL
99 DumpMenuItemList(PMENU_ITEM MenuItem)
100 {
101 UINT cnt = 0;
102 while(MenuItem)
103 {
104 if(MenuItem->Text.Length)
105 DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text);
106 else
107 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer);
108 DbgPrint(" fType=");
109 if(MFT_BITMAP & MenuItem->fType) DbgPrint("MFT_BITMAP ");
110 if(MFT_MENUBARBREAK & MenuItem->fType) DbgPrint("MFT_MENUBARBREAK ");
111 if(MFT_MENUBREAK & MenuItem->fType) DbgPrint("MFT_MENUBREAK ");
112 if(MFT_OWNERDRAW & MenuItem->fType) DbgPrint("MFT_OWNERDRAW ");
113 if(MFT_RADIOCHECK & MenuItem->fType) DbgPrint("MFT_RADIOCHECK ");
114 if(MFT_RIGHTJUSTIFY & MenuItem->fType) DbgPrint("MFT_RIGHTJUSTIFY ");
115 if(MFT_SEPARATOR & MenuItem->fType) DbgPrint("MFT_SEPARATOR ");
116 if(MFT_STRING & MenuItem->fType) DbgPrint("MFT_STRING ");
117 DbgPrint("\n fState=");
118 if(MFS_DISABLED & MenuItem->fState) DbgPrint("MFS_DISABLED ");
119 else DbgPrint("MFS_ENABLED ");
120 if(MFS_CHECKED & MenuItem->fState) DbgPrint("MFS_CHECKED ");
121 else DbgPrint("MFS_UNCHECKED ");
122 if(MFS_HILITE & MenuItem->fState) DbgPrint("MFS_HILITE ");
123 else DbgPrint("MFS_UNHILITE ");
124 if(MFS_DEFAULT & MenuItem->fState) DbgPrint("MFS_DEFAULT ");
125 if(MFS_GRAYED & MenuItem->fState) DbgPrint("MFS_GRAYED ");
126 DbgPrint("\n wId=%d\n", MenuItem->wID);
127 MenuItem = MenuItem->Next;
128 }
129 DbgPrint("Entries: %d\n", cnt);
130 return;
131 }
132 #endif
133
134 PMENU_OBJECT FASTCALL
135 IntGetMenuObject(HMENU hMenu)
136 {
137 PMENU_OBJECT MenuObject;
138 PW32THREAD W32Thread = PsGetWin32Thread();
139
140 if(!W32Thread)
141 {
142 return NULL;
143 }
144
145 NTSTATUS Status = ObmReferenceObjectByHandle(W32Thread->Desktop->WindowStation->HandleTable,
146 hMenu, otMenu, (PVOID*)&MenuObject);
147 if (!NT_SUCCESS(Status))
148 {
149 return NULL;
150 }
151 return MenuObject;
152 }
153
154 BOOL FASTCALL
155 IntFreeMenuItem(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem,
156 BOOL RemoveFromList, BOOL bRecurse)
157 {
158 FreeMenuText(MenuItem);
159 if(RemoveFromList)
160 {
161 /* FIXME - Remove from List */
162 MenuObject->MenuInfo.MenuItemCount--;
163 }
164 if(bRecurse && MenuItem->hSubMenu)
165 {
166 PMENU_OBJECT SubMenuObject;
167 SubMenuObject = IntGetMenuObject(MenuItem->hSubMenu );
168 if(SubMenuObject)
169 {
170 IntDestroyMenuObject(SubMenuObject, bRecurse, TRUE);
171 IntReleaseMenuObject(SubMenuObject);
172 }
173 }
174
175 /* Free memory */
176 ExFreePool(MenuItem);
177
178 return TRUE;
179 }
180
181 BOOL FASTCALL
182 IntRemoveMenuItem(PMENU_OBJECT MenuObject, UINT uPosition, UINT uFlags,
183 BOOL bRecurse)
184 {
185 PMENU_ITEM PrevMenuItem, MenuItem;
186 if(IntGetMenuItemByFlag(MenuObject, uPosition, uFlags, &MenuItem,
187 &PrevMenuItem) > -1)
188 {
189 if(MenuItem)
190 {
191 if(PrevMenuItem)
192 PrevMenuItem->Next = MenuItem->Next;
193 else
194 {
195 MenuObject->MenuItemList = MenuItem->Next;
196 }
197 return IntFreeMenuItem(MenuObject, MenuItem, TRUE, bRecurse);
198 }
199 }
200 return FALSE;
201 }
202
203 UINT FASTCALL
204 IntDeleteMenuItems(PMENU_OBJECT MenuObject, BOOL bRecurse)
205 {
206 UINT res = 0;
207 PMENU_ITEM NextItem;
208 PMENU_ITEM CurItem = MenuObject->MenuItemList;
209 while(CurItem)
210 {
211 NextItem = CurItem->Next;
212 IntFreeMenuItem(MenuObject, CurItem, FALSE, bRecurse);
213 CurItem = NextItem;
214 res++;
215 }
216 MenuObject->MenuInfo.MenuItemCount = 0;
217 MenuObject->MenuItemList = NULL;
218 return res;
219 }
220
221 BOOL FASTCALL
222 IntDestroyMenuObject(PMENU_OBJECT MenuObject,
223 BOOL bRecurse, BOOL RemoveFromProcess)
224 {
225 if(MenuObject)
226 {
227 PWINSTATION_OBJECT WindowStation;
228 NTSTATUS Status;
229
230 /* remove all menu items */
231 IntLockMenuItems(MenuObject);
232 IntDeleteMenuItems(MenuObject, bRecurse); /* do not destroy submenus */
233 IntUnLockMenuItems(MenuObject);
234
235 if(RemoveFromProcess)
236 {
237 IntLockProcessMenus((PW32PROCESS)MenuObject->Process->Win32Process);
238 RemoveEntryList(&MenuObject->ListEntry);
239 IntUnLockProcessMenus((PW32PROCESS)MenuObject->Process->Win32Process);
240 }
241
242 Status = ObReferenceObjectByHandle(MenuObject->Process->Win32WindowStation,
243 0,
244 ExWindowStationObjectType,
245 KernelMode,
246 (PVOID*)&WindowStation,
247 NULL);
248 if(NT_SUCCESS(Status))
249 {
250 ObmCloseHandle(WindowStation->HandleTable, MenuObject->MenuInfo.Self);
251 ObDereferenceObject(WindowStation);
252 return TRUE;
253 }
254 }
255 return FALSE;
256 }
257
258 PMENU_OBJECT FASTCALL
259 IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
260 {
261 PMENU_OBJECT MenuObject;
262 PW32THREAD Win32Thread = PsGetWin32Thread();
263
264 MenuObject = (PMENU_OBJECT)ObmCreateObject(
265 Win32Thread->Desktop->WindowStation->HandleTable, Handle,
266 otMenu, sizeof(MENU_OBJECT));
267
268 if(!MenuObject)
269 {
270 *Handle = 0;
271 return NULL;
272 }
273
274 MenuObject->Process = PsGetCurrentProcess();
275 MenuObject->RtoL = FALSE; /* default */
276 MenuObject->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
277 MenuObject->MenuInfo.fMask = 0; /* not used */
278 MenuObject->MenuInfo.dwStyle = 0; /* FIXME */
279 MenuObject->MenuInfo.cyMax = 0; /* default */
280 MenuObject->MenuInfo.hbrBack =
281 NtGdiCreateSolidBrush(RGB(192, 192, 192)); /* FIXME: default background color */
282 MenuObject->MenuInfo.dwContextHelpID = 0; /* default */
283 MenuObject->MenuInfo.dwMenuData = 0; /* default */
284 MenuObject->MenuInfo.Self = *Handle;
285 MenuObject->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
286 MenuObject->MenuInfo.Flags = (IsMenuBar ? 0 : MF_POPUP);
287 MenuObject->MenuInfo.Wnd = NULL;
288 MenuObject->MenuInfo.WndOwner = NULL;
289 MenuObject->MenuInfo.Height = 0;
290 MenuObject->MenuInfo.Width = 0;
291 MenuObject->MenuInfo.TimeToHide = FALSE;
292
293 MenuObject->MenuInfo.MenuItemCount = 0;
294 MenuObject->MenuItemList = NULL;
295 ExInitializeFastMutex(&MenuObject->MenuItemsLock);
296
297 /* Insert menu item into process menu handle list */
298 IntLockProcessMenus(PsGetWin32Process());
299 InsertTailList(&PsGetWin32Process()->MenuListHead, &MenuObject->ListEntry);
300 IntUnLockProcessMenus(PsGetWin32Process());
301
302 return MenuObject;
303 }
304
305 BOOL FASTCALL
306 IntCloneMenuItems(PMENU_OBJECT Destination, PMENU_OBJECT Source)
307 {
308 PMENU_ITEM MenuItem, NewMenuItem = NULL;
309 PMENU_ITEM Old = NULL;
310
311 if(!Source->MenuInfo.MenuItemCount)
312 return FALSE;
313
314 IntLockMenuItems(Destination);
315 IntLockMenuItems(Source);
316
317 MenuItem = Source->MenuItemList;
318 while(MenuItem)
319 {
320 Old = NewMenuItem;
321 if(NewMenuItem)
322 NewMenuItem->Next = MenuItem;
323 NewMenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
324 if(!NewMenuItem)
325 break;
326 NewMenuItem->fType = MenuItem->fType;
327 NewMenuItem->fState = MenuItem->fState;
328 NewMenuItem->wID = MenuItem->wID;
329 NewMenuItem->hSubMenu = MenuItem->hSubMenu;
330 NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
331 NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
332 NewMenuItem->dwItemData = MenuItem->dwItemData;
333 if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING))
334 {
335 if(MenuItem->Text.Length)
336 {
337 NewMenuItem->Text.Length = 0;
338 NewMenuItem->Text.MaximumLength = MenuItem->Text.MaximumLength;
339 NewMenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, MenuItem->Text.MaximumLength, TAG_STRING);
340 if(!NewMenuItem->Text.Buffer)
341 {
342 ExFreePool(NewMenuItem);
343 break;
344 }
345 RtlCopyUnicodeString(&NewMenuItem->Text, &MenuItem->Text);
346 }
347 else
348 {
349 NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
350 }
351 }
352 else
353 {
354 NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
355 }
356 NewMenuItem->hbmpItem = MenuItem->hbmpItem;
357
358 NewMenuItem->Next = NULL;
359 if(Old)
360 Old->Next = NewMenuItem;
361 else
362 Destination->MenuItemList = NewMenuItem;
363 Destination->MenuInfo.MenuItemCount++;
364 MenuItem = MenuItem->Next;
365 }
366
367 IntUnLockMenuItems(Source);
368 IntUnLockMenuItems(Destination);
369 return TRUE;
370 }
371
372 PMENU_OBJECT FASTCALL
373 IntCloneMenu(PMENU_OBJECT Source)
374 {
375 HANDLE Handle;
376 PMENU_OBJECT MenuObject;
377
378 if(!Source)
379 return NULL;
380
381 MenuObject = (PMENU_OBJECT)ObmCreateObject(
382 PsGetWin32Thread()->Desktop->WindowStation->HandleTable, &Handle,
383 otMenu, sizeof(MENU_OBJECT));
384 if(!MenuObject)
385 return NULL;
386
387 MenuObject->Process = PsGetCurrentProcess();
388 MenuObject->RtoL = Source->RtoL;
389 MenuObject->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
390 MenuObject->MenuInfo.fMask = Source->MenuInfo.fMask;
391 MenuObject->MenuInfo.dwStyle = Source->MenuInfo.dwStyle;
392 MenuObject->MenuInfo.cyMax = Source->MenuInfo.cyMax;
393 MenuObject->MenuInfo.hbrBack = Source->MenuInfo.hbrBack;
394 MenuObject->MenuInfo.dwContextHelpID = Source->MenuInfo.dwContextHelpID;
395 MenuObject->MenuInfo.dwMenuData = Source->MenuInfo.dwMenuData;
396 MenuObject->MenuInfo.Self = Handle;
397 MenuObject->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
398 MenuObject->MenuInfo.Wnd = NULL;
399 MenuObject->MenuInfo.WndOwner = NULL;
400 MenuObject->MenuInfo.Height = 0;
401 MenuObject->MenuInfo.Width = 0;
402 MenuObject->MenuInfo.TimeToHide = FALSE;
403
404 MenuObject->MenuInfo.MenuItemCount = 0;
405 MenuObject->MenuItemList = NULL;
406 ExInitializeFastMutex(&MenuObject->MenuItemsLock);
407
408 /* Insert menu item into process menu handle list */
409 IntLockProcessMenus(PsGetWin32Process());
410 InsertTailList(&PsGetWin32Process()->MenuListHead, &MenuObject->ListEntry);
411 IntUnLockProcessMenus(PsGetWin32Process());
412
413 IntCloneMenuItems(MenuObject, Source);
414
415 return MenuObject;
416 }
417
418 BOOL FASTCALL
419 IntSetMenuFlagRtoL(PMENU_OBJECT MenuObject)
420 {
421 MenuObject->RtoL = TRUE;
422 return TRUE;
423 }
424
425 BOOL FASTCALL
426 IntSetMenuContextHelpId(PMENU_OBJECT MenuObject, DWORD dwContextHelpId)
427 {
428 MenuObject->MenuInfo.dwContextHelpID = dwContextHelpId;
429 return TRUE;
430 }
431
432 BOOL FASTCALL
433 IntGetMenuInfo(PMENU_OBJECT MenuObject, PROSMENUINFO lpmi)
434 {
435 if(lpmi->fMask & MIM_BACKGROUND)
436 lpmi->hbrBack = MenuObject->MenuInfo.hbrBack;
437 if(lpmi->fMask & MIM_HELPID)
438 lpmi->dwContextHelpID = MenuObject->MenuInfo.dwContextHelpID;
439 if(lpmi->fMask & MIM_MAXHEIGHT)
440 lpmi->cyMax = MenuObject->MenuInfo.cyMax;
441 if(lpmi->fMask & MIM_MENUDATA)
442 lpmi->dwMenuData = MenuObject->MenuInfo.dwMenuData;
443 if(lpmi->fMask & MIM_STYLE)
444 lpmi->dwStyle = MenuObject->MenuInfo.dwStyle;
445 if (sizeof(MENUINFO) < lpmi->cbSize)
446 {
447 RtlCopyMemory((char *) lpmi + sizeof(MENUINFO),
448 (char *) &MenuObject->MenuInfo + sizeof(MENUINFO),
449 lpmi->cbSize - sizeof(MENUINFO));
450 }
451
452 return TRUE;
453 }
454
455
456 BOOL FASTCALL
457 IntIsMenu(HMENU hMenu)
458 {
459 PMENU_OBJECT Menu;
460
461 if((Menu = IntGetMenuObject(hMenu)))
462 {
463 IntReleaseMenuObject(Menu);
464 return TRUE;
465 }
466 return FALSE;
467 }
468
469
470 BOOL FASTCALL
471 IntSetMenuInfo(PMENU_OBJECT MenuObject, PROSMENUINFO lpmi)
472 {
473 if(lpmi->fMask & MIM_BACKGROUND)
474 MenuObject->MenuInfo.hbrBack = lpmi->hbrBack;
475 if(lpmi->fMask & MIM_HELPID)
476 MenuObject->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID;
477 if(lpmi->fMask & MIM_MAXHEIGHT)
478 MenuObject->MenuInfo.cyMax = lpmi->cyMax;
479 if(lpmi->fMask & MIM_MENUDATA)
480 MenuObject->MenuInfo.dwMenuData = lpmi->dwMenuData;
481 if(lpmi->fMask & MIM_STYLE)
482 MenuObject->MenuInfo.dwStyle = lpmi->dwStyle;
483 if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
484 {
485 /* FIXME */
486 }
487 if (sizeof(MENUINFO) < lpmi->cbSize)
488 {
489 MenuObject->MenuInfo.FocusedItem = lpmi->FocusedItem;
490 MenuObject->MenuInfo.Height = lpmi->Height;
491 MenuObject->MenuInfo.Width = lpmi->Width;
492 MenuObject->MenuInfo.Wnd = lpmi->Wnd;
493 MenuObject->MenuInfo.WndOwner = lpmi->WndOwner;
494 MenuObject->MenuInfo.TimeToHide = lpmi->TimeToHide;
495 }
496
497 return TRUE;
498 }
499
500
501 int FASTCALL
502 IntGetMenuItemByFlag(PMENU_OBJECT MenuObject, UINT uSearchBy, UINT fFlag,
503 PMENU_ITEM *MenuItem, PMENU_ITEM *PrevMenuItem)
504 {
505 PMENU_ITEM PrevItem = NULL;
506 PMENU_ITEM CurItem = MenuObject->MenuItemList;
507 int p;
508 int ret;
509
510 if(MF_BYPOSITION & fFlag)
511 {
512 p = uSearchBy;
513 while(CurItem && (p > 0))
514 {
515 PrevItem = CurItem;
516 CurItem = CurItem->Next;
517 p--;
518 }
519 if(CurItem)
520 {
521 if(MenuItem) *MenuItem = CurItem;
522 if(PrevMenuItem) *PrevMenuItem = PrevItem;
523 }
524 else
525 {
526 if(MenuItem) *MenuItem = NULL;
527 if(PrevMenuItem) *PrevMenuItem = NULL; /* ? */
528 return -1;
529 }
530
531 return uSearchBy - p;
532 }
533 else
534 {
535 p = 0;
536 while(CurItem)
537 {
538 if(CurItem->wID == uSearchBy)
539 {
540 if(MenuItem) *MenuItem = CurItem;
541 if(PrevMenuItem) *PrevMenuItem = PrevItem;
542 return p;
543 }
544 else if (0 != (CurItem->fType & MF_POPUP))
545 {
546 MenuObject = IntGetMenuObject(CurItem->hSubMenu);
547 if (NULL != MenuObject)
548 {
549 ret = IntGetMenuItemByFlag(MenuObject, uSearchBy, fFlag,
550 MenuItem, PrevMenuItem);
551 if (-1 != ret)
552 {
553 IntReleaseMenuObject(MenuObject);
554 return ret;
555 }
556 }
557 IntReleaseMenuObject(MenuObject);
558 }
559 PrevItem = CurItem;
560 CurItem = CurItem->Next;
561 p++;
562 }
563 }
564 return -1;
565 }
566
567
568 int FASTCALL
569 IntInsertMenuItemToList(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, int pos)
570 {
571 PMENU_ITEM CurItem;
572 PMENU_ITEM LastItem = NULL;
573 UINT npos = 0;
574
575 CurItem = MenuObject->MenuItemList;
576 if(pos <= -1)
577 {
578 while(CurItem)
579 {
580 LastItem = CurItem;
581 CurItem = CurItem->Next;
582 npos++;
583 }
584 }
585 else
586 {
587 while(CurItem && (pos > 0))
588 {
589 LastItem = CurItem;
590 CurItem = CurItem->Next;
591 pos--;
592 npos++;
593 }
594 }
595
596 if(CurItem)
597 {
598 if(LastItem)
599 {
600 /* insert the item before CurItem */
601 MenuItem->Next = LastItem->Next;
602 LastItem->Next = MenuItem;
603 }
604 else
605 {
606 /* insert at the beginning */
607 MenuObject->MenuItemList = MenuItem;
608 MenuItem->Next = CurItem;
609 }
610 }
611 else
612 {
613 if(LastItem)
614 {
615 /* append item */
616 LastItem->Next = MenuItem;
617 MenuItem->Next = NULL;
618 }
619 else
620 {
621 /* insert first item */
622 MenuObject->MenuItemList = MenuItem;
623 MenuItem->Next = NULL;
624 }
625 }
626 MenuObject->MenuInfo.MenuItemCount++;
627
628 return npos;
629 }
630
631 BOOL FASTCALL
632 IntGetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
633 {
634 NTSTATUS Status;
635
636 if(lpmii->fMask & MIIM_BITMAP)
637 {
638 lpmii->hbmpItem = MenuItem->hbmpItem;
639 }
640 if(lpmii->fMask & MIIM_CHECKMARKS)
641 {
642 lpmii->hbmpChecked = MenuItem->hbmpChecked;
643 lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked;
644 }
645 if(lpmii->fMask & MIIM_DATA)
646 {
647 lpmii->dwItemData = MenuItem->dwItemData;
648 }
649 if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
650 {
651 lpmii->fType = MenuItem->fType;
652 }
653 if(lpmii->fMask & MIIM_ID)
654 {
655 lpmii->wID = MenuItem->wID;
656 }
657 if(lpmii->fMask & MIIM_STATE)
658 {
659 lpmii->fState = MenuItem->fState;
660 }
661 if(lpmii->fMask & MIIM_SUBMENU)
662 {
663 lpmii->hSubMenu = MenuItem->hSubMenu;
664 }
665 if (lpmii->fMask & (MIIM_STRING | MIIM_TYPE))
666 {
667 if (lpmii->dwTypeData == NULL)
668 {
669 lpmii->cch = MenuItem->Text.Length / sizeof(WCHAR);
670 }
671 else
672 {
673 Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->Text.Buffer,
674 min(lpmii->cch * sizeof(WCHAR),
675 MenuItem->Text.MaximumLength));
676 if (! NT_SUCCESS(Status))
677 {
678 SetLastNtError(Status);
679 return FALSE;
680 }
681 }
682 }
683
684 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
685 {
686 lpmii->Rect = MenuItem->Rect;
687 lpmii->XTab = MenuItem->XTab;
688 }
689
690 return TRUE;
691 }
692
693 BOOL FASTCALL
694 IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
695 {
696 PMENU_OBJECT SubMenuObject;
697
698 if(!MenuItem || !MenuObject || !lpmii)
699 {
700 return FALSE;
701 }
702
703 MenuItem->fType = lpmii->fType;
704
705 if(lpmii->fMask & MIIM_BITMAP)
706 {
707 MenuItem->hbmpItem = lpmii->hbmpItem;
708 }
709 if(lpmii->fMask & MIIM_CHECKMARKS)
710 {
711 MenuItem->hbmpChecked = lpmii->hbmpChecked;
712 MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked;
713 }
714 if(lpmii->fMask & MIIM_DATA)
715 {
716 MenuItem->dwItemData = lpmii->dwItemData;
717 }
718 if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
719 {
720 /*
721 * Delete the menu item type when changing type from
722 * MF_STRING.
723 */
724 if (MenuItem->fType != lpmii->fType &&
725 MENU_ITEM_TYPE(MenuItem->fType) == MF_STRING)
726 {
727 FreeMenuText(MenuItem);
728 RtlInitUnicodeString(&MenuItem->Text, NULL);
729 }
730 MenuItem->fType = lpmii->fType;
731 }
732 if(lpmii->fMask & MIIM_ID)
733 {
734 MenuItem->wID = lpmii->wID;
735 }
736 if(lpmii->fMask & MIIM_STATE)
737 {
738 /* remove MFS_DEFAULT flag from all other menu items if this item
739 has the MFS_DEFAULT state */
740 if(lpmii->fState & MFS_DEFAULT)
741 IntSetMenuDefaultItem(MenuObject, -1, 0);
742 /* update the menu item state flags */
743 UpdateMenuItemState(MenuItem->fState, lpmii->fState);
744 }
745
746 if(lpmii->fMask & MIIM_SUBMENU)
747 {
748 MenuItem->hSubMenu = lpmii->hSubMenu;
749 /* Make sure the submenu is marked as a popup menu */
750 if (MenuItem->hSubMenu)
751 {
752 SubMenuObject = IntGetMenuObject(MenuItem->hSubMenu);
753 if (SubMenuObject != NULL)
754 {
755 SubMenuObject->MenuInfo.Flags |= MF_POPUP;
756 MenuItem->fType |= MF_POPUP;
757 IntReleaseMenuObject(SubMenuObject);
758 }
759 else
760 {
761 MenuItem->fType &= ~MF_POPUP;
762 }
763 }
764 else
765 {
766 MenuItem->fType &= ~MF_POPUP;
767 }
768 }
769 if ((lpmii->fMask & (MIIM_TYPE | MIIM_STRING)) &&
770 (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))
771 {
772 FreeMenuText(MenuItem);
773
774 if(lpmii->dwTypeData && lpmii->cch)
775 {
776 UNICODE_STRING Source;
777
778 Source.Length =
779 Source.MaximumLength = lpmii->cch * sizeof(WCHAR);
780 Source.Buffer = lpmii->dwTypeData;
781
782 MenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(
783 PagedPool, Source.Length + sizeof(WCHAR), TAG_STRING);
784 if(MenuItem->Text.Buffer != NULL)
785 {
786 MenuItem->Text.Length = 0;
787 MenuItem->Text.MaximumLength = Source.Length + sizeof(WCHAR);
788 RtlCopyUnicodeString(&MenuItem->Text, &Source);
789 MenuItem->Text.Buffer[MenuItem->Text.Length / sizeof(WCHAR)] = 0;
790 }
791 else
792 {
793 RtlInitUnicodeString(&MenuItem->Text, NULL);
794 }
795 }
796 else
797 {
798 MenuItem->fType |= MF_SEPARATOR;
799 RtlInitUnicodeString(&MenuItem->Text, NULL);
800 }
801 }
802
803 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
804 {
805 MenuItem->Rect = lpmii->Rect;
806 MenuItem->XTab = lpmii->XTab;
807 }
808
809 return TRUE;
810 }
811
812 BOOL FASTCALL
813 IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition,
814 PROSMENUITEMINFO ItemInfo)
815 {
816 int pos = (int)uItem;
817 PMENU_ITEM MenuItem;
818
819 if (MAX_MENU_ITEMS <= MenuObject->MenuInfo.MenuItemCount)
820 {
821 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
822 return FALSE;
823 }
824
825 if (fByPosition)
826 {
827 /* calculate position */
828 if(MenuObject->MenuInfo.MenuItemCount < pos)
829 {
830 pos = MenuObject->MenuInfo.MenuItemCount;
831 }
832 }
833 else
834 {
835 pos = IntGetMenuItemByFlag(MenuObject, uItem, MF_BYCOMMAND, NULL, NULL);
836 }
837 if (pos < -1)
838 {
839 pos = -1;
840 }
841
842 MenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
843 if (NULL == MenuItem)
844 {
845 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
846 return FALSE;
847 }
848
849 MenuItem->fType = MFT_STRING;
850 MenuItem->fState = MFS_ENABLED | MFS_UNCHECKED;
851 MenuItem->wID = 0;
852 MenuItem->hSubMenu = (HMENU)0;
853 MenuItem->hbmpChecked = (HBITMAP)0;
854 MenuItem->hbmpUnchecked = (HBITMAP)0;
855 MenuItem->dwItemData = 0;
856 RtlInitUnicodeString(&MenuItem->Text, NULL);
857 MenuItem->hbmpItem = (HBITMAP)0;
858
859 if (! IntSetMenuItemInfo(MenuObject, MenuItem, ItemInfo))
860 {
861 ExFreePool(MenuItem);
862 return FALSE;
863 }
864
865 /* Force size recalculation! */
866 MenuObject->MenuInfo.Height = 0;
867
868 pos = IntInsertMenuItemToList(MenuObject, MenuItem, pos);
869
870 return pos >= 0;
871 }
872
873 UINT FASTCALL
874 IntEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable)
875 {
876 PMENU_ITEM MenuItem;
877 UINT res = IntGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, &MenuItem, NULL);
878 if(!MenuItem || (res == (UINT)-1))
879 {
880 return (UINT)-1;
881 }
882
883 res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
884
885 if(uEnable & MF_DISABLED)
886 {
887 if(!(MenuItem->fState & MF_DISABLED))
888 MenuItem->fState |= MF_DISABLED;
889 if(uEnable & MF_GRAYED)
890 {
891 if(!(MenuItem->fState & MF_GRAYED))
892 MenuItem->fState |= MF_GRAYED;
893 }
894 }
895 else
896 {
897 if(uEnable & MF_GRAYED)
898 {
899 if(!(MenuItem->fState & MF_GRAYED))
900 MenuItem->fState |= MF_GRAYED;
901 if(!(MenuItem->fState & MF_DISABLED))
902 MenuItem->fState |= MF_DISABLED;
903 }
904 else
905 {
906 if(MenuItem->fState & MF_DISABLED)
907 MenuItem->fState ^= MF_DISABLED;
908 if(MenuItem->fState & MF_GRAYED)
909 MenuItem->fState ^= MF_GRAYED;
910 }
911 }
912
913 return res;
914 }
915
916
917 DWORD FASTCALL
918 IntBuildMenuItemList(PMENU_OBJECT MenuObject, PVOID Buffer, ULONG nMax)
919 {
920 DWORD res = 0;
921 UINT sz;
922 ROSMENUITEMINFO mii;
923 PVOID Buf;
924 PMENU_ITEM CurItem = MenuObject->MenuItemList;
925 PWCHAR StrOut;
926 NTSTATUS Status;
927 WCHAR NulByte;
928
929 if (0 != nMax)
930 {
931 if (nMax < MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO))
932 {
933 return 0;
934 }
935 StrOut = (PWCHAR)((char *) Buffer + MenuObject->MenuInfo.MenuItemCount
936 * sizeof(ROSMENUITEMINFO));
937 nMax -= MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO);
938 sz = sizeof(ROSMENUITEMINFO);
939 Buf = Buffer;
940 mii.cbSize = sizeof(ROSMENUITEMINFO);
941 mii.fMask = 0;
942 NulByte = L'\0';
943
944 while (NULL != CurItem)
945 {
946 mii.cch = CurItem->Text.Length / sizeof(WCHAR);
947 mii.dwItemData = CurItem->dwItemData;
948 if (0 != CurItem->Text.Length)
949 {
950 mii.dwTypeData = StrOut;
951 }
952 else
953 {
954 mii.dwTypeData = NULL;
955 }
956 mii.fState = CurItem->fState;
957 mii.fType = CurItem->fType;
958 mii.hbmpChecked = CurItem->hbmpChecked;
959 mii.hbmpItem = CurItem->hbmpItem;
960 mii.hbmpUnchecked = CurItem->hbmpUnchecked;
961 mii.hSubMenu = CurItem->hSubMenu;
962 mii.Rect = CurItem->Rect;
963 mii.XTab = CurItem->XTab;
964
965 Status = MmCopyToCaller(Buf, &mii, sizeof(ROSMENUITEMINFO));
966 if (! NT_SUCCESS(Status))
967 {
968 SetLastNtError(Status);
969 return 0;
970 }
971 Buf += sizeof(ROSMENUITEMINFO);
972
973 if (0 != CurItem->Text.Length
974 && (nMax >= CurItem->Text.Length + sizeof(WCHAR)))
975 {
976 /* copy string */
977 Status = MmCopyToCaller(StrOut, CurItem->Text.Buffer,
978 CurItem->Text.Length);
979 if (! NT_SUCCESS(Status))
980 {
981 SetLastNtError(Status);
982 return 0;
983 }
984 StrOut += CurItem->Text.Length / sizeof(WCHAR);
985 Status = MmCopyToCaller(StrOut, &NulByte, sizeof(WCHAR));
986 if (! NT_SUCCESS(Status))
987 {
988 SetLastNtError(Status);
989 return 0;
990 }
991 StrOut++;
992 nMax -= CurItem->Text.Length + sizeof(WCHAR);
993 }
994 else if (0 != CurItem->Text.Length)
995 {
996 break;
997 }
998
999 CurItem = CurItem->Next;
1000 res++;
1001 }
1002 }
1003 else
1004 {
1005 while (NULL != CurItem)
1006 {
1007 res += sizeof(ROSMENUITEMINFO) + CurItem->Text.Length + sizeof(WCHAR);
1008 CurItem = CurItem->Next;
1009 }
1010 }
1011
1012 return res;
1013 }
1014
1015
1016 DWORD FASTCALL
1017 IntCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck)
1018 {
1019 PMENU_ITEM MenuItem;
1020 int res = -1;
1021
1022 if((IntGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, &MenuItem, NULL) < 0) || !MenuItem)
1023 {
1024 return -1;
1025 }
1026
1027 res = (DWORD)(MenuItem->fState & MF_CHECKED);
1028 if(uCheck & MF_CHECKED)
1029 {
1030 if(!(MenuItem->fState & MF_CHECKED))
1031 MenuItem->fState |= MF_CHECKED;
1032 }
1033 else
1034 {
1035 if(MenuItem->fState & MF_CHECKED)
1036 MenuItem->fState ^= MF_CHECKED;
1037 }
1038
1039 return (DWORD)res;
1040 }
1041
1042 BOOL FASTCALL
1043 IntHiliteMenuItem(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject,
1044 UINT uItemHilite, UINT uHilite)
1045 {
1046 PMENU_ITEM MenuItem;
1047 BOOL res = IntGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, &MenuItem, NULL);
1048 if(!MenuItem || !res)
1049 {
1050 return FALSE;
1051 }
1052
1053 if(uHilite & MF_HILITE)
1054 {
1055 if(!(MenuItem->fState & MF_HILITE))
1056 MenuItem->fState |= MF_HILITE;
1057 }
1058 else
1059 {
1060 if(MenuItem->fState & MF_HILITE)
1061 MenuItem->fState ^= MF_HILITE;
1062 }
1063
1064 /* FIXME - update the window's menu */
1065
1066 return TRUE;
1067 }
1068
1069 BOOL FASTCALL
1070 IntSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
1071 {
1072 BOOL ret = FALSE;
1073 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1074
1075 if(uItem == (UINT)-1)
1076 {
1077 while(MenuItem)
1078 {
1079 if(MenuItem->fState & MFS_DEFAULT)
1080 MenuItem->fState ^= MFS_DEFAULT;
1081 MenuItem = MenuItem->Next;
1082 }
1083 return TRUE;
1084 }
1085
1086 if(fByPos)
1087 {
1088 UINT pos = 0;
1089 while(MenuItem)
1090 {
1091 if(pos == uItem)
1092 {
1093 if(!(MenuItem->fState & MFS_DEFAULT))
1094 MenuItem->fState |= MFS_DEFAULT;
1095 ret = TRUE;
1096 }
1097 else
1098 {
1099 if(MenuItem->fState & MFS_DEFAULT)
1100 MenuItem->fState ^= MFS_DEFAULT;
1101 }
1102 pos++;
1103 MenuItem = MenuItem->Next;
1104 }
1105 }
1106 else
1107 {
1108 while(MenuItem)
1109 {
1110 if(!ret && (MenuItem->wID == uItem))
1111 {
1112 if(!(MenuItem->fState & MFS_DEFAULT))
1113 MenuItem->fState |= MFS_DEFAULT;
1114 ret = TRUE;
1115 }
1116 else
1117 {
1118 if(MenuItem->fState & MFS_DEFAULT)
1119 MenuItem->fState ^= MFS_DEFAULT;
1120 }
1121 MenuItem = MenuItem->Next;
1122 }
1123 }
1124 return ret;
1125 }
1126
1127
1128 UINT FASTCALL
1129 IntGetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT fByPos, UINT gmdiFlags,
1130 DWORD *gismc)
1131 {
1132 UINT x = 0;
1133 UINT res = -1;
1134 UINT sres;
1135 PMENU_OBJECT SubMenuObject;
1136 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1137
1138 while(MenuItem)
1139 {
1140 if(MenuItem->fState & MFS_DEFAULT)
1141 {
1142
1143 if(!(gmdiFlags & GMDI_USEDISABLED) && (MenuItem->fState & MFS_DISABLED))
1144 break;
1145
1146 if(fByPos & MF_BYPOSITION)
1147 res = x;
1148 else
1149 res = MenuItem->wID;
1150
1151 if((*gismc < MAX_GOINTOSUBMENU) && (gmdiFlags & GMDI_GOINTOPOPUPS) &&
1152 MenuItem->hSubMenu)
1153 {
1154
1155 SubMenuObject = IntGetMenuObject(MenuItem->hSubMenu);
1156 if(!SubMenuObject || (SubMenuObject == MenuObject))
1157 break;
1158
1159 IntLockMenuItems(SubMenuObject);
1160 IntUnLockMenuItems(MenuObject);
1161
1162 (*gismc)++;
1163 sres = IntGetMenuDefaultItem(SubMenuObject, fByPos, gmdiFlags, gismc);
1164 (*gismc)--;
1165
1166 IntUnLockMenuItems(SubMenuObject);
1167 IntLockMenuItems(MenuObject);
1168 IntReleaseMenuObject(SubMenuObject);
1169
1170 if(sres > (UINT)-1)
1171 res = sres;
1172 }
1173
1174 break;
1175 }
1176
1177 MenuItem = MenuItem->Next;
1178 x++;
1179 }
1180
1181 return res;
1182 }
1183
1184 VOID FASTCALL
1185 IntInitTracking(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject, BOOL Popup,
1186 UINT Flags)
1187 {
1188 /* FIXME - hide caret */
1189
1190 if(!(Flags & TPM_NONOTIFY))
1191 IntSendMessage(WindowObject->Self, WM_SETCURSOR, (WPARAM)WindowObject->Self, HTCAPTION);
1192
1193 /* FIXME - send WM_SETCURSOR message */
1194
1195 if(!(Flags & TPM_NONOTIFY))
1196 IntSendMessage(WindowObject->Self, WM_INITMENU, (WPARAM)MenuObject->MenuInfo.Self, 0);
1197 }
1198
1199 VOID FASTCALL
1200 IntExitTracking(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject, BOOL Popup,
1201 UINT Flags)
1202 {
1203 if(!(Flags & TPM_NONOTIFY))
1204 IntSendMessage(WindowObject->Self, WM_EXITMENULOOP, 0 /* FIXME */, 0);
1205
1206 /* FIXME - Show caret again */
1207 }
1208
1209 INT FASTCALL
1210 IntTrackMenu(PMENU_OBJECT MenuObject, PWINDOW_OBJECT WindowObject, INT x, INT y,
1211 RECT lprect)
1212 {
1213 return 0;
1214 }
1215
1216 BOOL FASTCALL
1217 IntTrackPopupMenu(PMENU_OBJECT MenuObject, PWINDOW_OBJECT WindowObject,
1218 UINT Flags, POINT *Pos, UINT MenuPos, RECT *ExcludeRect)
1219 {
1220 IntInitTracking(WindowObject, MenuObject, TRUE, Flags);
1221
1222 IntExitTracking(WindowObject, MenuObject, TRUE, Flags);
1223 return FALSE;
1224 }
1225
1226 BOOL FASTCALL
1227 IntSetMenuItemRect(PMENU_OBJECT MenuObject, UINT Item, BOOL fByPos, RECT *rcRect)
1228 {
1229 PMENU_ITEM mi;
1230 if(IntGetMenuItemByFlag(MenuObject, Item, (fByPos ? MF_BYPOSITION : MF_BYCOMMAND),
1231 &mi, NULL) > -1)
1232 {
1233 mi->Rect = *rcRect;
1234 return TRUE;
1235 }
1236 return FALSE;
1237 }
1238
1239
1240 /*!
1241 * Internal function. Called when the process is destroyed to free the remaining menu handles.
1242 */
1243 BOOL FASTCALL
1244 IntCleanupMenus(struct _EPROCESS *Process, PW32PROCESS Win32Process)
1245 {
1246 PEPROCESS CurrentProcess;
1247 PLIST_ENTRY LastHead = NULL;
1248 PMENU_OBJECT MenuObject;
1249
1250 CurrentProcess = PsGetCurrentProcess();
1251 if (CurrentProcess != Process)
1252 {
1253 KeAttachProcess(EPROCESS_TO_KPROCESS(Process));
1254 }
1255
1256 IntLockProcessMenus(Win32Process);
1257 while (Win32Process->MenuListHead.Flink != &(Win32Process->MenuListHead) &&
1258 Win32Process->MenuListHead.Flink != LastHead)
1259 {
1260 LastHead = Win32Process->MenuListHead.Flink;
1261 MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU_OBJECT, ListEntry);
1262
1263 IntUnLockProcessMenus(Win32Process);
1264 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
1265 IntLockProcessMenus(Win32Process);
1266 }
1267 IntUnLockProcessMenus(Win32Process);
1268
1269 if (CurrentProcess != Process)
1270 {
1271 KeDetachProcess();
1272 }
1273 return TRUE;
1274 }
1275
1276 /* FUNCTIONS *****************************************************************/
1277
1278
1279 /*
1280 * @implemented
1281 */
1282 DWORD
1283 STDCALL
1284 NtUserBuildMenuItemList(
1285 HMENU hMenu,
1286 VOID* Buffer,
1287 ULONG nBufSize,
1288 DWORD Reserved)
1289 {
1290 DWORD res = -1;
1291 PMENU_OBJECT MenuObject = IntGetMenuObject(hMenu);
1292 if(!MenuObject)
1293 {
1294 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1295 return (DWORD)-1;
1296 }
1297
1298 if(Buffer)
1299 {
1300 IntLockMenuItems(MenuObject);
1301 res = IntBuildMenuItemList(MenuObject, Buffer, nBufSize);
1302 IntUnLockMenuItems(MenuObject);
1303 }
1304 else
1305 {
1306 res = MenuObject->MenuInfo.MenuItemCount;
1307 }
1308
1309 IntReleaseMenuObject(MenuObject);
1310
1311 return res;
1312 }
1313
1314
1315 /*
1316 * @implemented
1317 */
1318 DWORD STDCALL
1319 NtUserCheckMenuItem(
1320 HMENU hmenu,
1321 UINT uIDCheckItem,
1322 UINT uCheck)
1323 {
1324 DWORD res = 0;
1325 PMENU_OBJECT MenuObject = IntGetMenuObject(hmenu);
1326 if(!MenuObject)
1327 {
1328 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1329 return (DWORD)-1;
1330 }
1331 IntLockMenuItems(MenuObject);
1332 res = IntCheckMenuItem(MenuObject, uIDCheckItem, uCheck);
1333 IntUnLockMenuItems(MenuObject);
1334 IntReleaseMenuObject(MenuObject);
1335 return res;
1336 }
1337
1338
1339 /*
1340 * @unimplemented
1341 */
1342 HMENU STDCALL
1343 NtUserCreateMenu(BOOL PopupMenu)
1344 {
1345 PWINSTATION_OBJECT WinStaObject;
1346 HANDLE Handle;
1347
1348 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1349 KernelMode,
1350 0,
1351 &WinStaObject);
1352
1353 if (!NT_SUCCESS(Status))
1354 {
1355 DPRINT("Validation of window station handle (0x%X) failed\n",
1356 PsGetCurrentProcess()->Win32WindowStation);
1357 SetLastNtError(Status);
1358 return (HMENU)0;
1359 }
1360
1361 IntCreateMenu(&Handle, !PopupMenu);
1362
1363 ObDereferenceObject(WinStaObject);
1364 return (HMENU)Handle;
1365 }
1366
1367
1368 /*
1369 * @implemented
1370 */
1371 BOOL STDCALL
1372 NtUserDeleteMenu(
1373 HMENU hMenu,
1374 UINT uPosition,
1375 UINT uFlags)
1376 {
1377 BOOL res;
1378 PMENU_OBJECT MenuObject = IntGetMenuObject(hMenu);
1379 if(!MenuObject)
1380 {
1381 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1382 return FALSE;
1383 }
1384
1385 res = IntRemoveMenuItem(MenuObject, uPosition, uFlags, TRUE);
1386 IntReleaseMenuObject(MenuObject);
1387
1388 return res;
1389 }
1390
1391
1392 /*
1393 * @implemented
1394 */
1395 BOOL STDCALL
1396 NtUserDestroyMenu(
1397 HMENU hMenu)
1398 {
1399 BOOL Ret;
1400
1401 PMENU_OBJECT MenuObject = IntGetMenuObject(hMenu);
1402 if(!MenuObject)
1403 {
1404 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1405 return FALSE;
1406 }
1407 if(MenuObject->Process != PsGetCurrentProcess())
1408 {
1409 IntReleaseMenuObject(MenuObject);
1410 SetLastWin32Error(ERROR_ACCESS_DENIED);
1411 return FALSE;
1412 }
1413
1414 Ret = IntDestroyMenuObject(MenuObject, FALSE, TRUE);
1415
1416 IntReleaseMenuObject(MenuObject);
1417 return Ret;
1418 }
1419
1420
1421 /*
1422 * @implemented
1423 */
1424 UINT STDCALL
1425 NtUserEnableMenuItem(
1426 HMENU hMenu,
1427 UINT uIDEnableItem,
1428 UINT uEnable)
1429 {
1430 UINT res = (UINT)-1;
1431 PMENU_OBJECT MenuObject;
1432 MenuObject = IntGetMenuObject(hMenu);
1433 if(!MenuObject)
1434 {
1435 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1436 return res;
1437 }
1438 IntLockMenuItems(MenuObject);
1439 res = IntEnableMenuItem(MenuObject, uIDEnableItem, uEnable);
1440 IntUnLockMenuItems(MenuObject);
1441 IntReleaseMenuObject(MenuObject);
1442
1443 return res;
1444 }
1445
1446
1447 /*
1448 * @implemented
1449 */
1450 DWORD STDCALL
1451 NtUserInsertMenuItem(
1452 HMENU hMenu,
1453 UINT uItem,
1454 BOOL fByPosition,
1455 LPCMENUITEMINFOW UnsafeItemInfo)
1456 {
1457 DWORD Res = 0;
1458 PMENU_OBJECT MenuObject;
1459 NTSTATUS Status;
1460 ROSMENUITEMINFO ItemInfo;
1461
1462 MenuObject = IntGetMenuObject(hMenu);
1463 if(!MenuObject)
1464 {
1465 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1466 return 0;
1467 }
1468
1469 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
1470 if (! NT_SUCCESS(Status))
1471 {
1472 IntReleaseMenuObject(MenuObject);
1473 SetLastNtError(Status);
1474 return FALSE;
1475 }
1476 if (ItemInfo.cbSize != sizeof(MENUITEMINFOW))
1477 {
1478 IntReleaseMenuObject(MenuObject);
1479 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1480 return FALSE;
1481 }
1482
1483 IntLockMenuItems(MenuObject);
1484 Res = IntInsertMenuItem(MenuObject, uItem, fByPosition, &ItemInfo);
1485 IntUnLockMenuItems(MenuObject);
1486 IntReleaseMenuObject(MenuObject);
1487
1488 return Res;
1489 }
1490
1491
1492 /*
1493 * @unimplemented
1494 */
1495 BOOL STDCALL
1496 NtUserEndMenu(VOID)
1497 {
1498 UNIMPLEMENTED
1499
1500 return 0;
1501 }
1502
1503
1504 /*
1505 * @implemented
1506 */
1507 UINT STDCALL
1508 NtUserGetMenuDefaultItem(
1509 HMENU hMenu,
1510 UINT fByPos,
1511 UINT gmdiFlags)
1512 {
1513 PMENU_OBJECT MenuObject;
1514 UINT res = -1;
1515 DWORD gismc = 0;
1516 MenuObject = IntGetMenuObject(hMenu);
1517 if(!MenuObject)
1518 {
1519 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1520 return res;
1521 }
1522 IntLockMenuItems(MenuObject);
1523 res = IntGetMenuDefaultItem(MenuObject, fByPos, gmdiFlags, &gismc);
1524 IntUnLockMenuItems(MenuObject);
1525 IntReleaseMenuObject(MenuObject);
1526 return res;
1527 }
1528
1529
1530 /*
1531 * @unimplemented
1532 */
1533 BOOL STDCALL
1534 NtUserGetMenuBarInfo(
1535 HWND hwnd,
1536 LONG idObject,
1537 LONG idItem,
1538 PMENUBARINFO pmbi)
1539 {
1540 UNIMPLEMENTED
1541
1542 return 0;
1543 }
1544
1545
1546 /*
1547 * @unimplemented
1548 */
1549 UINT STDCALL
1550 NtUserGetMenuIndex(
1551 HMENU hMenu,
1552 UINT wID)
1553 {
1554 UNIMPLEMENTED
1555
1556 return 0;
1557 }
1558
1559
1560 /*
1561 * @unimplemented
1562 */
1563 BOOL STDCALL
1564 NtUserGetMenuItemRect(
1565 HWND hWnd,
1566 HMENU hMenu,
1567 UINT uItem,
1568 LPRECT lprcItem)
1569 {
1570 UNIMPLEMENTED
1571
1572 return 0;
1573 }
1574
1575
1576 /*
1577 * @implemented
1578 */
1579 BOOL STDCALL
1580 NtUserHiliteMenuItem(
1581 HWND hwnd,
1582 HMENU hmenu,
1583 UINT uItemHilite,
1584 UINT uHilite)
1585 {
1586 BOOL res = FALSE;
1587 PMENU_OBJECT MenuObject;
1588 PWINDOW_OBJECT WindowObject = IntGetWindowObject(hwnd);
1589 if(!WindowObject)
1590 {
1591 SetLastWin32Error(ERROR_INVALID_HANDLE);
1592 return res;
1593 }
1594 MenuObject = IntGetMenuObject(hmenu);
1595 if(!MenuObject)
1596 {
1597 IntReleaseWindowObject(WindowObject);
1598 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1599 return res;
1600 }
1601 if(WindowObject->IDMenu == (UINT)hmenu)
1602 {
1603 IntLockMenuItems(MenuObject);
1604 res = IntHiliteMenuItem(WindowObject, MenuObject, uItemHilite, uHilite);
1605 IntUnLockMenuItems(MenuObject);
1606 }
1607 IntReleaseMenuObject(MenuObject);
1608 IntReleaseWindowObject(WindowObject);
1609 return res;
1610 }
1611
1612
1613 /*
1614 * @implemented
1615 */
1616 BOOL
1617 STDCALL
1618 NtUserMenuInfo(
1619 HMENU Menu,
1620 PROSMENUINFO UnsafeMenuInfo,
1621 BOOL SetOrGet)
1622 {
1623 BOOL Res;
1624 PMENU_OBJECT MenuObject;
1625 DWORD Size;
1626 NTSTATUS Status;
1627 ROSMENUINFO MenuInfo;
1628
1629 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
1630 if (! NT_SUCCESS(Status))
1631 {
1632 SetLastNtError(Status);
1633 return FALSE;
1634 }
1635 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
1636 {
1637 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1638 return FALSE;
1639 }
1640 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
1641 if (! NT_SUCCESS(Status))
1642 {
1643 SetLastNtError(Status);
1644 return FALSE;
1645 }
1646
1647 MenuObject = IntGetMenuObject(Menu);
1648 if (NULL == MenuObject)
1649 {
1650 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1651 return FALSE;
1652 }
1653
1654 if(SetOrGet)
1655 {
1656 /* Set MenuInfo */
1657 Res = IntSetMenuInfo(MenuObject, &MenuInfo);
1658 }
1659 else
1660 {
1661 /* Get MenuInfo */
1662 Res = IntGetMenuInfo(MenuObject, &MenuInfo);
1663 if (Res)
1664 {
1665 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
1666 if (! NT_SUCCESS(Status))
1667 {
1668 SetLastNtError(Status);
1669 return FALSE;
1670 }
1671 }
1672 }
1673
1674 IntReleaseMenuObject(MenuObject);
1675
1676 return Res;
1677 }
1678
1679
1680 /*
1681 * @implemented
1682 */
1683 int STDCALL
1684 NtUserMenuItemFromPoint(
1685 HWND Wnd,
1686 HMENU Menu,
1687 DWORD X,
1688 DWORD Y)
1689 {
1690 PMENU_OBJECT MenuObject;
1691 PWINDOW_OBJECT WindowObject = NULL;
1692 PMENU_ITEM mi;
1693 int i;
1694
1695 MenuObject = IntGetMenuObject(Menu);
1696 if (NULL == MenuObject)
1697 {
1698 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1699 return -1;
1700 }
1701
1702 WindowObject = IntGetWindowObject(MenuObject->MenuInfo.Wnd);
1703 if (NULL == WindowObject)
1704 {
1705 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1706 return -1;
1707 }
1708 X -= WindowObject->WindowRect.left;
1709 Y -= WindowObject->WindowRect.top;
1710 IntReleaseWindowObject(WindowObject);
1711
1712 IntLockMenuItems(MenuObject);
1713 mi = MenuObject->MenuItemList;
1714 for (i = 0; NULL != mi; i++)
1715 {
1716 if (InRect(mi->Rect, X, Y))
1717 {
1718 break;
1719 }
1720 mi = mi->Next;
1721 }
1722 IntUnLockMenuItems(MenuObject);
1723
1724 IntReleaseMenuObject(MenuObject);
1725
1726 return (mi ? i : NO_SELECTED_ITEM);
1727 }
1728
1729
1730 /*
1731 * @implemented
1732 */
1733 BOOL
1734 STDCALL
1735 NtUserMenuItemInfo(
1736 HMENU Menu,
1737 UINT Item,
1738 BOOL ByPosition,
1739 PROSMENUITEMINFO UnsafeItemInfo,
1740 BOOL SetOrGet)
1741 {
1742 PMENU_OBJECT MenuObject;
1743 PMENU_ITEM MenuItem;
1744 ROSMENUITEMINFO ItemInfo;
1745 NTSTATUS Status;
1746 UINT Size;
1747 BOOL Ret;
1748
1749 MenuObject = IntGetMenuObject(Menu);
1750 if (NULL == MenuObject)
1751 {
1752 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1753 return FALSE;
1754 }
1755 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
1756 if (! NT_SUCCESS(Status))
1757 {
1758 IntReleaseMenuObject(MenuObject);
1759 SetLastNtError(Status);
1760 return FALSE;
1761 }
1762 if (sizeof(MENUITEMINFOW) != Size
1763 && sizeof(MENUITEMINFOW) - sizeof(HBITMAP) != Size
1764 && sizeof(ROSMENUITEMINFO) != Size)
1765 {
1766 IntReleaseMenuObject(MenuObject);
1767 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1768 return FALSE;
1769 }
1770 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
1771 if (! NT_SUCCESS(Status))
1772 {
1773 IntReleaseMenuObject(MenuObject);
1774 SetLastNtError(Status);
1775 return FALSE;
1776 }
1777 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
1778 set/get hbmpItem */
1779 if (sizeof(MENUITEMINFOW) - sizeof(HBITMAP) == Size
1780 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
1781 {
1782 IntReleaseMenuObject(MenuObject);
1783 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1784 return FALSE;
1785 }
1786
1787 if (IntGetMenuItemByFlag(MenuObject, Item,
1788 (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND),
1789 &MenuItem, NULL) < 0)
1790 {
1791 IntReleaseMenuObject(MenuObject);
1792 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1793 return FALSE;
1794 }
1795
1796 if (SetOrGet)
1797 {
1798 Ret = IntSetMenuItemInfo(MenuObject, MenuItem, &ItemInfo);
1799 }
1800 else
1801 {
1802 Ret = IntGetMenuItemInfo(MenuObject, MenuItem, &ItemInfo);
1803 if (Ret)
1804 {
1805 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
1806 if (! NT_SUCCESS(Status))
1807 {
1808 IntReleaseMenuObject(MenuObject);
1809 SetLastNtError(Status);
1810 return FALSE;
1811 }
1812 }
1813 }
1814
1815 IntReleaseMenuObject(MenuObject);
1816
1817 return Ret;
1818 }
1819
1820
1821 /*
1822 * @implemented
1823 */
1824 BOOL STDCALL
1825 NtUserRemoveMenu(
1826 HMENU hMenu,
1827 UINT uPosition,
1828 UINT uFlags)
1829 {
1830 BOOL res;
1831 PMENU_OBJECT MenuObject = IntGetMenuObject(hMenu);
1832 if(!MenuObject)
1833 {
1834 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1835 return FALSE;
1836 }
1837
1838 res = IntRemoveMenuItem(MenuObject, uPosition, uFlags, FALSE);
1839 IntReleaseMenuObject(MenuObject);
1840
1841 return res;
1842 }
1843
1844
1845 /*
1846 * @implemented
1847 */
1848 BOOL STDCALL
1849 NtUserSetMenuContextHelpId(
1850 HMENU hmenu,
1851 DWORD dwContextHelpId)
1852 {
1853 BOOL res;
1854 PMENU_OBJECT MenuObject = IntGetMenuObject(hmenu);
1855 if(!MenuObject)
1856 {
1857 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1858 return FALSE;
1859 }
1860
1861 res = IntSetMenuContextHelpId(MenuObject, dwContextHelpId);
1862 IntReleaseMenuObject(MenuObject);
1863 return res;
1864 }
1865
1866
1867 /*
1868 * @implemented
1869 */
1870 BOOL STDCALL
1871 NtUserSetMenuDefaultItem(
1872 HMENU hMenu,
1873 UINT uItem,
1874 UINT fByPos)
1875 {
1876 BOOL res = FALSE;
1877 PMENU_OBJECT MenuObject;
1878 MenuObject = IntGetMenuObject(hMenu);
1879 if(!MenuObject)
1880 {
1881 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1882 return FALSE;
1883 }
1884 IntLockMenuItems(MenuObject);
1885 res = IntSetMenuDefaultItem(MenuObject, uItem, fByPos);
1886 IntUnLockMenuItems(MenuObject);
1887 IntReleaseMenuObject(MenuObject);
1888
1889 return res;
1890 }
1891
1892
1893 /*
1894 * @implemented
1895 */
1896 BOOL STDCALL
1897 NtUserSetMenuFlagRtoL(
1898 HMENU hMenu)
1899 {
1900 BOOL res;
1901 PMENU_OBJECT MenuObject = IntGetMenuObject(hMenu);
1902 if(!MenuObject)
1903 {
1904 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1905 return FALSE;
1906 }
1907
1908 res = IntSetMenuFlagRtoL(MenuObject);
1909 IntReleaseMenuObject(MenuObject);
1910 return res;
1911 }
1912
1913
1914 /*
1915 * @unimplemented
1916 */
1917 DWORD STDCALL
1918 NtUserThunkedMenuInfo(
1919 HMENU hMenu,
1920 LPCMENUINFO lpcmi)
1921 {
1922 UNIMPLEMENTED
1923 /* This function seems just to call SetMenuInfo() */
1924 return 0;
1925 }
1926
1927
1928 /*
1929 * @unimplemented
1930 */
1931 DWORD STDCALL
1932 NtUserThunkedMenuItemInfo(
1933 HMENU hMenu,
1934 UINT uItem,
1935 BOOL fByPosition,
1936 BOOL bInsert,
1937 LPMENUITEMINFOW lpmii,
1938 PUNICODE_STRING lpszCaption)
1939 {
1940 UNIMPLEMENTED
1941 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
1942 if bInsert == TRUE call NtUserInsertMenuItem() else NtUserSetMenuItemInfo()
1943 */
1944 return 0;
1945 }
1946
1947
1948 /*
1949 * @implemented
1950 */
1951 BOOL STDCALL
1952 NtUserTrackPopupMenuEx(
1953 HMENU hmenu,
1954 UINT fuFlags,
1955 int x,
1956 int y,
1957 HWND hwnd,
1958 LPTPMPARAMS lptpm)
1959 {
1960 PMENU_OBJECT MenuObject;
1961 PWINDOW_OBJECT WindowObject;
1962 TPMPARAMS Safetpm;
1963 NTSTATUS Status;
1964 POINT Pos;
1965 BOOL Ret;
1966
1967 MenuObject = IntGetMenuObject(hmenu);
1968 if(!MenuObject)
1969 {
1970 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1971 return FALSE;
1972 }
1973
1974 WindowObject = IntGetWindowObject(hwnd);
1975 if(!WindowObject)
1976 {
1977 IntReleaseMenuObject(MenuObject);
1978 SetLastWin32Error(ERROR_INVALID_HANDLE);
1979 return FALSE;
1980 }
1981
1982 if(lptpm)
1983 {
1984 Status = MmCopyFromCaller(&Safetpm, lptpm, sizeof(TPMPARAMS));
1985 if(!NT_SUCCESS(Status))
1986 {
1987 IntReleaseWindowObject(WindowObject);
1988 IntReleaseMenuObject(MenuObject);
1989 SetLastNtError(Status);
1990 return FALSE;
1991 }
1992 if(Safetpm.cbSize != sizeof(TPMPARAMS))
1993 {
1994 IntReleaseWindowObject(WindowObject);
1995 IntReleaseMenuObject(MenuObject);
1996 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1997 return FALSE;
1998 }
1999 }
2000
2001 Pos.x = x;
2002 Pos.y = y;
2003
2004 Ret = IntTrackPopupMenu(MenuObject, WindowObject, fuFlags, &Pos, 0,
2005 (lptpm ? &Safetpm.rcExclude : NULL));
2006
2007 IntReleaseWindowObject(WindowObject);
2008 IntReleaseMenuObject(MenuObject);
2009
2010 return Ret;
2011 }
2012
2013
2014 /* EOF */