diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index b81c50dec9683910817819a51752ec796989255b..53da53cf95fa11f3572e4c2ac7deaf1feee753d0 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -80,6 +80,7 @@
 #include "winerror.h"
 
 #include "wine/server.h"
+#include "async.h"
 #include "file.h"
 #include "heap.h"
 
@@ -91,6 +92,52 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(comm);
 
+/***********************************************************************
+ * Asynchronous I/O for asynchronous wait requests                     *
+ */
+
+static DWORD commio_get_async_status (const async_private *ovp);
+static DWORD commio_get_async_count (const async_private *ovp);
+static void commio_set_async_status (async_private *ovp, const DWORD status);
+static void CALLBACK commio_call_completion_func (ULONG_PTR data);
+
+static async_ops commio_async_ops =
+{
+    commio_get_async_status,       /* get_status */
+    commio_set_async_status,       /* set_status */
+    commio_get_async_count,        /* get_count */
+    commio_call_completion_func    /* call_completion */
+};
+
+typedef struct async_commio
+{
+    struct async_private             async;
+    LPOVERLAPPED                     lpOverlapped;
+    char                             *buffer;
+} async_commio;
+
+static DWORD commio_get_async_status (const struct async_private *ovp)
+{
+    return ((async_commio*) ovp)->lpOverlapped->Internal;
+}
+
+static void commio_set_async_status (async_private *ovp, const DWORD status)
+{
+    ((async_commio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD commio_get_async_count (const struct async_private *ovp)
+{
+    return 0;
+}
+
+static void CALLBACK commio_call_completion_func (ULONG_PTR data)
+{
+    HeapFree(GetProcessHeap(), 0, (void*) data);
+}
+
+/***********************************************************************/
+
 #if !defined(TIOCINQ) && defined(FIONREAD)
 #define	TIOCINQ FIONREAD
 #endif
@@ -1558,12 +1605,13 @@ BOOL WINAPI GetCommModemStatus(
  */
 static void COMM_WaitCommEventService(async_private *ovp)
 {
-    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    async_commio *commio = (async_commio*) ovp;
+    LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
 
     TRACE("overlapped %p\n",lpOverlapped);
 
     /* FIXME: detect other events */
-            *ovp->buffer = EV_RXCHAR;
+    *commio->buffer = EV_RXCHAR;
  
     lpOverlapped->Internal = STATUS_SUCCESS;
 }
@@ -1579,8 +1627,8 @@ static BOOL COMM_WaitCommEvent(
     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
 {
-    int fd,ret;
-    async_private *ovp;
+    int fd;
+    async_commio *ovp;
 
     if(!lpOverlapped)
     {
@@ -1591,53 +1639,32 @@ static BOOL COMM_WaitCommEvent(
     if(NtResetEvent(lpOverlapped->hEvent,NULL))
         return FALSE;
 
-    lpOverlapped->Internal = STATUS_PENDING;
-    lpOverlapped->InternalHigh = 0;
-    lpOverlapped->Offset = 0;
-    lpOverlapped->OffsetHigh = 0;
-
     fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
     if(fd<0)
 	return FALSE;
 
-    ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
     if(!ovp)
     {
         close(fd);
         return FALSE;
     }
-    ovp->event = lpOverlapped->hEvent;
+
+    ovp->async.ops = &commio_async_ops;
+    ovp->async.handle = hFile;
+    ovp->async.fd = fd;
+    ovp->async.type = ASYNC_TYPE_WAIT;
+    ovp->async.func = COMM_WaitCommEventService;
+    ovp->async.event = lpOverlapped->hEvent;
     ovp->lpOverlapped = lpOverlapped;
-    ovp->func = COMM_WaitCommEventService;
     ovp->buffer = (char *)lpdwEvents;
-    ovp->fd = fd;
-    ovp->count = 0;
-    ovp->completion_func = 0;                                                  
-    ovp->type = ASYNC_TYPE_WAIT;
-    ovp->handle = hFile;
-  
-    ovp->next = NtCurrentTeb()->pending_list;
-    ovp->prev = NULL;
-    if(ovp->next)
-        ovp->next->prev=ovp;
-    NtCurrentTeb()->pending_list = ovp;
-  
-    /* start an ASYNCHRONOUS WaitCommEvent */
-    SERVER_START_REQ( register_async )
-    {
-        req->handle = hFile;
-        req->overlapped = lpOverlapped;
-        req->type = ASYNC_TYPE_WAIT;
-        req->count = 0;
-        req->func = check_async_list;
-        req->status = STATUS_PENDING;
-
-        ret=wine_server_call_err(req);
-    }
-    SERVER_END_REQ;
 
-    if (!ret)
-    SetLastError(ERROR_IO_PENDING);
+    lpOverlapped->InternalHigh = 0;
+    lpOverlapped->Offset = 0;
+    lpOverlapped->OffsetHigh = 0;
+
+    if ( !register_new_async (&ovp->async) )
+        SetLastError( ERROR_IO_PENDING );
 
     return FALSE;
 }
diff --git a/files/file.c b/files/file.c
index 7d23c6c6c6fa072ac8dccd22adf34a22e4a9f2b0..dbae5f2a57b4c8814ebd719bb4450d50ddd663be 100644
--- a/files/file.c
+++ b/files/file.c
@@ -51,8 +51,11 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/winbase16.h"
+#include "wine/server.h"
+
 #include "drive.h"
 #include "file.h"
+#include "async.h"
 #include "heap.h"
 #include "msdos.h"
 #include "wincon.h"
@@ -60,8 +63,6 @@
 #include "smb.h"
 #include "wine/debug.h"
 
-#include "wine/server.h"
-
 WINE_DEFAULT_DEBUG_CHANNEL(file);
 
 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
@@ -80,6 +81,61 @@ mode_t FILE_umask;
 
 extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name);
 
+/***********************************************************************
+ *                  Asynchronous file I/O                              *
+ */
+static DWORD fileio_get_async_status (const async_private *ovp);
+static DWORD fileio_get_async_count (const async_private *ovp);
+static void fileio_set_async_status (async_private *ovp, const DWORD status);
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
+
+static async_ops fileio_async_ops =
+{
+    fileio_get_async_status,       /* get_status */
+    fileio_set_async_status,       /* set_status */
+    fileio_get_async_count,        /* get_count */
+    fileio_call_completion_func    /* call_completion */
+};
+
+typedef struct async_fileio
+{
+    struct async_private             async;
+    LPOVERLAPPED                     lpOverlapped;
+    LPOVERLAPPED_COMPLETION_ROUTINE  completion_func;
+    char                             *buffer;
+    int                              count;
+} async_fileio;
+
+static DWORD fileio_get_async_status (const struct async_private *ovp)
+{
+    return ((async_fileio*) ovp)->lpOverlapped->Internal;
+}
+
+static void fileio_set_async_status (async_private *ovp, const DWORD status)
+{
+    ((async_fileio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD fileio_get_async_count (const struct async_private *ovp)
+{
+    async_fileio *fileio = (async_fileio*) ovp;
+    DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
+    return (ret < 0 ? 0 : ret);
+}
+
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
+{
+    async_fileio *ovp = (async_fileio*) data;
+    TRACE ("data: %p\n", ovp);
+
+    if (ovp->completion_func)
+        ovp->completion_func(ovp->lpOverlapped->Internal,
+                             ovp->lpOverlapped->InternalHigh,
+                             ovp->lpOverlapped);
+
+    HeapFree(GetProcessHeap(), 0, ovp);
+}
+
 /***********************************************************************
  *              FILE_ConvertOFMode
  *
@@ -1344,30 +1400,6 @@ BOOL WINAPI GetOverlappedResult(
     return (r==WAIT_OBJECT_0);
 }
 
-
-/***********************************************************************
- *              FILE_StartAsync                (INTERNAL)
- *
- * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
- * lpOverlapped==NULL means all overlappeds match
- */
-BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
-{
-    BOOL ret;
-    SERVER_START_REQ(register_async)
-    {
-        req->handle = hFile;
-        req->overlapped = lpOverlapped;
-        req->type = type;
-        req->count = count;
-        req->func = check_async_list;
-        req->status = status;
-        ret = wine_server_call( req );
-    }
-    SERVER_END_REQ;
-    return !ret;
-}
-
 /***********************************************************************
  *             CancelIo                   (KERNEL32.@)
  */
@@ -1377,16 +1409,11 @@ BOOL WINAPI CancelIo(HANDLE handle)
 
     TRACE("handle = %x\n",handle);
 
-    ovp = NtCurrentTeb()->pending_list;
-    while(ovp)
+    for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
     {
         t = ovp->next;
-        if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
-        {
-            TRACE("overlapped = %p\n",ovp->lpOverlapped);
-            finish_async(ovp, STATUS_CANCELLED);
-        }
-        ovp = t;
+        if ( ovp->handle == handle )
+             cancel_async ( ovp );
     }
     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
     return TRUE;
@@ -1400,18 +1427,19 @@ BOOL WINAPI CancelIo(HANDLE handle)
  */
 static void FILE_AsyncReadService(async_private *ovp)
 {
-    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    async_fileio *fileio = (async_fileio*) ovp;
+    LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
     int result, r;
     int already = lpOverlapped->InternalHigh;
 
-    TRACE("%p %p\n", lpOverlapped, ovp->buffer );
+    TRACE("%p %p\n", lpOverlapped, fileio->buffer );
 
     /* check to see if the data is ready (non-blocking) */
 
-    result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
+    result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
                     OVERLAPPED_OFFSET (lpOverlapped) + already);
     if ((result < 0) && (errno == ESPIPE))
-        result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
+        result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
@@ -1429,9 +1457,9 @@ static void FILE_AsyncReadService(async_private *ovp)
     }
 
     lpOverlapped->InternalHigh += result;
-    TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+    TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
 
-    if(lpOverlapped->InternalHigh < ovp->count)
+    if(lpOverlapped->InternalHigh < fileio->count)
         r = STATUS_PENDING;
     else
         r = STATUS_SUCCESS;
@@ -1448,7 +1476,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
                          HANDLE hEvent)
 {
-    async_private *ovp;
+    async_fileio *ovp;
     int fd;
 
     TRACE("file %d to buf %p num %ld %p func %p\n",
@@ -1468,7 +1496,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
         return FALSE;
     }
 
-    ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
     if(!ovp)
     {
         TRACE("HeapAlloc Failed\n");
@@ -1476,31 +1504,19 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
         close(fd);
         return FALSE;
     }
-    ovp->event = hEvent;
+
+    ovp->async.ops = &fileio_async_ops;
+    ovp->async.handle = hFile;
+    ovp->async.fd = fd;
+    ovp->async.type = ASYNC_TYPE_READ;
+    ovp->async.func = FILE_AsyncReadService;
+    ovp->async.event = hEvent;
     ovp->lpOverlapped = overlapped;
     ovp->count = bytesToRead;
     ovp->completion_func = lpCompletionRoutine;
-    ovp->func = FILE_AsyncReadService;
     ovp->buffer = buffer;
-    ovp->fd = fd;
-    ovp->type = ASYNC_TYPE_READ;
-    ovp->handle = hFile;
 
-    /* hook this overlap into the pending async operation list */
-    ovp->next = NtCurrentTeb()->pending_list;
-    ovp->prev = NULL;
-    if(ovp->next)
-        ovp->next->prev = ovp;
-    NtCurrentTeb()->pending_list = ovp;
-
-    if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
-    {
-        /* FIXME: remove async_private and release memory */
-        ERR("FILE_StartAsync failed\n");
-        return FALSE;
-    }
-
-    return TRUE;
+    return !register_new_async (&ovp->async);
 }
 
 /***********************************************************************
@@ -1510,7 +1526,6 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
 			 LPOVERLAPPED overlapped, 
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    overlapped->Internal     = STATUS_PENDING;
     overlapped->InternalHigh = 0;
     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
 }
@@ -1588,7 +1603,6 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
         }
 
         /* at last resort, do an overlapped read */
-        overlapped->Internal     = STATUS_PENDING;
         overlapped->InternalHigh = result;
         
         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
@@ -1646,18 +1660,19 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
  */
 static void FILE_AsyncWriteService(struct async_private *ovp)
 {
-    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    async_fileio *fileio = (async_fileio *) ovp;
+    LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
     int result, r;
     int already = lpOverlapped->InternalHigh;
 
-    TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
+    TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
 
     /* write some data (non-blocking) */
 
-    result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
+    result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
                     OVERLAPPED_OFFSET (lpOverlapped) + already);
     if ((result < 0) && (errno == ESPIPE))
-        result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
+        result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
@@ -1674,9 +1689,9 @@ static void FILE_AsyncWriteService(struct async_private *ovp)
 
     lpOverlapped->InternalHigh += result;
 
-    TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+    TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
 
-    if(lpOverlapped->InternalHigh < ovp->count)
+    if(lpOverlapped->InternalHigh < fileio->count)
         r = STATUS_PENDING;
     else
         r = STATUS_SUCCESS;
@@ -1693,7 +1708,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
                              LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
                              HANDLE hEvent)
 {
-    async_private *ovp;
+    async_fileio *ovp;
+    int fd;
 
     TRACE("file %d to buf %p num %ld %p func %p stub\n",
 	  hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1704,46 +1720,34 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
         return FALSE;
     }
 
-    overlapped->Internal     = STATUS_PENDING;
-    overlapped->InternalHigh = 0;
-
-    if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
+    fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+    if ( fd < 0 )
     {
-        TRACE("FILE_StartAsync failed\n");
+        TRACE( "Couldn't get FD\n" );
         return FALSE;
     }
 
-    ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
     if(!ovp)
     {
         TRACE("HeapAlloc Failed\n");
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        close (fd);
         return FALSE;
     }
+
+    ovp->async.ops = &fileio_async_ops;
+    ovp->async.handle = hFile;
+    ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+    ovp->async.type = ASYNC_TYPE_WRITE;
+    ovp->async.func = FILE_AsyncWriteService;
     ovp->lpOverlapped = overlapped;
-    ovp->event = hEvent;
-    ovp->func = FILE_AsyncWriteService;
+    ovp->async.event = hEvent;
     ovp->buffer = (LPVOID) buffer;
     ovp->count = bytesToWrite;
     ovp->completion_func = lpCompletionRoutine;
-    ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
-    ovp->type = ASYNC_TYPE_WRITE;
-    ovp->handle = hFile;
 
-    if(ovp->fd <0)
-    {
-        HeapFree(GetProcessHeap(), 0, ovp);
-        return FALSE;
-    }
-
-    /* hook this overlap into the pending async operation list */
-    ovp->next = NtCurrentTeb()->pending_list;
-    ovp->prev = NULL;
-    if(ovp->next)
-        ovp->next->prev = ovp;
-    NtCurrentTeb()->pending_list = ovp;
-
-    return TRUE;
+    return !register_new_async (&ovp->async);
 }
 
 /***********************************************************************
@@ -1753,7 +1757,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
 			 LPOVERLAPPED overlapped, 
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    overlapped->Internal     = STATUS_PENDING;
     overlapped->InternalHigh = 0;
  
     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
diff --git a/include/async.h b/include/async.h
new file mode 100644
index 0000000000000000000000000000000000000000..26774d38dfb3c10bbacab510cb66c007d3958dce
--- /dev/null
+++ b/include/async.h
@@ -0,0 +1,126 @@
+/*
+ * Structures and static functions for handling asynchronous I/O.
+ *
+ * Copyright (C) 2002 Mike McCormack,  Martin Wilck
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * This file declares static functions.
+ * It should only be included by those source files that implement async I/O requests.
+ */
+
+#ifndef __WINE_ASYNC_H
+#define __WINE_ASYNC_H
+
+#include "wine/server.h"
+
+struct async_private;
+
+typedef void (*async_handler)(struct async_private *ovp);
+typedef void CALLBACK (*async_call_completion_func)(ULONG_PTR data);
+typedef DWORD (*async_get_status)(const struct async_private *ovp);
+typedef DWORD (*async_get_count)(const struct async_private *ovp);
+typedef void (*async_set_status)(struct async_private *ovp, const DWORD status);
+
+typedef struct async_ops
+{
+    async_get_status            get_status;
+    async_set_status            set_status;
+    async_get_count             get_count;
+    async_call_completion_func  call_completion;
+} async_ops;
+
+typedef struct async_private
+{
+    struct async_ops     *ops;
+    HANDLE        handle;
+    HANDLE        event;
+    int           fd;
+    async_handler func;
+    int           type;
+    struct async_private *next;
+    struct async_private *prev;
+} async_private;
+
+/* All functions declared static for Dll separation purposes */
+
+inline static void finish_async( async_private *ovp )
+{
+    if(ovp->prev)
+        ovp->prev->next = ovp->next;
+    else
+        NtCurrentTeb()->pending_list = ovp->next;
+
+    if(ovp->next)
+        ovp->next->prev = ovp->prev;
+
+    ovp->next = ovp->prev = NULL;
+
+    close( ovp->fd );
+    if( ovp->event != INVALID_HANDLE_VALUE )
+        NtSetEvent( ovp->event, NULL );
+
+    QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
+}
+
+inline static BOOL __register_async( async_private *ovp, const DWORD status )
+{
+    BOOL ret;
+
+    SERVER_START_REQ( register_async )
+    {
+        req->handle = ovp->handle;
+        req->overlapped = ovp;
+        req->type = ovp->type;
+        req->count = ovp->ops->get_count( ovp );
+        req->status = status;
+        ret = wine_server_call( req );
+    }
+    SERVER_END_REQ;
+
+    if ( ret ) ovp->ops->set_status ( ovp, GetLastError() );
+    if ( ovp->ops->get_status (ovp) != STATUS_PENDING )
+        finish_async (ovp);
+
+    return ret;
+}
+
+#define register_old_async(ovp) \
+    __register_async (ovp, ovp->ops->get_status( ovp ));
+
+inline static BOOL register_new_async( async_private *ovp )
+{
+    ovp->ops->set_status ( ovp, STATUS_PENDING );
+
+    ovp->next = NtCurrentTeb()->pending_list;
+    ovp->prev = NULL;
+    if ( ovp->next ) ovp->next->prev = ovp;
+    NtCurrentTeb()->pending_list = ovp;
+
+    return __register_async( ovp, STATUS_PENDING );
+}
+
+inline static BOOL cancel_async ( async_private *ovp )
+{
+     /* avoid multiple cancellations */
+     if ( ovp->ops->get_status( ovp ) != STATUS_PENDING )
+          return 0;
+     ovp->ops->set_status ( ovp, STATUS_CANCELLED );
+     return __register_async ( ovp, STATUS_CANCELLED );
+}
+
+#endif /* __WINE_ASYNC_H */
diff --git a/include/file.h b/include/file.h
index e061f4c2766101ee4b08011c8386edbe56f0153c..a986d4ecad789c15d617138f80c17a1e7e71bc1f 100644
--- a/include/file.h
+++ b/include/file.h
@@ -46,27 +46,6 @@ typedef struct
     int flags;
 } DOS_DEVICE;
 
-/* overlapped private structure */
-struct async_private;
-typedef void (*async_handler)(struct async_private *ovp);
-typedef struct async_private
-{
-     LPOVERLAPPED  lpOverlapped;
-     HANDLE        handle;
-     HANDLE        event;
-     int           fd;
-     char         *buffer;
-     async_handler func;
-     int           count;
-     int           type;
-     LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
-     struct async_private *next;
-     struct async_private *prev;
-} async_private;
-
-extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status);
-extern void finish_async(struct async_private *ovp, DWORD status);
-
 /* locale-independent case conversion */
 inline static char FILE_tolower( char c )
 {
@@ -99,7 +78,6 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
                                DWORD attributes, HANDLE template, BOOL fail_read_only,
                                UINT drive_type );
 extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa );
-extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status);
 
 extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 3d4e5a15c5cd899b2a19b2008a7c69a18901c5ed..5f778d3e2b66c182d8ec04c3c1eb4303a9dace1f 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -502,7 +502,7 @@ struct get_apc_reply
     int          type;
     /* VARARG(args,ptrs); */
 };
-enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
+enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
 
 
 
@@ -2278,7 +2278,6 @@ struct register_async_request
 {
     struct request_header __header;
     handle_t     handle;
-    void*        func;
     int          type;
     void*        overlapped;
     int          count;
@@ -3184,6 +3183,6 @@ union generic_reply
     struct get_window_properties_reply get_window_properties_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 77
+#define SERVER_PROTOCOL_VERSION 78
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index 4343c34e82cc06e8e4b2fa6c77885a0cbc0c7953..41788dc6315e59ddc8f2d99a70c4503c9368f093 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -30,6 +30,7 @@
 #include "thread.h"
 #include "winerror.h"
 #include "wine/server.h"
+#include "async.h"
 
 
 /***********************************************************************
@@ -50,74 +51,32 @@ inline static void get_timeout( struct timeval *when, int timeout )
     }
 }
 
-static void CALLBACK call_completion_routine(ULONG_PTR data)
-{
-    async_private* ovp = (async_private*)data;
-
-    ovp->completion_func(ovp->lpOverlapped->Internal,
-                         ovp->lpOverlapped->InternalHigh,
-                         ovp->lpOverlapped);
-    ovp->completion_func=NULL;
-    HeapFree(GetProcessHeap(), 0, ovp);
-}
-
-void finish_async(async_private *ovp, DWORD status)
-{
-    ovp->lpOverlapped->Internal=status;
-
-    /* call ReadFileEx/WriteFileEx's overlapped completion function */
-    if(ovp->completion_func)
-    {
-        QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp);
-    }
-
-    /* remove it from the active list */
-    if(ovp->prev)
-        ovp->prev->next = ovp->next;
-    else
-        NtCurrentTeb()->pending_list = ovp->next;
-
-    if(ovp->next)
-        ovp->next->prev = ovp->prev;
-
-    ovp->next=NULL;
-    ovp->prev=NULL;
-
-    close(ovp->fd);
-    if(ovp->event!=INVALID_HANDLE_VALUE)
-        NtSetEvent(ovp->event,NULL);
-    if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp);
-}
-
 /***********************************************************************
  *           check_async_list
  *
  * Process a status event from the server.
  */
-void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status)
+static void WINAPI check_async_list(async_private *asp, DWORD status)
 {
     async_private *ovp;
+    DWORD ovp_status;
 
-    /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
-
-    for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
-        if(ovp->lpOverlapped == overlapped)
-            break;
+    for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
 
     if(!ovp)
             return;
 
-    if(status != STATUS_ALERTED)
-        ovp->lpOverlapped->Internal = status;
+    if( status != STATUS_ALERTED )
+    {
+        ovp_status = status;
+        ovp->ops->set_status (ovp, status);
+    }
+    else ovp_status = ovp->ops->get_status (ovp);
 
-    if(ovp->lpOverlapped->Internal==STATUS_PENDING)
-        {
-        ovp->func(ovp);
-        FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
-        }
+    if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
 
-    if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
-        finish_async(ovp,ovp->lpOverlapped->Internal);
+    /* This will destroy all but PENDING requests */
+    register_old_async( ovp );
 }
 
 
@@ -201,6 +160,9 @@ static void call_apcs( BOOL alertable )
             DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
             proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
             break;
+        case APC_ASYNC_IO:
+            check_async_list ( args[0], (DWORD) args[1]);
+            break;
         default:
             server_protocol_error( "get_apc_request: bad type %d\n", type );
             break;
diff --git a/server/async.c b/server/async.c
index 5cbbcc59791130fa2b696e6b0e1023fcea59469a..ad13eb47ab56a48da50f5da433d4026ca2a41cec 100644
--- a/server/async.c
+++ b/server/async.c
@@ -64,7 +64,7 @@ void async_notify(struct async *async, int status)
 {
     /* fprintf(stderr,"notifying %p!\n",async->overlapped); */
     async->status = status;
-    thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status);
+    thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1, 2, async->overlapped, status);
 }
 
 void destroy_async_queue( struct async_queue *q )
@@ -116,7 +116,7 @@ static void async_callback(void *private)
     destroy_async(async);
 }
 
-struct async *create_async(struct object *obj, struct thread *thread, void *func, 
+struct async *create_async(struct object *obj, struct thread *thread,
                            void *overlapped)
 {
     struct async *async = (struct async *) malloc(sizeof(struct async));
@@ -128,7 +128,6 @@ struct async *create_async(struct object *obj, struct thread *thread, void *func
 
     async->obj = obj;
     async->thread = thread;
-    async->func = func;
     async->overlapped = overlapped;
     async->next = NULL;
     async->prev = NULL;
@@ -165,7 +164,7 @@ DECL_HANDLER(register_async)
         if(req->status==STATUS_PENDING)
         {
             if(!async)
-                async = create_async(obj, current, req->func, req->overlapped);
+                async = create_async(obj, current, req->overlapped);
 
             if(async)
             {
diff --git a/server/async.h b/server/async.h
index ec752b5cb22220705bcbe1583ce4bd5ed402e970..37b528f82f39ab1095fbc438883b303a8848411f 100644
--- a/server/async.h
+++ b/server/async.h
@@ -30,7 +30,6 @@ struct async
 {
     struct object       *obj;
     struct thread       *thread;
-    void                *func;
     void                *overlapped;
     unsigned int         status;
     struct timeval       when;
@@ -51,7 +50,7 @@ void async_notify(struct async *async, int status);
 struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped);
 void async_insert(struct async_queue *q, struct async *async);
 struct async *create_async(struct object *obj, struct thread *thread, 
-                           void *func, void *overlapped);
+                           void *overlapped);
 void async_add_timeout(struct async *async, int timeout);
 static inline void init_async_queue(struct async_queue *q) 
 { 
diff --git a/server/protocol.def b/server/protocol.def
index a13fcc7a8b77debc6f98390630ca262c4836be4c..ba96ea7f660170fa153e88f54d67722e20768b6b 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -412,7 +412,7 @@ typedef struct
     int          type;         /* function type */
     VARARG(args,ptrs);         /* function arguments */
 @END
-enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
+enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
 
 
 /* Close a handle for the current process */
@@ -1615,10 +1615,9 @@ enum message_type
 #define SERIALINFO_SET_ERROR     0x04
 
 
-/* Create/Destroy an async I/O */
+/* Create / reschedule an async I/O */
 @REQ(register_async)
     handle_t     handle;  /* handle to comm port, socket or file */
-    void*        func;
     int          type;
     void*        overlapped;
     int          count;
diff --git a/server/thread.c b/server/thread.c
index 7e019fabbd0a3bbe0021c53891815a035e0285a0..a43db32749d7c4285e3b73bbbe8a12eeb0bfde51 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -959,8 +959,9 @@ DECL_HANDLER(get_apc)
         }
         /* 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.
          */
-        if (apc->func) break;
+        if (apc->func || apc->type == APC_ASYNC_IO) break;
         free( apc );
     }
     size = apc->nb_args * sizeof(apc->args[0]);
diff --git a/server/trace.c b/server/trace.c
index cb2f19f03b3d1d1636a8f613ce4fa6243d37f775..00eb57d0d1c4c969bfa88d9b605c8b90099e3ea5 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1846,7 +1846,6 @@ static void dump_set_serial_info_request( const struct set_serial_info_request *
 static void dump_register_async_request( const struct register_async_request *req )
 {
     fprintf( stderr, " handle=%d,", req->handle );
-    fprintf( stderr, " func=%p,", req->func );
     fprintf( stderr, " type=%d,", req->type );
     fprintf( stderr, " overlapped=%p,", req->overlapped );
     fprintf( stderr, " count=%d,", req->count );