diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index 47375590e29..ffa131e9d63 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -124,6 +124,7 @@ extern void MENU_TrackMouseMenuBar( HWND hwnd, INT ht, POINT pt ) DECLSPEC_HIDDE extern void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar ) DECLSPEC_HIDDEN; extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) DECLSPEC_HIDDEN; extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN; +extern void free_menu_items( void *ptr ) DECLSPEC_HIDDEN; /* nonclient area */ extern LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip) DECLSPEC_HIDDEN; diff --git a/dlls/user32/defdlg.c b/dlls/user32/defdlg.c index 3c7a8a78855..e330cf6603d 100644 --- a/dlls/user32/defdlg.c +++ b/dlls/user32/defdlg.c @@ -240,7 +240,7 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam, WND *wndPtr; if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont ); - if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu ); + if (dlgInfo->hMenu) NtUserDestroyMenu( dlgInfo->hMenu ); HeapFree( GetProcessHeap(), 0, dlgInfo ); wndPtr = WIN_GetPtr( hwnd ); diff --git a/dlls/user32/dialog.c b/dlls/user32/dialog.c index a3efd5b6742..ea9fae4200a 100644 --- a/dlls/user32/dialog.c +++ b/dlls/user32/dialog.c @@ -639,7 +639,7 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate, if (!hwnd) { if (hUserFont) DeleteObject( hUserFont ); - if (hMenu) DestroyMenu( hMenu ); + if (hMenu) NtUserDestroyMenu( hMenu ); if (disabled_owner) EnableWindow( disabled_owner, TRUE ); return 0; } diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 28d93b98b83..02ed19dffd5 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -3337,7 +3337,7 @@ static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y) if (cmd) EDIT_ContextMenuCommand(es, cmd); - DestroyMenu(menu); + NtUserDestroyMenu(menu); } diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index 19db8382bd0..baabc331ca1 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -887,7 +887,7 @@ static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild ) (UINT_PTR)hSysPopup, (LPSTR)hSysMenuBitmap)) { TRACE("not inserted\n"); - DestroyMenu(hSysPopup); + NtUserDestroyMenu( hSysPopup ); return FALSE; } diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 113e6103cd9..c6fdb01c113 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -59,7 +59,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu); WINE_DECLARE_DEBUG_CHANNEL(accel); /* Menu item structure */ -typedef struct { +typedef struct menu_item { /* ----------- MENUITEMINFO Stuff ----------- */ UINT fType; /* Item type. */ UINT fState; /* Item state. */ @@ -79,32 +79,6 @@ typedef struct { * bitmap */ } MENUITEM; -/* Popup menu structure */ -typedef struct { - struct user_object obj; - WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */ - WORD Width; /* Width of the whole menu */ - WORD Height; /* Height of the whole menu */ - UINT nItems; /* Number of items in the menu */ - HWND hWnd; /* Window containing the menu */ - MENUITEM *items; /* Array of menu items */ - UINT FocusedItem; /* Currently focused item */ - HWND hwndOwner; /* window receiving the messages for ownerdraw */ - BOOL bScrolling; /* Scroll arrows are active */ - UINT nScrollPos; /* Current scroll position */ - UINT nTotalHeight; /* Total height of menu items inside menu */ - RECT items_rect; /* Rectangle within which the items lie. Excludes margins and scroll arrows */ - LONG refcount; - /* ------------ MENUINFO members ------ */ - DWORD dwStyle; /* Extended menu style */ - UINT cyMax; /* max height of the whole menu, 0 is screen height */ - HBRUSH hbrBack; /* brush for menu background */ - DWORD dwContextHelpID; - ULONG_PTR dwMenuData; /* application defined value */ - HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */ - WORD textOffset; /* Offset of text when items have both bitmaps and text */ -} POPUPMENU, *LPPOPUPMENU; - /* internal flags for menu tracking */ #define TF_ENDMENU 0x10000 @@ -477,7 +451,7 @@ static HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu ); return hMenu; } - DestroyMenu( hMenu ); + NtUserDestroyMenu( hMenu ); } ERR("failed to load system menu!\n"); return 0; @@ -2264,7 +2238,7 @@ static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) if (!mii.hSubMenu) return NULL; if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) { - DestroyMenu(mii.hSubMenu); + NtUserDestroyMenu( mii.hSubMenu ); return NULL; } mii.fMask |= MIIM_SUBMENU; @@ -4117,7 +4091,7 @@ BOOL WINAPI DeleteMenu( HMENU hMenu, UINT id, UINT flags ) return FALSE; if (menu->items[pos].fType & MF_POPUP) - DestroyMenu(menu->items[pos].hSubMenu); + NtUserDestroyMenu( menu->items[pos].hSubMenu ); RemoveMenu(menu->obj.handle, pos, flags | MF_BYPOSITION); release_menu_ptr(menu); @@ -4239,53 +4213,22 @@ BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags, */ HMENU WINAPI CreateMenu(void) { - HMENU hMenu; - LPPOPUPMENU menu; - - if (!(menu = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*menu) ))) return 0; - menu->FocusedItem = NO_SELECTED_ITEM; - menu->refcount = 1; - - if (!(hMenu = alloc_user_handle( &menu->obj, NTUSER_OBJ_MENU ))) HeapFree( GetProcessHeap(), 0, menu ); - - TRACE("return %p\n", hMenu ); - - return hMenu; + return UlongToHandle( NtUserCallNoParam( NtUserCreateMenu )); } -/********************************************************************** - * DestroyMenu (USER32.@) - */ -BOOL WINAPI DestroyMenu( HMENU hMenu ) +void free_menu_items( void *ptr ) { - LPPOPUPMENU lppop; + POPUPMENU *menu = ptr; + MENUITEM *item = menu->items; + int i; - TRACE("(%p)\n", hMenu); - - if (!(lppop = free_user_handle( hMenu, NTUSER_OBJ_MENU ))) return FALSE; - if (lppop == OBJ_OTHER_PROCESS) return FALSE; - - /* DestroyMenu should not destroy system menu popup owner */ - if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd) + for (i = menu->nItems; i > 0; i--, item++) { - NtUserDestroyWindow( lppop->hWnd ); - lppop->hWnd = 0; + if (item->fType & MF_POPUP) NtUserDestroyMenu( item->hSubMenu ); + MENU_FreeItemData( item ); } - - if (lppop->items) /* recursively destroy submenus */ - { - int i; - MENUITEM *item = lppop->items; - for (i = lppop->nItems; i > 0; i--, item++) - { - if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu); - MENU_FreeItemData( item ); - } - HeapFree( GetProcessHeap(), 0, lppop->items ); - } - HeapFree( GetProcessHeap(), 0, lppop ); - return TRUE; + HeapFree( GetProcessHeap(), 0, menu->items ); } @@ -4306,7 +4249,7 @@ HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert ) { if (wndPtr->hSysMenu && bRevert) { - DestroyMenu(wndPtr->hSysMenu); + NtUserDestroyMenu( wndPtr->hSysMenu ); wndPtr->hSysMenu = 0; } @@ -4339,7 +4282,7 @@ BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu ) if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP) { - if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu ); + if (wndPtr->hSysMenu) NtUserDestroyMenu( wndPtr->hSysMenu ); wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu ); WIN_ReleasePtr( wndPtr ); return TRUE; @@ -4670,7 +4613,7 @@ HMENU WINAPI LoadMenuIndirectW( LPCVOID template ) if (!(hMenu = CreateMenu())) return 0; if (!MENU_ParseResource( p, hMenu )) { - DestroyMenu( hMenu ); + NtUserDestroyMenu( hMenu ); return 0; } return hMenu; @@ -4680,7 +4623,7 @@ HMENU WINAPI LoadMenuIndirectW( LPCVOID template ) if (!(hMenu = CreateMenu())) return 0; if (!MENUEX_ParseResource( p, hMenu)) { - DestroyMenu( hMenu ); + NtUserDestroyMenu( hMenu ); return 0; } return hMenu; diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 36ec63c21d4..aae124ebdcc 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -159,7 +159,7 @@ @ stdcall DestroyCaret() @ stdcall DestroyCursor(long) @ stdcall DestroyIcon(long) -@ stdcall DestroyMenu(long) +@ stdcall DestroyMenu(long) NtUserDestroyMenu # @ stub DestroyReasons @ stdcall DestroyWindow(long) NtUserDestroyWindow # @ stub DeviceEventWorker diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 8a7b8a578cc..1543ceca207 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -162,7 +162,6 @@ static const struct user_callbacks user_funcs = AdjustWindowRectEx, CopyImage, DestroyCaret, - DestroyMenu, EndMenu, HideCaret, PostMessageW, @@ -174,6 +173,7 @@ static const struct user_callbacks user_funcs = SetSystemMenu, ShowCaret, WaitForInputIdle, + free_menu_items, free_win_ptr, MENU_IsMenuActive, notify_ime, diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 77dfc131928..b49afec9bd1 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -39,15 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); static DWORD process_layout = ~0u; -/*********************************************************************** - * alloc_user_handle - */ -HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) -{ - return UlongToHandle( NtUserCallTwoParam( (UINT_PTR)ptr, type, NtUserAllocHandle )); -} - - /*********************************************************************** * get_user_handle_ptr */ @@ -67,15 +58,6 @@ void release_user_handle_ptr( void *ptr ) } -/*********************************************************************** - * free_user_handle - */ -void *free_user_handle( HANDLE handle, unsigned int type ) -{ - return UlongToHandle( NtUserCallTwoParam( HandleToUlong(handle), type, NtUserFreeHandle )); -} - - /******************************************************************* * list_window_children * @@ -672,7 +654,7 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, hwnd = NtUserCreateWindowEx( cs->dwExStyle, &class, NULL, NULL, cs->style, cs->x, cs->y, cs->cx, cs->cy, cs->hwndParent, menu, module, cs->lpCreateParams, 0, &cbtc, 0, !unicode ); - if (!hwnd && menu && menu != cs->hMenu) DestroyMenu( menu ); + if (!hwnd && menu && menu != cs->hMenu) NtUserDestroyMenu( menu ); return hwnd; } diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 6941a578393..b6c63d5d516 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1163,6 +1163,7 @@ static struct unix_funcs unix_funcs = NtUserCreateWindowEx, NtUserDeferWindowPosAndBand, NtUserDestroyCursor, + NtUserDestroyMenu, NtUserDestroyWindow, NtUserDispatchMessage, NtUserDrawIconEx, diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 1889a75b966..6ae55e5cee1 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -27,6 +27,7 @@ #include "ntuser_private.h" #include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(menu); WINE_DECLARE_DEBUG_CHANNEL(accel); /* the accelerator user object */ @@ -37,6 +38,9 @@ struct accelerator ACCEL table[1]; }; +/* (other menu->FocusedItem values give the position of the focused item) */ +#define NO_SELECTED_ITEM 0xffff + /********************************************************************** * NtUserCopyAcceleratorTable (win32u.@) */ @@ -112,12 +116,46 @@ HMENU get_menu( HWND hwnd ) return UlongToHandle( get_window_long( hwnd, GWLP_ID )); } +/* see CreateMenu */ +HMENU create_menu(void) +{ + POPUPMENU *menu; + HMENU handle; + + if (!(menu = calloc( 1, sizeof(*menu) ))) return 0; + menu->FocusedItem = NO_SELECTED_ITEM; + menu->refcount = 1; + + if (!(handle = alloc_user_handle( &menu->obj, NTUSER_OBJ_MENU ))) free( menu ); + + TRACE( "return %p\n", handle ); + return handle; +} + /********************************************************************** * NtUserDestroyMenu (win32u.@) */ -BOOL WINAPI NtUserDestroyMenu( HMENU menu ) +BOOL WINAPI NtUserDestroyMenu( HMENU handle ) { - return user_callbacks && user_callbacks->pDestroyMenu( menu ); + POPUPMENU *menu; + + TRACE( "(%p)\n", handle ); + + if (!(menu = free_user_handle( handle, NTUSER_OBJ_MENU ))) return FALSE; + if (menu == OBJ_OTHER_PROCESS) return FALSE; + + /* DestroyMenu should not destroy system menu popup owner */ + if ((menu->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && menu->hWnd) + { + NtUserDestroyWindow( menu->hWnd ); + menu->hWnd = 0; + } + + if (menu->items && user_callbacks) /* recursively destroy submenus */ + user_callbacks->free_menu_items( menu ); + + free( menu ); + return TRUE; } /******************************************************************* diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 7c03474286d..9427ef498a5 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -33,7 +33,6 @@ struct user_callbacks BOOL (WINAPI *pAdjustWindowRectEx)( RECT *, DWORD, BOOL, DWORD ); HANDLE (WINAPI *pCopyImage)( HANDLE, UINT, INT, INT, UINT ); BOOL (WINAPI *pDestroyCaret)(void); - BOOL (WINAPI *pDestroyMenu)( HMENU ); BOOL (WINAPI *pEndMenu)(void); BOOL (WINAPI *pHideCaret)( HWND hwnd ); BOOL (WINAPI *pPostMessageW)( HWND, UINT, WPARAM, LPARAM ); @@ -45,6 +44,7 @@ struct user_callbacks BOOL (WINAPI *pSetSystemMenu)( HWND hwnd, HMENU menu ); BOOL (WINAPI *pShowCaret)( HWND hwnd ); DWORD (WINAPI *pWaitForInputIdle)( HANDLE, DWORD ); + void (CDECL *free_menu_items)( void *ptr ); void (CDECL *free_win_ptr)( struct tagWND *win ); HWND (CDECL *is_menu_active)(void); void (CDECL *notify_ime)( HWND hwnd, UINT param ); @@ -199,6 +199,35 @@ enum builtin_winprocs NB_BUILTIN_AW_WINPROCS = WINPROC_DESKTOP }; +struct menu_item; + +/* FIXME: make it private to menu.c */ +typedef struct +{ + struct user_object obj; + WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */ + WORD Width; /* Width of the whole menu */ + WORD Height; /* Height of the whole menu */ + UINT nItems; /* Number of items in the menu */ + HWND hWnd; /* Window containing the menu */ + struct menu_item *items; /* Array of menu items */ + UINT FocusedItem; /* Currently focused item */ + HWND hwndOwner; /* window receiving the messages for ownerdraw */ + BOOL bScrolling; /* Scroll arrows are active */ + UINT nScrollPos; /* Current scroll position */ + UINT nTotalHeight; /* Total height of menu items inside menu */ + RECT items_rect; /* Rectangle within which the items lie. Excludes margins and scroll arrows */ + LONG refcount; + /* ------------ MENUINFO members ------ */ + DWORD dwStyle; /* Extended menu style */ + UINT cyMax; /* max height of the whole menu, 0 is screen height */ + HBRUSH hbrBack; /* brush for menu background */ + DWORD dwContextHelpID; + ULONG_PTR dwMenuData; /* application defined value */ + HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */ + WORD textOffset; /* Offset of text when items have both bitmaps and text */ +} POPUPMENU, *LPPOPUPMENU; + /* FIXME: make it private to class.c */ typedef struct tagWINDOWPROC { diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index f22f6604454..e5a3d60f98d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -4623,6 +4623,8 @@ ULONG_PTR WINAPI NtUserCallNoParam( ULONG code ) { switch(code) { + case NtUserCreateMenu: + return HandleToUlong( create_menu() ); case NtUserGetDesktopWindow: return HandleToUlong( get_desktop_window() ); case NtUserGetInputState: @@ -4739,12 +4741,8 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code case NtUserUnhookWindowsHook: return unhook_windows_hook( arg1, (HOOKPROC)arg2 ); /* temporary exports */ - case NtUserAllocHandle: - return HandleToUlong( alloc_user_handle( (struct user_object *)arg1, arg2 )); case NtUserAllocWinProc: return (UINT_PTR)alloc_winproc( (WNDPROC)arg1, arg2 ); - case NtUserFreeHandle: - return (UINT_PTR)free_user_handle( UlongToHandle(arg1), arg2 ); case NtUserGetHandlePtr: return (UINT_PTR)get_user_handle_ptr( UlongToHandle(arg1), arg2 ); default: diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 10ff58acf5b..83901550f3b 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -832,7 +832,7 @@ @ stdcall NtUserDestroyCursor(long long) @ stub NtUserDestroyDCompositionHwndTarget @ stub NtUserDestroyInputContext -@ stub NtUserDestroyMenu +@ stdcall NtUserDestroyMenu(long) @ stub NtUserDestroyPalmRejectionDelayZone @ stdcall NtUserDestroyWindow(long) @ stub NtUserDisableImmersiveOwner diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 61e4ed9876a..e7b7fdf0ee7 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -204,6 +204,7 @@ struct unix_funcs INT x, INT y, INT cx, INT cy, UINT flags, UINT unk1, UINT unk2 ); BOOL (WINAPI *pNtUserDestroyCursor)( HCURSOR cursor, ULONG arg ); + BOOL (WINAPI *pNtUserDestroyMenu)( HMENU handle ); BOOL (WINAPI *pNtUserDestroyWindow)( HWND hwnd ); LRESULT (WINAPI *pNtUserDispatchMessage)( const MSG *msg ); BOOL (WINAPI *pNtUserDrawIconEx)( HDC hdc, INT x0, INT y0, HICON icon, INT width, @@ -336,6 +337,7 @@ extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECL extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; /* menu.c */ +extern HMENU create_menu(void) DECLSPEC_HIDDEN; extern HMENU get_menu( HWND hwnd ) DECLSPEC_HIDDEN; /* message.c */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 1f341e266d7..e65557e13ee 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -795,6 +795,12 @@ BOOL WINAPI NtUserDestroyCursor( HCURSOR cursor, ULONG arg ) return unix_funcs->pNtUserDestroyCursor( cursor, arg ); } +BOOL WINAPI NtUserDestroyMenu( HMENU handle ) +{ + if (!unix_funcs) return FALSE; + return unix_funcs->pNtUserDestroyMenu( handle ); +} + BOOL WINAPI NtUserDestroyWindow( HWND hwnd ) { if (!unix_funcs) return FALSE; diff --git a/include/ntuser.h b/include/ntuser.h index da0a8974004..8ba643df7ba 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -121,6 +121,7 @@ struct win_hook_params /* NtUserCallNoParam codes, not compatible with Windows */ enum { + NtUserCreateMenu, NtUserGetDesktopWindow, NtUserGetInputState, NtUserReleaseCapture, @@ -169,9 +170,7 @@ enum NtUserSetIconParam, NtUserUnhookWindowsHook, /* temporary exports */ - NtUserAllocHandle, NtUserAllocWinProc, - NtUserFreeHandle, NtUserGetHandlePtr, };