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