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)