Made server communication faster by using a shared memory block.
A few other optimizations in request processing in the server.
Moved automatically generated request definitions to server.h and
removed include/server/request.h.

diff --git a/server/change.c b/server/change.c
index 679df12..fb1f0cb 100644
--- a/server/change.c
+++ b/server/change.c
@@ -13,6 +13,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct change
 {
@@ -23,10 +24,10 @@
 
 static void change_dump( struct object *obj, int verbose );
 static int change_signaled( struct object *obj, struct thread *thread );
-static void change_destroy( struct object *obj );
 
 static const struct object_ops change_ops =
 {
+    sizeof(struct change),
     change_dump,
     add_queue,
     remove_queue,
@@ -36,15 +37,14 @@
     no_write_fd,
     no_flush,
     no_get_file_info,
-    change_destroy
+    no_destroy
 };
 
 
 static struct object *create_change_notification( int subtree, int filter )
 {
     struct change *change;
-    if (!(change = mem_alloc( sizeof(*change) ))) return NULL;
-    init_object( &change->obj, &change_ops, NULL );
+    if (!(change = alloc_object( &change_ops ))) return NULL;
     change->subtree = subtree;
     change->filter  = filter;
     return &change->obj;
@@ -65,24 +65,16 @@
     return 0;  /* never signaled for now */
 }
 
-static void change_destroy( struct object *obj )
-{
-    struct change *change = (struct change *)obj;
-    assert( obj->ops == &change_ops );
-    free( change );
-}
-
 /* create a change notification */
 DECL_HANDLER(create_change_notification)
 {
     struct object *obj;
-    struct create_change_notification_reply reply = { -1 };
+    struct create_change_notification_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if ((obj = create_change_notification( req->subtree, req->filter )))
     {
-        reply.handle = alloc_handle( current->process, obj,
-                                     STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
+        reply->handle = alloc_handle( current->process, obj,
+                                      STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
         release_object( obj );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
 }
diff --git a/server/console.c b/server/console.c
index 8ed9ec1..a4792b8 100644
--- a/server/console.c
+++ b/server/console.c
@@ -27,6 +27,7 @@
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
+#include "request.h"
 
 struct screen_buffer;
 
@@ -72,6 +73,7 @@
 
 static const struct object_ops console_input_ops =
 {
+    sizeof(struct console_input),
     console_input_dump,
     console_input_add_queue,
     console_input_remove_queue,
@@ -86,6 +88,7 @@
 
 static const struct object_ops screen_buffer_ops =
 {
+    sizeof(struct screen_buffer),
     screen_buffer_dump,
     screen_buffer_add_queue,
     screen_buffer_remove_queue,
@@ -99,76 +102,76 @@
 };
 
 
-static int create_console( int fd, struct object *obj[2] )
+static struct object *create_console_input( int fd )
 {
     struct console_input *console_input;
-    struct screen_buffer *screen_buffer;
-    int read_fd, write_fd;
 
-    if ((read_fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
+    if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
     {
         file_set_error();
-        return 0;
+        return NULL;
     }
-    if ((write_fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
+    if ((console_input = alloc_object( &console_input_ops )))
+    {
+        console_input->select.fd      = fd;
+        console_input->select.func    = default_select_event;
+        console_input->select.private = console_input;
+        console_input->mode           = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+                                        ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
+        console_input->output         = NULL;
+        console_input->recnum         = 0;
+        console_input->records        = NULL;
+        register_select_user( &console_input->select );
+        return &console_input->obj;
+    }
+    close( fd );
+    return NULL;
+}
+
+static struct object *create_console_output( int fd, struct object *input )
+{
+    struct console_input *console_input = (struct console_input *)input;
+    struct screen_buffer *screen_buffer;
+
+    if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
     {
         file_set_error();
-        close( read_fd );
-        return 0;
+        return NULL;
     }
-    if (!(console_input = mem_alloc( sizeof(struct console_input) )))
+    if ((screen_buffer = alloc_object( &screen_buffer_ops )))
     {
-        close( read_fd );
-        close( write_fd );
-        return 0;
+        screen_buffer->select.fd      = fd;
+        screen_buffer->select.func    = default_select_event;
+        screen_buffer->select.private = screen_buffer;
+        screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
+        screen_buffer->input          = console_input;
+        screen_buffer->cursor_size    = 100;
+        screen_buffer->cursor_visible = 1;
+        screen_buffer->pid            = 0;
+        screen_buffer->title          = strdup( "Wine console" );
+        register_select_user( &screen_buffer->select );
+        console_input->output = screen_buffer;
+        return &screen_buffer->obj;
     }
-    if (!(screen_buffer = mem_alloc( sizeof(struct screen_buffer) )))
-    {
-        close( read_fd );
-        close( write_fd );
-        free( console_input );
-        return 0;
-    }
-    init_object( &console_input->obj, &console_input_ops, NULL );
-    init_object( &screen_buffer->obj, &screen_buffer_ops, NULL );
-    console_input->select.fd      = read_fd;
-    console_input->select.func    = default_select_event;
-    console_input->select.private = console_input;
-    console_input->mode           = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
-                                    ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
-    console_input->output         = screen_buffer;
-    console_input->recnum         = 0;
-    console_input->records        = NULL;
-    screen_buffer->select.fd      = write_fd;
-    screen_buffer->select.func    = default_select_event;
-    screen_buffer->select.private = screen_buffer;
-    screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-    screen_buffer->input          = console_input;
-    screen_buffer->cursor_size    = 100;
-    screen_buffer->cursor_visible = 1;
-    screen_buffer->pid            = 0;
-    screen_buffer->title          = strdup( "Wine console" );
-    register_select_user( &console_input->select );
-    register_select_user( &screen_buffer->select );
-    CLEAR_ERROR();
-    obj[0] = &console_input->obj;
-    obj[1] = &screen_buffer->obj;
-    return 1;
+    close( fd );
+    return NULL;
 }
 
 /* allocate a console for this process */
 int alloc_console( struct process *process )
 {
-    struct object *obj[2];
     if (process->console_in || process->console_out)
     {
-        SET_ERROR( ERROR_ACCESS_DENIED );
+        set_error( ERROR_ACCESS_DENIED );
         return 0;
     }
-    if (!create_console( -1, obj )) return 0;
-    process->console_in  = obj[0];
-    process->console_out = obj[1];
-    return 1;
+    if ((process->console_in = create_console_input( -1 )))
+    {
+        if ((process->console_out = create_console_output( -1, process->console_in )))
+            return 1;
+        release_object( process->console_in );
+    }
+    return 0;
 }
 
 /* free the console for this process */
@@ -203,7 +206,7 @@
     }
     else
     {
-        SET_ERROR( ERROR_INVALID_HANDLE );
+        set_error( ERROR_INVALID_HANDLE );
         release_object( obj );
         return 0;
     }
@@ -258,7 +261,7 @@
         *mode = ((struct screen_buffer *)obj)->mode;
         ret = 1;
     }
-    else SET_ERROR( ERROR_INVALID_HANDLE );
+    else set_error( ERROR_INVALID_HANDLE );
     release_object( obj );
     return ret;
 }
@@ -280,13 +283,14 @@
         ((struct screen_buffer *)obj)->mode = mode;
         ret = 1;
     }
-    else SET_ERROR( ERROR_INVALID_HANDLE );
+    else set_error( ERROR_INVALID_HANDLE );
     release_object( obj );
     return ret;
 }
 
 /* set misc console information (output handle only) */
-static int set_console_info( int handle, struct set_console_info_request *req, const char *title )
+static int set_console_info( int handle, struct set_console_info_request *req,
+                             const char *title, size_t len )
 {
     struct screen_buffer *console;
     if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
@@ -299,8 +303,14 @@
     }
     if (req->mask & SET_CONSOLE_INFO_TITLE)
     {
-        if (console->title) free( console->title );
-        console->title = strdup( title );
+        char *new_title = mem_alloc( len + 1 );
+        if (new_title)
+        {
+            memcpy( new_title, title, len );
+            new_title[len] = 0;
+            if (console->title) free( console->title );
+            console->title = new_title;
+        }
     }
     release_object( console );
     return 1;
@@ -333,7 +343,7 @@
     if (!(new_rec = realloc( console->records,
                              (console->recnum + count) * sizeof(INPUT_RECORD) )))
     {
-        SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
+        set_error( ERROR_NOT_ENOUGH_MEMORY );
         release_object( console );
         return -1;
     }
@@ -348,14 +358,13 @@
 static int read_console_input( int handle, int count, int flush )
 {
     struct console_input *console;
-    struct read_console_input_reply reply;
+    struct read_console_input_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
                                                             GENERIC_READ, &console_input_ops )))
         return -1;
     if ((count < 0) || (count > console->recnum)) count = console->recnum;
-    send_reply( current, -1, 2, &reply, sizeof(reply),
-                console->records, count * sizeof(INPUT_RECORD) );
+    add_reply_data( current, console->records, count * sizeof(INPUT_RECORD) );
     if (flush)
     {
         int i;
@@ -445,7 +454,6 @@
     unregister_select_user( &console->select );
     close( console->select.fd );
     if (console->output) console->output->input = NULL;
-    free( console );
 }
 
 static void screen_buffer_dump( struct object *obj, int verbose )
@@ -511,101 +519,94 @@
     if (console->input) console->input->output = NULL;
     if (console->pid) kill( console->pid, SIGTERM );
     if (console->title) free( console->title );
-    free( console );
 }
 
 /* allocate a console for the current process */
 DECL_HANDLER(alloc_console)
 {
-    struct alloc_console_reply reply = { -1, -1 };
+    struct alloc_console_reply *reply = push_reply_data( current, sizeof(*reply) );
+    int in = -1, out = -1;
 
     if (!alloc_console( current->process )) goto done;
 
-    if ((reply.handle_in = alloc_handle( current->process, current->process->console_in,
-                                         req->access, req->inherit )) != -1)
+    if ((in = alloc_handle( current->process, current->process->console_in,
+                            req->access, req->inherit )) != -1)
     {
-        if ((reply.handle_out = alloc_handle( current->process, current->process->console_out,
-                                              req->access, req->inherit )) != -1)
+        if ((out = alloc_handle( current->process, current->process->console_out,
+                                 req->access, req->inherit )) != -1)
             goto done;  /* everything is fine */
-        close_handle( current->process, reply.handle_in );
-        reply.handle_in = -1;
+        close_handle( current->process, in );
+        in = -1;
     }
     free_console( current->process );
 
  done:
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    reply->handle_in  = in;
+    reply->handle_out = out;
 }
 
 /* free the console of the current process */
 DECL_HANDLER(free_console)
 {
     free_console( current->process );
-    send_reply( current, -1, 0 );
 }
 
 /* open a handle to the process console */
 DECL_HANDLER(open_console)
 {
-    struct open_console_reply reply = { -1 };
+    struct open_console_reply *reply = push_reply_data( current, sizeof(*reply) );
     struct object *obj= req->output ? current->process->console_out : current->process->console_in;
 
-    if (obj) reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    if (obj) reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
+    else set_error( ERROR_ACCESS_DENIED );
 }
 
 /* set info about a console (output only) */
 DECL_HANDLER(set_console_info)
 {
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "set_console_info", name, len );
-    set_console_info( req->handle, req, name );
-    send_reply( current, -1, 0 );
+    size_t len = get_req_strlen();
+    set_console_info( req->handle, req, get_req_data( len + 1 ), len );
 }
 
 /* get info about a console (output only) */
 DECL_HANDLER(get_console_info)
 {
-    struct get_console_info_reply reply;
+    struct get_console_info_reply *reply = push_reply_data( current, sizeof(*reply) );
     const char *title;
-    get_console_info( req->handle, &reply, &title );
-    send_reply( current, -1, 2, &reply, sizeof(reply),
-                title, title ? strlen(title)+1 : 0 );
+    get_console_info( req->handle, reply, &title );
+    if (title) add_reply_data( current, title, strlen(title) + 1 );
 }
 
 /* set a console fd */
 DECL_HANDLER(set_console_fd)
 {
     set_console_fd( req->handle, fd, req->pid );
-    send_reply( current, -1, 0 );
 }
 
 /* get a console mode (input or output) */
 DECL_HANDLER(get_console_mode)
 {
-    struct get_console_mode_reply reply;
-    get_console_mode( req->handle, &reply.mode );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    struct get_console_mode_reply *reply = push_reply_data( current, sizeof(*reply) );
+    get_console_mode( req->handle, &reply->mode );
 }
 
 /* set a console mode (input or output) */
 DECL_HANDLER(set_console_mode)
 {
     set_console_mode( req->handle, req->mode );
-    send_reply( current, -1, 0 );
 }
 
 /* add input records to a console input queue */
 DECL_HANDLER(write_console_input)
 {
-    struct write_console_input_reply reply;
-    INPUT_RECORD *records = (INPUT_RECORD *)data;
+    struct write_console_input_reply *reply = push_reply_data( current, sizeof(*reply) );
 
-    if (len != req->count * sizeof(INPUT_RECORD))
-        fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
-                              len, req->count );
-    reply.written = write_console_input( req->handle, req->count, records );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    if (check_req_data( req->count * sizeof(INPUT_RECORD)))
+    {
+        INPUT_RECORD *records = get_req_data( req->count * sizeof(INPUT_RECORD) );
+        reply->written = write_console_input( req->handle, req->count, records );
+    }
+    else fatal_protocol_error( "write_console_input: bad length" );
 }
 
 /* fetch input records from a console input queue */
diff --git a/server/debugger.c b/server/debugger.c
index 3a85925..0181d71 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -8,11 +8,10 @@
 #include "winbase.h"
 #include "winerror.h"
 
-#include "server.h"
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
-
+#include "request.h"
 
 struct debug_event
 {
@@ -143,20 +142,20 @@
 }
 
 /* send the first queue event as a reply */
-static void send_event_reply( struct debug_ctx *debug_ctx )
+static void build_event_reply( struct debug_ctx *debug_ctx )
 {
-    struct wait_debug_event_reply reply;
     struct debug_event *event = debug_ctx->event_head;
     struct thread *thread = event->thread;
+    struct wait_debug_event_reply *reply = push_reply_data( debug_ctx->owner, sizeof(*reply) );
 
     assert( event );
     assert( debug_ctx->waiting );
 
     unlink_event( debug_ctx, event );
     event->sent = 1;
-    reply.code = event->code;
-    reply.pid  = thread->process;
-    reply.tid  = thread;
+    reply->code = event->code;
+    reply->pid  = thread->process;
+    reply->tid  = thread;
     debug_ctx->waiting = 0;
     if (debug_ctx->timeout)
     {
@@ -164,25 +163,24 @@
         debug_ctx->timeout = NULL;
     }
     debug_ctx->owner->error = 0;
-    send_reply( debug_ctx->owner, -1, 2, &reply, sizeof(reply),
-                &event->data, event_sizes[event->code] );
+    add_reply_data( debug_ctx->owner, &event->data, event_sizes[event->code] );
 }
 
 /* timeout callback while waiting for a debug event */
 static void wait_event_timeout( void *ctx )
 {
     struct debug_ctx *debug_ctx = (struct debug_ctx *)ctx;
-    struct wait_debug_event_reply reply;
+    struct wait_debug_event_reply *reply = push_reply_data( debug_ctx->owner, sizeof(*reply) );
 
     assert( debug_ctx->waiting );
 
-    reply.code = 0;
-    reply.pid  = 0;
-    reply.tid  = 0;
+    reply->code = 0;
+    reply->pid  = 0;
+    reply->tid  = 0;
     debug_ctx->waiting = 0;
     debug_ctx->timeout = NULL;
     debug_ctx->owner->error = WAIT_TIMEOUT;
-    send_reply( debug_ctx->owner, -1, 1, &reply, sizeof(reply) );    
+    send_reply( debug_ctx->owner );
 }
 
 /* wait for a debug event (or send a reply at once if one is pending) */
@@ -193,19 +191,19 @@
 
     if (!debug_ctx)  /* current thread is not a debugger */
     {
-        SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */
+        set_error( ERROR_ACCESS_DENIED ); /* FIXME */
         return 0;
     }
     assert( !debug_ctx->waiting );
     if (debug_ctx->event_head)  /* already have a pending event */
     {
         debug_ctx->waiting = 1;
-        send_event_reply( debug_ctx );
+        build_event_reply( debug_ctx );
         return 1;
     }
     if (!timeout)  /* no event and we don't want to wait */
     {
-        SET_ERROR( WAIT_TIMEOUT );
+        set_error( WAIT_TIMEOUT );
         return 0;
     }
     if (timeout != -1)  /* start the timeout */
@@ -215,6 +213,7 @@
             return 0;
     }
     debug_ctx->waiting = 1;
+    current->state = SLEEPING;
     return 1;
 }
 
@@ -226,16 +225,16 @@
     if (process->debugger != current || !event || !event->sent)
     {
         /* not debugging this process, or no event pending */
-        SET_ERROR( ERROR_ACCESS_DENIED );  /* FIXME */
+        set_error( ERROR_ACCESS_DENIED );  /* FIXME */
         return 0;
     }
     if (thread->state != TERMINATED)
     {
         /* only send a reply if the thread is still there */
         /* (we can get a continue on an exit thread/process event) */
-        struct send_debug_event_reply reply;
-        reply.status = status;
-        send_reply( thread, -1, 1, &reply, sizeof(reply) );
+        struct send_debug_event_reply *reply = push_reply_data( thread, sizeof(*reply) );
+        reply->status = status;
+        send_reply( thread );
     }
     free_event( event );
     resume_process( process );
@@ -279,7 +278,11 @@
     link_event( debug_ctx, event );
     thread->debug_event = event;
     suspend_process( thread->process );
-    if (debug_ctx->waiting) send_event_reply( debug_ctx );
+    if (debug_ctx->waiting)
+    {
+        build_event_reply( debug_ctx );
+        send_reply( debug_ctx->owner );
+    }
     return event;
 }
 
@@ -291,14 +294,14 @@
 
     if (process->debugger)  /* already being debugged */
     {
-        SET_ERROR( ERROR_ACCESS_DENIED );
+        set_error( ERROR_ACCESS_DENIED );
         return 0;
     }
     /* make sure we don't create a debugging loop */
     for (thread = debugger; thread; thread = thread->process->debugger)
         if (thread->process == process)
         {
-            SET_ERROR( ERROR_ACCESS_DENIED );
+            set_error( ERROR_ACCESS_DENIED );
             return 0;
         }
 
@@ -375,14 +378,12 @@
 /* Wait for a debug event */
 DECL_HANDLER(wait_debug_event)
 {
-    struct wait_debug_event_reply reply;
-
     if (!wait_for_debug_event( req->timeout ))
     {
-        reply.code = 0;
-        reply.pid  = NULL;
-        reply.tid  = NULL;
-        send_reply( current, -1, 1, &reply, sizeof(reply) );
+        struct wait_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
+        reply->code = 0;
+        reply->pid  = NULL;
+        reply->tid  = NULL;
     }
 }
 
@@ -400,7 +401,6 @@
         }
         release_object( process );
     }
-    send_reply( current, -1, 0 );
 }
 
 /* Start debugging an existing process */
@@ -413,26 +413,33 @@
         /* FIXME: should notice the debugged process somehow */
         release_object( process );
     }
-    send_reply( current, -1, 0 );
 }
 
 /* Send a debug event */
 DECL_HANDLER(send_debug_event)
 {
     struct thread *debugger = current->process->debugger;
-    struct send_debug_event_reply reply;
 
-    if ((req->code <= 0) || (req->code > RIP_EVENT))
-        fatal_protocol_error( "send_debug_event: bad event code %d\n", req->code );
-    if (len != event_sizes[req->code])
-        fatal_protocol_error( "send_debug_event: bad event length %d/%d\n",
-                              len, event_sizes[req->code] );
     assert( !current->debug_event );
-    reply.status = 0;
-    if (debugger)
+    if ((req->code <= 0) || (req->code > RIP_EVENT))
     {
-        if (queue_debug_event( debugger, current, req->code, data ))
-            return;  /* don't reply now, wait for continue_debug_event */
+        fatal_protocol_error( "send_debug_event: bad event code" );
+        return;
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    if (!check_req_data( event_sizes[req->code] ))
+    {
+        fatal_protocol_error( "send_debug_event: bad length" );
+        return;
+    }
+    if (debugger && queue_debug_event( debugger, current, req->code,
+                                       get_req_data( event_sizes[req->code] )))
+    {
+        /* wait for continue_debug_event */
+        current->state = SLEEPING;
+    }
+    else
+    {
+        struct send_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
+        reply->status = 0;
+    }
 }
diff --git a/server/device.c b/server/device.c
index 5822293..d167c67 100644
--- a/server/device.c
+++ b/server/device.c
@@ -21,6 +21,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct device
 {
@@ -30,10 +31,10 @@
 
 static void device_dump( struct object *obj, int verbose );
 static int device_get_info( struct object *obj, struct get_file_info_reply *reply );
-static void device_destroy( struct object *obj );
 
 static const struct object_ops device_ops =
 {
+    sizeof(struct device),
     device_dump,
     no_add_queue,
     NULL,  /* should never get called */
@@ -43,17 +44,17 @@
     no_write_fd,
     no_flush,
     device_get_info,
-    device_destroy
+    no_destroy
 };
 
-static struct object *create_device( int id )
+static struct device *create_device( int id )
 {
     struct device *dev;
-
-    if (!(dev = mem_alloc(sizeof(*dev)))) return NULL;
-    init_object( &dev->obj, &device_ops, NULL );
-    dev->id = id;
-    return &dev->obj;
+    if ((dev = alloc_object( &device_ops )))
+    {
+        dev->id = id;
+    }
+    return dev;
 }
 
 static void device_dump( struct object *obj, int verbose )
@@ -73,24 +74,16 @@
     return 1;
 }
 
-static void device_destroy( struct object *obj )
-{
-    struct device *dev = (struct device *)obj;
-    assert( obj->ops == &device_ops );
-    free( dev );
-}
-
 /* create a device */
 DECL_HANDLER(create_device)
 {
-    struct object *obj;
-    struct create_device_reply reply = { -1 };
+    struct device *dev;
+    struct create_device_reply *reply = push_reply_data( current, sizeof(*reply) );
 
-    if ((obj = create_device( req->id )))
+    if ((dev = create_device( req->id )))
     {
-        reply.handle = alloc_handle( current->process, obj,
-                                     req->access, req->inherit );
-        release_object( obj );
+        reply->handle = alloc_handle( current->process, dev, req->access, req->inherit );
+        release_object( dev );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
diff --git a/server/event.c b/server/event.c
index 5546d6e..4d3ee7e 100644
--- a/server/event.c
+++ b/server/event.c
@@ -13,6 +13,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct event
 {
@@ -24,10 +25,10 @@
 static void event_dump( struct object *obj, int verbose );
 static int event_signaled( struct object *obj, struct thread *thread );
 static int event_satisfied( struct object *obj, struct thread *thread );
-static void event_destroy( struct object *obj );
 
 static const struct object_ops event_ops =
 {
+    sizeof(struct event),
     event_dump,
     add_queue,
     remove_queue,
@@ -37,23 +38,25 @@
     no_write_fd,
     no_flush,
     no_get_file_info,
-    event_destroy
+    no_destroy
 };
 
 
-static struct object *create_event( const char *name, int manual_reset, int initial_state )
+static struct event *create_event( const char *name, size_t len,
+                                   int manual_reset, int initial_state )
 {
     struct event *event;
 
-    if (!(event = (struct event *)create_named_object( name, &event_ops, sizeof(*event) )))
-        return NULL;
-    if (GET_ERROR() != ERROR_ALREADY_EXISTS)
+    if ((event = create_named_object( &event_ops, name, len )))
     {
-        /* initialize it if it didn't already exist */
-        event->manual_reset = manual_reset;
-        event->signaled     = initial_state;
+        if (get_error() != ERROR_ALREADY_EXISTS)
+        {
+            /* initialize it if it didn't already exist */
+            event->manual_reset = manual_reset;
+            event->signaled     = initial_state;
+        }
     }
-    return &event->obj;
+    return event;
 }
 
 static int pulse_event( int handle )
@@ -122,41 +125,28 @@
     return 0;  /* Not abandoned */
 }
 
-static void event_destroy( struct object *obj )
-{
-    struct event *event = (struct event *)obj;
-    assert( obj->ops == &event_ops );
-    free( event );
-}
-
 /* create an event */
 DECL_HANDLER(create_event)
 {
-    struct create_event_reply reply = { -1 };
-    struct object *obj;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "create_event", name, len );
+    size_t len = get_req_strlen();
+    struct create_event_reply *reply = push_reply_data( current, sizeof(*reply) );
+    struct event *event;
 
-    obj = create_event( name, req->manual_reset, req->initial_state );
-    if (obj)
+    if ((event = create_event( get_req_data(len+1), len, req->manual_reset, req->initial_state )))
     {
-        reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
-        release_object( obj );
+        reply->handle = alloc_handle( current->process, event, EVENT_ALL_ACCESS, req->inherit );
+        release_object( event );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* open a handle to an event */
 DECL_HANDLER(open_event)
 {
-    struct open_event_reply reply;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "open_event", name, len );
-
-    reply.handle = open_object( name, &event_ops, req->access, req->inherit );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    size_t len = get_req_strlen();
+    struct open_event_reply *reply = push_reply_data( current, sizeof(*reply) );
+    reply->handle = open_object( get_req_data( len + 1 ), len, &event_ops,
+                                 req->access, req->inherit );
 }
 
 /* do an event operation */
@@ -174,7 +164,6 @@
         reset_event( req->handle );
         break;
     default:
-        fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
+        fatal_protocol_error( "event_op: invalid operation" );
     }
-    send_reply( current, -1, 0 );
 }
diff --git a/server/file.c b/server/file.c
index 041c67c..8e9fd80 100644
--- a/server/file.c
+++ b/server/file.c
@@ -23,6 +23,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct file
 {
@@ -51,6 +52,7 @@
 
 static const struct object_ops file_ops =
 {
+    sizeof(struct file),
     file_dump,
     file_add_queue,
     file_remove_queue,
@@ -86,123 +88,99 @@
         existing_sharing &= file->sharing;
         existing_access |= file->access;
     }
-    if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) return 0;
-    if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
-    if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
-    if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
+    if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) goto error;
+    if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) goto error;
+    if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) goto error;
+    if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) goto error;
     return 1;
+ error:
+    set_error( ERROR_SHARING_VIOLATION );
+    return 0;
 }
 
-static struct object *create_file( int fd, const char *name, unsigned int access,
-                                   unsigned int sharing, int create, unsigned int attrs )
+static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
+                                        unsigned int attrs )
 {
     struct file *file;
-    int hash = 0;
-
-    if (fd == -1)
+    if ((file = alloc_object( &file_ops )))
     {
-        int flags;
-        struct stat st;
-
-        if (!name)
-        {
-            SET_ERROR( ERROR_INVALID_PARAMETER );
-            return NULL;
-        }
-
-        /* check sharing mode */
-        hash = get_name_hash( name );
-        if (!check_sharing( name, hash, access, sharing ))
-        {
-            SET_ERROR( ERROR_SHARING_VIOLATION );
-            return NULL;
-        }
-
-        switch(create)
-        {
-        case CREATE_NEW:        flags = O_CREAT | O_EXCL; break;
-        case CREATE_ALWAYS:     flags = O_CREAT | O_TRUNC; break;
-        case OPEN_ALWAYS:       flags = O_CREAT; break;
-        case TRUNCATE_EXISTING: flags = O_TRUNC; break;
-        case OPEN_EXISTING:     flags = 0; break;
-        default:                SET_ERROR( ERROR_INVALID_PARAMETER ); return NULL;
-        }
-        switch(access & (GENERIC_READ | GENERIC_WRITE))
-        {
-        case 0: break;
-        case GENERIC_READ:  flags |= O_RDONLY; break;
-        case GENERIC_WRITE: flags |= O_WRONLY; break;
-        case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
-        }
-
-        /* FIXME: should set error to ERROR_ALREADY_EXISTS if file existed before */
-        if ((fd = open( name, flags | O_NONBLOCK,
-                        (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666 )) == -1)
-        {
-            file_set_error();
-            return NULL;
-        }
-        /* Refuse to open a directory */
-        if (fstat( fd, &st ) == -1)
-        {
-            file_set_error();
-            close( fd );
-            return NULL;
-        }
-        if (S_ISDIR(st.st_mode))
-        {
-            SET_ERROR( ERROR_ACCESS_DENIED );
-            close( fd );
-            return NULL;
-        }            
+        file->name           = NULL;
+        file->next           = NULL;
+        file->select.fd      = fd;
+        file->select.func    = default_select_event;
+        file->select.private = file;
+        file->access         = access;
+        file->flags          = attrs;
+        file->sharing        = sharing;
+        register_select_user( &file->select );
     }
-    else
-    {
-        if ((fd = dup(fd)) == -1)
-        {
-            file_set_error();
-            return NULL;
-        }
-    }
-
-    if (!(file = mem_alloc( sizeof(*file) )))
-    {
-        close( fd );
-        return NULL;
-    }
-    if (name)
-    {
-        if (!(file->name = mem_alloc( strlen(name) + 1 )))
-        {
-            close( fd );
-            free( file );
-            return NULL;
-        }
-        strcpy( file->name, name );
-        file->next = file_hash[hash];
-        file_hash[hash] = file;
-    }
-    else
-    {
-        file->name = NULL;
-        file->next = NULL;
-    }
-    init_object( &file->obj, &file_ops, NULL );
-    file->select.fd      = fd;
-    file->select.func    = default_select_event;
-    file->select.private = file;
-    file->access         = access;
-    file->flags          = attrs;
-    file->sharing        = sharing;
-    register_select_user( &file->select );
-    CLEAR_ERROR();
-    return &file->obj;
+    return file;
 }
 
-/* Create a temp file for anonymous mappings */
-struct file *create_temp_file( int access )
+
+static struct file *create_file( const char *nameptr, size_t len, unsigned int access,
+                                 unsigned int sharing, int create, unsigned int attrs )
 {
     struct file *file;
+    int hash, flags;
+    struct stat st;
+    char *name;
+    int fd = -1;
+
+    if (!(name = mem_alloc( len + 1 ))) return NULL;
+    memcpy( name, nameptr, len );
+    name[len] = 0;
+
+    /* check sharing mode */
+    hash = get_name_hash( name );
+    if (!check_sharing( name, hash, access, sharing )) goto error;
+
+    switch(create)
+    {
+    case CREATE_NEW:        flags = O_CREAT | O_EXCL; break;
+    case CREATE_ALWAYS:     flags = O_CREAT | O_TRUNC; break;
+    case OPEN_ALWAYS:       flags = O_CREAT; break;
+    case TRUNCATE_EXISTING: flags = O_TRUNC; break;
+    case OPEN_EXISTING:     flags = 0; break;
+    default:                set_error( ERROR_INVALID_PARAMETER ); goto error;
+    }
+    switch(access & (GENERIC_READ | GENERIC_WRITE))
+    {
+    case 0: break;
+    case GENERIC_READ:  flags |= O_RDONLY; break;
+    case GENERIC_WRITE: flags |= O_WRONLY; break;
+    case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
+    }
+
+    /* FIXME: should set error to ERROR_ALREADY_EXISTS if file existed before */
+    if ((fd = open( name, flags | O_NONBLOCK,
+                    (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666 )) == -1)
+        goto file_error;
+    /* refuse to open a directory */
+    if (fstat( fd, &st ) == -1) goto file_error;
+    if (S_ISDIR(st.st_mode))
+    {
+        set_error( ERROR_ACCESS_DENIED );
+        goto error;
+    }            
+
+    if (!(file = create_file_for_fd( fd, access, sharing, attrs ))) goto error;
+    file->name = name;
+    file->next = file_hash[hash];
+    file_hash[hash] = file;
+    return file;
+
+ file_error:
+    file_set_error();
+ error:
+    if (fd != -1) close( fd );
+    free( name );
+    return NULL;
+}
+
+/* Create an anonymous Unix file */
+int create_anonymous_file(void)
+{
     char *name;
     int fd;
 
@@ -210,34 +188,28 @@
     {
         if (!(name = tmpnam(NULL)))
         {
-            SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
-            return NULL;
+            set_error( ERROR_TOO_MANY_OPEN_FILES );
+            return -1;
         }
         fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 );
     } while ((fd == -1) && (errno == EEXIST));
     if (fd == -1)
     {
         file_set_error();
-        return NULL;
+        return -1;
     }
     unlink( name );
+    return fd;
+}
 
-    if (!(file = mem_alloc( sizeof(*file) )))
-    {
-        close( fd );
-        return NULL;
-    }
-    init_object( &file->obj, &file_ops, NULL );
-    file->name           = NULL;
-    file->next           = NULL;
-    file->select.fd      = fd;
-    file->select.func    = default_select_event;
-    file->select.private = file;
-    file->access         = access;
-    file->flags          = 0;
-    file->sharing        = 0;
-    register_select_user( &file->select );
-    CLEAR_ERROR();
+/* Create a temp file for anonymous mappings */
+struct file *create_temp_file( int access )
+{
+    struct file *file;
+    int fd;
+
+    if ((fd = create_anonymous_file()) != -1) return NULL;
+    if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
     return file;
 }
 
@@ -245,8 +217,8 @@
 {
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
-    printf( "File fd=%d flags=%08x name='%s'\n",
-            file->select.fd, file->flags, file->name );
+    fprintf( stderr, "File fd=%d flags=%08x name='%s'\n",
+             file->select.fd, file->flags, file->name );
 }
 
 static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -368,7 +340,6 @@
     }
     unregister_select_user( &file->select );
     close( file->select.fd );
-    free( file );
 }
 
 /* set the last error depending on errno */
@@ -376,22 +347,22 @@
 {
     switch (errno)
     {
-    case EAGAIN:    SET_ERROR( ERROR_SHARING_VIOLATION ); break;
-    case EBADF:     SET_ERROR( ERROR_INVALID_HANDLE ); break;
-    case ENOSPC:    SET_ERROR( ERROR_HANDLE_DISK_FULL ); break;
+    case EAGAIN:    set_error( ERROR_SHARING_VIOLATION ); break;
+    case EBADF:     set_error( ERROR_INVALID_HANDLE ); break;
+    case ENOSPC:    set_error( ERROR_HANDLE_DISK_FULL ); break;
     case EACCES:
-    case EPERM:     SET_ERROR( ERROR_ACCESS_DENIED ); break;
-    case EROFS:     SET_ERROR( ERROR_WRITE_PROTECT ); break;
-    case EBUSY:     SET_ERROR( ERROR_LOCK_VIOLATION ); break;
-    case ENOENT:    SET_ERROR( ERROR_FILE_NOT_FOUND ); break;
-    case EISDIR:    SET_ERROR( ERROR_CANNOT_MAKE ); break;
+    case EPERM:     set_error( ERROR_ACCESS_DENIED ); break;
+    case EROFS:     set_error( ERROR_WRITE_PROTECT ); break;
+    case EBUSY:     set_error( ERROR_LOCK_VIOLATION ); break;
+    case ENOENT:    set_error( ERROR_FILE_NOT_FOUND ); break;
+    case EISDIR:    set_error( ERROR_CANNOT_MAKE ); break;
     case ENFILE:
-    case EMFILE:    SET_ERROR( ERROR_NO_MORE_FILES ); break;
-    case EEXIST:    SET_ERROR( ERROR_FILE_EXISTS ); break;
-    case EINVAL:    SET_ERROR( ERROR_INVALID_PARAMETER ); break;
-    case ESPIPE:    SET_ERROR( ERROR_SEEK ); break;
-    case ENOTEMPTY: SET_ERROR( ERROR_DIR_NOT_EMPTY ); break;
-    default:        perror("file_set_error"); SET_ERROR( ERROR_UNKNOWN ); break;
+    case EMFILE:    set_error( ERROR_NO_MORE_FILES ); break;
+    case EEXIST:    set_error( ERROR_FILE_EXISTS ); break;
+    case EINVAL:    set_error( ERROR_INVALID_PARAMETER ); break;
+    case ESPIPE:    set_error( ERROR_SEEK ); break;
+    case ENOTEMPTY: set_error( ERROR_DIR_NOT_EMPTY ); break;
+    default:        perror("file_set_error"); set_error( ERROR_UNKNOWN ); break;
     }
 }
 
@@ -415,7 +386,7 @@
     if (*high)
     {
         fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
-        SET_ERROR( ERROR_INVALID_PARAMETER );
+        set_error( ERROR_INVALID_PARAMETER );
         return 0;
     }
 
@@ -425,7 +396,7 @@
     {
         /* Check for seek before start of file */
         if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
-            SET_ERROR( ERROR_NEGATIVE_SEEK );
+            set_error( ERROR_NEGATIVE_SEEK );
         else
             file_set_error();
         release_object( file );
@@ -462,7 +433,7 @@
 
     if (size_high)
     {
-        SET_ERROR( ERROR_INVALID_PARAMETER );
+        set_error( ERROR_INVALID_PARAMETER );
         return 0;
     }
     if (fstat( file->select.fd, &st ) == -1)
@@ -517,19 +488,28 @@
 /* create a file */
 DECL_HANDLER(create_file)
 {
-    struct create_file_reply reply = { -1 };
-    struct object *obj;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "create_file", name, len );
+    struct create_file_reply *reply = push_reply_data( current, sizeof(*reply) );
+    struct file *file = NULL;
 
-    if ((obj = create_file( fd, name, req->access,
-                            req->sharing, req->create, req->attrs )) != NULL)
+    if (fd == -1)
     {
-        reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
-        release_object( obj );
+        size_t len = get_req_strlen();
+        file = create_file( get_req_data( len + 1), len, req->access,
+                            req->sharing, req->create, req->attrs );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else
+    {
+        if ((fd = dup(fd)) == -1)
+            file_set_error();
+        else
+            file = create_file_for_fd( fd, req->access, req->sharing, req->attrs );
+    }
+    if (file)
+    {
+        reply->handle = alloc_handle( current->process, file, req->access, req->inherit );
+        release_object( file );
+    }
+    else reply->handle = -1;
 }
 
 /* get a Unix fd to read from a file */
@@ -544,7 +524,7 @@
         release_object( obj );
     }
     else read_fd = -1;
-    send_reply( current, read_fd, 0 );
+    set_reply_fd( current, read_fd );
 }
 
 /* get a Unix fd to write to a file */
@@ -559,7 +539,7 @@
         release_object( obj );
     }
     else write_fd = -1;
-    send_reply( current, write_fd, 0 );
+    set_reply_fd( current, write_fd );
 }
 
 /* set a file current position */
@@ -569,14 +549,13 @@
     reply.low = req->low;
     reply.high = req->high;
     set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    add_reply_data( current, &reply, sizeof(reply) );
 }
 
 /* truncate (or extend) a file */
 DECL_HANDLER(truncate_file)
 {
     truncate_file( req->handle );
-    send_reply( current, -1, 0 );
 }
 
 /* flush a file buffers */
@@ -589,28 +568,25 @@
         obj->ops->flush( obj );
         release_object( obj );
     }
-    send_reply( current, -1, 0 );
 }
 
 /* set a file access and modification times */
 DECL_HANDLER(set_file_time)
 {
     set_file_time( req->handle, req->access_time, req->write_time );
-    send_reply( current, -1, 0 );
 }
 
 /* get a file information */
 DECL_HANDLER(get_file_info)
 {
     struct object *obj;
-    struct get_file_info_reply reply;
+    struct get_file_info_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
     {
-        obj->ops->get_file_info( obj, &reply );
+        obj->ops->get_file_info( obj, reply );
         release_object( obj );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
 }
 
 /* lock a region of a file */
@@ -624,7 +600,6 @@
                    req->count_high, req->count_low );
         release_object( file );
     }
-    send_reply( current, -1, 0 );
 }
 
 /* unlock a region of a file */
@@ -638,5 +613,4 @@
                      req->count_high, req->count_low );
         release_object( file );
     }
-    send_reply( current, -1, 0 );
 }
diff --git a/server/handle.c b/server/handle.c
index bb6b64e..4b5c303 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -16,6 +16,7 @@
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
+#include "request.h"
 
 struct handle_entry
 {
@@ -55,6 +56,7 @@
 
 static const struct object_ops handle_table_ops =
 {
+    sizeof(struct handle_table),
     handle_table_dump,
     no_add_queue,
     NULL,  /* should never get called */
@@ -104,7 +106,6 @@
         if (obj) release_object( obj );
     }
     free( table->entries );
-    free( table );
 }
 
 /* allocate a new handle table */
@@ -113,7 +114,7 @@
     struct handle_table *table;
 
     if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
-    if (!(table = alloc_object( sizeof(*table), &handle_table_ops, NULL )))
+    if (!(table = alloc_object( &handle_table_ops )))
         return NULL;
     table->process = process;
     table->count   = count;
@@ -134,7 +135,7 @@
     count *= 2;
     if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
     {
-        SET_ERROR( ERROR_OUTOFMEMORY );
+        set_error( ERROR_OUTOFMEMORY );
         return 0;
     }
     table->entries = new_entries;
@@ -216,7 +217,7 @@
     return entry;
 
  error:
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return NULL;
 }
 
@@ -319,7 +320,7 @@
         if (!(entry = get_handle( process, handle ))) return NULL;
         if ((entry->access & access) != access)
         {
-            SET_ERROR( ERROR_ACCESS_DENIED );
+            set_error( ERROR_ACCESS_DENIED );
             return NULL;
         }
         obj = entry->ptr;
@@ -327,7 +328,7 @@
     }
     if (ops && (obj->ops != ops))
     {
-        SET_ERROR( ERROR_INVALID_HANDLE );  /* not the right type */
+        set_error( ERROR_INVALID_HANDLE );  /* not the right type */
         return NULL;
     }
     return grab_object( obj );
@@ -362,7 +363,7 @@
         else  /* pseudo-handle, give it full access */
         {
             access = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
-            CLEAR_ERROR();
+            clear_error();
         }
     }
     access &= ~RESERVED_ALL;
@@ -375,19 +376,19 @@
 }
 
 /* open a new handle to an existing object */
-int open_object( const char *name, const struct object_ops *ops,
+int open_object( const char *name, size_t len, const struct object_ops *ops,
                  unsigned int access, int inherit )
 {
-    struct object *obj = find_object( name );
+    struct object *obj = find_object( name, len );
     if (!obj) 
     {
-        SET_ERROR( ERROR_FILE_NOT_FOUND );
+        set_error( ERROR_FILE_NOT_FOUND );
         return -1;
     }
     if (ops && obj->ops != ops)
     {
         release_object( obj );
-        SET_ERROR( ERROR_INVALID_HANDLE );  /* FIXME: not the right type */ 
+        set_error( ERROR_INVALID_HANDLE );  /* FIXME: not the right type */ 
         return -1;
     }
     return alloc_handle( current->process, obj, access, inherit );
@@ -397,22 +398,19 @@
 DECL_HANDLER(close_handle)
 {
     close_handle( current->process, req->handle );
-    send_reply( current, -1, 0 );
 }
 
 /* get information about a handle */
 DECL_HANDLER(get_handle_info)
 {
-    struct get_handle_info_reply reply;
-    reply.flags = set_handle_info( current->process, req->handle, 0, 0 );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    struct get_handle_info_reply *reply = push_reply_data( current, sizeof(*reply) );
+    reply->flags = set_handle_info( current->process, req->handle, 0, 0 );
 }
 
 /* set a handle information */
 DECL_HANDLER(set_handle_info)
 {
     set_handle_info( current->process, req->handle, req->mask, req->flags );
-    send_reply( current, -1, 0 );
 }
 
 /* duplicate a handle */
@@ -439,5 +437,5 @@
             close_handle( src, req->src_handle );
         release_object( src );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    add_reply_data( current, &reply, sizeof(reply) );
 }
diff --git a/server/handle.h b/server/handle.h
index cd42e87..5763714 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -11,6 +11,8 @@
 #error This file can only be used in the Wine server
 #endif
 
+#include <stdlib.h>
+
 struct process;
 struct object_ops;
 
@@ -25,7 +27,7 @@
                                       unsigned int access, const struct object_ops *ops );
 extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
                              unsigned int access, int inherit, int options );
-extern int open_object( const char *name, const struct object_ops *ops,
+extern int open_object( const char *name, size_t len, const struct object_ops *ops,
                         unsigned int access, int inherit );
 extern struct object *alloc_handle_table( struct process *process, int count );
 extern struct object *copy_handle_table( struct process *process, struct process *parent );
diff --git a/server/main.c b/server/main.c
index fe70c32..ac0c308 100644
--- a/server/main.c
+++ b/server/main.c
@@ -10,7 +10,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "server.h"
 #include "object.h"
 #include "thread.h"
 
diff --git a/server/mapping.c b/server/mapping.c
index 91e958a..b336749 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -16,6 +16,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct mapping
 {
@@ -31,6 +32,7 @@
 
 static const struct object_ops mapping_ops =
 {
+    sizeof(struct mapping),
     mapping_dump,
     no_add_queue,
     NULL,  /* should never get called */
@@ -82,17 +84,16 @@
 
 
 static struct object *create_mapping( int size_high, int size_low, int protect,
-                                      int handle, const char *name )
+                                      int handle, const char *name, size_t len )
 {
     struct mapping *mapping;
     int access = 0;
 
     if (!page_mask) init_page_size();
 
-    if (!(mapping = (struct mapping *)create_named_object( name, &mapping_ops,
-                                                           sizeof(*mapping) )))
+    if (!(mapping = create_named_object( &mapping_ops, name, len )))
         return NULL;
-    if (GET_ERROR() == ERROR_ALREADY_EXISTS)
+    if (get_error() == ERROR_ALREADY_EXISTS)
         return &mapping->obj;  /* Nothing else to do */
 
     if (protect & VPROT_READ) access |= GENERIC_READ;
@@ -115,7 +116,7 @@
     {
         if (!size_high && !size_low)
         {
-            SET_ERROR( ERROR_INVALID_PARAMETER );
+            set_error( ERROR_INVALID_PARAMETER );
             mapping->file = NULL;
             goto error;
         }
@@ -163,45 +164,39 @@
     struct mapping *mapping = (struct mapping *)obj;
     assert( obj->ops == &mapping_ops );
     if (mapping->file) release_object( mapping->file );
-    free( mapping );
 }
 
 /* create a file mapping */
 DECL_HANDLER(create_mapping)
 {
+    size_t len = get_req_strlen();
+    struct create_mapping_reply *reply = push_reply_data( current, sizeof(*reply) );
     struct object *obj;
-    struct create_mapping_reply reply = { -1 };
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "create_mapping", name, len );
 
     if ((obj = create_mapping( req->size_high, req->size_low,
-                               req->protect, req->handle, name )))
+                               req->protect, req->handle, get_req_data( len + 1 ), len )))
     {
         int access = FILE_MAP_ALL_ACCESS;
         if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
-        reply.handle = alloc_handle( current->process, obj, access, req->inherit );
+        reply->handle = alloc_handle( current->process, obj, access, req->inherit );
         release_object( obj );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* open a handle to a mapping */
 DECL_HANDLER(open_mapping)
 {
-    struct open_mapping_reply reply;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "open_mapping", name, len );
-
-    reply.handle = open_object( name, &mapping_ops, req->access, req->inherit );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    size_t len = get_req_strlen();
+    struct open_mapping_reply *reply = push_reply_data( current, sizeof(*reply) );
+    reply->handle = open_object( get_req_data( len + 1 ), len, &mapping_ops,
+                                 req->access, req->inherit );
 }
 
 /* get a mapping information */
 DECL_HANDLER(get_mapping_info)
 {
-    struct get_mapping_info_reply reply;
-    int map_fd = get_mapping_info( req->handle, &reply );
-    send_reply( current, map_fd, 1, &reply, sizeof(reply) );
+    struct get_mapping_info_reply *reply = push_reply_data( current, sizeof(*reply) );
+    int map_fd = get_mapping_info( req->handle, reply );
+    set_reply_fd( current, map_fd );
 }
diff --git a/server/mutex.c b/server/mutex.c
index 2adaacb..f171d95 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -13,6 +13,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct mutex
 {
@@ -27,10 +28,10 @@
 static void mutex_dump( struct object *obj, int verbose );
 static int mutex_signaled( struct object *obj, struct thread *thread );
 static int mutex_satisfied( struct object *obj, struct thread *thread );
-static void mutex_destroy( struct object *obj );
 
 static const struct object_ops mutex_ops =
 {
+    sizeof(struct mutex),
     mutex_dump,
     add_queue,
     remove_queue,
@@ -40,26 +41,27 @@
     no_write_fd,
     no_flush,
     no_get_file_info,
-    mutex_destroy
+    no_destroy
 };
 
 
-static struct object *create_mutex( const char *name, int owned )
+static struct mutex *create_mutex( const char *name, size_t len, int owned )
 {
     struct mutex *mutex;
 
-    if (!(mutex = (struct mutex *)create_named_object( name, &mutex_ops, sizeof(*mutex) )))
-        return NULL;
-    if (GET_ERROR() != ERROR_ALREADY_EXISTS)
+    if ((mutex = create_named_object( &mutex_ops, name, len )))
     {
-        /* initialize it if it didn't already exist */
-        mutex->count = 0;
-        mutex->owner = NULL;
-        mutex->abandoned = 0;
-        mutex->next = mutex->prev = NULL;
-        if (owned) mutex_satisfied( &mutex->obj, current );
+        if (get_error() != ERROR_ALREADY_EXISTS)
+        {
+            /* initialize it if it didn't already exist */
+            mutex->count = 0;
+            mutex->owner = NULL;
+            mutex->abandoned = 0;
+            mutex->next = mutex->prev = NULL;
+            if (owned) mutex_satisfied( &mutex->obj, current );
+        }
     }
-    return &mutex->obj;
+    return mutex;
 }
 
 /* release a mutex once the recursion count is 0 */
@@ -75,23 +77,6 @@
     wake_up( &mutex->obj, 0 );
 }
 
-static int release_mutex( int handle )
-{
-    struct mutex *mutex;
-
-    if (!(mutex = (struct mutex *)get_handle_obj( current->process, handle,
-                                                  MUTEX_MODIFY_STATE, &mutex_ops )))
-        return 0;
-    if (!mutex->count || (mutex->owner != current))
-    {
-        SET_ERROR( ERROR_NOT_OWNER );
-        return 0;
-    }
-    if (!--mutex->count) do_release( mutex, current );
-    release_object( mutex );
-    return 1;
-}
-
 void abandon_mutexes( struct thread *thread )
 {
     while (thread->mutex)
@@ -138,46 +123,40 @@
     return 1;
 }
 
-static void mutex_destroy( struct object *obj )
-{
-    struct mutex *mutex = (struct mutex *)obj;
-    assert( obj->ops == &mutex_ops );
-    free( mutex );
-}
-
 /* create a mutex */
 DECL_HANDLER(create_mutex)
 {
-    struct create_mutex_reply reply = { -1 };
-    struct object *obj;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "create_mutex", name, len );
+    size_t len = get_req_strlen();
+    struct create_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
+    struct mutex *mutex;
 
-    obj = create_mutex( name, req->owned );
-    if (obj)
+    if ((mutex = create_mutex( get_req_data( len + 1 ), len, req->owned )))
     {
-        reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
-        release_object( obj );
+        reply->handle = alloc_handle( current->process, mutex, MUTEX_ALL_ACCESS, req->inherit );
+        release_object( mutex );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* open a handle to a mutex */
 DECL_HANDLER(open_mutex)
 {
-    struct open_mutex_reply reply;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "open_mutex", name, len );
-
-    reply.handle = open_object( name, &mutex_ops, req->access, req->inherit );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    size_t len = get_req_strlen();
+    struct open_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
+    reply->handle = open_object( get_req_data( len + 1 ), len, &mutex_ops,
+                                 req->access, req->inherit );
 }
 
 /* release a mutex */
 DECL_HANDLER(release_mutex)
 {
-    if (release_mutex( req->handle )) CLEAR_ERROR();
-    send_reply( current, -1, 0 );
+    struct mutex *mutex;
+
+    if ((mutex = (struct mutex *)get_handle_obj( current->process, req->handle,
+                                                 MUTEX_MODIFY_STATE, &mutex_ops )))
+    {
+        if (!mutex->count || (mutex->owner != current)) set_error( ERROR_NOT_OWNER );
+        else if (!--mutex->count) do_release( mutex, current );
+        release_object( mutex );
+    }
 }
diff --git a/server/object.c b/server/object.c
index e036392..7054e41 100644
--- a/server/object.c
+++ b/server/object.c
@@ -19,8 +19,9 @@
 struct object_name
 {
     struct object_name *next;
+    struct object_name *prev;
     struct object      *obj;
-    int                 len;
+    size_t              len;
     char                name[1];
 };
 
@@ -45,96 +46,115 @@
 
 /*****************************************************************/
 
+/* malloc replacement */
 void *mem_alloc( size_t size )
 {
     void *ptr = malloc( size );
     if (ptr) memset( ptr, 0x55, size );
-    else if (current) SET_ERROR( ERROR_OUTOFMEMORY );
+    else if (current) set_error( ERROR_OUTOFMEMORY );
     return ptr;
 }
 
 /*****************************************************************/
 
-static int get_name_hash( const char *name )
+static int get_name_hash( const char *name, size_t len )
 {
-    int hash = 0;
-    while (*name) hash ^= *name++;
+    char hash = 0;
+    while (len--) hash ^= *name++;
     return hash % NAME_HASH_SIZE;
 }
 
-static struct object_name *add_name( struct object *obj, const char *name )
+/* allocate a name for an object */
+static struct object_name *alloc_name( const char *name, size_t len )
 {
     struct object_name *ptr;
-    int hash = get_name_hash( name );
-    int len = strlen( name );
 
-    if (!(ptr = (struct object_name *)mem_alloc( sizeof(*ptr) + len )))
-        return NULL;
-    ptr->next = names[hash];
-    ptr->obj  = obj;
-    ptr->len  = len;
-    strcpy( ptr->name, name );
-    names[hash] = ptr;
+    if ((ptr = mem_alloc( sizeof(*ptr) + len )))
+    {
+        ptr->len = len;
+        memcpy( ptr->name, name, len );
+        ptr->name[len] = 0;
+    }
     return ptr;
 }
 
+/* free the name of an object */
 static void free_name( struct object *obj )
 {
-    int hash = get_name_hash( obj->name->name );
-    struct object_name **pptr = &names[hash];
-    while (*pptr && *pptr != obj->name) pptr = &(*pptr)->next;
-    assert( *pptr );
-    *pptr = (*pptr)->next;
-    free( obj->name );
+    struct object_name *ptr = obj->name;
+    if (ptr->next) ptr->next->prev = ptr->prev;
+    if (ptr->prev) ptr->prev->next = ptr->next;
+    else
+    {
+        int hash;
+        for (hash = 0; hash < NAME_HASH_SIZE; hash++)
+            if (names[hash] == ptr)
+            {
+                names[hash] = ptr->next;
+                break;
+            }
+    }
+    free( ptr );
 }
 
-/* initialize an already allocated object */
-/* return 1 if OK, 0 on error */
-int init_object( struct object *obj, const struct object_ops *ops,
-                 const char *name )
+/* set the name of an existing object */
+static void set_object_name( struct object *obj, struct object_name *ptr )
 {
-    obj->refcount = 1;
-    obj->ops      = ops;
-    obj->head     = NULL;
-    obj->tail     = NULL;
-    if (!name) obj->name = NULL;
-    else if (!(obj->name = add_name( obj, name ))) return 0;
-#ifdef DEBUG_OBJECTS
-    obj->prev = NULL;
-    if ((obj->next = first) != NULL) obj->next->prev = obj;
-    first = obj;
-#endif
-    return 1;
+    int hash = get_name_hash( ptr->name, ptr->len );
+
+    if ((ptr->next = names[hash]) != NULL) ptr->next->prev = ptr;
+    ptr->obj = obj;
+    ptr->prev = NULL;
+    names[hash] = ptr;
+    assert( !obj->name );
+    obj->name = ptr;
 }
 
 /* allocate and initialize an object */
-void *alloc_object( size_t size, const struct object_ops *ops, const char *name )
+void *alloc_object( const struct object_ops *ops )
 {
-    struct object *obj = mem_alloc( size );
-    if (obj) init_object( obj, ops, name );
+    struct object *obj = mem_alloc( ops->size );
+    if (obj)
+    {
+        obj->refcount = 1;
+        obj->ops      = ops;
+        obj->head     = NULL;
+        obj->tail     = NULL;
+        obj->name     = NULL;
+#ifdef DEBUG_OBJECTS
+        obj->prev = NULL;
+        if ((obj->next = first) != NULL) obj->next->prev = obj;
+        first = obj;
+#endif
+    }
     return obj;
 }
 
-struct object *create_named_object( const char *name, const struct object_ops *ops, size_t size )
+void *create_named_object( const struct object_ops *ops, const char *name, size_t len )
 {
     struct object *obj;
-    if ((obj = find_object( name )))
+    struct object_name *name_ptr;
+
+    if (!name || !len) return alloc_object( ops );
+    if (!(name_ptr = alloc_name( name, len ))) return NULL;
+
+    if ((obj = find_object( name_ptr->name, name_ptr->len )))
     {
+        free( name_ptr );  /* we no longer need it */
         if (obj->ops == ops)
         {
-            SET_ERROR( ERROR_ALREADY_EXISTS );
+            set_error( ERROR_ALREADY_EXISTS );
             return obj;
         }
-        SET_ERROR( ERROR_INVALID_HANDLE );
+        set_error( ERROR_INVALID_HANDLE );
         return NULL;
     }
-    if (!(obj = mem_alloc( size ))) return NULL;
-    if (!init_object( obj, ops, name ))
+    if ((obj = alloc_object( ops )))
     {
-        free( obj );
-        return NULL;
+        set_object_name( obj, name_ptr );
+        clear_error();
     }
-    CLEAR_ERROR();
+    else free( name_ptr );
     return obj;
 }
 
@@ -171,25 +191,29 @@
         else first = obj->next;
 #endif
         obj->ops->destroy( obj );
+        memset( obj, 0xaa, obj->ops->size );
+        free( obj );
     }
 }
 
 /* find an object by its name; the refcount is incremented */
-struct object *find_object( const char *name )
+struct object *find_object( const char *name, size_t len )
 {
     struct object_name *ptr;
-    if (!name) return NULL;
-    ptr = names[ get_name_hash( name ) ];
-    while (ptr && strcmp( ptr->name, name )) ptr = ptr->next;
-    if (!ptr) return NULL;
-    return grab_object( ptr->obj );
+    if (!name || !len) return NULL;
+    for (ptr = names[ get_name_hash( name, len ) ]; ptr; ptr = ptr->next)
+    {
+        if (ptr->len != len) continue;
+        if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj );
+    }
+    return NULL;
 }
 
 /* functions for unimplemented object operations */
 
 int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
 {
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return 0;
 }
 
@@ -200,28 +224,32 @@
 
 int no_read_fd( struct object *obj )
 {
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return -1;
 }
 
 int no_write_fd( struct object *obj )
 {
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return -1;
 }
 
 int no_flush( struct object *obj )
 {
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return 0;
 }
 
 int no_get_file_info( struct object *obj, struct get_file_info_reply *info )
 {
-    SET_ERROR( ERROR_INVALID_HANDLE );
+    set_error( ERROR_INVALID_HANDLE );
     return 0;
 }
 
+void no_destroy( struct object *obj )
+{
+}
+
 void default_select_event( int event, void *private )
 {
     struct object *obj = (struct object *)private;
diff --git a/server/object.h b/server/object.h
index c5d69fd..8da0c81 100644
--- a/server/object.h
+++ b/server/object.h
@@ -13,7 +13,6 @@
 
 #include <sys/time.h>
 #include "server.h"
-#include "server/request.h"
 
 #define DEBUG_OBJECTS
 
@@ -29,6 +28,8 @@
 /* operations valid on all objects */
 struct object_ops
 {
+    /* size of this object type */
+    size_t size;
     /* dump the object (for debugging) */
     void (*dump)(struct object *,int);
     /* add a thread to the object wait queue */
@@ -65,49 +66,27 @@
 };
 
 extern void *mem_alloc( size_t size );  /* malloc wrapper */
-extern void *alloc_object( size_t size, const struct object_ops *ops, const char *name );
-extern struct object *create_named_object( const char *name, const struct object_ops *ops,
-                                           size_t size );
-extern int init_object( struct object *obj, const struct object_ops *ops, const char *name );
+extern char *mem_strdup( const char *str );
+extern void *alloc_object( const struct object_ops *ops );
 extern const char *get_object_name( struct object *obj );
+extern void *create_named_object( const struct object_ops *ops, const char *name, size_t len );
 /* grab/release_object can take any pointer, but you better make sure */
 /* that the thing pointed to starts with a struct object... */
 extern struct object *grab_object( void *obj );
 extern void release_object( void *obj );
-extern struct object *find_object( const char *name );
+extern struct object *find_object( const char *name, size_t len );
 extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern int no_satisfied( struct object *obj, struct thread *thread );
 extern int no_read_fd( struct object *obj );
 extern int no_write_fd( struct object *obj );
 extern int no_flush( struct object *obj );
 extern int no_get_file_info( struct object *obj, struct get_file_info_reply *info );
+extern void no_destroy( struct object *obj );
 extern void default_select_event( int event, void *private );
 #ifdef DEBUG_OBJECTS
 extern void dump_objects(void);
 #endif
 
-/* request handlers */
-
-struct iovec;
-struct thread;
-
-extern void fatal_protocol_error( const char *err, ... );
-extern void call_req_handler( struct thread *thread, enum request req,
-                              void *data, int len, int fd );
-extern void call_timeout_handler( void *thread );
-extern void call_kill_handler( struct thread *thread, int exit_code );
-
-extern void trace_request( enum request req, void *data, int len, int fd );
-extern void trace_timeout(void);
-extern void trace_kill( int exit_code );
-extern void trace_reply( struct thread *thread, int type, int pass_fd,
-                         struct iovec *vec, int veclen );
-/* check that the string is NULL-terminated and that the len is correct */
-#define CHECK_STRING(func,str,len) \
-  do { if (((str)[(len)-1] || strlen(str) != (len)-1)) \
-         fatal_protocol_error( "%s: invalid string '%.*s'\n", (func), (len), (str) ); \
-     } while(0)
-
 /* select functions */
 
 #define READ_EVENT    1
@@ -143,8 +122,8 @@
 
 extern struct client *add_client( int client_fd, struct thread *self );
 extern void remove_client( struct client *client, int exit_code );
-extern int send_reply_v( struct client *client, int type, int pass_fd,
-                         struct iovec *vec, int veclen );
+extern void client_pass_fd( struct client *client, int pass_fd );
+extern void client_reply( struct client *client );
 
 /* mutex functions */
 
@@ -156,6 +135,7 @@
                                   unsigned int access );
 extern int file_get_mmap_fd( struct file *file );
 extern int grow_file( struct file *file, int size_high, int size_low );
+extern int create_anonymous_file(void);
 extern struct file *create_temp_file( int access );
 extern void file_set_error(void);
 
diff --git a/server/pipe.c b/server/pipe.c
index 368c782..9eaf93d 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -21,6 +21,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 enum side { READ_SIDE, WRITE_SIDE };
 
@@ -43,6 +44,7 @@
 
 static const struct object_ops pipe_ops =
 {
+    sizeof(struct pipe),
     pipe_dump,
     pipe_add_queue,
     pipe_remove_queue,
@@ -56,9 +58,26 @@
 };
 
 
+static struct pipe *create_pipe_side( int fd, int side )
+{
+    struct pipe *pipe;
+
+    if ((pipe = alloc_object( &pipe_ops )))
+    {
+        pipe->select.fd      = fd;
+        pipe->select.func    = default_select_event;
+        pipe->select.private = pipe;
+        pipe->other          = NULL;
+        pipe->side           = side;
+        register_select_user( &pipe->select );
+    }
+    return pipe;
+}
+
 static int create_pipe( struct object *obj[2] )
 {
-    struct pipe *newpipe[2];
+    struct pipe *read_pipe;
+    struct pipe *write_pipe;
     int fd[2];
 
     if (pipe( fd ) == -1)
@@ -66,37 +85,21 @@
         file_set_error();
         return 0;
     }
-    if (!(newpipe[0] = mem_alloc( sizeof(struct pipe) )))
+    if ((read_pipe = create_pipe_side( fd[0], READ_SIDE )))
     {
-        close( fd[0] );
-        close( fd[1] );
-        return 0;
+        if ((write_pipe = create_pipe_side( fd[1], WRITE_SIDE )))
+        {
+            write_pipe->other = read_pipe;
+            read_pipe->other  = write_pipe;
+            obj[0] = &read_pipe->obj;
+            obj[1] = &write_pipe->obj;
+            return 1;
+        }
+        release_object( read_pipe );
     }
-    if (!(newpipe[1] = mem_alloc( sizeof(struct pipe) )))
-    {
-        close( fd[0] );
-        close( fd[1] );
-        free( newpipe[0] );
-        return 0;
-    }
-    init_object( &newpipe[0]->obj, &pipe_ops, NULL );
-    init_object( &newpipe[1]->obj, &pipe_ops, NULL );
-    newpipe[0]->select.fd      = fd[0];
-    newpipe[0]->select.func    = default_select_event;
-    newpipe[0]->select.private = newpipe[0];
-    newpipe[0]->other          = newpipe[1];
-    newpipe[0]->side           = READ_SIDE;
-    newpipe[1]->select.fd      = fd[1];
-    newpipe[1]->select.func    = default_select_event;
-    newpipe[1]->select.private = newpipe[1];
-    newpipe[1]->other          = newpipe[0];
-    newpipe[1]->side           = WRITE_SIDE;
-    obj[0] = &newpipe[0]->obj;
-    obj[1] = &newpipe[1]->obj;
-    register_select_user( &newpipe[0]->select );
-    register_select_user( &newpipe[1]->select );
-    CLEAR_ERROR();
-    return 1;
+    close( fd[0] );
+    close( fd[1] );
+    return 0;
 }
 
 static void pipe_dump( struct object *obj, int verbose )
@@ -157,12 +160,12 @@
 
     if (!pipe->other)
     {
-        SET_ERROR( ERROR_BROKEN_PIPE );
+        set_error( ERROR_BROKEN_PIPE );
         return -1;
     }
     if (pipe->side != READ_SIDE)  /* FIXME: should not be necessary */
     {
-        SET_ERROR( ERROR_ACCESS_DENIED );
+        set_error( ERROR_ACCESS_DENIED );
         return -1;
     }
     return dup( pipe->select.fd );
@@ -175,12 +178,12 @@
 
     if (!pipe->other)
     {
-        SET_ERROR( ERROR_BROKEN_PIPE );
+        set_error( ERROR_BROKEN_PIPE );
         return -1;
     }
     if (pipe->side != WRITE_SIDE)  /* FIXME: should not be necessary */
     {
-        SET_ERROR( ERROR_ACCESS_DENIED );
+        set_error( ERROR_ACCESS_DENIED );
         return -1;
     }
     return dup( pipe->select.fd );
@@ -201,7 +204,6 @@
     if (pipe->other) pipe->other->other = NULL;
     unregister_select_user( &pipe->select );
     close( pipe->select.fd );
-    free( pipe );
 }
 
 /* create an anonymous pipe */
@@ -225,5 +227,5 @@
         release_object( obj[0] );
         release_object( obj[1] );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    add_reply_data( current, &reply, sizeof(reply) );
 }
diff --git a/server/process.c b/server/process.c
index aa14337..b1e4df7 100644
--- a/server/process.c
+++ b/server/process.c
@@ -17,10 +17,10 @@
 #include "winbase.h"
 #include "winnt.h"
 
-#include "server.h"
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
+#include "request.h"
 
 /* process structure */
 
@@ -35,6 +35,7 @@
 
 static const struct object_ops process_ops =
 {
+    sizeof(struct process),
     process_dump,
     add_queue,
     remove_queue,
@@ -49,12 +50,12 @@
 
 
 /* create a new process */
-static struct process *create_process( struct process *parent,
-                                       struct new_process_request *req, const char *cmd_line )
+static struct process *create_process( struct process *parent, struct new_process_request *req,
+                                       const char *cmd_line, size_t len )
 {
     struct process *process;
 
-    if (!(process = alloc_object( sizeof(*process), &process_ops, NULL ))) return NULL;
+    if (!(process = alloc_object( &process_ops ))) return NULL;
     process->next            = NULL;
     process->prev            = NULL;
     process->thread_list     = NULL;
@@ -81,9 +82,10 @@
     /* alloc a handle for the process itself */
     alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
 
-    if (!(process->info = mem_alloc( sizeof(*process->info) + strlen(cmd_line) + 1 ))) goto error;
+    if (!(process->info = mem_alloc( sizeof(*process->info) + len + 1 ))) goto error;
     memcpy( process->info, req, sizeof(*req) );
-    strcpy( process->info->cmd_line, cmd_line );
+    memcpy( process->info->cmd_line, cmd_line, len );
+    process->info->cmd_line[len] = 0;
 
     /* set the process console */
     if (req->create_flags & CREATE_NEW_CONSOLE)
@@ -139,7 +141,7 @@
     req.hstderr      = -1;
     req.cmd_show     = 0;
     req.env_ptr      = NULL;
-    if ((process = create_process( NULL, &req, "" )))
+    if ((process = create_process( NULL, &req, "", 1 )))
     {
         process->info->hstdin  = alloc_handle( process, process->console_in,
                                                GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
@@ -163,8 +165,6 @@
     if (process->prev) process->prev->next = process->next;
     else first_process = process->next;
     if (process->info) free( process->info );
-    if (debug_level) memset( process, 0xbb, sizeof(process) );  /* catch errors */
-    free( process );
 }
 
 /* dump a process on stdout for debugging purposes */
@@ -191,7 +191,7 @@
     struct process *p = first_process;
     while (p && (p != id)) p = p->next;
     if (p) grab_object( p );
-    else SET_ERROR( ERROR_INVALID_PARAMETER );
+    else set_error( ERROR_INVALID_PARAMETER );
     return p;
 }
 
@@ -303,7 +303,7 @@
         process->priority = req->priority;
     if (req->mask & SET_PROCESS_INFO_AFFINITY)
     {
-        if (req->affinity != 1) SET_ERROR( ERROR_INVALID_PARAMETER );
+        if (req->affinity != 1) set_error( ERROR_INVALID_PARAMETER );
         else process->affinity = req->affinity;
     }
 }
@@ -333,33 +333,31 @@
 /* create a new process */
 DECL_HANDLER(new_process)
 {
-    struct new_process_reply reply;
+    struct new_process_reply *reply = push_reply_data( current, sizeof(*reply) );
+    size_t len = get_req_strlen();
     struct process *process;
-    char *cmd_line = (char *)data;
 
-    CHECK_STRING( "new_process", cmd_line, len );
-    if ((process = create_process( current->process, req, cmd_line )))
+    if ((process = create_process( current->process, req, get_req_data( len + 1 ), len )))
     {
-        reply.pid    = process;
-        reply.handle = alloc_handle( current->process, process,
-                                     PROCESS_ALL_ACCESS, req->inherit );
+        reply->handle = alloc_handle( current->process, process,
+                                      PROCESS_ALL_ACCESS, req->inherit );
+        reply->pid    = process;
         release_object( process );
     }
     else
     {
-        reply.handle = -1;
-        reply.pid    = NULL;
+        reply->handle = -1;
+        reply->pid    = NULL;
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
 }
 
 /* initialize a new process */
 DECL_HANDLER(init_process)
 {
-    struct init_process_reply reply;
+    struct init_process_reply *reply = push_reply_data( current, sizeof(*reply) );
     struct new_process_request *info;
 
-    if (current->state != RUNNING)
+    if (current->state == STARTING)
     {
         fatal_protocol_error( "init_process: init_thread not called yet\n" );
         return;
@@ -370,29 +368,27 @@
         return;
     }
     current->process->info = NULL;
-    reply.start_flags = info->start_flags;
-    reply.hstdin      = info->hstdin;
-    reply.hstdout     = info->hstdout;
-    reply.hstderr     = info->hstderr;
-    reply.cmd_show    = info->cmd_show;
-    reply.env_ptr     = info->env_ptr;
-    send_reply( current, -1, 2, &reply, sizeof(reply),
-                info->cmd_line, strlen(info->cmd_line) + 1 );
+    reply->start_flags = info->start_flags;
+    reply->hstdin      = info->hstdin;
+    reply->hstdout     = info->hstdout;
+    reply->hstderr     = info->hstderr;
+    reply->cmd_show    = info->cmd_show;
+    reply->env_ptr     = info->env_ptr;
+    add_reply_data( current, info->cmd_line, strlen(info->cmd_line) + 1 );
     free( info );
 }
 
 /* open a handle to a process */
 DECL_HANDLER(open_process)
 {
-    struct open_process_reply reply = { -1 };
+    struct open_process_reply *reply = push_reply_data( current, sizeof(*reply) );
     struct process *process = get_process_from_id( req->pid );
     if (process)
     {
-        reply.handle = alloc_handle( current->process, process,
-                                     req->access, req->inherit );
+        reply->handle = alloc_handle( current->process, process, req->access, req->inherit );
         release_object( process );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* terminate a process */
@@ -405,21 +401,19 @@
         kill_process( process, req->exit_code );
         release_object( process );
     }
-    if (current) send_reply( current, -1, 0 );
 }
 
 /* fetch information about a process */
 DECL_HANDLER(get_process_info)
 {
     struct process *process;
-    struct get_process_info_reply reply = { 0, 0, 0 };
+    struct get_process_info_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
     {
-        get_process_info( process, &reply );
+        get_process_info( process, reply );
         release_object( process );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
 }
 
 /* set information about a process */
@@ -432,5 +426,4 @@
         set_process_info( process, req );
         release_object( process );
     }
-    send_reply( current, -1, 0 );
 }
diff --git a/server/request.c b/server/request.c
index d8b6eab..a8cab9c 100644
--- a/server/request.c
+++ b/server/request.c
@@ -18,54 +18,63 @@
 #include "winnt.h"
 #include "winbase.h"
 #include "wincon.h"
-#define WANT_REQUEST_HANDLERS
-#include "server.h"
 #include "thread.h"
+#include "server.h"
+#define WANT_REQUEST_HANDLERS
+#include "request.h"
  
 struct thread *current = NULL;  /* thread handling the current request */
 
 /* complain about a protocol error and terminate the client connection */
-void fatal_protocol_error( const char *err, ... )
+void fatal_protocol_error( const char *err )
 {
-    va_list args;
+    unsigned char *p;
 
-    va_start( args, err );
-    fprintf( stderr, "Protocol error:%p: ", current );
-    vfprintf( stderr, err, args );
-    va_end( args );
+    fprintf( stderr, "Protocol error:%p: %s\n    request:", current, err );
+    for (p = (unsigned char *)current->buffer; p < (unsigned char *)current->req_end; p++)
+        fprintf( stderr, " %02x", *p );
+    fprintf( stderr, "\n" );
     remove_client( current->client, -2 );
 }
 
 /* call a request handler */
-void call_req_handler( struct thread *thread, enum request req,
-                       void *data, int len, int fd )
+void call_req_handler( struct thread *thread, int fd )
 {
-    const struct handler *handler = &req_handlers[req];
-    char *ptr;
+    const struct handler *handler;
+    struct header *head;
+    unsigned int req, len;
 
     current = thread;
-    if ((req < 0) || (req >= REQ_NB_REQUESTS))
-    {
-        fatal_protocol_error( "unknown request %d\n", req );
-        return;
-    }
+    assert (current);
 
-    if (len < handler->min_size)
-    {
-        fatal_protocol_error( "req %d bad length %d < %d\n", req, len, handler->min_size );
-        return;
-    }
+    head = (struct header *)current->buffer;
+
+    req = head->type;
+    len = head->len;
+
+    /* set the buffer pointers */
+    current->req_pos = current->reply_pos = (char *)current->buffer + sizeof(struct header);
+    current->req_end = (char *)current->buffer + len;
+    clear_error();
+
+    if ((len < sizeof(struct header)) || (len > MAX_MSG_LENGTH)) goto bad_header;
+    if (req >= REQ_NB_REQUESTS) goto bad_header;
+
+    if (debug_level) trace_request( req, fd );
 
     /* now call the handler */
-    if (current)
-    {
-        CLEAR_ERROR();
-        if (debug_level) trace_request( req, data, len, fd );
-    }
-    len -= handler->min_size;
-    ptr = (char *)data + handler->min_size;
-    handler->handler( data, ptr, len, fd );
+    handler = &req_handlers[req];
+    if (!check_req_data( handler->min_size )) goto bad_request;
+    handler->handler( get_req_data( handler->min_size ), fd );
+    if (current && current->state != SLEEPING) send_reply( current );
     current = NULL;
+    return;
+
+ bad_header:
+    /* dump only the header */
+    current->req_end = (char *)current->buffer + sizeof(struct header);
+ bad_request:
+    fatal_protocol_error( "bad request" );
 }
 
 /* handle a client timeout */
@@ -73,7 +82,7 @@
 {
     current = (struct thread *)thread;
     if (debug_level) trace_timeout();
-    CLEAR_ERROR();
+    clear_error();
     thread_timeout();
     current = NULL;
 }
@@ -92,14 +101,32 @@
     current = (old_current != thread) ? old_current : NULL;
 }
 
+/* set the fd to pass to the thread */
+void set_reply_fd( struct thread *thread, int pass_fd )
+{
+    client_pass_fd( thread->client, pass_fd );
+}
+
+/* send a reply to a thread */
+void send_reply( struct thread *thread )
+{
+    struct header *head = thread->buffer;
+    int len = (char *)thread->reply_pos - (char *)thread->buffer;
+
+    assert( len < MAX_MSG_LENGTH );
+
+    head->len  = len;
+    head->type = thread->error;
+    if (thread->state == SLEEPING) thread->state = RUNNING;
+    client_reply( thread->client );
+}
+
 /* set the debug level */
 DECL_HANDLER(set_debug)
 {
     debug_level = req->level;
     /* Make sure last_req is initialized */
     current->last_req = REQ_SET_DEBUG;
-    CLEAR_ERROR();
-    send_reply( current, -1, 0 );
 }
 
 /* debugger support operations */
@@ -115,6 +142,4 @@
         resume_all_threads();
         break;
     }
-
-    send_reply( current, -1, 0 );
 }
diff --git a/server/request.h b/server/request.h
new file mode 100644
index 0000000..b161a55
--- /dev/null
+++ b/server/request.h
@@ -0,0 +1,216 @@
+/*
+ * Wine server requests
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ */
+
+#ifndef __WINE_SERVER_REQUEST_H
+#define __WINE_SERVER_REQUEST_H
+
+#ifndef __WINE_SERVER__
+#error This file can only be used in the Wine server
+#endif
+
+#include "thread.h"
+
+/* request handler definition */
+
+#define DECL_HANDLER(name) void req_##name( struct name##_request *req, int fd )
+
+/* request functions */
+
+extern void fatal_protocol_error( const char *err );
+extern void call_req_handler( struct thread *thread, int fd );
+extern void call_timeout_handler( void *thread );
+extern void call_kill_handler( struct thread *thread, int exit_code );
+extern void set_reply_fd( struct thread *thread, int pass_fd );
+extern void send_reply( struct thread *thread );
+
+extern void trace_request( enum request req, int fd );
+extern void trace_timeout(void);
+extern void trace_kill( int exit_code );
+extern void trace_reply( struct thread *thread, int pass_fd );
+
+
+/* Warning: the buffer is shared between request and reply,
+ * so make sure you are finished using the request before starting
+ * to add data for the reply.
+ */
+
+/* remove some data from the current request */
+static inline void *get_req_data( size_t len )
+{
+    void *old = current->req_pos;
+    current->req_pos = (char *)old + len;
+    return old;
+}
+
+/* check that there is enough data available in the current request */
+static inline int check_req_data( size_t len )
+{
+    return (char *)current->req_pos + len <= (char *)current->req_end;
+}
+
+/* get the length of a request string, without going past the end of the request */
+static inline size_t get_req_strlen(void)
+{
+    char *p = current->req_pos;
+    while (*p && (p < (char *)current->req_end - 1)) p++;
+    return p - (char *)current->req_pos;
+}
+
+/* make space for some data in the current reply */
+static inline void *push_reply_data( struct thread *thread, size_t len )
+{
+    void *old = thread->reply_pos;
+    thread->reply_pos = (char *)old + len;
+    return old;
+}
+
+/* add some data to the current reply */
+static inline void add_reply_data( struct thread *thread, const void *data, size_t len )
+{
+    memcpy( push_reply_data( thread, len ), data, len );
+}
+
+/* Everything below this line is generated automatically by tools/make_requests */
+/* ### make_requests begin ### */
+
+DECL_HANDLER(new_process);
+DECL_HANDLER(new_thread);
+DECL_HANDLER(set_debug);
+DECL_HANDLER(init_process);
+DECL_HANDLER(init_thread);
+DECL_HANDLER(terminate_process);
+DECL_HANDLER(terminate_thread);
+DECL_HANDLER(get_process_info);
+DECL_HANDLER(set_process_info);
+DECL_HANDLER(get_thread_info);
+DECL_HANDLER(set_thread_info);
+DECL_HANDLER(suspend_thread);
+DECL_HANDLER(resume_thread);
+DECL_HANDLER(debugger);
+DECL_HANDLER(queue_apc);
+DECL_HANDLER(close_handle);
+DECL_HANDLER(get_handle_info);
+DECL_HANDLER(set_handle_info);
+DECL_HANDLER(dup_handle);
+DECL_HANDLER(open_process);
+DECL_HANDLER(select);
+DECL_HANDLER(create_event);
+DECL_HANDLER(event_op);
+DECL_HANDLER(open_event);
+DECL_HANDLER(create_mutex);
+DECL_HANDLER(release_mutex);
+DECL_HANDLER(open_mutex);
+DECL_HANDLER(create_semaphore);
+DECL_HANDLER(release_semaphore);
+DECL_HANDLER(open_semaphore);
+DECL_HANDLER(create_file);
+DECL_HANDLER(get_read_fd);
+DECL_HANDLER(get_write_fd);
+DECL_HANDLER(set_file_pointer);
+DECL_HANDLER(truncate_file);
+DECL_HANDLER(set_file_time);
+DECL_HANDLER(flush_file);
+DECL_HANDLER(get_file_info);
+DECL_HANDLER(lock_file);
+DECL_HANDLER(unlock_file);
+DECL_HANDLER(create_pipe);
+DECL_HANDLER(alloc_console);
+DECL_HANDLER(free_console);
+DECL_HANDLER(open_console);
+DECL_HANDLER(set_console_fd);
+DECL_HANDLER(get_console_mode);
+DECL_HANDLER(set_console_mode);
+DECL_HANDLER(set_console_info);
+DECL_HANDLER(get_console_info);
+DECL_HANDLER(write_console_input);
+DECL_HANDLER(read_console_input);
+DECL_HANDLER(create_change_notification);
+DECL_HANDLER(create_mapping);
+DECL_HANDLER(open_mapping);
+DECL_HANDLER(get_mapping_info);
+DECL_HANDLER(create_device);
+DECL_HANDLER(create_snapshot);
+DECL_HANDLER(next_process);
+DECL_HANDLER(wait_debug_event);
+DECL_HANDLER(send_debug_event);
+DECL_HANDLER(continue_debug_event);
+DECL_HANDLER(debug_process);
+
+#ifdef WANT_REQUEST_HANDLERS
+
+static const struct handler {
+    void       (*handler)( void *req, int fd );
+    unsigned int min_size;
+} req_handlers[REQ_NB_REQUESTS] = {
+    { (void(*)())req_new_process, sizeof(struct new_process_request) },
+    { (void(*)())req_new_thread, sizeof(struct new_thread_request) },
+    { (void(*)())req_set_debug, sizeof(struct set_debug_request) },
+    { (void(*)())req_init_process, sizeof(struct init_process_request) },
+    { (void(*)())req_init_thread, sizeof(struct init_thread_request) },
+    { (void(*)())req_terminate_process, sizeof(struct terminate_process_request) },
+    { (void(*)())req_terminate_thread, sizeof(struct terminate_thread_request) },
+    { (void(*)())req_get_process_info, sizeof(struct get_process_info_request) },
+    { (void(*)())req_set_process_info, sizeof(struct set_process_info_request) },
+    { (void(*)())req_get_thread_info, sizeof(struct get_thread_info_request) },
+    { (void(*)())req_set_thread_info, sizeof(struct set_thread_info_request) },
+    { (void(*)())req_suspend_thread, sizeof(struct suspend_thread_request) },
+    { (void(*)())req_resume_thread, sizeof(struct resume_thread_request) },
+    { (void(*)())req_debugger, sizeof(struct debugger_request) },
+    { (void(*)())req_queue_apc, sizeof(struct queue_apc_request) },
+    { (void(*)())req_close_handle, sizeof(struct close_handle_request) },
+    { (void(*)())req_get_handle_info, sizeof(struct get_handle_info_request) },
+    { (void(*)())req_set_handle_info, sizeof(struct set_handle_info_request) },
+    { (void(*)())req_dup_handle, sizeof(struct dup_handle_request) },
+    { (void(*)())req_open_process, sizeof(struct open_process_request) },
+    { (void(*)())req_select, sizeof(struct select_request) },
+    { (void(*)())req_create_event, sizeof(struct create_event_request) },
+    { (void(*)())req_event_op, sizeof(struct event_op_request) },
+    { (void(*)())req_open_event, sizeof(struct open_event_request) },
+    { (void(*)())req_create_mutex, sizeof(struct create_mutex_request) },
+    { (void(*)())req_release_mutex, sizeof(struct release_mutex_request) },
+    { (void(*)())req_open_mutex, sizeof(struct open_mutex_request) },
+    { (void(*)())req_create_semaphore, sizeof(struct create_semaphore_request) },
+    { (void(*)())req_release_semaphore, sizeof(struct release_semaphore_request) },
+    { (void(*)())req_open_semaphore, sizeof(struct open_semaphore_request) },
+    { (void(*)())req_create_file, sizeof(struct create_file_request) },
+    { (void(*)())req_get_read_fd, sizeof(struct get_read_fd_request) },
+    { (void(*)())req_get_write_fd, sizeof(struct get_write_fd_request) },
+    { (void(*)())req_set_file_pointer, sizeof(struct set_file_pointer_request) },
+    { (void(*)())req_truncate_file, sizeof(struct truncate_file_request) },
+    { (void(*)())req_set_file_time, sizeof(struct set_file_time_request) },
+    { (void(*)())req_flush_file, sizeof(struct flush_file_request) },
+    { (void(*)())req_get_file_info, sizeof(struct get_file_info_request) },
+    { (void(*)())req_lock_file, sizeof(struct lock_file_request) },
+    { (void(*)())req_unlock_file, sizeof(struct unlock_file_request) },
+    { (void(*)())req_create_pipe, sizeof(struct create_pipe_request) },
+    { (void(*)())req_alloc_console, sizeof(struct alloc_console_request) },
+    { (void(*)())req_free_console, sizeof(struct free_console_request) },
+    { (void(*)())req_open_console, sizeof(struct open_console_request) },
+    { (void(*)())req_set_console_fd, sizeof(struct set_console_fd_request) },
+    { (void(*)())req_get_console_mode, sizeof(struct get_console_mode_request) },
+    { (void(*)())req_set_console_mode, sizeof(struct set_console_mode_request) },
+    { (void(*)())req_set_console_info, sizeof(struct set_console_info_request) },
+    { (void(*)())req_get_console_info, sizeof(struct get_console_info_request) },
+    { (void(*)())req_write_console_input, sizeof(struct write_console_input_request) },
+    { (void(*)())req_read_console_input, sizeof(struct read_console_input_request) },
+    { (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) },
+    { (void(*)())req_create_mapping, sizeof(struct create_mapping_request) },
+    { (void(*)())req_open_mapping, sizeof(struct open_mapping_request) },
+    { (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) },
+    { (void(*)())req_create_device, sizeof(struct create_device_request) },
+    { (void(*)())req_create_snapshot, sizeof(struct create_snapshot_request) },
+    { (void(*)())req_next_process, sizeof(struct next_process_request) },
+    { (void(*)())req_wait_debug_event, sizeof(struct wait_debug_event_request) },
+    { (void(*)())req_send_debug_event, sizeof(struct send_debug_event_request) },
+    { (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) },
+    { (void(*)())req_debug_process, sizeof(struct debug_process_request) },
+};
+#endif  /* WANT_REQUEST_HANDLERS */
+
+/* ### make_requests end ### */
+/* Everything above this line is generated automatically by tools/make_requests */
+
+#endif  /* __WINE_SERVER_REQUEST_H */
diff --git a/server/semaphore.c b/server/semaphore.c
index 5d297e4..6b2caec 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -13,6 +13,7 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "request.h"
 
 struct semaphore
 {
@@ -24,10 +25,10 @@
 static void semaphore_dump( struct object *obj, int verbose );
 static int semaphore_signaled( struct object *obj, struct thread *thread );
 static int semaphore_satisfied( struct object *obj, struct thread *thread );
-static void semaphore_destroy( struct object *obj );
 
 static const struct object_ops semaphore_ops =
 {
+    sizeof(struct semaphore),
     semaphore_dump,
     add_queue,
     remove_queue,
@@ -37,45 +38,46 @@
     no_write_fd,
     no_flush,
     no_get_file_info,
-    semaphore_destroy
+    no_destroy
 };
 
 
-static struct object *create_semaphore( const char *name, unsigned int initial, unsigned int max )
+static struct semaphore *create_semaphore( const char *name, size_t len,
+                                           unsigned int initial, unsigned int max )
 {
     struct semaphore *sem;
 
     if (!max || (initial > max))
     {
-        SET_ERROR( ERROR_INVALID_PARAMETER );
+        set_error( ERROR_INVALID_PARAMETER );
         return NULL;
     }
-    if (!(sem = (struct semaphore *)create_named_object( name, &semaphore_ops, sizeof(*sem) )))
-        return NULL;
-    if (GET_ERROR() != ERROR_ALREADY_EXISTS)
+    if ((sem = create_named_object( &semaphore_ops, name, len )))
     {
-        /* initialize it if it didn't already exist */
-        sem->count = initial;
-        sem->max   = max;
+        if (get_error() != ERROR_ALREADY_EXISTS)
+        {
+            /* initialize it if it didn't already exist */
+            sem->count = initial;
+            sem->max   = max;
+        }
     }
-    return &sem->obj;
+    return sem;
 }
 
-static int release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
+static void release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
 {
     struct semaphore *sem;
 
     if (!(sem = (struct semaphore *)get_handle_obj( current->process, handle,
                                                     SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
-        return 0;
+        return;
 
     *prev_count = sem->count;
     if (sem->count + count < sem->count || sem->count + count > sem->max)
     {
-        SET_ERROR( ERROR_TOO_MANY_POSTS );
-        return 0;
+        set_error( ERROR_TOO_MANY_POSTS );
     }
-    if (sem->count)
+    else if (sem->count)
     {
         /* there cannot be any thread waiting if the count is != 0 */
         assert( !sem->obj.head );
@@ -87,7 +89,6 @@
         wake_up( &sem->obj, count );
     }
     release_object( sem );
-    return 1;
 }
 
 static void semaphore_dump( struct object *obj, int verbose )
@@ -114,47 +115,33 @@
     return 0;  /* not abandoned */
 }
 
-static void semaphore_destroy( struct object *obj )
-{
-    struct semaphore *sem = (struct semaphore *)obj;
-    assert( obj->ops == &semaphore_ops );
-    free( sem );
-}
-
 /* create a semaphore */
 DECL_HANDLER(create_semaphore)
 {
-    struct create_semaphore_reply reply = { -1 };
-    struct object *obj;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "create_semaphore", name, len );
+    size_t len = get_req_strlen();
+    struct create_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
+    struct semaphore *sem;
 
-    obj = create_semaphore( name, req->initial, req->max );
-    if (obj)
+    if ((sem = create_semaphore( get_req_data( len + 1 ), len, req->initial, req->max )))
     {
-        reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
-        release_object( obj );
+        reply->handle = alloc_handle( current->process, sem, SEMAPHORE_ALL_ACCESS, req->inherit );
+        release_object( sem );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* open a handle to a semaphore */
 DECL_HANDLER(open_semaphore)
 {
-    struct open_semaphore_reply reply;
-    char *name = (char *)data;
-    if (!len) name = NULL;
-    else CHECK_STRING( "open_semaphore", name, len );
-
-    reply.handle = open_object( name, &semaphore_ops, req->access, req->inherit );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    size_t len = get_req_strlen();
+    struct open_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
+    reply->handle = open_object( get_req_data( len + 1 ), len, &semaphore_ops,
+                                 req->access, req->inherit );
 }
 
 /* release a semaphore */
 DECL_HANDLER(release_semaphore)
 {
-    struct release_semaphore_reply reply;
-    if (release_semaphore( req->handle, req->count, &reply.prev_count )) CLEAR_ERROR();
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    struct release_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
+    release_semaphore( req->handle, req->count, &reply->prev_count );
 }
diff --git a/server/snapshot.c b/server/snapshot.c
index c9e678a..6aebf1b 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -17,6 +17,7 @@
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
+#include "request.h"
 
 
 struct snapshot
@@ -32,6 +33,7 @@
 
 static const struct object_ops snapshot_ops =
 {
+    sizeof(struct snapshot),
     snapshot_dump,
     no_add_queue,
     NULL,  /* should never get called */
@@ -46,18 +48,19 @@
 
 
 /* create a new snapshot */
-static struct object *create_snapshot( int flags )
+static struct snapshot *create_snapshot( int flags )
 {
     struct snapshot *snapshot;
-    if (!(snapshot = mem_alloc( sizeof(*snapshot) ))) return NULL;
-    init_object( &snapshot->obj, &snapshot_ops, NULL );
-    if (flags & TH32CS_SNAPPROCESS)
-        snapshot->process = process_snap( &snapshot->process_count );
-    else
-        snapshot->process_count = 0;
 
-    snapshot->process_pos = 0;
-    return &snapshot->obj;
+    if ((snapshot = alloc_object( &snapshot_ops )))
+    {
+        if (flags & TH32CS_SNAPPROCESS)
+            snapshot->process = process_snap( &snapshot->process_count );
+        else
+            snapshot->process_count = 0;
+        snapshot->process_pos = 0;
+    }
+    return snapshot;
 }
 
 /* get the next process in the snapshot */
@@ -70,14 +73,14 @@
         return 0;
     if (!snapshot->process_count)
     {
-        SET_ERROR( ERROR_INVALID_PARAMETER );  /* FIXME */
+        set_error( ERROR_INVALID_PARAMETER );  /* FIXME */
         release_object( snapshot );
         return 0;
     }
     if (reset) snapshot->process_pos = 0;
     else if (snapshot->process_pos >= snapshot->process_count)
     {
-        SET_ERROR( ERROR_NO_MORE_FILES );
+        set_error( ERROR_NO_MORE_FILES );
         release_object( snapshot );
         return 0;
     }
@@ -108,27 +111,25 @@
             release_object( snapshot->process[i].process );
         free( snapshot->process );
     }
-    free( snapshot );
 }
 
 /* create a snapshot */
 DECL_HANDLER(create_snapshot)
 {
-    struct object *obj;
-    struct create_snapshot_reply reply = { -1 };
+    struct snapshot *snapshot;
+    struct create_snapshot_reply *reply = push_reply_data( current, sizeof(*reply) );
 
-    if ((obj = create_snapshot( req->flags )))
+    if ((snapshot = create_snapshot( req->flags )))
     {
-        reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
-        release_object( obj );
+        reply->handle = alloc_handle( current->process, snapshot, 0, req->inherit );
+        release_object( snapshot );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    else reply->handle = -1;
 }
 
 /* get the next process from a snapshot */
 DECL_HANDLER(next_process)
 {
-    struct next_process_reply reply;
-    snapshot_next_process( req->handle, req->reset, &reply );
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    struct next_process_reply *reply = push_reply_data( current, sizeof(*reply) );
+    snapshot_next_process( req->handle, req->reset, reply );
 }
diff --git a/server/socket.c b/server/socket.c
index 915de42..9b78e07 100644
--- a/server/socket.c
+++ b/server/socket.c
@@ -18,32 +18,19 @@
 #include <unistd.h>
 
 #include "config.h"
-#include "server.h"
 #include "object.h"
+#include "request.h"
 
 /* Some versions of glibc don't define this */
 #ifndef SCM_RIGHTS
 #define SCM_RIGHTS 1
 #endif
 
-/* client state */
-enum state
-{
-    RUNNING,   /* running normally */
-    SENDING,   /* sending us a request */
-    WAITING,   /* waiting for us to reply */
-    READING    /* reading our reply */
-};
-
 /* client structure */
 struct client
 {
-    enum state           state;      /* client state */
     struct select_user   select;     /* select user */
     unsigned int         seq;        /* current sequence number */
-    struct header        head;       /* current msg header */
-    char                *data;       /* current msg data */
-    int                  count;      /* bytes sent/received so far */
     int                  pass_fd;    /* fd to pass to and from the client */
     struct thread       *self;       /* client thread (opaque pointer) */
     struct timeout_user *timeout;    /* current timeout (opaque pointer) */
@@ -62,110 +49,81 @@
     va_list args;
 
     va_start( args, err );
-    fprintf( stderr, "Protocol error:%d: ", client->select.fd );
+    fprintf( stderr, "Protocol error:%p: ", client->self );
     vfprintf( stderr, err, args );
     va_end( args );
+    remove_client( client, PROTOCOL_ERROR );
 }
 
 /* send a message to a client that is ready to receive something */
-static void do_write( struct client *client, int client_fd )
+static void do_write( struct client *client )
 {
-    struct iovec vec[2];
-#ifndef HAVE_MSGHDR_ACCRIGHTS
-    struct cmsg_fd cmsg;
-#endif
-    struct msghdr msghdr;
     int ret;
 
-    /* make sure we have something to send */
-    assert( client->count < client->head.len );
-    /* make sure the client is listening */
-    assert( client->state == READING );
-
-    msghdr.msg_name = NULL;
-    msghdr.msg_namelen = 0;
-    msghdr.msg_iov = vec;
-
-    if (client->count < sizeof(client->head))
+    if (client->pass_fd == -1)
     {
-        vec[0].iov_base = (char *)&client->head + client->count;
-        vec[0].iov_len  = sizeof(client->head) - client->count;
-        vec[1].iov_base = client->data;
-        vec[1].iov_len  = client->head.len - sizeof(client->head);
-        msghdr.msg_iovlen = 2;
+        ret = write( client->select.fd, &client->seq, sizeof(client->seq) );
     }
-    else
+    else  /* we have an fd to send */
     {
-        vec[0].iov_base = client->data + client->count - sizeof(client->head);
-        vec[0].iov_len  = client->head.len - client->count;
-        msghdr.msg_iovlen = 1;
-    }
+        struct iovec vec;
+        struct msghdr msghdr;
 
 #ifdef HAVE_MSGHDR_ACCRIGHTS
-    if (client->pass_fd != -1)  /* we have an fd to send */
-    {
         msghdr.msg_accrights = (void *)&client->pass_fd;
         msghdr.msg_accrightslen = sizeof(client->pass_fd);
-    }
-    else
-    {
-        msghdr.msg_accrights = NULL;
-        msghdr.msg_accrightslen = 0;
-    }
 #else  /* HAVE_MSGHDR_ACCRIGHTS */
-    if (client->pass_fd != -1)  /* we have an fd to send */
-    {
-        cmsg.len = sizeof(cmsg);
+        struct cmsg_fd cmsg;
+
+        cmsg.len   = sizeof(cmsg);
         cmsg.level = SOL_SOCKET;
-        cmsg.type = SCM_RIGHTS;
-        cmsg.fd = client->pass_fd;
-        msghdr.msg_control = &cmsg;
+        cmsg.type  = SCM_RIGHTS;
+        cmsg.fd    = client->pass_fd;
+        msghdr.msg_control    = &cmsg;
         msghdr.msg_controllen = sizeof(cmsg);
-    }
-    else
-    {
-        msghdr.msg_control = NULL;
-        msghdr.msg_controllen = 0;
-    }
-    msghdr.msg_flags = 0;
+        msghdr.msg_flags      = 0;
 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
 
-    ret = sendmsg( client_fd, &msghdr, 0 );
+        msghdr.msg_name    = NULL;
+        msghdr.msg_namelen = 0;
+        msghdr.msg_iov     = &vec;
+        msghdr.msg_iovlen  = 1;
+        vec.iov_base = (char *)&client->seq;
+        vec.iov_len  = sizeof(client->seq);
+
+        ret = sendmsg( client->select.fd, &msghdr, 0 );
+        close( client->pass_fd );
+        client->pass_fd = -1;
+    }
+    if (ret == sizeof(client->seq))
+    {
+        /* everything OK */
+        client->seq++;
+        set_select_events( &client->select, READ_EVENT );
+        return;
+    }
     if (ret == -1)
     {
         if (errno != EPIPE) perror("sendmsg");
         remove_client( client, BROKEN_PIPE );
         return;
     }
-    if (client->pass_fd != -1)  /* We sent the fd, now we can close it */
-    {
-        close( client->pass_fd );
-        client->pass_fd = -1;
-    }
-    if ((client->count += ret) < client->head.len) return;
-
-    /* we have finished with this message */
-    if (client->data) free( client->data );
-    client->data  = NULL;
-    client->count = 0;
-    client->state = RUNNING;
-    client->seq++;
-    set_select_events( &client->select, READ_EVENT );
+    fprintf( stderr, "Partial sequence sent (%d)\n", ret );
+    remove_client( client, BROKEN_PIPE );
 }
 
 
 /* read a message from a client that has something to say */
-static void do_read( struct client *client, int client_fd )
+static void do_read( struct client *client )
 {
     struct iovec vec;
-    int pass_fd = -1;
-    int ret;
+    int ret, seq;
 
 #ifdef HAVE_MSGHDR_ACCRIGHTS
     struct msghdr msghdr;
 
-    msghdr.msg_accrights    = (void *)&pass_fd;
-    msghdr.msg_accrightslen = sizeof(int);
+    msghdr.msg_accrights    = (void *)&client->pass_fd;
+    msghdr.msg_accrightslen = sizeof(client->pass_fd);
 #else  /* HAVE_MSGHDR_ACCRIGHTS */
     struct msghdr msghdr;
     struct cmsg_fd cmsg;
@@ -179,109 +137,57 @@
     msghdr.msg_flags      = 0;
 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
 
+    assert( client->pass_fd == -1 );
+
     msghdr.msg_name    = NULL;
     msghdr.msg_namelen = 0;
     msghdr.msg_iov     = &vec;
     msghdr.msg_iovlen  = 1;
 
-    if (client->count < sizeof(client->head))
+    vec.iov_base = &seq;
+    vec.iov_len  = sizeof(seq);
+
+    ret = recvmsg( client->select.fd, &msghdr, 0 );
+#ifndef HAVE_MSGHDR_ACCRIGHTS
+    client->pass_fd = cmsg.fd;
+#endif
+
+    if (ret == sizeof(seq))
     {
-        vec.iov_base = (char *)&client->head + client->count;
-        vec.iov_len  = sizeof(client->head) - client->count;
-    }
-    else
-    {
-        if (!client->data &&
-            !(client->data = malloc(client->head.len-sizeof(client->head))))
+        int pass_fd = client->pass_fd;
+        if (seq != client->seq++)
         {
-            remove_client( client, OUT_OF_MEMORY );
+            protocol_error( client, "bad sequence %08x instead of %08x\n",
+                            seq, client->seq - 1 );
             return;
         }
-        vec.iov_base = client->data + client->count - sizeof(client->head);
-        vec.iov_len  = client->head.len - client->count;
+        client->pass_fd = -1;
+        call_req_handler( client->self, pass_fd );
+        if (pass_fd != -1) close( pass_fd );
+        return;
     }
-
-    ret = recvmsg( client_fd, &msghdr, 0 );
     if (ret == -1)
     {
         perror("recvmsg");
         remove_client( client, BROKEN_PIPE );
         return;
     }
-#ifndef HAVE_MSGHDR_ACCRIGHTS
-    pass_fd = cmsg.fd;
-#endif
-    if (pass_fd != -1)
-    {
-        /* can only receive one fd per message */
-        if (client->pass_fd != -1) close( client->pass_fd );
-        client->pass_fd = pass_fd;
-    }
-    else if (!ret)  /* closed pipe */
+    if (!ret)  /* closed pipe */
     {
         remove_client( client, BROKEN_PIPE );
         return;
     }
-
-    if (client->state == RUNNING) client->state = SENDING;
-    assert( client->state == SENDING );
-
-    client->count += ret;
-
-    /* received the complete header yet? */
-    if (client->count < sizeof(client->head)) return;
-
-    /* sanity checks */
-    if (client->head.seq != client->seq)
-    {
-        protocol_error( client, "bad sequence %08x instead of %08x\n",
-                        client->head.seq, client->seq );
-        remove_client( client, PROTOCOL_ERROR );
-        return;
-    }
-    if ((client->head.len < sizeof(client->head)) ||
-        (client->head.len > MAX_MSG_LENGTH + sizeof(client->head)))
-    {
-        protocol_error( client, "bad header length %08x\n",
-                        client->head.len );
-        remove_client( client, PROTOCOL_ERROR );
-        return;
-    }
-
-    /* received the whole message? */
-    if (client->count == client->head.len)
-    {
-        /* done reading the data, call the callback function */
-
-        int len = client->head.len - sizeof(client->head);
-        char *data = client->data;
-        int passed_fd = client->pass_fd;
-        enum request type = client->head.type;
-
-        /* clear the info now, as the client may be deleted by the callback */
-        client->head.len  = 0;
-        client->head.type = 0;
-        client->count     = 0;
-        client->data      = NULL;
-        client->pass_fd   = -1;
-        client->state     = WAITING;
-        client->seq++;
-
-        call_req_handler( client->self, type, data, len, passed_fd );
-        if (passed_fd != -1) close( passed_fd );
-        if (data) free( data );
-    }
+    protocol_error( client, "partial sequence received %d/%d\n", ret, sizeof(seq) );
 }
 
 /* handle a client event */
 static void client_event( int event, void *private )
 {
     struct client *client = (struct client *)private;
-    if (event & WRITE_EVENT) do_write( client, client->select.fd );
-    if (event & READ_EVENT) do_read( client, client->select.fd );
+    if (event & WRITE_EVENT) do_write( client );
+    if (event & READ_EVENT) do_read( client );
 }
 
-
 /*******************************************************************/
 /* server-side exported functions                                  */
 
@@ -295,15 +201,10 @@
     flags = fcntl( fd, F_GETFL, 0 );
     fcntl( fd, F_SETFL, flags | O_NONBLOCK );
 
-    client->state                = RUNNING;
     client->select.fd            = fd;
     client->select.func          = client_event;
     client->select.private       = client;
     client->seq                  = 0;
-    client->head.len             = 0;
-    client->head.type            = 0;
-    client->count                = 0;
-    client->data                 = NULL;
     client->self                 = self;
     client->timeout              = NULL;
     client->pass_fd              = -1;
@@ -324,42 +225,20 @@
     close( client->select.fd );
 
     /* Purge messages */
-    if (client->data) free( client->data );
     if (client->pass_fd != -1) close( client->pass_fd );
     free( client );
 }
 
-/* send a reply to a client */
-int send_reply_v( struct client *client, int type, int pass_fd,
-                  struct iovec *vec, int veclen )
+/* set the fd to pass to the client */
+void client_pass_fd( struct client *client, int pass_fd )
 {
-    int i;
-    unsigned int len;
-    char *p;
+    assert( client->pass_fd == -1 );
+    client->pass_fd = pass_fd;
+}
 
-    assert( client );
-    assert( client->state == WAITING );
-    assert( !client->data );
-
-    if (debug_level) trace_reply( client->self, type, pass_fd, vec, veclen );
-
-    for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
-    assert( len < MAX_MSG_LENGTH );
-
-    if (len && !(client->data = malloc( len ))) return -1;
-    client->count     = 0;
-    client->head.len  = len + sizeof(client->head);
-    client->head.type = type;
-    client->head.seq  = client->seq;
-    client->pass_fd   = pass_fd;
-
-    for (i = 0, p = client->data; i < veclen; i++)
-    {
-        memcpy( p, vec[i].iov_base, vec[i].iov_len );
-        p += vec[i].iov_len;
-    }
-
-    client->state = READING;
+/* send a reply to a client */
+void client_reply( struct client *client )
+{
+    if (debug_level) trace_reply( client->self, client->pass_fd );
     set_select_events( &client->select, WRITE_EVENT );
-    return 0;
 }
diff --git a/server/thread.c b/server/thread.c
index 2e4f9e5..aa9febc 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
@@ -20,9 +21,9 @@
 #include "winerror.h"
 
 #include "handle.h"
-#include "server.h"
 #include "process.h"
 #include "thread.h"
+#include "request.h"
 
 
 /* thread queues */
@@ -62,6 +63,7 @@
 
 static const struct object_ops thread_ops =
 {
+    sizeof(struct thread),
     dump_thread,
     add_queue,
     remove_queue,
@@ -76,10 +78,32 @@
 
 static struct thread *first_thread;
 
-/* initialization of a thread structure */
-static void init_thread( struct thread *thread, int fd )
+/* allocate the buffer for the communication with the client */
+static int alloc_client_buffer( struct thread *thread )
 {
-    init_object( &thread->obj, &thread_ops, NULL );
+    int fd;
+
+    if ((fd = create_anonymous_file()) == -1) return -1;
+    if (ftruncate( fd, MAX_MSG_LENGTH ) == -1) goto error;
+    if ((thread->buffer = mmap( 0, MAX_MSG_LENGTH, PROT_READ | PROT_WRITE,
+                                MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
+    thread->req_pos = thread->reply_pos = thread->buffer;
+    return fd;
+
+ error:
+    file_set_error();
+    if (fd != -1) close( fd );
+    return -1;
+}
+
+/* create a new thread */
+static struct thread *create_thread( int fd, struct process *process, int suspend )
+{
+    struct thread *thread;
+    int buf_fd;
+
+    if (!(thread = alloc_object( &thread_ops ))) return NULL;
+
     thread->client      = NULL;
     thread->unix_pid    = 0;  /* not known yet */
     thread->teb         = NULL;
@@ -97,61 +121,46 @@
     thread->prev        = NULL;
     thread->priority    = THREAD_PRIORITY_NORMAL;
     thread->affinity    = 1;
-    thread->suspend     = 0;
-}
+    thread->suspend     = (suspend != 0);
+    thread->buffer      = (void *)-1;
+    thread->last_req    = 0;
 
-/* create the initial thread and start the main server loop */
-void create_initial_thread( int fd )
-{
-    first_thread = mem_alloc( sizeof(*first_thread) );
-    assert( first_thread );
-
-    current = first_thread;
-    init_thread( first_thread, fd );
-    first_thread->process = create_initial_process(); 
-    add_process_thread( first_thread->process, first_thread );
-    first_thread->client = add_client( fd, first_thread );
-    select_loop();
-}
-
-/* create a new thread */
-static struct thread *create_thread( int fd, void *pid, int suspend, int inherit, int *handle )
-{
-    struct thread *thread;
-    struct process *process;
-
-    if (!(thread = mem_alloc( sizeof(*thread) ))) return NULL;
-
-    if (!(process = get_process_from_id( pid )))
+    if (!first_thread)  /* creating the first thread */
     {
-        free( thread );
-        return NULL;
+        current = thread;
+        thread->process = process = create_initial_process(); 
+        assert( process );
     }
-    init_thread( thread, fd );
-    thread->process = process;
-
-    if (suspend) thread->suspend++;
+    else thread->process = (struct process *)grab_object( process );
 
     if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
     first_thread = thread;
     add_process_thread( process, thread );
 
-    if ((*handle = alloc_handle( current->process, thread,
-                                 THREAD_ALL_ACCESS, inherit )) == -1) goto error;
+    if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
     if (!(thread->client = add_client( fd, thread )))
     {
-        SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
+        close( buf_fd );
         goto error;
     }
+    push_reply_data( thread, sizeof(struct header) );
+    set_reply_fd( thread, buf_fd );  /* send the fd to the client */
+    send_reply( thread );
     return thread;
 
  error:
-    close_handle( current->process, *handle );
     remove_process_thread( process, thread );
     release_object( thread );
     return NULL;
 }
 
+/* create the initial thread and start the main server loop */
+void create_initial_thread( int fd )
+{
+    create_thread( fd, NULL, 0 );
+    select_loop();
+}
+
 /* destroy a thread when its refcount is 0 */
 static void destroy_thread( struct object *obj )
 {
@@ -164,8 +173,7 @@
     if (thread->prev) thread->prev->next = thread->next;
     else first_thread = thread->next;
     if (thread->apc) free( thread->apc );
-    if (debug_level) memset( thread, 0xaa, sizeof(thread) );  /* catch errors */
-    free( thread );
+    if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_MSG_LENGTH );
 }
 
 /* dump a thread on stdout for debugging purposes */
@@ -208,7 +216,7 @@
         thread->priority = req->priority;
     if (req->mask & SET_THREAD_INFO_AFFINITY)
     {
-        if (req->affinity != 1) SET_ERROR( ERROR_INVALID_PARAMETER );
+        if (req->affinity != 1) set_error( ERROR_INVALID_PARAMETER );
         else thread->affinity = req->affinity;
     }
 }
@@ -259,25 +267,6 @@
             resume_thread( thread );
 }
 
-/* send a reply to a thread */
-int send_reply( struct thread *thread, int pass_fd, int n,
-                ... /* arg_1, len_1, ..., arg_n, len_n */ )
-{
-    struct iovec vec[16];
-    va_list args;
-    int i;
-
-    assert( n < 16 );
-    va_start( args, n );
-    for (i = 0; i < n; i++)
-    {
-        vec[i].iov_base = va_arg( args, void * );
-        vec[i].iov_len  = va_arg( args, int );
-    }
-    va_end( args );
-    return send_reply_v( thread->client, thread->error, pass_fd, vec, n );
-}
-
 /* add a thread to an object wait queue; return 1 if OK, 0 on error */
 int add_queue( struct object *obj, struct wait_queue_entry *entry )
 {
@@ -327,7 +316,7 @@
 
     if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
     {
-        SET_ERROR( ERROR_INVALID_PARAMETER );
+        set_error( ERROR_INVALID_PARAMETER );
         return 0;
     }
     if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) return 0;
@@ -415,22 +404,18 @@
     return 0;
 }
 
-/* send the select reply to wake up the client */
-static void send_select_reply( struct thread *thread, int signaled )
+/* build a select reply to wake up the client */
+static void build_select_reply( struct thread *thread, int signaled )
 {
-    struct select_reply reply;
-    reply.signaled = signaled;
+    struct select_reply *reply = push_reply_data( thread, sizeof(*reply) );
+    reply->signaled = signaled;
     if ((signaled == STATUS_USER_APC) && thread->apc)
     {
-        struct thread_apc *apc = thread->apc;
-        int len = thread->apc_count * sizeof(*apc);
+        add_reply_data( thread, thread->apc, thread->apc_count * sizeof(*thread->apc) );
+        free( thread->apc );
         thread->apc = NULL;
         thread->apc_count = 0;
-        send_reply( thread, -1, 2, &reply, sizeof(reply),
-                    apc, len );
-        free( apc );
     }
-    else send_reply( thread, -1, 1, &reply, sizeof(reply) );
 }
 
 /* attempt to wake up a thread */
@@ -441,7 +426,7 @@
 
     if (!check_wait( thread, &signaled )) return 0;
     end_wait( thread );
-    send_select_reply( thread, signaled );
+    build_select_reply( thread, signaled );
     return 1;
 }
 
@@ -451,8 +436,7 @@
     assert( !thread->wait );
     if (!wait_on( thread, count, handles, flags, timeout ))
     {
-        /* return an error */
-        send_select_reply( thread, -1 );
+        build_select_reply( thread, -1 );
         return;
     }
     if (wake_thread( thread )) return;
@@ -462,9 +446,11 @@
         if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
                                                      call_timeout_handler, thread )))
         {
-            send_select_reply( thread, -1 );
+            build_select_reply( thread, -1 );
+            return;
         }
     }
+    thread->state = SLEEPING;
 }
 
 /* timeout for the current thread */
@@ -473,7 +459,8 @@
     assert( current->wait );
     current->wait->user = NULL;
     end_wait( current );
-    send_select_reply( current, STATUS_TIMEOUT );
+    build_select_reply( current, STATUS_TIMEOUT );
+    send_reply( current );
 }
 
 /* attempt to wake threads sleeping on the object wait queue */
@@ -483,12 +470,13 @@
 
     while (entry)
     {
-        struct wait_queue_entry *next = entry->next;
-        if (wake_thread( entry->thread ))
+        struct thread *thread = entry->thread;
+        entry = entry->next;
+        if (wake_thread( thread ))
         {
+            send_reply( thread );
             if (max && !--max) break;
         }
-        entry = next;
     }
 }
 
@@ -506,7 +494,10 @@
     thread->apc[thread->apc_count].func  = func;
     thread->apc[thread->apc_count].param = param;
     thread->apc_count++;
-    if (thread->wait) wake_thread( thread );
+    if (thread->wait)
+    {
+        if (wake_thread( thread )) send_reply( thread );
+    }
     return 1;
 }
 
@@ -535,24 +526,34 @@
 DECL_HANDLER(new_thread)
 {
     struct new_thread_reply reply;
+    struct thread *thread;
+    struct process *process;
     int new_fd;
 
-    if ((new_fd = dup(fd)) != -1)
+    if ((process = get_process_from_id( req->pid )))
     {
-        reply.tid = create_thread( new_fd, req->pid, req->suspend,
-                                   req->inherit, &reply.handle );
-        if (!reply.tid) close( new_fd );
+        if ((new_fd = dup(fd)) != -1)
+        {
+            if ((thread = create_thread( new_fd, process, req->suspend )))
+            {
+                reply.tid = thread;
+                reply.handle = alloc_handle( current->process, thread,
+                                             THREAD_ALL_ACCESS, req->inherit );
+                if (reply.handle == -1) release_object( thread );
+                /* else will be released when the thread gets killed */
+            }
+            else close( new_fd );
+        }
+        else set_error( ERROR_TOO_MANY_OPEN_FILES );
+        release_object( process );
     }
-    else
-        SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
-
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    add_reply_data( current, &reply, sizeof(reply) );
 }
 
 /* initialize a new thread */
 DECL_HANDLER(init_thread)
 {
-    struct init_thread_reply reply;
+    struct init_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if (current->state != STARTING)
     {
@@ -564,9 +565,8 @@
     current->teb      = req->teb;
     if (current->suspend + current->process->suspend > 0)
         kill( current->unix_pid, SIGSTOP );
-    reply.pid = current->process;
-    reply.tid = current;
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
+    reply->pid = current->process;
+    reply->tid = current;
 }
 
 /* terminate a thread */
@@ -579,23 +579,21 @@
         kill_thread( thread, req->exit_code );
         release_object( thread );
     }
-    if (current) send_reply( current, -1, 0 );
 }
 
 /* fetch information about a thread */
 DECL_HANDLER(get_thread_info)
 {
     struct thread *thread;
-    struct get_thread_info_reply reply = { 0, 0, 0 };
+    struct get_thread_info_reply *reply = push_reply_data( current, sizeof(*reply) );
 
     if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
     {
-        reply.tid       = thread;
-        reply.exit_code = thread->exit_code;
-        reply.priority  = thread->priority;
+        reply->tid       = thread;
+        reply->exit_code = thread->exit_code;
+        reply->priority  = thread->priority;
         release_object( thread );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
 }
 
 /* set information about a thread */
@@ -608,44 +606,41 @@
         set_thread_info( thread, req );
         release_object( thread );
     }
-    send_reply( current, -1, 0 );
 }
 
 /* suspend a thread */
 DECL_HANDLER(suspend_thread)
 {
     struct thread *thread;
-    struct suspend_thread_reply reply = { -1 };
+    struct suspend_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
     if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
     {
-        reply.count = suspend_thread( thread );
+        reply->count = suspend_thread( thread );
         release_object( thread );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
-    
 }
 
 /* resume a thread */
 DECL_HANDLER(resume_thread)
 {
     struct thread *thread;
-    struct resume_thread_reply reply = { -1 };
+    struct resume_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
     if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
     {
-        reply.count = resume_thread( thread );
+        reply->count = resume_thread( thread );
         release_object( thread );
     }
-    send_reply( current, -1, 1, &reply, sizeof(reply) );
-    
 }
 
 /* select on a handle list */
 DECL_HANDLER(select)
 {
-    if (len != req->count * sizeof(int))
-        fatal_protocol_error( "select: bad length %d for %d handles\n",
-                              len, req->count );
-    sleep_on( current, req->count, (int *)data, req->flags, req->timeout );
+    if (check_req_data( req->count * sizeof(int) ))
+    {
+        sleep_on( current, req->count, get_req_data( req->count * sizeof(int) ),
+                  req->flags, req->timeout );
+    }
+    else fatal_protocol_error( "select: bad length" );
 }
 
 /* queue an APC for a thread */
@@ -657,5 +652,4 @@
         thread_queue_apc( thread, req->func, req->param );
         release_object( thread );
     }
-    send_reply( current, -1, 0 );
 }
diff --git a/server/thread.h b/server/thread.h
index 4498bfc..cb8c248 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -22,7 +22,7 @@
 struct debug_ctx;
 struct debug_event;
 
-enum run_state { STARTING, RUNNING, TERMINATED };
+enum run_state { STARTING, RUNNING, SLEEPING, TERMINATED };
 
 struct thread
 {
@@ -48,6 +48,10 @@
     int                 priority;  /* priority level */
     int                 affinity;  /* affinity mask */
     int                 suspend;   /* suspend count */
+    void               *buffer;    /* buffer for communication with the client */
+    void               *req_pos;   /* current request position in buffer */
+    void               *req_end;   /* ptr to end of current request */
+    void               *reply_pos; /* current reply position in buffer */
     enum request        last_req;  /* last request received (for debugging) */
 };
 
@@ -60,8 +64,6 @@
 extern struct thread *get_thread_from_handle( int handle, unsigned int access );
 extern void suspend_all_threads( void );
 extern void resume_all_threads( void );
-extern int send_reply( struct thread *thread, int pass_fd,
-                       int n, ... /* arg_1, len_1, ..., arg_n, len_n */ );
 extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
 extern void kill_thread( struct thread *thread, int exit_code );
@@ -69,8 +71,8 @@
 extern void thread_timeout(void);
 extern void wake_up( struct object *obj, int max );
 
-#define GET_ERROR()     (current->error)
-#define SET_ERROR(err)  (current->error = (err))
-#define CLEAR_ERROR()   (current->error = 0)
+static inline int get_error(void)       { return current->error; }
+static inline void set_error( int err ) { current->error = err; }
+static inline void clear_error(void)    { set_error(0); }
 
 #endif  /* __WINE_SERVER_THREAD_H */
diff --git a/server/trace.c b/server/trace.c
index e45dbc3..10ca05d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1,10 +1,13 @@
-/* File generated automatically by tools/make_requests; DO NOT EDIT!! */
+/*
+ * Server request tracing
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ */
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/uio.h>
-#include "server.h"
-#include "thread.h"
+#include "request.h"
 
 static int dump_chars( void *ptr, int len )
 {
@@ -40,6 +43,11 @@
     return len * sizeof(void*);
 }
 
+typedef int (*dump_func)( const void *req, int len );
+
+/* Everything below this line is generated automatically by tools/make_requests */
+/* ### make_requests begin ### */
+
 static int dump_new_process_request( struct new_process_request *req, int len )
 {
     fprintf( stderr, " inherit=%d,", req->inherit );
@@ -770,7 +778,6 @@
     fprintf( stderr, " pid=%p", req->pid );
     return (int)sizeof(*req);
 }
-typedef int (*dump_func)( void *req, int len );
 
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
@@ -902,8 +909,7 @@
     (dump_func)0,
 };
 
-static const char * const req_names[REQ_NB_REQUESTS] =
-{
+static const char * const req_names[REQ_NB_REQUESTS] = {
     "new_process",
     "new_thread",
     "set_debug",
@@ -968,15 +974,19 @@
     "debug_process",
 };
 
-void trace_request( enum request req, void *data, int len, int fd )
+/* ### make_requests end ### */
+/* Everything above this line is generated automatically by tools/make_requests */
+
+void trace_request( enum request req, int fd )
 {
-    int size;
+    int size, len;
     current->last_req = req;
     fprintf( stderr, "%08x: %s(", (unsigned int)current, req_names[req] );
-    size = req_dumpers[req]( data, len );
+    len = (char *)current->req_end - (char *)current->req_pos;
+    size = req_dumpers[req]( current->req_pos, len );
     if ((len -= size) > 0)
     {
-        unsigned char *ptr = (unsigned char *)data + size;
+        unsigned char *ptr = (unsigned char *)current->req_pos + size;
         while (len--) fprintf( stderr, ", %02x", *ptr++ );
     }
     if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd );
@@ -994,29 +1004,22 @@
              (unsigned int)current, exit_code );
 }
 
-void trace_reply( struct thread *thread, int type, int pass_fd,
-                  struct iovec *vec, int veclen )
+void trace_reply( struct thread *thread, int pass_fd )
 {
-    static unsigned char buffer[MAX_MSG_LENGTH];
-
-    if (!thread) return;
+    struct header *head = thread->buffer;
+    int len = head->len - sizeof(*head);
     fprintf( stderr, "%08x: %s() = %d",
-             (unsigned int)thread, req_names[thread->last_req], type );
-    if (veclen)
+             (unsigned int)thread, req_names[thread->last_req], head->type );
+    if (len)
     {
-        unsigned char *p = buffer;
-        int len;
-        for (; veclen; veclen--, vec++)
-        {
-            memcpy( p, vec->iov_base, vec->iov_len );
-            p += vec->iov_len;
-        }
+        const unsigned char *data = (unsigned char *)(head + 1);
+        int res = 0;
 	fprintf( stderr, " {" );
-        len = p - buffer;
 	if (reply_dumpers[thread->last_req])
-	    len -= reply_dumpers[thread->last_req]( buffer, len );
-        p -= len;
-        while (len--) fprintf( stderr, ", %02x", *p++ );
+	    res = reply_dumpers[thread->last_req]( data, len );
+        len -= res;
+        data += res;
+        while (len--) fprintf( stderr, ", %02x", *data++ );
 	fprintf( stderr, " }" );
     }
     if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );