1 /* 2 * PROJECT: ReactOS Timedate Control Panel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/timedate/dateandtime.c 5 * PURPOSE: Date & Time property page 6 * COPYRIGHT: Copyright 2004-2007 Eric Kohl 7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com> 8 * Copyright 2006 Thomas Weidenmueller <w3seek@reactos.com> 9 * 10 */ 11 12 #include "timedate.h" 13 14 static WNDPROC pOldWndProc = NULL; 15 16 BOOL 17 SystemSetTime(LPSYSTEMTIME lpSystemTime, 18 BOOL SystemTime) 19 { 20 HANDLE hToken; 21 DWORD PrevSize; 22 TOKEN_PRIVILEGES priv, previouspriv; 23 BOOL Ret = FALSE; 24 25 /* 26 * Enable the SeSystemtimePrivilege privilege 27 */ 28 29 if (OpenProcessToken(GetCurrentProcess(), 30 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 31 &hToken)) 32 { 33 priv.PrivilegeCount = 1; 34 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 35 36 if (LookupPrivilegeValueW(NULL, 37 SE_SYSTEMTIME_NAME, 38 &priv.Privileges[0].Luid)) 39 { 40 if (AdjustTokenPrivileges(hToken, 41 FALSE, 42 &priv, 43 sizeof(previouspriv), 44 &previouspriv, 45 &PrevSize) && 46 GetLastError() == ERROR_SUCCESS) 47 { 48 /* 49 * We successfully enabled it, we're permitted to change the time. 50 * Check the second parameter for SystemTime and if TRUE set System Time. 51 * Otherwise, if FALSE set the Local Time. 52 * Call SetLocalTime twice to ensure correct results. 53 */ 54 if (SystemTime) 55 { 56 Ret = SetSystemTime(lpSystemTime); 57 } 58 else 59 { 60 Ret = SetLocalTime(lpSystemTime) && 61 SetLocalTime(lpSystemTime); 62 } 63 64 /* 65 * For the sake of security, restore the previous status again 66 */ 67 if (previouspriv.PrivilegeCount > 0) 68 { 69 AdjustTokenPrivileges(hToken, 70 FALSE, 71 &previouspriv, 72 0, 73 NULL, 74 0); 75 } 76 } 77 } 78 CloseHandle(hToken); 79 } 80 81 return Ret; 82 } 83 84 85 static VOID 86 SetLocalSystemTime(HWND hwnd) 87 { 88 SYSTEMTIME Time; 89 90 if (DateTime_GetSystemtime(GetDlgItem(hwnd, 91 IDC_TIMEPICKER), 92 &Time) == GDT_VALID && 93 SendMessageW(GetDlgItem(hwnd, 94 IDC_MONTHCALENDAR), 95 MCCM_GETDATE, 96 (WPARAM)&Time, 97 0)) 98 { 99 /* Set Local Time with SystemTime = FALSE */ 100 SystemSetTime(&Time, FALSE); 101 102 SetWindowLongPtrW(hwnd, 103 DWLP_MSGRESULT, 104 PSNRET_NOERROR); 105 106 SendMessageW(GetDlgItem(hwnd, 107 IDC_MONTHCALENDAR), 108 MCCM_RESET, 109 (WPARAM)&Time, 110 0); 111 112 /* Broadcast the time change message */ 113 SendMessageW(HWND_BROADCAST, 114 WM_TIMECHANGE, 115 0, 116 0); 117 } 118 } 119 120 121 static VOID 122 SetTimeZoneName(HWND hwnd) 123 { 124 TIME_ZONE_INFORMATION TimeZoneInfo; 125 WCHAR TimeZoneString[128]; 126 WCHAR TimeZoneText[128]; 127 WCHAR TimeZoneName[128]; 128 DWORD TimeZoneId; 129 130 TimeZoneId = GetTimeZoneInformation(&TimeZoneInfo); 131 132 LoadStringW(hApplet, IDS_TIMEZONETEXT, TimeZoneText, 128); 133 134 switch (TimeZoneId) 135 { 136 case TIME_ZONE_ID_STANDARD: 137 case TIME_ZONE_ID_UNKNOWN: 138 wcscpy(TimeZoneName, TimeZoneInfo.StandardName); 139 break; 140 141 case TIME_ZONE_ID_DAYLIGHT: 142 wcscpy(TimeZoneName, TimeZoneInfo.DaylightName); 143 break; 144 145 case TIME_ZONE_ID_INVALID: 146 default: 147 LoadStringW(hApplet, IDS_TIMEZONEINVALID, TimeZoneName, 128); 148 break; 149 } 150 151 wsprintfW(TimeZoneString, TimeZoneText, TimeZoneName); 152 SendDlgItemMessageW(hwnd, IDC_TIMEZONE, WM_SETTEXT, 0, (LPARAM)TimeZoneString); 153 } 154 155 156 static VOID 157 FillMonthsComboBox(HWND hCombo) 158 { 159 SYSTEMTIME LocalDate = {0}; 160 WCHAR szBuf[64]; 161 INT i; 162 UINT Month; 163 164 GetLocalTime(&LocalDate); 165 166 SendMessageW(hCombo, 167 CB_RESETCONTENT, 168 0, 169 0); 170 171 for (Month = 1; 172 Month <= 13; 173 Month++) 174 { 175 i = GetLocaleInfoW(LOCALE_USER_DEFAULT, 176 ((Month < 13) ? LOCALE_SMONTHNAME1 + Month - 1 : LOCALE_SMONTHNAME13), 177 szBuf, 178 sizeof(szBuf) / sizeof(szBuf[0])); 179 if (i > 1) 180 { 181 i = (INT)SendMessageW(hCombo, 182 CB_ADDSTRING, 183 0, 184 (LPARAM)szBuf); 185 if (i != CB_ERR) 186 { 187 SendMessageW(hCombo, 188 CB_SETITEMDATA, 189 (WPARAM)i, 190 Month); 191 192 if (Month == (UINT)LocalDate.wMonth) 193 { 194 SendMessageW(hCombo, 195 CB_SETCURSEL, 196 (WPARAM)i, 197 0); 198 } 199 } 200 } 201 } 202 } 203 204 205 static WORD 206 GetCBSelectedMonth(HWND hCombo) 207 { 208 INT i; 209 WORD Ret = (WORD)-1; 210 211 i = (INT)SendMessageW(hCombo, 212 CB_GETCURSEL, 213 0, 214 0); 215 if (i != CB_ERR) 216 { 217 i = (INT)SendMessageW(hCombo, 218 CB_GETITEMDATA, 219 (WPARAM)i, 220 0); 221 222 if (i >= 1 && i <= 13) 223 Ret = (WORD)i; 224 } 225 226 return Ret; 227 } 228 229 230 static VOID 231 ChangeMonthCalDate(HWND hMonthCal, 232 WORD Day, 233 WORD Month, 234 WORD Year) 235 { 236 SendMessageW(hMonthCal, 237 MCCM_SETDATE, 238 MAKEWPARAM(Day, 239 Month), 240 MAKELPARAM(Year, 241 0)); 242 } 243 244 static VOID 245 AutoUpdateMonthCal(HWND hwndDlg, 246 PNMMCCAUTOUPDATE lpAutoUpdate) 247 { 248 UNREFERENCED_PARAMETER(lpAutoUpdate); 249 250 /* Update the controls */ 251 FillMonthsComboBox(GetDlgItem(hwndDlg, 252 IDC_MONTHCB)); 253 } 254 255 256 static INT_PTR CALLBACK 257 DTPProc(HWND hwnd, 258 UINT uMsg, 259 WPARAM wParam, 260 LPARAM lParam) 261 { 262 switch (uMsg) 263 { 264 case WM_KEYDOWN: 265 /* Stop the timer when the user is about to change the time */ 266 if ((wParam != VK_LEFT) & (wParam != VK_RIGHT)) 267 KillTimer(GetParent(hwnd), ID_TIMER); 268 break; 269 } 270 271 return CallWindowProcW(pOldWndProc, hwnd, uMsg, wParam, lParam); 272 } 273 274 /* Property page dialog callback */ 275 INT_PTR CALLBACK 276 DateTimePageProc(HWND hwndDlg, 277 UINT uMsg, 278 WPARAM wParam, 279 LPARAM lParam) 280 { 281 SYSTEMTIME st; 282 GetLocalTime(&st); 283 284 switch (uMsg) 285 { 286 case WM_INITDIALOG: 287 FillMonthsComboBox(GetDlgItem(hwndDlg, 288 IDC_MONTHCB)); 289 290 SetTimer(hwndDlg, ID_TIMER, 1000, NULL); 291 292 /* Set range and current year */ 293 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETRANGE, 0, MAKELONG ((short) 9999, (short) 1900)); 294 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETPOS, 0, MAKELONG( (short) st.wYear, 0)); 295 296 pOldWndProc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), GWLP_WNDPROC, (LONG_PTR)DTPProc); 297 break; 298 299 case WM_TIMER: 300 SendMessageW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM) &st); 301 break; 302 303 case WM_COMMAND: 304 switch (LOWORD(wParam)) 305 { 306 case IDC_MONTHCB: 307 if (HIWORD(wParam) == CBN_SELCHANGE) 308 { 309 ChangeMonthCalDate(GetDlgItem(hwndDlg, 310 IDC_MONTHCALENDAR), 311 (WORD) -1, 312 GetCBSelectedMonth((HWND)lParam), 313 (WORD) -1); 314 } 315 break; 316 } 317 break; 318 319 case WM_CTLCOLORSTATIC: 320 if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_YEARTEXT)) 321 return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); 322 break; 323 324 case WM_NOTIFY: 325 { 326 LPNMHDR lpnm = (LPNMHDR)lParam; 327 328 switch (lpnm->idFrom) 329 { 330 case IDC_YEAR: 331 switch (lpnm->code) 332 { 333 case UDN_DELTAPOS: 334 { 335 SHORT wYear; 336 LPNMUPDOWN updown = (LPNMUPDOWN)lpnm; 337 wYear = (SHORT)SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_GETPOS, 0, 0); 338 /* Enable the 'Apply' button */ 339 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 340 ChangeMonthCalDate(GetDlgItem(hwndDlg, 341 IDC_MONTHCALENDAR), 342 (WORD) -1, 343 (WORD) -1, 344 (WORD) (wYear + updown->iDelta)); 345 } 346 break; 347 } 348 break; 349 350 case IDC_TIMEPICKER: 351 switch (lpnm->code) 352 { 353 case DTN_DATETIMECHANGE: 354 /* Stop the timer */ 355 KillTimer(hwndDlg, ID_TIMER); 356 357 /* Tell the clock to stop ticking */ 358 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STOPCLOCK, 359 0, 0); 360 361 /* Enable the 'Apply' button */ 362 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 363 break; 364 } 365 break; 366 367 case IDC_MONTHCALENDAR: 368 switch (lpnm->code) 369 { 370 case MCCN_SELCHANGE: 371 /* Enable the 'Apply' button */ 372 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 373 break; 374 375 case MCCN_AUTOUPDATE: 376 AutoUpdateMonthCal(hwndDlg, 377 (PNMMCCAUTOUPDATE)lpnm); 378 break; 379 } 380 break; 381 382 default: 383 switch (lpnm->code) 384 { 385 case PSN_SETACTIVE: 386 SetTimeZoneName(hwndDlg); 387 break; 388 389 case PSN_APPLY: 390 SetLocalSystemTime(hwndDlg); 391 SetTimer(hwndDlg, ID_TIMER, 1000, NULL); 392 393 /* Tell the clock to start ticking */ 394 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STARTCLOCK, 395 0, 0); 396 return TRUE; 397 } 398 break; 399 } 400 } 401 break; 402 403 case WM_TIMECHANGE: 404 /* FIXME: We don't get this message as we're not a top-level window... */ 405 SendMessageW(GetDlgItem(hwndDlg, 406 IDC_MONTHCALENDAR), 407 MCCM_RESET, 408 0, 409 0); 410 break; 411 412 case WM_DESTROY: 413 KillTimer(hwndDlg, ID_TIMER); 414 break; 415 } 416 417 return FALSE; 418 } 419