[PATCH 10/11] server: add calls to get/set menu item info
Thomas Kho
tkho at ucla.edu
Thu Jun 29 15:34:26 CDT 2006
server: add calls to get/set menu item info
Add server calls and modify client menu item abstraction to use these calls
Thomas Kho
---
dlls/user/menu.c | 347 +++++++++++++++++++---------------------
dlls/user/tests/menu.c | 2
include/wine/server_protocol.h | 111 ++++++++++++-
server/menu.c | 303 ++++++++++++++++++++++++++++++++++-
server/protocol.def | 77 ++++++++-
server/request.h | 8 +
server/trace.c | 91 ++++++++++
7 files changed, 723 insertions(+), 216 deletions(-)
diff --git a/dlls/user/menu.c b/dlls/user/menu.c
index 7cfd934..6a2f7d7 100644
--- a/dlls/user/menu.c
+++ b/dlls/user/menu.c
@@ -97,7 +97,6 @@ typedef struct {
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 */
HWND hwndOwner; /* window receiving the messages for ownerdraw */
UINT nTotalHeight; /* Total height of menu items inside menu */
/* ------------ MENUINFO members ------ */
@@ -317,7 +316,6 @@ static NTSTATUS MENU_GetMenu(HMENU hMenu
menu->Height = reply->height;
menu->nItems = reply->nitems;
menu->hWnd = reply->hwnd;
- menu->items = reply->items;
menu->hwndOwner = reply->hwndowner;
menu->nTotalHeight = reply->totalheight;
@@ -351,9 +349,7 @@ static NTSTATUS MENU_UpdateMenu(HMENU hM
req->flags = menu->wFlags;
req->width = menu->Width;
req->height = menu->Height;
- req->nitems = menu->nItems;
req->hwnd = menu->hWnd;
- req->items = menu->items;
req->hwndowner = menu->hwndOwner;
req->totalheight = menu->nTotalHeight;
@@ -374,78 +370,63 @@ static NTSTATUS MENU_UpdateMenu(HMENU hM
}
/***********************************************************************
- * MENU_GetAllMenuItems
+ * MENU_GetMenuItem
*
- * Get a local copy of all menu items for given hMenu
- * TODO: slow, implement reference counting
+ * Get a local copy of menu item for given hMenu
*/
-static NTSTATUS MENU_GetAllMenuItems(HMENU hMenu, MENUITEM **item)
+static NTSTATUS MENU_GetMenuItem(HMENU hMenu, unsigned int pos, MENUITEM **item)
{
- int i;
- unsigned int allocsize;
- char *tmp;
- POPUPMENU menu;
NTSTATUS ret;
- if ((ret = MENU_GetMenu(hMenu, &menu)))
- return ret;
- if (menu.nItems == 0)
- {
- *item = NULL;
- return 0;
- }
- allocsize = sizeof(MENUITEM) * menu.nItems;
- for (i = 0; i < menu.nItems; i++)
- if (menu.items[i].text)
- allocsize += sizeof(WCHAR)*(strlenW(menu.items[i].text)+1);
- if (!(*item = HeapAlloc(GetProcessHeap(), 0, allocsize)))
- return STATUS_NO_MEMORY;
- memcpy(*item, menu.items, sizeof(MENUITEM) * menu.nItems);
+ unsigned int size = sizeof(MENUITEM) + 100; /* should generally be sufficient */
+ unsigned int required_size;
- tmp = (char *) *item + menu.nItems * sizeof(MENUITEM);
- for (i = 0; i < menu.nItems; i++)
+ while (1)
{
- if (menu.items[i].text)
+ *item = HeapAlloc(GetProcessHeap(), 0, size);
+ SERVER_START_REQ( get_menu_item_info )
{
- memcpy(tmp, menu.items[i].text,
- sizeof(WCHAR)*(strlenW(menu.items[i].text)+1));
- (*item)[i].text = (WCHAR *) tmp;
- tmp += sizeof(WCHAR)*(strlenW(menu.items[i].text)+1);
+ req->handle = hMenu;
+ req->pos = pos;
+ wine_server_set_reply(req, (char *) (*item) + sizeof(MENUITEM),
+ size - sizeof(MENUITEM));
+ if ((ret = wine_server_call_err( req )))
+ WARN("error hMenu=0x%x, status=%ld\n", (unsigned) hMenu, ret);
+
+ required_size = reply->required_size;
+
+ (*item)->fType = reply->type;
+ (*item)->fState = reply->state;
+ (*item)->wID = reply->id;
+ (*item)->hSubMenu = reply->submenu;
+ (*item)->hCheckBit = reply->checkbit;
+ (*item)->hUnCheckBit = reply->uncheckbit;
+ (*item)->text = reply->text;
+ (*item)->dwItemData = reply->itemdata;
+ (*item)->dwTypeData = reply->typedata;
+ (*item)->hbmpItem = reply->bmpitem;
+
+ (*item)->rect.left = reply->rect.left;
+ (*item)->rect.right = reply->rect.right;
+ (*item)->rect.top = reply->rect.top;
+ (*item)->rect.bottom = reply->rect.bottom;
+ (*item)->xTab = reply->xTab;
+ (*item)->bmpsize.cx = reply->bmpsize.x;
+ (*item)->bmpsize.cy = reply->bmpsize.y;
}
- }
- return 0;
-}
+ SERVER_END_REQ;
-/***********************************************************************
- * MENU_GetMenuItem
- *
- * Get a local copy of menu item for given hMenu
- */
-static NTSTATUS MENU_GetMenuItem(HMENU hMenu, unsigned int pos, MENUITEM **item)
-{
- unsigned int allocsize;
- POPUPMENU menu;
- NTSTATUS ret;
- if ((ret = MENU_GetMenu(hMenu, &menu)))
- return ret;
- if (pos >= menu.nItems)
- {
- *item = NULL;
- return 0;
- }
- allocsize = sizeof(MENUITEM);
- if (menu.items[pos].text)
- allocsize += sizeof(WCHAR)*(strlenW(menu.items[pos].text)+1);
- if (!(*item = HeapAlloc(GetProcessHeap(), 0, allocsize)))
- return STATUS_NO_MEMORY;
- memcpy(*item, &menu.items[pos], sizeof(MENUITEM));
- if (menu.items[pos].text)
- {
- char *dest = (char *) *item + sizeof(MENUITEM);
- memcpy(dest, menu.items[pos].text,
- sizeof(WCHAR)*(strlenW(menu.items[pos].text)+1));
- (*item)->text = (WCHAR *) dest;
+ if (required_size > size - sizeof(MENUITEM))
+ {
+ HeapFree(GetProcessHeap(), 0, *item);
+ size = required_size + sizeof(MENUITEM);
+ }
+ else
+ break;
}
- return 0;
+
+ if ((*item)->text)
+ (*item)->text = (LPWSTR) ((char *) (*item) + sizeof(MENUITEM));
+ return ret;
}
/***********************************************************************
@@ -456,33 +437,39 @@ static NTSTATUS MENU_GetMenuItem(HMENU h
static NTSTATUS MENU_UpdateMenuItem(HMENU hMenu, unsigned int pos,
MENUITEM *item)
{
- POPUPMENU menu;
NTSTATUS ret;
- LPWSTR oldtext;
- if ((ret = MENU_GetMenu(hMenu, &menu)))
- return ret;
- oldtext = menu.items[pos].text;
- memcpy(&menu.items[pos], item, sizeof(MENUITEM));
- if (!item->text)
- {
- if (oldtext)
- HeapFree(GetProcessHeap(), 0, oldtext);
- return 0;
- }
- if (oldtext && !strcmpW(oldtext, item->text))
+ SERVER_START_REQ( set_menu_item_info )
{
- menu.items[pos].text = oldtext;
- return 0;
+ req->handle = hMenu;
+ req->pos = pos;
+
+ req->type = item->fType;
+ req->state = item->fState;
+ req->id = item->wID;
+ req->submenu = item->hSubMenu;
+ req->checkbit = item->hCheckBit;
+ req->uncheckbit = item->hUnCheckBit;
+ req->text = item->text;
+ req->itemdata = item->dwItemData;
+ req->typedata = item->dwTypeData;
+ req->bmpitem = item->hbmpItem;
+
+ req->rect.left = item->rect.left;
+ req->rect.right = item->rect.right;
+ req->rect.top = item->rect.top;
+ req->rect.bottom = item->rect.bottom;
+ req->xTab = item->xTab;
+ req->bmpsize.x = item->bmpsize.cx;
+ req->bmpsize.y = item->bmpsize.cy;
+
+ if (item->text)
+ wine_server_add_data(req, item->text,
+ (lstrlenW(item->text)+1)*sizeof(WCHAR));
+ if ((ret = wine_server_call_err( req )))
+ WARN("error hMenu=0x%x, status=%ld\n", (unsigned) hMenu, ret);
}
- if (oldtext)
- HeapFree(GetProcessHeap(), 0, oldtext);
- menu.items[pos].text = HeapAlloc(GetProcessHeap(), 0,
- sizeof(WCHAR)*(strlenW(item->text)+1));
- if (!menu.items[pos].text)
- return STATUS_NO_MEMORY;
- memcpy(menu.items[pos].text, item->text,
- sizeof(WCHAR)*(strlenW(item->text)+1));
- return 0;
+ SERVER_END_REQ;
+ return ret;
}
/***********************************************************************
@@ -496,6 +483,69 @@ static NTSTATUS MENU_ReleaseMenuItem(MEN
}
/***********************************************************************
+ * MENU_GetAllMenuItems
+ *
+ * Get a local copy of all menu items for given hMenu
+ */
+static NTSTATUS MENU_GetAllMenuItems(HMENU hMenu, MENUITEM **item)
+{
+ char *data;
+ unsigned int i, size;
+ MENUITEM *tmp, *mi;
+ POPUPMENU menu;
+
+ MENU_GetMenu(hMenu, &menu);
+
+ /* should generally be sufficient */
+ size = (sizeof(MENUITEM) + 20 * sizeof(WCHAR)) * menu.nItems;
+ if ((mi = HeapAlloc(GetProcessHeap(), 0, size)) == NULL)
+ return STATUS_NO_MEMORY;
+ data = (char *) mi + sizeof(MENUITEM) * menu.nItems;
+ for (i = 0; i < menu.nItems; i++)
+ {
+ NTSTATUS ret;
+ if ((ret = MENU_GetMenuItem(hMenu, i, &tmp)))
+ {
+ MENU_ReleaseMenuItem(tmp);
+ return ret;
+ }
+ memcpy(&mi[i], tmp, sizeof(MENUITEM));
+ if (tmp->text)
+ {
+ unsigned int len = (lstrlenW(tmp->text) + 1) * sizeof(WCHAR);
+ if (data + len > (char *) mi + size)
+ {
+ /* copy and make larger */
+ MENUITEM *newitem;
+ newitem = HeapAlloc(GetProcessHeap(), 0, size << 1);
+ if (newitem == NULL)
+ {
+ MENU_ReleaseMenuItem(tmp);
+ return STATUS_NO_MEMORY;
+ }
+ memcpy(newitem, mi, data - (char *) mi);
+ data = (char *) newitem + (data - (char *) mi);
+ HeapFree(GetProcessHeap(), 0, mi);
+ mi = newitem;
+ size = size << 1;
+ }
+ /* keep text locations as offsets in case of resize */
+ mi[i].text = (LPWSTR) (data - (char *) mi);
+ memcpy(data, tmp->text, len);
+ data = (char *) data + len;
+ }
+ MENU_ReleaseMenuItem(tmp);
+ }
+
+ for (i = 0; i < menu.nItems; i++) /* convert offsets to loactions */
+ if (mi[i].text)
+ mi[i].text = (LPWSTR) ((char *) mi + (int) mi[i].text);
+
+ *item = mi;
+ return 0;
+}
+
+/***********************************************************************
* get_win_sys_menu
*
* Get the system menu of a window
@@ -898,15 +948,6 @@ UINT MENU_FindSubMenu( HMENU *hmenu, HME
}
/***********************************************************************
- * MENU_FreeItemData
- */
-static void MENU_FreeItemData( MENUITEM* item )
-{
- /* delete text */
- HeapFree( GetProcessHeap(), 0, item->text );
-}
-
-/***********************************************************************
* MENU_AdjustMenuItemRect
*
* Adjust menu item rectangle according to scrolling state.
@@ -2421,49 +2462,19 @@ static BOOL MENU_SetItemData( HMENU hmen
*/
static UINT MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
{
- MENUITEM *newItems;
- POPUPMENU tmpmenu;
- POPUPMENU *menu = &tmpmenu;
-
- if (MENU_GetMenu(hMenu, menu))
- return ITEM_NOT_FOUND;
-
- /* Find where to insert new item */
-
- if (flags & MF_BYPOSITION) {
- if (pos > menu->nItems)
- pos = menu->nItems;
- } else {
- if (MENU_FindItem( &hMenu, &pos, flags ) == ITEM_NOT_FOUND)
- pos = menu->nItems;
- else {
- if (MENU_GetMenu(hMenu, menu))
- return ITEM_NOT_FOUND;
- }
- }
-
- /* Create new items array */
-
- newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
- if (!newItems)
- {
- WARN("allocation failed\n" );
- return ITEM_NOT_FOUND;
- }
- if (menu->nItems > 0)
+ NTSTATUS ret;
+ UINT itempos = ITEM_NOT_FOUND;
+ SERVER_START_REQ( insert_menu_item )
{
- /* Copy the old array into the new one */
- if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
- if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
- (menu->nItems-pos)*sizeof(MENUITEM) );
- HeapFree( GetProcessHeap(), 0, menu->items );
+ req->handle = hMenu;
+ req->pos = pos;
+ req->flags = flags;
+ if ((ret = wine_server_call_err( req )))
+ WARN("error hMenu=0x%x, status=%ld\n", (unsigned) hMenu, ret);
+ itempos = reply->pos;
}
- menu->items = newItems;
- menu->nItems++;
- memset( &newItems[pos], 0, sizeof(*newItems) );
- menu->Height = 0; /* force size recalculate */
- MENU_UpdateMenu(hMenu, menu, SET_MI_ITEMS|SET_MI_NITEMS|SET_MI_HEIGHT);
- return pos;
+ SERVER_END_REQ;
+ return itempos;
}
@@ -4281,39 +4292,18 @@ BOOL WINAPI AppendMenuW( HMENU hMenu, UI
*/
BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
{
- POPUPMENU tmpmenu;
- LPPOPUPMENU menu = &tmpmenu;
- MENUITEM *item;
- UINT pos;
-
+ NTSTATUS ret;
TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
- if ((pos = MENU_FindItem( &hMenu, &nPos, wFlags )) == ITEM_NOT_FOUND)
- return FALSE;
- if (MENU_GetMenu(hMenu, menu)) return FALSE;
- item = &menu->items[pos];
-
- /* Remove item */
-
- MENU_FreeItemData( item );
-
- if (--menu->nItems == 0)
- {
- HeapFree( GetProcessHeap(), 0, menu->items );
- menu->items = NULL;
- }
- else
+ SERVER_START_REQ( remove_menu_item )
{
- while(nPos < menu->nItems)
- {
- *item = *(item+1);
- item++;
- nPos++;
- }
- menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
- menu->nItems * sizeof(MENUITEM) );
+ req->handle = hMenu;
+ req->pos = nPos;
+ req->flags = wFlags;
+ if ((ret = wine_server_call_err( req )))
+ WARN("error hMenu=0x%x, status=%ld\n", (unsigned) hMenu, ret);
}
- MENU_UpdateMenu(hMenu, menu, SET_MI_NITEMS|SET_MI_ITEMS);
- return TRUE;
+ SERVER_END_REQ;
+ return ret;
}
@@ -4491,18 +4481,6 @@ BOOL WINAPI DestroyMenu( HMENU hMenu )
lppop->hWnd = 0;
}
- 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 );
- }
-
SERVER_START_REQ( destroy_menu )
{
req->handle = hMenu;
@@ -4512,6 +4490,7 @@ BOOL WINAPI DestroyMenu( HMENU hMenu )
}
SERVER_END_REQ;
+ /* Free local data */
index = USER_HANDLE_TO_INDEX(hMenu);
HeapFree( GetProcessHeap(), 0, user_handles[index]);
user_handles[index] = NULL;
@@ -5394,13 +5373,11 @@ UINT WINAPI GetMenuDefaultItem(HMENU hme
BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
const MENUITEMINFOA *lpmii)
{
- MENUITEM *item;
UINT pos;
POPUPMENU menu;
MENUITEMINFOA mii;
pos = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
MENU_GetMenu(hMenu, &menu);
- item = &menu.items[pos];
if( lpmii->cbSize != sizeof( mii) &&
lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
SetLastError( ERROR_INVALID_PARAMETER);
@@ -5422,13 +5399,11 @@ BOOL WINAPI InsertMenuItemA(HMENU hMenu,
BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
const MENUITEMINFOW *lpmii)
{
- MENUITEM *item;
UINT pos;
POPUPMENU menu;
MENUITEMINFOW mii;
pos = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
MENU_GetMenu(hMenu, &menu);
- item = &menu.items[pos];
if( lpmii->cbSize != sizeof( mii) &&
lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
SetLastError( ERROR_INVALID_PARAMETER);
diff --git a/dlls/user/tests/menu.c b/dlls/user/tests/menu.c
index e715ae6..e76d6ad 100644
--- a/dlls/user/tests/menu.c
+++ b/dlls/user/tests/menu.c
@@ -1721,7 +1721,7 @@ static void test_menu_remote_process()
mii.dwTypeData = malloc(++mii.cch);
ok (GetMenuItemInfo(hMenu, 0, TRUE, &mii),
"error=%ld, dwTypeData='%s'\n", GetLastError(), mii.dwTypeData);
- todo_wine ok (mii.dwTypeData && !strcmp(mii.dwTypeData, "&File"),
+ ok (mii.dwTypeData && !strcmp(mii.dwTypeData, "&File"),
"error=%ld, dwTypeData='%s'\n", GetLastError(), mii.dwTypeData);
free(mii.dwTypeData);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 829ebf1..45c725a 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -32,7 +32,7 @@ struct reply_header
struct request_max_size
{
- int pad[21];
+ int pad[22];
};
typedef void *obj_handle_t;
@@ -3499,6 +3499,92 @@ #define SET_GLOBAL_PROGMAN_WINDOW 0x02
#define SET_GLOBAL_TASKMAN_WINDOW 0x04
+struct get_menu_item_info_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int pos;
+};
+struct get_menu_item_info_reply
+{
+ struct reply_header __header;
+ unsigned int required_size;
+
+ unsigned int type;
+ unsigned int state;
+ unsigned int id;
+ user_handle_t submenu;
+ user_handle_t checkbit;
+ user_handle_t uncheckbit;
+ void* text;
+ unsigned long itemdata;
+ void* typedata;
+ user_handle_t bmpitem;
+
+ rectangle_t rect;
+ unsigned int xTab;
+ dimension_t bmpsize;
+
+ /* VARARG(text,unicode_str); */
+};
+
+
+struct set_menu_item_info_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int pos;
+
+ unsigned int type;
+ unsigned int state;
+ unsigned int id;
+ user_handle_t submenu;
+ user_handle_t checkbit;
+ user_handle_t uncheckbit;
+ void* text;
+ unsigned long itemdata;
+ void* typedata;
+ user_handle_t bmpitem;
+
+ rectangle_t rect;
+ unsigned int xTab;
+ dimension_t bmpsize;
+
+ /* VARARG(text,unicode_str); */
+};
+struct set_menu_item_info_reply
+{
+ struct reply_header __header;
+};
+
+
+struct insert_menu_item_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int pos;
+ unsigned int flags;
+};
+struct insert_menu_item_reply
+{
+ struct reply_header __header;
+ unsigned int pos;
+};
+
+
+struct remove_menu_item_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int pos;
+ unsigned int flags;
+};
+struct remove_menu_item_reply
+{
+ struct reply_header __header;
+};
+
+
struct get_menu_info_request
{
struct request_header __header;
@@ -3507,13 +3593,13 @@ struct get_menu_info_request
struct get_menu_info_reply
{
struct reply_header __header;
+ unsigned int nitems;
+
unsigned short flags;
unsigned short magic;
unsigned short width;
unsigned short height;
- unsigned int nitems;
user_handle_t hwnd;
- void* items;
user_handle_t hwndowner;
unsigned int totalheight;
@@ -3537,9 +3623,7 @@ struct set_menu_info_request
unsigned short magic;
unsigned short width;
unsigned short height;
- unsigned int nitems;
user_handle_t hwnd;
- void* items;
user_handle_t hwndowner;
unsigned int totalheight;
@@ -3586,8 +3670,7 @@ #define SET_MI_WIDTH 0x08000000
#define SET_MI_HEIGHT 0x04000000
#define SET_MI_TOTALHEIGHT 0x02000000
#define SET_MI_MAXBMPSIZE 0x01000000
-#define SET_MI_ITEMS 0x00800000
-#define SET_MI_NITEMS 0x00400000
+
struct adjust_token_privileges_request
@@ -4025,6 +4108,10 @@ enum request
REQ_set_clipboard_info,
REQ_open_token,
REQ_set_global_windows,
+ REQ_get_menu_item_info,
+ REQ_set_menu_item_info,
+ REQ_insert_menu_item,
+ REQ_remove_menu_item,
REQ_get_menu_info,
REQ_set_menu_info,
REQ_create_menu,
@@ -4249,6 +4336,10 @@ 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 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;
+ struct remove_menu_item_request remove_menu_item_request;
struct get_menu_info_request get_menu_info_request;
struct set_menu_info_request set_menu_info_request;
struct create_menu_request create_menu_request;
@@ -4471,6 +4562,10 @@ 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 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;
+ struct remove_menu_item_reply remove_menu_item_reply;
struct get_menu_info_reply get_menu_info_reply;
struct set_menu_info_reply set_menu_info_reply;
struct create_menu_reply create_menu_reply;
@@ -4492,6 +4587,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply;
};
-#define SERVER_PROTOCOL_VERSION 239
+#define SERVER_PROTOCOL_VERSION 242
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/menu.c b/server/menu.c
index 9a49a62..cc0f781 100644
--- a/server/menu.c
+++ b/server/menu.c
@@ -37,16 +37,37 @@ #include "request.h"
#include "user.h"
#include "unicode.h"
+/* Menu item structure */
+struct menu_item
+{
+ WCHAR *text; /* Item text. */
+ unsigned int textsize;
+
+ unsigned int type; /* Item type. */
+ unsigned int state; /* Item state. */
+ unsigned int id; /* Item id. */
+ user_handle_t submenu; /* Pop-up menu. */
+ user_handle_t checkbit; /* Bitmap when checked. */
+ user_handle_t uncheckbit; /* Bitmap when unchecked. */
+ unsigned long itemdata; /* Application defined. */
+ WCHAR *typedata; /* depends on fMask */
+ user_handle_t bmpitem; /* bitmap */
+
+ rectangle_t rect; /* Item area (relative to menu window) */
+ unsigned int xTab; /* X position of text after Tab */
+ dimension_t bmpsize; /* size needed for the HBMMENU_CALLBACK bitmap */
+};
+
/* Popup menu structure */
struct menu {
user_handle_t handle;
+ struct menu_item *items;
unsigned short flags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
unsigned short width; /* Width of the whole menu */
unsigned short height; /* Height of the whole menu */
unsigned int nitems; /* Number of items in the menu */
user_handle_t hwnd; /* Window containing the menu */
- void *items; /* Array of menu items */
user_handle_t hwndowner; /* window receiving the messages for ownerdraw */
unsigned int totalheight; /* Total height of menu items inside menu */
@@ -63,6 +84,7 @@ struct menu {
/* (other menu->FocusedItem values give the position of the focused item) */
#define NO_SELECTED_ITEM 0xffff
+#define ITEM_NOT_FOUND 0xffff
/* retrive a pointer to a menu given its handle */
@@ -95,13 +117,280 @@ static struct menu *create_menu()
/* destroy a menu */
-static void destroy_menu(struct menu *menu)
+static void destroy_menu(user_handle_t handle)
{
+ struct menu *menu;
+
+ if (!(menu = get_menu(handle)))
+ return;
+
+ if (menu->items) /* recursively destroy submenus */
+ {
+ int i;
+ struct menu_item *item = menu->items;
+ for (i = menu->nitems; i > 0; i--, item++)
+ {
+ if (item->type & MF_POPUP)
+ destroy_menu(item->submenu);
+ free(item->text);
+ }
+ free(menu->items);
+ }
+
free_user_handle(menu->handle);
free(menu);
}
+/* Find a menu item. Return a pointer on the item, and modifies *hmenu
+ * in case the item was in a sub-menu. */
+static unsigned int find_item(user_handle_t *hmenu, unsigned int *nPos,
+ unsigned int wFlags)
+{
+ struct menu *menu;
+ struct menu_item *fallback = NULL;
+ unsigned int fallback_pos = ITEM_NOT_FOUND;
+ unsigned int i;
+
+ if ((*hmenu == (HMENU)0xffff) || !(menu = get_menu(*hmenu)))
+ return ITEM_NOT_FOUND;
+ if (wFlags & MF_BYPOSITION)
+ {
+ if (*nPos >= menu->nitems) return ITEM_NOT_FOUND;
+ return *nPos;
+ }
+ else
+ {
+ struct menu_item *items;
+ struct menu_item *item;
+ items = menu->items;
+ item = items;
+ for (i = 0; i < menu->nitems; i++, item++)
+ {
+ if (item->type & MF_POPUP)
+ {
+ user_handle_t hsubmenu = item->submenu;
+ unsigned int subitem = find_item( &hsubmenu, nPos, wFlags );
+ if (subitem != ITEM_NOT_FOUND)
+ {
+ *hmenu = hsubmenu;
+ return subitem;
+ }
+ else if (item->id == *nPos)
+ {
+ /* fallback to this item if nothing else found */
+ fallback_pos = i;
+ fallback = item;
+ }
+ }
+ else if (item->id == *nPos)
+ {
+ *nPos = i;
+ return i;
+ }
+ }
+ }
+
+ if (fallback)
+ *nPos = fallback_pos;
+
+ return fallback_pos;
+}
+
+
+unsigned int remove_item(user_handle_t hMenu, unsigned int nPos,
+ unsigned int wFlags)
+{
+ struct menu *menu;
+ struct menu_item *item;
+ unsigned int pos;
+
+ if (!(menu = get_menu(hMenu)))
+ return FALSE;
+
+ if ((pos = find_item( &hMenu, &nPos, wFlags )) == ITEM_NOT_FOUND)
+ return FALSE;
+
+ item = &menu->items[pos];
+
+ free(item->text);
+
+ if (--menu->nitems == 0)
+ {
+ free(menu->items);
+ menu->items = NULL;
+ }
+ else
+ {
+ struct menu_item *newitem = mem_alloc(menu->nitems
+ * sizeof(struct menu_item));
+ memcpy(newitem, menu->items, nPos * sizeof(struct menu_item));
+ memcpy(newitem + nPos, menu->items + nPos + 1,
+ (menu->nitems - nPos) * sizeof(struct menu_item));
+ free(menu->items);
+ menu->items = newitem;
+ }
+ return TRUE;
+}
+
+
+/* Insert (allocate) a new item into a menu. */
+static unsigned int insert_item(user_handle_t handle, unsigned int pos,
+ unsigned int flags)
+{
+ struct menu_item *newItems;
+ struct menu *menu;
+
+ if (!(menu = get_menu(handle)))
+ return ITEM_NOT_FOUND;
+
+ /* Find where to insert new item */
+
+ if (flags & MF_BYPOSITION)
+ {
+ if (pos > menu->nitems)
+ pos = menu->nitems;
+ }
+ else
+ {
+ if (find_item( &handle, &pos, flags ) == ITEM_NOT_FOUND)
+ pos = menu->nitems;
+ else if (!(menu = get_menu(handle)))
+ return ITEM_NOT_FOUND;
+ }
+
+ /* Create new items array */
+
+ newItems = mem_alloc(sizeof(struct menu_item) * (menu->nitems+1));
+ if (!newItems)
+ {
+ set_error( STATUS_NO_MEMORY );
+ return ITEM_NOT_FOUND;
+ }
+ if (menu->nitems > 0)
+ {
+ /* Copy the old array into the new one */
+ if (pos > 0)
+ memcpy( newItems, menu->items, pos * sizeof(struct menu_item) );
+ if (pos < menu->nitems)
+ memcpy( &newItems[pos+1], &menu->items[pos],
+ (menu->nitems-pos)*sizeof(struct menu_item) );
+ free(menu->items);
+ }
+ menu->items = newItems;
+ menu->nitems++;
+ memset( &newItems[pos], 0, sizeof(*newItems) );
+ menu->height = 0; /* force size recalculate */
+ return pos;
+}
+
+
+/* validate the given menu handle and get menu item info */
+DECL_HANDLER(get_menu_item_info)
+{
+ const unsigned int pos = req->pos;
+ struct menu *menu;
+ struct menu_item *item;
+
+ if (!(menu = get_menu(req->handle)) || pos >= menu->nitems)
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ return;
+ }
+
+ item = &menu->items[pos];
+
+ reply->required_size = 0;
+ if (item->textsize > get_reply_max_size())
+ {
+ reply->required_size = item->textsize;
+ return;
+ }
+
+ reply->type = item->type;
+ reply->state = item->state;
+ reply->id = item->id;
+ reply->submenu = item->submenu;
+ reply->checkbit = item->checkbit;
+ reply->uncheckbit = item->uncheckbit;
+ reply->text = (void *) item->textsize;
+ reply->itemdata = item->itemdata;
+ reply->typedata = item->typedata;
+ reply->bmpitem = item->bmpitem;
+
+ reply->rect = item->rect;
+ reply->xTab = item->xTab;
+ reply->bmpsize = item->bmpsize;
+
+ if (item->text)
+ if (!set_reply_data(item->text, item->textsize))
+ {
+ set_error( STATUS_NO_MEMORY );
+ return;
+ }
+}
+
+
+/* validate the given menu handle and set menu item info */
+DECL_HANDLER(set_menu_item_info)
+{
+ const unsigned int pos = req->pos;
+ int text_size;
+ struct menu *menu;
+ struct menu_item *item;
+
+ if (!(menu = get_menu(req->handle)) || pos >= menu->nitems)
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ return;
+ }
+
+ item = &menu->items[pos];
+
+ item->type = req->type;
+ item->state = req->state;
+ item->id = req->id;
+ item->submenu = req->submenu;
+ item->checkbit = req->checkbit;
+ item->uncheckbit = req->uncheckbit;
+ item->itemdata = req->itemdata;
+ item->typedata = req->typedata;
+ item->bmpitem = req->bmpitem;
+
+ item->rect = req->rect;
+ item->xTab = req->xTab;
+ item->bmpsize = req->bmpsize;
+
+ if (item->text)
+ free(item->text);
+
+ text_size = get_req_data_size();
+ if (!text_size)
+ {
+ item->text = NULL;
+ item->textsize = 0;
+ return;
+ }
+ item->text = mem_alloc(text_size);
+ item->textsize = text_size;
+ memcpy(item->text, get_req_data(), text_size);
+}
+
+
+/* insert (allocate) a new item into a menu */
+DECL_HANDLER(insert_menu_item)
+{
+ reply->pos = insert_item(req->handle, req->pos, req->flags);;
+}
+
+
+/* remove a menu item */
+DECL_HANDLER(remove_menu_item)
+{
+ remove_item(req->handle, req->pos, req->flags);;
+}
+
+
/* create a menu */
DECL_HANDLER(create_menu)
{
@@ -117,10 +406,7 @@ DECL_HANDLER(create_menu)
/* destroy a menu */
DECL_HANDLER(destroy_menu)
{
- struct menu *menu = get_menu(req->handle);
-
- if (menu)
- destroy_menu(menu);
+ destroy_menu(req->handle);
}
@@ -137,7 +423,6 @@ DECL_HANDLER(get_menu_info)
reply->height = menu->height;
reply->nitems = menu->nitems;
reply->hwnd = menu->hwnd;
- reply->items = menu->items;
reply->hwndowner = menu->hwndowner;
reply->totalheight = menu->totalheight;
@@ -157,14 +442,12 @@ DECL_HANDLER(set_menu_info)
struct menu *menu;
if (!(menu = get_menu(req->handle)))
- set_error( STATUS_INVALID_HANDLE );
+ return;
if (req->mask & SET_MI_FLAGS) menu->flags = req->flags;
if (req->mask & SET_MI_WIDTH) menu->width = req->width;
if (req->mask & SET_MI_HEIGHT) menu->height = req->height;
- if (req->mask & SET_MI_NITEMS) menu->nitems = req->nitems;
if (req->mask & SET_MI_HWND) menu->hwnd = req->hwnd;
- if (req->mask & SET_MI_ITEMS) menu->items = req->items;
if (req->mask & SET_MI_OWNER) menu->hwndowner = req->hwndowner;
if (req->mask & SET_MI_TOTALHEIGHT) menu->totalheight = req->totalheight;
diff --git a/server/protocol.def b/server/protocol.def
index 7b3fa42..c5653a0 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -48,7 +48,7 @@ struct reply_header
/* this is used to construct the generic_request union */
struct request_max_size
{
- int pad[21]; /* the max request size is 21 ints */
+ int pad[22]; /* the max request size is 22 ints */
};
typedef void *obj_handle_t;
@@ -2463,17 +2463,83 @@ #define SET_GLOBAL_SHELL_WINDOWS 0x01
#define SET_GLOBAL_PROGMAN_WINDOW 0x02
#define SET_GLOBAL_TASKMAN_WINDOW 0x04
+/* Get menu item info */
+ at REQ(get_menu_item_info)
+ user_handle_t handle;
+ unsigned int pos;
+ at REPLY
+ unsigned int required_size;
+
+ unsigned int type;
+ unsigned int state;
+ unsigned int id;
+ user_handle_t submenu;
+ user_handle_t checkbit;
+ user_handle_t uncheckbit;
+ void* text;
+ unsigned long itemdata;
+ void* typedata;
+ user_handle_t bmpitem;
+
+ rectangle_t rect;
+ unsigned int xTab;
+ dimension_t bmpsize;
+
+ VARARG(text,unicode_str);
+ at END
+
+/* Set menu item info */
+ at REQ(set_menu_item_info)
+ user_handle_t handle;
+ unsigned int pos;
+
+ unsigned int type;
+ unsigned int state;
+ unsigned int id;
+ user_handle_t submenu;
+ user_handle_t checkbit;
+ user_handle_t uncheckbit;
+ void* text;
+ unsigned long itemdata;
+ void* typedata;
+ user_handle_t bmpitem;
+
+ rectangle_t rect;
+ unsigned int xTab;
+ dimension_t bmpsize;
+
+ VARARG(text,unicode_str);
+ at REPLY
+ at END
+
+/* Insert menu item */
+ at REQ(insert_menu_item)
+ user_handle_t handle;
+ unsigned int pos;
+ unsigned int flags;
+ at REPLY
+ unsigned int pos;
+ at END
+
+/* Remove menu item */
+ at REQ(remove_menu_item)
+ user_handle_t handle;
+ unsigned int pos;
+ unsigned int flags;
+ at REPLY
+ at END
+
/* Get menu info */
@REQ(get_menu_info)
user_handle_t handle;
@REPLY
+ unsigned int nitems;
+
unsigned short flags;
unsigned short magic;
unsigned short width;
unsigned short height;
- unsigned int nitems;
user_handle_t hwnd;
- void* items;
user_handle_t hwndowner;
unsigned int totalheight;
@@ -2495,9 +2561,7 @@ #define SET_GLOBAL_TASKMAN_WINDOW 0x04
unsigned short magic;
unsigned short width;
unsigned short height;
- unsigned int nitems;
user_handle_t hwnd;
- void* items;
user_handle_t hwndowner;
unsigned int totalheight;
@@ -2531,8 +2595,7 @@ #define SET_MI_WIDTH 0x08000000
#define SET_MI_HEIGHT 0x04000000
#define SET_MI_TOTALHEIGHT 0x02000000
#define SET_MI_MAXBMPSIZE 0x01000000
-#define SET_MI_ITEMS 0x00800000
-#define SET_MI_NITEMS 0x00400000
+/* above are in conjunction with MIIM_*, which has a maximum value of 0x100 */
/* Adjust the privileges held by a token */
@REQ(adjust_token_privileges)
diff --git a/server/request.h b/server/request.h
index 9baa1fd..9724d5a 100644
--- a/server/request.h
+++ b/server/request.h
@@ -308,6 +308,10 @@ DECL_HANDLER(set_class_info);
DECL_HANDLER(set_clipboard_info);
DECL_HANDLER(open_token);
DECL_HANDLER(set_global_windows);
+DECL_HANDLER(get_menu_item_info);
+DECL_HANDLER(set_menu_item_info);
+DECL_HANDLER(insert_menu_item);
+DECL_HANDLER(remove_menu_item);
DECL_HANDLER(get_menu_info);
DECL_HANDLER(set_menu_info);
DECL_HANDLER(create_menu);
@@ -531,6 +535,10 @@ 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_get_menu_item_info,
+ (req_handler)req_set_menu_item_info,
+ (req_handler)req_insert_menu_item,
+ (req_handler)req_remove_menu_item,
(req_handler)req_get_menu_info,
(req_handler)req_set_menu_info,
(req_handler)req_create_menu,
diff --git a/server/trace.c b/server/trace.c
index 4a05044..7504c08 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3049,6 +3049,80 @@ static void dump_set_global_windows_repl
fprintf( stderr, " old_taskman_window=%p", req->old_taskman_window );
}
+static void dump_get_menu_item_info_request( const struct get_menu_item_info_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " pos=%08x", req->pos );
+}
+
+static void dump_get_menu_item_info_reply( const struct get_menu_item_info_reply *req )
+{
+ fprintf( stderr, " required_size=%08x,", req->required_size );
+ fprintf( stderr, " type=%08x,", req->type );
+ fprintf( stderr, " state=%08x,", req->state );
+ fprintf( stderr, " id=%08x,", req->id );
+ fprintf( stderr, " submenu=%p,", req->submenu );
+ fprintf( stderr, " checkbit=%p,", req->checkbit );
+ fprintf( stderr, " uncheckbit=%p,", req->uncheckbit );
+ fprintf( stderr, " text=%p,", req->text );
+ fprintf( stderr, " itemdata=%lx,", req->itemdata );
+ fprintf( stderr, " typedata=%p,", req->typedata );
+ fprintf( stderr, " bmpitem=%p,", req->bmpitem );
+ fprintf( stderr, " rect=" );
+ dump_rectangle( &req->rect );
+ fprintf( stderr, "," );
+ fprintf( stderr, " xTab=%08x,", req->xTab );
+ fprintf( stderr, " bmpsize=" );
+ dump_dimension( &req->bmpsize );
+ fprintf( stderr, "," );
+ fprintf( stderr, " text=" );
+ dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_set_menu_item_info_request( const struct set_menu_item_info_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " pos=%08x,", req->pos );
+ fprintf( stderr, " type=%08x,", req->type );
+ fprintf( stderr, " state=%08x,", req->state );
+ fprintf( stderr, " id=%08x,", req->id );
+ fprintf( stderr, " submenu=%p,", req->submenu );
+ fprintf( stderr, " checkbit=%p,", req->checkbit );
+ fprintf( stderr, " uncheckbit=%p,", req->uncheckbit );
+ fprintf( stderr, " text=%p,", req->text );
+ fprintf( stderr, " itemdata=%lx,", req->itemdata );
+ fprintf( stderr, " typedata=%p,", req->typedata );
+ fprintf( stderr, " bmpitem=%p,", req->bmpitem );
+ fprintf( stderr, " rect=" );
+ dump_rectangle( &req->rect );
+ fprintf( stderr, "," );
+ fprintf( stderr, " xTab=%08x,", req->xTab );
+ fprintf( stderr, " bmpsize=" );
+ dump_dimension( &req->bmpsize );
+ fprintf( stderr, "," );
+ fprintf( stderr, " text=" );
+ dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_insert_menu_item_request( const struct insert_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_insert_menu_item_reply( const struct insert_menu_item_reply *req )
+{
+ fprintf( stderr, " pos=%08x", req->pos );
+}
+
+static void dump_remove_menu_item_request( const struct remove_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_get_menu_info_request( const struct get_menu_info_request *req )
{
fprintf( stderr, " handle=%p", req->handle );
@@ -3056,13 +3130,12 @@ static void dump_get_menu_info_request(
static void dump_get_menu_info_reply( const struct get_menu_info_reply *req )
{
+ fprintf( stderr, " nitems=%08x,", req->nitems );
fprintf( stderr, " flags=%04x,", req->flags );
fprintf( stderr, " magic=%04x,", req->magic );
fprintf( stderr, " width=%04x,", req->width );
fprintf( stderr, " height=%04x,", req->height );
- fprintf( stderr, " nitems=%08x,", req->nitems );
fprintf( stderr, " hwnd=%p,", req->hwnd );
- fprintf( stderr, " items=%p,", req->items );
fprintf( stderr, " hwndowner=%p,", req->hwndowner );
fprintf( stderr, " totalheight=%08x,", req->totalheight );
fprintf( stderr, " style=%lx,", req->style );
@@ -3083,9 +3156,7 @@ static void dump_set_menu_info_request(
fprintf( stderr, " magic=%04x,", req->magic );
fprintf( stderr, " width=%04x,", req->width );
fprintf( stderr, " height=%04x,", req->height );
- fprintf( stderr, " nitems=%08x,", req->nitems );
fprintf( stderr, " hwnd=%p,", req->hwnd );
- fprintf( stderr, " items=%p,", req->items );
fprintf( stderr, " hwndowner=%p,", req->hwndowner );
fprintf( stderr, " totalheight=%08x,", req->totalheight );
fprintf( stderr, " style=%lx,", req->style );
@@ -3530,6 +3601,10 @@ 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_get_menu_item_info_request,
+ (dump_func)dump_set_menu_item_info_request,
+ (dump_func)dump_insert_menu_item_request,
+ (dump_func)dump_remove_menu_item_request,
(dump_func)dump_get_menu_info_request,
(dump_func)dump_set_menu_info_request,
(dump_func)dump_create_menu_request,
@@ -3750,6 +3825,10 @@ 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_get_menu_item_info_reply,
+ (dump_func)0,
+ (dump_func)dump_insert_menu_item_reply,
+ (dump_func)0,
(dump_func)dump_get_menu_info_reply,
(dump_func)0,
(dump_func)dump_create_menu_reply,
@@ -3970,6 +4049,10 @@ static const char * const req_names[REQ_
"set_clipboard_info",
"open_token",
"set_global_windows",
+ "get_menu_item_info",
+ "set_menu_item_info",
+ "insert_menu_item",
+ "remove_menu_item",
"get_menu_info",
"set_menu_info",
"create_menu",
More information about the wine-patches
mailing list