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 BOOL 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 FALSE; 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 FALSE; 445 } 446 MakeFloatValueString(&flt, szBuf, szHz); 447 } 448 449 SetDlgItemText(hwnd, uID, szBuf); 450 return TRUE; 451 } 452 453 return FALSE; 454 } 455 456 static VOID GetSystemInformation(HWND hwnd) 457 { 458 HKEY hKey; 459 TCHAR SysKey[] = _T("HARDWARE\\DESCRIPTION\\System"); 460 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); 461 MEMORYSTATUSEX MemStat; 462 TCHAR Buf[32]; 463 WCHAR SMBiosName[96]; 464 INT CurMachineLine = IDC_MACHINELINE1; 465 466 /* 467 * Get hardware device name or motherboard name 468 * using information from raw SMBIOS data 469 */ 470 if (GetSystemName(SMBiosName, _countof(SMBiosName))) 471 { 472 SetDlgItemText(hwnd, CurMachineLine, SMBiosName); 473 CurMachineLine++; 474 } 475 else 476 { 477 /* If SMBIOS is not available, use System Identifier */ 478 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SysKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 479 { 480 SetRegTextData(hwnd, hKey, _T("Identifier"), CurMachineLine); 481 CurMachineLine++; 482 RegCloseKey(hKey); 483 } 484 } 485 /* 486 * Get Processor information 487 * although undocumented, this information is being pulled 488 * directly out of the registry instead of via setupapi as it 489 * contains all the info we need, and should remain static 490 */ 491 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 492 { 493 INT PrevMachineLine; 494 495 SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine); 496 CurMachineLine++; 497 498 PrevMachineLine = CurMachineLine; 499 CurMachineLine += SetProcNameString(hwnd, 500 hKey, 501 _T("ProcessorNameString"), 502 CurMachineLine, 503 CurMachineLine + 1); 504 505 if (CurMachineLine == PrevMachineLine) 506 { 507 /* TODO: Try obtaining CPU name from WMI (i.e. CIM_Processor) */ 508 509 /* Brand String is not available, use Identifier instead */ 510 CurMachineLine += SetProcNameString(hwnd, 511 hKey, 512 _T("Identifier"), 513 CurMachineLine, 514 CurMachineLine + 1); 515 } 516 517 if (SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine)) 518 CurMachineLine++; 519 RegCloseKey(hKey); 520 } 521 522 /* Get total physical RAM */ 523 MemStat.dwLength = sizeof(MemStat); 524 525 if (GlobalMemoryStatusEx(&MemStat)) 526 { 527 TCHAR szStr[32]; 528 double dTotalPhys; 529 530 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024) 531 { 532 UINT i = 0; 533 static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE}; 534 535 // We're dealing with GBs or more 536 MemStat.ullTotalPhys /= 1024 * 1024; 537 538 if (MemStat.ullTotalPhys > 1024 * 1024) 539 { 540 // We're dealing with TBs or more 541 MemStat.ullTotalPhys /= 1024; 542 i++; 543 544 if (MemStat.ullTotalPhys > 1024 * 1024) 545 { 546 // We're dealing with PBs or more 547 MemStat.ullTotalPhys /= 1024; 548 i++; 549 550 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 551 } 552 else 553 { 554 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 555 } 556 } 557 else 558 { 559 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 560 } 561 562 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR)); 563 MakeFloatValueString(&dTotalPhys, Buf, szStr); 564 } 565 else 566 { 567 // We're dealing with MBs, don't show any decimals 568 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR)); 569 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr); 570 } 571 572 SetDlgItemText(hwnd, CurMachineLine, Buf); 573 } 574 } 575 576 static VOID GetSystemVersion(HWND hwnd) 577 { 578 HWND hRosVersion; 579 SIZE_T lenStr, lenVersion; 580 PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC); 581 PWSTR pwszStr; 582 583 lenVersion = wcslen(pwszVersion); 584 if (lenVersion == 0) 585 { 586 return; 587 } 588 589 hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION); 590 if (!hRosVersion) 591 { 592 return; 593 } 594 lenStr = GetWindowTextLengthW(hRosVersion); 595 lenStr += lenVersion + 1; 596 pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR)); 597 if (!pwszStr) 598 { 599 return; 600 } 601 GetWindowText(hRosVersion, pwszStr, lenStr); 602 603 StringCchCatW(pwszStr, lenStr, pwszVersion); 604 SetWindowText(hRosVersion, pwszStr); 605 606 HeapFree(GetProcessHeap(), 0, pwszStr); 607 } 608 609 /** 610 * @brief 611 * An equivalent of GetTickCount64, implemented using QueryPerformanceCounter. 612 * 613 * @return 614 * The number of milliseconds that have elapsed since the system was started. 615 */ 616 static ULONGLONG GetTickCountQPC(VOID) 617 { 618 LARGE_INTEGER Counter, Frequency; 619 620 QueryPerformanceCounter(&Counter); 621 QueryPerformanceFrequency(&Frequency); 622 623 return (Counter.QuadPart * 1000) / Frequency.QuadPart; 624 } 625 626 static VOID GetSystemUptime(HWND hwndDlg) 627 { 628 HWND hUptimeLabel; 629 ULONGLONG cMilliseconds; 630 ULONG cSeconds; 631 WCHAR szBuf[64]; 632 633 hUptimeLabel = GetDlgItem(hwndDlg, IDC_UPTIME); 634 if (!hUptimeLabel) 635 { 636 return; 637 } 638 639 if (pGetTickCount64) 640 { 641 cMilliseconds = pGetTickCount64(); 642 } 643 else 644 { 645 cMilliseconds = GetTickCountQPC(); 646 } 647 648 cSeconds = cMilliseconds / 1000; 649 StringCchPrintfW(szBuf, _countof(szBuf), szUptimeFormat, 650 cSeconds / (60*60*24), // Days 651 (cSeconds / (60*60)) % 24, // Hours 652 (cSeconds / 60) % 60, // Minutes 653 cSeconds % 60); // Seconds 654 655 SetWindowTextW(hUptimeLabel, szBuf); 656 657 /* Set update timer (reset timeout if the timer exists) */ 658 SetTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER, 1000 - (cMilliseconds % 1000), NULL); 659 } 660 661 static VOID InitSystemUptime(HWND hwndDlg) 662 { 663 HMODULE hKernel32; 664 665 /* Load time format string */ 666 if (LoadStringW(hApplet, IDS_UPTIME_FORMAT, szUptimeFormat, _countof(szUptimeFormat)) == 0) 667 { 668 return; 669 } 670 671 /* Load required DLLs */ 672 hKernel32 = GetModuleHandleW(L"kernel32.dll"); 673 if (hKernel32) 674 { 675 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32, "GetTickCount64"); 676 if (!pGetTickCount64) 677 { 678 hKernel32Vista = LoadLibraryW(L"kernel32_vista.dll"); 679 if (hKernel32Vista) 680 { 681 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32Vista, "GetTickCount64"); 682 } 683 } 684 } 685 686 /* Show system uptime and set update timer */ 687 GetSystemUptime(hwndDlg); 688 } 689 690 /* Property page dialog callback */ 691 INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 692 { 693 UNREFERENCED_PARAMETER(lParam); 694 UNREFERENCED_PARAMETER(wParam); 695 696 switch (uMsg) 697 { 698 case WM_INITDIALOG: 699 { 700 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO)); 701 if (pImgInfo == NULL) 702 { 703 EndDialog(hwndDlg, 0); 704 return FALSE; 705 } 706 707 InitLogo(hwndDlg); 708 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc); 709 GetSystemInformation(hwndDlg); 710 GetSystemVersion(hwndDlg); 711 InitSystemUptime(hwndDlg); 712 break; 713 } 714 715 case WM_DESTROY: 716 { 717 KillTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER); 718 719 if (hKernel32Vista) 720 { 721 FreeLibrary(hKernel32Vista); 722 } 723 724 HeapFree(GetProcessHeap(), 0, pImgInfo); 725 break; 726 } 727 728 case WM_TIMER: 729 { 730 if (wParam == ID_SYSUPTIME_UPDATE_TIMER) 731 { 732 /* Update system uptime */ 733 GetSystemUptime(hwndDlg); 734 } 735 736 break; 737 } 738 739 case WM_COMMAND: 740 { 741 if (LOWORD(wParam) == IDC_LICENCE) 742 { 743 DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc); 744 745 return TRUE; 746 } 747 break; 748 } 749 750 case WM_DRAWITEM: 751 { 752 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam; 753 754 if (lpDrawItem->CtlID == IDC_ROSIMG) 755 { 756 HDC hdcMem; 757 LONG left; 758 759 /* Position image in centre of dialog */ 760 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2; 761 762 hdcMem = CreateCompatibleDC(lpDrawItem->hDC); 763 if (hdcMem != NULL) 764 { 765 SelectObject(hdcMem, pImgInfo->hBitmap); 766 BitBlt(lpDrawItem->hDC, 767 left, 768 lpDrawItem->rcItem.top, 769 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left, 770 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 771 hdcMem, 772 0, 773 0, 774 SRCCOPY); 775 DeleteDC(hdcMem); 776 } 777 } 778 return TRUE; 779 } 780 781 case WM_NOTIFY: 782 { 783 NMHDR *nmhdr = (NMHDR *)lParam; 784 785 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK) 786 { 787 PNMLINK nml = (PNMLINK)nmhdr; 788 789 ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL); 790 } 791 break; 792 } 793 794 } 795 796 return FALSE; 797 } 798