server: Add a generic apc_call structure to make it easier to extend, and more type-safe.
diff --git a/server/fd.c b/server/fd.c
index 157db69..d20360a 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1283,8 +1283,15 @@
 /* destroys the server side of it */
 static void async_terminate( struct async *async, int status )
 {
-    thread_queue_apc( async->thread, NULL, async->apc, APC_ASYNC_IO,
-                      1, async->user, async->sb, (void *)status );
+    apc_call_t data;
+
+    memset( &data, 0, sizeof(data) );
+    data.type            = APC_ASYNC_IO;
+    data.async_io.func   = async->apc;
+    data.async_io.user   = async->user;
+    data.async_io.sb     = async->sb;
+    data.async_io.status = status;
+    thread_queue_apc( async->thread, NULL, &data );
 
     if (async->timeout) remove_timeout_user( async->timeout );
     async->timeout = NULL;
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 8cbd7e5..9077c58 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -857,9 +857,16 @@
     server = find_server( pipe, ps_wait_open );
     if (server)
     {
+        apc_call_t data;
+
         /* there's already a server waiting for a client to connect */
-        thread_queue_apc( current, NULL, req->func, APC_ASYNC_IO,
-                          1, req->event, NULL, (void *)STATUS_SUCCESS );
+        memset( &data, 0, sizeof(data) );
+        data.type            = APC_ASYNC_IO;
+        data.async_io.func   = req->func;
+        data.async_io.user   = req->event;
+        data.async_io.sb     = NULL;
+        data.async_io.status = STATUS_SUCCESS;
+        thread_queue_apc( current, NULL, &data );
         release_object( server );
     }
     else
diff --git a/server/protocol.def b/server/protocol.def
index 7cde312..a71bcee 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -225,6 +225,34 @@
     /* VARARGS(sids,SID); */
 };
 
+enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
+
+typedef union
+{
+    enum apc_type type;
+    struct
+    {
+        enum apc_type    type;     /* APC_USER */
+        void (__stdcall *func)(unsigned long,unsigned long,unsigned long);
+        unsigned long    args[3];  /* arguments for user function */
+    } user;
+    struct
+    {
+        enum apc_type   type;     /* APC_TIMER */
+        void (__stdcall *func)(void*, unsigned int, unsigned int);
+        abs_time_t       time;     /* absolute time of expiration */
+        void            *arg;      /* user argument */
+    } timer;
+    struct
+    {
+        enum apc_type    type;     /* APC_ASYNC_IO */
+        void (__stdcall *func)(void*, void*, unsigned int);
+        void            *user;     /* user pointer */
+        void            *sb;       /* status block */
+        unsigned int     status;   /* I/O status */
+    } async_io;
+} apc_call_t;
+
 /****************************************************************/
 /* Request declarations */
 
@@ -436,11 +464,7 @@
 /* Queue an APC for a thread */
 @REQ(queue_apc)
     obj_handle_t handle;       /* thread handle */
-    int          user;         /* user or system apc? */
-    void*        func;         /* function to call */
-    void*        arg1;         /* params for function to call */
-    void*        arg2;
-    void*        arg3;
+    apc_call_t   call;         /* call arguments */
 @END
 
 
@@ -450,13 +474,8 @@
     obj_handle_t prev;         /* handle to previous APC */
 @REPLY
     obj_handle_t handle;       /* handle to APC */
-    void*        func;         /* function to call */
-    int          type;         /* function type */
-    void*        arg1;         /* function arguments */
-    void*        arg2;
-    void*        arg3;
+    apc_call_t   call;         /* call arguments */
 @END
-enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
 
 
 /* Close a handle for the current process */
diff --git a/server/thread.c b/server/thread.c
index 630447a..476ee32 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -72,11 +72,7 @@
     struct list         entry;    /* queue linked list */
     struct object      *owner;    /* object that queued this apc */
     int                 executed; /* has it been executed by the client? */
-    void               *func;     /* function to call in client */
-    enum apc_type       type;     /* type of apc function */
-    void               *arg1;     /* function arguments */
-    void               *arg2;
-    void               *arg3;
+    apc_call_t          call;
 };
 
 static void dump_thread_apc( struct object *obj, int verbose );
@@ -306,7 +302,7 @@
     struct thread_apc *apc = (struct thread_apc *)obj;
     assert( obj->ops == &thread_apc_ops );
 
-    fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->type );
+    fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->call.type );
 }
 
 static int thread_apc_signaled( struct object *obj, struct thread *thread )
@@ -663,24 +659,33 @@
     }
 }
 
+/* return the apc queue to use for a given apc type */
+static inline struct list *get_apc_queue( struct thread *thread, enum apc_type type )
+{
+    switch(type)
+    {
+    case APC_NONE:
+    case APC_USER:
+    case APC_TIMER:
+        return &thread->user_apc;
+    default:
+        return &thread->system_apc;
+    }
+}
+
 /* queue an async procedure call */
-int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
-                      enum apc_type type, int system, void *arg1, void *arg2, void *arg3 )
+int thread_queue_apc( struct thread *thread, struct object *owner, const apc_call_t *call_data )
 {
     struct thread_apc *apc;
-    struct list *queue = system ? &thread->system_apc : &thread->user_apc;
+    struct list *queue = get_apc_queue( thread, call_data->type );
 
     /* cancel a possible previous APC with the same owner */
-    if (owner) thread_cancel_apc( thread, owner, system );
+    if (owner) thread_cancel_apc( thread, owner, call_data->type );
     if (thread->state == TERMINATED) return 0;
 
     if (!(apc = alloc_object( &thread_apc_ops ))) return 0;
-    apc->owner  = owner;
-    apc->func   = func;
-    apc->type   = type;
-    apc->arg1   = arg1;
-    apc->arg2   = arg2;
-    apc->arg3   = arg3;
+    apc->call     = *call_data;
+    apc->owner    = owner;
     apc->executed = 0;
     list_add_tail( queue, &apc->entry );
     if (!list_prev( queue, &apc->entry ))  /* first one */
@@ -690,10 +695,11 @@
 }
 
 /* cancel the async procedure call owned by a specific object */
-void thread_cancel_apc( struct thread *thread, struct object *owner, int system )
+void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type )
 {
     struct thread_apc *apc;
-    struct list *queue = system ? &thread->system_apc : &thread->user_apc;
+    struct list *queue = get_apc_queue( thread, type );
+
     LIST_FOR_EACH_ENTRY( apc, queue, struct thread_apc, entry )
     {
         if (apc->owner != owner) continue;
@@ -1053,8 +1059,16 @@
     struct thread *thread;
     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
     {
-        thread_queue_apc( thread, NULL, req->func, APC_USER, !req->user,
-                          req->arg1, req->arg2, req->arg3 );
+        switch( req->call.type )
+        {
+        case APC_NONE:
+        case APC_USER:
+            thread_queue_apc( thread, NULL, &req->call );
+            break;
+        default:
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
+        }
         release_object( thread );
     }
 }
@@ -1082,22 +1096,15 @@
             set_error( STATUS_PENDING );
             return;
         }
-        /* Optimization: ignore APCs that have a NULL func; they are only used
-         * to wake up a thread, but since we got here the thread woke up already.
-         * Exception: for APC_ASYNC_IO, func == NULL is legal.
+        /* Optimization: ignore APC_NONE calls, they are only used to
+         * wake up a thread, but since we got here the thread woke up already.
          */
-        if (apc->func || apc->type == APC_ASYNC_IO) break;
+        if (apc->call.type != APC_NONE) break;
         release_object( apc );
     }
 
     if ((reply->handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
-    {
-        reply->func = apc->func;
-        reply->type = apc->type;
-        reply->arg1 = apc->arg1;
-        reply->arg2 = apc->arg2;
-        reply->arg3 = apc->arg3;
-    }
+        reply->call = apc->call;
     release_object( apc );
 }
 
diff --git a/server/thread.h b/server/thread.h
index 0fc162f..e09c11b 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -112,9 +112,8 @@
 extern void kill_thread( struct thread *thread, int violent_death );
 extern void break_thread( struct thread *thread );
 extern void wake_up( struct object *obj, int max );
-extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
-                             enum apc_type type, int system, void *arg1, void *arg2, void *arg3 );
-extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system );
+extern int thread_queue_apc( struct thread *thread, struct object *owner, const apc_call_t *call_data );
+extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type );
 extern int thread_add_inflight_fd( struct thread *thread, int client, int server );
 extern int thread_get_inflight_fd( struct thread *thread, int client );
 extern struct thread_snapshot *thread_snap( int *count );
diff --git a/server/timer.c b/server/timer.c
index 2640dd8..9ffa649 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -104,8 +104,20 @@
     /* queue an APC */
     if (timer->thread)
     {
-        if (!thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0,
-                               (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg))
+        apc_call_t data;
+
+        memset( &data, 0, sizeof(data) );
+        if (timer->callback)
+        {
+            data.type            = APC_TIMER;
+            data.timer.func      = timer->callback;
+            data.timer.time.sec  = timer->when.tv_sec;
+            data.timer.time.usec = timer->when.tv_usec;
+            data.timer.arg       = timer->arg;
+        }
+        else data.type = APC_NONE;  /* wake up only */
+
+        if (!thread_queue_apc( timer->thread, &timer->obj, &data ))
         {
             release_object( timer->thread );
             timer->thread = NULL;
@@ -136,7 +148,7 @@
     }
     if (timer->thread)
     {
-        thread_cancel_apc( timer->thread, &timer->obj, 0 );
+        thread_cancel_apc( timer->thread, &timer->obj, APC_TIMER );
         release_object( timer->thread );
         timer->thread = NULL;
     }
diff --git a/server/trace.c b/server/trace.c
index 5018423..fcd24e6 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -43,6 +43,8 @@
 static const void *cur_data;
 static data_size_t cur_size;
 
+static const char *get_status_name( unsigned int status );
+
 /* utility functions */
 
 inline static void remove_data( data_size_t size )
@@ -96,6 +98,34 @@
     fprintf( stderr, "',%04x}", info->attr );
 }
 
+static void dump_apc_call( const apc_call_t *call )
+{
+    fputc( '{', stderr );
+    switch(call->type)
+    {
+    case APC_NONE:
+        fprintf( stderr, "APC_NONE" );
+        break;
+    case APC_USER:
+        fprintf( stderr, "APC_USER,args={%lx,%lx,%lx}",
+                 call->user.args[0], call->user.args[1], call->user.args[2] );
+        break;
+    case APC_TIMER:
+        fprintf( stderr, "APC_TIMER,time=" );
+        dump_abs_time( &call->timer.time );
+        fprintf( stderr, ",arg=%p", call->timer.arg );
+        break;
+    case APC_ASYNC_IO:
+        fprintf( stderr, "APC_ASYNC_IO,user=%p,sb=%p,status=%s",
+                 call->async_io.user, call->async_io.sb, get_status_name(call->async_io.status) );
+        break;
+    default:
+        fprintf( stderr, "type=%u", call->type );
+        break;
+    }
+    fputc( '}', stderr );
+}
+
 static void dump_context( const CONTEXT *context )
 {
 #ifdef __i386__
@@ -845,11 +875,8 @@
 static void dump_queue_apc_request( const struct queue_apc_request *req )
 {
     fprintf( stderr, " handle=%p,", req->handle );
-    fprintf( stderr, " user=%d,", req->user );
-    fprintf( stderr, " func=%p,", req->func );
-    fprintf( stderr, " arg1=%p,", req->arg1 );
-    fprintf( stderr, " arg2=%p,", req->arg2 );
-    fprintf( stderr, " arg3=%p", req->arg3 );
+    fprintf( stderr, " call=" );
+    dump_apc_call( &req->call );
 }
 
 static void dump_get_apc_request( const struct get_apc_request *req )
@@ -861,11 +888,8 @@
 static void dump_get_apc_reply( const struct get_apc_reply *req )
 {
     fprintf( stderr, " handle=%p,", req->handle );
-    fprintf( stderr, " func=%p,", req->func );
-    fprintf( stderr, " type=%d,", req->type );
-    fprintf( stderr, " arg1=%p,", req->arg1 );
-    fprintf( stderr, " arg2=%p,", req->arg2 );
-    fprintf( stderr, " arg3=%p", req->arg3 );
+    fprintf( stderr, " call=" );
+    dump_apc_call( &req->call );
 }
 
 static void dump_close_handle_request( const struct close_handle_request *req )