1 /* 2 * PROJECT: ReactOS TimeZone Utilities Library 3 * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0) 4 * PURPOSE: Provides time-zone utility wrappers around Win32 functions, 5 * that are used by different ReactOS modules such as 6 * timedate.cpl, syssetup.dll. 7 * COPYRIGHT: Copyright 2004-2005 Eric Kohl 8 * Copyright 2016 Carlo Bramini 9 * Copyright 2020 Hermes Belusca-Maito 10 */ 11 12 #include <stdlib.h> 13 #include <windef.h> 14 #include <winbase.h> 15 #include <winreg.h> 16 17 #include "tzlib.h" 18 19 BOOL 20 GetTimeZoneListIndex( 21 IN OUT PULONG pIndex) 22 { 23 LONG lError; 24 HKEY hKey; 25 DWORD dwType; 26 DWORD dwValueSize; 27 DWORD Length; 28 LPWSTR Buffer; 29 LPWSTR Ptr, End; 30 BOOL bFound = FALSE; 31 unsigned long iLanguageID; 32 WCHAR szLanguageIdString[9]; 33 34 if (*pIndex == -1) 35 { 36 *pIndex = 85; /* fallback to GMT time zone */ 37 38 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 39 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language", 40 0, 41 KEY_QUERY_VALUE, 42 &hKey); 43 if (lError != ERROR_SUCCESS) 44 { 45 return FALSE; 46 } 47 48 dwValueSize = sizeof(szLanguageIdString); 49 lError = RegQueryValueExW(hKey, 50 L"Default", 51 NULL, 52 NULL, 53 (LPBYTE)szLanguageIdString, 54 &dwValueSize); 55 if (lError != ERROR_SUCCESS) 56 { 57 RegCloseKey(hKey); 58 return FALSE; 59 } 60 61 iLanguageID = wcstoul(szLanguageIdString, NULL, 16); 62 RegCloseKey(hKey); 63 } 64 else 65 { 66 iLanguageID = *pIndex; 67 } 68 69 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 70 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 71 0, 72 KEY_QUERY_VALUE, 73 &hKey); 74 if (lError != ERROR_SUCCESS) 75 { 76 return FALSE; 77 } 78 79 dwValueSize = 0; 80 lError = RegQueryValueExW(hKey, 81 L"IndexMapping", 82 NULL, 83 &dwType, 84 NULL, 85 &dwValueSize); 86 if ((lError != ERROR_SUCCESS) || (dwType != REG_MULTI_SZ)) 87 { 88 RegCloseKey(hKey); 89 return FALSE; 90 } 91 92 Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwValueSize); 93 if (Buffer == NULL) 94 { 95 RegCloseKey(hKey); 96 return FALSE; 97 } 98 99 lError = RegQueryValueExW(hKey, 100 L"IndexMapping", 101 NULL, 102 &dwType, 103 (LPBYTE)Buffer, 104 &dwValueSize); 105 106 RegCloseKey(hKey); 107 108 if ((lError != ERROR_SUCCESS) || (dwType != REG_MULTI_SZ)) 109 { 110 HeapFree(GetProcessHeap(), 0, Buffer); 111 return FALSE; 112 } 113 114 Ptr = Buffer; 115 while (*Ptr != 0) 116 { 117 Length = wcslen(Ptr); 118 if (wcstoul(Ptr, NULL, 16) == iLanguageID) 119 bFound = TRUE; 120 121 Ptr = Ptr + Length + 1; 122 if (*Ptr == 0) 123 break; 124 125 if (bFound) 126 { 127 *pIndex = wcstoul(Ptr, &End, 10); 128 HeapFree(GetProcessHeap(), 0, Buffer); 129 return TRUE; 130 } 131 132 Length = wcslen(Ptr); 133 Ptr = Ptr + Length + 1; 134 } 135 136 HeapFree(GetProcessHeap(), 0, Buffer); 137 return FALSE; 138 } 139 140 LONG 141 QueryTimeZoneData( 142 IN HKEY hZoneKey, 143 OUT PULONG Index OPTIONAL, 144 OUT PREG_TZI_FORMAT TimeZoneInfo, 145 OUT PWCHAR Description OPTIONAL, 146 IN OUT PULONG DescriptionSize OPTIONAL, 147 OUT PWCHAR StandardName OPTIONAL, 148 IN OUT PULONG StandardNameSize OPTIONAL, 149 OUT PWCHAR DaylightName OPTIONAL, 150 IN OUT PULONG DaylightNameSize OPTIONAL) 151 { 152 LONG lError; 153 DWORD dwValueSize; 154 155 if (Index) 156 { 157 dwValueSize = sizeof(*Index); 158 lError = RegQueryValueExW(hZoneKey, 159 L"Index", 160 NULL, 161 NULL, 162 (LPBYTE)Index, 163 &dwValueSize); 164 if (lError != ERROR_SUCCESS) 165 *Index = 0; 166 } 167 168 /* The time zone information structure is mandatory for a valid time zone */ 169 dwValueSize = sizeof(*TimeZoneInfo); 170 lError = RegQueryValueExW(hZoneKey, 171 L"TZI", 172 NULL, 173 NULL, 174 (LPBYTE)TimeZoneInfo, 175 &dwValueSize); 176 if (lError != ERROR_SUCCESS) 177 return lError; 178 179 if (Description && DescriptionSize && *DescriptionSize > 0) 180 { 181 lError = RegQueryValueExW(hZoneKey, 182 L"Display", 183 NULL, 184 NULL, 185 (LPBYTE)Description, 186 DescriptionSize); 187 if (lError != ERROR_SUCCESS) 188 *Description = 0; 189 } 190 191 if (StandardName && StandardNameSize && *StandardNameSize > 0) 192 { 193 lError = RegQueryValueExW(hZoneKey, 194 L"Std", 195 NULL, 196 NULL, 197 (LPBYTE)StandardName, 198 StandardNameSize); 199 if (lError != ERROR_SUCCESS) 200 *StandardName = 0; 201 } 202 203 if (DaylightName && DaylightNameSize && *DaylightNameSize > 0) 204 { 205 lError = RegQueryValueExW(hZoneKey, 206 L"Dlt", 207 NULL, 208 NULL, 209 (LPBYTE)DaylightName, 210 DaylightNameSize); 211 if (lError != ERROR_SUCCESS) 212 *DaylightName = 0; 213 } 214 215 return ERROR_SUCCESS; 216 } 217 218 // 219 // NOTE: Very similar to the EnumDynamicTimeZoneInformation() function 220 // introduced in Windows 8. 221 // 222 VOID 223 EnumerateTimeZoneList( 224 IN PENUM_TIMEZONE_CALLBACK Callback, 225 IN PVOID Context OPTIONAL) 226 { 227 LONG lError; 228 HKEY hZonesKey; 229 HKEY hZoneKey; 230 DWORD dwIndex; 231 DWORD dwNameSize; 232 WCHAR szKeyName[256]; 233 234 /* Open the registry key containing the list of time zones */ 235 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 236 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 237 0, 238 KEY_ENUMERATE_SUB_KEYS, 239 &hZonesKey); 240 if (lError != ERROR_SUCCESS) 241 return; 242 243 /* Enumerate it */ 244 for (dwIndex = 0; ; dwIndex++) 245 { 246 dwNameSize = sizeof(szKeyName); 247 lError = RegEnumKeyExW(hZonesKey, 248 dwIndex, 249 szKeyName, 250 &dwNameSize, 251 NULL, 252 NULL, 253 NULL, 254 NULL); 255 // if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA) 256 if (lError == ERROR_NO_MORE_ITEMS) 257 break; 258 259 /* Open the time zone sub-key */ 260 if (RegOpenKeyExW(hZonesKey, 261 szKeyName, 262 0, 263 KEY_QUERY_VALUE, 264 &hZoneKey)) 265 { 266 /* We failed, continue with another sub-key */ 267 continue; 268 } 269 270 /* Call the user-provided callback */ 271 lError = Callback(hZoneKey, Context); 272 // lError = QueryTimeZoneData(hZoneKey, Context); 273 274 RegCloseKey(hZoneKey); 275 } 276 277 RegCloseKey(hZonesKey); 278 } 279 280 // Returns TRUE if AutoDaylight is ON. 281 // Returns FALSE if AutoDaylight is OFF. 282 BOOL 283 GetAutoDaylight(VOID) 284 { 285 LONG lError; 286 HKEY hKey; 287 DWORD dwType; 288 DWORD dwDisabled; 289 DWORD dwValueSize; 290 291 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 292 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", 293 0, 294 KEY_QUERY_VALUE, 295 &hKey); 296 if (lError != ERROR_SUCCESS) 297 return FALSE; 298 299 // NOTE: On Vista+: REG_DWORD "DynamicDaylightTimeDisabled" 300 dwValueSize = sizeof(dwDisabled); 301 lError = RegQueryValueExW(hKey, 302 L"DisableAutoDaylightTimeSet", 303 NULL, 304 &dwType, 305 (LPBYTE)&dwDisabled, 306 &dwValueSize); 307 308 RegCloseKey(hKey); 309 310 if ((lError != ERROR_SUCCESS) || (dwType != REG_DWORD) || (dwValueSize != sizeof(dwDisabled))) 311 { 312 /* 313 * The call failed (non zero) because the registry value isn't available, 314 * which means auto-daylight shouldn't be disabled. 315 */ 316 dwDisabled = FALSE; 317 } 318 319 return !dwDisabled; 320 } 321 322 VOID 323 SetAutoDaylight( 324 IN BOOL EnableAutoDaylightTime) 325 { 326 LONG lError; 327 HKEY hKey; 328 DWORD dwDisabled = TRUE; 329 330 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 331 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", 332 0, 333 KEY_SET_VALUE, 334 &hKey); 335 if (lError != ERROR_SUCCESS) 336 return; 337 338 if (!EnableAutoDaylightTime) 339 { 340 /* Auto-Daylight disabled: set the value to TRUE */ 341 // NOTE: On Vista+: REG_DWORD "DynamicDaylightTimeDisabled" 342 RegSetValueExW(hKey, 343 L"DisableAutoDaylightTimeSet", 344 0, 345 REG_DWORD, 346 (LPBYTE)&dwDisabled, 347 sizeof(dwDisabled)); 348 } 349 else 350 { 351 /* Auto-Daylight enabled: just delete the value */ 352 RegDeleteValueW(hKey, L"DisableAutoDaylightTimeSet"); 353 } 354 355 RegCloseKey(hKey); 356 } 357