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 SetTimer(hwndDlg, ID_TIMER, 1000, NULL); 280 281 /* Set range and current year */ 282 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETRANGE, 0, MAKELONG ((short) 9999, (short) 1900)); 283 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETPOS, 0, MAKELONG( (short) st.wYear, 0)); 284 285 pOldWndProc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), GWLP_WNDPROC, (LONG_PTR)DTPProc); 286 break; 287 288 case WM_TIMER: 289 SendMessageW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM) &st); 290 break; 291 292 case WM_COMMAND: 293 switch (LOWORD(wParam)) 294 { 295 case IDC_MONTHCB: 296 if (HIWORD(wParam) == CBN_SELCHANGE) 297 { 298 ChangeMonthCalDate(GetDlgItem(hwndDlg, 299 IDC_MONTHCALENDAR), 300 (WORD) -1, 301 GetCBSelectedMonth((HWND)lParam), 302 (WORD) -1); 303 } 304 break; 305 } 306 break; 307 308 case WM_CTLCOLORSTATIC: 309 if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_YEARTEXT)) 310 return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); 311 break; 312 313 case WM_NOTIFY: 314 { 315 LPNMHDR lpnm = (LPNMHDR)lParam; 316 317 switch (lpnm->idFrom) 318 { 319 case IDC_YEAR: 320 switch (lpnm->code) 321 { 322 case UDN_DELTAPOS: 323 { 324 SHORT wYear; 325 LPNMUPDOWN updown = (LPNMUPDOWN)lpnm; 326 wYear = (SHORT)SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_GETPOS, 0, 0); 327 /* Enable the 'Apply' button */ 328 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 329 ChangeMonthCalDate(GetDlgItem(hwndDlg, 330 IDC_MONTHCALENDAR), 331 (WORD) -1, 332 (WORD) -1, 333 (WORD) (wYear + updown->iDelta)); 334 } 335 break; 336 } 337 break; 338 339 case IDC_TIMEPICKER: 340 switch (lpnm->code) 341 { 342 case DTN_DATETIMECHANGE: 343 /* Stop the timer */ 344 KillTimer(hwndDlg, ID_TIMER); 345 346 /* Tell the clock to stop ticking */ 347 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STOPCLOCK, 348 0, 0); 349 350 /* Enable the 'Apply' button */ 351 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 352 break; 353 } 354 break; 355 356 case IDC_MONTHCALENDAR: 357 switch (lpnm->code) 358 { 359 case MCCN_SELCHANGE: 360 /* Enable the 'Apply' button */ 361 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 362 break; 363 364 case MCCN_AUTOUPDATE: 365 AutoUpdateMonthCal(hwndDlg, 366 (PNMMCCAUTOUPDATE)lpnm); 367 break; 368 } 369 break; 370 371 default: 372 switch (lpnm->code) 373 { 374 case PSN_SETACTIVE: 375 SetTimeZoneName(hwndDlg); 376 break; 377 378 case PSN_APPLY: 379 SetLocalSystemTime(hwndDlg); 380 SetTimer(hwndDlg, ID_TIMER, 1000, NULL); 381 382 /* Tell the clock to start ticking */ 383 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STARTCLOCK, 384 0, 0); 385 return TRUE; 386 } 387 break; 388 } 389 } 390 break; 391 392 case WM_TIMECHANGE: 393 /* FIXME: We don't get this message as we're not a top-level window... */ 394 SendMessageW(GetDlgItem(hwndDlg, 395 IDC_MONTHCALENDAR), 396 MCCM_RESET, 397 0, 398 0); 399 break; 400 401 case WM_DESTROY: 402 KillTimer(hwndDlg, ID_TIMER); 403 break; 404 } 405 406 return FALSE; 407 } 408