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