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