implements system timers (similar to standard timers)

svn path=/trunk/; revision=6240
This commit is contained in:
Thomas Bluemel 2003-10-04 22:36:37 +00:00
parent 996d541acf
commit 93e9630e67
9 changed files with 465 additions and 121 deletions

View file

@ -428,6 +428,7 @@ NtUserInternalGetWindowText 3
NtUserInvalidateRect 3 NtUserInvalidateRect 3
NtUserInvalidateRgn 3 NtUserInvalidateRgn 3
NtUserIsClipboardFormatAvailable 1 NtUserIsClipboardFormatAvailable 1
NtUserKillSystemTimer 2
NtUserKillTimer 2 NtUserKillTimer 2
NtUserLoadKeyboardLayoutEx 6 NtUserLoadKeyboardLayoutEx 6
NtUserLockWindowStation 1 NtUserLockWindowStation 1

View file

@ -4713,11 +4713,11 @@ SetWindowStationUser(
UINT UINT
STDCALL STDCALL
SetSystemTimer( SetSystemTimer(
HWND hwnd, HWND hWnd,
UINT id, UINT_PTR IDEvent,
UINT timeout, UINT Period,
TIMERPROC proc TIMERPROC TimerFunc
); );
WINBOOL WINBOOL
STDCALL STDCALL
@ -4777,9 +4777,9 @@ RegisterLogonProcess(
WINBOOL WINBOOL
STDCALL STDCALL
KillSystemTimer( KillSystemTimer(
HWND hwnd, HWND hWnd,
UINT id UINT_PTR IDEvent
); );
DWORD DWORD
STDCALL STDCALL

View file

@ -1105,6 +1105,7 @@ extern "C" {
#define WM_TCARD (82) #define WM_TCARD (82)
#define WM_TIMECHANGE (30) #define WM_TIMECHANGE (30)
#define WM_TIMER (275) #define WM_TIMER (275)
#define WM_SYSTIMER (280)
#define WM_UNDO (772) #define WM_UNDO (772)
#define WM_USER (1024) #define WM_USER (1024)
#define WM_USERCHANGED (84) #define WM_USERCHANGED (84)

View file

@ -959,6 +959,14 @@ STDCALL
NtUserIsClipboardFormatAvailable( NtUserIsClipboardFormatAvailable(
DWORD Unknown0); DWORD Unknown0);
BOOL
STDCALL
NtUserKillSystemTimer
(
HWND hWnd,
UINT_PTR uIDEvent
);
BOOL BOOL
STDCALL STDCALL
NtUserKillTimer NtUserKillTimer
@ -1485,14 +1493,6 @@ NtUserSetSystemMenu(
HWND hWnd, HWND hWnd,
HMENU hMenu); HMENU hMenu);
DWORD
STDCALL
NtUserSetSystemTimer(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3);
BOOL BOOL
STDCALL STDCALL
NtUserSetThreadDesktop( NtUserSetThreadDesktop(
@ -1504,6 +1504,16 @@ NtUserSetThreadState(
DWORD Unknown0, DWORD Unknown0,
DWORD Unknown1); DWORD Unknown1);
UINT_PTR
STDCALL
NtUserSetSystemTimer
(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);
UINT_PTR UINT_PTR
STDCALL STDCALL
NtUserSetTimer NtUserSetTimer

View file

@ -1,4 +1,4 @@
/* $Id: listbox.c,v 1.11 2003/09/27 00:29:52 weiden Exp $ /* $Id: listbox.c,v 1.12 2003/10/04 22:36:36 weiden Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS User32 * PROJECT: ReactOS User32
@ -74,12 +74,6 @@ BOOL is_old_app(HWND hwnd)
#define WM_LBTRACKPOINT 0x0131 #define WM_LBTRACKPOINT 0x0131
#define WS_EX_DRAGDETECT 0x00000002L #define WS_EX_DRAGDETECT 0x00000002L
#define WM_BEGINDRAG 0x022C #define WM_BEGINDRAG 0x022C
//#define WM_MOUSEWHEEL 0x020A
//#define WHEEL_DELTA 120
#define WM_SYSTIMER WM_TIMER
#define SetSystemTimer SetTimer
#define KillSystemTimer KillTimer
/* End of hack section -------------------------------- */ /* End of hack section -------------------------------- */

View file

@ -1,4 +1,4 @@
/* $Id: stubs.c,v 1.43 2003/09/12 17:51:48 vizzini Exp $ /* $Id: stubs.c,v 1.44 2003/10/04 22:36:36 weiden Exp $
* *
* COPYRIGHT: See COPYING WINBOOLthe top level directory * COPYRIGHT: See COPYING WINBOOLthe top level directory
* PROJECT: ReactOS user32.dll * PROJECT: ReactOS user32.dll
@ -869,22 +869,6 @@ SetWindowStationUser ( DWORD x1, DWORD x2 )
return FALSE; return FALSE;
} }
/*
* @unimplemented
*/
UINT
STDCALL
SetSystemTimer(
HWND hwnd,
UINT id,
UINT timeout,
TIMERPROC proc
)
{
UNIMPLEMENTED;
return FALSE;
}
/* /*
* @unimplemented * @unimplemented
*/ */
@ -978,17 +962,6 @@ RegisterLogonProcess ( HANDLE hprocess, BOOL x )
return FALSE; return FALSE;
} }
/*
* @unimplemented
*/
WINBOOL
STDCALL
KillSystemTimer ( HWND hwnd, UINT id )
{
UNIMPLEMENTED;
return FALSE;
}
/* /*
* @unimplemented * @unimplemented
*/ */

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: timer.c,v 1.8 2003/07/10 21:04:31 chorns Exp $ /* $Id: timer.c,v 1.9 2003/10/04 22:36:36 weiden Exp $
* *
* PROJECT: ReactOS user32.dll * PROJECT: ReactOS user32.dll
* FILE: lib/user32/misc/dde.c * FILE: lib/user32/misc/dde.c
@ -35,6 +35,20 @@
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
WINBOOL
STDCALL
KillSystemTimer(
HWND hWnd,
UINT_PTR IDEvent)
{
return NtUserKillSystemTimer(hWnd, IDEvent);
}
/* /*
* @implemented * @implemented
*/ */
@ -44,7 +58,22 @@ KillTimer(
HWND hWnd, HWND hWnd,
UINT_PTR IDEvent) UINT_PTR IDEvent)
{ {
return NtUserKillTimer(hWnd, IDEvent); return NtUserKillTimer(hWnd, IDEvent);
}
/*
* @implemented
*/
UINT_PTR
STDCALL
SetSystemTimer(
HWND hWnd,
UINT_PTR IDEvent,
UINT Period,
TIMERPROC TimerFunc)
{
return NtUserSetSystemTimer(hWnd, IDEvent, Period, TimerFunc);
} }
@ -59,6 +88,6 @@ SetTimer(
UINT Period, UINT Period,
TIMERPROC TimerFunc) TIMERPROC TimerFunc)
{ {
return NtUserSetTimer(hWnd, IDEvent, Period, TimerFunc); return NtUserSetTimer(hWnd, IDEvent, Period, TimerFunc);
} }

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: timer.c,v 1.10 2003/08/13 20:24:05 chorns Exp $ /* $Id: timer.c,v 1.11 2003/10/04 22:36:37 weiden Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -35,6 +35,8 @@
#include <internal/ntoskrnl.h> #include <internal/ntoskrnl.h>
#include <internal/ps.h> #include <internal/ps.h>
#include <include/msgqueue.h> #include <include/msgqueue.h>
#include <include/window.h>
#include <include/error.h>
#include <messages.h> #include <messages.h>
#include <napi/win32.h> #include <napi/win32.h>
@ -48,6 +50,7 @@
static FAST_MUTEX Mutex; static FAST_MUTEX Mutex;
static LIST_ENTRY TimerListHead; static LIST_ENTRY TimerListHead;
static LIST_ENTRY SysTimerListHead;
static KTIMER Timer; static KTIMER Timer;
static RTL_BITMAP HandleLessTimersBitMap; static RTL_BITMAP HandleLessTimersBitMap;
static PVOID HandleLessTimersBitMapBuffer; static PVOID HandleLessTimersBitMapBuffer;
@ -72,32 +75,56 @@ typedef struct _MSG_TIMER_ENTRY{
//must hold mutex while calling this //must hold mutex while calling this
BOOL BOOL
FASTCALL FASTCALL
InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer) InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer, BOOL SysTimer)
{ {
PLIST_ENTRY EnumEntry, InsertAfter; PLIST_ENTRY EnumEntry, InsertAfter;
PMSG_TIMER_ENTRY MsgTimer; PMSG_TIMER_ENTRY MsgTimer;
InsertAfter = NULL; InsertAfter = NULL;
EnumEntry = TimerListHead.Flink; if(!SysTimer)
while (EnumEntry != &TimerListHead)
{ {
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry); EnumEntry = TimerListHead.Flink;
if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart) while (EnumEntry != &TimerListHead)
{ {
InsertAfter = EnumEntry; MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
} if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
EnumEntry = EnumEntry->Flink; {
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);
} }
if (InsertAfter)
{
InsertTailList(InsertAfter, &NewTimer->ListEntry);
return FALSE;
}
//insert as first entry
InsertHeadList(&TimerListHead, &NewTimer->ListEntry);
return TRUE; return TRUE;
} }
@ -105,25 +132,46 @@ InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer)
//must hold mutex while calling this //must hold mutex while calling this
PMSG_TIMER_ENTRY PMSG_TIMER_ENTRY
FASTCALL FASTCALL
RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID) RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
{ {
PMSG_TIMER_ENTRY MsgTimer; PMSG_TIMER_ENTRY MsgTimer;
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
//remove timer if allready in the queue if(!SysTimer)
EnumEntry = TimerListHead.Flink;
while (EnumEntry != &TimerListHead)
{ {
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry); //remove timer if allready in the queue
EnumEntry = EnumEntry->Flink; EnumEntry = TimerListHead.Flink;
while (EnumEntry != &TimerListHead)
{
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
EnumEntry = EnumEntry->Flink;
if (MsgTimer->Msg.hwnd == hWnd && if (MsgTimer->Msg.hwnd == hWnd &&
MsgTimer->Msg.wParam == (WPARAM)IDEvent && MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
MsgTimer->ThreadID == ThreadID) MsgTimer->ThreadID == ThreadID)
{ {
RemoveEntryList(&MsgTimer->ListEntry); RemoveEntryList(&MsgTimer->ListEntry);
return MsgTimer; 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 (MsgTimer->Msg.hwnd == hWnd &&
MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
MsgTimer->ThreadID == ThreadID)
{
RemoveEntryList(&MsgTimer->ListEntry);
return MsgTimer;
}
}
} }
return NULL; return NULL;
@ -142,6 +190,19 @@ RemoveTimersThread(HANDLE ThreadID)
ExAcquireFastMutex(&Mutex); ExAcquireFastMutex(&Mutex);
EnumEntry = SysTimerListHead.Flink;
while (EnumEntry != &SysTimerListHead)
{
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
EnumEntry = EnumEntry->Flink;
if (MsgTimer->ThreadID == ThreadID)
{
RemoveEntryList(&MsgTimer->ListEntry);
ExFreePool(MsgTimer);
}
}
EnumEntry = TimerListHead.Flink; EnumEntry = TimerListHead.Flink;
while (EnumEntry != &TimerListHead) while (EnumEntry != &TimerListHead)
{ {
@ -177,19 +238,13 @@ NtUserSetTimer
) )
{ {
ULONG Index; ULONG Index;
PMSG_TIMER_ENTRY MsgTimer = NULL; PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
PMSG_TIMER_ENTRY NewTimer; PMSG_TIMER_ENTRY NewTimer;
PLIST_ENTRY EnumEntry;
LARGE_INTEGER CurrentTime; LARGE_INTEGER CurrentTime;
PWINDOW_OBJECT WindowObject;
HANDLE ThreadID; HANDLE ThreadID;
//FIXME: WINE: window must be owned by the calling thread
#if 0
if(hWnd && !(hWnd = WIN_IsCurrentThread(hWnd))
{
return STATUS_UNSUCCESSFUL;
}
#endif
ThreadID = PsGetCurrentThreadId(); ThreadID = PsGetCurrentThreadId();
KeQuerySystemTime(&CurrentTime); KeQuerySystemTime(&CurrentTime);
ExAcquireFastMutex(&Mutex); ExAcquireFastMutex(&Mutex);
@ -201,7 +256,6 @@ NtUserSetTimer
if(Index == (ULONG) -1) if(Index == (ULONG) -1)
{ {
/* FIXME: set the last error */
ExReleaseFastMutex(&Mutex); ExReleaseFastMutex(&Mutex);
return 0; return 0;
} }
@ -213,10 +267,45 @@ NtUserSetTimer
} }
else else
{ {
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 */ /* remove timer if already in the queue */
MsgTimer = RemoveTimer(hWnd, nIDEvent, ThreadID); 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) if(MsgTimer)
{ {
/* modify existing (removed) timer */ /* modify existing (removed) timer */
@ -230,6 +319,12 @@ NtUserSetTimer
{ {
/* FIXME: use lookaside? */ /* FIXME: use lookaside? */
NewTimer = ExAllocatePool(PagedPool, sizeof(MSG_TIMER_ENTRY)); NewTimer = ExAllocatePool(PagedPool, sizeof(MSG_TIMER_ENTRY));
if(!NewTimer)
{
ExReleaseFastMutex(&Mutex);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
NewTimer->Msg.hwnd = hWnd; NewTimer->Msg.hwnd = hWnd;
NewTimer->Msg.message = WM_TIMER; NewTimer->Msg.message = WM_TIMER;
@ -240,10 +335,23 @@ NtUserSetTimer
NewTimer->ThreadID = ThreadID; NewTimer->ThreadID = ThreadID;
} }
if(InsertTimerAscendingOrder(NewTimer)) if(InsertTimerAscendingOrder(NewTimer, FALSE))
{ {
/* new timer is first in queue and expires first */ EnumEntry = SysTimerListHead.Flink;
KeSetTimer(&Timer, NewTimer->Timeout, NULL); 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);
@ -261,6 +369,7 @@ NtUserKillTimer
) )
{ {
PMSG_TIMER_ENTRY MsgTimer; PMSG_TIMER_ENTRY MsgTimer;
PWINDOW_OBJECT WindowObject;
ExAcquireFastMutex(&Mutex); ExAcquireFastMutex(&Mutex);
@ -277,8 +386,26 @@ NtUserKillTimer
RtlClearBits(&HandleLessTimersBitMap, uIDEvent - 1, 1); 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()); MsgTimer = RemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), FALSE);
ExReleaseFastMutex(&Mutex); ExReleaseFastMutex(&Mutex);
@ -295,17 +422,171 @@ NtUserKillTimer
return TRUE; return TRUE;
} }
DWORD UINT_PTR
STDCALL STDCALL
NtUserSetSystemTimer( NtUserSetSystemTimer(
DWORD Unknown0, HWND hWnd,
DWORD Unknown1, UINT_PTR nIDEvent,
DWORD Unknown2, UINT uElapse,
DWORD Unknown3) TIMERPROC lpTimerFunc
)
{ {
UNIMPLEMENTED /* 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;
return 0; ThreadID = PsGetCurrentThreadId();
KeQuerySystemTime(&CurrentTime);
ExAcquireFastMutex(&Mutex);
if(hWnd == NULL)
{
ExReleaseFastMutex(&Mutex);
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return 0;
}
else
{
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 = 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)
{
ExReleaseFastMutex(&Mutex);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
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)
{
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);
return 1;
}
BOOL
STDCALL
NtUserKillSystemTimer(
HWND hWnd,
UINT_PTR uIDEvent
)
{
/* 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;
} }
@ -317,7 +598,7 @@ TimerThreadMain(
NTSTATUS Status; NTSTATUS Status;
LARGE_INTEGER CurrentTime; LARGE_INTEGER CurrentTime;
PLIST_ENTRY EnumEntry; PLIST_ENTRY EnumEntry;
PMSG_TIMER_ENTRY MsgTimer; PMSG_TIMER_ENTRY MsgTimer, MsgTimer2;
PETHREAD Thread; PETHREAD Thread;
for (;;) for (;;)
@ -339,6 +620,41 @@ TimerThreadMain(
KeQuerySystemTime(&CurrentTime); KeQuerySystemTime(&CurrentTime);
EnumEntry = SysTimerListHead.Flink;
while (EnumEntry != &SysTimerListHead)
{
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;
}
}
EnumEntry = TimerListHead.Flink; EnumEntry = TimerListHead.Flink;
while (EnumEntry != &TimerListHead) while (EnumEntry != &TimerListHead)
{ {
@ -365,7 +681,7 @@ TimerThreadMain(
//set up next periodic timeout //set up next periodic timeout
MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000); MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000);
InsertTimerAscendingOrder(MsgTimer); InsertTimerAscendingOrder(MsgTimer, FALSE);
} }
else else
@ -378,12 +694,31 @@ TimerThreadMain(
if (!IsListEmpty(&TimerListHead)) if (!IsListEmpty(&TimerListHead))
{ {
MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry); MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
KeSetTimer(&Timer, MsgTimer->Timeout, NULL); 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);
}
} }
else else
{ {
/* Reinitialize the timer, this reset the state of the timer event on which we wait */ if(!IsListEmpty(&SysTimerListHead))
KeInitializeTimer(&Timer); {
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);
}
} }
ExReleaseFastMutex(&Mutex); ExReleaseFastMutex(&Mutex);
@ -403,6 +738,7 @@ InitTimerImpl(VOID)
BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8; BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
InitializeListHead(&TimerListHead); InitializeListHead(&TimerListHead);
InitializeListHead(&SysTimerListHead);
KeInitializeTimer(&Timer); KeInitializeTimer(&Timer);
ExInitializeFastMutex(&Mutex); ExInitializeFastMutex(&Mutex);

View file

@ -340,7 +340,7 @@ NtUserGetClipCursor(
{ {
DPRINT("Validation of window station handle (0x%X) failed\n", DPRINT("Validation of window station handle (0x%X) failed\n",
PROCESS_WINDOW_STATION()); PROCESS_WINDOW_STATION());
SetLastWin32Error(Status); SetLastNtError(Status);
return FALSE; return FALSE;
} }