some work on timers
authorThomas Bluemel <thomas@reactsoft.com>
Wed, 15 Oct 2003 13:39:09 +0000 (13:39 +0000)
committerThomas Bluemel <thomas@reactsoft.com>
Wed, 15 Oct 2003 13:39:09 +0000 (13:39 +0000)
svn path=/trunk/; revision=6323

reactos/subsys/win32k/ntuser/timer.c

index 73075bd..663f404 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: timer.c,v 1.11 2003/10/04 22:36:37 weiden Exp $
+/* $Id: timer.c,v 1.12 2003/10/15 13:39:09 weiden Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Window timers messages
  * FILE:             subsys/win32k/ntuser/timer.c
  * PROGRAMER:        Gunnar
- * REVISION HISTORY:
+ *                   Thomas Weidenmueller (w3seek@users.sourceforge.net)
+ * REVISION HISTORY: 10/04/2003 Implemented System Timers
  *
  */
 
@@ -73,691 +74,576 @@ typedef struct _MSG_TIMER_ENTRY{
 
 //return true if the new timer became the first entry
 //must hold mutex while calling this
-BOOL
-FASTCALL
-InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer, BOOL SysTimer)
-{
-   PLIST_ENTRY EnumEntry, InsertAfter;
-   PMSG_TIMER_ENTRY MsgTimer;
-
-   InsertAfter = NULL;
-
-   if(!SysTimer)
-   {
-     EnumEntry = TimerListHead.Flink;
-     while (EnumEntry != &TimerListHead)
-     {
-        MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-        if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
-        {
-           InsertAfter = EnumEntry;
-        }
-        EnumEntry = EnumEntry->Flink;
-     }
-
-     if (InsertAfter)
-     {
-        InsertTailList(InsertAfter, &NewTimer->ListEntry);
-        return FALSE;
-     }
-     //insert as first entry
-     InsertHeadList(&TimerListHead, &NewTimer->ListEntry);
-   }
-   else
-   {
-     EnumEntry = SysTimerListHead.Flink;
-     while (EnumEntry != &SysTimerListHead)
-     {
-        MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-        if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
-        {
-           InsertAfter = EnumEntry;
-        }
-        EnumEntry = EnumEntry->Flink;
-     }
-
-     if (InsertAfter)
-     {
-        InsertTailList(InsertAfter, &NewTimer->ListEntry);
-        return FALSE;
-     }
-     //insert as first entry
-     InsertHeadList(&SysTimerListHead, &NewTimer->ListEntry);
-   }
-
-   return TRUE;
-
-}
-
-//must hold mutex while calling this
-PMSG_TIMER_ENTRY
-FASTCALL
-RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
+BOOL FASTCALL
+IntInsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer, BOOL SysTimer)
 {
-   PMSG_TIMER_ENTRY MsgTimer;
-   PLIST_ENTRY EnumEntry;
-
-   if(!SysTimer)
-   {
-     //remove timer if allready in the queue
-     EnumEntry = TimerListHead.Flink;
-     while (EnumEntry != &TimerListHead)
-     {
-        MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-        EnumEntry = EnumEntry->Flink;
+  PLIST_ENTRY EnumEntry, InsertAfter;
+  PMSG_TIMER_ENTRY MsgTimer;
+  
+  InsertAfter = NULL;
+  
+  if(!SysTimer)
+  {
+    EnumEntry = TimerListHead.Flink;
+    while (EnumEntry != &TimerListHead)
+    {
+      MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+      if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
+      {
+        InsertAfter = EnumEntry;
+      }
+      EnumEntry = EnumEntry->Flink;
+    }
     
-        if (MsgTimer->Msg.hwnd == hWnd && 
-            MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
-            MsgTimer->ThreadID == ThreadID)
-        {
-           RemoveEntryList(&MsgTimer->ListEntry);
-           return MsgTimer;
-        }
-     }
-   }
-   else
-   {
-     //remove timer if allready in the queue
-     EnumEntry = SysTimerListHead.Flink;
-     while (EnumEntry != &SysTimerListHead)
-     {
-        MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-        EnumEntry = EnumEntry->Flink;
+    if (InsertAfter)
+    {
+      InsertTailList(InsertAfter, &NewTimer->ListEntry);
+      return FALSE;
+    }
+    //insert as first entry
+    InsertHeadList(&TimerListHead, &NewTimer->ListEntry);
+  }
+  else
+  {
+    EnumEntry = SysTimerListHead.Flink;
+    while (EnumEntry != &SysTimerListHead)
+    {
+      MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+      if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
+      {
+        InsertAfter = EnumEntry;
+      }
+      EnumEntry = EnumEntry->Flink;
+    }
     
-        if (MsgTimer->Msg.hwnd == hWnd && 
-            MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
-            MsgTimer->ThreadID == ThreadID)
-        {
-           RemoveEntryList(&MsgTimer->ListEntry);
-           return MsgTimer;
-        }
-     }
-   }
-
-   return NULL;
+    if (InsertAfter)
+    {
+      InsertTailList(InsertAfter, &NewTimer->ListEntry);
+      return FALSE;
+    }
+    //insert as first entry
+    InsertHeadList(&SysTimerListHead, &NewTimer->ListEntry);
+  }
+  
+  return TRUE;
 }
 
-
-/* 
- * NOTE: It doesn't kill timers. It just removes them from the list.
- */
-VOID
-FASTCALL
-RemoveTimersThread(HANDLE ThreadID)
+//must hold mutex while calling this
+PMSG_TIMER_ENTRY FASTCALL
+IntRemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
 {
-   PMSG_TIMER_ENTRY MsgTimer;
-   PLIST_ENTRY EnumEntry;
-
-   ExAcquireFastMutex(&Mutex);
-
-   EnumEntry = SysTimerListHead.Flink;
-   while (EnumEntry != &SysTimerListHead)
-   {
+  PMSG_TIMER_ENTRY MsgTimer;
+  PLIST_ENTRY EnumEntry;
+  
+  if(!SysTimer)
+  {
+    //remove timer if already in the queue
+    EnumEntry = TimerListHead.Flink;
+    while (EnumEntry != &TimerListHead)
+    {
       MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
       EnumEntry = EnumEntry->Flink;
-
-      if (MsgTimer->ThreadID == ThreadID)
+      
+      if (MsgTimer->Msg.hwnd == hWnd && 
+          MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
+          MsgTimer->ThreadID == ThreadID)
       {
-         RemoveEntryList(&MsgTimer->ListEntry);
-         ExFreePool(MsgTimer);
+        RemoveEntryList(&MsgTimer->ListEntry);
+        return MsgTimer;
       }
-   }
-
-   EnumEntry = TimerListHead.Flink;
-   while (EnumEntry != &TimerListHead)
-   {
+    }
+  }
+  else
+  {
+    //remove timer if already in the queue
+    EnumEntry = SysTimerListHead.Flink;
+    while (EnumEntry != &SysTimerListHead)
+    {
       MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
       EnumEntry = EnumEntry->Flink;
-
-      if (MsgTimer->ThreadID == ThreadID)
+      
+      if (MsgTimer->Msg.hwnd == hWnd && 
+          MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
+          MsgTimer->ThreadID == ThreadID)
       {
-         if (MsgTimer->Msg.hwnd == NULL)
-         {
-            RtlClearBits(&HandleLessTimersBitMap, ((UINT_PTR)MsgTimer->Msg.wParam) - 1, 1);   
-         }
-
-         RemoveEntryList(&MsgTimer->ListEntry);
-         ExFreePool(MsgTimer);
+        RemoveEntryList(&MsgTimer->ListEntry);
+        return MsgTimer;
       }
-   }
-
-   ExReleaseFastMutex(&Mutex);
-
+    }
+  }
+  
+  return NULL;
 }
 
 
-
-UINT_PTR
-STDCALL
-NtUserSetTimer
-(
- HWND hWnd,
- UINT_PTR nIDEvent,
- UINT uElapse,
- TIMERPROC lpTimerFunc
-)
+/* 
+ * NOTE: It doesn't kill timers. It just removes them from the list.
+ */
+VOID FASTCALL
+RemoveTimersThread(HANDLE ThreadID)
 {
- ULONG Index;
- PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
- PMSG_TIMER_ENTRY NewTimer;
- PLIST_ENTRY EnumEntry;
- LARGE_INTEGER CurrentTime;
- PWINDOW_OBJECT WindowObject;
- HANDLE ThreadID;
-
- ThreadID = PsGetCurrentThreadId();
- KeQuerySystemTime(&CurrentTime);
- ExAcquireFastMutex(&Mutex);
-
- if(hWnd == NULL)
- {
-  /* find a free, handle-less timer id */
-  Index = RtlFindClearBitsAndSet(&HandleLessTimersBitMap, 1, HintIndex);
-
-  if(Index == (ULONG) -1)
-  {
-   ExReleaseFastMutex(&Mutex);
-   return 0;
-  }
-
-  ++ Index;
-  HintIndex = Index;
-  ExReleaseFastMutex(&Mutex);
-  return Index;
- }
- else
- {
-  WindowObject = IntGetWindowObject(hWnd);
-  if(!WindowObject)
-  {
-   ExReleaseFastMutex(&Mutex);
-   SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-   return 0;
-  }
+  PMSG_TIMER_ENTRY MsgTimer;
+  PLIST_ENTRY EnumEntry;
+  
+  ExAcquireFastMutex(&Mutex);
   
-  if(WindowObject->OwnerThread != PsGetCurrentThread())
-  {
-   IntReleaseWindowObject(WindowObject);
-   ExReleaseFastMutex(&Mutex);
-   SetLastWin32Error(ERROR_ACCESS_DENIED);
-   return 0;
-  }
-  IntReleaseWindowObject(WindowObject);
-   
-  /* remove timer if already in the queue */
-  MsgTimer = RemoveTimer(hWnd, nIDEvent, ThreadID, FALSE); 
- }
- #if 1
- /* Win NT/2k/XP */
- if(uElapse > 0x7fffffff)
-   uElapse = 1;
- #else
- /* Win Server 2003 */
- if(uElapse > 0x7fffffff)
-   uElapse = 0x7fffffff;
- #endif
- /* Win 2k/XP */
- if(uElapse < 10)
-   uElapse = 10;
-
- if(MsgTimer)
- {
-  /* modify existing (removed) timer */
-  NewTimer = MsgTimer;
-
-  NewTimer->Period = uElapse;
-  NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
-  NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
- }
- else
- {
-  /* FIXME: use lookaside? */
-  NewTimer = ExAllocatePool(PagedPool, sizeof(MSG_TIMER_ENTRY));
-  if(!NewTimer)
-  {
-    ExReleaseFastMutex(&Mutex);
-    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-    return 0;
-  }
-
-  NewTimer->Msg.hwnd = hWnd;
-  NewTimer->Msg.message = WM_TIMER;
-  NewTimer->Msg.wParam = (WPARAM)nIDEvent;
-  NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
-  NewTimer->Period = uElapse;
-  NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
-  NewTimer->ThreadID = ThreadID;
- }
-
- if(InsertTimerAscendingOrder(NewTimer, FALSE))
- {
   EnumEntry = SysTimerListHead.Flink;
-  if(EnumEntry != &SysTimerListHead)
+  while (EnumEntry != &SysTimerListHead)
   {
-    MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-    if (NewTimer->Timeout.QuadPart <= MsgTimer2->Timeout.QuadPart)
+    MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+    EnumEntry = EnumEntry->Flink;
+    
+    if (MsgTimer->ThreadID == ThreadID)
     {
-      /* new timer is first in queue and expires first */
-      KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+      RemoveEntryList(&MsgTimer->ListEntry);
+      ExFreePool(MsgTimer);
     }
   }
-  else
-  {  
-   /* new timer is first in queue and expires first */
-   KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+  
+  EnumEntry = TimerListHead.Flink;
+  while (EnumEntry != &TimerListHead)
+  {
+    MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+    EnumEntry = EnumEntry->Flink;
+    
+    if (MsgTimer->ThreadID == ThreadID)
+    {
+      if (MsgTimer->Msg.hwnd == NULL)
+      {
+        RtlClearBits(&HandleLessTimersBitMap, ((UINT_PTR)MsgTimer->Msg.wParam) - 1, 1);   
+      }
+      
+      RemoveEntryList(&MsgTimer->ListEntry);
+      ExFreePool(MsgTimer);
+    }
   }
- }
-
- ExReleaseFastMutex(&Mutex);
-
- return 1;
+  
+  ExReleaseFastMutex(&Mutex);
 }
 
-
-BOOL
-STDCALL
-NtUserKillTimer
-(
- HWND hWnd,
- UINT_PTR uIDEvent
-)
+UINT_PTR FASTCALL
+IntSetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc, BOOL SystemTimer)
 {
- PMSG_TIMER_ENTRY MsgTimer;
- PWINDOW_OBJECT WindowObject;
- ExAcquireFastMutex(&Mutex);
-
- /* handle-less timer? */
- if(hWnd == NULL)
- {
-  if(!RtlAreBitsSet(&HandleLessTimersBitMap, uIDEvent - 1, 1))
+  ULONG Index;
+  PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
+  PMSG_TIMER_ENTRY NewTimer;
+  PLIST_ENTRY EnumEntry;
+  LARGE_INTEGER CurrentTime;
+  PWINDOW_OBJECT WindowObject;
+  HANDLE ThreadID;
+  UINT_PTR Ret = 0;
+  
+  ThreadID = PsGetCurrentThreadId();
+  KeQuerySystemTime(&CurrentTime);
+  ExAcquireFastMutex(&Mutex);
+  
+  if((hWnd == NULL) && !SystemTimer)
   {
-   /* bit was not set */
-   /* FIXME: set the last error */
-   ExReleaseFastMutex(&Mutex); 
-   return FALSE;
+    /* find a free, handle-less timer id */
+    Index = RtlFindClearBitsAndSet(&HandleLessTimersBitMap, 1, HintIndex);
+    
+    if(Index == (ULONG) -1)
+    {
+      ExReleaseFastMutex(&Mutex);
+      return 0;
+    }
+    
+    HintIndex = ++Index;
+    ExReleaseFastMutex(&Mutex);
+    return Index;
   }
-
-  RtlClearBits(&HandleLessTimersBitMap, uIDEvent - 1, 1);
- }
- else
- {
-   WindowObject = IntGetWindowObject(hWnd);
-   if(!WindowObject)
-   {
-     ExReleaseFastMutex(&Mutex); 
-     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-     return FALSE;
-   }
-   if(WindowObject->OwnerThread != PsGetCurrentThread())
-   {
-     IntReleaseWindowObject(WindowObject);
-     ExReleaseFastMutex(&Mutex); 
-     SetLastWin32Error(ERROR_ACCESS_DENIED);
-     return FALSE;
-   }
-   IntReleaseWindowObject(WindowObject);
- }
-
- MsgTimer = RemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), FALSE);
-
- ExReleaseFastMutex(&Mutex);
-
- if(MsgTimer == NULL)
- {
-  /* didn't find timer */
-  /* FIXME: set the last error */
-  return FALSE;
- }
-
- /* FIXME: use lookaside? */
- ExFreePool(MsgTimer);
- return TRUE;
-}
-
-UINT_PTR
-STDCALL
-NtUserSetSystemTimer(
- HWND hWnd,
- UINT_PTR nIDEvent,
- UINT uElapse,
- TIMERPROC lpTimerFunc
-)
-{
- /* As opposed to SetTimer() this one seems not to allow window-less timers! */
- PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
- PMSG_TIMER_ENTRY NewTimer;
- PLIST_ENTRY EnumEntry;
- LARGE_INTEGER CurrentTime;
- PWINDOW_OBJECT WindowObject;
- HANDLE ThreadID;
-
- ThreadID = PsGetCurrentThreadId();
- KeQuerySystemTime(&CurrentTime);
- ExAcquireFastMutex(&Mutex);
-
- if(hWnd == NULL)
- {
-   ExReleaseFastMutex(&Mutex);
-   SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-   return 0;
- }
- else
- {
-  WindowObject = IntGetWindowObject(hWnd);
-  if(!WindowObject)
+  else
   {
-   ExReleaseFastMutex(&Mutex);
-   SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-   return 0;
+    WindowObject = IntGetWindowObject(hWnd);
+    if(!WindowObject)
+    {
+      ExReleaseFastMutex(&Mutex);
+      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+      return 0;
+    }
+    
+    if(WindowObject->OwnerThread != PsGetCurrentThread())
+    {
+      IntReleaseWindowObject(WindowObject);
+      ExReleaseFastMutex(&Mutex);
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      return 0;
+    }
+    IntReleaseWindowObject(WindowObject);
+    
+    /* remove timer if already in the queue */
+    MsgTimer = IntRemoveTimer(hWnd, nIDEvent, ThreadID, FALSE); 
   }
   
-  if(WindowObject->OwnerThread != PsGetCurrentThread())
+  #if 1
+  
+  /* Win NT/2k/XP */
+  if(uElapse > 0x7fffffff)
+    uElapse = 1;
+  
+  #else
+  
+  /* Win Server 2003 */
+  if(uElapse > 0x7fffffff)
+    uElapse = 0x7fffffff;
+  
+  #endif
+  
+  /* Win 2k/XP */
+  if(uElapse < 10)
+    uElapse = 10;
+  
+  if(MsgTimer)
   {
-   IntReleaseWindowObject(WindowObject);
-   ExReleaseFastMutex(&Mutex);
-   SetLastWin32Error(ERROR_ACCESS_DENIED);
-   return 0;
+    /* modify existing (removed) timer */
+    NewTimer = MsgTimer;
+    
+    NewTimer->Period = uElapse;
+    NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
+    NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
   }
-  IntReleaseWindowObject(WindowObject);
-   
-  /* remove timer if already in the queue */
-  MsgTimer = RemoveTimer(hWnd, nIDEvent, ThreadID, TRUE); 
- }
- #if 1
- /* Win NT/2k/XP */
- if(uElapse > 0x7fffffff)
-   uElapse = 1;
- #else
- /* Win Server 2003 */
- if(uElapse > 0x7fffffff)
-   uElapse = 0x7fffffff;
- #endif
- /* Win 2k/XP */
- if(uElapse < 10)
-   uElapse = 10;
-
- if(MsgTimer)
- {
-  /* modify existing (removed) timer */
-  NewTimer = MsgTimer;
-
-  NewTimer->Period = uElapse;
-  NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
-  NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
- }
- else
- {
-  /* FIXME: use lookaside? */
-  NewTimer = ExAllocatePool(PagedPool, sizeof(MSG_TIMER_ENTRY));
-  if(!NewTimer)
+  else
   {
-    ExReleaseFastMutex(&Mutex);
-    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-    return 0;
+    /* FIXME: use lookaside? */
+    NewTimer = ExAllocatePool(PagedPool, sizeof(MSG_TIMER_ENTRY));
+    if(!NewTimer)
+    {
+      ExReleaseFastMutex(&Mutex);
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return 0;
+    }
+    
+    NewTimer->Msg.hwnd = hWnd;
+    NewTimer->Msg.message = (SystemTimer ? WM_SYSTIMER : WM_TIMER);
+    NewTimer->Msg.wParam = (WPARAM)nIDEvent;
+    NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
+    NewTimer->Period = uElapse;
+    NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
+    NewTimer->ThreadID = ThreadID;
   }
-
-  NewTimer->Msg.hwnd = hWnd;
-  NewTimer->Msg.message = WM_SYSTIMER;
-  NewTimer->Msg.wParam = (WPARAM)nIDEvent;
-  NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
-  NewTimer->Period = uElapse;
-  NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
-  NewTimer->ThreadID = ThreadID;
- }
-
- if(InsertTimerAscendingOrder(NewTimer, TRUE))
- {
-  EnumEntry = TimerListHead.Flink;
-  if(EnumEntry != &TimerListHead)
+  
+  Ret = nIDEvent; // FIXME - return lpTimerProc if it's not a system timer
+  
+  if(SystemTimer)
   {
-    MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-    if (NewTimer->Timeout.QuadPart <= MsgTimer2->Timeout.QuadPart)
+    if(IntInsertTimerAscendingOrder(NewTimer, TRUE))
     {
-      /* new timer is first in queue and expires first */
-      KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+      EnumEntry = TimerListHead.Flink;
+      if(EnumEntry != &TimerListHead)
+      {
+        MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+        if (NewTimer->Timeout.QuadPart < MsgTimer2->Timeout.QuadPart)
+        {
+          /* new timer is first in queue and expires first */
+          KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+        }
+      }
+      else
+      {
+        /* new timer is first in queue and expires first */
+        KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+      }
     }
   }
   else
-  {  
-   /* new timer is first in queue and expires first */
-   KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+  {
+    if(IntInsertTimerAscendingOrder(NewTimer, FALSE))
+    {
+      EnumEntry = SysTimerListHead.Flink;
+      if(EnumEntry != &SysTimerListHead)
+      {
+        MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+        if (NewTimer->Timeout.QuadPart < MsgTimer2->Timeout.QuadPart)
+        {
+          /* new timer is first in queue and expires first */
+          KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+        }
+      }
+      else
+      {
+        /* new timer is first in queue and expires first */
+        KeSetTimer(&Timer, NewTimer->Timeout, NULL);
+      }
+    }
   }
- }
 
- ExReleaseFastMutex(&Mutex);
 ExReleaseFastMutex(&Mutex);
 
return 1;
 return Ret;
 }
 
-BOOL
-STDCALL
-NtUserKillSystemTimer(
- HWND hWnd,
- UINT_PTR uIDEvent
-)
+BOOL FASTCALL
+IntKillTimer(HWND hWnd, UINT_PTR uIDEvent, BOOL SystemTimer)
 {
- /* As opposed to KillTimer() this one seems not to allow window-less timers! */
- PMSG_TIMER_ENTRY MsgTimer;
- PWINDOW_OBJECT WindowObject;
- WindowObject = IntGetWindowObject(hWnd);
-
- /* handle-less timer? Not allowed for SystemTimers! */
- if(!WindowObject)
- {
-   SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-   return FALSE;
- }
- if(WindowObject->OwnerThread != PsGetCurrentThread())
- {
-   IntReleaseWindowObject(WindowObject);
-   SetLastWin32Error(ERROR_ACCESS_DENIED);
-   return FALSE;
- }
- IntReleaseWindowObject(WindowObject);
- ExAcquireFastMutex(&Mutex);
-
- MsgTimer = RemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), TRUE);
-
- ExReleaseFastMutex(&Mutex);
-
- if(MsgTimer == NULL)
- {
-  /* didn't find timer */
-  /* FIXME: set the last error */
-  return FALSE;
- }
-
- /* FIXME: use lookaside? */
- ExFreePool(MsgTimer);
-
- return TRUE;
+  PMSG_TIMER_ENTRY MsgTimer;
+  PWINDOW_OBJECT WindowObject;
+  
+  ExAcquireFastMutex(&Mutex);
+  
+  /* handle-less timer? */
+  if((hWnd == NULL) && !SystemTimer)
+  {
+    if(!RtlAreBitsSet(&HandleLessTimersBitMap, uIDEvent - 1, 1))
+    {
+      /* bit was not set */
+      /* FIXME: set the last error */
+      ExReleaseFastMutex(&Mutex); 
+      return FALSE;
+    }
+    
+    RtlClearBits(&HandleLessTimersBitMap, uIDEvent - 1, 1);
+  }
+  else
+  {
+    WindowObject = IntGetWindowObject(hWnd);
+    if(!WindowObject)
+    {
+      ExReleaseFastMutex(&Mutex); 
+      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+      return FALSE;
+    }
+    if(WindowObject->OwnerThread != PsGetCurrentThread())
+    {
+      IntReleaseWindowObject(WindowObject);
+      ExReleaseFastMutex(&Mutex); 
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      return FALSE;
+    }
+    IntReleaseWindowObject(WindowObject);
+  }
+  
+  MsgTimer = IntRemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), SystemTimer);
+  
+  ExReleaseFastMutex(&Mutex);
+  
+  if(MsgTimer == NULL)
+  {
+    /* didn't find timer */
+    /* FIXME: set the last error */
+    return FALSE;
+  }
+  
+  /* FIXME: use lookaside? */
+  ExFreePool(MsgTimer);
+  
+  return TRUE;
 }
 
-
 static VOID STDCALL_FUNC
-TimerThreadMain(
-   PVOID StartContext
-   )
+TimerThreadMain(PVOID StartContext)
 {
-   NTSTATUS Status;
-   LARGE_INTEGER CurrentTime;
-   PLIST_ENTRY EnumEntry;
-   PMSG_TIMER_ENTRY MsgTimer, MsgTimer2;
-   PETHREAD Thread;
-
-   for (;;)
-   {
-
-      Status = KeWaitForSingleObject(   &Timer,
-                                        Executive,
-                                        KernelMode,
-                                        FALSE,
-                                        NULL
-                                        );
-      if (!NT_SUCCESS(Status))
+  NTSTATUS Status;
+  LARGE_INTEGER CurrentTime;
+  PLIST_ENTRY EnumEntry;
+  PMSG_TIMER_ENTRY MsgTimer, MsgTimer2;
+  PETHREAD Thread;
+  
+  for(;;)
+  {
+    Status = KeWaitForSingleObject(&Timer,
+                                   Executive,
+                                   KernelMode,
+                                   FALSE,
+                                   NULL);
+    if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Error waiting in TimerThreadMain\n");
+      KEBUGCHECK(0);
+    }
+    
+    ExAcquireFastMutex(&Mutex);
+    
+    KeQuerySystemTime(&CurrentTime);
+    
+    EnumEntry = TimerListHead.Flink;
+    while (EnumEntry != &TimerListHead)
+    {
+      MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+      EnumEntry = EnumEntry->Flink;
+      
+      if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
       {
-         DPRINT1("Error waiting in TimerThreadMain\n");
-         KEBUGCHECK(0);
+        RemoveEntryList(&MsgTimer->ListEntry);
+        
+        /* 
+         * FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
+         */
+        
+        if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer->ThreadID, &Thread)))
+        {
+          ExFreePool(MsgTimer);
+          continue;
+        }
+        
+        if(!MsgTimer->Msg.lParam)
+        {
+          MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer->Msg));
+        }
+        else
+        {
+          /* FIXME - call TIMERPROC */
+        }
+        
+        ObDereferenceObject(Thread);
+        
+        //set up next periodic timeout
+        MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000); 
+        IntInsertTimerAscendingOrder(MsgTimer, FALSE);
       }
-
-      ExAcquireFastMutex(&Mutex);
-      
-      KeQuerySystemTime(&CurrentTime);
+      else
+      {
+        break;
+      }
+    }
+    
+    EnumEntry = SysTimerListHead.Flink;
+    while (EnumEntry != &SysTimerListHead)
+    {
+      MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
+      EnumEntry = EnumEntry->Flink;
       
-      EnumEntry = SysTimerListHead.Flink;
-      while (EnumEntry != &SysTimerListHead)
+      if (CurrentTime.QuadPart >= MsgTimer2->Timeout.QuadPart)
       {
-         MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-         EnumEntry = EnumEntry->Flink;
-
-         if (CurrentTime.QuadPart >= MsgTimer2->Timeout.QuadPart)
-         {
-            RemoveEntryList(&MsgTimer2->ListEntry);
-
-            /* 
-             * FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
-             */
-
-            if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer2->ThreadID, &Thread)))
-            {
-               ExFreePool(MsgTimer2);
-               continue;
-            }
-            
-            MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer2->Msg));
-
-            ObDereferenceObject(Thread);
-
-            //set up next periodic timeout
-            MsgTimer2->Timeout.QuadPart += (MsgTimer2->Period * 10000); 
-            InsertTimerAscendingOrder(MsgTimer2, TRUE);
-
-         }                          
-         else                       
-         {
-            break;
-         }
+        RemoveEntryList(&MsgTimer2->ListEntry);
+        
+        /* 
+         * FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
+         */
+        
+        if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer2->ThreadID, &Thread)))
+        {
+          ExFreePool(MsgTimer2);
+          continue;
+        }
+        
+        MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer2->Msg));
+        
+        ObDereferenceObject(Thread);
+        
+        //set up next periodic timeout
+        MsgTimer2->Timeout.QuadPart += (MsgTimer2->Period * 10000); 
+        IntInsertTimerAscendingOrder(MsgTimer2, TRUE);
       }
-
-      EnumEntry = TimerListHead.Flink;
-      while (EnumEntry != &TimerListHead)
+      else
       {
-         MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
-         EnumEntry = EnumEntry->Flink;
-
-         if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
-         {
-            RemoveEntryList(&MsgTimer->ListEntry);
-
-            /* 
-             * FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
-             */
-
-            if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer->ThreadID, &Thread)))
-            {
-               ExFreePool(MsgTimer);
-               continue;
-            }
-            
-            MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer->Msg));
-
-            ObDereferenceObject(Thread);
-
-            //set up next periodic timeout
-            MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000); 
-            InsertTimerAscendingOrder(MsgTimer, FALSE);
-
-         }                          
-         else                       
-         {
-            break;
-         }
+        break;
+      }
+    }
+    
+    //set up next timeout from first entry (if any)
+    if (!IsListEmpty(&TimerListHead))
+    {
+      MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
+      if(!IsListEmpty(&SysTimerListHead))
+      {         
+        MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
+        if(MsgTimer->Timeout.QuadPart <= MsgTimer2->Timeout.QuadPart)
+          KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
+        else
+          KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
       }
-   
-      //set up next timeout from first entry (if any)
-      if (!IsListEmpty(&TimerListHead))
+      else
+      {
+        KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
+      }
+    }
+    else
+    {
+      if(!IsListEmpty(&SysTimerListHead))
       {
-         MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
-         if(!IsListEmpty(&SysTimerListHead))
-         {         
-           MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
-           if(MsgTimer->Timeout.QuadPart >= MsgTimer2->Timeout.QuadPart)
-             KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
-           else
-             KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
-         }
-         else
-         {
-           KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
-         }
+        MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
+        KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
       }
       else
       {
-         if(!IsListEmpty(&SysTimerListHead))
-         {
-           MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
-           KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
-         }
-         else
-         {
-           /* Reinitialize the timer, this reset the state of the timer event on which we wait */
-           KeInitializeTimer(&Timer);
-         }
+        /* Reinitialize the timer, this reset the state of the timer event on which we wait */
+        KeInitializeTimer(&Timer);
       }
+    }
+    
+    ExReleaseFastMutex(&Mutex);
+  }
+}
 
-      ExReleaseFastMutex(&Mutex);
+NTSTATUS FASTCALL
+InitTimerImpl(VOID)
+{
+  NTSTATUS Status;
+  ULONG BitmapBytes;
+  
+  BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
+  
+  InitializeListHead(&TimerListHead);
+  InitializeListHead(&SysTimerListHead);
+  KeInitializeTimer(&Timer);
+  ExInitializeFastMutex(&Mutex);
+  
+  HandleLessTimersBitMapBuffer = ExAllocatePool(PagedPool, BitmapBytes);
+  RtlInitializeBitMap(&HandleLessTimersBitMap,
+                      HandleLessTimersBitMapBuffer,
+                      BitmapBytes * 8);
+  
+  //yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory
+  RtlClearAllBits(&HandleLessTimersBitMap); 
+  
+  Status = PsCreateSystemThread(&MsgTimerThreadHandle,
+                                THREAD_ALL_ACCESS,
+                                NULL,
+                                NULL,
+                                &MsgTimerThreadId,
+                                TimerThreadMain,
+                                NULL);
+  return Status;
+}
 
-   }
 
+UINT_PTR
+STDCALL
+NtUserSetTimer
+(
+ HWND hWnd,
+ UINT_PTR nIDEvent,
+ UINT uElapse,
+ TIMERPROC lpTimerFunc
+)
+{
+  return IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE);
 }
 
 
-
-NTSTATUS FASTCALL
-InitTimerImpl(VOID)
+BOOL
+STDCALL
+NtUserKillTimer
+(
+ HWND hWnd,
+ UINT_PTR uIDEvent
+)
 {
-   NTSTATUS Status;
-   ULONG BitmapBytes;
-
-   BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
+  return IntKillTimer(hWnd, uIDEvent, FALSE);
+}
 
-   InitializeListHead(&TimerListHead);
-   InitializeListHead(&SysTimerListHead);
-   KeInitializeTimer(&Timer);
-   ExInitializeFastMutex(&Mutex);
 
-   HandleLessTimersBitMapBuffer = ExAllocatePool(PagedPool, BitmapBytes);
-   RtlInitializeBitMap(&HandleLessTimersBitMap,
-                       HandleLessTimersBitMapBuffer,
-                       BitmapBytes * 8);
+UINT_PTR
+STDCALL
+NtUserSetSystemTimer(
+ HWND hWnd,
+ UINT_PTR nIDEvent,
+ UINT uElapse,
+ TIMERPROC lpTimerFunc
+)
+{
+  return IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE);
+}
 
-   //yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory
-   RtlClearAllBits(&HandleLessTimersBitMap); 
 
-   Status = PsCreateSystemThread(&MsgTimerThreadHandle,
-                                 THREAD_ALL_ACCESS,
-                                 NULL,
                                NULL,
-                                 &MsgTimerThreadId,
-                                 TimerThreadMain,
-                                 NULL);
-   return Status;
+BOOL
+STDCALL
+NtUserKillSystemTimer(
HWND hWnd,
+ UINT_PTR uIDEvent
+)
+{
+  return IntKillTimer(hWnd, uIDEvent, TRUE);
 }
 
 /* EOF */