Implemented NtQueueApcThread, and changed the server APC interface to
always take 3 parameters.
Implemented a number of other ntdll thread functions, and use them
from the kernel ones.

diff --git a/server/async.c b/server/async.c
index 039833e..338f0d1 100644
--- a/server/async.c
+++ b/server/async.c
@@ -65,7 +65,8 @@
 {
     /* fprintf(stderr,"notifying %p!\n",async->overlapped); */
     async->status = status;
-    thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1, 2, async->overlapped, status);
+    thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1,
+                     async->overlapped, (void *)status, NULL );
 }
 
 void destroy_async_queue( struct async_queue *q )
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 05cdda7..984c575 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -151,8 +151,8 @@
     if(user->thread && user->func && user->overlapped)
     {
         /* queue a system APC, to notify a waiting thread */
-        thread_queue_apc(user->thread,NULL,user->func,
-            APC_ASYNC,1,2,user->overlapped,status);
+        thread_queue_apc(user->thread, NULL, user->func, APC_ASYNC, 1,
+                         user->overlapped, (void *)status, NULL);
     }
     if (user->thread) release_object(user->thread);
     user->thread = NULL;
@@ -426,7 +426,7 @@
         /* this should use notify_waiter,
            but no pipe_user object exists now... */
         thread_queue_apc(current,NULL,req->func,
-                         APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
+                         APC_ASYNC, 1, req->overlapped, STATUS_SUCCESS, NULL);
         release_object(partner);
     }
     else
diff --git a/server/protocol.def b/server/protocol.def
index b27788b..90565f8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -417,7 +417,9 @@
     obj_handle_t handle;       /* thread handle */
     int          user;         /* user or system apc? */
     void*        func;         /* function to call */
-    void*        param;        /* param for function to call */
+    void*        arg1;         /* params for function to call */
+    void*        arg2;
+    void*        arg3;
 @END
 
 
@@ -427,7 +429,9 @@
 @REPLY
     void*        func;         /* function to call */
     int          type;         /* function type */
-    VARARG(args,ptrs);         /* function arguments */
+    void*        arg1;         /* function arguments */
+    void*        arg2;
+    void*        arg3;
 @END
 enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
 
diff --git a/server/thread.c b/server/thread.c
index ad310c9..c6ef4ac 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -67,7 +67,9 @@
     void               *func;     /* function to call in client */
     enum apc_type       type;     /* type of apc function */
     int                 nb_args;  /* number of arguments */
-    void               *args[1];  /* function arguments */
+    void               *arg1;     /* function arguments */
+    void               *arg2;
+    void               *arg3;
 };
 
 
@@ -580,7 +582,7 @@
 
 /* queue an async procedure call */
 int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
-                      enum apc_type type, int system, int nb_args, ... )
+                      enum apc_type type, int system, void *arg1, void *arg2, void *arg3 )
 {
     struct thread_apc *apc;
     struct apc_queue *queue = system ? &thread->system_apc : &thread->user_apc;
@@ -589,21 +591,15 @@
     if (owner) thread_cancel_apc( thread, owner, system );
     if (thread->state == TERMINATED) return 0;
 
-    if (!(apc = mem_alloc( sizeof(*apc) + (nb_args-1)*sizeof(apc->args[0]) ))) return 0;
-    apc->prev    = queue->tail;
-    apc->next    = NULL;
-    apc->owner   = owner;
-    apc->func    = func;
-    apc->type    = type;
-    apc->nb_args = nb_args;
-    if (nb_args)
-    {
-        int i;
-        va_list args;
-        va_start( args, nb_args );
-        for (i = 0; i < nb_args; i++) apc->args[i] = va_arg( args, void * );
-        va_end( args );
-    }
+    if (!(apc = mem_alloc( sizeof(*apc) ))) return 0;
+    apc->prev   = queue->tail;
+    apc->next   = NULL;
+    apc->owner  = owner;
+    apc->func   = func;
+    apc->type   = type;
+    apc->arg1   = arg1;
+    apc->arg2   = arg2;
+    apc->arg3   = arg3;
     queue->tail = apc;
     if (!apc->prev)  /* first one */
     {
@@ -972,7 +968,8 @@
     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, 1, req->param );
+        thread_queue_apc( thread, NULL, req->func, APC_USER, !req->user,
+                          req->arg1, req->arg2, req->arg3 );
         release_object( thread );
     }
 }
@@ -981,7 +978,6 @@
 DECL_HANDLER(get_apc)
 {
     struct thread_apc *apc;
-    size_t size;
 
     for (;;)
     {
@@ -999,11 +995,11 @@
         if (apc->func || apc->type == APC_ASYNC_IO) break;
         free( apc );
     }
-    size = apc->nb_args * sizeof(apc->args[0]);
-    if (size > get_reply_max_size()) size = get_reply_max_size();
     reply->func = apc->func;
     reply->type = apc->type;
-    set_reply_data( apc->args, size );
+    reply->arg1 = apc->arg1;
+    reply->arg2 = apc->arg2;
+    reply->arg3 = apc->arg3;
     free( apc );
 }
 
diff --git a/server/thread.h b/server/thread.h
index f30ef4c..b0fa9c3 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -118,7 +118,7 @@
 extern void kill_thread( struct thread *thread, int violent_death );
 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, int nb_args, ... );
+                             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_add_inflight_fd( struct thread *thread, int client, int server );
 extern int thread_get_inflight_fd( struct thread *thread, int client );
diff --git a/server/timer.c b/server/timer.c
index 85cf080..2db8606 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -94,7 +94,7 @@
     /* queue an APC */
     if (timer->thread)
     {
-        if (!thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0, 3,
+        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))
         {
             release_object( timer->thread );
diff --git a/server/trace.c b/server/trace.c
index 9f46615..93b3de8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -157,21 +157,6 @@
     remove_data( size );
 }
 
-static void dump_varargs_ptrs( size_t size )
-{
-    void * const *data = cur_data;
-    size_t len = size / sizeof(*data);
-
-    fputc( '{', stderr );
-    while (len > 0)
-    {
-        fprintf( stderr, "%p", *data++ );
-        if (--len) fputc( ',', stderr );
-    }
-    fputc( '}', stderr );
-    remove_data( size );
-}
-
 static void dump_varargs_user_handles( size_t size )
 {
     const user_handle_t *data = cur_data;
@@ -623,7 +608,9 @@
     fprintf( stderr, " handle=%p,", req->handle );
     fprintf( stderr, " user=%d,", req->user );
     fprintf( stderr, " func=%p,", req->func );
-    fprintf( stderr, " param=%p", req->param );
+    fprintf( stderr, " arg1=%p,", req->arg1 );
+    fprintf( stderr, " arg2=%p,", req->arg2 );
+    fprintf( stderr, " arg3=%p", req->arg3 );
 }
 
 static void dump_get_apc_request( const struct get_apc_request *req )
@@ -635,8 +622,9 @@
 {
     fprintf( stderr, " func=%p,", req->func );
     fprintf( stderr, " type=%d,", req->type );
-    fprintf( stderr, " args=" );
-    dump_varargs_ptrs( cur_size );
+    fprintf( stderr, " arg1=%p,", req->arg1 );
+    fprintf( stderr, " arg2=%p,", req->arg2 );
+    fprintf( stderr, " arg3=%p", req->arg3 );
 }
 
 static void dump_close_handle_request( const struct close_handle_request *req )