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