Module: wine Branch: master Commit: 396e47ef5c201ff01f2eef7fcb0339520db4e6fa URL: http://source.winehq.org/git/wine.git/?a=commit;h=396e47ef5c201ff01f2eef7fcb...
Author: Dan Hipschman dsh@linux.ucla.edu Date: Thu Jul 24 16:27:03 2008 -0700
ntdll: Implement RtlUpdateTimer for kernel32's ChangeTimerQueueTimer.
---
dlls/kernel32/sync.c | 15 +++++++++------ dlls/kernel32/tests/sync.c | 15 ++++++++++++--- dlls/ntdll/ntdll.spec | 2 +- dlls/ntdll/threadpool.c | 36 ++++++++++++++++++++++++++++++++++++ include/winternl.h | 1 + 5 files changed, 59 insertions(+), 10 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index c739a5b..8bd4243 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -1109,16 +1109,19 @@ BOOL WINAPI CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, * * RETURNS * nonzero on success or zero on failure - * - * BUGS - * Unimplemented */ BOOL WINAPI ChangeTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period ) { - FIXME("stub\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + NTSTATUS status = RtlUpdateTimer(TimerQueue, Timer, DueTime, Period); + + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } + + return TRUE; }
/*********************************************************************** diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index d41bd79..19fc8e2 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -583,7 +583,6 @@ static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut) /* Basically kill the timer since it won't have time to run again. */ BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 10000, 0); - todo_wine ok(ret, "ChangeTimerQueueTimer\n"); } } @@ -600,7 +599,6 @@ static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut) fail if the timer is already flagged. Hence we really run only once. Otherwise we will run multiple times. */ BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 50, 50); - todo_wine ok(ret, "ChangeTimerQueueTimer\n"); ++d->num_calls; } @@ -707,6 +705,16 @@ static void test_timer_queue(void) q = pCreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
+ /* Test changing a once-only timer before it fires (this is allowed, + whereas after it fires you cannot). */ + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + ret = pChangeTimerQueueTimer(q, t1, 0, 0); + ok(ret, "ChangeTimerQueueTimer\n"); + d2.t = t2 = NULL; d2.num_calls = 0; d2.max_calls = 3; @@ -740,11 +748,12 @@ static void test_timer_queue(void)
ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueEx\n"); + ok(n1 == 1, "ChangeTimerQueueTimer\n"); todo_wine { ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n"); - ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); } + ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n"); }
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 595a5f6..4d200eb 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -895,7 +895,7 @@ @ stub RtlUpcaseUnicodeToCustomCPN @ stdcall RtlUpcaseUnicodeToMultiByteN(ptr long ptr ptr long) @ stdcall RtlUpcaseUnicodeToOemN(ptr long ptr ptr long) -# @ stub RtlUpdateTimer +@ stdcall RtlUpdateTimer(ptr ptr long long) @ stdcall RtlUpperChar(long) @ stdcall RtlUpperString(ptr ptr) @ stub RtlUsageHeap diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index cbb97f4..f6e6c1e 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -907,3 +907,39 @@ NTSTATUS WINAPI RtlCreateTimer(PHANDLE NewTimer, HANDLE TimerQueue,
return status; } + +/*********************************************************************** + * RtlUpdateTimer (NTDLL.@) + * + * Changes the time at which a timer expires. + * + * PARAMS + * TimerQueue [I] The queue that holds the timer. + * Timer [I] The timer to update. + * DueTime [I] The delay, in milliseconds, before next firing the timer. + * Period [I] The period, in milliseconds, at which to fire the timer + * after the first callback. If zero, the timer will not + * refire once. It still needs to be deleted with + * RtlDeleteTimer. + * + * RETURNS + * Success: STATUS_SUCCESS. + * Failure: Any NTSTATUS code. + */ +NTSTATUS WINAPI RtlUpdateTimer(HANDLE TimerQueue, HANDLE Timer, + DWORD DueTime, DWORD Period) +{ + struct timer_queue *q = TimerQueue; + struct queue_timer *t = Timer; + + RtlEnterCriticalSection(&q->cs); + /* Can't change a timer if it was once-only or destroyed. */ + if (t->expire != EXPIRE_NEVER) + { + t->period = Period; + queue_move_timer(t, queue_current_time() + DueTime, TRUE); + } + RtlLeaveCriticalSection(&q->cs); + + return STATUS_SUCCESS; +} diff --git a/include/winternl.h b/include/winternl.h index 30bd0e5..cb9a6f7 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2340,6 +2340,7 @@ NTSYSAPI NTSTATUS WINAPI RtlUpcaseUnicodeStringToCountedOemString(STRING*,const NTSYSAPI NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString(STRING*,const UNICODE_STRING*,BOOLEAN); NTSYSAPI NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD); NTSYSAPI NTSTATUS WINAPI RtlUpcaseUnicodeToOemN(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD); +NTSYSAPI NTSTATUS WINAPI RtlUpdateTimer(HANDLE, HANDLE, DWORD, DWORD); NTSYSAPI CHAR WINAPI RtlUpperChar(CHAR); NTSYSAPI void WINAPI RtlUpperString(STRING *,const STRING *); NTSYSAPI NTSTATUS WINAPI RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR);