Put skeleton in place for 'internet time' tab in the 'date and time' control panel...
[reactos.git] / reactos / lib / cpl / timedate / timedate.c
1 /*
2 * ReactOS
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS Timedate Control Panel
22 * FILE: lib/cpl/timedate/timedate.c
23 * PURPOSE: ReactOS Timedate Control Panel
24 * PROGRAMMER: Eric Kohl
25 */
26
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <cpl.h>
30
31 #include "resource.h"
32 #include "timedate.h"
33
34
35 typedef struct _TZ_INFO
36 {
37 LONG Bias;
38 LONG StandardBias;
39 LONG DaylightBias;
40 SYSTEMTIME StandardDate;
41 SYSTEMTIME DaylightDate;
42 } TZ_INFO, *PTZ_INFO;
43
44 typedef struct _TIMEZONE_ENTRY
45 {
46 struct _TIMEZONE_ENTRY *Prev;
47 struct _TIMEZONE_ENTRY *Next;
48 WCHAR Description[64]; /* 'Display' */
49 WCHAR StandardName[32]; /* 'Std' */
50 WCHAR DaylightName[32]; /* 'Dlt' */
51 TZ_INFO TimezoneInfo; /* 'TZI' */
52 ULONG Index; /* 'Index ' */
53 } TIMEZONE_ENTRY, *PTIMEZONE_ENTRY;
54
55
56 #define NUM_APPLETS (1)
57
58 LONG APIENTRY
59 Applet(HWND hwnd, UINT uMsg, LONG wParam, LONG lParam);
60
61
62 HINSTANCE hApplet = 0;
63
64 PTIMEZONE_ENTRY TimeZoneListHead = NULL;
65 PTIMEZONE_ENTRY TimeZoneListTail = NULL;
66
67
68 /* Applets */
69 APPLET Applets[NUM_APPLETS] =
70 {
71 {IDC_CPLICON, IDS_CPLNAME, IDS_CPLDESCRIPTION, Applet}
72 };
73
74
75 static VOID
76 SetLocalSystemTime(HWND hwnd)
77 {
78 SYSTEMTIME Date;
79 SYSTEMTIME Time;
80
81 if (DateTime_GetSystemTime(GetDlgItem(hwnd, IDC_DATEPICKER), &Date) != GDT_VALID)
82 {
83 return;
84 }
85
86 if (DateTime_GetSystemTime(GetDlgItem(hwnd, IDC_TIMEPICKER), &Time) != GDT_VALID)
87 {
88 return;
89 }
90
91 Time.wYear = Date.wYear;
92 Time.wMonth = Date.wMonth;
93 Time.wDayOfWeek = Date.wDayOfWeek;
94 Time.wDay = Date.wDay;
95
96 SetLocalTime(&Time);
97 }
98
99
100 static VOID
101 SetTimeZoneName(HWND hwnd)
102 {
103 TIME_ZONE_INFORMATION TimeZoneInfo;
104 WCHAR TimeZoneString[128];
105 WCHAR TimeZoneText[128];
106 WCHAR TimeZoneName[128];
107 DWORD TimeZoneId;
108
109 TimeZoneId = GetTimeZoneInformation(&TimeZoneInfo);
110
111 LoadString(hApplet, IDS_TIMEZONETEXT, TimeZoneText, 128);
112
113 switch (TimeZoneId)
114 {
115 case TIME_ZONE_ID_STANDARD:
116 wcscpy(TimeZoneName, TimeZoneInfo.StandardName);
117 break;
118
119 case TIME_ZONE_ID_DAYLIGHT:
120 wcscpy(TimeZoneName, TimeZoneInfo.DaylightName);
121 break;
122
123 case TIME_ZONE_ID_UNKNOWN:
124 LoadString(hApplet, IDS_TIMEZONEUNKNOWN, TimeZoneName, 128);
125 break;
126
127 case TIME_ZONE_ID_INVALID:
128 default:
129 LoadString(hApplet, IDS_TIMEZONEINVALID, TimeZoneName, 128);
130 break;
131 }
132
133 wsprintf(TimeZoneString, TimeZoneText, TimeZoneName);
134 SendDlgItemMessageW(hwnd, IDC_TIMEZONE, WM_SETTEXT, 0, (LPARAM)TimeZoneString);
135 }
136
137
138 /* Property page dialog callback */
139 INT_PTR CALLBACK
140 DateTimePageProc(HWND hwndDlg,
141 UINT uMsg,
142 WPARAM wParam,
143 LPARAM lParam)
144 {
145 switch (uMsg)
146 {
147 case WM_NOTIFY:
148 {
149 LPNMHDR lpnm = (LPNMHDR)lParam;
150
151 switch (lpnm->code)
152 {
153 case DTN_DATETIMECHANGE:
154 case MCN_SELECT:
155 /* Enable the 'Apply' button */
156 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
157 break;
158
159 case PSN_SETACTIVE:
160 SetTimeZoneName(hwndDlg);
161 return 0;
162
163 case PSN_APPLY:
164 SetLocalSystemTime(hwndDlg);
165 SetWindowLong(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
166 return TRUE;
167
168 default:
169 break;
170 }
171 }
172 break;
173 }
174
175 return FALSE;
176 }
177
178
179
180
181 static PTIMEZONE_ENTRY
182 GetLargerTimeZoneEntry(DWORD Index)
183 {
184 PTIMEZONE_ENTRY Entry;
185
186 Entry = TimeZoneListHead;
187 while (Entry != NULL)
188 {
189 if (Entry->Index >= Index)
190 return Entry;
191
192 Entry = Entry->Next;
193 }
194
195 return NULL;
196 }
197
198
199 static VOID
200 CreateTimeZoneList(VOID)
201 {
202 WCHAR szKeyName[256];
203 DWORD dwIndex;
204 DWORD dwNameSize;
205 DWORD dwValueSize;
206 LONG lError;
207 HKEY hZonesKey;
208 HKEY hZoneKey;
209
210 PTIMEZONE_ENTRY Entry;
211 PTIMEZONE_ENTRY Current;
212
213 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
214 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
215 0,
216 KEY_ALL_ACCESS,
217 &hZonesKey))
218 return;
219
220 dwIndex = 0;
221 while (TRUE)
222 {
223 dwNameSize = 256;
224 lError = RegEnumKeyExW(hZonesKey,
225 dwIndex,
226 szKeyName,
227 &dwNameSize,
228 NULL,
229 NULL,
230 NULL,
231 NULL);
232 if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA)
233 break;
234
235 if (RegOpenKeyExW(hZonesKey,
236 szKeyName,
237 0,
238 KEY_ALL_ACCESS,
239 &hZoneKey))
240 break;
241
242 Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY));
243 if (Entry == NULL)
244 {
245 RegCloseKey(hZoneKey);
246 break;
247 }
248
249 dwValueSize = 64 * sizeof(WCHAR);
250 if (RegQueryValueExW(hZoneKey,
251 L"Display",
252 NULL,
253 NULL,
254 (LPBYTE)&Entry->Description,
255 &dwValueSize))
256 {
257 RegCloseKey(hZoneKey);
258 break;
259 }
260
261 dwValueSize = 32 * sizeof(WCHAR);
262 if (RegQueryValueExW(hZoneKey,
263 L"Std",
264 NULL,
265 NULL,
266 (LPBYTE)&Entry->StandardName,
267 &dwValueSize))
268 {
269 RegCloseKey(hZoneKey);
270 break;
271 }
272
273 dwValueSize = 32 * sizeof(WCHAR);
274 if (RegQueryValueExW(hZoneKey,
275 L"Dlt",
276 NULL,
277 NULL,
278 (LPBYTE)&Entry->DaylightName,
279 &dwValueSize))
280 {
281 RegCloseKey(hZoneKey);
282 break;
283 }
284
285 dwValueSize = sizeof(DWORD);
286 if (RegQueryValueExW(hZoneKey,
287 L"Index",
288 NULL,
289 NULL,
290 (LPBYTE)&Entry->Index,
291 &dwValueSize))
292 {
293 RegCloseKey(hZoneKey);
294 break;
295 }
296
297 dwValueSize = sizeof(TZ_INFO);
298 if (RegQueryValueExW(hZoneKey,
299 L"TZI",
300 NULL,
301 NULL,
302 (LPBYTE)&Entry->TimezoneInfo,
303 &dwValueSize))
304 {
305 RegCloseKey(hZoneKey);
306 break;
307 }
308
309 RegCloseKey(hZoneKey);
310
311 if (TimeZoneListHead == NULL &&
312 TimeZoneListTail == NULL)
313 {
314 Entry->Prev = NULL;
315 Entry->Next = NULL;
316 TimeZoneListHead = Entry;
317 TimeZoneListTail = Entry;
318 }
319 else
320 {
321 Current = GetLargerTimeZoneEntry(Entry->Index);
322 if (Current != NULL)
323 {
324 if (Current == TimeZoneListHead)
325 {
326 /* Prepend to head */
327 Entry->Prev = NULL;
328 Entry->Next = TimeZoneListHead;
329 TimeZoneListHead->Prev = Entry;
330 TimeZoneListHead = Entry;
331 }
332 else
333 {
334 /* Insert before current */
335 Entry->Prev = Current->Prev;
336 Entry->Next = Current;
337 Current->Prev->Next = Entry;
338 Current->Prev = Entry;
339 }
340 }
341 else
342 {
343 /* Append to tail */
344 Entry->Prev = TimeZoneListTail;
345 Entry->Next = NULL;
346 TimeZoneListTail->Next = Entry;
347 TimeZoneListTail = Entry;
348 }
349 }
350
351 dwIndex++;
352 }
353
354 RegCloseKey(hZonesKey);
355 }
356
357
358 static VOID
359 DestroyTimeZoneList(VOID)
360 {
361 PTIMEZONE_ENTRY Entry;
362
363 while (TimeZoneListHead != NULL)
364 {
365 Entry = TimeZoneListHead;
366
367 TimeZoneListHead = Entry->Next;
368 if (TimeZoneListHead != NULL)
369 {
370 TimeZoneListHead->Prev = NULL;
371 }
372
373 HeapFree(GetProcessHeap(), 0, Entry);
374 }
375
376 TimeZoneListTail = NULL;
377 }
378
379
380 static VOID
381 ShowTimeZoneList(HWND hwnd)
382 {
383 TIME_ZONE_INFORMATION TimeZoneInfo;
384 PTIMEZONE_ENTRY Entry;
385 DWORD dwIndex;
386 DWORD i;
387
388 GetTimeZoneInformation(&TimeZoneInfo);
389
390 dwIndex = 0;
391 i = 0;
392 Entry = TimeZoneListHead;
393 while (Entry != NULL)
394 {
395 SendMessageW(hwnd,
396 CB_ADDSTRING,
397 0,
398 (LPARAM)Entry->Description);
399
400 if (!wcscmp(Entry->StandardName, TimeZoneInfo.StandardName))
401 dwIndex = i;
402
403 i++;
404 Entry = Entry->Next;
405 }
406
407 SendMessageW(hwnd,
408 CB_SETCURSEL,
409 (WPARAM)dwIndex,
410 0);
411 }
412
413
414 static VOID
415 SetLocalTimeZone(HWND hwnd)
416 {
417 TIME_ZONE_INFORMATION TimeZoneInformation;
418 PTIMEZONE_ENTRY Entry;
419 DWORD dwIndex;
420 DWORD i;
421
422 dwIndex = SendMessage(hwnd,
423 CB_GETCURSEL,
424 0,
425 0);
426
427 i = 0;
428 Entry = TimeZoneListHead;
429 while (i < dwIndex)
430 {
431 if (Entry == NULL)
432 return;
433
434 i++;
435 Entry = Entry->Next;
436 }
437
438 wcscpy(TimeZoneInformation.StandardName,
439 Entry->StandardName);
440 wcscpy(TimeZoneInformation.DaylightName,
441 Entry->DaylightName);
442
443 TimeZoneInformation.Bias = Entry->TimezoneInfo.Bias;
444 TimeZoneInformation.StandardBias = Entry->TimezoneInfo.StandardBias;
445 TimeZoneInformation.DaylightBias = Entry->TimezoneInfo.DaylightBias;
446
447 memcpy(&TimeZoneInformation.StandardDate,
448 &Entry->TimezoneInfo.StandardDate,
449 sizeof(SYSTEMTIME));
450 memcpy(&TimeZoneInformation.DaylightDate,
451 &Entry->TimezoneInfo.DaylightDate,
452 sizeof(SYSTEMTIME));
453
454 /* Set time zone information */
455 SetTimeZoneInformation(&TimeZoneInformation);
456 }
457
458
459 static VOID
460 GetAutoDaylightInfo(HWND hwnd)
461 {
462 HKEY hKey;
463
464 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
465 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
466 0,
467 KEY_QUERY_VALUE,
468 &hKey))
469 return;
470
471 if (RegQueryValueExW(hKey,
472 L"DisableAutoDaylightTimeSet",
473 NULL,
474 NULL,
475 NULL,
476 NULL))
477 {
478 SendMessage(hwnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
479 }
480 else
481 {
482 SendMessage(hwnd, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
483 }
484
485 RegCloseKey(hKey);
486 }
487
488
489 static VOID
490 SetAutoDaylightInfo(HWND hwnd)
491 {
492 HKEY hKey;
493 DWORD dwValue = 1;
494
495 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
496 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
497 0,
498 KEY_SET_VALUE,
499 &hKey))
500 return;
501
502 if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_UNCHECKED)
503 {
504 RegSetValueExW(hKey,
505 L"DisableAutoDaylightTimeSet",
506 0,
507 REG_DWORD,
508 (LPBYTE)&dwValue,
509 sizeof(DWORD));
510 }
511 else
512 {
513 RegDeleteValueW(hKey,
514 L"DisableAutoDaylightTimeSet");
515 }
516
517 RegCloseKey(hKey);
518 }
519
520
521 /* Property page dialog callback */
522 INT_PTR CALLBACK
523 TimeZonePageProc(HWND hwndDlg,
524 UINT uMsg,
525 WPARAM wParam,
526 LPARAM lParam)
527 {
528 switch (uMsg)
529 {
530 case WM_INITDIALOG:
531 CreateTimeZoneList();
532 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST));
533 GetAutoDaylightInfo(GetDlgItem(hwndDlg, IDC_AUTODAYLIGHT));
534 break;
535
536 case WM_COMMAND:
537 if ((LOWORD(wParam) == IDC_TIMEZONELIST && HIWORD(wParam) == CBN_SELCHANGE) ||
538 (LOWORD(wParam) == IDC_AUTODAYLIGHT && HIWORD(wParam) == BN_CLICKED))
539 {
540 /* Enable the 'Apply' button */
541 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
542 }
543 break;
544
545 case WM_DESTROY:
546 DestroyTimeZoneList();
547 break;
548
549 case WM_NOTIFY:
550 {
551 LPNMHDR lpnm = (LPNMHDR)lParam;
552
553 switch (lpnm->code)
554 {
555 case PSN_APPLY:
556 SetAutoDaylightInfo(GetDlgItem(hwndDlg, IDC_AUTODAYLIGHT));
557 SetLocalTimeZone(GetDlgItem(hwndDlg, IDC_TIMEZONELIST));
558 SetWindowLong(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
559 return TRUE;
560
561 default:
562 break;
563 }
564
565 }
566 break;
567 }
568
569 return FALSE;
570 }
571
572
573 /* Property page dialog callback */
574 INT_PTR CALLBACK
575 InetTimePageProc(HWND hwndDlg,
576 UINT uMsg,
577 WPARAM wParam,
578 LPARAM lParam)
579 {
580 switch (uMsg)
581 {
582 case WM_INITDIALOG:
583 break;
584
585 case WM_COMMAND:
586 break;
587
588 case WM_DESTROY:
589 break;
590
591 case WM_NOTIFY:
592 {
593 switch (lParam)
594 {
595
596 default:
597 break;
598 }
599
600 }
601 break;
602 }
603
604 return FALSE;
605 }
606
607
608 static VOID
609 InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc)
610 {
611 ZeroMemory(psp, sizeof(PROPSHEETPAGE));
612 psp->dwSize = sizeof(PROPSHEETPAGE);
613 psp->dwFlags = PSP_DEFAULT;
614 psp->hInstance = hApplet;
615 psp->pszTemplate = MAKEINTRESOURCE(idDlg);
616 psp->pfnDlgProc = DlgProc;
617 }
618
619
620 LONG APIENTRY
621 Applet(HWND hwnd, UINT uMsg, LONG wParam, LONG lParam)
622 {
623 PROPSHEETHEADER psh;
624 PROPSHEETPAGE psp[3];
625 TCHAR Caption[256];
626
627 LoadString(hApplet, IDS_CPLNAME, Caption, sizeof(Caption) / sizeof(TCHAR));
628
629 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
630 psh.dwSize = sizeof(PROPSHEETHEADER);
631 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE;
632 psh.hwndParent = NULL;
633 psh.hInstance = hApplet;
634 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDC_CPLICON));
635 psh.pszCaption = Caption;
636 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
637 psh.nStartPage = 0;
638 psh.ppsp = psp;
639
640 InitPropSheetPage(&psp[0], IDD_DATETIMEPAGE, DateTimePageProc);
641 InitPropSheetPage(&psp[1], IDD_TIMEZONEPAGE, TimeZonePageProc);
642 InitPropSheetPage(&psp[2], IDD_INETTIMEPAGE, InetTimePageProc);
643
644 return (LONG)(PropertySheet(&psh) != -1);
645 }
646
647
648 /* Control Panel Callback */
649 LONG CALLBACK
650 CPlApplet(HWND hwndCpl,
651 UINT uMsg,
652 LPARAM lParam1,
653 LPARAM lParam2)
654 {
655 int i = (int)lParam1;
656
657 switch (uMsg)
658 {
659 case CPL_INIT:
660 return TRUE;
661
662 case CPL_GETCOUNT:
663 return NUM_APPLETS;
664
665 case CPL_INQUIRE:
666 {
667 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
668 CPlInfo->lData = 0;
669 CPlInfo->idIcon = Applets[i].idIcon;
670 CPlInfo->idName = Applets[i].idName;
671 CPlInfo->idInfo = Applets[i].idDescription;
672 break;
673 }
674
675 case CPL_DBLCLK:
676 {
677 Applets[i].AppletProc(hwndCpl, uMsg, lParam1, lParam2);
678 break;
679 }
680 }
681 return FALSE;
682 }
683
684
685 BOOL STDCALL
686 DllMain(HINSTANCE hinstDLL,
687 DWORD dwReason,
688 LPVOID lpReserved)
689 {
690 switch (dwReason)
691 {
692 case DLL_PROCESS_ATTACH:
693 {
694 INITCOMMONCONTROLSEX InitControls;
695
696 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
697 InitControls.dwICC = ICC_DATE_CLASSES | ICC_PROGRESS_CLASS | ICC_UPDOWN_CLASS;
698 InitCommonControlsEx(&InitControls);
699
700 hApplet = hinstDLL;
701 }
702 break;
703 }
704
705 return TRUE;
706 }
707
708 /* EOF */