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