diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 7d7d212e802..aab4c3e6e94 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -187,7 +187,7 @@ @ stub NtQuerySystemEnvironmentValue @ stdcall NtQuerySystemInformation(long long long long) @ stdcall NtQuerySystemTime(ptr) -@ stub NtQueryTimer +@ stdcall NtQueryTimer(ptr long ptr long ptr) @ stdcall NtQueryTimerResolution(long long long) @ stdcall NtQueryValueKey(long long long long long long) @ stdcall NtQueryVirtualMemory(long ptr long ptr long ptr) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index a2e44185817..75739e591ac 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -42,6 +42,7 @@ extern LPCSTR debugstr_us( const UNICODE_STRING *str ); extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes); extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout ); +extern void NTDLL_from_server_timeout( LARGE_INTEGER *timeout, const abs_time_t *when ); extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags, const LARGE_INTEGER *timeout ); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 324cdf9ce86..9b1dc499a34 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -510,6 +510,74 @@ NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state) return status; } +/****************************************************************************** + * NtQueryTimer (NTDLL.@) + * + * Retrieves information about a timer. + * + * PARAMS + * TimerHandle [I] The timer to retrieve information about. + * TimerInformationClass [I] The type of information to retrieve. + * TimerInformation [O] Pointer to buffer to store information in. + * Length [I] The length of the buffer pointed to by TimerInformation. + * ReturnLength [O] Optional. The size of buffer actually used. + * + * RETURNS + * Success: STATUS_SUCCESS + * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data + * size for the class specified. + * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified. + * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access + * to the timer. + */ +NTSTATUS WINAPI NtQueryTimer( + HANDLE TimerHandle, + TIMER_INFORMATION_CLASS TimerInformationClass, + PVOID TimerInformation, + ULONG Length, + PULONG ReturnLength) +{ + TIMER_BASIC_INFORMATION * basic_info = (TIMER_BASIC_INFORMATION *)TimerInformation; + NTSTATUS status; + LARGE_INTEGER now; + + TRACE("(%p,%d,%p,0x%08lx,%p)\n", TimerHandle, TimerInformationClass, + TimerInformation, Length, ReturnLength); + + switch (TimerInformationClass) + { + case TimerBasicInformation: + if (Length < sizeof(TIMER_BASIC_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + + SERVER_START_REQ(get_timer_info) + { + req->handle = TimerHandle; + status = wine_server_call(req); + + /* convert server time to absolute NTDLL time */ + NTDLL_from_server_timeout(&basic_info->RemainingTime, &reply->when); + basic_info->TimerState = reply->signaled; + } + SERVER_END_REQ; + + /* convert from absolute into relative time */ + NtQuerySystemTime(&now); + if (now.QuadPart > basic_info->RemainingTime.QuadPart) + basic_info->RemainingTime.QuadPart = 0; + else + basic_info->RemainingTime.QuadPart -= now.QuadPart; + + if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); + + return status; + } + + FIXME("Unhandled class %d\n", TimerInformationClass); + return STATUS_INVALID_INFO_CLASS; +} + + /****************************************************************************** * NtQueryTimerResolution [NTDLL.@] */ diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c index 6b5fd0989fb..9e520abd6dd 100644 --- a/dlls/ntdll/time.c +++ b/dlls/ntdll/time.c @@ -398,6 +398,18 @@ void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout ) } +/*********************************************************************** + * NTDLL_from_server_timeout + * + * Convert a timeval struct from the server into an NTDLL timeout. + */ +void NTDLL_from_server_timeout( LARGE_INTEGER *timeout, const abs_time_t *when ) +{ + timeout->QuadPart = when->sec * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; + timeout->QuadPart += when->usec * 10; +} + + /****************************************************************************** * RtlTimeToTimeFields [NTDLL.@] * diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 17e78278257..f7753920a7a 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1928,6 +1928,19 @@ struct cancel_timer_reply }; +struct get_timer_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_timer_info_reply +{ + struct reply_header __header; + abs_time_t when; + int signaled; +}; + + struct get_thread_context_request { @@ -3239,6 +3252,7 @@ enum request REQ_open_timer, REQ_set_timer, REQ_cancel_timer, + REQ_get_timer_info, REQ_get_thread_context, REQ_set_thread_context, REQ_get_selector_entry, @@ -3424,6 +3438,7 @@ union generic_request struct open_timer_request open_timer_request; struct set_timer_request set_timer_request; struct cancel_timer_request cancel_timer_request; + struct get_timer_info_request get_timer_info_request; struct get_thread_context_request get_thread_context_request; struct set_thread_context_request set_thread_context_request; struct get_selector_entry_request get_selector_entry_request; @@ -3607,6 +3622,7 @@ union generic_reply struct open_timer_reply open_timer_reply; struct set_timer_reply set_timer_reply; struct cancel_timer_reply cancel_timer_reply; + struct get_timer_info_reply get_timer_info_reply; struct get_thread_context_reply get_thread_context_reply; struct set_thread_context_reply set_thread_context_reply; struct get_selector_entry_reply get_selector_entry_reply; @@ -3681,6 +3697,6 @@ union generic_reply struct set_global_windows_reply set_global_windows_reply; }; -#define SERVER_PROTOCOL_VERSION 152 +#define SERVER_PROTOCOL_VERSION 153 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/winternl.h b/include/winternl.h index 8a58bedc74e..5946ec7eb8c 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -632,6 +632,16 @@ typedef struct _MUTANT_BASIC_INFORMATION { BOOLEAN AbandonedState; } MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION; +typedef enum _TIMER_INFORMATION_CLASS +{ + TimerBasicInformation = 0 +} TIMER_INFORMATION_CLASS; + +typedef struct _TIMER_BASIC_INFORMATION +{ + LARGE_INTEGER RemainingTime; + BOOLEAN TimerState; +} TIMER_BASIC_INFORMATION, *PTIMER_BASIC_INFORMATION; /* return type of RtlDetermineDosPathNameType_U (FIXME: not the correct names) */ @@ -1401,6 +1411,7 @@ NTSTATUS WINAPI NtQueryObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, P NTSTATUS WINAPI NtQuerySecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,ULONG,PULONG); NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS,PVOID,ULONG,PULONG); NTSTATUS WINAPI NtQuerySystemTime(PLARGE_INTEGER); +NTSTATUS WINAPI NtQueryTimer(HANDLE,TIMER_INFORMATION_CLASS,PVOID,ULONG,PULONG); NTSTATUS WINAPI NtQueryValueKey(HKEY,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *); NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE,LPCVOID,MEMORY_INFORMATION_CLASS,PVOID,ULONG,ULONG*); NTSTATUS WINAPI NtQueryVolumeInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS); diff --git a/server/protocol.def b/server/protocol.def index 5423b7c1ea9..0cfd8c5bb26 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1378,6 +1378,14 @@ enum char_info_mode int signaled; /* was the timer signaled before this calltime ? */ @END +/* Get information on a waitable timer */ +@REQ(get_timer_info) + obj_handle_t handle; /* handle to the timer */ +@REPLY + abs_time_t when; /* absolute time when the timer next expires */ + int signaled; /* is the timer signaled? */ +@END + /* Retrieve the current context of a thread */ @REQ(get_thread_context) diff --git a/server/request.h b/server/request.h index d4ceb244688..0a2319f2f7a 100644 --- a/server/request.h +++ b/server/request.h @@ -209,6 +209,7 @@ DECL_HANDLER(create_timer); DECL_HANDLER(open_timer); DECL_HANDLER(set_timer); DECL_HANDLER(cancel_timer); +DECL_HANDLER(get_timer_info); DECL_HANDLER(get_thread_context); DECL_HANDLER(set_thread_context); DECL_HANDLER(get_selector_entry); @@ -393,6 +394,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_open_timer, (req_handler)req_set_timer, (req_handler)req_cancel_timer, + (req_handler)req_get_timer_info, (req_handler)req_get_thread_context, (req_handler)req_set_thread_context, (req_handler)req_get_selector_entry, diff --git a/server/timer.c b/server/timer.c index ef07f2a04d1..1903ba71fd7 100644 --- a/server/timer.c +++ b/server/timer.c @@ -241,3 +241,18 @@ DECL_HANDLER(cancel_timer) release_object( timer ); } } + +/* Get information on a waitable timer */ +DECL_HANDLER(get_timer_info) +{ + struct timer *timer; + + if ((timer = (struct timer *)get_handle_obj( current->process, req->handle, + TIMER_QUERY_STATE, &timer_ops ))) + { + reply->when.sec = timer->when.tv_sec; + reply->when.usec = timer->when.tv_usec; + reply->signaled = timer->signaled; + release_object( timer ); + } +} diff --git a/server/trace.c b/server/trace.c index daafbf502dd..bcba1d1444f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1692,6 +1692,19 @@ static void dump_cancel_timer_reply( const struct cancel_timer_reply *req ) fprintf( stderr, " signaled=%d", req->signaled ); } +static void dump_get_timer_info_request( const struct get_timer_info_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_get_timer_info_reply( const struct get_timer_info_reply *req ) +{ + fprintf( stderr, " when=" ); + dump_abs_time( &req->when ); + fprintf( stderr, "," ); + fprintf( stderr, " signaled=%d", req->signaled ); +} + static void dump_get_thread_context_request( const struct get_thread_context_request *req ) { fprintf( stderr, " handle=%p,", req->handle ); @@ -2695,6 +2708,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_open_timer_request, (dump_func)dump_set_timer_request, (dump_func)dump_cancel_timer_request, + (dump_func)dump_get_timer_info_request, (dump_func)dump_get_thread_context_request, (dump_func)dump_set_thread_context_request, (dump_func)dump_get_selector_entry_request, @@ -2876,6 +2890,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_open_timer_reply, (dump_func)dump_set_timer_reply, (dump_func)dump_cancel_timer_reply, + (dump_func)dump_get_timer_info_reply, (dump_func)dump_get_thread_context_reply, (dump_func)0, (dump_func)dump_get_selector_entry_reply, @@ -3057,6 +3072,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "open_timer", "set_timer", "cancel_timer", + "get_timer_info", "get_thread_context", "set_thread_context", "get_selector_entry",