Rewrote most of SendMessage/PeekMessage. Implemented inter-process messaging. Moved most message routines to dlls/user, and split off 16-bit routines to a separate file.
diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in index eb6f038..5975585 100644 --- a/dlls/user/Makefile.in +++ b/dlls/user/Makefile.in
@@ -18,8 +18,10 @@ display.c \ exticon.c \ lstr.c \ + message.c \ misc.c \ mouse.c \ + msg16.c \ network.c \ resource.c \ text.c \
diff --git a/dlls/user/message.c b/dlls/user/message.c new file mode 100644 index 0000000..13ab74e --- /dev/null +++ b/dlls/user/message.c
@@ -0,0 +1,1814 @@ +/* + * Window messaging support + * + * Copyright 2001 Alexandre Julliard + */ + +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "winnls.h" +#include "wine/unicode.h" +#include "wine/server.h" +#include "queue.h" +#include "input.h" +#include "message.h" +#include "hook.h" +#include "spy.h" +#include "user.h" +#include "win.h" +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(msg); + +#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +#define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK + +#define MAX_PACK_COUNT 4 + +/* description of the data fields that need to be packed along with a sent message */ +struct packed_message +{ + int count; + const void *data[MAX_PACK_COUNT]; + size_t size[MAX_PACK_COUNT]; +}; + +/* info about the message currently being received by the current thread */ +struct received_message_info +{ + enum message_type type; + MSG msg; + UINT flags; /* InSendMessageEx return flags */ +}; + +/* structure to group all parameters for sent messages of the various kinds */ +struct send_message_info +{ + enum message_type type; + HWND hwnd; + UINT msg; + WPARAM wparam; + LPARAM lparam; + UINT flags; /* flags for SendMessageTimeout */ + UINT timeout; /* timeout for SendMessageTimeout */ + SENDASYNCPROC callback; /* callback function for SendMessageCallback */ + ULONG_PTR data; /* callback data */ +}; + + + +/* flag for messages that contain pointers */ +/* 16 messages per entry, messages 0..15 map to bits 0..15 */ + +#define SET(msg) (1 << ((msg) & 15)) + +static const unsigned short message_pointer_flags[] = +{ + /* 0x00 - 0x0f */ + SET(WM_CREATE) | SET(WM_GETTEXT) | SET(WM_SETTEXT), + /* 0x10 - 0x1f */ + SET(WM_WININICHANGE), + /* 0x20 - 0x2f */ + SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM), + /* 0x30 - 0x3f */ + SET(WM_COMPAREITEM), + /* 0x40 - 0x4f */ + SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) | SET(WM_NOTIFY), + /* 0x50 - 0x5f */ + SET(WM_HELP), + /* 0x60 - 0x6f */ + 0, + /* 0x70 - 0x7f */ + SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED), + /* 0x80 - 0x8f */ + SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE), + /* 0x90 - 0x9f */ + 0, + /* 0xa0 - 0xaf */ + 0, + /* 0xb0 - 0xbf */ + SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP), + /* 0xc0 - 0xcf */ + SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS), + /* 0xd0 - 0xdf */ + 0, + /* 0xe0 - 0xef */ + 0, + /* 0xf0 - 0xff */ + 0, + /* 0x100 - 0x10f */ + 0, + /* 0x110 - 0x11f */ + 0, + /* 0x120 - 0x12f */ + 0, + /* 0x130 - 0x13f */ + 0, + /* 0x140 - 0x14f */ + SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_INSERTSTRING) | + SET(CB_FINDSTRING) | SET(CB_SELECTSTRING), + /* 0x150 - 0x15f */ + SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT), + /* 0x160 - 0x16f */ + 0, + /* 0x170 - 0x17f */ + 0, + /* 0x180 - 0x18f */ + SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) | + SET(LB_DIR) | SET(LB_FINDSTRING), + /* 0x190 - 0x19f */ + SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT), + /* 0x1a0 - 0x1af */ + SET(LB_FINDSTRINGEXACT), + /* 0x1b0 - 0x1bf */ + 0, + /* 0x1c0 - 0x1cf */ + 0, + /* 0x1d0 - 0x1df */ + 0, + /* 0x1e0 - 0x1ef */ + 0, + /* 0x1f0 - 0x1ff */ + 0, + /* 0x200 - 0x20f */ + 0, + /* 0x210 - 0x21f */ + 0, + /* 0x220 - 0x22f */ + SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) | + SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE) +}; + +#undef SET + +/* check whether a given message type includes pointers */ +inline static int is_pointer_message( UINT message ) +{ + if (message >= 8*sizeof(message_pointer_flags)) return FALSE; + return (message_pointer_flags[message / 16] & (1 << (message & 15))) != 0; +} + + +/* compute the total size of the packed data */ +inline static size_t get_data_total_size( const struct packed_message *data ) +{ + int i; + size_t total = 0; + for (i = 0; i < data->count; i++) total += data->size[i]; + return total; +} + +/* copy all the data of a packed message into a single dest buffer */ +inline static void copy_all_data( void *dest, const struct packed_message *data ) +{ + int i; + for (i = 0; i < data->count; i++) + { + memcpy( dest, data->data[i], data->size[i] ); + dest = (char *)dest + data->size[i]; + } +} + +/* add a data field to a packed message */ +inline static void push_data( struct packed_message *data, const void *ptr, size_t size ) +{ + data->data[data->count] = ptr; + data->size[data->count] = size; + data->count++; +} + +/* add a string to a packed message */ +inline static void push_string( struct packed_message *data, LPCWSTR str ) +{ + push_data( data, str, (strlenW(str) + 1) * sizeof(WCHAR) ); +} + +/* retrieve a pointer to data from a packed message and increment the buffer pointer */ +inline static void *get_data( void **buffer, size_t size ) +{ + void *ret = *buffer; + *buffer = (char *)*buffer + size; + return ret; +} + +/* make sure that the buffer contains a valid null-terminated Unicode string */ +inline static BOOL check_string( LPCWSTR str, size_t size ) +{ + for (size /= sizeof(WCHAR); size; size--, str++) + if (!*str) return TRUE; + return FALSE; +} + +/* make sure that there is space for 'size' bytes in buffer, growing it if needed */ +inline static void *get_buffer_space( void **buffer, size_t size ) +{ + void *ret; + if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size ))) + HeapFree( GetProcessHeap(), 0, *buffer ); + *buffer = ret; + return ret; +} + +/* retrieve a string pointer from packed data */ +inline static LPWSTR get_string( void **buffer ) +{ + return get_data( buffer, (strlenW( (LPWSTR)*buffer ) + 1) * sizeof(WCHAR) ); +} + +/* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */ +inline static BOOL combobox_has_strings( HWND hwnd ) +{ + DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); + return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS)); +} + +/* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */ +inline static BOOL listbox_has_strings( HWND hwnd ) +{ + DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); + return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS)); +} + +/* check if hwnd is a broadcast magic handle */ +inline static BOOL is_broadcast( HWND hwnd ) +{ + return (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST); +} + + +/*********************************************************************** + * broadcast_message_callback + * + * Helper callback for broadcasting messages. + */ +static BOOL CALLBACK broadcast_message_callback( HWND hwnd, LPARAM lparam ) +{ + struct send_message_info *info = (struct send_message_info *)lparam; + if (!(GetWindowLongW( hwnd, GWL_STYLE ) & (WS_POPUP|WS_CAPTION))) return TRUE; + switch(info->type) + { + case MSG_UNICODE: + SendMessageTimeoutW( hwnd, info->msg, info->wparam, info->lparam, + info->flags, info->timeout, NULL ); + break; + case MSG_ASCII: + SendMessageTimeoutA( hwnd, info->msg, info->wparam, info->lparam, + info->flags, info->timeout, NULL ); + break; + case MSG_NOTIFY: + SendNotifyMessageW( hwnd, info->msg, info->wparam, info->lparam ); + break; + case MSG_CALLBACK: + SendMessageCallbackW( hwnd, info->msg, info->wparam, info->lparam, + info->callback, info->data ); + break; + case MSG_POSTED: + PostMessageW( hwnd, info->msg, info->wparam, info->lparam ); + break; + default: + ERR( "bad type %d\n", info->type ); + break; + } + return TRUE; +} + + +/*********************************************************************** + * map_wparam_AtoW + * + * Convert the wparam of an ASCII message to Unicode. + */ +static WPARAM map_wparam_AtoW( UINT message, WPARAM wparam ) +{ + if (message == WM_CHARTOITEM || + message == EM_SETPASSWORDCHAR || + message == WM_CHAR || + message == WM_DEADCHAR || + message == WM_SYSCHAR || + message == WM_SYSDEADCHAR || + message == WM_MENUCHAR) + { + char ch = LOWORD(wparam); + WCHAR wch; + MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1); + wparam = MAKEWPARAM( wch, HIWORD(wparam) ); + } + return wparam; +} + + +/*********************************************************************** + * map_wparam_WtoA + * + * Convert the wparam of a Unicode message to ASCII. + */ +static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam ) +{ + if (message == WM_CHARTOITEM || + message == EM_SETPASSWORDCHAR || + message == WM_CHAR || + message == WM_DEADCHAR || + message == WM_SYSCHAR || + message == WM_SYSDEADCHAR || + message == WM_MENUCHAR) + { + WCHAR wch = LOWORD(wparam); + char ch; + WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL ); + wparam = MAKEWPARAM( ch, HIWORD(wparam) ); + } + return wparam; +} + + +/*********************************************************************** + * pack_message + * + * Pack a message for sending to another process. + * Return the size of the data we expect in the message reply. + * Set data->count to -1 if there is an error. + */ +static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, + struct packed_message *data ) +{ + data->count = 0; + switch(message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam; + push_data( data, cs, sizeof(*cs) ); + if (HIWORD(cs->lpszName)) push_string( data, cs->lpszName ); + if (HIWORD(cs->lpszClass)) push_string( data, cs->lpszClass ); + return sizeof(*cs); + } + case WM_GETTEXT: + return wparam * sizeof(WCHAR); + case WM_SETTEXT: + case WM_WININICHANGE: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: + case EM_REPLACESEL: + push_string( data, (LPWSTR)lparam ); + return 0; + case WM_GETMINMAXINFO: + push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) ); + return sizeof(MINMAXINFO); + case WM_DRAWITEM: + push_data( data, (DRAWITEMSTRUCT *)lparam, sizeof(DRAWITEMSTRUCT) ); + return 0; + case WM_MEASUREITEM: + push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) ); + return sizeof(MEASUREITEMSTRUCT); + case WM_DELETEITEM: + push_data( data, (DELETEITEMSTRUCT *)lparam, sizeof(DELETEITEMSTRUCT) ); + return 0; + case WM_COMPAREITEM: + push_data( data, (COMPAREITEMSTRUCT *)lparam, sizeof(COMPAREITEMSTRUCT) ); + return 0; + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) ); + return sizeof(WINDOWPOS); + case WM_COPYDATA: + { + COPYDATASTRUCT *cp = (COPYDATASTRUCT *)lparam; + push_data( data, cp, sizeof(*cp) ); + if (cp->lpData) push_data( data, cp->lpData, cp->cbData ); + return 0; + } + case WM_NOTIFY: + /* WM_NOTIFY cannot be sent across processes (MSDN) */ + data->count = -1; + return 0; + case WM_HELP: + push_data( data, (HELPINFO *)lparam, sizeof(HELPINFO) ); + return 0; + case WM_STYLECHANGING: + case WM_STYLECHANGED: + push_data( data, (STYLESTRUCT *)lparam, sizeof(STYLESTRUCT) ); + return 0; + case WM_NCCALCSIZE: + if (!wparam) + { + push_data( data, (RECT *)lparam, sizeof(RECT) ); + return sizeof(RECT); + } + else + { + NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam; + push_data( data, nc, sizeof(*nc) ); + push_data( data, nc->lppos, sizeof(*nc->lppos) ); + return sizeof(*nc) + sizeof(*nc->lppos); + } + case WM_GETDLGCODE: + if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) ); + return sizeof(MSG); + case EM_GETSEL: + { + size_t size = 0; + if (wparam) size += sizeof(DWORD); + if (lparam) size += sizeof(DWORD); + return size; + } + case EM_GETRECT: + case LB_GETITEMRECT: + case CB_GETDROPPEDCONTROLRECT: + return sizeof(RECT); + case EM_SETRECT: + case EM_SETRECTNP: + push_data( data, (RECT *)lparam, sizeof(RECT) ); + return 0; + case EM_GETLINE: + { + WORD *pw = (WORD *)lparam; + push_data( data, pw, sizeof(*pw) ); + return *pw * sizeof(WCHAR); + } + case EM_SETTABSTOPS: + case LB_SETTABSTOPS: + if (wparam) push_data( data, (UINT *)lparam, sizeof(UINT) * wparam ); + return 0; + case CB_ADDSTRING: + case CB_INSERTSTRING: + if (combobox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam ); + return 0; + case CB_GETLBTEXT: + if (!combobox_has_strings( hwnd )) return sizeof(ULONG_PTR); + return (SendMessageW( hwnd, CB_GETLBTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR); + case LB_ADDSTRING: + case LB_INSERTSTRING: + if (listbox_has_strings( hwnd )) push_string( data, (LPWSTR)lparam ); + return 0; + case LB_GETTEXT: + if (!listbox_has_strings( hwnd )) return sizeof(ULONG_PTR); + return (SendMessageW( hwnd, LB_GETTEXTLEN, wparam, 0 ) + 1) * sizeof(WCHAR); + case LB_GETSELITEMS: + return wparam * sizeof(UINT); + case WM_MDICREATE: + { + MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam; + push_data( data, cs, sizeof(*cs) ); + if (HIWORD(cs->szTitle)) push_string( data, cs->szTitle ); + if (HIWORD(cs->szClass)) push_string( data, cs->szClass ); + return sizeof(*cs); + } + case WM_MDIGETACTIVE: + if (lparam) return sizeof(BOOL); + return 0; + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + FIXME("msg %x not supported yet\n",message); + return 0; + } + return 0; +} + + +/*********************************************************************** + * unpack_message + * + * Unpack a message received from another process. + */ +static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, + void **buffer, size_t size ) +{ + size_t minsize = 0; + + switch(message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = *buffer; + WCHAR *str = (WCHAR *)(cs + 1); + if (size < sizeof(*cs)) return FALSE; + size -= sizeof(*cs); + if (HIWORD(cs->lpszName)) + { + if (!check_string( str, size )) return FALSE; + cs->lpszName = str; + size -= (strlenW(str) + 1) * sizeof(WCHAR); + str += strlenW(str) + 1; + } + if (HIWORD(cs->lpszClass)) + { + if (!check_string( str, size )) return FALSE; + cs->lpszClass = str; + } + break; + } + case WM_GETTEXT: + if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE; + break; + case WM_SETTEXT: + case WM_WININICHANGE: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: + case EM_REPLACESEL: + if (!check_string( *buffer, size )) return FALSE; + break; + case WM_GETMINMAXINFO: + minsize = sizeof(MINMAXINFO); + break; + case WM_DRAWITEM: + minsize = sizeof(DRAWITEMSTRUCT); + break; + case WM_MEASUREITEM: + minsize = sizeof(MEASUREITEMSTRUCT); + break; + case WM_DELETEITEM: + minsize = sizeof(DELETEITEMSTRUCT); + break; + case WM_COMPAREITEM: + minsize = sizeof(COMPAREITEMSTRUCT); + break; + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + minsize = sizeof(WINDOWPOS); + break; + case WM_COPYDATA: + { + COPYDATASTRUCT *cp = *buffer; + if (size < sizeof(*cp)) return FALSE; + if (cp->lpData) + { + minsize = sizeof(*cp) + cp->cbData; + cp->lpData = cp + 1; + } + break; + } + case WM_NOTIFY: + /* WM_NOTIFY cannot be sent across processes (MSDN) */ + return FALSE; + case WM_HELP: + minsize = sizeof(HELPINFO); + break; + case WM_STYLECHANGING: + case WM_STYLECHANGED: + minsize = sizeof(STYLESTRUCT); + break; + case WM_NCCALCSIZE: + if (!*wparam) minsize = sizeof(RECT); + else + { + NCCALCSIZE_PARAMS *nc = *buffer; + if (size < sizeof(*nc) + sizeof(*nc->lppos)) return FALSE; + nc->lppos = (WINDOWPOS *)(nc + 1); + } + break; + case WM_GETDLGCODE: + if (!*lparam) return TRUE; + minsize = sizeof(MSG); + break; + case EM_GETSEL: + if (*wparam || *lparam) + { + if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE; + if (*wparam) *wparam = (WPARAM)*buffer; + if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1); + } + return TRUE; + case EM_GETRECT: + case LB_GETITEMRECT: + case CB_GETDROPPEDCONTROLRECT: + if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE; + break; + case EM_SETRECT: + case EM_SETRECTNP: + minsize = sizeof(RECT); + break; + case EM_GETLINE: + { + WORD len; + if (size < sizeof(WORD)) return FALSE; + len = *(WORD *)*buffer; + if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE; + *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */ + return TRUE; + } + case EM_SETTABSTOPS: + case LB_SETTABSTOPS: + if (!*wparam) return TRUE; + minsize = *wparam * sizeof(UINT); + break; + case CB_ADDSTRING: + case CB_INSERTSTRING: + case LB_ADDSTRING: + case LB_INSERTSTRING: + if (!*buffer) return TRUE; + if (!check_string( *buffer, size )) return FALSE; + break; + case CB_GETLBTEXT: + { + size = sizeof(ULONG_PTR); + if (combobox_has_strings( hwnd )) + size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); + if (!get_buffer_space( buffer, size )) return FALSE; + break; + } + case LB_GETTEXT: + { + size = sizeof(ULONG_PTR); + if (listbox_has_strings( hwnd )) + size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); + if (!get_buffer_space( buffer, size )) return FALSE; + break; + } + case LB_GETSELITEMS: + if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE; + break; + case WM_MDICREATE: + { + MDICREATESTRUCTW *cs = *buffer; + WCHAR *str = (WCHAR *)(cs + 1); + if (size < sizeof(*cs)) return FALSE; + size -= sizeof(*cs); + if (HIWORD(cs->szTitle)) + { + if (!check_string( str, size )) return FALSE; + cs->szTitle = str; + size -= (strlenW(str) + 1) * sizeof(WCHAR); + str += strlenW(str) + 1; + } + if (HIWORD(cs->szClass)) + { + if (!check_string( str, size )) return FALSE; + cs->szClass = str; + } + break; + } + case WM_MDIGETACTIVE: + if (!*lparam) return TRUE; + if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE; + break; + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + FIXME("msg %x not supported yet\n",message); + return FALSE; + default: + return TRUE; /* message doesn't need any unpacking */ + } + + /* default exit for most messages: check minsize and store buffer in lparam */ + if (size < minsize) return FALSE; + *lparam = (LPARAM)*buffer; + return TRUE; +} + + +/*********************************************************************** + * pack_reply + * + * Pack a reply to a message for sending to another process. + */ +static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, + LRESULT res, struct packed_message *data ) +{ + data->count = 0; + switch(message) + { + case WM_NCCREATE: + case WM_CREATE: + push_data( data, (CREATESTRUCTW *)lparam, sizeof(CREATESTRUCTW) ); + break; + case WM_GETTEXT: + case CB_GETLBTEXT: + case LB_GETTEXT: + push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) ); + break; + case WM_GETMINMAXINFO: + push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) ); + break; + case WM_MEASUREITEM: + push_data( data, (MEASUREITEMSTRUCT *)lparam, sizeof(MEASUREITEMSTRUCT) ); + break; + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) ); + break; + case WM_GETDLGCODE: + if (lparam) push_data( data, (MSG *)lparam, sizeof(MSG) ); + break; + case EM_GETRECT: + case LB_GETITEMRECT: + case CB_GETDROPPEDCONTROLRECT: + push_data( data, (RECT *)lparam, sizeof(RECT) ); + break; + case EM_GETLINE: + { + WORD *ptr = (WORD *)lparam; + push_data( data, ptr, ptr[-1] * sizeof(WCHAR) ); + break; + } + case LB_GETSELITEMS: + push_data( data, (UINT *)lparam, wparam * sizeof(UINT) ); + break; + case WM_MDIGETACTIVE: + if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) ); + break; + case WM_NCCALCSIZE: + if (!wparam) + push_data( data, (RECT *)lparam, sizeof(RECT) ); + else + { + NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam; + push_data( data, nc, sizeof(*nc) ); + push_data( data, nc->lppos, sizeof(*nc->lppos) ); + } + break; + case EM_GETSEL: + if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) ); + if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) ); + break; + case WM_MDICREATE: + push_data( data, (MDICREATESTRUCTW *)lparam, sizeof(MDICREATESTRUCTW) ); + break; + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + FIXME("not implemented yet\n"); + break; + } +} + + +/*********************************************************************** + * unpack_reply + * + * Unpack a message reply received from another process. + */ +static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, + void *buffer, size_t size ) +{ + switch(message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam; + LPCWSTR name = cs->lpszName, class = cs->lpszClass; + memcpy( cs, buffer, min( sizeof(*cs), size )); + cs->lpszName = name; /* restore the original pointers */ + cs->lpszClass = class; + break; + } + case WM_GETTEXT: + memcpy( (WCHAR *)lparam, buffer, min( wparam*sizeof(WCHAR), size )); + break; + case WM_GETMINMAXINFO: + memcpy( (MINMAXINFO *)lparam, buffer, min( sizeof(MINMAXINFO), size )); + break; + case WM_MEASUREITEM: + memcpy( (MEASUREITEMSTRUCT *)lparam, buffer, min( sizeof(MEASUREITEMSTRUCT), size )); + break; + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + memcpy( (WINDOWPOS *)lparam, buffer, min( sizeof(WINDOWPOS), size )); + break; + case WM_GETDLGCODE: + if (lparam) memcpy( (MSG *)lparam, buffer, min( sizeof(MSG), size )); + break; + case EM_GETRECT: + case CB_GETDROPPEDCONTROLRECT: + case LB_GETITEMRECT: + memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size )); + break; + case EM_GETLINE: + size = min( size, *(WORD *)lparam ); + memcpy( (WCHAR *)lparam, buffer, size ); + break; + case LB_GETSELITEMS: + memcpy( (UINT *)lparam, buffer, min( wparam*sizeof(UINT), size )); + break; + case LB_GETTEXT: + case CB_GETLBTEXT: + memcpy( (WCHAR *)lparam, buffer, size ); + break; + case WM_MDIGETACTIVE: + if (lparam) memcpy( (BOOL *)lparam, buffer, min( sizeof(BOOL), size )); + break; + case WM_NCCALCSIZE: + if (!wparam) + memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size )); + else + { + NCCALCSIZE_PARAMS *nc = (NCCALCSIZE_PARAMS *)lparam; + WINDOWPOS *wp = nc->lppos; + memcpy( nc, buffer, min( sizeof(*nc), size )); + if (size > sizeof(*nc)) + { + size -= sizeof(*nc); + memcpy( wp, (NCCALCSIZE_PARAMS*)buffer + 1, min( sizeof(*wp), size )); + } + nc->lppos = wp; /* restore the original pointer */ + } + break; + case EM_GETSEL: + if (wparam) + { + memcpy( (DWORD *)wparam, buffer, min( sizeof(DWORD), size )); + if (size <= sizeof(DWORD)) break; + size -= sizeof(DWORD); + buffer = (DWORD *)buffer + 1; + } + if (lparam) memcpy( (DWORD *)lparam, buffer, min( sizeof(DWORD), size )); + break; + case WM_MDICREATE: + { + MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lparam; + LPCWSTR title = cs->szTitle, class = cs->szClass; + memcpy( cs, buffer, min( sizeof(*cs), size )); + cs->szTitle = title; /* restore the original pointers */ + cs->szClass = class; + break; + } + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + FIXME("not implemented yet\n"); + break; + default: + ERR( "should not happen: unexpected message %x\n", message ); + break; + } +} + + +/*********************************************************************** + * reply_message + * + * Send a reply to a sent message. + */ +static void reply_message( struct received_message_info *info, LRESULT result, BOOL remove ) +{ + struct packed_message data; + int replied = info->flags & ISMEX_REPLIED; + + if (info->flags & ISMEX_NOTIFY) return; /* notify messages don't get replies */ + if (!remove && replied) return; /* replied already */ + + data.count = 0; + info->flags |= ISMEX_REPLIED; + + if (info->type == MSG_OTHER_PROCESS && !replied) + { + pack_reply( info->msg.hwnd, info->msg.message, info->msg.wParam, + info->msg.lParam, result, &data ); + if (data.count) + { + size_t total = get_data_total_size( &data ); + + if (total > REQUEST_MAX_VAR_SIZE) + { + FIXME( "inter-process msg data size %d not supported yet, expect trouble\n", + total ); + total = REQUEST_MAX_VAR_SIZE; + } + + SERVER_START_VAR_REQ( reply_message, total ) + { + req->result = result; + req->remove = remove; + copy_all_data( server_data_ptr(req), &data ); + SERVER_CALL(); + } + SERVER_END_VAR_REQ; + return; + } + } + + SERVER_START_REQ( reply_message ) + { + req->result = result; + req->remove = remove; + SERVER_CALL(); + } + SERVER_END_REQ; +} + + +/*********************************************************************** + * call_window_proc + * + * Call a window procedure and the corresponding hooks. + */ +static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode ) +{ + LRESULT result; + WND *wndPtr; + WNDPROC winproc; + + /* FIXME: should check for exiting queue */ + + /* first the WH_CALLWNDPROC hook */ + if (HOOK_IsHooked( WH_CALLWNDPROC )) + { + CWPSTRUCT cwp; + cwp.lParam = lparam; + cwp.wParam = wparam; + cwp.message = msg; + cwp.hwnd = hwnd; + if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); + else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); + lparam = cwp.lParam; + wparam = cwp.wParam; + msg = cwp.message; + hwnd = cwp.hwnd; + } + + /* now call the window procedure */ + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + WARN( "bad window %x\n", hwnd ); + return 0; + } + winproc = wndPtr->winproc; + WIN_ReleaseWndPtr(wndPtr); + + if (unicode) + result = CallWindowProcW( winproc, hwnd, msg, wparam, lparam ); + else + result = CallWindowProcA( winproc, hwnd, msg, wparam, lparam ); + + /* and finally the WH_CALLWNDPROCRET hook */ + if (HOOK_IsHooked( WH_CALLWNDPROCRET )) + { + CWPRETSTRUCT cwp; + cwp.lResult = result; + cwp.lParam = lparam; + cwp.wParam = wparam; + cwp.message = msg; + cwp.hwnd = hwnd; + if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp ); + else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp ); + } + return result; +} + + +/*********************************************************************** + * MSG_peek_message + * + * Peek for a message matching the given parameters. Return FALSE if none available. + * All pending sent messages are processed before returning. + */ +BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags ) +{ + BOOL ret; + LRESULT result; + ULONG_PTR extra_info = 0; + MESSAGEQUEUE *queue = QUEUE_Current(); + struct received_message_info info, *old_info; + + if (!first && !last) last = ~0; + + for (;;) + { + void *buffer = NULL; + size_t size = 0; + + SERVER_START_VAR_REQ( get_message, REQUEST_MAX_VAR_SIZE ) + { + req->flags = flags; + req->get_win = hwnd; + req->get_first = first; + req->get_last = last; + if ((ret = !SERVER_CALL())) + { + info.type = req->type; + info.msg.hwnd = req->win; + info.msg.message = req->msg; + info.msg.wParam = req->wparam; + info.msg.lParam = req->lparam; + info.msg.time = req->time; + info.msg.pt.x = req->x; + info.msg.pt.y = req->y; + extra_info = req->info; + + if ((size = server_data_size(req))) + { + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) + { + ERR("out of memory for message data\n"); + ret = FALSE; + } + else memcpy( buffer, server_data_ptr(req), size ); + } + } + } + SERVER_END_VAR_REQ; + + if (!ret) return FALSE; /* no message available */ + + TRACE( "got type %d msg %x hwnd %x wp %x lp %lx\n", + info.type, info.msg.message, info.msg.hwnd, info.msg.wParam, info.msg.lParam ); + + switch(info.type) + { + case MSG_ASCII: + case MSG_UNICODE: + info.flags = ISMEX_SEND; + break; + case MSG_NOTIFY: + info.flags = ISMEX_NOTIFY; + break; + case MSG_CALLBACK: + info.flags = ISMEX_CALLBACK; + break; + case MSG_OTHER_PROCESS: + info.flags = ISMEX_SEND; + if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, + &info.msg.lParam, &buffer, size )) + { + ERR( "invalid packed message %x (%s) hwnd %x wp %x lp %lx size %d\n", + info.msg.message, SPY_GetMsgName(info.msg.message), info.msg.hwnd, + info.msg.wParam, info.msg.lParam, size ); + /* ignore it */ + reply_message( &info, 0, TRUE ); + continue; + } + break; + case MSG_POSTED: + goto got_one; + case MSG_HARDWARE_RAW: + if (!MSG_process_raw_hardware_message( &info.msg, extra_info, + hwnd, first, last, flags & GET_MSG_REMOVE )) + continue; + /* fall through */ + case MSG_HARDWARE_COOKED: + if (!MSG_process_cooked_hardware_message( &info.msg, flags & GET_MSG_REMOVE )) + { + flags |= GET_MSG_REMOVE_LAST; + continue; + } + queue->GetMessageExtraInfoVal = extra_info; + goto got_one; + } + + /* if we get here, we have a sent message; call the window procedure */ + old_info = queue->receive_info; + queue->receive_info = &info; + result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam, + info.msg.lParam, (info.type != MSG_ASCII) ); + reply_message( &info, result, TRUE ); + queue->receive_info = old_info; + + if (buffer) HeapFree( GetProcessHeap(), 0, buffer ); + } + + got_one: + *msg = info.msg; + return TRUE; +} + + +/*********************************************************************** + * wait_message_reply + * + * Wait until a sent message gets replied to. + */ +static void wait_message_reply( UINT flags ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = QUEUE_Current())) return; + + for (;;) + { + unsigned int wake_bits = 0, changed_bits = 0; + DWORD dwlc, res; + + SERVER_START_REQ( set_queue_mask ) + { + req->wake_mask = (flags & SMTO_BLOCK) ? 0 : QS_SENDMESSAGE; + req->changed_mask = QS_SMRESULT | req->wake_mask; + req->skip_wait = 1; + if (!SERVER_CALL()) + { + wake_bits = req->wake_bits; + changed_bits = req->changed_bits; + } + } + SERVER_END_REQ; + + if (changed_bits & QS_SMRESULT) return; /* got a result */ + if (wake_bits & QS_SENDMESSAGE) + { + /* Process the sent message immediately */ + MSG msg; + MSG_peek_message( &msg, 0, 0, 0, GET_MSG_REMOVE | GET_MSG_SENT_ONLY ); + continue; + } + + /* now wait for it */ + + ReleaseThunkLock( &dwlc ); + + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + res = USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, + INFINITE, 0, 0 ); + else + res = WaitForSingleObject( queue->server_queue, INFINITE ); + + if (dwlc) RestoreThunkLock( dwlc ); + } +} + +/*********************************************************************** + * put_message_in_queue + * + * Put a sent message into the destination queue. + * For inter-process message, reply_size is set to expected size of reply data. + */ +static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info *info, + size_t *reply_size ) +{ + unsigned int res; + int timeout = -1; + + /* FIXME: should check for exiting queue */ + + if (info->type != MSG_NOTIFY && + info->type != MSG_CALLBACK && + info->type != MSG_POSTED && + info->timeout != INFINITE) + timeout = info->timeout; + + if (info->type == MSG_OTHER_PROCESS) + { + struct packed_message data; + *reply_size = pack_message( info->hwnd, info->msg, info->wparam, info->lparam, &data ); + + if (data.count == -1) + { + WARN( "cannot pack message %x\n", info->msg ); + return FALSE; + } + + if (data.size[0]) /* need to send extra data along with the message */ + { + size_t total = get_data_total_size( &data ); + + if (total > REQUEST_MAX_VAR_SIZE) + { + FIXME( "inter-process msg data size %d not supported yet, expect trouble\n", + total ); + total = REQUEST_MAX_VAR_SIZE; + } + + SERVER_START_VAR_REQ( send_message, total ) + { + req->id = (void *)dest_tid; + req->type = MSG_OTHER_PROCESS; + req->win = info->hwnd; + req->msg = info->msg; + req->wparam = info->wparam; + req->lparam = info->lparam; + req->time = GetCurrentTime(); + req->timeout = timeout; + copy_all_data( server_data_ptr(req), &data ); + res = SERVER_CALL(); + } + SERVER_END_VAR_REQ; + goto done; + } + } + + /* no extra data, or not inter-process message */ + SERVER_START_REQ( send_message ) + { + req->id = (void *)dest_tid; + req->type = info->type; + req->win = info->hwnd; + req->msg = info->msg; + req->wparam = info->wparam; + req->lparam = info->lparam; + req->time = GetCurrentTime(); + req->timeout = timeout; + res = SERVER_CALL(); + } + SERVER_END_REQ; + + done: + if (res) + { + if (res == STATUS_INVALID_PARAMETER) + /* FIXME: find a STATUS_ value for this one */ + SetLastError( ERROR_INVALID_THREAD_ID ); + else + SetLastError( RtlNtStatusToDosError(res) ); + } + return !res; +} + + +/*********************************************************************** + * retrieve_reply + * + * Retrieve a message reply from the server. + */ +static LRESULT retrieve_reply( const struct send_message_info *info, + size_t reply_size, LRESULT *result ) +{ + NTSTATUS status; + + if (reply_size) + { + if (reply_size > REQUEST_MAX_VAR_SIZE) + { + WARN( "reply_size %d too large, reply may be truncated\n", reply_size ); + reply_size = REQUEST_MAX_VAR_SIZE; + } + SERVER_START_VAR_REQ( get_message_reply, reply_size ) + { + req->cancel = 1; + if (!(status = SERVER_CALL())) + { + *result = req->result; + unpack_reply( info->hwnd, info->msg, info->wparam, info->lparam, + server_data_ptr(req), server_data_size(req) ); + } + } + SERVER_END_VAR_REQ; + } + else + { + SERVER_START_REQ( get_message_reply ) + { + req->cancel = 1; + if (!(status = SERVER_CALL())) *result = req->result; + } + SERVER_END_REQ; + } + + TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n", + info->hwnd, info->msg, SPY_GetMsgName(info->msg), info->wparam, + info->lparam, *result, status ); + + if (!status) return 1; + if (status == STATUS_TIMEOUT) SetLastError(0); /* timeout */ + else SetLastError( RtlNtStatusToDosError(status) ); + return 0; +} + + +/*********************************************************************** + * send_inter_thread_message + */ +static LRESULT send_inter_thread_message( DWORD dest_tid, const struct send_message_info *info, + LRESULT *res_ptr ) +{ + LRESULT ret; + int locks; + size_t reply_size = 0; + + TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", + info->hwnd, info->msg, SPY_GetMsgName(info->msg), info->wparam, info->lparam ); + + if (!put_message_in_queue( dest_tid, info, &reply_size )) return 0; + + /* there's no reply to wait for on notify/callback messages */ + if (info->type == MSG_NOTIFY || info->type == MSG_CALLBACK) return 1; + + locks = WIN_SuspendWndsLock(); + + wait_message_reply( info->flags ); + ret = retrieve_reply( info, reply_size, res_ptr ); + + WIN_RestoreWndsLock( locks ); + return ret; +} + + +/*********************************************************************** + * SendMessageTimeoutW (USER32.@) + */ +LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + UINT flags, UINT timeout, LPDWORD res_ptr ) +{ + struct send_message_info info; + DWORD dest_tid, dest_pid; + LRESULT ret, result; + + info.type = MSG_UNICODE; + info.hwnd = hwnd; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + info.flags = flags; + info.timeout = timeout; + + if (is_broadcast(hwnd)) + { + EnumWindows( broadcast_message_callback, (LPARAM)&info ); + if (res_ptr) *res_ptr = 1; + return 1; + } + + SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam ); + + dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ); + + if (dest_tid == GetCurrentThreadId()) + { + result = call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + ret = 1; + } + else + { + if (dest_pid != GetCurrentProcessId()) info.type = MSG_OTHER_PROCESS; + ret = send_inter_thread_message( dest_tid, &info, &result ); + } + + SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam ); + if (ret && res_ptr) *res_ptr = result; + return ret; +} + + +/*********************************************************************** + * SendMessageTimeoutA (USER32.@) + */ +LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + UINT flags, UINT timeout, LPDWORD res_ptr ) +{ + struct send_message_info info; + DWORD dest_tid, dest_pid; + LRESULT ret, result; + + info.type = MSG_ASCII; + info.hwnd = hwnd; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + info.flags = flags; + info.timeout = timeout; + + if (is_broadcast(hwnd)) + { + EnumWindows( broadcast_message_callback, (LPARAM)&info ); + if (res_ptr) *res_ptr = 1; + return 1; + } + + SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wparam, lparam ); + + dest_tid = GetWindowThreadProcessId( hwnd, &dest_pid ); + + if (dest_tid == GetCurrentThreadId()) + { + result = call_window_proc( hwnd, msg, wparam, lparam, FALSE ); + ret = 1; + } + else if (dest_pid == GetCurrentProcessId()) + { + ret = send_inter_thread_message( dest_tid, &info, &result ); + } + else + { + /* inter-process message: need to map to Unicode */ + info.type = MSG_OTHER_PROCESS; + if (WINPROC_MapMsg32ATo32W( info.hwnd, info.msg, &info.wparam, &info.lparam ) == -1) + return 0; + ret = send_inter_thread_message( dest_tid, &info, &result ); + WINPROC_UnmapMsg32ATo32W( info.hwnd, info.msg, info.wparam, info.lparam ); + } + SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, result, wparam, lparam ); + if (ret && res_ptr) *res_ptr = result; + return ret; +} + + +/*********************************************************************** + * SendMessageW (USER32.@) + */ +LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + LRESULT res = 0; + SendMessageTimeoutW( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res ); + return res; +} + + +/*********************************************************************** + * SendMessageA (USER32.@) + */ +LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + LRESULT res = 0; + SendMessageTimeoutA( hwnd, msg, wparam, lparam, SMTO_NORMAL, INFINITE, &res ); + return res; +} + + +/*********************************************************************** + * SendNotifyMessageA (USER32.@) + */ +BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + return SendNotifyMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam ); +} + + +/*********************************************************************** + * SendNotifyMessageW (USER32.@) + */ +BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct send_message_info info; + DWORD dest_tid; + LRESULT result; + + if (is_pointer_message(msg)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + info.type = MSG_NOTIFY; + info.hwnd = hwnd; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + + if (is_broadcast(hwnd)) + { + EnumWindows( broadcast_message_callback, (LPARAM)&info ); + return TRUE; + } + + dest_tid = GetWindowThreadProcessId( hwnd, NULL ); + + if (dest_tid == GetCurrentThreadId()) + { + call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + return TRUE; + } + return send_inter_thread_message( dest_tid, &info, &result ); +} + + +/*********************************************************************** + * SendMessageCallbackA (USER32.@) + */ +BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + SENDASYNCPROC callback, ULONG_PTR data ) +{ + return SendMessageCallbackW( hwnd, msg, map_wparam_AtoW( msg, wparam ), + lparam, callback, data ); +} + + +/*********************************************************************** + * SendMessageCallbackW (USER32.@) + */ +BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + SENDASYNCPROC callback, ULONG_PTR data ) +{ + struct send_message_info info; + LRESULT result; + DWORD dest_tid; + + if (is_pointer_message(msg)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + info.type = MSG_CALLBACK; + info.hwnd = hwnd; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + info.callback = callback; + info.data = data; + + if (is_broadcast(hwnd)) + { + EnumWindows( broadcast_message_callback, (LPARAM)&info ); + return TRUE; + } + + dest_tid = GetWindowThreadProcessId( hwnd, NULL ); + + if (dest_tid == GetCurrentThreadId()) + { + result = call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + callback( hwnd, msg, data, result ); + return TRUE; + } + FIXME( "callback will not be called\n" ); + return send_inter_thread_message( dest_tid, &info, &result ); +} + + +/*********************************************************************** + * ReplyMessage (USER32.@) + */ +BOOL WINAPI ReplyMessage( LRESULT result ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct received_message_info *info = queue->receive_info; + + if (!info) return FALSE; + reply_message( info, result, FALSE ); + return TRUE; +} + + +/*********************************************************************** + * InSendMessage (USER32.@) + */ +BOOL WINAPI InSendMessage(void) +{ + return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND; +} + + +/*********************************************************************** + * InSendMessageEx (USER32.@) + */ +DWORD WINAPI InSendMessageEx( LPVOID reserved ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct received_message_info *info = queue->receive_info; + + if (info) return info->flags; + return ISMEX_NOSEND; +} + + +/*********************************************************************** + * PostMessageA (USER32.@) + */ +BOOL WINAPI PostMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + return PostMessageW( hwnd, msg, map_wparam_AtoW( msg, wparam ), lparam ); +} + + +/*********************************************************************** + * PostMessageW (USER32.@) + */ +BOOL WINAPI PostMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct send_message_info info; + + if (is_pointer_message( msg )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + info.type = MSG_POSTED; + info.hwnd = hwnd; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + + if (is_broadcast(hwnd)) + { + EnumWindows( broadcast_message_callback, (LPARAM)&info ); + return TRUE; + } + return put_message_in_queue( GetWindowThreadProcessId( hwnd, NULL ), &info, NULL ); +} + + +/********************************************************************** + * PostThreadMessageA (USER32.@) + */ +BOOL WINAPI PostThreadMessageA( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + return PostThreadMessageW( thread, msg, map_wparam_AtoW( msg, wparam ), lparam ); +} + + +/********************************************************************** + * PostThreadMessageW (USER32.@) + */ +BOOL WINAPI PostThreadMessageW( DWORD thread, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct send_message_info info; + + if (is_pointer_message( msg )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + info.type = MSG_POSTED; + info.hwnd = 0; + info.msg = msg; + info.wparam = wparam; + info.lparam = lparam; + return put_message_in_queue( thread, &info, NULL ); +} + + +/*********************************************************************** + * PostQuitMessage (USER32.@) + */ +void WINAPI PostQuitMessage( INT exitCode ) +{ + PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 ); +} + + +/*********************************************************************** + * PeekMessageW (USER32.@) + */ +BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ) +{ + MESSAGEQUEUE *queue; + MSG msg; + int locks; + + /* check for graphics events */ + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); + + locks = WIN_SuspendWndsLock(); + + if (!MSG_peek_message( &msg, hwnd, first, last, + (flags & PM_REMOVE) ? GET_MSG_REMOVE : 0 )) + { + /* FIXME: should be done before checking for hw events */ + MSG_JournalPlayBackMsg(); + + if (!(flags & PM_NOYIELD)) + { + DWORD count; + ReleaseThunkLock(&count); + if (count) RestoreThunkLock(count); + } + WIN_RestoreWndsLock( locks ); + return FALSE; + } + + WIN_RestoreWndsLock( locks ); + + /* need to fill the window handle for WM_PAINT message */ + if (msg.message == WM_PAINT) + { + if (!(msg.hwnd = WIN_FindWinToRepaint( hwnd ))) return FALSE; + + if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON )) + { + msg.message = WM_PAINTICON; + msg.wParam = 1; + } + + /* check hwnd filter */ + if (hwnd && msg.hwnd != hwnd && !IsChild( hwnd, msg.hwnd )) return FALSE; + + /* clear internal paint flag */ + RedrawWindow( msg.hwnd, NULL, 0, RDW_NOINTERNALPAINT | RDW_NOCHILDREN ); + } + + if ((queue = QUEUE_Current())) + { + queue->GetMessageTimeVal = msg.time; + queue->GetMessagePosVal = MAKELONG( msg.pt.x, msg.pt.y ); + } + + /* We got a message */ + if (flags & PM_REMOVE) + { + if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) + { + BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff]; + + if (!(*p & 0x80)) *p ^= 0x01; + *p |= 0x80; + } + else if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) + QueueKeyStateTable[msg.wParam & 0xff] &= ~0x80; + } + + HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg ); + + /* copy back our internal safe copy of message data to msg_out. + * msg_out is a variable from the *program*, so it can't be used + * internally as it can get "corrupted" by our use of SendMessage() + * (back to the program) inside the message handling itself. */ + *msg_out = msg; + return TRUE; +} + + +/*********************************************************************** + * PeekMessageA (USER32.@) + */ +BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags ) +{ + BOOL ret = PeekMessageW( msg, hwnd, first, last, flags ); + if (ret) msg->wParam = map_wparam_WtoA( msg->message, msg->wParam ); + return ret; +} + + +/*********************************************************************** + * GetMessageW (USER32.@) + */ +BOOL WINAPI GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + int mask, locks; + + mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */ + if (first || last) + { + if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; + if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) || + ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE; + if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER; + if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER; + if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT; + } + else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT; + + locks = WIN_SuspendWndsLock(); + + while (!PeekMessageW( msg, hwnd, first, last, PM_REMOVE )) + { + /* wait until one of the bits is set */ + unsigned int wake_bits = 0, changed_bits = 0; + DWORD dwlc; + + SERVER_START_REQ( set_queue_mask ) + { + req->wake_mask = QS_SENDMESSAGE; + req->changed_mask = mask; + req->skip_wait = 1; + if (!SERVER_CALL()) + { + wake_bits = req->wake_bits; + changed_bits = req->changed_bits; + } + } + SERVER_END_REQ; + + if (changed_bits & mask) continue; + if (wake_bits & QS_SENDMESSAGE) continue; + + TRACE( "(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n", + queue->self, mask, wake_bits, changed_bits ); + + ReleaseThunkLock( &dwlc ); + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, INFINITE, 0, 0 ); + else + WaitForSingleObject( queue->server_queue, INFINITE ); + if (dwlc) RestoreThunkLock( dwlc ); + } + + WIN_RestoreWndsLock( locks ); + + return (msg->message != WM_QUIT); +} + + +/*********************************************************************** + * GetMessageA (USER32.@) + */ +BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last ) +{ + GetMessageW( msg, hwnd, first, last ); + msg->wParam = map_wparam_WtoA( msg->message, msg->wParam ); + return (msg->message != WM_QUIT); +} + + +/*********************************************************************** + * SetMessageQueue (USER32.@) + */ +BOOL WINAPI SetMessageQueue( INT size ) +{ + /* now obsolete the message queue will be expanded dynamically as necessary */ + return TRUE; +}
diff --git a/dlls/user/msg16.c b/dlls/user/msg16.c new file mode 100644 index 0000000..55a4317 --- /dev/null +++ b/dlls/user/msg16.c
@@ -0,0 +1,383 @@ +/* + * 16-bit messaging support + * + * Copyright 2001 Alexandre Julliard + */ + +#include "wine/winuser16.h" +#include "heap.h" +#include "hook.h" +#include "message.h" +#include "spy.h" +#include "task.h" +#include "thread.h" +#include "win.h" +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(msg); + + +/*********************************************************************** + * SendMessage (USER.111) + */ +LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam ) +{ + LRESULT result; + + if (hwnd != HWND_BROADCAST && + GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId()) + { + /* call 16-bit window proc directly */ + WND *wndPtr; + WNDPROC16 winproc; + + /* first the WH_CALLWNDPROC hook */ + if (HOOK_IsHooked( WH_CALLWNDPROC )) + { + CWPSTRUCT16 *cwp; + + if ((cwp = SEGPTR_NEW(CWPSTRUCT16))) + { + cwp->hwnd = hwnd; + cwp->message = msg; + cwp->wParam = wparam; + cwp->lParam = lparam; + HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, SEGPTR_GET(cwp) ); + hwnd = cwp->hwnd; + msg = cwp->message; + wparam = cwp->wParam; + lparam = cwp->lParam; + SEGPTR_FREE( cwp ); + } + } + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + WARN("invalid hwnd %04x\n", hwnd ); + return 0; + } + winproc = (WNDPROC16)wndPtr->winproc; + WIN_ReleaseWndPtr( wndPtr ); + + SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wparam, lparam ); + result = CallWindowProc16( (WNDPROC16)winproc, hwnd, msg, wparam, lparam ); + SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, result, wparam, lparam ); + } + else /* map to 32-bit unicode for inter-thread/process message */ + { + UINT msg32; + WPARAM wparam32; + + if (WINPROC_MapMsg16To32W( hwnd, msg, wparam, &msg32, &wparam32, &lparam ) == -1) + return 0; + result = WINPROC_UnmapMsg16To32W( hwnd, msg32, wparam32, lparam, + SendMessageW( hwnd, msg32, wparam32, lparam ) ); + } + return result; +} + + +/*********************************************************************** + * PostMessage (USER.110) + */ +BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam ) +{ + WPARAM wparam32; + UINT msg32; + + switch (WINPROC_MapMsg16To32W( hwnd, msg, wparam, &msg32, &wparam32, &lparam )) + { + case 0: + return PostMessageW( hwnd, msg32, wparam32, lparam ); + case 1: + ERR( "16-bit message %x contains pointer, cannot post\n", msg ); + return FALSE; + default: + return FALSE; + } +} + + +/*********************************************************************** + * PostAppMessage (USER.116) + * PostAppMessage16 (USER32.@) + */ +BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 msg, WPARAM16 wparam, LPARAM lparam ) +{ + WPARAM wparam32; + UINT msg32; + TDB *pTask = TASK_GetPtr( hTask ); + if (!pTask) return FALSE; + + switch (WINPROC_MapMsg16To32W( 0, msg, wparam, &msg32, &wparam32, &lparam )) + { + case 0: + return PostThreadMessageW( (DWORD)pTask->teb->tid, msg32, wparam32, lparam ); + case 1: + ERR( "16-bit message %x contains pointer, cannot post\n", msg ); + return FALSE; + default: + return FALSE; + } +} + + +/*********************************************************************** + * InSendMessage (USER.192) + */ +BOOL16 WINAPI InSendMessage16(void) +{ + return InSendMessage(); +} + + +/*********************************************************************** + * ReplyMessage (USER.115) + */ +void WINAPI ReplyMessage16( LRESULT result ) +{ + ReplyMessage( result ); +} + + +/*********************************************************************** + * PeekMessage32 (USER.819) + */ +BOOL16 WINAPI PeekMessage32_16( MSG32_16 *msg16, HWND16 hwnd, + UINT16 first, UINT16 last, UINT16 flags, + BOOL16 wHaveParamHigh ) +{ + MSG msg; + + if (!PeekMessageW( &msg, hwnd, first, last, flags )) return FALSE; + + msg16->msg.hwnd = msg.hwnd; + msg16->msg.lParam = msg.lParam; + msg16->msg.time = msg.time; + msg16->msg.pt.x = (INT16)msg.pt.x; + msg16->msg.pt.y = (INT16)msg.pt.y; + if (wHaveParamHigh) msg16->wParamHigh = HIWORD(msg.wParam); + + return (WINPROC_MapMsg32WTo16( msg.hwnd, msg.message, msg.wParam, + &msg16->msg.message, &msg16->msg.wParam, + &msg16->msg.lParam ) != -1); +} + + +/*********************************************************************** + * PeekMessage (USER.109) + */ +BOOL16 WINAPI PeekMessage16( MSG16 *msg, HWND16 hwnd, + UINT16 first, UINT16 last, UINT16 flags ) +{ + return PeekMessage32_16( (MSG32_16 *)msg, hwnd, first, last, flags, FALSE ); +} + + +/*********************************************************************** + * GetMessage32 (USER.820) + */ +BOOL16 WINAPI GetMessage32_16( MSG32_16 *msg16, HWND16 hwnd, UINT16 first, + UINT16 last, BOOL16 wHaveParamHigh ) +{ + MSG msg; + + do + { + GetMessageW( &msg, hwnd, first, last ); + msg16->msg.hwnd = msg.hwnd; + msg16->msg.lParam = msg.lParam; + msg16->msg.time = msg.time; + msg16->msg.pt.x = (INT16)msg.pt.x; + msg16->msg.pt.y = (INT16)msg.pt.y; + if (wHaveParamHigh) msg16->wParamHigh = HIWORD(msg.wParam); + } + while (WINPROC_MapMsg32WTo16( msg.hwnd, msg.message, msg.wParam, + &msg16->msg.message, &msg16->msg.wParam, + &msg16->msg.lParam ) == -1); + + TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n", + msg16->msg.message, hwnd, first, last ); + + return msg16->msg.message != WM_QUIT; +} + + +/*********************************************************************** + * GetMessage (USER.108) + */ +BOOL16 WINAPI GetMessage16( MSG16 *msg, HWND16 hwnd, UINT16 first, UINT16 last ) +{ + return GetMessage32_16( (MSG32_16 *)msg, hwnd, first, last, FALSE ); +} + + +/*********************************************************************** + * TranslateMessage32 (USER.821) + */ +BOOL16 WINAPI TranslateMessage32_16( const MSG32_16 *msg, BOOL16 wHaveParamHigh ) +{ + MSG msg32; + + msg32.hwnd = msg->msg.hwnd; + msg32.message = msg->msg.message; + msg32.wParam = MAKEWPARAM( msg->msg.wParam, wHaveParamHigh ? msg->wParamHigh : 0 ); + msg32.lParam = msg->msg.lParam; + return TranslateMessage( &msg32 ); +} + + +/*********************************************************************** + * TranslateMessage (USER.113) + */ +BOOL16 WINAPI TranslateMessage16( const MSG16 *msg ) +{ + return TranslateMessage32_16( (MSG32_16 *)msg, FALSE ); +} + + +/*********************************************************************** + * DispatchMessage (USER.114) + */ +LONG WINAPI DispatchMessage16( const MSG16* msg ) +{ + WND * wndPtr; + WNDPROC16 winproc; + LONG retval; + int painting; + + /* Process timer messages */ + if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) + { + if (msg->lParam) + { + /* before calling window proc, verify whether timer is still valid; + there's a slim chance that the application kills the timer + between GetMessage and DispatchMessage API calls */ + if (!TIMER_IsTimerValid(msg->hwnd, (UINT) msg->wParam, (HWINDOWPROC) msg->lParam)) + return 0; /* invalid winproc */ + + return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + } + + if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0; + if (!wndPtr->winproc) + { + WIN_ReleaseWndPtr( wndPtr ); + return 0; + } + winproc = (WNDPROC16)wndPtr->winproc; + painting = (msg->message == WM_PAINT); + if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT; + WIN_ReleaseWndPtr( wndPtr ); + + SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message, msg->wParam, msg->lParam ); + retval = CallWindowProc16( winproc, msg->hwnd, msg->message, msg->wParam, msg->lParam ); + SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval, msg->wParam, msg->lParam ); + + if (!painting) return retval; + + if ((wndPtr = WIN_FindWndPtr( msg->hwnd ))) + { + if ((wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate) + { + ERR( "BeginPaint not called on WM_PAINT for hwnd %04x!\n", msg->hwnd ); + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + /* Validate the update region to avoid infinite WM_PAINT loop */ + RedrawWindow( wndPtr->hwndSelf, NULL, 0, + RDW_NOFRAME | RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOINTERNALPAINT ); + } + WIN_ReleaseWndPtr( wndPtr ); + } + return retval; +} + + +/*********************************************************************** + * DispatchMessage32 (USER.822) + */ +LONG WINAPI DispatchMessage32_16( const MSG32_16 *msg16, BOOL16 wHaveParamHigh ) +{ + if (wHaveParamHigh == FALSE) + return DispatchMessage16( &msg16->msg ); + else + { + MSG msg; + + msg.hwnd = msg16->msg.hwnd; + msg.message = msg16->msg.message; + msg.wParam = MAKEWPARAM( msg16->msg.wParam, msg16->wParamHigh ); + msg.lParam = msg16->msg.lParam; + msg.time = msg16->msg.time; + msg.pt.x = msg16->msg.pt.x; + msg.pt.y = msg16->msg.pt.y; + return DispatchMessageA( &msg ); + } +} + + +/*********************************************************************** + * MsgWaitForMultipleObjects (USER.640) + */ +DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles, + BOOL wait_all, DWORD timeout, DWORD mask ) +{ + return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask, + wait_all ? MWMO_WAITALL : 0 ); +} + + +/********************************************************************** + * SetDoubleClickTime (USER.20) + */ +void WINAPI SetDoubleClickTime16( UINT16 interval ) +{ + SetDoubleClickTime( interval ); +} + + +/********************************************************************** + * GetDoubleClickTime (USER.21) + */ +UINT16 WINAPI GetDoubleClickTime16(void) +{ + return GetDoubleClickTime(); +} + + +/*********************************************************************** + * PostQuitMessage (USER.6) + */ +void WINAPI PostQuitMessage16( INT16 exitCode ) +{ + PostQuitMessage( exitCode ); +} + + +/*********************************************************************** + * SetMessageQueue (USER.266) + */ +BOOL16 WINAPI SetMessageQueue16( INT16 size ) +{ + return SetMessageQueue( size ); +} + + +/*********************************************************************** + * GetQueueStatus (USER.334) + */ +DWORD WINAPI GetQueueStatus16( UINT16 flags ) +{ + return GetQueueStatus( flags ); +} + + +/*********************************************************************** + * GetInputState (USER.335) + */ +BOOL16 WINAPI GetInputState16(void) +{ + return GetInputState(); +}
diff --git a/dlls/user/user.spec b/dlls/user/user.spec index 6288023..bc215b1 100644 --- a/dlls/user/user.spec +++ b/dlls/user/user.spec
@@ -112,8 +112,8 @@ 105 pascal16 FlashWindow(word word) FlashWindow16 106 pascal16 GetKeyState(word) GetKeyState16 107 pascal DefWindowProc(word word word long) DefWindowProc16 -108 pascal16 GetMessage(segptr word word word) GetMessage16 -109 pascal16 PeekMessage(segptr word word word word) PeekMessage16 +108 pascal16 GetMessage(ptr word word word) GetMessage16 +109 pascal16 PeekMessage(ptr word word word word) PeekMessage16 110 pascal16 PostMessage(word word word long) PostMessage16 111 pascal SendMessage(word word word long) SendMessage16 112 pascal16 WaitMessage() WaitMessage @@ -538,8 +538,8 @@ 802 stub OPENFILENAME_CALLBACK16 803 stub PRINTDLG_CALLBACK16 804 stub CHOOSECOLOR_CALLBACK16 -819 pascal16 PeekMessage32(segptr word word word word word) PeekMessage32_16 -820 pascal GetMessage32(segptr word word word word) GetMessage32_16 +819 pascal16 PeekMessage32(ptr word word word word word) PeekMessage32_16 +820 pascal GetMessage32(ptr word word word word) GetMessage32_16 821 pascal16 TranslateMessage32(ptr word) TranslateMessage32_16 #821 stub IsDialogMessage32 # FIXME: two ordinal 821??? 822 pascal DispatchMessage32(ptr word) DispatchMessage32_16
diff --git a/include/message.h b/include/message.h index 1d9968b..f27bc6b 100644 --- a/include/message.h +++ b/include/message.h
@@ -11,12 +11,14 @@ #include "wine/windef16.h" #include "winproc.h" -struct tagMSG; - /* message.c */ -extern BOOL MSG_InternalGetMessage( struct tagMSG *msg, HWND hwnd, HWND hwndOwner, - UINT first, UINT last, WPARAM code, - WORD flags, BOOL sendIdle, BOOL* idleSent ); +extern BOOL MSG_process_raw_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd_filter, + UINT first, UINT last, BOOL remove ); +extern BOOL MSG_process_cooked_hardware_message( MSG *msg, BOOL remove ); +extern void MSG_JournalPlayBackMsg(void); + +/* sendmsg.c */ +extern BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags ); /* timer.c */ extern void TIMER_RemoveWindowTimers( HWND hwnd );
diff --git a/include/queue.h b/include/queue.h index b43eb16..2c94c73 100644 --- a/include/queue.h +++ b/include/queue.h
@@ -30,12 +30,15 @@ CRITICAL_SECTION cSection; /* Critical section for thread safe access */ } PERQUEUEDATA; +struct received_message_info; + /* Message queue */ typedef struct tagMESSAGEQUEUE { HQUEUE16 self; /* Handle to self (was: reserved) */ TEB* teb; /* Thread owning queue */ HANDLE server_queue; /* Handle to server-side queue */ + struct received_message_info *receive_info; /* Info about message being currently received */ DWORD magic; /* magic number should be QUEUE_MAGIC */ DWORD lockCount; /* reference counter */ @@ -69,7 +72,6 @@ extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue ); extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue ); extern void QUEUE_DeleteMsgQueue(void); -extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue ); extern void QUEUE_CleanupWindow( HWND hwnd ); #endif /* __WINE_QUEUE_H */
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a8d8a8a..ebf2721 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h
@@ -1338,20 +1338,31 @@ struct send_message_request { struct request_header __header; - int kind; void* id; int type; handle_t win; unsigned int msg; unsigned int wparam; unsigned int lparam; - unsigned short x; - unsigned short y; + int x; + int y; unsigned int time; unsigned int info; + int timeout; + /* VARARG(data,bytes); */ }; -enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE }; -#define NB_MSG_KINDS (RAW_HW_MESSAGE+1) + +enum message_type +{ + MSG_ASCII, + MSG_UNICODE, + MSG_NOTIFY, + MSG_CALLBACK, + MSG_OTHER_PROCESS, + MSG_POSTED, + MSG_HARDWARE_RAW, + MSG_HARDWARE_COOKED +}; @@ -1362,16 +1373,16 @@ handle_t get_win; unsigned int get_first; unsigned int get_last; - int kind; int type; handle_t win; unsigned int msg; unsigned int wparam; unsigned int lparam; - unsigned short x; - unsigned short y; + int x; + int y; unsigned int time; unsigned int info; + /* VARARG(data,bytes); */ }; #define GET_MSG_REMOVE 1 #define GET_MSG_SENT_ONLY 2 @@ -1383,6 +1394,7 @@ struct request_header __header; unsigned int result; int remove; + /* VARARG(data,bytes); */ }; @@ -1392,14 +1404,7 @@ struct request_header __header; int cancel; unsigned int result; -}; - - - -struct in_send_message_request -{ - struct request_header __header; - int flags; + /* VARARG(data,bytes); */ }; @@ -1639,7 +1644,6 @@ REQ_get_message, REQ_reply_message, REQ_get_message_reply, - REQ_in_send_message, REQ_cleanup_window_queue, REQ_set_win_timer, REQ_kill_win_timer, @@ -1767,7 +1771,6 @@ struct get_message_request get_message; struct reply_message_request reply_message; struct get_message_reply_request get_message_reply; - struct in_send_message_request in_send_message; struct cleanup_window_queue_request cleanup_window_queue; struct set_win_timer_request set_win_timer; struct kill_win_timer_request kill_win_timer; @@ -1780,6 +1783,6 @@ struct connect_named_pipe_request connect_named_pipe; }; -#define SERVER_PROTOCOL_VERSION 48 +#define SERVER_PROTOCOL_VERSION 49 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h index 7fe3745..522cac2 100644 --- a/include/wine/winuser16.h +++ b/include/wine/winuser16.h
@@ -561,8 +561,6 @@ BOOL16 WINAPI IsWindow16(HWND16); INT16 WINAPI LookupIconIdFromDirectory16(LPBYTE,BOOL16); UINT16 WINAPI MapVirtualKey16(UINT16,UINT16); -LRESULT WINAPI SendMessageTimeout16(HWND16,UINT16,WPARAM16,LPARAM,UINT16, - UINT16,LPWORD); FARPROC16 WINAPI SetWindowsHook16(INT16,HOOKPROC16); HHOOK WINAPI SetWindowsHookEx16(INT16,HOOKPROC16,HINSTANCE16,HTASK16); BOOL16 WINAPI UnhookWindowsHook16(INT16,HOOKPROC16); @@ -746,8 +744,8 @@ BOOL16 WINAPI GetMenuItemRect16(HWND16,HMENU16,UINT16,LPRECT16); UINT16 WINAPI GetMenuState16(HMENU16,UINT16,UINT16); INT16 WINAPI GetMenuString16(HMENU16,UINT16,LPSTR,INT16,UINT16); -BOOL16 WINAPI GetMessage16(SEGPTR,HWND16,UINT16,UINT16); -BOOL16 WINAPI GetMessage32_16(SEGPTR,HWND16,UINT16,UINT16,BOOL16); +BOOL16 WINAPI GetMessage16(MSG16*,HWND16,UINT16,UINT16); +BOOL16 WINAPI GetMessage32_16(MSG32_16*,HWND16,UINT16,UINT16,BOOL16); HWND16 WINAPI GetNextDlgGroupItem16(HWND16,HWND16,BOOL16); HWND16 WINAPI GetNextDlgTabItem16(HWND16,HWND16,BOOL16); HWND16 WINAPI GetNextWindow16(HWND16,WORD); @@ -825,8 +823,8 @@ void WINAPI OffsetRect16(LPRECT16,INT16,INT16); BOOL16 WINAPI OpenClipboard16(HWND16); BOOL16 WINAPI OpenIcon16(HWND16); -BOOL16 WINAPI PeekMessage16(SEGPTR,HWND16,UINT16,UINT16,UINT16); -BOOL16 WINAPI PeekMessage32_16(SEGPTR,HWND16,UINT16,UINT16,UINT16,BOOL16); +BOOL16 WINAPI PeekMessage16(MSG16*,HWND16,UINT16,UINT16,UINT16); +BOOL16 WINAPI PeekMessage32_16(MSG32_16*,HWND16,UINT16,UINT16,UINT16,BOOL16); BOOL16 WINAPI PostAppMessage16(HTASK16,UINT16,WPARAM16,LPARAM); BOOL16 WINAPI PostMessage16(HWND16,UINT16,WPARAM16,LPARAM); void WINAPI PostQuitMessage16(INT16);
diff --git a/server/protocol.def b/server/protocol.def index 32e9697..a4a7af8 100644 --- a/server/protocol.def +++ b/server/protocol.def
@@ -1195,20 +1195,31 @@ /* Send a message to a thread queue */ @REQ(send_message) - int kind; /* message kind (see below) */ void* id; /* thread id */ - int type; /* message type */ + int type; /* message type (see below) */ handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ - unsigned short x; /* x position */ - unsigned short y; /* y position */ + int x; /* x position */ + int y; /* y position */ unsigned int time; /* message time */ unsigned int info; /* extra info */ + int timeout; /* timeout for reply */ + VARARG(data,bytes); /* message data for sent messages */ @END -enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE }; -#define NB_MSG_KINDS (RAW_HW_MESSAGE+1) + +enum message_type +{ + MSG_ASCII, /* Ascii message (from SendMessageA) */ + MSG_UNICODE, /* Unicode message (from SendMessageW) */ + MSG_NOTIFY, /* notify message (from SendNotifyMessageW), always Unicode */ + MSG_CALLBACK, /* callback message (from SendMessageCallbackW), always Unicode */ + MSG_OTHER_PROCESS, /* sent from other process, may include vararg data, always Unicode */ + MSG_POSTED, /* posted message (from PostMessageW), always Unicode */ + MSG_HARDWARE_RAW, /* raw hardware message */ + MSG_HARDWARE_COOKED /* cooked hardware message */ +}; /* Get a message from the current queue */ @@ -1218,16 +1229,16 @@ unsigned int get_first; /* first message code to get */ unsigned int get_last; /* last message code to get */ @REPLY - int kind; /* message kind */ int type; /* message type */ handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ - unsigned short x; /* x position */ - unsigned short y; /* y position */ + int x; /* x position */ + int y; /* y position */ unsigned int time; /* message time */ unsigned int info; /* extra info */ + VARARG(data,bytes); /* message data for sent messages */ @END #define GET_MSG_REMOVE 1 /* remove the message */ #define GET_MSG_SENT_ONLY 2 /* only get sent messages */ @@ -1237,6 +1248,7 @@ @REQ(reply_message) unsigned int result; /* message result */ int remove; /* should we remove the message? */ + VARARG(data,bytes); /* message data for sent messages */ @END @@ -1245,13 +1257,7 @@ int cancel; /* cancel message if not ready? */ @REPLY unsigned int result; /* message result */ -@END - - -/* Check if we are processing a sent message */ -@REQ(in_send_message) -@REPLY - int flags; /* ISMEX_* flags */ + VARARG(data,bytes); /* message data for sent messages */ @END
diff --git a/server/queue.c b/server/queue.c index 2c53a92..238e3a9 100644 --- a/server/queue.c +++ b/server/queue.c
@@ -17,6 +17,10 @@ #include "process.h" #include "request.h" +enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE }; +#define NB_MSG_KINDS (RAW_HW_MESSAGE+1) + + struct message_result { struct message_result *send_next; /* next in sender list */ @@ -26,21 +30,26 @@ int replied; /* has it been replied to? */ unsigned int result; /* reply result */ unsigned int error; /* error code to pass back to sender */ + void *data; /* message reply data */ + unsigned int data_size; /* size of message reply data */ + struct timeout_user *timeout; /* result timeout */ }; struct message { struct message *next; /* next message in list */ struct message *prev; /* prev message in list */ - int type; /* message type (FIXME) */ + enum message_type type; /* message type */ handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ - unsigned short x; /* x position */ - unsigned short y; /* y position */ + int x; /* x position */ + int y; /* y position */ unsigned int time; /* message time */ unsigned int info; /* extra info */ + void *data; /* message data for sent messages */ + unsigned int data_size; /* size of message data */ struct message_result *result; /* result in sender queue */ }; @@ -141,14 +150,21 @@ return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask)); } -/* set/clear some queue bits */ -inline static void change_queue_bits( struct msg_queue *queue, unsigned int set, unsigned int clear ) +/* set some queue bits */ +inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits ) { - queue->wake_bits = (queue->wake_bits | set) & ~clear; - queue->changed_bits = (queue->changed_bits | set) & ~clear; + queue->wake_bits |= bits; + queue->changed_bits |= bits; if (is_signaled( queue )) wake_up( &queue->obj, 0 ); } +/* clear some queue bits */ +inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits ) +{ + queue->wake_bits &= ~bits; + queue->changed_bits &= ~bits; +} + /* get the QS_* bit corresponding to a given hardware message */ inline static int get_hardware_msg_bit( struct message *msg ) { @@ -203,6 +219,31 @@ return 1; } +/* free a result structure */ +static void free_result( struct message_result *result ) +{ + if (result->timeout) remove_timeout_user( result->timeout ); + if (result->data) free( result->data ); + free( result ); +} + +/* store the message result in the appropriate structure */ +static void store_message_result( struct message_result *res, unsigned int result, + unsigned int error ) +{ + res->result = result; + res->error = error; + res->replied = 1; + if (res->timeout) + { + remove_timeout_user( res->timeout ); + res->timeout = NULL; + } + /* wake sender queue if waiting on this result */ + if (res->sender && res->sender->send_result == res) + set_queue_bits( res->sender, QS_SMRESULT ); +} + /* free a message when deleting a queue or window */ static void free_message( struct message *msg ) { @@ -211,16 +252,12 @@ { if (result->sender) { - result->result = 0; - result->error = STATUS_ACCESS_DENIED; /* FIXME */ - result->replied = 1; result->receiver = NULL; - /* wake sender queue if waiting on this result */ - if (result->sender->send_result == result) - change_queue_bits( result->sender, QS_SMRESULT, 0 ); + store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ ); } - else free( result ); + else free_result( result ); } + if (msg->data) free( msg->data ); free( msg ); } @@ -236,41 +273,59 @@ switch(kind) { case SEND_MESSAGE: - if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_SENDMESSAGE ); + if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE ); break; case POST_MESSAGE: - if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_POSTMESSAGE ); + if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE ); break; case COOKED_HW_MESSAGE: case RAW_HW_MESSAGE: clr_bit = get_hardware_msg_bit( msg ); for (other = queue->msg_list[kind].first; other; other = other->next) if (get_hardware_msg_bit( other ) == clr_bit) break; - if (!other) change_queue_bits( queue, 0, clr_bit ); + if (!other) clear_queue_bits( queue, clr_bit ); break; } free_message( msg ); } -/* send a message from the sender queue to the receiver queue */ -static int send_message( struct msg_queue *send_queue, struct msg_queue *recv_queue, - struct message *msg ) +/* message timed out without getting a reply */ +static void result_timeout( void *private ) +{ + struct message_result *result = private; + + assert( !result->replied ); + + result->timeout = NULL; + store_message_result( result, 0, STATUS_TIMEOUT ); +} + +/* allocate and fill a message result structure */ +static struct message_result *alloc_message_result( struct msg_queue *send_queue, + struct msg_queue *recv_queue, + unsigned int timeout ) { struct message_result *result = mem_alloc( sizeof(*result) ); - if (!result) return 0; - - /* put the result on the sender result stack */ - result->sender = send_queue; - result->receiver = recv_queue; - result->replied = 0; - result->send_next = send_queue->send_result; - send_queue->send_result = result; - - /* and put the message on the receiver queue */ - msg->result = result; - append_message( &recv_queue->msg_list[SEND_MESSAGE], msg ); - change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 ); - return 1; + if (result) + { + /* put the result on the sender result stack */ + result->sender = send_queue; + result->receiver = recv_queue; + result->replied = 0; + result->data = NULL; + result->data_size = 0; + result->timeout = NULL; + result->send_next = send_queue->send_result; + send_queue->send_result = result; + if (timeout != -1) + { + struct timeval when; + gettimeofday( &when, 0 ); + add_timeout( &when, timeout ); + result->timeout = add_timeout_user( &when, result_timeout, result ); + } + } + return result; } /* receive a message, removing it from the sent queue */ @@ -280,15 +335,19 @@ unlink_message( &queue->msg_list[SEND_MESSAGE], msg ); /* put the result on the receiver result stack */ - result->recv_next = queue->recv_result; - queue->recv_result = result; + if (result) + { + result->recv_next = queue->recv_result; + queue->recv_result = result; + } + if (msg->data) free( msg->data ); free( msg ); - if (!queue->msg_list[SEND_MESSAGE].first) change_queue_bits( queue, 0, QS_SENDMESSAGE ); + if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE ); } /* set the result of the current received message */ static void reply_message( struct msg_queue *queue, unsigned int result, - unsigned int error, int remove ) + unsigned int error, int remove, void *data, size_t len ) { struct message_result *res = queue->recv_result; @@ -298,45 +357,17 @@ res->receiver = NULL; if (!res->sender) /* no one waiting for it */ { - free( res ); + free_result( res ); return; } } if (!res->replied) { - res->result = result; - res->error = error; - res->replied = 1; - /* wake sender queue if waiting on this result */ - if (res->sender && res->sender->send_result == res) - change_queue_bits( res->sender, QS_SMRESULT, 0 ); + if (len && (res->data = memdup( data, len ))) res->data_size = len; + store_message_result( res, result, error ); } } -/* retrieve the reply of the current message being sent */ -static unsigned int get_message_reply( struct msg_queue *queue, int cancel ) -{ - struct message_result *res = queue->send_result; - unsigned int ret = 0; - - set_error( STATUS_PENDING ); - - if (res && (res->replied || cancel)) - { - if (res->replied) - { - ret = res->result; - set_error( res->error ); - } - queue->send_result = res->send_next; - res->sender = NULL; - if (!res->receiver) free( res ); - if (!queue->send_result || !queue->send_result->replied) - change_queue_bits( queue, 0, QS_SMRESULT ); - } - return ret; -} - /* empty a message list and free all the messages */ static void empty_msg_list( struct message_list *list ) { @@ -359,11 +390,12 @@ { next = result->send_next; result->sender = NULL; - if (!result->receiver) free( result ); + if (!result->receiver) free_result( result ); result = next; } - while (queue->recv_result) reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1 ); + while (queue->recv_result) + reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 ); } static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry ) @@ -454,9 +486,9 @@ /* set/clear QS_TIMER bit */ if (queue->next_timer == queue->first_timer) - change_queue_bits( queue, 0, QS_TIMER ); + clear_queue_bits( queue, QS_TIMER ); else - change_queue_bits( queue, QS_TIMER, 0 ); + set_queue_bits( queue, QS_TIMER ); } /* callback for the next timer expiration */ @@ -504,7 +536,7 @@ else queue->first_timer = timer->next; /* check if we removed the next timer */ if (queue->next_timer == timer) set_next_timer( queue, timer->next ); - else if (queue->next_timer == queue->first_timer) change_queue_bits( queue, 0, QS_TIMER ); + else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER ); } /* restart an expired timer */ @@ -620,9 +652,9 @@ if ((queue->paint_count += req->incr) < 0) queue->paint_count = 0; if (queue->paint_count) - change_queue_bits( queue, QS_PAINT, 0 ); + set_queue_bits( queue, QS_PAINT ); else - change_queue_bits( queue, 0, QS_PAINT ); + clear_queue_bits( queue, QS_PAINT ); } else set_error( STATUS_INVALID_PARAMETER ); @@ -685,40 +717,64 @@ if ((msg = mem_alloc( sizeof(*msg) ))) { - msg->type = req->type; - msg->win = req->win; - msg->msg = req->msg; - msg->wparam = req->wparam; - msg->lparam = req->lparam; - msg->x = req->x; - msg->y = req->y; - msg->time = req->time; - msg->info = req->info; - msg->result = NULL; - switch(req->kind) + msg->type = req->type; + msg->win = req->win; + msg->msg = req->msg; + msg->wparam = req->wparam; + msg->lparam = req->lparam; + msg->time = req->time; + msg->x = req->x; + msg->y = req->y; + msg->info = req->info; + msg->result = NULL; + msg->data = NULL; + msg->data_size = 0; + + switch(msg->type) { - case SEND_MESSAGE: - send_message( send_queue, recv_queue, msg ); - break; - case POST_MESSAGE: - append_message( &recv_queue->msg_list[POST_MESSAGE], msg ); - change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 ); - break; - case COOKED_HW_MESSAGE: - case RAW_HW_MESSAGE: - if (msg->msg == WM_MOUSEMOVE && merge_message( &recv_queue->msg_list[req->kind], msg )) + case MSG_OTHER_PROCESS: + msg->data_size = get_req_data_size(req); + if (msg->data_size && !(msg->data = memdup( get_req_data(req), msg->data_size ))) { free( msg ); + break; } - else + /* fall through */ + case MSG_ASCII: + case MSG_UNICODE: + case MSG_CALLBACK: + if (!(msg->result = alloc_message_result( send_queue, recv_queue, req->timeout ))) { - append_message( &recv_queue->msg_list[req->kind], msg ); - change_queue_bits( recv_queue, get_hardware_msg_bit(msg), 0 ); + free( msg ); + break; } + /* fall through */ + case MSG_NOTIFY: + append_message( &recv_queue->msg_list[SEND_MESSAGE], msg ); + set_queue_bits( recv_queue, QS_SENDMESSAGE ); break; + case MSG_POSTED: + append_message( &recv_queue->msg_list[POST_MESSAGE], msg ); + set_queue_bits( recv_queue, QS_POSTMESSAGE ); + break; + case MSG_HARDWARE_RAW: + case MSG_HARDWARE_COOKED: + { + struct message_list *list = ((msg->type == MSG_HARDWARE_RAW) ? + &recv_queue->msg_list[RAW_HW_MESSAGE] : + &recv_queue->msg_list[COOKED_HW_MESSAGE]); + if (msg->msg == WM_MOUSEMOVE && merge_message( list, msg )) + { + free( msg ); + break; + } + append_message( list, msg ); + set_queue_bits( recv_queue, get_hardware_msg_bit(msg) ); + break; + } default: - free( msg ); set_error( STATUS_INVALID_PARAMETER ); + free( msg ); break; } } @@ -728,6 +784,8 @@ /* store a message contents into the request buffer; helper for get_message */ inline static void put_req_message( struct get_message_request *req, const struct message *msg ) { + int len = min( get_req_data_size(req), msg->data_size ); + req->type = msg->type; req->win = msg->win; req->msg = msg->msg; @@ -737,16 +795,17 @@ req->y = msg->y; req->time = msg->time; req->info = msg->info; + if (len) memcpy( get_req_data(req), msg->data, len ); + set_req_data_size( req, len ); } /* return a message to the application, removing it from the queue if needed */ static void return_message_to_app( struct msg_queue *queue, struct get_message_request *req, struct message *msg, enum message_kind kind ) { - req->kind = kind; put_req_message( req, msg ); /* raw messages always get removed */ - if ((kind == RAW_HW_MESSAGE) || (req->flags & GET_MSG_REMOVE)) + if ((msg->type == MSG_HARDWARE_RAW) || (req->flags & GET_MSG_REMOVE)) { queue->last_msg = NULL; remove_queue_message( queue, msg, kind ); @@ -784,16 +843,20 @@ struct message *msg; struct msg_queue *queue = get_current_queue(); - if (!queue) return; + if (!queue) + { + set_req_data_size( req, 0 ); + return; + } /* first check for sent messages */ if ((msg = queue->msg_list[SEND_MESSAGE].first)) { - req->kind = SEND_MESSAGE; put_req_message( req, msg ); receive_message( queue, msg ); return; } + set_req_data_size( req, 0 ); /* only sent messages can have data */ if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */ /* if requested, remove the last returned but not yet removed message */ @@ -831,8 +894,7 @@ if ((queue->wake_bits & QS_PAINT) && (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last)) { - req->kind = POST_MESSAGE; - req->type = 0; + req->type = MSG_POSTED; req->win = 0; req->msg = WM_PAINT; req->wparam = 0; @@ -848,8 +910,7 @@ if ((timer = find_expired_timer( queue, req->get_win, req->get_first, req->get_last, (req->flags & GET_MSG_REMOVE) ))) { - req->kind = POST_MESSAGE; - req->type = 0; + req->type = MSG_POSTED; req->win = timer->win; req->msg = timer->msg; req->wparam = timer->id; @@ -870,7 +931,8 @@ DECL_HANDLER(reply_message) { if (current->queue && current->queue->recv_result) - reply_message( current->queue, req->result, 0, req->remove ); + reply_message( current->queue, req->result, 0, req->remove, + get_req_data(req), get_req_data_size(req) ); else set_error( STATUS_ACCESS_DENIED ); } @@ -879,26 +941,40 @@ /* retrieve the reply for the last message sent */ DECL_HANDLER(get_message_reply) { - if (current->queue) req->result = get_message_reply( current->queue, req->cancel ); - else set_error( STATUS_ACCESS_DENIED ); -} + struct msg_queue *queue = current->queue; + size_t data_len = 0; - -/* check if we are processing a sent message */ -DECL_HANDLER(in_send_message) -{ - int flags = 0; - - if (current->queue) + if (queue) { - struct message_result *result = current->queue->recv_result; - if (result) + struct message_result *result = queue->send_result; + + set_error( STATUS_PENDING ); + req->result = 0; + + if (result && (result->replied || req->cancel)) { - flags |= ISMEX_SEND; /* FIXME */ - if (result->replied || !result->sender) flags |= ISMEX_REPLIED; + if (result->replied) + { + req->result = result->result; + set_error( result->error ); + if (result->data) + { + data_len = min( result->data_size, get_req_data_size(req) ); + memcpy( get_req_data(req), result->data, data_len ); + free( result->data ); + result->data = NULL; + result->data_size = 0; + } + } + queue->send_result = result->send_next; + result->sender = NULL; + if (!result->receiver) free_result( result ); + if (!queue->send_result || !queue->send_result->replied) + clear_queue_bits( queue, QS_SMRESULT ); } } - req->flags = flags; + else set_error( STATUS_ACCESS_DENIED ); + set_req_data_size( req, data_len ); }
diff --git a/server/request.h b/server/request.h index 12725b4..c9882b5 100644 --- a/server/request.h +++ b/server/request.h
@@ -175,7 +175,6 @@ DECL_HANDLER(get_message); DECL_HANDLER(reply_message); DECL_HANDLER(get_message_reply); -DECL_HANDLER(in_send_message); DECL_HANDLER(cleanup_window_queue); DECL_HANDLER(set_win_timer); DECL_HANDLER(kill_win_timer); @@ -302,7 +301,6 @@ (req_handler)req_get_message, (req_handler)req_reply_message, (req_handler)req_get_message_reply, - (req_handler)req_in_send_message, (req_handler)req_cleanup_window_queue, (req_handler)req_set_win_timer, (req_handler)req_kill_win_timer,
diff --git a/server/trace.c b/server/trace.c index 438121c..225be9c 100644 --- a/server/trace.c +++ b/server/trace.c
@@ -1457,17 +1457,19 @@ static void dump_send_message_request( const struct send_message_request *req ) { - fprintf( stderr, " kind=%d,", req->kind ); fprintf( stderr, " id=%p,", req->id ); fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " win=%d,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " wparam=%08x,", req->wparam ); fprintf( stderr, " lparam=%08x,", req->lparam ); - fprintf( stderr, " x=%04x,", req->x ); - fprintf( stderr, " y=%04x,", req->y ); + fprintf( stderr, " x=%d,", req->x ); + fprintf( stderr, " y=%d,", req->y ); fprintf( stderr, " time=%08x,", req->time ); - fprintf( stderr, " info=%08x", req->info ); + fprintf( stderr, " info=%08x,", req->info ); + fprintf( stderr, " timeout=%d,", req->timeout ); + fprintf( stderr, " data=" ); + cur_pos += dump_varargs_bytes( req ); } static void dump_get_message_request( const struct get_message_request *req ) @@ -1480,22 +1482,25 @@ static void dump_get_message_reply( const struct get_message_request *req ) { - fprintf( stderr, " kind=%d,", req->kind ); fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " win=%d,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " wparam=%08x,", req->wparam ); fprintf( stderr, " lparam=%08x,", req->lparam ); - fprintf( stderr, " x=%04x,", req->x ); - fprintf( stderr, " y=%04x,", req->y ); + fprintf( stderr, " x=%d,", req->x ); + fprintf( stderr, " y=%d,", req->y ); fprintf( stderr, " time=%08x,", req->time ); - fprintf( stderr, " info=%08x", req->info ); + fprintf( stderr, " info=%08x,", req->info ); + fprintf( stderr, " data=" ); + cur_pos += dump_varargs_bytes( req ); } static void dump_reply_message_request( const struct reply_message_request *req ) { fprintf( stderr, " result=%08x,", req->result ); - fprintf( stderr, " remove=%d", req->remove ); + fprintf( stderr, " remove=%d,", req->remove ); + fprintf( stderr, " data=" ); + cur_pos += dump_varargs_bytes( req ); } static void dump_get_message_reply_request( const struct get_message_reply_request *req ) @@ -1505,16 +1510,9 @@ static void dump_get_message_reply_reply( const struct get_message_reply_request *req ) { - fprintf( stderr, " result=%08x", req->result ); -} - -static void dump_in_send_message_request( const struct in_send_message_request *req ) -{ -} - -static void dump_in_send_message_reply( const struct in_send_message_request *req ) -{ - fprintf( stderr, " flags=%d", req->flags ); + fprintf( stderr, " result=%08x,", req->result ); + fprintf( stderr, " data=" ); + cur_pos += dump_varargs_bytes( req ); } static void dump_cleanup_window_queue_request( const struct cleanup_window_queue_request *req ) @@ -1739,7 +1737,6 @@ (dump_func)dump_get_message_request, (dump_func)dump_reply_message_request, (dump_func)dump_get_message_reply_request, - (dump_func)dump_in_send_message_request, (dump_func)dump_cleanup_window_queue_request, (dump_func)dump_set_win_timer_request, (dump_func)dump_kill_win_timer_request, @@ -1863,7 +1860,6 @@ (dump_func)dump_get_message_reply, (dump_func)0, (dump_func)dump_get_message_reply_reply, - (dump_func)dump_in_send_message_reply, (dump_func)0, (dump_func)0, (dump_func)0, @@ -1987,7 +1983,6 @@ "get_message", "reply_message", "get_message_reply", - "in_send_message", "cleanup_window_queue", "set_win_timer", "kill_win_timer",
diff --git a/windows/input.c b/windows/input.c index 62c7518..f371e61 100644 --- a/windows/input.c +++ b/windows/input.c
@@ -85,9 +85,8 @@ { SERVER_START_REQ( send_message ) { - req->kind = RAW_HW_MESSAGE; req->id = (void *)GetCurrentThreadId(); - req->type = 0; + req->type = MSG_HARDWARE_RAW; req->win = 0; req->msg = message; req->wparam = wParam; @@ -96,6 +95,7 @@ req->y = yPos; req->time = time; req->info = extraInfo; + req->timeout = 0; SERVER_CALL(); } SERVER_END_REQ;
diff --git a/windows/message.c b/windows/message.c index 7658e52..7134d04 100644 --- a/windows/message.c +++ b/windows/message.c
@@ -10,8 +10,9 @@ #include <sys/time.h> #include <sys/types.h> -#include "wine/winbase16.h" -#include "wine/winuser16.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" #include "message.h" #include "winerror.h" #include "wine/server.h" @@ -36,109 +37,8 @@ #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK -#define QMSG_WIN16 1 -#define QMSG_WIN32A 2 -#define QMSG_WIN32W 3 - static UINT doubleClickSpeed = 452; -static BOOL MSG_ConvertMsg( MSG *msg, int srcType, int dstType ); - - - -/* flag for messages that contain pointers */ -/* 16 messages per entry, messages 0..15 map to bits 0..15 */ - -#define SET(msg) (1 << ((msg) & 15)) - -static const unsigned short message_pointer_flags[] = -{ - /* 0x00 - 0x0f */ - SET(WM_CREATE) | SET(WM_GETTEXT) | SET(WM_SETTEXT), - /* 0x10 - 0x1f */ - SET(WM_WININICHANGE), - /* 0x20 - 0x2f */ - SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM), - /* 0x30 - 0x3f */ - SET(WM_COMPAREITEM), - /* 0x40 - 0x4f */ - SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) | SET(WM_NOTIFY), - /* 0x50 - 0x5f */ - SET(WM_HELP), - /* 0x60 - 0x6f */ - 0, - /* 0x70 - 0x7f */ - SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED), - /* 0x80 - 0x8f */ - SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE), - /* 0x90 - 0x9f */ - 0, - /* 0xa0 - 0xaf */ - 0, - /* 0xb0 - 0xbf */ - SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP), - /* 0xc0 - 0xcf */ - SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS), - /* 0xd0 - 0xdf */ - 0, - /* 0xe0 - 0xef */ - 0, - /* 0xf0 - 0xff */ - 0, - /* 0x100 - 0x10f */ - 0, - /* 0x110 - 0x11f */ - 0, - /* 0x120 - 0x12f */ - 0, - /* 0x130 - 0x13f */ - 0, - /* 0x140 - 0x14f */ - SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | SET(CB_INSERTSTRING) | - SET(CB_FINDSTRING) | SET(CB_SELECTSTRING), - /* 0x150 - 0x15f */ - SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT), - /* 0x160 - 0x16f */ - 0, - /* 0x170 - 0x17f */ - 0, - /* 0x180 - 0x18f */ - SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) | - SET(LB_DIR) | SET(LB_FINDSTRING), - /* 0x190 - 0x19f */ - SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT), - /* 0x1a0 - 0x1af */ - SET(LB_FINDSTRINGEXACT), - /* 0x1b0 - 0x1bf */ - 0, - /* 0x1c0 - 0x1cf */ - 0, - /* 0x1d0 - 0x1df */ - 0, - /* 0x1e0 - 0x1ef */ - 0, - /* 0x1f0 - 0x1ff */ - 0, - /* 0x200 - 0x20f */ - 0, - /* 0x210 - 0x21f */ - 0, - /* 0x220 - 0x22f */ - SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) | - SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE) -}; - -#undef SET - -/*********************************************************************** - * is_pointer_message - */ -inline static int is_pointer_message( UINT message ) -{ - if (message >= 8*sizeof(message_pointer_flags)) return FALSE; - return (message_pointer_flags[message / 16] & (1 << (message & 15))) != 0; -} - /*********************************************************************** * is_keyboard_message @@ -177,50 +77,14 @@ /*********************************************************************** - * map_wparam_AtoW + * process_sent_messages * - * Convert the wparam of an ASCII message to Unicode. + * Process all pending sent messages. */ -static WPARAM map_wparam_AtoW( UINT message, WPARAM wparam ) +inline static void process_sent_messages(void) { - if (message == WM_CHARTOITEM || - message == EM_SETPASSWORDCHAR || - message == WM_CHAR || - message == WM_DEADCHAR || - message == WM_SYSCHAR || - message == WM_SYSDEADCHAR || - message == WM_MENUCHAR) - { - char ch = LOWORD(wparam); - WCHAR wch; - MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1); - wparam = MAKEWPARAM( wch, HIWORD(wparam) ); - } - return wparam; -} - - -/*********************************************************************** - * map_wparam_WtoA - * - * Convert the wparam of a Unicode message to ASCII. - */ -static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam ) -{ - if (message == WM_CHARTOITEM || - message == EM_SETPASSWORDCHAR || - message == WM_CHAR || - message == WM_DEADCHAR || - message == WM_SYSCHAR || - message == WM_SYSDEADCHAR || - message == WM_MENUCHAR) - { - WCHAR wch = LOWORD(wparam); - char ch; - WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL ); - wparam = MAKEWPARAM( ch, HIWORD(wparam) ); - } - return wparam; + MSG msg; + MSG_peek_message( &msg, 0, 0, 0, GET_MSG_REMOVE | GET_MSG_SENT_ONLY ); } @@ -229,13 +93,12 @@ * * store a hardware message in the thread queue */ -static void queue_hardware_message( MSG *msg, ULONG_PTR extra_info, enum message_kind kind ) +static void queue_hardware_message( MSG *msg, ULONG_PTR extra_info, enum message_type type ) { SERVER_START_REQ( send_message ) { - req->kind = kind; + req->type = type; req->id = (void *)GetWindowThreadProcessId( msg->hwnd, NULL ); - req->type = 0; req->win = msg->hwnd; req->msg = msg->message; req->wparam = msg->wParam; @@ -244,6 +107,7 @@ req->y = msg->pt.y; req->time = msg->time; req->info = extra_info; + req->timeout = 0; SERVER_CALL(); } SERVER_END_REQ; @@ -283,7 +147,7 @@ * * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function */ -static void MSG_JournalPlayBackMsg(void) +void MSG_JournalPlayBackMsg(void) { EVENTMSG tmpMsg; MSG msg; @@ -324,7 +188,7 @@ msg.lParam |= 0x01000000; msg.pt.x = msg.pt.y = 0; - queue_hardware_message( &msg, 0, RAW_HW_MESSAGE ); + queue_hardware_message( &msg, 0, MSG_HARDWARE_RAW ); } else if ((tmpMsg.message>= WM_MOUSEFIRST) && (tmpMsg.message <= WM_MOUSELAST)) { @@ -355,7 +219,7 @@ msg.pt.x = tmpMsg.paramL; msg.pt.y = tmpMsg.paramH; - queue_hardware_message( &msg, 0, RAW_HW_MESSAGE ); + queue_hardware_message( &msg, 0, MSG_HARDWARE_RAW ); } HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg); } @@ -626,8 +490,8 @@ * * returns TRUE if the contents of 'msg' should be passed to the application */ -static BOOL process_raw_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd_filter, - UINT first, UINT last, BOOL remove ) +BOOL MSG_process_raw_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd_filter, + UINT first, UINT last, BOOL remove ) { if (is_keyboard_message( msg->message )) { @@ -648,22 +512,22 @@ GetWindowThreadProcessId( msg->hwnd, NULL ) != GetCurrentThreadId()) { /* queue it for later, or for another thread */ - queue_hardware_message( msg, extra_info, COOKED_HW_MESSAGE ); + queue_hardware_message( msg, extra_info, MSG_HARDWARE_COOKED ); return FALSE; } /* save the message in the cooked queue if we didn't want to remove it */ - if (!remove) queue_hardware_message( msg, extra_info, COOKED_HW_MESSAGE ); + if (!remove) queue_hardware_message( msg, extra_info, MSG_HARDWARE_COOKED ); return TRUE; } /*********************************************************************** - * process_cooked_hardware_message + * MSG_process_cooked_hardware_message * * returns TRUE if the contents of 'msg' should be passed to the application */ -static BOOL process_cooked_hardware_message( MSG *msg, BOOL remove ) +BOOL MSG_process_cooked_hardware_message( MSG *msg, BOOL remove ) { if (is_keyboard_message( msg->message )) return process_cooked_keyboard_message( msg, remove ); @@ -676,249 +540,6 @@ } -/*********************************************************************** - * handle_sent_message - * - * Handle the reception of a sent message by calling the corresponding window proc - */ -static void handle_sent_message( MSG *msg, int type, ULONG_PTR extra_info ) -{ - LRESULT result = 0; - MESSAGEQUEUE *queue = QUEUE_Current(); - ULONG_PTR old_extra_info = queue->GetMessageExtraInfoVal; /* save ExtraInfo */ - WND *wndPtr = WIN_FindWndPtr( msg->hwnd ); - - TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n", - msg->hwnd, msg->message, SPY_GetMsgName(msg->message), - msg->wParam, msg->lParam ); - - queue->GetMessageExtraInfoVal = extra_info; - - /* call the right version of CallWindowProcXX */ - switch(type) - { - case QMSG_WIN16: - result = CallWindowProc16( (WNDPROC16)wndPtr->winproc, - (HWND16) msg->hwnd, - (UINT16) msg->message, - LOWORD(msg->wParam), - msg->lParam ); - break; - case QMSG_WIN32A: - result = CallWindowProcA( wndPtr->winproc, msg->hwnd, msg->message, - msg->wParam, msg->lParam ); - break; - case QMSG_WIN32W: - result = CallWindowProcW( wndPtr->winproc, msg->hwnd, msg->message, - msg->wParam, msg->lParam ); - break; - } - - queue->GetMessageExtraInfoVal = old_extra_info; /* Restore extra info */ - WIN_ReleaseWndPtr(wndPtr); - - SERVER_START_REQ( reply_message ) - { - req->result = result; - req->remove = 1; - SERVER_CALL(); - } - SERVER_END_REQ; -} - - -/*********************************************************************** - * process_sent_messages - * - * Process all pending sent messages - */ -static void process_sent_messages(void) -{ - MSG msg; - int type; - unsigned int res; - ULONG_PTR extra_info; - - for (;;) - { - SERVER_START_REQ( get_message ) - { - req->flags = GET_MSG_REMOVE | GET_MSG_SENT_ONLY; - req->get_win = 0; - req->get_first = 0; - req->get_last = ~0; - if (!(res = SERVER_CALL())) - { - type = req->type; - msg.hwnd = req->win; - msg.message = req->msg; - msg.wParam = req->wparam; - msg.lParam = req->lparam; - msg.time = req->time; - msg.pt.x = req->x; - msg.pt.y = req->y; - extra_info = req->info; - } - } - SERVER_END_REQ; - - if (res) break; - handle_sent_message( &msg, type, extra_info ); - } -} - - - -/*********************************************************************** - * peek_message - * - * Peek for a message matching the given parameters. Return FALSE if none available. - */ -static BOOL peek_message( HWND hwnd, UINT first, UINT last, int flags, int type, - MSG *msg, ULONG_PTR *extra_info ) -{ - BOOL ret = FALSE; - enum message_kind kind; - int msg_type; - - if (!first && !last) last = ~0; - - for (;;) - { - SERVER_START_REQ( get_message ) - { - req->flags = flags; - req->get_win = hwnd; - req->get_first = first; - req->get_last = last; - if ((ret = !SERVER_CALL())) - { - kind = req->kind; - msg_type = req->type; - msg->hwnd = req->win; - msg->message = req->msg; - msg->wParam = req->wparam; - msg->lParam = req->lparam; - msg->time = req->time; - msg->pt.x = req->x; - msg->pt.y = req->y; - *extra_info = req->info; - } - } - SERVER_END_REQ; - - if (!ret) return FALSE; - - switch(kind) - { - case SEND_MESSAGE: - handle_sent_message( msg, msg_type, *extra_info ); - continue; - case POST_MESSAGE: - /* try to convert message to requested type */ - if (!MSG_ConvertMsg( msg, msg_type, type )) - { - ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n", - SPY_GetMsgName(msg->message)); - /* remove it */ - flags |= GET_MSG_REMOVE_LAST; - continue; - } - break; - case RAW_HW_MESSAGE: - if (!process_raw_hardware_message( msg, *extra_info, - hwnd, first, last, flags & GET_MSG_REMOVE )) - continue; - /* fall through */ - case COOKED_HW_MESSAGE: - if (!process_cooked_hardware_message( msg, flags & GET_MSG_REMOVE )) - { - flags |= GET_MSG_REMOVE_LAST; - continue; - } - break; - } - - /* now we got something */ - TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n", - msg->hwnd, msg->message, SPY_GetMsgName(msg->message), - msg->wParam, msg->lParam ); - return TRUE; - } -} - - -/*********************************************************************** - * wait_queue_bits - * - * See "Windows Internals", p.447 - * - * return values: - * 0 if exit with timeout - * 1 otherwise - */ -static int wait_queue_bits( WORD bits, DWORD timeout ) -{ - MESSAGEQUEUE *queue; - - if (!(queue = QUEUE_Current())) return 0; - - TRACE("q %04x waiting for %04x\n", queue->self, bits); - - for (;;) - { - unsigned int wake_bits = 0, changed_bits = 0; - DWORD dwlc; - - SERVER_START_REQ( set_queue_mask ) - { - req->wake_mask = QS_SENDMESSAGE; - req->changed_mask = bits | QS_SENDMESSAGE; - req->skip_wait = 1; - if (!SERVER_CALL()) - { - wake_bits = req->wake_bits; - changed_bits = req->changed_bits; - } - } - SERVER_END_REQ; - - if (changed_bits & bits) - { - /* One of the bits is set; we can return */ - return 1; - } - if (wake_bits & QS_SENDMESSAGE) - { - /* Process the sent message immediately */ - process_sent_messages(); - continue; /* nested sm crux */ - } - - TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n", - queue->self, bits, wake_bits, changed_bits ); - - ReleaseThunkLock( &dwlc ); - if (dwlc) TRACE_(msg)("had win16 lock\n"); - - if (USER_Driver.pMsgWaitForMultipleObjectsEx) - USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 ); - else - WaitForSingleObject( queue->server_queue, timeout ); - if (dwlc) RestoreThunkLock( dwlc ); - } -} - - -/********************************************************************** - * SetDoubleClickTime (USER.20) - */ -void WINAPI SetDoubleClickTime16( UINT16 interval ) -{ - SetDoubleClickTime( interval ); -} - - /********************************************************************** * SetDoubleClickTime (USER32.@) */ @@ -930,15 +551,6 @@ /********************************************************************** - * GetDoubleClickTime (USER.21) - */ -UINT16 WINAPI GetDoubleClickTime16(void) -{ - return doubleClickSpeed; -} - - -/********************************************************************** * GetDoubleClickTime (USER32.@) */ UINT WINAPI GetDoubleClickTime(void) @@ -948,986 +560,6 @@ /*********************************************************************** - * MSG_SendMessageInterThread - * - * Implementation of an inter-task SendMessage. - * Return values: - * 0 if error or timeout - * 1 if successful - */ -static LRESULT MSG_SendMessageInterThread( DWORD dest_tid, HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam, - DWORD timeout, WORD type, - LRESULT *pRes) -{ - BOOL ret; - int iWndsLocks; - LRESULT result = 0; - - TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam ); - - SERVER_START_REQ( send_message ) - { - req->kind = SEND_MESSAGE; - req->id = (void *)dest_tid; - req->type = type; - req->win = hwnd; - req->msg = msg; - req->wparam = wParam; - req->lparam = lParam; - req->x = 0; - req->y = 0; - req->time = GetCurrentTime(); - req->info = 0; - ret = !SERVER_CALL_ERR(); - } - SERVER_END_REQ; - if (!ret) return 0; - - iWndsLocks = WIN_SuspendWndsLock(); - - /* wait for the result */ - wait_queue_bits( QS_SMRESULT, timeout ); - - SERVER_START_REQ( get_message_reply ) - { - req->cancel = 1; - if ((ret = !SERVER_CALL_ERR())) result = req->result; - } - SERVER_END_REQ; - - TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n", - hwnd, msg, SPY_GetMsgName(msg), wParam, lParam, result, GetLastError() ); - - if (!ret && (GetLastError() == ERROR_IO_PENDING)) - { - if (timeout == INFINITE) ERR("no timeout but no result\n"); - SetLastError(0); /* timeout */ - } - - if (pRes) *pRes = result; - - WIN_RestoreWndsLock(iWndsLocks); - return ret; -} - - -/*********************************************************************** - * ReplyMessage (USER.115) - */ -void WINAPI ReplyMessage16( LRESULT result ) -{ - ReplyMessage( result ); -} - -/*********************************************************************** - * ReplyMessage (USER32.@) - */ -BOOL WINAPI ReplyMessage( LRESULT result ) -{ - BOOL ret; - SERVER_START_REQ( reply_message ) - { - req->result = result; - req->remove = 0; - ret = !SERVER_CALL_ERR(); - } - SERVER_END_REQ; - return ret; -} - -/*********************************************************************** - * MSG_ConvertMsg - */ -static BOOL MSG_ConvertMsg( MSG *msg, int srcType, int dstType ) -{ - if (srcType == QMSG_WIN32A || dstType == QMSG_WIN32A) - { - /* posted messages are always either Win16 or Unicode Win32, - * QMSG_WIN32A is only for sent messages */ - ERR( "invalid type %d/%d\n", srcType, dstType ); - return FALSE; - } - - if (!srcType || srcType == dstType) return TRUE; - - if (srcType == QMSG_WIN16) - { - if (dstType == QMSG_WIN32W) - { - switch ( WINPROC_MapMsg16To32W( msg->hwnd, msg->message, msg->wParam, - &msg->message, &msg->wParam, &msg->lParam ) ) - { - case 0: - return TRUE; - case 1: - /* Pointer messages were mapped --> need to free allocated memory and fail */ - WINPROC_UnmapMsg16To32W( msg->hwnd, msg->message, msg->wParam, msg->lParam, 0 ); - default: - return FALSE; - } - } - } - else if (srcType == QMSG_WIN32W) - { - if (dstType == QMSG_WIN16) - { - UINT16 msg16; - MSGPARAM16 mp16; - - mp16.lParam = msg->lParam; - switch ( WINPROC_MapMsg32WTo16( msg->hwnd, msg->message, msg->wParam, - &msg16, &mp16.wParam, &mp16.lParam ) ) - { - case 0: - msg->message = msg16; - msg->wParam = mp16.wParam; - msg->lParam = mp16.lParam; - return TRUE; - case 1: - /* Pointer messages were mapped --> need to free allocated memory and fail */ - WINPROC_UnmapMsg32WTo16( msg->hwnd, msg->message, msg->wParam, msg->lParam, &mp16 ); - default: - return FALSE; - } - } - } - - FIXME( "Invalid message type(s): %d / %d\n", srcType, dstType ); - return FALSE; -} - - -/*********************************************************************** - * MSG_PeekMessage - */ -static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, - DWORD first, DWORD last, WORD flags, BOOL peek ) -{ - int mask, msg_flags = 0; - MESSAGEQUEUE *msgQueue; - int iWndsLocks; - MSG msg; - ULONG_PTR extra_info; - - mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */ - if (first || last) - { - if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; - if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) || - ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE; - if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER; - if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER; - if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT; - } - else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT; - - if (IsTaskLocked16()) flags |= PM_NOYIELD; - - iWndsLocks = WIN_SuspendWndsLock(); - - /* check for graphics events */ - if (USER_Driver.pMsgWaitForMultipleObjectsEx) - USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); - - if (flags & PM_REMOVE) msg_flags |= GET_MSG_REMOVE; - - while(1) - { - if (peek_message( hwnd, first, last, msg_flags, type, &msg, &extra_info )) - { - /* need to fill the window handle for WM_PAINT message */ - if (msg.message == WM_PAINT) - { - if ((msg.hwnd = WIN_FindWinToRepaint( hwnd ))) - { - if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON )) - { - msg.message = WM_PAINTICON; - msg.wParam = 1; - } - if( !hwnd || msg.hwnd == hwnd || IsChild(hwnd,msg.hwnd) ) - { - /* clear internal paint flag */ - RedrawWindow( msg.hwnd, NULL, 0, - RDW_NOINTERNALPAINT | RDW_NOCHILDREN ); - break; - } - } - } - else break; - } - - /* FIXME: should be done before checking for hw events */ - MSG_JournalPlayBackMsg(); - - if (peek) - { -#if 0 /* FIXME */ - if (!(flags & PM_NOYIELD)) UserYield16(); -#endif - WIN_RestoreWndsLock(iWndsLocks); - return FALSE; - } - - wait_queue_bits( mask, INFINITE ); - } - - WIN_RestoreWndsLock(iWndsLocks); - - if ((msgQueue = QUEUE_Current())) - { - msgQueue->GetMessageTimeVal = msg.time; - msgQueue->GetMessagePosVal = MAKELONG( msg.pt.x, msg.pt.y ); - msgQueue->GetMessageExtraInfoVal = extra_info; - } - - /* We got a message */ - if (flags & PM_REMOVE) - { - if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) - { - BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff]; - - if (!(*p & 0x80)) - *p ^= 0x01; - *p |= 0x80; - } - else if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) - QueueKeyStateTable[msg.wParam & 0xff] &= ~0x80; - } - - /* copy back our internal safe copy of message data to msg_out. - * msg_out is a variable from the *program*, so it can't be used - * internally as it can get "corrupted" by our use of SendMessage() - * (back to the program) inside the message handling itself. */ - *msg_out = msg; - if (peek) - return TRUE; - - else - return (msg.message != WM_QUIT); -} - -/*********************************************************************** - * MSG_InternalGetMessage - * - * GetMessage() function for internal use. Behave like GetMessage(), - * but also call message filters and optionally send WM_ENTERIDLE messages. - * 'hwnd' must be the handle of the dialog or menu window. - * 'code' is the message filter value (MSGF_??? codes). - */ -BOOL MSG_InternalGetMessage( MSG *msg, HWND hwnd, HWND hwndOwner, UINT first, UINT last, - WPARAM code, WORD flags, BOOL sendIdle, BOOL* idleSent ) -{ - for (;;) - { - if (sendIdle) - { - if (!MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, TRUE )) - { - /* No message present -> send ENTERIDLE and wait */ - if (IsWindow(hwndOwner)) - { - SendMessageA( hwndOwner, WM_ENTERIDLE, - code, (LPARAM)hwnd ); - - if (idleSent!=NULL) - *idleSent=TRUE; - } - MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE ); - } - } - else /* Always wait for a message */ - MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE ); - - /* Call message filters */ - - if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER )) - { - MSG tmp_msg = *msg; - - if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)&tmp_msg ) || - HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)&tmp_msg )) - { - /* Message filtered -> remove it from the queue if it's still there. */ - if (!(flags & PM_REMOVE)) - MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, PM_REMOVE, TRUE ); - continue; - } - } - /* need to return an ASCII message (FIXME) */ - msg->wParam = map_wparam_WtoA( msg->message, msg->wParam ); - return (msg->message != WM_QUIT); - } -} - - -/*********************************************************************** - * PeekMessage32 (USER.819) - */ -BOOL16 WINAPI PeekMessage32_16( SEGPTR msg16_32, HWND16 hwnd, - UINT16 first, UINT16 last, UINT16 flags, - BOOL16 wHaveParamHigh ) -{ - BOOL ret; - MSG32_16 *lpmsg16_32 = MapSL(msg16_32); - MSG msg; - - ret = MSG_PeekMessage( QMSG_WIN16, &msg, hwnd, first, last, flags, TRUE ); - - lpmsg16_32->msg.hwnd = msg.hwnd; - lpmsg16_32->msg.message = msg.message; - lpmsg16_32->msg.wParam = LOWORD(msg.wParam); - lpmsg16_32->msg.lParam = msg.lParam; - lpmsg16_32->msg.time = msg.time; - lpmsg16_32->msg.pt.x = (INT16)msg.pt.x; - lpmsg16_32->msg.pt.y = (INT16)msg.pt.y; - - if ( wHaveParamHigh ) - lpmsg16_32->wParamHigh = HIWORD(msg.wParam); - - HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg16_32 ); - return ret; -} - -/*********************************************************************** - * PeekMessage (USER.109) - */ -BOOL16 WINAPI PeekMessage16( SEGPTR msg, HWND16 hwnd, - UINT16 first, UINT16 last, UINT16 flags ) -{ - return PeekMessage32_16( msg, hwnd, first, last, flags, FALSE ); -} - -/*********************************************************************** - * PeekMessageA (USER32.@) - */ -BOOL WINAPI PeekMessageA( LPMSG lpmsg, HWND hwnd, UINT min, UINT max, UINT flags ) -{ - BOOL ret = PeekMessageW( lpmsg, hwnd, min, max, flags ); - if (ret) lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam ); - return ret; -} - -/*********************************************************************** - * PeekMessageW (USER32.@) Check queue for messages - * - * Checks for a message in the thread's queue, filtered as for - * GetMessage(). Returns immediately whether a message is available - * or not. - * - * Whether a retrieved message is removed from the queue is set by the - * _wRemoveMsg_ flags, which should be one of the following values: - * - * PM_NOREMOVE Do not remove the message from the queue. - * - * PM_REMOVE Remove the message from the queue. - * - * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to - * request that the system not yield control during PeekMessage(); - * however applications may not rely on scheduling behavior. - * - * RETURNS - * - * Nonzero if a message is available and is retrieved, zero otherwise. - * - * CONFORMANCE - * - * ECMA-234, Win32 - * - */ -BOOL WINAPI PeekMessageW( - LPMSG lpmsg, /* [out] buffer to receive message */ - HWND hwnd, /* [in] restrict to messages for hwnd */ - UINT min, /* [in] minimum message to receive */ - UINT max, /* [in] maximum message to receive */ - UINT wRemoveMsg /* [in] removal flags */ -) -{ - BOOL ret = MSG_PeekMessage( QMSG_WIN32W, lpmsg, hwnd, min, max, wRemoveMsg, TRUE ); - if (ret) HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, - wRemoveMsg & PM_REMOVE, (LPARAM)lpmsg ); - return ret; -} - - -/*********************************************************************** - * GetMessage32 (USER.820) - */ -BOOL16 WINAPI GetMessage32_16( SEGPTR msg16_32, HWND16 hWnd, UINT16 first, - UINT16 last, BOOL16 wHaveParamHigh ) -{ - MSG32_16 *lpmsg16_32 = MapSL(msg16_32); - MSG msg; - - MSG_PeekMessage( QMSG_WIN16, &msg, hWnd, first, last, PM_REMOVE, FALSE ); - - lpmsg16_32->msg.hwnd = msg.hwnd; - lpmsg16_32->msg.message = msg.message; - lpmsg16_32->msg.wParam = LOWORD(msg.wParam); - lpmsg16_32->msg.lParam = msg.lParam; - lpmsg16_32->msg.time = msg.time; - lpmsg16_32->msg.pt.x = (INT16)msg.pt.x; - lpmsg16_32->msg.pt.y = (INT16)msg.pt.y; - - if ( wHaveParamHigh ) - lpmsg16_32->wParamHigh = HIWORD(msg.wParam); - - TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n", - lpmsg16_32->msg.message, hWnd, first, last ); - - HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, PM_REMOVE, (LPARAM)msg16_32 ); - return lpmsg16_32->msg.message != WM_QUIT; -} - -/*********************************************************************** - * GetMessage (USER.108) - */ -BOOL16 WINAPI GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last) -{ - return GetMessage32_16( msg, hwnd, first, last, FALSE ); -} - -/*********************************************************************** - * GetMessageA (USER32.@) - */ -BOOL WINAPI GetMessageA( MSG *lpmsg, HWND hwnd, UINT min, UINT max ) -{ - GetMessageW( lpmsg, hwnd, min, max ); - lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam ); - return lpmsg->message != WM_QUIT; -} - -/*********************************************************************** - * GetMessageW (USER32.@) Retrieve next message - * - * GetMessage retrieves the next event from the calling thread's - * queue and deposits it in *lpmsg. - * - * If _hwnd_ is not NULL, only messages for window _hwnd_ and its - * children as specified by IsChild() are retrieved. If _hwnd_ is NULL - * all application messages are retrieved. - * - * _min_ and _max_ specify the range of messages of interest. If - * min==max==0, no filtering is performed. Useful examples are - * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and - * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input. - * - * WM_PAINT messages are not removed from the queue; they remain until - * processed. Other messages are removed from the queue. - * - * RETURNS - * - * -1 on error, 0 if message is WM_QUIT, nonzero otherwise. - * - * CONFORMANCE - * - * ECMA-234, Win32 - * - */ -BOOL WINAPI GetMessageW( - MSG* lpmsg, /* [out] buffer to receive message */ - HWND hwnd, /* [in] restrict to messages for hwnd */ - UINT min, /* [in] minimum message to receive */ - UINT max /* [in] maximum message to receive */ -) -{ - MSG_PeekMessage( QMSG_WIN32W, lpmsg, hwnd, min, max, PM_REMOVE, FALSE ); - - TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n", - lpmsg->message, hwnd, min, max ); - - HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, PM_REMOVE, (LPARAM)lpmsg ); - return lpmsg->message != WM_QUIT; -} - -/*********************************************************************** - * MSG_PostToQueue - */ -static BOOL MSG_PostToQueue( DWORD tid, int type, HWND hwnd, - UINT message, WPARAM wParam, LPARAM lParam ) -{ - unsigned int res; - - TRACE( "posting %x %x (%s) %x %lx\n", hwnd, message, SPY_GetMsgName(message), wParam, lParam ); - - SERVER_START_REQ( send_message ) - { - req->kind = POST_MESSAGE; - req->id = (void *)tid; - req->type = type; - req->win = hwnd; - req->msg = message; - req->wparam = wParam; - req->lparam = lParam; - req->x = 0; - req->y = 0; - req->time = GetCurrentTime(); - req->info = 0; - res = SERVER_CALL(); - } - SERVER_END_REQ; - - if (res) - { - if (res == STATUS_INVALID_PARAMETER) - SetLastError( ERROR_INVALID_THREAD_ID ); - else - SetLastError( RtlNtStatusToDosError(res) ); - } - return !res; -} - - -/*********************************************************************** - * MSG_PostMessage - */ -static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam ) -{ - WND *wndPtr; - - if (hwnd == HWND_BROADCAST) - { - WND *pDesktop = WIN_GetDesktop(); - TRACE("HWND_BROADCAST !\n"); - - for (wndPtr=WIN_LockWndPtr(pDesktop->child); wndPtr; WIN_UpdateWndPtr(&wndPtr,wndPtr->next)) - { - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - { - TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n", - wndPtr->hwndSelf, message, wParam, lParam); - MSG_PostToQueue( GetWindowThreadProcessId( wndPtr->hwndSelf, NULL ), type, - wndPtr->hwndSelf, message, wParam, lParam ); - } - } - WIN_ReleaseDesktop(); - TRACE("End of HWND_BROADCAST !\n"); - return TRUE; - } - - return MSG_PostToQueue( GetWindowThreadProcessId( hwnd, NULL ), - type, hwnd, message, wParam, lParam ); -} - - -/*********************************************************************** - * PostMessage (USER.110) - */ -BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam, - LPARAM lParam ) -{ - return (BOOL16) MSG_PostMessage( QMSG_WIN16, hwnd, message, wParam, lParam ); -} - -/*********************************************************************** - * PostMessageA (USER32.@) - */ -BOOL WINAPI PostMessageA( HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam ) -{ - return PostMessageW( hwnd, message, map_wparam_AtoW( message, wParam ), lParam ); -} - -/*********************************************************************** - * PostMessageW (USER32.@) - */ -BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam ) -{ - /* See thread on wine-devel around 6.2.2001. Basically posted messages - * that are known to contain pointers are dropped by the Windows 32bit - * PostMessage() with return FALSE; and invalid parameter last error. - * (tested against NT4 by Gerard Patel) - */ - if (is_pointer_message(message)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return MSG_PostMessage( QMSG_WIN32W, hwnd, message, wParam, lParam ); -} - -/*********************************************************************** - * PostAppMessage (USER.116) - * PostAppMessage16 (USER32.@) - */ -BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, - WPARAM16 wParam, LPARAM lParam ) -{ - TDB *pTask = TASK_GetPtr( hTask ); - if (!pTask) return FALSE; - return MSG_PostToQueue( (DWORD)pTask->teb->tid, QMSG_WIN16, 0, message, wParam, lParam ); -} - -/********************************************************************** - * PostThreadMessageA (USER32.@) - */ -BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message, - WPARAM wParam, LPARAM lParam ) -{ - return PostThreadMessageW( idThread, message, map_wparam_AtoW( message, wParam ), lParam ); -} - -/********************************************************************** - * PostThreadMessageW (USER32.@) - */ -BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message, - WPARAM wParam, LPARAM lParam ) -{ - if (is_pointer_message( message )) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - return MSG_PostToQueue( idThread, QMSG_WIN32W, 0, message, wParam, lParam ); -} - - -/************************************************************************ - * MSG_CallWndProcHook32 - */ -static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode ) -{ - CWPSTRUCT cwp; - - cwp.lParam = pmsg->lParam; - cwp.wParam = pmsg->wParam; - cwp.message = pmsg->message; - cwp.hwnd = pmsg->hwnd; - - if (bUnicode) HOOK_CallHooksW(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp); - else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); - - pmsg->lParam = cwp.lParam; - pmsg->wParam = cwp.wParam; - pmsg->message = cwp.message; - pmsg->hwnd = cwp.hwnd; -} - - -/*********************************************************************** - * MSG_SendMessage - * - * return values: 0 if timeout occurs - * 1 otherwise - */ -static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam, DWORD timeout, WORD type, - LRESULT *pRes) -{ - WND * wndPtr = 0; - WND **list, **ppWnd; - LRESULT ret = 1; - DWORD dest_tid; - WNDPROC winproc; - - if (pRes) *pRes = 0; - - if (hwnd == HWND_BROADCAST|| hwnd == HWND_TOPMOST) - { - if (pRes) *pRes = 1; - - if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) - { - WIN_ReleaseDesktop(); - return 1; - } - WIN_ReleaseDesktop(); - - TRACE("HWND_BROADCAST !\n"); - for (ppWnd = list; *ppWnd; ppWnd++) - { - WIN_UpdateWndPtr(&wndPtr,*ppWnd); - if (!IsWindow(wndPtr->hwndSelf)) continue; - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - { - TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n", - wndPtr->hwndSelf, msg, (DWORD)wParam, lParam); - MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam, - timeout, type, pRes); - } - } - WIN_ReleaseWndPtr(wndPtr); - WIN_ReleaseWinArray(list); - TRACE("End of HWND_BROADCAST !\n"); - return 1; - } - - if (HOOK_IsHooked( WH_CALLWNDPROC )) - { - switch(type) - { - case QMSG_WIN16: - { - LPCWPSTRUCT16 pmsg; - - if ((pmsg = SEGPTR_NEW(CWPSTRUCT16))) - { - pmsg->hwnd = hwnd & 0xffff; - pmsg->message= msg & 0xffff; - pmsg->wParam = wParam & 0xffff; - pmsg->lParam = lParam; - HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, - (LPARAM)SEGPTR_GET(pmsg) ); - hwnd = pmsg->hwnd; - msg = pmsg->message; - wParam = pmsg->wParam; - lParam = pmsg->lParam; - SEGPTR_FREE( pmsg ); - } - } - break; - case QMSG_WIN32A: - MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); - break; - case QMSG_WIN32W: - MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); - break; - } - } - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) - { - WARN("invalid hwnd %04x\n", hwnd ); - return 0; - } - if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) - { - WIN_ReleaseWndPtr( wndPtr ); - return 0; /* Don't send anything if the task is dying */ - } - winproc = (WNDPROC)wndPtr->winproc; - WIN_ReleaseWndPtr( wndPtr ); - - if (type != QMSG_WIN16) - SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); - else - SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam ); - - dest_tid = GetWindowThreadProcessId( hwnd, NULL ); - if (dest_tid && dest_tid != GetCurrentThreadId()) - { - ret = MSG_SendMessageInterThread( dest_tid, hwnd, msg, - wParam, lParam, timeout, type, pRes ); - } - else - { - LRESULT res = 0; - - /* Call the right CallWindowProc flavor */ - switch(type) - { - case QMSG_WIN16: - res = CallWindowProc16( (WNDPROC16)winproc, hwnd, msg, wParam, lParam ); - break; - case QMSG_WIN32A: - res = CallWindowProcA( winproc, hwnd, msg, wParam, lParam ); - break; - case QMSG_WIN32W: - res = CallWindowProcW( winproc, hwnd, msg, wParam, lParam ); - break; - } - if (pRes) *pRes = res; - } - - if (type != QMSG_WIN16) - SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam ); - else - SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam ); - - return ret; -} - - -/*********************************************************************** - * SendMessage (USER.111) - */ -LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, - LPARAM lParam) -{ - LRESULT res; - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN16, &res); - return res; -} - - -/*********************************************************************** - * SendMessageA (USER32.@) - */ -LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam ) - { - LRESULT res; - - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, &res); - - return res; -} - - -/*********************************************************************** - * SendMessageW (USER32.@) Send Window Message - * - * Sends a message to the window procedure of the specified window. - * SendMessage() will not return until the called window procedure - * either returns or calls ReplyMessage(). - * - * Use PostMessage() to send message and return immediately. A window - * procedure may use InSendMessage() to detect - * SendMessage()-originated messages. - * - * Applications which communicate via HWND_BROADCAST may use - * RegisterWindowMessage() to obtain a unique message to avoid conflicts - * with other applications. - * - * CONFORMANCE - * - * ECMA-234, Win32 - */ -LRESULT WINAPI SendMessageW( - HWND hwnd, /* [in] Window to send message to. If HWND_BROADCAST, - the message will be sent to all top-level windows. */ - - UINT msg, /* [in] message */ - WPARAM wParam, /* [in] message parameter */ - LPARAM lParam /* [in] additional message parameter */ -) { - LRESULT res; - - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, &res); - - return res; -} - - -/*********************************************************************** - * SendMessageTimeout (not a WINAPI) - */ -LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, - LPARAM lParam, UINT16 flags, - UINT16 timeout, LPWORD resultp) -{ - LRESULT ret; - LRESULT msgRet; - - /* FIXME: need support for SMTO_BLOCK */ - - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN16, &msgRet); - if (resultp) *resultp = (WORD) msgRet; - return ret; -} - - -/*********************************************************************** - * SendMessageTimeoutA (USER32.@) - */ -LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam, UINT flags, - UINT timeout, LPDWORD resultp) -{ - LRESULT ret; - LRESULT msgRet; - - /* FIXME: need support for SMTO_BLOCK */ - - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32A, &msgRet); - - if (resultp) *resultp = (DWORD) msgRet; - return ret; -} - - -/*********************************************************************** - * SendMessageTimeoutW (USER32.@) - */ -LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam, UINT flags, - UINT timeout, LPDWORD resultp) -{ - LRESULT ret; - LRESULT msgRet; - - /* FIXME: need support for SMTO_BLOCK */ - - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32W, &msgRet); - - if (resultp) *resultp = (DWORD) msgRet; - return ret; -} - - -/*********************************************************************** - * SendNotifyMessageA (USER32.@) - */ -BOOL WINAPI SendNotifyMessageA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - return SendNotifyMessageW( hwnd, msg, map_wparam_AtoW( msg, wParam ), lParam ); -} - - -/*********************************************************************** - * SendNotifyMessageW (USER32.@) - */ -BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - if (is_pointer_message(msg)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return MSG_SendMessage( hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, NULL ); -} - - -/*********************************************************************** - * SendMessageCallbackA (USER32.@) - */ -BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, - SENDASYNCPROC callback, ULONG_PTR data ) -{ - return SendMessageCallbackW( hwnd, msg, map_wparam_AtoW( msg, wParam ), - lParam, callback, data ); -} - - -/*********************************************************************** - * SendMessageCallbackW (USER32.@) - * - * FIXME: It's like PostMessage. The callback gets called when the message - * is processed. We have to modify the message processing for an exact - * implementation... - * The callback is only called when the thread that called us calls one of - * Get/Peek/WaitMessage. - */ -BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, - SENDASYNCPROC callback, ULONG_PTR data ) -{ - LRESULT result; - - if (is_pointer_message(msg)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - FIXME( "(0x%04x,0x%04x,0x%08x,0x%08lx,%p,0x%08x),stub!\n", - hwnd, msg, wParam, lParam, callback, data ); - - if (hwnd == HWND_BROADCAST) - { - PostMessageW( hwnd, msg, wParam, lParam ); - FIXME("Broadcast: Callback will not be called!\n"); - return TRUE; - } - result = SendMessageW( hwnd, msg, wParam, lParam ); - callback( hwnd, msg, data, result ); - return TRUE; -} - - -/*********************************************************************** * WaitMessage (USER.112) Suspend thread pending messages * WaitMessage (USER32.@) Suspend thread pending messages * @@ -1997,17 +629,6 @@ /*********************************************************************** - * MsgWaitForMultipleObjects (USER.640) - */ -DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles, - BOOL wait_all, DWORD timeout, DWORD mask ) -{ - return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask, - wait_all ? MWMO_WAITALL : 0 ); -} - - -/*********************************************************************** * WaitForInputIdle (USER32.@) */ DWORD WINAPI WaitForInputIdle( HANDLE hProcess, DWORD dwTimeOut ) @@ -2058,14 +679,19 @@ */ void WINAPI UserYield16(void) { + DWORD count; + /* Handle sent messages */ process_sent_messages(); /* Yield */ - OldYield16(); - - /* Handle sent messages again */ - process_sent_messages(); + ReleaseThunkLock(&count); + if (count) + { + RestoreThunkLock(count); + /* Handle sent messages again */ + process_sent_messages(); + } } @@ -2188,7 +814,7 @@ /*********************************************************************** - * MSG_DoTranslateMessage + * TranslateMessage (USER32.@) * * Implementation of TranslateMessage. * @@ -2199,29 +825,26 @@ * This produces WM_CHAR messages only for keys mapped to ASCII characters * by the keyboard driver. */ -static BOOL MSG_DoTranslateMessage( UINT message, HWND hwnd, - WPARAM wParam, LPARAM lParam ) +BOOL WINAPI TranslateMessage( const MSG *msg ) { static int dead_char; + UINT message; WCHAR wp[2]; - - if (message != WM_MOUSEMOVE && message != WM_TIMER) - TRACE("(%s, %04X, %08lX)\n", - SPY_GetMsgName(message), wParam, lParam ); - if(message >= WM_KEYFIRST && message <= WM_KEYLAST) - TRACE_(key)("(%s, %04X, %08lX)\n", - SPY_GetMsgName(message), wParam, lParam ); - if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE; + if (msg->message >= WM_KEYFIRST && msg->message <= WM_KEYLAST) + TRACE_(key)("(%s, %04X, %08lX)\n", + SPY_GetMsgName(msg->message), msg->wParam, msg->lParam ); + + if ((msg->message != WM_KEYDOWN) && (msg->message != WM_SYSKEYDOWN)) return FALSE; TRACE_(key)("Translating key %s (%04x), scancode %02x\n", - SPY_GetVKeyName(wParam), wParam, LOBYTE(HIWORD(lParam))); + SPY_GetVKeyName(msg->wParam), msg->wParam, LOBYTE(HIWORD(msg->lParam))); /* FIXME : should handle ToUnicode yielding 2 */ - switch (ToUnicode(wParam, HIWORD(lParam), QueueKeyStateTable, wp, 2, 0)) + switch (ToUnicode(msg->wParam, HIWORD(msg->lParam), QueueKeyStateTable, wp, 2, 0)) { case 1: - message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; + message = (msg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; /* Should dead chars handling go in ToAscii ? */ if (dead_char) { @@ -2245,14 +868,14 @@ dead_char = 0; } TRACE_(key)("1 -> PostMessage(%s)\n", SPY_GetMsgName(message)); - PostMessageW( hwnd, message, wp[0], lParam ); + PostMessageW( msg->hwnd, message, wp[0], msg->lParam ); return TRUE; case -1: - message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR; + message = (msg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR; dead_char = wp[0]; TRACE_(key)("-1 -> PostMessage(%s)\n", SPY_GetMsgName(message)); - PostMessageW( hwnd, message, wp[0], lParam ); + PostMessageW( msg->hwnd, message, wp[0], msg->lParam ); return TRUE; } return FALSE; @@ -2260,125 +883,6 @@ /*********************************************************************** - * TranslateMessage (USER.113) - */ -BOOL16 WINAPI TranslateMessage16( const MSG16 *msg ) -{ - return MSG_DoTranslateMessage( msg->message, msg->hwnd, - msg->wParam, msg->lParam ); -} - - -/*********************************************************************** - * TranslateMessage32 (USER.821) - */ -BOOL16 WINAPI TranslateMessage32_16( const MSG32_16 *msg, BOOL16 wHaveParamHigh ) -{ - WPARAM wParam; - - if (wHaveParamHigh) - wParam = MAKELONG(msg->msg.wParam, msg->wParamHigh); - else - wParam = (WPARAM)msg->msg.wParam; - - return MSG_DoTranslateMessage( msg->msg.message, msg->msg.hwnd, - wParam, msg->msg.lParam ); -} - -/*********************************************************************** - * TranslateMessage (USER32.@) - */ -BOOL WINAPI TranslateMessage( const MSG *msg ) -{ - return MSG_DoTranslateMessage( msg->message, msg->hwnd, - msg->wParam, msg->lParam ); -} - - -/*********************************************************************** - * DispatchMessage (USER.114) - */ -LONG WINAPI DispatchMessage16( const MSG16* msg ) -{ - WND * wndPtr; - LONG retval; - int painting; - - /* Process timer messages */ - if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) - { - if (msg->lParam) - { - /* before calling window proc, verify whether timer is still valid; - there's a slim chance that the application kills the timer - between GetMessage and DispatchMessage API calls */ - if (!TIMER_IsTimerValid(msg->hwnd, (UINT) msg->wParam, (HWINDOWPROC) msg->lParam)) - return 0; /* invalid winproc */ - - return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd, - msg->message, msg->wParam, GetTickCount() ); - } - } - - if (!msg->hwnd) return 0; - if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0; - if (!wndPtr->winproc) - { - retval = 0; - goto END; - } - painting = (msg->message == WM_PAINT); - if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT; - - SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message, - msg->wParam, msg->lParam ); - retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc, - msg->hwnd, msg->message, - msg->wParam, msg->lParam ); - SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval, - msg->wParam, msg->lParam ); - - WIN_ReleaseWndPtr(wndPtr); - wndPtr = WIN_FindWndPtr(msg->hwnd); - if (painting && wndPtr && - (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate) - { - ERR("BeginPaint not called on WM_PAINT for hwnd %04x!\n", - msg->hwnd); - wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; - /* Validate the update region to avoid infinite WM_PAINT loop */ - RedrawWindow( wndPtr->hwndSelf, NULL, 0, - RDW_NOFRAME | RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOINTERNALPAINT ); - } -END: - WIN_ReleaseWndPtr(wndPtr); - return retval; -} - - -/*********************************************************************** - * DispatchMessage32 (USER.822) - */ -LONG WINAPI DispatchMessage32_16( const MSG32_16* lpmsg16_32, BOOL16 wHaveParamHigh ) -{ - if (wHaveParamHigh == FALSE) - return DispatchMessage16(&(lpmsg16_32->msg)); - else - { - MSG msg; - - msg.hwnd = lpmsg16_32->msg.hwnd; - msg.message = lpmsg16_32->msg.message; - msg.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh); - msg.lParam = lpmsg16_32->msg.lParam; - msg.time = lpmsg16_32->msg.time; - msg.pt.x = (INT)lpmsg16_32->msg.pt.x; - msg.pt.y = (INT)lpmsg16_32->msg.pt.y; - return DispatchMessageA(&msg); - } -} - -/*********************************************************************** * DispatchMessageA (USER32.@) */ LONG WINAPI DispatchMessageA( const MSG* msg ) @@ -2548,39 +1052,6 @@ /*********************************************************************** - * InSendMessage (USER.192) - */ -BOOL16 WINAPI InSendMessage16(void) -{ - return InSendMessage(); -} - - -/*********************************************************************** - * InSendMessage (USER32.@) - */ -BOOL WINAPI InSendMessage(void) -{ - return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND; -} - - -/*********************************************************************** - * InSendMessageEx (USER32.@) - */ -DWORD WINAPI InSendMessageEx( LPVOID reserved ) -{ - DWORD ret = 0; - SERVER_START_REQ( in_send_message ) - { - if (!SERVER_CALL_ERR()) ret = req->flags; - } - SERVER_END_REQ; - return ret; -} - - -/*********************************************************************** * BroadcastSystemMessage (USER32.@) */ LONG WINAPI BroadcastSystemMessage(
diff --git a/windows/queue.c b/windows/queue.c index 4f9fd73..d4400ba 100644 --- a/windows/queue.c +++ b/windows/queue.c
@@ -456,64 +456,24 @@ /*********************************************************************** - * QUEUE_GetQueueTask - */ -HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue ) -{ - HTASK16 hTask = 0; - - MESSAGEQUEUE *queue = QUEUE_Lock( hQueue ); - - if (queue) - { - hTask = queue->teb->htask16; - QUEUE_Unlock( queue ); - } - - return hTask; -} - - -/*********************************************************************** - * PostQuitMessage (USER.6) - */ -void WINAPI PostQuitMessage16( INT16 exitCode ) -{ - PostQuitMessage( exitCode ); -} - - -/*********************************************************************** - * PostQuitMessage (USER32.@) - * - * PostQuitMessage() posts a message to the system requesting an - * application to terminate execution. As a result of this function, - * the WM_QUIT message is posted to the application, and - * PostQuitMessage() returns immediately. The exitCode parameter - * specifies an application-defined exit code, which appears in the - * _wParam_ parameter of the WM_QUIT message posted to the application. - * - * CONFORMANCE - * - * ECMA-234, Win32 - */ -void WINAPI PostQuitMessage( INT exitCode ) -{ - PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 ); -} - - -/*********************************************************************** * GetWindowTask (USER.224) */ HTASK16 WINAPI GetWindowTask16( HWND16 hwnd ) { HTASK16 retvalue; - WND *wndPtr = WIN_FindWndPtr( hwnd ); + MESSAGEQUEUE *queue; + WND *wndPtr = WIN_FindWndPtr( hwnd ); if (!wndPtr) return 0; - retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ ); + + queue = QUEUE_Lock( wndPtr->hmemTaskQ ); WIN_ReleaseWndPtr(wndPtr); + + if (!queue) return 0; + + retvalue = queue->teb->htask16; + QUEUE_Unlock( queue ); + return retvalue; } @@ -542,25 +502,6 @@ /*********************************************************************** - * SetMessageQueue (USER.266) - */ -BOOL16 WINAPI SetMessageQueue16( INT16 size ) -{ - return SetMessageQueue( size ); -} - - -/*********************************************************************** - * SetMessageQueue (USER32.@) - */ -BOOL WINAPI SetMessageQueue( INT size ) -{ - /* now obsolete the message queue will be expanded dynamically - as necessary */ - return TRUE; -} - -/*********************************************************************** * InitThreadInput (USER.409) */ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) @@ -593,14 +534,6 @@ } /*********************************************************************** - * GetQueueStatus (USER.334) - */ -DWORD WINAPI GetQueueStatus16( UINT16 flags ) -{ - return GetQueueStatus( flags ); -} - -/*********************************************************************** * GetQueueStatus (USER32.@) */ DWORD WINAPI GetQueueStatus( UINT flags ) @@ -619,14 +552,6 @@ /*********************************************************************** - * GetInputState (USER.335) - */ -BOOL16 WINAPI GetInputState16(void) -{ - return GetInputState(); -} - -/*********************************************************************** * GetInputState (USER32.@) */ BOOL WINAPI GetInputState(void)