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