1 /* 2 * PROJECT: ReactOS System Control Panel Applet 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/sysdm/general.c 5 * PURPOSE: General System Information 6 * COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org> 7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com> 8 * Copyright 2006-2007 Colin Finck <mail@colinfinck.de> 9 * 10 */ 11 12 #include "precomp.h" 13 14 #include <winnls.h> 15 #include <powrprof.h> 16 #include <buildno.h> 17 18 #define ANIM_STEP 2 19 #define ANIM_TIME 50 20 #define ID_SYSUPTIME_UPDATE_TIMER 1 21 22 typedef struct _IMGINFO 23 { 24 HBITMAP hBitmap; 25 INT cxSource; 26 INT cySource; 27 INT iPlanes; 28 INT iBits; 29 } IMGINFO, *PIMGINFO; 30 31 typedef ULONGLONG (WINAPI *PFGETTICKCOUNT64)(VOID); 32 33 static PIMGINFO pImgInfo; 34 static const BLENDFUNCTION BlendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; 35 static HMODULE hKernel32Vista = NULL; 36 static PFGETTICKCOUNT64 pGetTickCount64 = NULL; 37 static WCHAR szUptimeFormat[64]; 38 39 VOID ShowLastWin32Error(HWND hWndOwner) 40 { 41 LPTSTR lpMsg; 42 DWORD LastError; 43 44 LastError = GetLastError(); 45 if (LastError == ERROR_SUCCESS) 46 return; 47 48 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 49 FORMAT_MESSAGE_FROM_SYSTEM | 50 FORMAT_MESSAGE_IGNORE_INSERTS, 51 NULL, 52 LastError, 53 LANG_USER_DEFAULT, 54 (LPTSTR)&lpMsg, 55 0, NULL)) 56 { 57 return; 58 } 59 60 MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR); 61 LocalFree(lpMsg); 62 } 63 64 65 static VOID InitLogo(HWND hwndDlg) 66 { 67 BITMAP logoBitmap; 68 BITMAP maskBitmap; 69 BITMAPINFO bmpi; 70 HDC hDC, hDCLogo, hDCMask; 71 HBITMAP hMask = NULL, hLogo = NULL; 72 HBITMAP hAlphaLogo = NULL; 73 COLORREF *pBits; 74 INT line, column; 75 76 hDC = GetDC(hwndDlg); 77 hDCLogo = CreateCompatibleDC(NULL); 78 hDCMask = CreateCompatibleDC(NULL); 79 80 if (hDC == NULL || hDCLogo == NULL || hDCMask == NULL) 81 goto Cleanup; 82 83 ZeroMemory(pImgInfo, sizeof(*pImgInfo)); 84 ZeroMemory(&bmpi, sizeof(bmpi)); 85 86 hLogo = (HBITMAP)LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_ROSBMP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 87 hMask = (HBITMAP)LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_ROSMASK), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 88 89 if (hLogo == NULL || hMask == NULL) 90 goto Cleanup; 91 92 GetObject(hLogo, sizeof(logoBitmap), &logoBitmap); 93 GetObject(hMask, sizeof(maskBitmap), &maskBitmap); 94 95 if (logoBitmap.bmHeight != maskBitmap.bmHeight || logoBitmap.bmWidth != maskBitmap.bmWidth) 96 goto Cleanup; 97 98 bmpi.bmiHeader.biSize = sizeof(BITMAPINFO); 99 bmpi.bmiHeader.biWidth = logoBitmap.bmWidth; 100 bmpi.bmiHeader.biHeight = logoBitmap.bmHeight; 101 bmpi.bmiHeader.biPlanes = 1; 102 bmpi.bmiHeader.biBitCount = 32; 103 bmpi.bmiHeader.biCompression = BI_RGB; 104 bmpi.bmiHeader.biSizeImage = 4 * logoBitmap.bmWidth * logoBitmap.bmHeight; 105 106 /* Create a premultiplied bitmap */ 107 hAlphaLogo = CreateDIBSection(hDC, &bmpi, DIB_RGB_COLORS, (PVOID*)&pBits, 0, 0); 108 if (!hAlphaLogo) 109 goto Cleanup; 110 111 SelectObject(hDCLogo, hLogo); 112 SelectObject(hDCMask, hMask); 113 114 for (line = logoBitmap.bmHeight - 1; line >= 0; line--) 115 { 116 for (column = 0; column < logoBitmap.bmWidth; column++) 117 { 118 COLORREF alpha = GetPixel(hDCMask, column, line) & 0xFF; 119 COLORREF Color = GetPixel(hDCLogo, column, line); 120 DWORD r, g, b; 121 122 r = GetRValue(Color) * alpha / 255; 123 g = GetGValue(Color) * alpha / 255; 124 b = GetBValue(Color) * alpha / 255; 125 126 *pBits++ = b | (g << 8) | (r << 16) | (alpha << 24); 127 } 128 } 129 130 pImgInfo->hBitmap = hAlphaLogo; 131 pImgInfo->cxSource = logoBitmap.bmWidth; 132 pImgInfo->cySource = logoBitmap.bmHeight; 133 pImgInfo->iBits = logoBitmap.bmBitsPixel; 134 pImgInfo->iPlanes = logoBitmap.bmPlanes; 135 136 Cleanup: 137 if (hMask != NULL) DeleteObject(hMask); 138 if (hLogo != NULL) DeleteObject(hLogo); 139 if (hDCMask != NULL) DeleteDC(hDCMask); 140 if (hDCLogo != NULL) DeleteDC(hDCLogo); 141 if (hDC != NULL) ReleaseDC(hwndDlg, hDC); 142 } 143 144 LRESULT CALLBACK RosImageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 145 { 146 static UINT timerid = 0, top = 0, offset; 147 static HBITMAP hCreditsBitmap; 148 149 switch (uMsg) 150 { 151 case WM_LBUTTONDBLCLK: 152 if (wParam & (MK_CONTROL | MK_SHIFT)) 153 { 154 if (timerid == 0) 155 { 156 HDC hDC; 157 HDC hCreditsDC = NULL, hLogoDC = NULL; 158 HFONT hFont = NULL; 159 NONCLIENTMETRICS ncm; 160 RECT rcCredits; 161 TCHAR szCredits[2048]; 162 INT iDevsHeight; 163 164 hDC = GetDC(NULL); 165 if (hDC == NULL) 166 goto Cleanup; 167 168 top = 0; 169 offset = 0; 170 171 hCreditsDC = CreateCompatibleDC(hDC); 172 hLogoDC = CreateCompatibleDC(hCreditsDC); 173 174 if (hCreditsDC == NULL || hLogoDC == NULL) 175 goto Cleanup; 176 177 SetRect(&rcCredits, 0, 0, 0, 0); 178 179 ncm.cbSize = sizeof(NONCLIENTMETRICS); 180 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0); 181 182 hFont = CreateFontIndirect(&ncm.lfMessageFont); 183 if (!hFont) 184 goto Cleanup; 185 SelectObject(hCreditsDC, hFont); 186 187 LoadString(hApplet, IDS_DEVS, szCredits, sizeof(szCredits) / sizeof(TCHAR)); 188 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CALCRECT); 189 190 iDevsHeight = rcCredits.bottom - rcCredits.top; 191 192 hCreditsBitmap = CreateBitmap(pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1, pImgInfo->iPlanes, pImgInfo->iBits, NULL); 193 if (!hCreditsBitmap) 194 goto Cleanup; 195 196 SelectObject(hLogoDC, pImgInfo->hBitmap); 197 SelectObject(hCreditsDC, hCreditsBitmap); 198 199 offset += pImgInfo->cySource; 200 201 SetRect(&rcCredits, 0, 0, pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1); 202 FillRect(hCreditsDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 203 204 SetRect(&rcCredits, 0, offset, pImgInfo->cxSource, offset + iDevsHeight + 1); 205 SetBkMode(hCreditsDC, TRANSPARENT); 206 207 OffsetRect(&rcCredits, 1, 1); 208 SetTextColor(hCreditsDC, GetSysColor(COLOR_BTNSHADOW)); 209 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER); 210 211 OffsetRect(&rcCredits, -1, -1); 212 SetTextColor(hCreditsDC, GetSysColor(COLOR_WINDOWTEXT)); 213 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER); 214 215 offset += iDevsHeight; 216 217 AlphaBlend(hCreditsDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 218 AlphaBlend(hCreditsDC, 0, offset, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 219 220 timerid = SetTimer(hwnd, 1, ANIM_TIME, NULL); 221 222 Cleanup: 223 if (hFont != NULL) DeleteObject(hFont); 224 if (hLogoDC != NULL) DeleteDC(hLogoDC); 225 if (hCreditsDC != NULL) DeleteDC(hCreditsDC); 226 if (hDC != NULL) ReleaseDC(NULL, hDC); 227 } 228 } 229 break; 230 case WM_LBUTTONDOWN: 231 if (timerid) 232 { 233 RECT rcCredits; 234 HDC hDC = GetDC(hwnd); 235 if (hDC != NULL) 236 { 237 GetClientRect(hwnd, &rcCredits); 238 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource); 239 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 240 ReleaseDC(hwnd, hDC); 241 } 242 KillTimer(hwnd, timerid); 243 if (hCreditsBitmap != NULL) 244 DeleteObject(hCreditsBitmap); 245 246 InvalidateRect(hwnd, NULL, FALSE); 247 top = 0; 248 timerid = 0; 249 } 250 break; 251 case WM_TIMER: 252 top += ANIM_STEP; 253 254 if (top > offset) 255 { 256 RECT rcCredits; 257 HDC hDC = GetDC(hwnd); 258 if (hDC != NULL) 259 { 260 GetClientRect(hwnd, &rcCredits); 261 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource); 262 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 263 ReleaseDC(hwnd, hDC); 264 } 265 KillTimer(hwnd, timerid); 266 if (hCreditsBitmap != NULL) 267 DeleteObject(hCreditsBitmap); 268 269 top = 0; 270 timerid = 0; 271 } 272 273 InvalidateRect(hwnd, NULL, FALSE); 274 break; 275 case WM_PAINT: 276 { 277 PAINTSTRUCT PS; 278 HDC hdcMem, hdc; 279 LONG left; 280 281 hdc = wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &PS); 282 283 GetClientRect(hwnd, &PS.rcPaint); 284 285 /* Position image in center of dialog */ 286 left = (PS.rcPaint.right - pImgInfo->cxSource) / 2; 287 hdcMem = CreateCompatibleDC(hdc); 288 289 if (hdcMem != NULL) 290 { 291 if(timerid != 0) 292 { 293 SelectObject(hdcMem, hCreditsBitmap); 294 BitBlt(hdc, left, PS.rcPaint.top, PS.rcPaint.right - PS.rcPaint.left, PS.rcPaint.top + pImgInfo->cySource, hdcMem, 0, top, SRCCOPY); 295 } 296 else 297 { 298 SelectObject(hdcMem, pImgInfo->hBitmap); 299 AlphaBlend(hdc, left, PS.rcPaint.top, pImgInfo->cxSource, pImgInfo->cySource, hdcMem, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 300 } 301 302 DeleteDC(hdcMem); 303 } 304 305 if (wParam == 0) 306 EndPaint(hwnd,&PS); 307 break; 308 } 309 } 310 return TRUE; 311 } 312 313 static VOID SetRegTextData(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID) 314 { 315 LPTSTR lpBuf = NULL; 316 DWORD BufSize = 0; 317 DWORD Type; 318 319 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS) 320 { 321 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize); 322 323 if (!lpBuf) 324 return; 325 326 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS) 327 SetDlgItemText(hwnd, uID, lpBuf); 328 329 HeapFree(GetProcessHeap(), 0, lpBuf); 330 } 331 } 332 333 static INT SetProcNameString(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID1, UINT uID2) 334 { 335 LPTSTR lpBuf = NULL; 336 DWORD BufSize = 0; 337 DWORD Type; 338 INT Ret = 0; 339 TCHAR szBuf[31]; 340 TCHAR* szLastSpace; 341 INT LastSpace = 0; 342 343 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS) 344 { 345 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize); 346 347 if (!lpBuf) 348 return 0; 349 350 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS) 351 { 352 if (BufSize > ((30 + 1) * sizeof(TCHAR))) 353 { 354 /* Wrap the Processor Name String like XP does: * 355 * - Take the first 30 characters and look for the last space. * 356 * Then wrap the string after this space. * 357 * - If no space is found, wrap the string after character 30. * 358 * * 359 * For example the Processor Name String of a Pentium 4 is right-aligned. * 360 * With this wrapping the first line looks centered. */ 361 362 _tcsncpy(szBuf, lpBuf, 30); 363 szBuf[30] = 0; 364 szLastSpace = _tcsrchr(szBuf, ' '); 365 366 if (szLastSpace == 0) 367 { 368 LastSpace = 30; 369 } 370 else 371 { 372 LastSpace = (szLastSpace - szBuf); 373 szBuf[LastSpace] = 0; 374 } 375 376 _tcsncpy(szBuf, lpBuf, LastSpace); 377 378 SetDlgItemText(hwnd, uID1, szBuf); 379 SetDlgItemText(hwnd, uID2, lpBuf+LastSpace+1); 380 381 /* Return the number of used lines */ 382 Ret = 2; 383 } 384 else 385 { 386 SetDlgItemText(hwnd, uID1, lpBuf); 387 Ret = 1; 388 } 389 } 390 391 HeapFree(GetProcessHeap(), 0, lpBuf); 392 } 393 394 return Ret; 395 } 396 397 static VOID MakeFloatValueString(DOUBLE* dFloatValue, LPTSTR szOutput, LPTSTR szAppend) 398 { 399 TCHAR szDecimalSeparator[4]; 400 401 /* Get the decimal separator for the current locale */ 402 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0) 403 { 404 UCHAR uDecimals; 405 UINT uIntegral; 406 407 /* Show the value with two decimals */ 408 uIntegral = (UINT)*dFloatValue; 409 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100); 410 411 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend); 412 } 413 } 414 415 static VOID SetProcSpeed(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID) 416 { 417 TCHAR szBuf[64], szHz[16]; 418 DWORD BufSize = sizeof(DWORD); 419 DWORD Type = REG_SZ; 420 PROCESSOR_POWER_INFORMATION ppi; 421 422 ZeroMemory(&ppi, sizeof(ppi)); 423 424 if ((CallNtPowerInformation(ProcessorInformation, 425 NULL, 426 0, 427 (PVOID)&ppi, 428 sizeof(ppi)) == STATUS_SUCCESS && 429 ppi.CurrentMhz != 0) || RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)&ppi.CurrentMhz, &BufSize) == ERROR_SUCCESS) 430 { 431 if (ppi.CurrentMhz < 1000) 432 { 433 if (!LoadString(hApplet, IDS_MEGAHERTZ, szHz, _countof(szHz))) 434 { 435 return; 436 } 437 StringCchPrintf(szBuf, _countof(szBuf), _T("%lu %s"), ppi.CurrentMhz, szHz); 438 } 439 else 440 { 441 double flt = ppi.CurrentMhz / 1000.0; 442 if (!LoadString(hApplet, IDS_GIGAHERTZ, szHz, _countof(szHz))) 443 { 444 return; 445 } 446 MakeFloatValueString(&flt, szBuf, szHz); 447 } 448 449 SetDlgItemText(hwnd, uID, szBuf); 450 } 451 } 452 453 static VOID GetSystemInformation(HWND hwnd) 454 { 455 HKEY hKey; 456 TCHAR SysKey[] = _T("HARDWARE\\DESCRIPTION\\System"); 457 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); 458 MEMORYSTATUSEX MemStat; 459 TCHAR Buf[32]; 460 WCHAR SMBiosName[96]; 461 INT CurMachineLine = IDC_MACHINELINE1; 462 463 /* 464 * Get hardware device name or motherboard name 465 * using information from raw SMBIOS data 466 */ 467 if (GetSystemName(SMBiosName, _countof(SMBiosName))) 468 { 469 SetDlgItemText(hwnd, CurMachineLine, SMBiosName); 470 CurMachineLine++; 471 } 472 else 473 { 474 /* If SMBIOS is not available, use System Identifier */ 475 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SysKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 476 { 477 SetRegTextData(hwnd, hKey, _T("Identifier"), CurMachineLine); 478 CurMachineLine++; 479 RegCloseKey(hKey); 480 } 481 } 482 /* 483 * Get Processor information 484 * although undocumented, this information is being pulled 485 * directly out of the registry instead of via setupapi as it 486 * contains all the info we need, and should remain static 487 */ 488 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 489 { 490 INT PrevMachineLine; 491 492 SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine); 493 CurMachineLine++; 494 495 PrevMachineLine = CurMachineLine; 496 CurMachineLine += SetProcNameString(hwnd, 497 hKey, 498 _T("ProcessorNameString"), 499 CurMachineLine, 500 CurMachineLine + 1); 501 502 if (CurMachineLine == PrevMachineLine) 503 { 504 /* TODO: Try obtaining CPU name from WMI (i.e. CIM_Processor) */ 505 506 /* Brand String is not available, use Identifier instead */ 507 CurMachineLine += SetProcNameString(hwnd, 508 hKey, 509 _T("Identifier"), 510 CurMachineLine, 511 CurMachineLine + 1); 512 } 513 514 SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine); 515 CurMachineLine++; 516 RegCloseKey(hKey); 517 } 518 519 /* Get total physical RAM */ 520 MemStat.dwLength = sizeof(MemStat); 521 522 if (GlobalMemoryStatusEx(&MemStat)) 523 { 524 TCHAR szStr[32]; 525 double dTotalPhys; 526 527 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024) 528 { 529 UINT i = 0; 530 static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE}; 531 532 // We're dealing with GBs or more 533 MemStat.ullTotalPhys /= 1024 * 1024; 534 535 if (MemStat.ullTotalPhys > 1024 * 1024) 536 { 537 // We're dealing with TBs or more 538 MemStat.ullTotalPhys /= 1024; 539 i++; 540 541 if (MemStat.ullTotalPhys > 1024 * 1024) 542 { 543 // We're dealing with PBs or more 544 MemStat.ullTotalPhys /= 1024; 545 i++; 546 547 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 548 } 549 else 550 { 551 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 552 } 553 } 554 else 555 { 556 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 557 } 558 559 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR)); 560 MakeFloatValueString(&dTotalPhys, Buf, szStr); 561 } 562 else 563 { 564 // We're dealing with MBs, don't show any decimals 565 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR)); 566 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr); 567 } 568 569 SetDlgItemText(hwnd, CurMachineLine, Buf); 570 } 571 } 572 573 static VOID GetSystemVersion(HWND hwnd) 574 { 575 HWND hRosVersion; 576 SIZE_T lenStr, lenVersion; 577 PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC); 578 PWSTR pwszStr; 579 580 lenVersion = wcslen(pwszVersion); 581 if (lenVersion == 0) 582 { 583 return; 584 } 585 586 hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION); 587 if (!hRosVersion) 588 { 589 return; 590 } 591 lenStr = GetWindowTextLengthW(hRosVersion); 592 lenStr += lenVersion + 1; 593 pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR)); 594 if (!pwszStr) 595 { 596 return; 597 } 598 GetWindowText(hRosVersion, pwszStr, lenStr); 599 600 StringCchCatW(pwszStr, lenStr, pwszVersion); 601 SetWindowText(hRosVersion, pwszStr); 602 603 HeapFree(GetProcessHeap(), 0, pwszStr); 604 } 605 606 /** 607 * @brief 608 * An equivalent of GetTickCount64, implemented using QueryPerformanceCounter. 609 * 610 * @return 611 * The number of milliseconds that have elapsed since the system was started. 612 */ 613 static ULONGLONG GetTickCountQPC(VOID) 614 { 615 LARGE_INTEGER Counter, Frequency; 616 617 QueryPerformanceCounter(&Counter); 618 QueryPerformanceFrequency(&Frequency); 619 620 return (Counter.QuadPart * 1000) / Frequency.QuadPart; 621 } 622 623 static VOID GetSystemUptime(HWND hwndDlg) 624 { 625 HWND hUptimeLabel; 626 ULONGLONG cMilliseconds; 627 ULONG cSeconds; 628 WCHAR szBuf[64]; 629 630 hUptimeLabel = GetDlgItem(hwndDlg, IDC_UPTIME); 631 if (!hUptimeLabel) 632 { 633 return; 634 } 635 636 if (pGetTickCount64) 637 { 638 cMilliseconds = pGetTickCount64(); 639 } 640 else 641 { 642 cMilliseconds = GetTickCountQPC(); 643 } 644 645 cSeconds = cMilliseconds / 1000; 646 StringCchPrintfW(szBuf, _countof(szBuf), szUptimeFormat, 647 cSeconds / (60*60*24), // Days 648 (cSeconds / (60*60)) % 24, // Hours 649 (cSeconds / 60) % 60, // Minutes 650 cSeconds % 60); // Seconds 651 652 SetWindowTextW(hUptimeLabel, szBuf); 653 654 /* Set update timer (reset timeout if the timer exists) */ 655 SetTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER, 1000 - (cMilliseconds % 1000), NULL); 656 } 657 658 static VOID InitSystemUptime(HWND hwndDlg) 659 { 660 HMODULE hKernel32; 661 662 /* Load time format string */ 663 if (LoadStringW(hApplet, IDS_UPTIME_FORMAT, szUptimeFormat, _countof(szUptimeFormat)) == 0) 664 { 665 return; 666 } 667 668 /* Load required DLLs */ 669 hKernel32 = GetModuleHandleW(L"kernel32.dll"); 670 if (hKernel32) 671 { 672 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32, "GetTickCount64"); 673 if (!pGetTickCount64) 674 { 675 hKernel32Vista = LoadLibraryW(L"kernel32_vista.dll"); 676 if (hKernel32Vista) 677 { 678 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32Vista, "GetTickCount64"); 679 } 680 } 681 } 682 683 /* Show system uptime and set update timer */ 684 GetSystemUptime(hwndDlg); 685 } 686 687 /* Property page dialog callback */ 688 INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 689 { 690 UNREFERENCED_PARAMETER(lParam); 691 UNREFERENCED_PARAMETER(wParam); 692 693 switch (uMsg) 694 { 695 case WM_INITDIALOG: 696 { 697 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO)); 698 if (pImgInfo == NULL) 699 { 700 EndDialog(hwndDlg, 0); 701 return FALSE; 702 } 703 704 InitLogo(hwndDlg); 705 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc); 706 GetSystemInformation(hwndDlg); 707 GetSystemVersion(hwndDlg); 708 InitSystemUptime(hwndDlg); 709 break; 710 } 711 712 case WM_DESTROY: 713 { 714 KillTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER); 715 716 if (hKernel32Vista) 717 { 718 FreeLibrary(hKernel32Vista); 719 } 720 721 HeapFree(GetProcessHeap(), 0, pImgInfo); 722 break; 723 } 724 725 case WM_TIMER: 726 { 727 if (wParam == ID_SYSUPTIME_UPDATE_TIMER) 728 { 729 /* Update system uptime */ 730 GetSystemUptime(hwndDlg); 731 } 732 733 break; 734 } 735 736 case WM_COMMAND: 737 { 738 if (LOWORD(wParam) == IDC_LICENCE) 739 { 740 DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc); 741 742 return TRUE; 743 } 744 break; 745 } 746 747 case WM_DRAWITEM: 748 { 749 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam; 750 751 if (lpDrawItem->CtlID == IDC_ROSIMG) 752 { 753 HDC hdcMem; 754 LONG left; 755 756 /* Position image in centre of dialog */ 757 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2; 758 759 hdcMem = CreateCompatibleDC(lpDrawItem->hDC); 760 if (hdcMem != NULL) 761 { 762 SelectObject(hdcMem, pImgInfo->hBitmap); 763 BitBlt(lpDrawItem->hDC, 764 left, 765 lpDrawItem->rcItem.top, 766 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left, 767 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 768 hdcMem, 769 0, 770 0, 771 SRCCOPY); 772 DeleteDC(hdcMem); 773 } 774 } 775 return TRUE; 776 } 777 778 case WM_NOTIFY: 779 { 780 NMHDR *nmhdr = (NMHDR *)lParam; 781 782 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK) 783 { 784 PNMLINK nml = (PNMLINK)nmhdr; 785 786 ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL); 787 } 788 break; 789 } 790 791 } 792 793 return FALSE; 794 } 795