mirror of
https://github.com/reactos/reactos.git
synced 2024-12-26 17:14:41 +00:00
implements system timers (similar to standard timers)
svn path=/trunk/; revision=6240
This commit is contained in:
parent
996d541acf
commit
93e9630e67
9 changed files with 465 additions and 121 deletions
|
@ -428,6 +428,7 @@ NtUserInternalGetWindowText 3
|
|||
NtUserInvalidateRect 3
|
||||
NtUserInvalidateRgn 3
|
||||
NtUserIsClipboardFormatAvailable 1
|
||||
NtUserKillSystemTimer 2
|
||||
NtUserKillTimer 2
|
||||
NtUserLoadKeyboardLayoutEx 6
|
||||
NtUserLockWindowStation 1
|
||||
|
|
|
@ -4713,11 +4713,11 @@ SetWindowStationUser(
|
|||
UINT
|
||||
STDCALL
|
||||
SetSystemTimer(
|
||||
HWND hwnd,
|
||||
UINT id,
|
||||
UINT timeout,
|
||||
TIMERPROC proc
|
||||
);
|
||||
HWND hWnd,
|
||||
UINT_PTR IDEvent,
|
||||
UINT Period,
|
||||
TIMERPROC TimerFunc
|
||||
);
|
||||
|
||||
WINBOOL
|
||||
STDCALL
|
||||
|
@ -4777,9 +4777,9 @@ RegisterLogonProcess(
|
|||
WINBOOL
|
||||
STDCALL
|
||||
KillSystemTimer(
|
||||
HWND hwnd,
|
||||
UINT id
|
||||
);
|
||||
HWND hWnd,
|
||||
UINT_PTR IDEvent
|
||||
);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
|
|
|
@ -1105,6 +1105,7 @@ extern "C" {
|
|||
#define WM_TCARD (82)
|
||||
#define WM_TIMECHANGE (30)
|
||||
#define WM_TIMER (275)
|
||||
#define WM_SYSTIMER (280)
|
||||
#define WM_UNDO (772)
|
||||
#define WM_USER (1024)
|
||||
#define WM_USERCHANGED (84)
|
||||
|
|
|
@ -959,6 +959,14 @@ STDCALL
|
|||
NtUserIsClipboardFormatAvailable(
|
||||
DWORD Unknown0);
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserKillSystemTimer
|
||||
(
|
||||
HWND hWnd,
|
||||
UINT_PTR uIDEvent
|
||||
);
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserKillTimer
|
||||
|
@ -1485,14 +1493,6 @@ NtUserSetSystemMenu(
|
|||
HWND hWnd,
|
||||
HMENU hMenu);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserSetSystemTimer(
|
||||
DWORD Unknown0,
|
||||
DWORD Unknown1,
|
||||
DWORD Unknown2,
|
||||
DWORD Unknown3);
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserSetThreadDesktop(
|
||||
|
@ -1504,6 +1504,16 @@ NtUserSetThreadState(
|
|||
DWORD Unknown0,
|
||||
DWORD Unknown1);
|
||||
|
||||
UINT_PTR
|
||||
STDCALL
|
||||
NtUserSetSystemTimer
|
||||
(
|
||||
HWND hWnd,
|
||||
UINT_PTR nIDEvent,
|
||||
UINT uElapse,
|
||||
TIMERPROC lpTimerFunc
|
||||
);
|
||||
|
||||
UINT_PTR
|
||||
STDCALL
|
||||
NtUserSetTimer
|
||||
|
|
|
@ -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
|
||||
* PROJECT: ReactOS User32
|
||||
|
@ -74,12 +74,6 @@ BOOL is_old_app(HWND hwnd)
|
|||
#define WM_LBTRACKPOINT 0x0131
|
||||
#define WS_EX_DRAGDETECT 0x00000002L
|
||||
#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 -------------------------------- */
|
||||
|
||||
|
|
|
@ -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
|
||||
* PROJECT: ReactOS user32.dll
|
||||
|
@ -869,22 +869,6 @@ SetWindowStationUser ( DWORD x1, DWORD x2 )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
UINT
|
||||
STDCALL
|
||||
SetSystemTimer(
|
||||
HWND hwnd,
|
||||
UINT id,
|
||||
UINT timeout,
|
||||
TIMERPROC proc
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
|
@ -978,17 +962,6 @@ RegisterLogonProcess ( HANDLE hprocess, BOOL x )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
WINBOOL
|
||||
STDCALL
|
||||
KillSystemTimer ( HWND hwnd, UINT id )
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* 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.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
|
||||
* FILE: lib/user32/misc/dde.c
|
||||
|
@ -35,6 +35,20 @@
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
WINBOOL
|
||||
STDCALL
|
||||
KillSystemTimer(
|
||||
HWND hWnd,
|
||||
UINT_PTR IDEvent)
|
||||
{
|
||||
return NtUserKillSystemTimer(hWnd, IDEvent);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
@ -44,7 +58,22 @@ KillTimer(
|
|||
HWND hWnd,
|
||||
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,
|
||||
TIMERPROC TimerFunc)
|
||||
{
|
||||
return NtUserSetTimer(hWnd, IDEvent, Period, TimerFunc);
|
||||
return NtUserSetTimer(hWnd, IDEvent, Period, TimerFunc);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* 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.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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -35,6 +35,8 @@
|
|||
#include <internal/ntoskrnl.h>
|
||||
#include <internal/ps.h>
|
||||
#include <include/msgqueue.h>
|
||||
#include <include/window.h>
|
||||
#include <include/error.h>
|
||||
#include <messages.h>
|
||||
#include <napi/win32.h>
|
||||
|
||||
|
@ -48,6 +50,7 @@
|
|||
|
||||
static FAST_MUTEX Mutex;
|
||||
static LIST_ENTRY TimerListHead;
|
||||
static LIST_ENTRY SysTimerListHead;
|
||||
static KTIMER Timer;
|
||||
static RTL_BITMAP HandleLessTimersBitMap;
|
||||
static PVOID HandleLessTimersBitMapBuffer;
|
||||
|
@ -72,32 +75,56 @@ typedef struct _MSG_TIMER_ENTRY{
|
|||
//must hold mutex while calling this
|
||||
BOOL
|
||||
FASTCALL
|
||||
InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer)
|
||||
InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer, BOOL SysTimer)
|
||||
{
|
||||
PLIST_ENTRY EnumEntry, InsertAfter;
|
||||
PMSG_TIMER_ENTRY MsgTimer;
|
||||
|
||||
InsertAfter = NULL;
|
||||
|
||||
EnumEntry = TimerListHead.Flink;
|
||||
while (EnumEntry != &TimerListHead)
|
||||
if(!SysTimer)
|
||||
{
|
||||
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
||||
if (NewTimer->Timeout.QuadPart > MsgTimer->Timeout.QuadPart)
|
||||
{
|
||||
InsertAfter = EnumEntry;
|
||||
}
|
||||
EnumEntry = EnumEntry->Flink;
|
||||
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);
|
||||
}
|
||||
|
||||
if (InsertAfter)
|
||||
{
|
||||
InsertTailList(InsertAfter, &NewTimer->ListEntry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//insert as first entry
|
||||
InsertHeadList(&TimerListHead, &NewTimer->ListEntry);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
@ -105,25 +132,46 @@ InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer)
|
|||
//must hold mutex while calling this
|
||||
PMSG_TIMER_ENTRY
|
||||
FASTCALL
|
||||
RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID)
|
||||
RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
|
||||
{
|
||||
PMSG_TIMER_ENTRY MsgTimer;
|
||||
PLIST_ENTRY EnumEntry;
|
||||
|
||||
//remove timer if allready in the queue
|
||||
EnumEntry = TimerListHead.Flink;
|
||||
while (EnumEntry != &TimerListHead)
|
||||
if(!SysTimer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
//remove timer if allready in the queue
|
||||
EnumEntry = TimerListHead.Flink;
|
||||
while (EnumEntry != &TimerListHead)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -142,6 +190,19 @@ RemoveTimersThread(HANDLE ThreadID)
|
|||
|
||||
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;
|
||||
while (EnumEntry != &TimerListHead)
|
||||
{
|
||||
|
@ -177,19 +238,13 @@ NtUserSetTimer
|
|||
)
|
||||
{
|
||||
ULONG Index;
|
||||
PMSG_TIMER_ENTRY MsgTimer = NULL;
|
||||
PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
|
||||
PMSG_TIMER_ENTRY NewTimer;
|
||||
PLIST_ENTRY EnumEntry;
|
||||
LARGE_INTEGER CurrentTime;
|
||||
PWINDOW_OBJECT WindowObject;
|
||||
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();
|
||||
KeQuerySystemTime(&CurrentTime);
|
||||
ExAcquireFastMutex(&Mutex);
|
||||
|
@ -201,7 +256,6 @@ NtUserSetTimer
|
|||
|
||||
if(Index == (ULONG) -1)
|
||||
{
|
||||
/* FIXME: set the last error */
|
||||
ExReleaseFastMutex(&Mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -213,9 +267,44 @@ NtUserSetTimer
|
|||
}
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
@ -230,6 +319,12 @@ NtUserSetTimer
|
|||
{
|
||||
/* 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;
|
||||
|
@ -240,10 +335,23 @@ NtUserSetTimer
|
|||
NewTimer->ThreadID = ThreadID;
|
||||
}
|
||||
|
||||
if(InsertTimerAscendingOrder(NewTimer))
|
||||
if(InsertTimerAscendingOrder(NewTimer, FALSE))
|
||||
{
|
||||
/* new timer is first in queue and expires first */
|
||||
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
||||
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);
|
||||
|
@ -261,6 +369,7 @@ NtUserKillTimer
|
|||
)
|
||||
{
|
||||
PMSG_TIMER_ENTRY MsgTimer;
|
||||
PWINDOW_OBJECT WindowObject;
|
||||
|
||||
ExAcquireFastMutex(&Mutex);
|
||||
|
||||
|
@ -277,8 +386,193 @@ NtUserKillTimer
|
|||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -295,19 +589,6 @@ NtUserKillTimer
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserSetSystemTimer(
|
||||
DWORD Unknown0,
|
||||
DWORD Unknown1,
|
||||
DWORD Unknown2,
|
||||
DWORD Unknown3)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static VOID STDCALL_FUNC
|
||||
TimerThreadMain(
|
||||
|
@ -317,7 +598,7 @@ TimerThreadMain(
|
|||
NTSTATUS Status;
|
||||
LARGE_INTEGER CurrentTime;
|
||||
PLIST_ENTRY EnumEntry;
|
||||
PMSG_TIMER_ENTRY MsgTimer;
|
||||
PMSG_TIMER_ENTRY MsgTimer, MsgTimer2;
|
||||
PETHREAD Thread;
|
||||
|
||||
for (;;)
|
||||
|
@ -336,8 +617,43 @@ TimerThreadMain(
|
|||
}
|
||||
|
||||
ExAcquireFastMutex(&Mutex);
|
||||
|
||||
|
||||
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;
|
||||
while (EnumEntry != &TimerListHead)
|
||||
|
@ -365,7 +681,7 @@ TimerThreadMain(
|
|||
|
||||
//set up next periodic timeout
|
||||
MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000);
|
||||
InsertTimerAscendingOrder(MsgTimer);
|
||||
InsertTimerAscendingOrder(MsgTimer, FALSE);
|
||||
|
||||
}
|
||||
else
|
||||
|
@ -378,12 +694,31 @@ TimerThreadMain(
|
|||
if (!IsListEmpty(&TimerListHead))
|
||||
{
|
||||
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
|
||||
{
|
||||
/* Reinitialize the timer, this reset the state of the timer event on which we wait */
|
||||
KeInitializeTimer(&Timer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&Mutex);
|
||||
|
@ -403,6 +738,7 @@ InitTimerImpl(VOID)
|
|||
BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
||||
|
||||
InitializeListHead(&TimerListHead);
|
||||
InitializeListHead(&SysTimerListHead);
|
||||
KeInitializeTimer(&Timer);
|
||||
ExInitializeFastMutex(&Mutex);
|
||||
|
||||
|
|
|
@ -340,7 +340,7 @@ NtUserGetClipCursor(
|
|||
{
|
||||
DPRINT("Validation of window station handle (0x%X) failed\n",
|
||||
PROCESS_WINDOW_STATION());
|
||||
SetLastWin32Error(Status);
|
||||
SetLastNtError(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue