[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / timer.c
index 2c80d5e..de8caea 100644 (file)
@@ -1,27 +1,8 @@
 /*
- *  ReactOS W32 Subsystem
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program 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 General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id$
- *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Window timers messages
- * FILE:             subsys/win32k/ntuser/timer.c
+ * FILE:             subsystems/win32/win32k/ntuser/timer.c
  * PROGRAMER:        Gunnar
  *                   Thomas Weidenmueller (w3seek@users.sourceforge.net)
  * REVISION HISTORY: 10/04/2003 Implemented System Timers
 
 /* INCLUDES ******************************************************************/
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
 /* GLOBALS *******************************************************************/
 
+static PTIMER FirstpTmr = NULL;
+static LONG TimeLast = 0;
+
+#define MAX_ELAPSE_TIME 0x7FFFFFFF
+
 /* Windows 2000 has room for 32768 window-less timers */
-#define NUM_WINDOW_LESS_TIMERS   1024
+#define NUM_WINDOW_LESS_TIMERS   32768
 
 static FAST_MUTEX     Mutex;
 static RTL_BITMAP     WindowLessTimersBitMap;
 static PVOID          WindowLessTimersBitMapBuffer;
 static ULONG          HintIndex = 0;
 
+ERESOURCE TimerLock;
 
 #define IntLockWindowlessTimerBitmap() \
   ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Mutex)
@@ -52,14 +39,429 @@ static ULONG          HintIndex = 0;
 #define IntUnlockWindowlessTimerBitmap() \
   ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Mutex)
 
+#define TimerEnterExclusive() \
+{ \
+  KeEnterCriticalRegion(); \
+  ExAcquireResourceExclusiveLite(&TimerLock, TRUE); \
+}
+
+#define TimerLeave() \
+{ \
+  ExReleaseResourceLite(&TimerLock); \
+  KeLeaveCriticalRegion(); \
+}
+
+
 /* FUNCTIONS *****************************************************************/
+static
+PTIMER
+FASTCALL
+CreateTimer(VOID)
+{
+  HANDLE Handle;
+  PTIMER Ret = NULL;
+
+  if (!FirstpTmr)
+  {
+      ExInitializeResourceLite(&TimerLock);
+      FirstpTmr = UserCreateObject(gHandleTable, NULL, &Handle, otTimer, sizeof(TIMER));
+      if (FirstpTmr)
+      {
+         FirstpTmr->head.h = Handle;
+         InitializeListHead(&FirstpTmr->ptmrList);
+      }
+      Ret = FirstpTmr;
+  }
+  else
+  {
+      Ret = UserCreateObject(gHandleTable, NULL, &Handle, otTimer, sizeof(TIMER));
+      if (Ret)
+      {
+         Ret->head.h = Handle;
+         InsertTailList(&FirstpTmr->ptmrList, &Ret->ptmrList);
+      }
+  }
+  return Ret;
+}
 
+static
+BOOL
+FASTCALL
+RemoveTimer(PTIMER pTmr)
+{
+  BOOL Ret = FALSE;
+  if (pTmr)
+  {
+     /* Set the flag, it will be removed when ready */
+     RemoveEntryList(&pTmr->ptmrList);
+     if ((pTmr->pWnd == NULL) && (!(pTmr->flags & TMRF_SYSTEM)))
+     {
+        DPRINT("Clearing Bit %d)\n", pTmr->nID);
+        IntLockWindowlessTimerBitmap();
+        RtlClearBit(&WindowLessTimersBitMap, pTmr->nID);
+        IntUnlockWindowlessTimerBitmap();
+     }
+     UserDereferenceObject(pTmr);
+     Ret = UserDeleteObject( UserHMGetHandle(pTmr), otTimer);
+  }
+  if (!Ret) DPRINT1("Warning unable to delete timer\n");
+
+  return Ret;
+}
+
+PTIMER
+FASTCALL
+FindTimer(PWINDOW_OBJECT Window,
+          UINT_PTR nID,
+          UINT flags,
+          BOOL Distroy)
+{
+  PLIST_ENTRY pLE;
+  PTIMER pTmr = FirstpTmr, RetTmr = NULL;
+  TimerEnterExclusive();
+  do
+  {
+    if (!pTmr) break;
+
+    if ( pTmr->nID == nID &&
+         pTmr->pWnd == Window &&
+        (pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) == (flags & (TMRF_SYSTEM|TMRF_RIT)))
+    {
+       if (Distroy)
+       {
+          RemoveTimer(pTmr);
+       }
+       RetTmr = pTmr;
+       break;
+    }
+
+    pLE = pTmr->ptmrList.Flink;
+    pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+  } while (pTmr != FirstpTmr);
+  TimerLeave();
+
+  return RetTmr;
+}
+
+PTIMER
+FASTCALL
+FindSystemTimer(PMSG pMsg)
+{
+  PLIST_ENTRY pLE;
+  PTIMER pTmr = FirstpTmr;
+  TimerEnterExclusive();
+  do
+  {
+    if (!pTmr) break;
+
+    if ( pMsg->lParam == (LPARAM)pTmr->pfn &&
+         (pTmr->flags & TMRF_SYSTEM) )
+       break;
+
+    pLE = pTmr->ptmrList.Flink;
+    pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);    
+  } while (pTmr != FirstpTmr);
+  TimerLeave();
+
+  return pTmr;
+}
+
+BOOL
+FASTCALL
+ValidateTimerCallback(PTHREADINFO pti,
+                      PWINDOW_OBJECT Window,
+                      WPARAM wParam,
+                      LPARAM lParam)
+{
+  PLIST_ENTRY pLE;
+  PTIMER pTmr = FirstpTmr;
+
+  if (!pTmr) return FALSE;
+
+  TimerEnterExclusive();
+  do
+  {
+    if ( (lParam == (LPARAM)pTmr->pfn) &&
+         (pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) &&
+         (pTmr->pti->ppi == pti->ppi) )
+       break;
+
+    pLE = pTmr->ptmrList.Flink;
+    pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+  } while (pTmr != FirstpTmr);
+  TimerLeave();
+
+  if (!pTmr) return FALSE;
+
+  return TRUE;
+}
 
 UINT_PTR FASTCALL
-IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer)
+IntSetTimer( PWINDOW_OBJECT Window,
+                  UINT_PTR IDEvent,
+                  UINT Elapse,
+                  TIMERPROC TimerFunc,
+                  INT Type)
+{
+  PTIMER pTmr;
+  UINT Ret= IDEvent;
+  LARGE_INTEGER DueTime;
+  DueTime.QuadPart = (LONGLONG)(-10000000);
+
+#if 0
+  /* Windows NT/2k/XP behaviour */
+  if (Elapse > MAX_ELAPSE_TIME)
+  {
+     DPRINT("Adjusting uElapse\n");
+     Elapse = 1;
+  }
+#else
+  /* Windows XP SP2 and Windows Server 2003 behaviour */
+  if (Elapse > MAX_ELAPSE_TIME)
+  {
+     DPRINT("Adjusting uElapse\n");
+     Elapse = MAX_ELAPSE_TIME;
+  }
+#endif
+
+  /* Windows 2k/XP and Windows Server 2003 SP1 behaviour */
+  if (Elapse < 10)
+  {
+     DPRINT("Adjusting uElapse\n");
+     Elapse = 10;
+  }
+
+  if ((Window) && (IDEvent == 0))
+     IDEvent = 1;
+
+  pTmr = FindTimer(Window, IDEvent, Type, FALSE);
+
+  if ((!pTmr) && (Window == NULL) && (!(Type & TMRF_SYSTEM)))
+  {
+      IntLockWindowlessTimerBitmap();
+
+      IDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
+
+      if (IDEvent == (UINT_PTR) -1)
+      {
+         IntUnlockWindowlessTimerBitmap();
+         DPRINT1("Unable to find a free window-less timer id\n");
+         SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+         return 0;
+      }
+
+      Ret = IDEvent;
+      //HintIndex = IDEvent + 1;
+      IntUnlockWindowlessTimerBitmap();
+  }
+
+  if (!pTmr)
+  {
+     pTmr = CreateTimer();
+     if (!pTmr) return 0;
+
+     if (Window && (Type & TMRF_TIFROMWND))
+        pTmr->pti = Window->pti->pEThread->Tcb.Win32Thread;
+     else
+     {
+        if (Type & TMRF_RIT)
+           pTmr->pti = ptiRawInput;
+        else
+           pTmr->pti = PsGetCurrentThreadWin32Thread();
+     }
+
+     pTmr->pWnd    = Window;
+     pTmr->cmsCountdown = Elapse;
+     pTmr->cmsRate = Elapse;
+     pTmr->pfn     = TimerFunc;
+     pTmr->nID     = IDEvent;
+     pTmr->flags   = Type|TMRF_INIT; // Set timer to Init mode.
+  }
+  else
+  {
+     pTmr->cmsCountdown = Elapse;
+     pTmr->cmsRate = Elapse;
+  }
+
+  ASSERT(MasterTimer != NULL);
+  // Start the timer thread!
+  if (pTmr == FirstpTmr)
+     KeSetTimer(MasterTimer, DueTime, NULL);
+
+  return Ret;
+}
+
+//
+// Process win32k system timers.
+//
+VOID
+CALLBACK
+SystemTimerProc(HWND hwnd,
+                UINT uMsg,
+         UINT_PTR idEvent,
+             DWORD dwTime)
+{
+  DPRINT( "Timer Running!\n" );
+}
+
+VOID
+FASTCALL
+StartTheTimers(VOID)
+{
+  // Need to start gdi syncro timers then start timer with Hang App proc
+  // that calles Idle process so the screen savers will know to run......    
+  IntSetTimer(NULL, 0, 1000, SystemTimerProc, TMRF_RIT);
+}
+
+UINT_PTR
+FASTCALL
+SystemTimerSet( PWINDOW_OBJECT Window,
+                UINT_PTR nIDEvent,
+                UINT uElapse,
+                TIMERPROC lpTimerFunc)
+{
+  if (Window && Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
+  {
+     SetLastWin32Error(ERROR_ACCESS_DENIED);
+     return 0;
+  }
+  return IntSetTimer( Window, nIDEvent, uElapse, lpTimerFunc, TMRF_SYSTEM);
+}
+
+BOOL
+FASTCALL
+PostTimerMessages(PWINDOW_OBJECT Window)
+{
+  PLIST_ENTRY pLE;
+  PUSER_MESSAGE_QUEUE ThreadQueue;
+  MSG Msg;
+  PTHREADINFO pti;
+  BOOL Hit = FALSE;
+  PTIMER pTmr = FirstpTmr;
+
+  if (!pTmr) return FALSE;
+
+  pti = PsGetCurrentThreadWin32Thread();
+  ThreadQueue = pti->MessageQueue;
+
+  TimerEnterExclusive();
+
+  do
+  {
+     if ( (pTmr->flags & TMRF_READY) &&
+          (pTmr->pti == pti) &&
+          ((pTmr->pWnd == Window) || (Window == NULL) ) )
+        {
+           Msg.hwnd    = (pTmr->pWnd) ? pTmr->pWnd->hSelf : 0;
+           Msg.message = (pTmr->flags & TMRF_SYSTEM) ? WM_SYSTIMER : WM_TIMER;
+           Msg.wParam  = (WPARAM) pTmr->nID;
+           Msg.lParam  = (LPARAM) pTmr->pfn;
+
+           MsqPostMessage(ThreadQueue, &Msg, FALSE, QS_TIMER);
+           pTmr->flags &= ~TMRF_READY;
+           ThreadQueue->WakeMask = ~QS_TIMER;
+           Hit = TRUE;
+        }
+
+     pLE = pTmr->ptmrList.Flink;
+     pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+  } while (pTmr != FirstpTmr);
+
+  TimerLeave();
+
+  return Hit;
+}
+
+VOID
+FASTCALL
+ProcessTimers(VOID)
+{
+  LARGE_INTEGER TickCount, DueTime;
+  LONG Time;
+  PLIST_ENTRY pLE;
+  PTIMER pTmr = FirstpTmr;
+  LONG TimerCount = 0;
+
+  if (!pTmr) return;
+
+  TimerEnterExclusive();
+
+  KeQueryTickCount(&TickCount);
+  Time = MsqCalculateMessageTime(&TickCount);
+
+  DueTime.QuadPart = (LONGLONG)(-1000000);
+
+  do
+  {
+    TimerCount++;
+    if (pTmr->flags & TMRF_WAITING)
+    {
+       pLE = pTmr->ptmrList.Flink;
+       pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+       continue;
+    }
+
+    if (pTmr->flags & TMRF_INIT)
+    {
+       pTmr->flags &= ~TMRF_INIT; // Skip this run.
+    }
+    else
+    {
+       if (pTmr->cmsCountdown < 0)
+       {
+          ASSERT(pTmr->pti);
+          if ((!(pTmr->flags & TMRF_READY)) && (!(pTmr->pti->TIF_flags & TIF_INCLEANUP)))
+          {
+             if (pTmr->flags & TMRF_ONESHOT)
+                pTmr->flags |= TMRF_WAITING;
+
+             if (pTmr->flags & TMRF_RIT)
+             {
+                // Hard coded call here, inside raw input thread.
+                pTmr->pfn(NULL, WM_SYSTIMER, pTmr->nID, (LPARAM)pTmr);
+             }
+             else
+             {
+                pTmr->flags |= TMRF_READY; // Set timer ready to be ran.
+                // Set thread message queue for this timer.
+                if (pTmr->pti->MessageQueue)
+                {  // Wakeup thread
+                   ASSERT(pTmr->pti->MessageQueue->NewMessages != NULL);
+                   KeSetEvent(pTmr->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+                }
+             }
+          }
+          pTmr->cmsCountdown = pTmr->cmsRate;
+       }
+       else
+          pTmr->cmsCountdown -= Time - TimeLast;
+    }
+
+    pLE = pTmr->ptmrList.Flink;
+    pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+  } while (pTmr != FirstpTmr);
+
+  // Restart the timer thread!
+  ASSERT(MasterTimer != NULL);
+  KeSetTimer(MasterTimer, DueTime, NULL);
+
+  TimeLast = Time;
+
+  TimerLeave();
+  DPRINT("TimerCount = %d\n", TimerCount);
+}
+
+//
+//
+// Old Timer Queueing
+//
+//
+UINT_PTR FASTCALL
+InternalSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer)
 {
    PWINDOW_OBJECT Window;
    UINT_PTR Ret = 0;
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE MessageQueue;
 
    DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
@@ -83,7 +485,8 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
       HintIndex = ++IDEvent;
       IntUnlockWindowlessTimerBitmap();
       Ret = IDEvent;
-      MessageQueue = PsGetCurrentThreadWin32Thread()->MessageQueue;
+      pti = PsGetCurrentThreadWin32Thread();
+      MessageQueue = pti->MessageQueue;
    }
    else
    {
@@ -93,7 +496,7 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
          return 0;
       }
 
-      if (Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
+      if (Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
       {
          DPRINT1("Trying to set timer for window in another process (shatter attack?)\n");
          SetLastWin32Error(ERROR_ACCESS_DENIED);
@@ -101,12 +504,12 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
       }
 
       Ret = IDEvent;
-      MessageQueue = Window->MessageQueue;
+      MessageQueue = Window->pti->MessageQueue;
    }
 
-#if 1
+#if 0
 
-   /* Win NT/2k/XP */
+   /* Windows NT/2k/XP behaviour */
    if (Elapse > 0x7fffffff)
    {
       DPRINT("Adjusting uElapse\n");
@@ -115,7 +518,7 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
 
 #else
 
-   /* Win Server 2003 */
+   /* Windows XP SP2 and Windows Server 2003 behaviour */
    if (Elapse > 0x7fffffff)
    {
       DPRINT("Adjusting uElapse\n");
@@ -124,7 +527,7 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
 
 #endif
 
-   /* Win 2k/XP */
+   /* Windows 2k/XP and Windows Server 2003 SP1 behaviour */
    if (Elapse < 10)
    {
       DPRINT("Adjusting uElapse\n");
@@ -140,34 +543,130 @@ IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL S
       return 0;
    }
 
-
+if (Ret == 0) ASSERT(FALSE);
    return Ret;
 }
 
+BOOL FASTCALL
+DestroyTimersForWindow(PTHREADINFO pti, PWINDOW_OBJECT Window)
+{
+   PLIST_ENTRY pLE;
+   PTIMER pTmr = FirstpTmr;
+   BOOL TimersRemoved = FALSE;
+
+   if ((FirstpTmr == NULL) || (Window == NULL))
+      return FALSE;
+
+   TimerEnterExclusive();
+
+   do
+   {
+      if ((pTmr) && (pTmr->pti == pti) && (pTmr->pWnd == Window))
+      {
+         TimersRemoved = RemoveTimer(pTmr);
+      }
+      pLE = pTmr->ptmrList.Flink;
+      pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+   } while (pTmr != FirstpTmr);
+
+   TimerLeave();
+
+   return TimersRemoved;
+}
+
+BOOL FASTCALL
+DestroyTimersForThread(PTHREADINFO pti)
+{
+   PLIST_ENTRY pLE;
+   PTIMER pTmr = FirstpTmr;
+   BOOL TimersRemoved = FALSE;
+
+   if (FirstpTmr == NULL)
+      return FALSE;
+
+   TimerEnterExclusive();
+
+   do
+   {
+      if ((pTmr) && (pTmr->pti == pti))
+      {
+         TimersRemoved = RemoveTimer(pTmr);
+      }
+      pLE = pTmr->ptmrList.Flink;
+      pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+   } while (pTmr != FirstpTmr);
+
+   TimerLeave();
+
+   return TimersRemoved;
+}
+
+BOOL FASTCALL
+IntKillTimer(PWINDOW_OBJECT Window, UINT_PTR IDEvent, BOOL SystemTimer)
+{
+   PTIMER pTmr = NULL;
+   DPRINT("IntKillTimer Window %x id %p systemtimer %s\n",
+          Window, IDEvent, SystemTimer ? "TRUE" : "FALSE");
+
+   if ((Window) && (IDEvent == 0))
+      IDEvent = 1;
+
+   pTmr = FindTimer(Window, IDEvent, SystemTimer ? TMRF_SYSTEM : 0, TRUE);
+   return pTmr ? TRUE :  FALSE;
+}
 
+//
+//
+// Old Kill Timer
+//
+//
 BOOL FASTCALL
-IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
+InternalKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
 {
+   PTHREADINFO pti;
+   PWINDOW_OBJECT Window = NULL;
+
    DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
           Wnd, IDEvent, SystemTimer ? "TRUE" : "FALSE");
 
-   if (! MsqKillTimer(PsGetCurrentThreadWin32Thread()->MessageQueue, Wnd,
-                      IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
+   pti = PsGetCurrentThreadWin32Thread();
+   if (Wnd)
    {
-      DPRINT1("Unable to locate timer in message queue\n");
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      return FALSE;
+      Window = UserGetWindowObject(Wnd);
+
+      if (! MsqKillTimer(pti->MessageQueue, Wnd,
+                                IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
+      {
+         // Give it another chance to find the timer.
+         if (Window && !( MsqKillTimer(Window->pti->MessageQueue, Wnd,
+                            IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER)))
+         {
+            DPRINT1("Unable to locate timer in message queue for Window.\n");
+            SetLastWin32Error(ERROR_INVALID_PARAMETER);
+            return FALSE;
+         }
+      }
    }
 
    /* window-less timer? */
    if ((Wnd == NULL) && ! SystemTimer)
    {
+      if (! MsqKillTimer(pti->MessageQueue, Wnd,
+                                IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
+      {
+         DPRINT1("Unable to locate timer in message queue for Window-less timer.\n");
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return FALSE;
+      }
+
       /* Release the id */
       IntLockWindowlessTimerBitmap();
 
       ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap, IDEvent - 1, 1));
       RtlClearBits(&WindowLessTimersBitMap, IDEvent - 1, 1);
 
+      HintIndex = IDEvent - 1;
+
       IntUnlockWindowlessTimerBitmap();
    }
 
@@ -181,13 +680,13 @@ InitTimerImpl(VOID)
 
    ExInitializeFastMutex(&Mutex);
 
-   BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;   
+   BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
    WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
    if (WindowLessTimersBitMapBuffer == NULL)
    {
       return STATUS_UNSUCCESSFUL;
-   }      
-   
+   }
+
    RtlInitializeBitMap(&WindowLessTimersBitMap,
                        WindowLessTimersBitMapBuffer,
                        BitmapBytes * 8);
@@ -198,9 +697,8 @@ InitTimerImpl(VOID)
    return STATUS_SUCCESS;
 }
 
-
 UINT_PTR
-STDCALL
+APIENTRY
 NtUserSetTimer
 (
    HWND hWnd,
@@ -209,44 +707,49 @@ NtUserSetTimer
    TIMERPROC lpTimerFunc
 )
 {
+   PWINDOW_OBJECT Window;
    DECLARE_RETURN(UINT_PTR);
 
    DPRINT("Enter NtUserSetTimer\n");
    UserEnterExclusive();
+   Window = UserGetWindowObject(hWnd);
+   UserLeave();
 
-   RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE));
+   RETURN(IntSetTimer(Window, nIDEvent, uElapse, lpTimerFunc, TMRF_TIFROMWND));
 
 CLEANUP:
    DPRINT("Leave NtUserSetTimer, ret=%i\n", _ret_);
-   UserLeave();
+
    END_CLEANUP;
 }
 
 
 BOOL
-STDCALL
+APIENTRY
 NtUserKillTimer
 (
    HWND hWnd,
    UINT_PTR uIDEvent
 )
 {
+   PWINDOW_OBJECT Window;
    DECLARE_RETURN(BOOL);
 
    DPRINT("Enter NtUserKillTimer\n");
    UserEnterExclusive();
+   Window = UserGetWindowObject(hWnd);
+   UserLeave();
 
-   RETURN(IntKillTimer(hWnd, uIDEvent, FALSE));
+   RETURN(IntKillTimer(Window, uIDEvent, FALSE));
 
 CLEANUP:
    DPRINT("Leave NtUserKillTimer, ret=%i\n", _ret_);
-   UserLeave();
    END_CLEANUP;
 }
 
 
 UINT_PTR
-STDCALL
+APIENTRY
 NtUserSetSystemTimer(
    HWND hWnd,
    UINT_PTR nIDEvent,
@@ -257,35 +760,14 @@ NtUserSetSystemTimer(
    DECLARE_RETURN(UINT_PTR);
 
    DPRINT("Enter NtUserSetSystemTimer\n");
-   UserEnterExclusive();
 
-   RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, TRUE));
+   // This is wrong, lpTimerFunc is NULL!
+   RETURN(IntSetTimer(UserGetWindowObject(hWnd), nIDEvent, uElapse, lpTimerFunc, TMRF_SYSTEM));
 
 CLEANUP:
    DPRINT("Leave NtUserSetSystemTimer, ret=%i\n", _ret_);
-   UserLeave();
    END_CLEANUP;
 }
 
 
-BOOL
-STDCALL
-NtUserKillSystemTimer(
-   HWND hWnd,
-   UINT_PTR uIDEvent
-)
-{
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("Enter NtUserKillSystemTimer\n");
-   UserEnterExclusive();
-
-   RETURN(IntKillTimer(hWnd, uIDEvent, TRUE));
-
-CLEANUP:
-   DPRINT("Leave NtUserKillSystemTimer, ret=%i\n", _ret_);
-   UserLeave();
-   END_CLEANUP;
-}
-
 /* EOF */