74fa262ad7cd96696f9dd225ad316ba9e33c7f91
[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: timedate.c,v 1.3 2004/11/08 10:33:08 ekohl Exp $
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 /* Property page dialog callback */
76 INT_PTR CALLBACK
77 DateTimePageProc(HWND hwndDlg,
78 UINT uMsg,
79 WPARAM wParam,
80 LPARAM lParam)
81 {
82 switch (uMsg)
83 {
84 case WM_INITDIALOG:
85 {
86 TIME_ZONE_INFORMATION TimeZoneInfo;
87
88 GetTimeZoneInformation(&TimeZoneInfo);
89
90 SendDlgItemMessageW(hwndDlg, IDC_TIMEZONE, WM_SETTEXT, 0, (LPARAM)TimeZoneInfo.StandardName);
91 }
92 break;
93
94 case WM_NOTIFY:
95 {
96 LPNMHDR lpnm = (LPNMHDR)lParam;
97
98 switch (lpnm->code)
99 {
100 case DTN_DATETIMECHANGE:
101 case MCN_SELECT:
102 /* Enable the 'Apply' button */
103 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
104 break;
105
106 default:
107 break;
108 }
109
110 }
111 break;
112 }
113
114 return FALSE;
115 }
116
117
118 static PTIMEZONE_ENTRY
119 GetLargerTimeZoneEntry(DWORD Index)
120 {
121 PTIMEZONE_ENTRY Entry;
122
123 Entry = TimeZoneListHead;
124 while (Entry != NULL)
125 {
126 if (Entry->Index >= Index)
127 return Entry;
128
129 Entry = Entry->Next;
130 }
131
132 return NULL;
133 }
134
135
136 static VOID
137 CreateTimeZoneList(VOID)
138 {
139 WCHAR szKeyName[256];
140 DWORD dwIndex;
141 DWORD dwNameSize;
142 DWORD dwValueSize;
143 LONG lError;
144 HKEY hZonesKey;
145 HKEY hZoneKey;
146
147 PTIMEZONE_ENTRY Entry;
148 PTIMEZONE_ENTRY Current;
149
150 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
151 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
152 0,
153 KEY_ALL_ACCESS,
154 &hZonesKey))
155 return;
156
157 dwIndex = 0;
158 while (TRUE)
159 {
160 dwNameSize = 256;
161 lError = RegEnumKeyExW(hZonesKey,
162 dwIndex,
163 szKeyName,
164 &dwNameSize,
165 NULL,
166 NULL,
167 NULL,
168 NULL);
169 if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA)
170 break;
171
172 if (RegOpenKeyExW(hZonesKey,
173 szKeyName,
174 0,
175 KEY_ALL_ACCESS,
176 &hZoneKey))
177 break;
178
179 Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY));
180 if (Entry == NULL)
181 {
182 RegCloseKey(hZoneKey);
183 break;
184 }
185
186 dwValueSize = 64 * sizeof(WCHAR);
187 if (RegQueryValueExW(hZoneKey,
188 L"Display",
189 NULL,
190 NULL,
191 (LPBYTE)&Entry->Description,
192 &dwValueSize))
193 {
194 RegCloseKey(hZoneKey);
195 break;
196 }
197
198 dwValueSize = 32 * sizeof(WCHAR);
199 if (RegQueryValueExW(hZoneKey,
200 L"Std",
201 NULL,
202 NULL,
203 (LPBYTE)&Entry->StandardName,
204 &dwValueSize))
205 {
206 RegCloseKey(hZoneKey);
207 break;
208 }
209
210 dwValueSize = 32 * sizeof(WCHAR);
211 if (RegQueryValueExW(hZoneKey,
212 L"Dlt",
213 NULL,
214 NULL,
215 (LPBYTE)&Entry->DaylightName,
216 &dwValueSize))
217 {
218 RegCloseKey(hZoneKey);
219 break;
220 }
221
222 dwValueSize = sizeof(DWORD);
223 if (RegQueryValueExW(hZoneKey,
224 L"Index",
225 NULL,
226 NULL,
227 (LPBYTE)&Entry->Index,
228 &dwValueSize))
229 {
230 RegCloseKey(hZoneKey);
231 break;
232 }
233
234 dwValueSize = sizeof(TZ_INFO);
235 if (RegQueryValueExW(hZoneKey,
236 L"TZI",
237 NULL,
238 NULL,
239 (LPBYTE)&Entry->TimezoneInfo,
240 &dwValueSize))
241 {
242 RegCloseKey(hZoneKey);
243 break;
244 }
245
246 RegCloseKey(hZoneKey);
247
248 if (TimeZoneListHead == NULL &&
249 TimeZoneListTail == NULL)
250 {
251 Entry->Prev = NULL;
252 Entry->Next = NULL;
253 TimeZoneListHead = Entry;
254 TimeZoneListTail = Entry;
255 }
256 else
257 {
258 Current = GetLargerTimeZoneEntry(Entry->Index);
259 if (Current != NULL)
260 {
261 if (Current == TimeZoneListHead)
262 {
263 /* Prepend to head */
264 Entry->Prev = NULL;
265 Entry->Next = TimeZoneListHead;
266 TimeZoneListHead->Prev = Entry;
267 TimeZoneListHead = Entry;
268 }
269 else
270 {
271 /* Insert before current */
272 Entry->Prev = Current->Prev;
273 Entry->Next = Current;
274 Current->Prev->Next = Entry;
275 Current->Prev = Entry;
276 }
277 }
278 else
279 {
280 /* Append to tail */
281 Entry->Prev = TimeZoneListTail;
282 Entry->Next = NULL;
283 TimeZoneListTail->Next = Entry;
284 TimeZoneListTail = Entry;
285 }
286 }
287
288 dwIndex++;
289 }
290
291 RegCloseKey(hZonesKey);
292 }
293
294
295 static VOID
296 DestroyTimeZoneList(VOID)
297 {
298 PTIMEZONE_ENTRY Entry;
299
300 while (TimeZoneListHead != NULL)
301 {
302 Entry = TimeZoneListHead;
303
304 TimeZoneListHead = Entry->Next;
305 if (TimeZoneListHead != NULL)
306 {
307 TimeZoneListHead->Prev = NULL;
308 }
309
310 HeapFree(GetProcessHeap(), 0, Entry);
311 }
312
313 TimeZoneListTail = NULL;
314 }
315
316
317 static VOID
318 ShowTimeZoneList(HWND hwnd)
319 {
320 TIME_ZONE_INFORMATION TimeZoneInfo;
321 PTIMEZONE_ENTRY Entry;
322 DWORD dwIndex;
323 DWORD i;
324
325 GetTimeZoneInformation(&TimeZoneInfo);
326
327 dwIndex = 0;
328 i = 0;
329 Entry = TimeZoneListHead;
330 while (Entry != NULL)
331 {
332 SendMessageW(hwnd,
333 CB_ADDSTRING,
334 0,
335 (LPARAM)Entry->Description);
336
337 if (!wcscmp(Entry->StandardName, TimeZoneInfo.StandardName))
338 dwIndex = i;
339
340 i++;
341 Entry = Entry->Next;
342 }
343
344 SendMessageW(hwnd,
345 CB_SETCURSEL,
346 (WPARAM)dwIndex,
347 0);
348 }
349
350
351 /* Property page dialog callback */
352 INT_PTR CALLBACK
353 TimeZonePageProc(HWND hwndDlg,
354 UINT uMsg,
355 WPARAM wParam,
356 LPARAM lParam)
357 {
358 switch (uMsg)
359 {
360 case WM_INITDIALOG:
361 CreateTimeZoneList();
362 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST));
363 break;
364
365 case WM_COMMAND:
366 if ((LOWORD(wParam) == IDC_TIMEZONELIST && HIWORD(wParam) == CBN_SELCHANGE) ||
367 (LOWORD(wParam) == IDC_AUTOADJUST && HIWORD(wParam) == BN_CLICKED))
368 {
369 /* Enable the 'Apply' button */
370 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
371 }
372 break;
373
374 case WM_DESTROY:
375 DestroyTimeZoneList();
376 break;
377 }
378
379 return FALSE;
380 }
381
382
383 static VOID
384 InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc)
385 {
386 ZeroMemory(psp, sizeof(PROPSHEETPAGE));
387 psp->dwSize = sizeof(PROPSHEETPAGE);
388 psp->dwFlags = PSP_DEFAULT;
389 psp->hInstance = hApplet;
390 psp->pszTemplate = MAKEINTRESOURCE(idDlg);
391 psp->pfnDlgProc = DlgProc;
392 }
393
394
395 LONG APIENTRY
396 Applet(HWND hwnd, UINT uMsg, LONG wParam, LONG lParam)
397 {
398 PROPSHEETHEADER psh;
399 PROPSHEETPAGE psp[3];
400 TCHAR Caption[256];
401
402 LoadString(hApplet, IDS_CPLNAME, Caption, sizeof(Caption) / sizeof(TCHAR));
403
404 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
405 psh.dwSize = sizeof(PROPSHEETHEADER);
406 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE;
407 psh.hwndParent = NULL;
408 psh.hInstance = hApplet;
409 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDC_CPLICON));
410 psh.pszCaption = Caption;
411 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
412 psh.nStartPage = 0;
413 psh.ppsp = psp;
414
415 InitPropSheetPage(&psp[0], IDD_DATETIMEPAGE, DateTimePageProc);
416 InitPropSheetPage(&psp[1], IDD_TIMEZONEPAGE, TimeZonePageProc);
417
418 return (LONG)(PropertySheet(&psh) != -1);
419 }
420
421
422 /* Control Panel Callback */
423 LONG CALLBACK
424 CPlApplet(HWND hwndCpl,
425 UINT uMsg,
426 LPARAM lParam1,
427 LPARAM lParam2)
428 {
429 int i = (int)lParam1;
430
431 switch (uMsg)
432 {
433 case CPL_INIT:
434 return TRUE;
435
436 case CPL_GETCOUNT:
437 return NUM_APPLETS;
438
439 case CPL_INQUIRE:
440 {
441 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
442 CPlInfo->lData = 0;
443 CPlInfo->idIcon = Applets[i].idIcon;
444 CPlInfo->idName = Applets[i].idName;
445 CPlInfo->idInfo = Applets[i].idDescription;
446 break;
447 }
448
449 case CPL_DBLCLK:
450 {
451 Applets[i].AppletProc(hwndCpl, uMsg, lParam1, lParam2);
452 break;
453 }
454 }
455 return FALSE;
456 }
457
458
459 BOOL STDCALL
460 DllMain(HINSTANCE hinstDLL,
461 DWORD dwReason,
462 LPVOID lpReserved)
463 {
464 switch (dwReason)
465 {
466 case DLL_PROCESS_ATTACH:
467 {
468 INITCOMMONCONTROLSEX InitControls;
469
470 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
471 InitControls.dwICC = ICC_DATE_CLASSES | ICC_PROGRESS_CLASS | ICC_UPDOWN_CLASS;
472 InitCommonControlsEx(&InitControls);
473
474 hApplet = hinstDLL;
475 }
476 break;
477 }
478
479 return TRUE;
480 }
481
482 /* EOF */