mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +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
|
NtUserInvalidateRect 3
|
||||||
NtUserInvalidateRgn 3
|
NtUserInvalidateRgn 3
|
||||||
NtUserIsClipboardFormatAvailable 1
|
NtUserIsClipboardFormatAvailable 1
|
||||||
|
NtUserKillSystemTimer 2
|
||||||
NtUserKillTimer 2
|
NtUserKillTimer 2
|
||||||
NtUserLoadKeyboardLayoutEx 6
|
NtUserLoadKeyboardLayoutEx 6
|
||||||
NtUserLockWindowStation 1
|
NtUserLockWindowStation 1
|
||||||
|
|
|
@ -4713,10 +4713,10 @@ 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
|
||||||
|
@ -4777,8 +4777,8 @@ RegisterLogonProcess(
|
||||||
WINBOOL
|
WINBOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
KillSystemTimer(
|
KillSystemTimer(
|
||||||
HWND hwnd,
|
HWND hWnd,
|
||||||
UINT id
|
UINT_PTR IDEvent
|
||||||
);
|
);
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 -------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -48,6 +62,21 @@ KillTimer(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
UINT_PTR
|
||||||
|
STDCALL
|
||||||
|
SetSystemTimer(
|
||||||
|
HWND hWnd,
|
||||||
|
UINT_PTR IDEvent,
|
||||||
|
UINT Period,
|
||||||
|
TIMERPROC TimerFunc)
|
||||||
|
{
|
||||||
|
return NtUserSetSystemTimer(hWnd, IDEvent, Period, TimerFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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,13 +75,15 @@ 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;
|
||||||
|
|
||||||
|
if(!SysTimer)
|
||||||
|
{
|
||||||
EnumEntry = TimerListHead.Flink;
|
EnumEntry = TimerListHead.Flink;
|
||||||
while (EnumEntry != &TimerListHead)
|
while (EnumEntry != &TimerListHead)
|
||||||
{
|
{
|
||||||
|
@ -95,9 +100,31 @@ InsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer)
|
||||||
InsertTailList(InsertAfter, &NewTimer->ListEntry);
|
InsertTailList(InsertAfter, &NewTimer->ListEntry);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//insert as first entry
|
//insert as first entry
|
||||||
InsertHeadList(&TimerListHead, &NewTimer->ListEntry);
|
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;
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -105,11 +132,13 @@ 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;
|
||||||
|
|
||||||
|
if(!SysTimer)
|
||||||
|
{
|
||||||
//remove timer if allready in the queue
|
//remove timer if allready in the queue
|
||||||
EnumEntry = TimerListHead.Flink;
|
EnumEntry = TimerListHead.Flink;
|
||||||
while (EnumEntry != &TimerListHead)
|
while (EnumEntry != &TimerListHead)
|
||||||
|
@ -125,6 +154,25 @@ RemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID)
|
||||||
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
|
||||||
{
|
{
|
||||||
/* remove timer if already in the queue */
|
WindowObject = IntGetWindowObject(hWnd);
|
||||||
MsgTimer = RemoveTimer(hWnd, nIDEvent, ThreadID);
|
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, 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,11 +335,24 @@ NtUserSetTimer
|
||||||
NewTimer->ThreadID = ThreadID;
|
NewTimer->ThreadID = ThreadID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(InsertTimerAscendingOrder(NewTimer))
|
if(InsertTimerAscendingOrder(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 */
|
/* new timer is first in queue and expires first */
|
||||||
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
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;
|
||||||
|
|
||||||
|
ThreadID = PsGetCurrentThreadId();
|
||||||
|
KeQuerySystemTime(&CurrentTime);
|
||||||
|
ExAcquireFastMutex(&Mutex);
|
||||||
|
|
||||||
|
if(hWnd == NULL)
|
||||||
|
{
|
||||||
|
ExReleaseFastMutex(&Mutex);
|
||||||
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
||||||
return 0;
|
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,13 +694,32 @@ 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);
|
||||||
|
if(!IsListEmpty(&SysTimerListHead))
|
||||||
|
{
|
||||||
|
MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
||||||
|
if(MsgTimer->Timeout.QuadPart >= MsgTimer2->Timeout.QuadPart)
|
||||||
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
||||||
|
else
|
||||||
|
KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!IsListEmpty(&SysTimerListHead))
|
||||||
|
{
|
||||||
|
MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
||||||
|
KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Reinitialize the timer, this reset the state of the timer event on which we wait */
|
/* Reinitialize the timer, this reset the state of the timer event on which we wait */
|
||||||
KeInitializeTimer(&Timer);
|
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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue