xref: /reactos/dll/win32/kernel32/client/time.c (revision c6b64448)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/time.c
5  * PURPOSE:         Time conversion functions
6  * PROGRAMMER:      Ariadne
7  *                  DOSDATE and DOSTIME structures from Onno Hovers
8  * UPDATE HISTORY:
9  *                  Created 19/01/99
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include <k32.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 /* FUNCTIONS ******************************************************************/
20 
21 /*
22  * @implemented
23  */
24 BOOL
25 WINAPI
IsTimeZoneRedirectionEnabled(VOID)26 IsTimeZoneRedirectionEnabled(VOID)
27 {
28     /* Return if a TS Timezone ID is active */
29     return (BaseStaticServerData->TermsrvClientTimeZoneId != TIME_ZONE_ID_INVALID);
30 }
31 
32 /*
33  * @implemented
34  */
35 BOOL
36 WINAPI
FileTimeToDosDateTime(IN CONST FILETIME * lpFileTime,OUT LPWORD lpFatDate,OUT LPWORD lpFatTime)37 FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime,
38                       OUT LPWORD lpFatDate,
39                       OUT LPWORD lpFatTime)
40 {
41     LARGE_INTEGER FileTime;
42     TIME_FIELDS TimeFields;
43 
44     FileTime.HighPart = lpFileTime->dwHighDateTime;
45     FileTime.LowPart = lpFileTime->dwLowDateTime;
46 
47     if (FileTime.QuadPart < 0)
48     {
49         SetLastError(ERROR_INVALID_PARAMETER);
50         return FALSE;
51     }
52 
53     RtlTimeToTimeFields(&FileTime, &TimeFields);
54     if ((TimeFields.Year < 1980) || (TimeFields.Year > 2107))
55     {
56         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
57         return FALSE;
58     }
59 
60     *lpFatDate = (TimeFields.Day) |
61                  (TimeFields.Month << 5) |
62                  ((TimeFields.Year - 1980) << 9);
63     *lpFatTime = (TimeFields.Second >> 1) |
64                  (TimeFields.Minute << 5) |
65                  (TimeFields.Hour << 11);
66 
67     return TRUE;
68 }
69 
70 /*
71  * @implemented
72  */
73 BOOL
74 WINAPI
DosDateTimeToFileTime(IN WORD wFatDate,IN WORD wFatTime,OUT LPFILETIME lpFileTime)75 DosDateTimeToFileTime(IN WORD wFatDate,
76                       IN WORD wFatTime,
77                       OUT LPFILETIME lpFileTime)
78 {
79     TIME_FIELDS TimeFields;
80     LARGE_INTEGER SystemTime;
81 
82     TimeFields.Year = (wFatDate >> 9) + 1980;
83     TimeFields.Month = (wFatDate >> 5) & 0xF;
84     TimeFields.Day = (wFatDate & 0x1F);
85     TimeFields.Hour = (wFatTime >> 11);
86     TimeFields.Minute = (wFatTime >> 5) & 0x3F;
87     TimeFields.Second = (wFatTime & 0x1F) << 1;
88     TimeFields.Milliseconds = 0;
89 
90     if (RtlTimeFieldsToTime(&TimeFields, &SystemTime))
91     {
92         lpFileTime->dwLowDateTime = SystemTime.LowPart;
93         lpFileTime->dwHighDateTime = SystemTime.HighPart;
94         return TRUE;
95     }
96 
97     BaseSetLastNTError(STATUS_INVALID_PARAMETER);
98     return FALSE;
99 }
100 
101 /*
102  * @implemented
103  */
104 LONG
105 WINAPI
CompareFileTime(IN CONST FILETIME * lpFileTime1,IN CONST FILETIME * lpFileTime2)106 CompareFileTime(IN CONST FILETIME *lpFileTime1,
107                 IN CONST FILETIME *lpFileTime2)
108 {
109     LARGE_INTEGER Time1, Time2, Diff;
110 
111     Time1.LowPart = lpFileTime1->dwLowDateTime;
112     Time2.LowPart = lpFileTime2->dwLowDateTime;
113     Time1.HighPart = lpFileTime1->dwHighDateTime;
114     Time2.HighPart = lpFileTime2->dwHighDateTime;
115 
116     Diff.QuadPart = Time1.QuadPart - Time2.QuadPart;
117 
118     if (Diff.HighPart < 0) return -1;
119     if (Diff.QuadPart == 0) return 0;
120     return 1;
121 }
122 
123 /*
124  * @implemented
125  */
126 VOID
127 WINAPI
GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)128 GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
129 {
130     LARGE_INTEGER SystemTime;
131 
132     do
133     {
134         SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
135         SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
136     }
137     while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
138 
139     lpFileTime->dwLowDateTime = SystemTime.LowPart;
140     lpFileTime->dwHighDateTime = SystemTime.HighPart;
141 }
142 
143 /*
144  * @unimplemented
145  */
146 VOID
147 WINAPI
GetSystemTimePreciseAsFileTime(OUT PFILETIME lpFileTime)148 GetSystemTimePreciseAsFileTime(OUT PFILETIME lpFileTime)
149 {
150     STUB;
151 }
152 
153 /*
154  * @implemented
155  */
156 BOOL
157 WINAPI
SystemTimeToFileTime(IN CONST SYSTEMTIME * lpSystemTime,OUT LPFILETIME lpFileTime)158 SystemTimeToFileTime(IN CONST SYSTEMTIME *lpSystemTime,
159                      OUT LPFILETIME lpFileTime)
160 {
161     TIME_FIELDS TimeFields;
162     LARGE_INTEGER liTime;
163 
164     TimeFields.Year = lpSystemTime->wYear;
165     TimeFields.Month = lpSystemTime->wMonth;
166     TimeFields.Day = lpSystemTime->wDay;
167     TimeFields.Hour = lpSystemTime->wHour;
168     TimeFields.Minute = lpSystemTime->wMinute;
169     TimeFields.Second = lpSystemTime->wSecond;
170     TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
171 
172     if (RtlTimeFieldsToTime(&TimeFields, &liTime))
173     {
174         lpFileTime->dwLowDateTime = liTime.u.LowPart;
175         lpFileTime->dwHighDateTime = liTime.u.HighPart;
176         return TRUE;
177     }
178 
179     BaseSetLastNTError(STATUS_INVALID_PARAMETER);
180     return FALSE;
181 }
182 
183 /*
184  * @implemented
185  */
186 BOOL
187 WINAPI
FileTimeToSystemTime(IN CONST FILETIME * lpFileTime,OUT LPSYSTEMTIME lpSystemTime)188 FileTimeToSystemTime(IN CONST FILETIME *lpFileTime,
189                      OUT LPSYSTEMTIME lpSystemTime)
190 {
191     TIME_FIELDS TimeFields;
192     LARGE_INTEGER liTime;
193 
194     liTime.u.LowPart = lpFileTime->dwLowDateTime;
195     liTime.u.HighPart = lpFileTime->dwHighDateTime;
196     if (liTime.QuadPart < 0)
197     {
198         SetLastError(ERROR_INVALID_PARAMETER);
199         return FALSE;
200     }
201 
202     RtlTimeToTimeFields(&liTime, &TimeFields);
203 
204     lpSystemTime->wYear = TimeFields.Year;
205     lpSystemTime->wMonth = TimeFields.Month;
206     lpSystemTime->wDay = TimeFields.Day;
207     lpSystemTime->wHour = TimeFields.Hour;
208     lpSystemTime->wMinute = TimeFields.Minute;
209     lpSystemTime->wSecond = TimeFields.Second;
210     lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
211     lpSystemTime->wDayOfWeek = TimeFields.Weekday;
212 
213     return TRUE;
214 }
215 
216 /*
217  * @implemented
218  */
219 BOOL
220 WINAPI
FileTimeToLocalFileTime(IN CONST FILETIME * lpFileTime,OUT LPFILETIME lpLocalFileTime)221 FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime,
222                         OUT LPFILETIME lpLocalFileTime)
223 {
224     LARGE_INTEGER TimeZoneBias, FileTime;
225     volatile KSYSTEM_TIME *TimePtr;
226 
227     TimePtr = IsTimeZoneRedirectionEnabled() ?
228               &BaseStaticServerData->ktTermsrvClientBias :
229               &SharedUserData->TimeZoneBias;
230     do
231     {
232         TimeZoneBias.HighPart = TimePtr->High1Time;
233         TimeZoneBias.LowPart = TimePtr->LowPart;
234     }
235     while (TimeZoneBias.HighPart != TimePtr->High2Time);
236 
237     FileTime.LowPart = lpFileTime->dwLowDateTime;
238     FileTime.HighPart = lpFileTime->dwHighDateTime;
239 
240     FileTime.QuadPart -= TimeZoneBias.QuadPart;
241 
242     lpLocalFileTime->dwLowDateTime = FileTime.LowPart;
243     lpLocalFileTime->dwHighDateTime = FileTime.HighPart;
244 
245     return TRUE;
246 }
247 
248 /*
249  * @implemented
250  */
251 BOOL
252 WINAPI
LocalFileTimeToFileTime(IN CONST FILETIME * lpLocalFileTime,OUT LPFILETIME lpFileTime)253 LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime,
254                         OUT LPFILETIME lpFileTime)
255 {
256     LARGE_INTEGER TimeZoneBias, FileTime;
257     volatile KSYSTEM_TIME *TimePtr;
258 
259     TimePtr = IsTimeZoneRedirectionEnabled() ?
260               &BaseStaticServerData->ktTermsrvClientBias :
261               &SharedUserData->TimeZoneBias;
262 
263     do
264     {
265         TimeZoneBias.HighPart = TimePtr->High1Time;
266         TimeZoneBias.LowPart = TimePtr->LowPart;
267     }
268     while (TimeZoneBias.HighPart != TimePtr->High2Time);
269 
270     FileTime.LowPart = lpLocalFileTime->dwLowDateTime;
271     FileTime.HighPart = lpLocalFileTime->dwHighDateTime;
272 
273     FileTime.QuadPart += TimeZoneBias.QuadPart;
274 
275     lpFileTime->dwLowDateTime = FileTime.LowPart;
276     lpFileTime->dwHighDateTime = FileTime.HighPart;
277 
278     return TRUE;
279 }
280 
281 /*
282  * @implemented
283  */
284 VOID
285 WINAPI
GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)286 GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
287 {
288     LARGE_INTEGER SystemTime, TimeZoneBias;
289     TIME_FIELDS TimeFields;
290     volatile KSYSTEM_TIME *TimePtr;
291 
292     do
293     {
294         SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
295         SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
296     }
297     while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
298 
299     TimePtr = IsTimeZoneRedirectionEnabled() ?
300               &BaseStaticServerData->ktTermsrvClientBias :
301               &SharedUserData->TimeZoneBias;
302     do
303     {
304         TimeZoneBias.HighPart = TimePtr->High1Time;
305         TimeZoneBias.LowPart = TimePtr->LowPart;
306     }
307     while (TimeZoneBias.HighPart != TimePtr->High2Time);
308 
309     SystemTime.QuadPart -= TimeZoneBias.QuadPart;
310     RtlTimeToTimeFields(&SystemTime, &TimeFields);
311 
312     lpSystemTime->wYear = TimeFields.Year;
313     lpSystemTime->wMonth = TimeFields.Month;
314     lpSystemTime->wDay = TimeFields.Day;
315     lpSystemTime->wHour = TimeFields.Hour;
316     lpSystemTime->wMinute = TimeFields.Minute;
317     lpSystemTime->wSecond = TimeFields.Second;
318     lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
319     lpSystemTime->wDayOfWeek = TimeFields.Weekday;
320 }
321 
322 /*
323  * @implemented
324  */
325 VOID
326 WINAPI
GetSystemTime(OUT LPSYSTEMTIME lpSystemTime)327 GetSystemTime(OUT LPSYSTEMTIME lpSystemTime)
328 {
329     LARGE_INTEGER SystemTime;
330     TIME_FIELDS TimeFields;
331 
332     do
333     {
334         SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
335         SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
336     }
337     while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
338 
339     RtlTimeToTimeFields(&SystemTime, &TimeFields);
340 
341     lpSystemTime->wYear = TimeFields.Year;
342     lpSystemTime->wMonth = TimeFields.Month;
343     lpSystemTime->wDay = TimeFields.Day;
344     lpSystemTime->wHour = TimeFields.Hour;
345     lpSystemTime->wMinute = TimeFields.Minute;
346     lpSystemTime->wSecond = TimeFields.Second;
347     lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
348     lpSystemTime->wDayOfWeek = TimeFields.Weekday;
349 }
350 
351 /*
352  * @implemented
353  */
354 BOOL
355 WINAPI
SetLocalTime(IN CONST SYSTEMTIME * lpSystemTime)356 SetLocalTime(IN CONST SYSTEMTIME *lpSystemTime)
357 {
358     LARGE_INTEGER NewSystemTime, TimeZoneBias;
359     NTSTATUS Status;
360     ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
361     TIME_FIELDS TimeFields;
362     PVOID State;
363     volatile KSYSTEM_TIME *TimePtr;
364 
365     TimePtr = IsTimeZoneRedirectionEnabled() ?
366               &BaseStaticServerData->ktTermsrvClientBias :
367               &SharedUserData->TimeZoneBias;
368     do
369     {
370         TimeZoneBias.HighPart = TimePtr->High1Time;
371         TimeZoneBias.LowPart = TimePtr->LowPart;
372     }
373     while (TimeZoneBias.HighPart != TimePtr->High2Time);
374 
375     TimeFields.Year = lpSystemTime->wYear;
376     TimeFields.Month = lpSystemTime->wMonth;
377     TimeFields.Day = lpSystemTime->wDay;
378     TimeFields.Hour = lpSystemTime->wHour;
379     TimeFields.Minute = lpSystemTime->wMinute;
380     TimeFields.Second = lpSystemTime->wSecond;
381     TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
382 
383     if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
384     {
385         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
386         return FALSE;
387     }
388 
389     NewSystemTime.QuadPart += TimeZoneBias.QuadPart;
390 
391     Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
392     if (NT_SUCCESS(Status))
393     {
394         Status = NtSetSystemTime(&NewSystemTime, NULL);
395         RtlReleasePrivilege(State);
396     }
397 
398     if (!NT_SUCCESS(Status))
399     {
400         BaseSetLastNTError(Status);
401         return FALSE;
402     }
403 
404     return TRUE;
405 }
406 
407 /*
408  * @implemented
409  */
410 BOOL
411 WINAPI
SetSystemTime(IN CONST SYSTEMTIME * lpSystemTime)412 SetSystemTime(IN CONST SYSTEMTIME *lpSystemTime)
413 {
414     LARGE_INTEGER NewSystemTime;
415     NTSTATUS Status;
416     ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
417     TIME_FIELDS TimeFields;
418     PVOID State;
419 
420     TimeFields.Year = lpSystemTime->wYear;
421     TimeFields.Month = lpSystemTime->wMonth;
422     TimeFields.Day = lpSystemTime->wDay;
423     TimeFields.Hour = lpSystemTime->wHour;
424     TimeFields.Minute = lpSystemTime->wMinute;
425     TimeFields.Second = lpSystemTime->wSecond;
426     TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
427 
428     if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
429     {
430         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
431         return FALSE;
432     }
433 
434     Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
435     if (NT_SUCCESS(Status))
436     {
437         Status = NtSetSystemTime(&NewSystemTime, NULL);
438         RtlReleasePrivilege(State);
439     }
440 
441     if (!NT_SUCCESS(Status))
442     {
443         BaseSetLastNTError(Status);
444         return FALSE;
445     }
446 
447     return TRUE;
448 }
449 
450 /*
451  * @implemented
452  */
453 DWORD
454 WINAPI
GetTickCount(VOID)455 GetTickCount(VOID)
456 {
457     ULARGE_INTEGER TickCount;
458 
459 #ifdef _WIN64
460     TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
461 #else
462     while (TRUE)
463     {
464         TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
465         TickCount.LowPart = SharedUserData->TickCount.LowPart;
466 
467         if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
468             break;
469 
470         YieldProcessor();
471     }
472 #endif
473 
474     return (ULONG)((UInt32x32To64(TickCount.LowPart,
475                                   SharedUserData->TickCountMultiplier) >> 24) +
476                     UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
477                                   SharedUserData->TickCountMultiplier));
478 
479 }
480 
481 /*
482  * @implemented
483  */
484 BOOL
485 WINAPI
GetSystemTimeAdjustment(OUT PDWORD lpTimeAdjustment,OUT PDWORD lpTimeIncrement,OUT PBOOL lpTimeAdjustmentDisabled)486 GetSystemTimeAdjustment(OUT PDWORD lpTimeAdjustment,
487                         OUT PDWORD lpTimeIncrement,
488                         OUT PBOOL lpTimeAdjustmentDisabled)
489 {
490     SYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo;
491     NTSTATUS Status;
492 
493     Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
494                                       &TimeInfo,
495                                       sizeof(TimeInfo),
496                                       NULL);
497     if (!NT_SUCCESS(Status))
498     {
499         BaseSetLastNTError(Status);
500         return FALSE;
501     }
502 
503     *lpTimeAdjustment = (DWORD)TimeInfo.TimeAdjustment;
504     *lpTimeIncrement = (DWORD)TimeInfo.TimeIncrement;
505     *lpTimeAdjustmentDisabled = (BOOL)TimeInfo.Enable;
506 
507     return TRUE;
508 }
509 
510 /*
511  * @implemented
512  */
513 BOOL
514 WINAPI
SetSystemTimeAdjustment(IN DWORD dwTimeAdjustment,IN BOOL bTimeAdjustmentDisabled)515 SetSystemTimeAdjustment(IN DWORD dwTimeAdjustment,
516                         IN BOOL bTimeAdjustmentDisabled)
517 {
518     NTSTATUS Status;
519     SYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo;
520 
521     TimeInfo.TimeAdjustment = (ULONG)dwTimeAdjustment;
522     TimeInfo.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
523 
524     Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
525                                     &TimeInfo,
526                                     sizeof(TimeInfo));
527     if (!NT_SUCCESS(Status))
528     {
529         BaseSetLastNTError(Status);
530         return FALSE;
531     }
532 
533     return TRUE;
534 }
535 
536 /*
537  * @implemented
538  */
539 BOOL
540 WINAPI
GetSystemTimes(OUT LPFILETIME lpIdleTime OPTIONAL,OUT LPFILETIME lpKernelTime OPTIONAL,OUT LPFILETIME lpUserTime OPTIONAL)541 GetSystemTimes(OUT LPFILETIME lpIdleTime OPTIONAL,
542                OUT LPFILETIME lpKernelTime OPTIONAL,
543                OUT LPFILETIME lpUserTime OPTIONAL)
544 {
545     PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcPerfInfo;
546     LARGE_INTEGER TotalUserTime, TotalKernTime, TotalIdleTime;
547     ULONG BufferSize, ReturnLength;
548     CCHAR i;
549     NTSTATUS Status;
550 
551     TotalUserTime.QuadPart = TotalKernTime.QuadPart = TotalIdleTime.QuadPart = 0;
552 
553     BufferSize = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) *
554                  BaseStaticServerData->SysInfo.NumberOfProcessors;
555 
556     ProcPerfInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
557     if (!ProcPerfInfo)
558     {
559         BaseSetLastNTError(STATUS_NO_MEMORY);
560         return FALSE;
561     }
562 
563     Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
564                                       ProcPerfInfo,
565                                       BufferSize,
566                                       &ReturnLength);
567     if ((NT_SUCCESS(Status)) && (ReturnLength == BufferSize))
568     {
569         if (lpIdleTime)
570         {
571             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
572             {
573                 TotalIdleTime.QuadPart += ProcPerfInfo[i].IdleTime.QuadPart;
574             }
575 
576             lpIdleTime->dwLowDateTime = TotalIdleTime.LowPart;
577             lpIdleTime->dwHighDateTime = TotalIdleTime.HighPart;
578         }
579 
580         if (lpKernelTime)
581         {
582             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
583             {
584                 TotalKernTime.QuadPart += ProcPerfInfo[i].KernelTime.QuadPart;
585             }
586 
587             lpKernelTime->dwLowDateTime = TotalKernTime.LowPart;
588             lpKernelTime->dwHighDateTime = TotalKernTime.HighPart;
589         }
590 
591         if (lpUserTime)
592         {
593             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
594             {
595                 TotalUserTime.QuadPart += ProcPerfInfo[i].UserTime.QuadPart;
596             }
597 
598             lpUserTime->dwLowDateTime = TotalUserTime.LowPart;
599             lpUserTime->dwHighDateTime = TotalUserTime.HighPart;
600         }
601     }
602     else if (NT_SUCCESS(Status))
603     {
604          Status = STATUS_INTERNAL_ERROR;
605     }
606 
607     RtlFreeHeap(RtlGetProcessHeap(), 0, ProcPerfInfo);
608     if (!NT_SUCCESS(Status))
609     {
610         BaseSetLastNTError(Status);
611         return FALSE;
612     }
613 
614     return TRUE;
615 }
616 
617 /*
618  * @unimplemented
619  */
620 BOOL
621 WINAPI
SetClientTimeZoneInformation(IN CONST TIME_ZONE_INFORMATION * lpTimeZoneInformation)622 SetClientTimeZoneInformation(IN CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
623 {
624     STUB;
625     return 0;
626 }
627 
628 /* EOF */
629