
server: implement and user find_menu_item server call
Found this function was a major bottleneck in real-world applications.

Thomas Kho

---

 dlls/user/menu.c               |   64 +++++++++-------------------------------
 include/wine/server_protocol.h |   19 ++++++++++++
 server/menu.c                  |    9 ++++++
 server/protocol.def            |   11 +++++++
 server/request.h               |    2 +
 server/trace.c                 |   17 +++++++++++
 6 files changed, 72 insertions(+), 50 deletions(-)

diff --git a/dlls/user/menu.c b/dlls/user/menu.c
index 6a2f7d7..717e922 100644
--- a/dlls/user/menu.c
+++ b/dlls/user/menu.c
@@ -855,58 +855,22 @@ static UINT  MENU_GetStartOfPrevColumn(
  */
 static UINT MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
 {
-    POPUPMENU tmpmenu;
-    POPUPMENU *menu = &tmpmenu;
-    MENUITEM *fallback = NULL;
-    UINT fallback_pos = ITEM_NOT_FOUND;
-    UINT i;
-
-    if ((*hmenu == (HMENU)0xffff) || (MENU_GetMenu(*hmenu, menu)))
-        return ITEM_NOT_FOUND;
-    if (wFlags & MF_BYPOSITION)
-    {
-	if (*nPos >= menu->nItems) return ITEM_NOT_FOUND;
-	return *nPos;
-    }
-    else
+    NTSTATUS ret;
+    UINT retpos = ITEM_NOT_FOUND;
+    SERVER_START_REQ( find_menu_item )
     {
-        MENUITEM *items;
-        MENUITEM *item;
-        MENU_GetAllMenuItems(*hmenu, &items);
-        item = items;
-	for (i = 0; i < menu->nItems; i++, item++)
-	{
-	    if (item->fType & MF_POPUP)
-	    {
-		HMENU hsubmenu = item->hSubMenu;
-		UINT subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
-		if (subitem != ITEM_NOT_FOUND)
-		{
-		    *hmenu = hsubmenu;
-                    MENU_ReleaseMenuItem(items);
-		    return subitem;
-		}
-		else if (item->wID == *nPos)
-		{
-		    /* fallback to this item if nothing else found */
-		    fallback_pos = i;
-		    fallback = item;
-		}
-	    }
-	    else if (item->wID == *nPos)
-	    {
-		*nPos = i;
-                MENU_ReleaseMenuItem(items);
-		return i;
-	    }
-	}
-        MENU_ReleaseMenuItem(items);
+        req->handle = *hmenu;
+        req->pos = *nPos;
+        req->flags = wFlags;
+        if ((ret = wine_server_call_err( req )))
+            WARN("error hMenu=0x%x, status=%x\n", (unsigned) *hmenu,
+                 (unsigned) ret);
+        *hmenu = reply->handle;
+        *nPos = reply->pos;
+        retpos = reply->retval;
     }
-
-    if (fallback)
-        *nPos = fallback_pos;
-
-    return fallback_pos;
+    SERVER_END_REQ;
+    return retpos;
 }
 
 /***********************************************************************
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 45c725a..ed578d2 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3499,6 +3499,22 @@ #define SET_GLOBAL_PROGMAN_WINDOW  0x02
 #define SET_GLOBAL_TASKMAN_WINDOW  0x04
 
 
+struct find_menu_item_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+    unsigned int   pos;
+    unsigned int   flags;
+};
+struct find_menu_item_reply
+{
+    struct reply_header __header;
+    user_handle_t  handle;
+    unsigned int   pos;
+    unsigned int   retval;
+};
+
+
 struct get_menu_item_info_request
 {
     struct request_header __header;
@@ -4108,6 +4124,7 @@ enum request
     REQ_set_clipboard_info,
     REQ_open_token,
     REQ_set_global_windows,
+    REQ_find_menu_item,
     REQ_get_menu_item_info,
     REQ_set_menu_item_info,
     REQ_insert_menu_item,
@@ -4336,6 +4353,7 @@ union generic_request
     struct set_clipboard_info_request set_clipboard_info_request;
     struct open_token_request open_token_request;
     struct set_global_windows_request set_global_windows_request;
+    struct find_menu_item_request find_menu_item_request;
     struct get_menu_item_info_request get_menu_item_info_request;
     struct set_menu_item_info_request set_menu_item_info_request;
     struct insert_menu_item_request insert_menu_item_request;
@@ -4562,6 +4580,7 @@ union generic_reply
     struct set_clipboard_info_reply set_clipboard_info_reply;
     struct open_token_reply open_token_reply;
     struct set_global_windows_reply set_global_windows_reply;
+    struct find_menu_item_reply find_menu_item_reply;
     struct get_menu_item_info_reply get_menu_item_info_reply;
     struct set_menu_item_info_reply set_menu_item_info_reply;
     struct insert_menu_item_reply insert_menu_item_reply;
diff --git a/server/menu.c b/server/menu.c
index cc0f781..b640b73 100644
--- a/server/menu.c
+++ b/server/menu.c
@@ -285,6 +285,15 @@ static unsigned int insert_item(user_han
 }
 
 
+/* find a menu item */
+DECL_HANDLER(find_menu_item)
+{
+    reply->handle = req->handle;
+    reply->pos = req->pos;
+    reply->retval = find_item(&reply->handle, &reply->pos, req->flags);
+}
+
+
 /* validate the given menu handle and get menu item info */
 DECL_HANDLER(get_menu_item_info)
 {
diff --git a/server/protocol.def b/server/protocol.def
index c5653a0..734f190 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2463,6 +2463,17 @@ #define SET_GLOBAL_SHELL_WINDOWS   0x01 
 #define SET_GLOBAL_PROGMAN_WINDOW  0x02
 #define SET_GLOBAL_TASKMAN_WINDOW  0x04
 
+/* Find menu item */
+@REQ(find_menu_item)
+    user_handle_t  handle;
+    unsigned int   pos;
+    unsigned int   flags;
+@REPLY
+    user_handle_t  handle;
+    unsigned int   pos;
+    unsigned int   retval;
+@END
+
 /* Get menu item info */
 @REQ(get_menu_item_info)
     user_handle_t  handle;
diff --git a/server/request.h b/server/request.h
index 9724d5a..317bb0c 100644
--- a/server/request.h
+++ b/server/request.h
@@ -308,6 +308,7 @@ DECL_HANDLER(set_class_info);
 DECL_HANDLER(set_clipboard_info);
 DECL_HANDLER(open_token);
 DECL_HANDLER(set_global_windows);
+DECL_HANDLER(find_menu_item);
 DECL_HANDLER(get_menu_item_info);
 DECL_HANDLER(set_menu_item_info);
 DECL_HANDLER(insert_menu_item);
@@ -535,6 +536,7 @@ static const req_handler req_handlers[RE
     (req_handler)req_set_clipboard_info,
     (req_handler)req_open_token,
     (req_handler)req_set_global_windows,
+    (req_handler)req_find_menu_item,
     (req_handler)req_get_menu_item_info,
     (req_handler)req_set_menu_item_info,
     (req_handler)req_insert_menu_item,
diff --git a/server/trace.c b/server/trace.c
index 7504c08..d32a922 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3049,6 +3049,20 @@ static void dump_set_global_windows_repl
     fprintf( stderr, " old_taskman_window=%p", req->old_taskman_window );
 }
 
+static void dump_find_menu_item_request( const struct find_menu_item_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " pos=%08x,", req->pos );
+    fprintf( stderr, " flags=%08x", req->flags );
+}
+
+static void dump_find_menu_item_reply( const struct find_menu_item_reply *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " pos=%08x,", req->pos );
+    fprintf( stderr, " retval=%08x", req->retval );
+}
+
 static void dump_get_menu_item_info_request( const struct get_menu_item_info_request *req )
 {
     fprintf( stderr, " handle=%p,", req->handle );
@@ -3601,6 +3615,7 @@ static const dump_func req_dumpers[REQ_N
     (dump_func)dump_set_clipboard_info_request,
     (dump_func)dump_open_token_request,
     (dump_func)dump_set_global_windows_request,
+    (dump_func)dump_find_menu_item_request,
     (dump_func)dump_get_menu_item_info_request,
     (dump_func)dump_set_menu_item_info_request,
     (dump_func)dump_insert_menu_item_request,
@@ -3825,6 +3840,7 @@ static const dump_func reply_dumpers[REQ
     (dump_func)dump_set_clipboard_info_reply,
     (dump_func)dump_open_token_reply,
     (dump_func)dump_set_global_windows_reply,
+    (dump_func)dump_find_menu_item_reply,
     (dump_func)dump_get_menu_item_info_reply,
     (dump_func)0,
     (dump_func)dump_insert_menu_item_reply,
@@ -4049,6 +4065,7 @@ static const char * const req_names[REQ_
     "set_clipboard_info",
     "open_token",
     "set_global_windows",
+    "find_menu_item",
     "get_menu_item_info",
     "set_menu_item_info",
     "insert_menu_item",

