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