diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 4fa4d1034a56892eab0474b8daa67a28eba77738..4206462d838fe2218a51de107f9e7679ac1029a3 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -18,9 +18,6 @@
 
 DEFAULT_DEBUG_CHANNEL(ntdll)
 
-/* move to winbase.h */
-typedef VOID (CALLBACK *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue);   
-
 /*
  *	Timer object
  */
diff --git a/include/server.h b/include/server.h
index 62fe2e1ad3856c6aa739325c5124dd5a136af403..1518f0ded7f59e0f5ca90ddd487ca95327829912 100644
--- a/include/server.h
+++ b/include/server.h
@@ -967,6 +967,43 @@ struct set_registry_levels_request
 };
 
 
+/* Create a waitable timer */
+struct create_timer_request
+{
+    IN  int          inherit;       /* inherit flag */
+    IN  int          manual;        /* manual reset */
+    OUT int          handle;        /* handle to the timer */
+    IN  WCHAR        name[1];       /* timer name */
+};
+
+
+/* Open a waitable timer */
+struct open_timer_request
+{
+    IN  unsigned int access;        /* wanted access rights */
+    IN  int          inherit;       /* inherit flag */
+    OUT int          handle;        /* handle to the timer */
+    IN  WCHAR        name[1];       /* timer name */
+};
+
+/* Set a waitable timer */
+struct set_timer_request
+{
+    IN  int          handle;        /* handle to the timer */
+    IN  int          sec;           /* next expiration absolute time */
+    IN  int          usec;          /* next expiration absolute time */
+    IN  int          period;        /* timer period in ms */
+    IN  void*        callback;      /* callback function */
+    IN  void*        arg;           /* callback argument */
+};
+
+/* Cancel a waitable timer */
+struct cancel_timer_request
+{
+    IN  int          handle;        /* handle to the timer */
+};
+
+
 /* Everything below this line is generated automatically by tools/make_requests */
 /* ### make_requests begin ### */
 
@@ -1058,6 +1095,10 @@ enum request
     REQ_LOAD_REGISTRY,
     REQ_SAVE_REGISTRY,
     REQ_SET_REGISTRY_LEVELS,
+    REQ_CREATE_TIMER,
+    REQ_OPEN_TIMER,
+    REQ_SET_TIMER,
+    REQ_CANCEL_TIMER,
     REQ_NB_REQUESTS
 };
 
diff --git a/include/winbase.h b/include/winbase.h
index 69a656faa8f1fcba3e85050b4fa43c2a56e14182..045544d98244628237f611a4c664c9a25f20dff3 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1086,7 +1086,8 @@ typedef struct tagCOMMTIMEOUTS {
   
 #include "poppack.h"
 
-typedef VOID (CALLBACK *PAPCFUNC)(ULONG_PTR);
+typedef void (CALLBACK *PAPCFUNC)(ULONG_PTR);
+typedef void (CALLBACK *PTIMERAPCROUTINE)(LPVOID,DWORD,DWORD);
 
 BOOL      WINAPI ClearCommError(INT,LPDWORD,LPCOMSTAT);
 BOOL      WINAPI BuildCommDCBA(LPCSTR,LPDCB);
@@ -1154,7 +1155,8 @@ BOOL      WINAPI AreFileApisANSI(void);
 BOOL        WINAPI BackupEventLogA(HANDLE,LPCSTR);
 BOOL        WINAPI BackupEventLogW(HANDLE,LPCWSTR);
 #define     BackupEventLog WINELIB_NAME_AW(BackupEventLog)
-BOOL      WINAPI Beep(DWORD,DWORD);
+BOOL        WINAPI Beep(DWORD,DWORD);
+BOOL        WINAPI CancelWaitableTimer(HANDLE);
 BOOL        WINAPI ClearEventLogA(HANDLE,LPCSTR);
 BOOL        WINAPI ClearEventLogW(HANDLE,LPCWSTR);
 #define     ClearEventLog WINELIB_NAME_AW(ClearEventLog)
@@ -1198,6 +1200,9 @@ HANDLE    WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCSTR);
 HANDLE    WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCWSTR);
 #define     CreateSemaphore WINELIB_NAME_AW(CreateSemaphore)
 HANDLE      WINAPI CreateThread(LPSECURITY_ATTRIBUTES,DWORD,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD);
+HANDLE      WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR);
+HANDLE      WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR);
+#define     CreateWaitableTimer WINELIB_NAME_AW(CreateWaitableTimer)
 BOOL        WINAPI DebugActiveProcess(DWORD);
 void        WINAPI DebugBreak(void);
 BOOL        WINAPI DeregisterEventSource(HANDLE);
@@ -1335,10 +1340,11 @@ BOOL      WINAPI GetStringTypeExA(LCID,DWORD,LPCSTR,INT,LPWORD);
 BOOL      WINAPI GetStringTypeExW(LCID,DWORD,LPCWSTR,INT,LPWORD);
 #define     GetStringTypeEx WINELIB_NAME_AW(GetStringTypeEx)
 VOID        WINAPI GetSystemInfo(LPSYSTEM_INFO);
-BOOL      WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS);
+BOOL        WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS);
 VOID        WINAPI GetSystemTime(LPSYSTEMTIME);
-INT       WINAPI GetTimeFormatA(LCID,DWORD,LPSYSTEMTIME,LPCSTR,LPSTR,INT);
-INT       WINAPI GetTimeFormatW(LCID,DWORD,LPSYSTEMTIME,LPCWSTR,LPWSTR,INT);
+VOID        WINAPI GetSystemTimeAsFileTime(LPFILETIME);
+INT         WINAPI GetTimeFormatA(LCID,DWORD,LPSYSTEMTIME,LPCSTR,LPSTR,INT);
+INT         WINAPI GetTimeFormatW(LCID,DWORD,LPSYSTEMTIME,LPCWSTR,LPWSTR,INT);
 #define     GetTimeFormat WINELIB_NAME_AW(GetTimeFormat)
 BOOL        WINAPI GetThreadContext(HANDLE,CONTEXT *);
 LCID        WINAPI GetThreadLocale(void);
@@ -1413,8 +1419,11 @@ HANDLE    WINAPI OpenSemaphoreA(DWORD,BOOL,LPCSTR);
 HANDLE    WINAPI OpenSemaphoreW(DWORD,BOOL,LPCWSTR);
 #define     OpenSemaphore WINELIB_NAME_AW(OpenSemaphore)
 BOOL        WINAPI OpenThreadToken(HANDLE,DWORD,BOOL,PHANDLE);
-BOOL      WINAPI PulseEvent(HANDLE);
-BOOL      WINAPI PurgeComm(HANDLE,DWORD);
+HANDLE      WINAPI OpenWaitableTimerA(DWORD,BOOL,LPCSTR);
+HANDLE      WINAPI OpenWaitableTimerW(DWORD,BOOL,LPCWSTR);
+#define     OpenWaitableTimer WINELIB_NAME_AW(OpenWaitableTimer)
+BOOL        WINAPI PulseEvent(HANDLE);
+BOOL        WINAPI PurgeComm(HANDLE,DWORD);
 DWORD       WINAPI QueryDosDeviceA(LPCSTR,LPSTR,DWORD);
 DWORD       WINAPI QueryDosDeviceW(LPCWSTR,LPWSTR,DWORD);
 #define     QueryDosDevice WINELIB_NAME_AW(QueryDosDevice)
@@ -1484,9 +1493,10 @@ BOOL      WINAPI SetSystemPowerState(BOOL,BOOL);
 BOOL      WINAPI SetSystemTime(const SYSTEMTIME*);
 DWORD       WINAPI SetThreadAffinityMask(HANDLE,DWORD);
 BOOL        WINAPI SetThreadContext(HANDLE,const CONTEXT *);
-BOOL      WINAPI SetThreadLocale(LCID);
-BOOL      WINAPI SetThreadPriority(HANDLE,INT);
-BOOL      WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION);
+BOOL        WINAPI SetThreadLocale(LCID);
+BOOL        WINAPI SetThreadPriority(HANDLE,INT);
+BOOL        WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION);
+BOOL        WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,BOOL);
 VOID        WINAPI Sleep(DWORD);
 DWORD       WINAPI SleepEx(DWORD,BOOL);
 DWORD       WINAPI SuspendThread(HANDLE);
diff --git a/relay32/kernel32.spec b/relay32/kernel32.spec
index dc64eadcb25f97f3194c23d34363bcfdf0162803..0218608ff64dfea43218736de00294aa529f7e2c 100644
--- a/relay32/kernel32.spec
+++ b/relay32/kernel32.spec
@@ -873,12 +873,12 @@ import  ntdll.dll
 
 # NT 4.0 additions
 856 stub CancelIo
-857 stub CancelWaitableTimer
+857 stdcall CancelWaitableTimer(long) CancelWaitableTimer
 858 stdcall CopyFileExA (str str ptr ptr ptr long) CopyFileExA
 859 stdcall CopyFileExW (wstr wstr ptr ptr ptr long) CopyFileExW
 860 stub CreateFiber
-861 stub CreateWaitableTimerA
-862 stub CreateWaitableTimerW
+861 stdcall CreateWaitableTimerA(ptr long str) CreateWaitableTimerA
+862 stdcall CreateWaitableTimerW(ptr long wstr) CreateWaitableTimerW
 863 stub DeleteFiber
 864 stub DuplicateConsoleHandle
 865 stub FindFirstFileExA
@@ -896,8 +896,8 @@ import  ntdll.dll
 878 stdcall InterlockedCompareExchange (ptr long long) InterlockedCompareExchange
 879 stdcall InterlockedExchangeAdd (ptr long ) InterlockedExchangeAdd
 880 stdcall IsProcessorFeaturePresent(long) IsProcessorFeaturePresent
-881 stub OpenWaitableTimerA
-882 stub OpenWaitableTimerW
+881 stdcall OpenWaitableTimerA(long long str) OpenWaitableTimerA
+882 stdcall OpenWaitableTimerW(long long wstr) OpenWaitableTimerW
 883 stub ReadConsoleInputExA
 884 stub ReadConsoleInputExW
 885 stub ReadDirectoryChangesW
@@ -909,7 +909,7 @@ import  ntdll.dll
 891 stdcall SetProcessPriorityBoost(long long) SetProcessPriorityBoost
 892 stub SetThreadIdealProcessor
 893 stub SetThreadPriorityBoost
-894 stub SetWaitableTimer
+894 stdcall SetWaitableTimer(long ptr long ptr ptr long) SetWaitableTimer
 895 stub SignalObjectAndWait
 896 stub SwitchToFiber
 897 stub SwitchToThread
diff --git a/scheduler/Makefile.in b/scheduler/Makefile.in
index e969ff0f468fca4aca9c89eabfde827310c5b7cb..c2127c52e3ffa7e7d6f11fdb86f00b71d41d1f4b 100644
--- a/scheduler/Makefile.in
+++ b/scheduler/Makefile.in
@@ -19,7 +19,8 @@ C_SRCS = \
 	synchro.c \
 	sysdeps.c \
 	syslevel.c \
-	thread.c
+	thread.c \
+	timer.c
 
 all: $(MODULE).o
 
diff --git a/scheduler/timer.c b/scheduler/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..0054187b974ef59b877c9af497c8c28f11b92e5c
--- /dev/null
+++ b/scheduler/timer.c
@@ -0,0 +1,122 @@
+/*
+ * Win32 waitable timers
+ *
+ * Copyright 1999 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "winerror.h"
+#include "file.h"  /* for FILETIME routines */
+#include "server.h"
+
+
+/***********************************************************************
+ *           CreateWaitableTimerA    (KERNEL32.861)
+ */
+HANDLE WINAPI CreateWaitableTimerA( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCSTR name )
+{
+    struct create_timer_request *req = get_req_buffer();
+
+    req->manual  = manual;
+    req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
+    server_strcpyAtoW( req->name, name );
+    SetLastError(0);
+    server_call( REQ_CREATE_TIMER );
+    if (req->handle == -1) return 0;
+    return req->handle;
+}
+
+
+/***********************************************************************
+ *           CreateWaitableTimerW    (KERNEL32.862)
+ */
+HANDLE WINAPI CreateWaitableTimerW( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCWSTR name )
+{
+    struct create_timer_request *req = get_req_buffer();
+
+    req->manual  = manual;
+    req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
+    server_strcpyW( req->name, name );
+    SetLastError(0);
+    server_call( REQ_CREATE_TIMER );
+    if (req->handle == -1) return 0;
+    return req->handle;
+}
+
+
+/***********************************************************************
+ *           OpenWaitableTimerA    (KERNEL32.881)
+ */
+HANDLE WINAPI OpenWaitableTimerA( DWORD access, BOOL inherit, LPCSTR name )
+{
+    struct open_timer_request *req = get_req_buffer();
+
+    req->access  = access;
+    req->inherit = inherit;
+    server_strcpyAtoW( req->name, name );
+    server_call( REQ_OPEN_TIMER );
+    if (req->handle == -1) return 0; /* must return 0 on failure, not -1 */
+    return req->handle;
+}
+
+
+/***********************************************************************
+ *           OpenWaitableTimerW    (KERNEL32.882)
+ */
+HANDLE WINAPI OpenWaitableTimerW( DWORD access, BOOL inherit, LPCWSTR name )
+{
+    struct open_timer_request *req = get_req_buffer();
+
+    req->access  = access;
+    req->inherit = inherit;
+    server_strcpyW( req->name, name );
+    server_call( REQ_OPEN_TIMER );
+    if (req->handle == -1) return 0; /* must return 0 on failure, not -1 */
+    return req->handle;
+}
+
+
+/***********************************************************************
+ *           SetWaitableTimer    (KERNEL32.894)
+ */
+BOOL WINAPI SetWaitableTimer( HANDLE handle, const LARGE_INTEGER *when, LONG period,
+                              PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
+{
+    FILETIME ft;
+    DWORD remainder;
+    struct set_timer_request *req = get_req_buffer();
+
+    if (when->s.HighPart < 0)  /* relative time */
+    {
+        DWORD low = ft.dwLowDateTime;
+        GetSystemTimeAsFileTime( &ft );
+        ft.dwLowDateTime -= when->s.LowPart;
+        ft.dwHighDateTime -= when->s.HighPart;
+        if (low < ft.dwLowDateTime) ft.dwHighDateTime--; /* overflow */
+    }
+    else  /* absolute time */
+    {
+        ft.dwLowDateTime = when->s.LowPart;
+        ft.dwHighDateTime = when->s.HighPart;
+    }
+    req->handle   = handle;
+    req->sec      = DOSFS_FileTimeToUnixTime( &ft, &remainder );
+    req->usec     = remainder / 10;  /* convert from 100-ns to us units */
+    req->period   = period;
+    req->callback = callback;
+    req->arg      = arg;
+    if (resume) SetLastError( ERROR_NOT_SUPPORTED ); /* set error but can still succeed */
+    return !server_call( REQ_SET_TIMER );
+}
+
+
+/***********************************************************************
+ *           CancelWaitableTimer    (KERNEL32.857)
+ */
+BOOL WINAPI CancelWaitableTimer( HANDLE handle )
+{
+    struct cancel_timer_request *req = get_req_buffer();
+    req->handle = handle;
+    return !server_call( REQ_CANCEL_TIMER );
+}
diff --git a/server/Makefile.in b/server/Makefile.in
index d917cfed5a3ccbd57fe6b5a51ca2ada50f043141..60aa6e0f647d139fc8e3867eb91abeb512ac3e6f 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -27,6 +27,7 @@ C_SRCS = \
 	sock.c \
 	socket.c \
 	thread.c \
+	timer.c \
 	trace.c \
 	unicode.c
 
diff --git a/server/request.h b/server/request.h
index 0d509ac643ea898d6b9fb61dde0331584e5360f6..d34c79863953337ff481e08b121af3201acbb1e1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -155,6 +155,10 @@ DECL_HANDLER(delete_key_value);
 DECL_HANDLER(load_registry);
 DECL_HANDLER(save_registry);
 DECL_HANDLER(set_registry_levels);
+DECL_HANDLER(create_timer);
+DECL_HANDLER(open_timer);
+DECL_HANDLER(set_timer);
+DECL_HANDLER(cancel_timer);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -248,6 +252,10 @@ static const struct handler {
     { (void(*)())req_load_registry, sizeof(struct load_registry_request) },
     { (void(*)())req_save_registry, sizeof(struct save_registry_request) },
     { (void(*)())req_set_registry_levels, sizeof(struct set_registry_levels_request) },
+    { (void(*)())req_create_timer, sizeof(struct create_timer_request) },
+    { (void(*)())req_open_timer, sizeof(struct open_timer_request) },
+    { (void(*)())req_set_timer, sizeof(struct set_timer_request) },
+    { (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) },
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/timer.c b/server/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a20ca160c49ba9ea57c9a82db087d8596abaa8b
--- /dev/null
+++ b/server/timer.c
@@ -0,0 +1,200 @@
+/*
+ * Waitable timers management
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "winerror.h"
+
+#include "handle.h"
+#include "request.h"
+
+/* FIXME: check values and move to standard header */
+#define TIMER_MODIFY_STATE  0x0001
+#define TIMER_QUERY_STATE   0x0002
+#define TIMER_ALL_ACCESS    (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
+
+struct timer
+{
+    struct object        obj;       /* object header */
+    int                  manual;    /* manual reset */
+    int                  signaled;  /* current signaled state */
+    int                  period;    /* timer period in ms */
+    struct timeval       when;      /* next expiration */
+    struct timeout_user *timeout;   /* timeout user */
+    void                *callback;  /* callback APC function */
+    void                *arg;       /* callback argument */
+};
+
+static void timer_dump( struct object *obj, int verbose );
+static int timer_signaled( struct object *obj, struct thread *thread );
+static int timer_satisfied( struct object *obj, struct thread *thread );
+static void timer_destroy( struct object *obj );
+
+static const struct object_ops timer_ops =
+{
+    sizeof(struct timer),
+    timer_dump,
+    add_queue,
+    remove_queue,
+    timer_signaled,
+    timer_satisfied,
+    no_read_fd,
+    no_write_fd,
+    no_flush,
+    no_get_file_info,
+    timer_destroy
+};
+
+
+/* create a timer object */
+static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
+{
+    struct timer *timer;
+
+    if ((timer = create_named_object( &timer_ops, name, len )))
+    {
+        if (get_error() != ERROR_ALREADY_EXISTS)
+        {
+            /* initialize it if it didn't already exist */
+            timer->manual       = manual;
+            timer->signaled     = 0;
+            timer->when.tv_sec  = 0;
+            timer->when.tv_usec = 0;
+            timer->period       = 0;
+            timer->timeout      = NULL;
+        }
+    }
+    return timer;
+}
+
+/* callback on timer expiration */
+static void timer_callback( void *private )
+{
+    struct timer *timer = (struct timer *)private;
+
+    if (timer->period)  /* schedule the next expiration */
+    {
+        make_timeout( &timer->when, timer->period );
+        timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
+    }
+    else timer->timeout = NULL;
+
+    /* wake up waiters */
+    timer->signaled = 1;
+    wake_up( &timer->obj, 0 );
+}
+
+/* set the timer expiration and period */
+static void set_timer( struct timer *timer, int sec, int usec, int period,
+                       void *callback, void *arg )
+{
+    if (timer->manual)
+    {
+        period = 0;  /* period doesn't make any sense for a manual timer */
+        timer->signaled = 0;
+    }
+    if (timer->timeout) remove_timeout_user( timer->timeout );
+    timer->when.tv_sec  = sec;
+    timer->when.tv_usec = usec;
+    timer->period       = period;
+    timer->callback     = callback;
+    timer->arg          = arg;
+    timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
+}
+
+/* cancel a running timer */
+static void cancel_timer( struct timer *timer )
+{
+    if (timer->timeout)
+    {
+        remove_timeout_user( timer->timeout );
+        timer->timeout = NULL;
+    }
+}
+
+static void timer_dump( struct object *obj, int verbose )
+{
+    struct timer *timer = (struct timer *)obj;
+    assert( obj->ops == &timer_ops );
+    fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
+             timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
+    dump_object_name( &timer->obj );
+    fputc( '\n', stderr );
+}
+
+static int timer_signaled( struct object *obj, struct thread *thread )
+{
+    struct timer *timer = (struct timer *)obj;
+    assert( obj->ops == &timer_ops );
+    return timer->signaled;
+}
+
+static int timer_satisfied( struct object *obj, struct thread *thread )
+{
+    struct timer *timer = (struct timer *)obj;
+    assert( obj->ops == &timer_ops );
+    if (!timer->manual) timer->signaled = 0;
+    return 0;
+}
+
+static void timer_destroy( struct object *obj )
+{
+    struct timer *timer = (struct timer *)obj;
+    assert( obj->ops == &timer_ops );
+
+    if (timer->timeout) remove_timeout_user( timer->timeout );
+}
+
+/* create a timer */
+DECL_HANDLER(create_timer)
+{
+    size_t len = get_req_strlenW( req->name );
+    struct timer *timer;
+
+    req->handle = -1;
+    if ((timer = create_timer( req->name, len, req->manual )))
+    {
+        req->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
+        release_object( timer );
+    }
+}
+
+/* open a handle to a timer */
+DECL_HANDLER(open_timer)
+{
+    size_t len = get_req_strlenW( req->name );
+    req->handle = open_object( req->name, len, &timer_ops, req->access, req->inherit );
+}
+
+/* set a waitable timer */
+DECL_HANDLER(set_timer)
+{
+    struct timer *timer;
+
+    if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
+                                                 TIMER_MODIFY_STATE, &timer_ops )))
+    {
+        set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
+        release_object( timer );
+    }
+}
+
+/* cancel a waitable timer */
+DECL_HANDLER(cancel_timer)
+{
+    struct timer *timer;
+
+    if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
+                                                 TIMER_MODIFY_STATE, &timer_ops )))
+    {
+        cancel_timer( timer );
+        release_object( timer );
+    }
+}
diff --git a/server/trace.c b/server/trace.c
index b05af06f7ae91d2112306faf528ed41acc58fd4c..0e436f2f8ba096641739062a428172528e30a247 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -999,6 +999,47 @@ static void dump_set_registry_levels_request( struct set_registry_levels_request
     fprintf( stderr, " version=%d", req->version );
 }
 
+static void dump_create_timer_request( struct create_timer_request *req )
+{
+    fprintf( stderr, " inherit=%d,", req->inherit );
+    fprintf( stderr, " manual=%d,", req->manual );
+    fprintf( stderr, " name=" );
+    dump_unicode_string( req->name );
+}
+
+static void dump_create_timer_reply( struct create_timer_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_open_timer_request( struct open_timer_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " inherit=%d,", req->inherit );
+    fprintf( stderr, " name=" );
+    dump_unicode_string( req->name );
+}
+
+static void dump_open_timer_reply( struct open_timer_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_set_timer_request( struct set_timer_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " sec=%d,", req->sec );
+    fprintf( stderr, " usec=%d,", req->usec );
+    fprintf( stderr, " period=%d,", req->period );
+    fprintf( stderr, " callback=%p,", req->callback );
+    fprintf( stderr, " arg=%p", req->arg );
+}
+
+static void dump_cancel_timer_request( struct cancel_timer_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_new_thread_request,
@@ -1086,6 +1127,10 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_load_registry_request,
     (dump_func)dump_save_registry_request,
     (dump_func)dump_set_registry_levels_request,
+    (dump_func)dump_create_timer_request,
+    (dump_func)dump_open_timer_request,
+    (dump_func)dump_set_timer_request,
+    (dump_func)dump_cancel_timer_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -1175,6 +1220,10 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)0,
     (dump_func)0,
     (dump_func)0,
+    (dump_func)dump_create_timer_reply,
+    (dump_func)dump_open_timer_reply,
+    (dump_func)0,
+    (dump_func)0,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -1264,6 +1313,10 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "load_registry",
     "save_registry",
     "set_registry_levels",
+    "create_timer",
+    "open_timer",
+    "set_timer",
+    "cancel_timer",
 };
 
 /* ### make_requests end ### */