- Remove cooked hardware messages when they are dropped (reported by
  Gerard Patel).
- Convert all posted 32-bit messages to Unicode before storing them in
  the queue.
- Faster implementation of MSG_IsPointerMessage.
- Moved a couple of functions from queue.c to message.c.

diff --git a/windows/message.c b/windows/message.c
index bb441ab..bb0cd12 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -36,8 +36,109 @@
 #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
@@ -76,6 +177,54 @@
 
 
 /***********************************************************************
+ *		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;
+}
+
+
+/***********************************************************************
  *           queue_hardware_message
  *
  * store a hardware message in the thread queue
@@ -86,7 +235,7 @@
     {
         req->kind   = kind;
         req->id     = (void *)GetWindowThreadProcessId( msg->hwnd, NULL );
-        req->type   = QMSG_HARDWARE;
+        req->type   = 0;
         req->win    = msg->hwnd;
         req->msg    = msg->message;
         req->wparam = msg->wParam;
@@ -476,47 +625,294 @@
  *
  * returns TRUE if the contents of 'msg' should be passed to the application
  */
-static BOOL process_hardware_message( QMSG *qmsg, HWND hwnd_filter,
-                                      UINT first, UINT last, BOOL remove )
+static BOOL process_raw_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd_filter,
+                                          UINT first, UINT last, BOOL remove )
 {
-    if (qmsg->kind == RAW_HW_MESSAGE)
+    if (is_keyboard_message( msg->message ))
     {
-        /* if it is raw, try to cook it first */
-        if (is_keyboard_message( qmsg->msg.message ))
-        {
-            if (!process_raw_keyboard_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
-        }
-        else if (is_mouse_message( qmsg->msg.message ))
-        {
-            if (!process_raw_mouse_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
-        }
-        else goto invalid;
-
-        /* check destination thread and filters */
-        if (!check_message_filter( &qmsg->msg, hwnd_filter, first, last ) ||
-            GetWindowThreadProcessId( qmsg->msg.hwnd, NULL ) != GetCurrentThreadId())
-        {
-            /* queue it for later, or for another thread */
-            queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
-            return FALSE;
-        }
-
-        /* save the message in the cooked queue if we didn't want to remove it */
-        if (!remove) queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
+        if (!process_raw_keyboard_message( msg, extra_info )) return FALSE;
+    }
+    else if (is_mouse_message( msg->message ))
+    {
+        if (!process_raw_mouse_message( msg, extra_info )) return FALSE;
+    }
+    else
+    {
+        ERR( "unknown message type %x\n", msg->message );
+        return FALSE;
     }
 
-    if (is_keyboard_message( qmsg->msg.message ))
-        return process_cooked_keyboard_message( &qmsg->msg, remove );
+    /* check destination thread and filters */
+    if (!check_message_filter( msg, hwnd_filter, first, last ) ||
+        GetWindowThreadProcessId( msg->hwnd, NULL ) != GetCurrentThreadId())
+    {
+        /* queue it for later, or for another thread */
+        queue_hardware_message( msg, extra_info, COOKED_HW_MESSAGE );
+        return FALSE;
+    }
 
-    if (is_mouse_message( qmsg->msg.message ))
-        return process_cooked_mouse_message( &qmsg->msg, remove );
+    /* 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 );
+    return TRUE;
+}
 
- invalid:
-    ERR( "unknown message type %x\n", qmsg->msg.message );
+
+/***********************************************************************
+ *          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 )
+{
+    if (is_keyboard_message( msg->message ))
+        return process_cooked_keyboard_message( msg, remove );
+
+    if (is_mouse_message( msg->message ))
+        return process_cooked_mouse_message( msg, remove );
+
+    ERR( "unknown message type %x\n", msg->message );
     return FALSE;
 }
 
 
+/***********************************************************************
+ *           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_Lock( GetFastQueue16() );
+    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);
+    QUEUE_Unlock( queue );
+
+    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;
+    HQUEUE16 hQueue;
+
+    TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
+
+    hQueue = GetFastQueue16();
+    if (!(queue = QUEUE_Lock( hQueue ))) return 0;
+
+    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 */
+            QUEUE_Unlock( queue );
+            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)
  */
@@ -594,7 +990,7 @@
     iWndsLocks = WIN_SuspendWndsLock();
 
     /* wait for the result */
-    QUEUE_WaitBits( QS_SMRESULT, timeout );
+    wait_queue_bits( QS_SMRESULT, timeout );
 
     SERVER_START_REQ( get_message_reply )
     {
@@ -648,116 +1044,74 @@
  */
 static BOOL MSG_ConvertMsg( MSG *msg, int srcType, int dstType )
 {
-    UINT16 msg16;
-    MSGPARAM16 mp16;
-
-    switch ( MAKELONG( srcType, dstType ) )
+    if (srcType == QMSG_WIN32A || dstType == QMSG_WIN32A)
     {
-    case MAKELONG( QMSG_WIN16,  QMSG_WIN16 ):
-    case MAKELONG( QMSG_WIN32A, QMSG_WIN32A ):
-    case MAKELONG( QMSG_WIN32W, QMSG_WIN32W ):
-        return TRUE;
-
-    case MAKELONG( QMSG_WIN16, QMSG_WIN32A ):
-        switch ( WINPROC_MapMsg16To32A( 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_UnmapMsg16To32A( msg->hwnd, msg->message, msg->wParam, msg->lParam, 0 );
-        default:
-            return FALSE;
-        }
-
-    case MAKELONG( QMSG_WIN16, 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;
-        }
-
-    case MAKELONG( QMSG_WIN32A, QMSG_WIN16 ):
-        mp16.lParam = msg->lParam;
-        switch ( WINPROC_MapMsg32ATo16( 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_UnmapMsg32ATo16( msg->hwnd, msg->message, msg->wParam, msg->lParam, &mp16 );
-        default:
-            return FALSE;
-        }
-
-    case MAKELONG( QMSG_WIN32W, QMSG_WIN16 ):
-        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;
-        }
-
-    case MAKELONG( QMSG_WIN32A, QMSG_WIN32W ):
-        switch ( WINPROC_MapMsg32ATo32W( msg->hwnd, msg->message, &msg->wParam, &msg->lParam ) )
-        {
-        case 0:
-            return TRUE;
-        case 1:
-            /* Pointer messages were mapped --> need to free allocated memory and fail */
-            WINPROC_UnmapMsg32ATo32W( msg->hwnd, msg->message, msg->wParam, msg->lParam );
-        default:
-            return FALSE;
-        }
-
-    case MAKELONG( QMSG_WIN32W, QMSG_WIN32A ):
-        switch ( WINPROC_MapMsg32WTo32A( msg->hwnd, msg->message, &msg->wParam, &msg->lParam ) )
-        {
-        case 0:
-            return TRUE;
-        case 1:
-            /* Pointer messages were mapped --> need to free allocated memory and fail */
-            WINPROC_UnmapMsg32WTo32A( msg->hwnd, msg->message, msg->wParam, msg->lParam );
-        default:
-            return FALSE;
-        }
-
-    default:    
-        FIXME( "Invalid message type(s): %d / %d\n", srcType, dstType );
+        /* 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;
+    int mask, msg_flags = 0;
     MESSAGEQUEUE *msgQueue;
     int iWndsLocks;
-    QMSG qmsg;
+    MSG msg;
+    ULONG_PTR extra_info;
 
     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
     if (first || last)
@@ -779,46 +1133,26 @@
     if (USER_Driver.pMsgWaitForMultipleObjectsEx)
         USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
 
+    if (flags & PM_REMOVE) msg_flags |= GET_MSG_REMOVE;
+
     while(1)
     {
-        /* FIXME: should remove this */
-        WORD wakeBits = HIWORD(GetQueueStatus( mask ));
-
-  retry:
-        if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, &qmsg ))
+        if (peek_message( hwnd, first, last, msg_flags, type, &msg, &extra_info ))
         {
-            if (qmsg.kind == RAW_HW_MESSAGE || qmsg.kind == COOKED_HW_MESSAGE)
-            {
-                if (!process_hardware_message( &qmsg, hwnd, first, last, flags & PM_REMOVE ))
-                    goto retry;
-            }
-            else
-            {
-                /* Try to convert message to requested type */
-                if ( !MSG_ConvertMsg( &qmsg.msg, qmsg.type, type ) )
-                {
-                    ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
-                         SPY_GetMsgName(qmsg.msg.message));
-                    /* remove it (FIXME) */
-                    if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, &qmsg );
-                    goto retry;
-                }
-            }
-
             /* need to fill the window handle for WM_PAINT message */
-            if (qmsg.msg.message == WM_PAINT)
+            if (msg.message == WM_PAINT)
             {
-                if ((qmsg.msg.hwnd = WIN_FindWinToRepaint( hwnd )))
+                if ((msg.hwnd = WIN_FindWinToRepaint( hwnd )))
                 {
-                    if (IsIconic( qmsg.msg.hwnd ) && GetClassLongA( qmsg.msg.hwnd, GCL_HICON ))
+                    if (IsIconic( msg.hwnd ) && GetClassLongA( msg.hwnd, GCL_HICON ))
                     {
-                        qmsg.msg.message = WM_PAINTICON;
-                        qmsg.msg.wParam = 1;
+                        msg.message = WM_PAINTICON;
+                        msg.wParam = 1;
                     }
-                    if( !hwnd || qmsg.msg.hwnd == hwnd || IsChild(hwnd,qmsg.msg.hwnd) )
+                    if( !hwnd || msg.hwnd == hwnd || IsChild(hwnd,msg.hwnd) )
                     {
                         /* clear internal paint flag */
-                        RedrawWindow( qmsg.msg.hwnd, NULL, 0,
+                        RedrawWindow( msg.hwnd, NULL, 0,
                                       RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
                         break;
                     }
@@ -839,46 +1173,44 @@
             return FALSE;
         }
 
-        QUEUE_WaitBits( mask, INFINITE );
+        wait_queue_bits( mask, INFINITE );
     }
 
     WIN_RestoreWndsLock(iWndsLocks);
 
     if ((msgQueue = QUEUE_Lock( GetFastQueue16() )))
     {
-        msgQueue->GetMessageTimeVal      = qmsg.msg.time;
-        msgQueue->GetMessagePosVal       = MAKELONG( qmsg.msg.pt.x, qmsg.msg.pt.y );
-        msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
+        msgQueue->GetMessageTimeVal      = msg.time;
+        msgQueue->GetMessagePosVal       = MAKELONG( msg.pt.x, msg.pt.y );
+        msgQueue->GetMessageExtraInfoVal = extra_info;
         QUEUE_Unlock( msgQueue );
     }
 
       /* We got a message */
     if (flags & PM_REMOVE)
     {
-	WORD message = qmsg.msg.message;
-
-	if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
+	if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
 	{
-	    BYTE *p = &QueueKeyStateTable[qmsg.msg.wParam & 0xff];
+	    BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff];
 
 	    if (!(*p & 0x80))
 		*p ^= 0x01;
 	    *p |= 0x80;
 	}
-	else if (message == WM_KEYUP || message == WM_SYSKEYUP)
-	    QueueKeyStateTable[qmsg.msg.wParam & 0xff] &= ~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 = qmsg.msg;
+    *msg_out = msg;
     if (peek)
         return TRUE;
 
     else
-        return (qmsg.msg.message != WM_QUIT);
+        return (msg.message != WM_QUIT);
 }
 
 /***********************************************************************
@@ -896,7 +1228,7 @@
     {
 	if (sendIdle)
 	{
-	    if (!MSG_PeekMessage( QMSG_WIN32A, msg, 0, first, last, flags, TRUE ))
+	    if (!MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, TRUE ))
 	    {
 		  /* No message present -> send ENTERIDLE and wait */
                 if (IsWindow(hwndOwner))
@@ -907,38 +1239,29 @@
 		    if (idleSent!=NULL)
 		      *idleSent=TRUE;
 		}
-		MSG_PeekMessage( QMSG_WIN32A, msg, 0, first, last, flags, FALSE );
+		MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE );
 	    }
 	}
 	else  /* Always wait for a message */
-	    MSG_PeekMessage( QMSG_WIN32A, msg, 0, first, last, flags, FALSE );
+	    MSG_PeekMessage( QMSG_WIN32W, msg, 0, first, last, flags, FALSE );
 
         /* Call message filters */
 
         if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
         {
-            MSG *pmsg = HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
-            if (pmsg)
+            MSG tmp_msg = *msg;
+
+            if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)&tmp_msg ) ||
+                HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)&tmp_msg ))
             {
-                BOOL ret;
-                *pmsg = *msg;
-                ret = (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0,
-                                          (LPARAM) pmsg ) ||
-                       HOOK_CallHooksA( WH_MSGFILTER, code, 0,
-                                          (LPARAM) pmsg ));
-                       
-                HeapFree( GetProcessHeap(), 0, pmsg );
-                if (ret)
-                {
-                    /* Message filtered -> remove it from the queue */
-                    /* if it's still there. */
-                    if (!(flags & PM_REMOVE))
-                        MSG_PeekMessage( QMSG_WIN32A, msg, 0, first, last, PM_REMOVE, TRUE );
-                    continue;
-                }
+                /* 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);
     }
 }
@@ -984,16 +1307,10 @@
 /***********************************************************************
  *		PeekMessageA (USER32.@)
  */
-BOOL WINAPI PeekMessageA( LPMSG lpmsg, HWND hwnd,
-                          UINT min, UINT max, UINT wRemoveMsg)
+BOOL WINAPI PeekMessageA( LPMSG lpmsg, HWND hwnd, UINT min, UINT max, UINT flags )
 {
-    BOOL ret = MSG_PeekMessage( QMSG_WIN32A, lpmsg, hwnd, min, max, wRemoveMsg, TRUE );
-
-    TRACE( "peekmessage %04x, hwnd %04x, filter(%04x - %04x)\n", 
-           lpmsg->message, hwnd, min, max );
-
-    if (ret) HOOK_CallHooksA( WH_GETMESSAGE, HC_ACTION,
-                              wRemoveMsg & PM_REMOVE, (LPARAM)lpmsg );
+    BOOL ret = PeekMessageW( lpmsg, hwnd, min, max, flags );
+    if (ret) lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam );
     return ret;
 }
 
@@ -1081,12 +1398,8 @@
  */
 BOOL WINAPI GetMessageA( MSG *lpmsg, HWND hwnd, UINT min, UINT max )
 {
-    MSG_PeekMessage( QMSG_WIN32A, lpmsg, hwnd, min, max, PM_REMOVE, FALSE );
-    
-    TRACE( "message %04x, hwnd %04x, filter(%04x - %04x)\n", 
-           lpmsg->message, hwnd, min, max );
-    
-    HOOK_CallHooksA( WH_GETMESSAGE, HC_ACTION, PM_REMOVE, (LPARAM)lpmsg );
+    GetMessageW( lpmsg, hwnd, min, max );
+    lpmsg->wParam = map_wparam_WtoA( lpmsg->message, lpmsg->wParam );
     return lpmsg->message != WM_QUIT;
 }
 
@@ -1172,79 +1485,6 @@
 
 
 /***********************************************************************
- *           MSG_IsPointerMessage
- *
- * Check whether this message (may) contain pointers. 
- * Those messages may not be PostMessage()d or GetMessage()d, but are dropped.
- *
- * FIXME: list of pointer messages might be incomplete.
- *
- * (We could do a generic !IsBadWritePtr() check, but this would cause too
- *  much slow down I think. MM20010206)
- */
-static BOOL MSG_IsPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) {
-    switch (message) {
-    case WM_CREATE:
-    case WM_NCCREATE:
-    case WM_COMPAREITEM:
-    case WM_DELETEITEM:
-    case WM_MEASUREITEM:
-    case WM_DRAWITEM:
-    case WM_GETMINMAXINFO:
-    case WM_GETTEXT:
-    case WM_SETTEXT:
-    case WM_MDICREATE:
-    case WM_MDIGETACTIVE:
-    case WM_NCCALCSIZE:
-    case WM_WINDOWPOSCHANGING:
-    case WM_WINDOWPOSCHANGED:
-    case WM_NOTIFY:
-    case WM_GETDLGCODE:
-    case WM_WININICHANGE:
-    case WM_HELP:
-    case WM_COPYDATA:
-    case WM_STYLECHANGING:
-    case WM_STYLECHANGED:
-    case WM_DROPOBJECT:
-    case WM_DRAGMOVE:
-    case WM_DRAGSELECT:
-    case WM_QUERYDROPOBJECT:
-
-    case CB_DIR:
-    case CB_ADDSTRING:
-    case CB_INSERTSTRING:
-    case CB_FINDSTRING:
-    case CB_FINDSTRINGEXACT:
-    case CB_SELECTSTRING:
-    case CB_GETLBTEXT:
-    case CB_GETDROPPEDCONTROLRECT:
-
-    case LB_DIR:
-    case LB_ADDFILE:
-    case LB_ADDSTRING:
-    case LB_INSERTSTRING:
-    case LB_GETTEXT:
-    case LB_GETITEMRECT:
-    case LB_FINDSTRING:
-    case LB_FINDSTRINGEXACT:
-    case LB_SELECTSTRING:
-    case LB_GETSELITEMS:
-    case LB_SETTABSTOPS:
-
-    case EM_REPLACESEL:
-    case EM_GETSEL:
-    case EM_GETRECT:
-    case EM_SETRECT:
-    case EM_SETRECTNP:
-    case EM_GETLINE:
-    case EM_SETTABSTOPS:
-	    return TRUE;
-    default:
-	    return FALSE;
-    }
-}
-
-/***********************************************************************
  *           MSG_PostMessage
  */
 static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, 
@@ -1252,20 +1492,6 @@
 {
     WND *wndPtr;
 
-    /* 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)
-     * 16 bit does not care, so we don't either.
-     */
-    if ( (type!=QMSG_WIN16) && MSG_IsPointerMessage(message,wParam,lParam)) {
-	FIXME("Ignoring posted pointer message 0x%04x to hwnd 0x%04x.\n",
-		message,hwnd
-	);
-	SetLastError(ERROR_INVALID_PARAMETER);
-	return FALSE;
-    }
-
     if (hwnd == HWND_BROADCAST)
     {
         WND *pDesktop = WIN_GetDesktop();
@@ -1290,6 +1516,7 @@
                             type, hwnd, message, wParam, lParam );
 }
 
+
 /***********************************************************************
  *		PostMessage (USER.110)
  */
@@ -1305,7 +1532,7 @@
 BOOL WINAPI PostMessageA( HWND hwnd, UINT message, WPARAM wParam,
                           LPARAM lParam )
 {
-    return MSG_PostMessage( QMSG_WIN32A, hwnd, message, wParam, lParam );
+    return PostMessageW( hwnd, message, map_wparam_AtoW( message, wParam ), lParam );
 }
 
 /***********************************************************************
@@ -1314,6 +1541,16 @@
 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 );
 }
 
@@ -1335,7 +1572,7 @@
 BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
                                 WPARAM wParam, LPARAM lParam )
 {
-    return MSG_PostToQueue( idThread, QMSG_WIN32A, 0, message, wParam, lParam );
+    return PostThreadMessageW( idThread, message, map_wparam_AtoW( message, wParam ), lParam );
 }
 
 /**********************************************************************
@@ -1344,6 +1581,11 @@
 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 );
 }
 
@@ -1702,6 +1944,68 @@
 }
 
 
+/***********************************************************************
+ *		WaitForInputIdle (USER32.@)
+ */
+DWORD WINAPI WaitForInputIdle( HANDLE hProcess, DWORD dwTimeOut )
+{
+    DWORD cur_time, ret;
+    HANDLE idle_event = -1;
+
+    SERVER_START_REQ( wait_input_idle )
+    {
+        req->handle = hProcess;
+        req->timeout = dwTimeOut;
+        if (!(ret = SERVER_CALL_ERR())) idle_event = req->event;
+    }
+    SERVER_END_REQ;
+    if (ret) return 0xffffffff;  /* error */
+    if (!idle_event) return 0;  /* no event to wait on */
+
+    cur_time = GetTickCount();
+
+    TRACE("waiting for %x\n", idle_event );
+    while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE )
+    {
+        ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
+        if ( ret == ( WAIT_OBJECT_0 + 1 ))
+        {
+            process_sent_messages();
+            continue;
+        }
+        if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF )
+        {
+            TRACE("timeout or error\n");
+            return ret;
+        }
+        else
+        {
+            TRACE("finished\n");
+            return 0;
+        }
+    }
+
+    return WAIT_TIMEOUT;
+}
+
+
+/***********************************************************************
+ *		UserYield (USER.332)
+ *		UserYield16 (USER32.@)
+ */
+void WINAPI UserYield16(void)
+{
+    /* Handle sent messages */
+    process_sent_messages();
+
+    /* Yield */
+    OldYield16();
+
+    /* Handle sent messages again */
+    process_sent_messages();
+}
+
+
 struct accent_char
 {
     BYTE ac_accent;