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/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 );
 }