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 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 PIMGINFO pImgInfo = NULL; 32 BLENDFUNCTION BlendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; 33 34 VOID ShowLastWin32Error(HWND hWndOwner) 35 { 36 LPTSTR lpMsg; 37 DWORD LastError; 38 39 LastError = GetLastError(); 40 if (LastError == ERROR_SUCCESS) 41 return; 42 43 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 44 FORMAT_MESSAGE_FROM_SYSTEM | 45 FORMAT_MESSAGE_IGNORE_INSERTS, 46 NULL, 47 LastError, 48 LANG_USER_DEFAULT, 49 (LPTSTR)&lpMsg, 50 0, NULL)) 51 { 52 return; 53 } 54 55 MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR); 56 LocalFree(lpMsg); 57 } 58 59 60 static VOID InitLogo(HWND hwndDlg) 61 { 62 BITMAP logoBitmap; 63 BITMAP maskBitmap; 64 BITMAPINFO bmpi; 65 HDC hDC = GetDC(hwndDlg); 66 HDC hDCLogo = CreateCompatibleDC(NULL); 67 HDC hDCMask = CreateCompatibleDC(NULL); 68 HBITMAP hMask, hLogo, hAlphaLogo = NULL; 69 COLORREF *pBits; 70 INT line, column; 71 72 ZeroMemory(pImgInfo, sizeof(*pImgInfo)); 73 ZeroMemory(&bmpi, sizeof(bmpi)); 74 75 hLogo = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSBMP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 76 hMask = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSMASK), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 77 78 if (hLogo != NULL && hMask != NULL) 79 { 80 GetObject(hLogo, sizeof(BITMAP), &logoBitmap); 81 GetObject(hMask, sizeof(BITMAP), &maskBitmap); 82 83 if(logoBitmap.bmHeight != maskBitmap.bmHeight || logoBitmap.bmWidth != maskBitmap.bmWidth) 84 return; 85 86 pImgInfo->cxSource = logoBitmap.bmWidth; 87 pImgInfo->cySource = logoBitmap.bmHeight; 88 89 bmpi.bmiHeader.biSize = sizeof(BITMAPINFO); 90 bmpi.bmiHeader.biWidth = logoBitmap.bmWidth; 91 bmpi.bmiHeader.biHeight = logoBitmap.bmHeight; 92 bmpi.bmiHeader.biPlanes = 1; 93 bmpi.bmiHeader.biBitCount = 32; 94 bmpi.bmiHeader.biCompression = BI_RGB; 95 bmpi.bmiHeader.biSizeImage = 4 * logoBitmap.bmWidth * logoBitmap.bmHeight; 96 97 hAlphaLogo = CreateDIBSection(hDC, &bmpi, DIB_RGB_COLORS, (PVOID*)&pBits, 0, 0); 98 99 if(!hAlphaLogo) 100 return; 101 102 SelectObject(hDCLogo, hLogo); 103 SelectObject(hDCMask, hMask); 104 105 for(line = logoBitmap.bmHeight - 1; line >= 0; line--) 106 { 107 for(column = 0; column < logoBitmap.bmWidth; column++) 108 { 109 COLORREF alpha = GetPixel(hDCMask, column, line) & 0xFF; 110 COLORREF Color = GetPixel(hDCLogo, column, line); 111 DWORD r, g, b; 112 113 r = GetRValue(Color) * alpha / 255; 114 g = GetGValue(Color) * alpha / 255; 115 b = GetBValue(Color) * alpha / 255; 116 117 *pBits++ = b | g << 8 | r << 16 | alpha << 24; 118 } 119 } 120 } 121 122 pImgInfo->hBitmap = hAlphaLogo; 123 pImgInfo->cxSource = logoBitmap.bmWidth; 124 pImgInfo->cySource = logoBitmap.bmHeight; 125 pImgInfo->iBits = logoBitmap.bmBitsPixel; 126 pImgInfo->iPLanes = logoBitmap.bmPlanes; 127 128 DeleteObject(hLogo); 129 DeleteObject(hMask); 130 DeleteDC(hDCLogo); 131 DeleteDC(hDCMask); 132 133 } 134 135 LRESULT CALLBACK RosImageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 136 { 137 static UINT timerid = 0, top = 0, offset; 138 static HBITMAP hCreditsBitmap; 139 140 switch (uMsg) 141 { 142 case WM_LBUTTONDBLCLK: 143 if (wParam & (MK_CONTROL | MK_SHIFT)) 144 { 145 if (timerid == 0) 146 { 147 HDC hCreditsDC, hLogoDC; 148 HFONT hFont; 149 NONCLIENTMETRICS ncm; 150 RECT rcCredits; 151 TCHAR szCredits[2048]; 152 INT iDevsHeight; 153 154 top = 0; 155 offset = 0; 156 hCreditsDC = CreateCompatibleDC(GetDC(NULL)); 157 hLogoDC = CreateCompatibleDC(hCreditsDC); 158 159 if (hCreditsDC == NULL || hLogoDC == NULL) 160 break; 161 162 SetRect(&rcCredits, 0, 0, 0, 0); 163 164 ncm.cbSize = sizeof(NONCLIENTMETRICS); 165 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0); 166 167 hFont = CreateFontIndirect(&ncm.lfMessageFont); 168 SelectObject(hCreditsDC, hFont); 169 170 LoadString(hApplet, IDS_DEVS, szCredits, sizeof(szCredits) / sizeof(TCHAR)); 171 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CALCRECT); 172 173 iDevsHeight = rcCredits.bottom - rcCredits.top; 174 175 hCreditsBitmap = CreateBitmap(pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1, pImgInfo->iPLanes, pImgInfo->iBits, NULL); 176 177 if(!hCreditsBitmap) 178 break; 179 180 SelectObject(hLogoDC, pImgInfo->hBitmap); 181 SelectObject(hCreditsDC, hCreditsBitmap); 182 183 offset += pImgInfo->cySource; 184 185 SetRect(&rcCredits, 0, 0, pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1); 186 FillRect(hCreditsDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 187 188 SetRect(&rcCredits, 0, offset, pImgInfo->cxSource, offset + iDevsHeight + 1); 189 SetBkMode(hCreditsDC, TRANSPARENT); 190 191 OffsetRect(&rcCredits, 1, 1); 192 SetTextColor(hCreditsDC, GetSysColor(COLOR_BTNSHADOW)); 193 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER); 194 195 OffsetRect(&rcCredits, -1, -1); 196 SetTextColor(hCreditsDC, GetSysColor(COLOR_WINDOWTEXT)); 197 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER); 198 199 offset += iDevsHeight; 200 201 AlphaBlend(hCreditsDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 202 AlphaBlend(hCreditsDC, 0, offset, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 203 204 DeleteDC(hLogoDC); 205 DeleteDC(hCreditsDC); 206 207 timerid = SetTimer(hwnd, 1, ANIM_TIME, NULL); 208 } 209 } 210 break; 211 case WM_LBUTTONDOWN: 212 if (timerid) 213 { 214 RECT rcCredits; 215 HDC hDC = GetDC(hwnd); 216 217 GetClientRect(hwnd, &rcCredits); 218 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource); 219 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 220 221 KillTimer(hwnd, timerid); 222 DeleteObject(hCreditsBitmap); 223 InvalidateRect(hwnd, NULL, FALSE); 224 225 top = 0; 226 timerid = 0; 227 } 228 break; 229 case WM_TIMER: 230 top += ANIM_STEP; 231 232 if (top > offset) 233 { 234 RECT rcCredits; 235 HDC hDC = GetDC(hwnd); 236 237 GetClientRect(hwnd, &rcCredits); 238 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource); 239 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE)); 240 241 KillTimer(hwnd, timerid); 242 DeleteObject(hCreditsBitmap); 243 244 top = 0; 245 timerid = 0; 246 } 247 248 InvalidateRect(hwnd, NULL, FALSE); 249 break; 250 case WM_PAINT: 251 { 252 PAINTSTRUCT PS; 253 HDC hdcMem, hdc; 254 LONG left; 255 256 hdc = wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &PS); 257 258 GetClientRect(hwnd, &PS.rcPaint); 259 260 /* Position image in center of dialog */ 261 left = (PS.rcPaint.right - pImgInfo->cxSource) / 2; 262 hdcMem = CreateCompatibleDC(hdc); 263 264 if (hdcMem != NULL) 265 { 266 if(timerid != 0) 267 { 268 SelectObject(hdcMem, hCreditsBitmap); 269 BitBlt(hdc, left, PS.rcPaint.top, PS.rcPaint.right - PS.rcPaint.left, PS.rcPaint.top + pImgInfo->cySource, hdcMem, 0, top, SRCCOPY); 270 } 271 else 272 { 273 SelectObject(hdcMem, pImgInfo->hBitmap); 274 AlphaBlend(hdc, left, PS.rcPaint.top, pImgInfo->cxSource, pImgInfo->cySource, hdcMem, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc); 275 } 276 277 DeleteDC(hdcMem); 278 } 279 280 if (wParam == 0) 281 EndPaint(hwnd,&PS); 282 break; 283 } 284 } 285 return TRUE; 286 } 287 288 static VOID SetRegTextData(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID) 289 { 290 LPTSTR lpBuf = NULL; 291 DWORD BufSize = 0; 292 DWORD Type; 293 294 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS) 295 { 296 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize); 297 298 if (!lpBuf) 299 return; 300 301 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS) 302 SetDlgItemText(hwnd, uID, lpBuf); 303 304 HeapFree(GetProcessHeap(), 0, lpBuf); 305 } 306 } 307 308 static INT SetProcNameString(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID1, UINT uID2) 309 { 310 LPTSTR lpBuf = NULL; 311 DWORD BufSize = 0; 312 DWORD Type; 313 INT Ret = 0; 314 TCHAR szBuf[31]; 315 TCHAR* szLastSpace; 316 INT LastSpace = 0; 317 318 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS) 319 { 320 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize); 321 322 if (!lpBuf) 323 return 0; 324 325 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS) 326 { 327 if (BufSize > ((30 + 1) * sizeof(TCHAR))) 328 { 329 /* Wrap the Processor Name String like XP does: * 330 * - Take the first 30 characters and look for the last space. * 331 * Then wrap the string after this space. * 332 * - If no space is found, wrap the string after character 30. * 333 * * 334 * For example the Processor Name String of a Pentium 4 is right-aligned. * 335 * With this wrapping the first line looks centered. */ 336 337 _tcsncpy(szBuf, lpBuf, 30); 338 szBuf[30] = 0; 339 szLastSpace = _tcsrchr(szBuf, ' '); 340 341 if (szLastSpace == 0) 342 { 343 LastSpace = 30; 344 } 345 else 346 { 347 LastSpace = (szLastSpace - szBuf); 348 szBuf[LastSpace] = 0; 349 } 350 351 _tcsncpy(szBuf, lpBuf, LastSpace); 352 353 SetDlgItemText(hwnd, uID1, szBuf); 354 SetDlgItemText(hwnd, uID2, lpBuf+LastSpace+1); 355 356 /* Return the number of used lines */ 357 Ret = 2; 358 } 359 else 360 { 361 SetDlgItemText(hwnd, uID1, lpBuf); 362 Ret = 1; 363 } 364 } 365 366 HeapFree(GetProcessHeap(), 0, lpBuf); 367 } 368 369 return Ret; 370 } 371 372 static VOID MakeFloatValueString(DOUBLE* dFloatValue, LPTSTR szOutput, LPTSTR szAppend) 373 { 374 TCHAR szDecimalSeparator[4]; 375 376 /* Get the decimal separator for the current locale */ 377 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0) 378 { 379 UCHAR uDecimals; 380 UINT uIntegral; 381 382 /* Show the value with two decimals */ 383 uIntegral = (UINT)*dFloatValue; 384 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100); 385 386 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend); 387 } 388 } 389 390 static VOID SetProcSpeed(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID) 391 { 392 TCHAR szBuf[64]; 393 DWORD BufSize = sizeof(DWORD); 394 DWORD Type = REG_SZ; 395 PROCESSOR_POWER_INFORMATION ppi; 396 397 ZeroMemory(&ppi, sizeof(ppi)); 398 399 if ((CallNtPowerInformation(ProcessorInformation, 400 NULL, 401 0, 402 (PVOID)&ppi, 403 sizeof(ppi)) == STATUS_SUCCESS && 404 ppi.CurrentMhz != 0) || RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)&ppi.CurrentMhz, &BufSize) == ERROR_SUCCESS) 405 { 406 if (ppi.CurrentMhz < 1000) 407 { 408 wsprintf(szBuf, _T("%lu MHz"), ppi.CurrentMhz); 409 } 410 else 411 { 412 double flt = ppi.CurrentMhz / 1000.0; 413 MakeFloatValueString(&flt, szBuf, _T("GHz")); 414 } 415 416 SetDlgItemText(hwnd, uID, szBuf); 417 } 418 } 419 420 static VOID GetSystemInformation(HWND hwnd) 421 { 422 HKEY hKey; 423 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); 424 MEMORYSTATUSEX MemStat; 425 TCHAR Buf[32]; 426 INT CurMachineLine = IDC_MACHINELINE1; 427 428 /* 429 * Get Processor information 430 * although undocumented, this information is being pulled 431 * directly out of the registry instead of via setupapi as it 432 * contains all the info we need, and should remain static 433 */ 434 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 435 { 436 SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine); 437 CurMachineLine++; 438 439 CurMachineLine += SetProcNameString(hwnd, 440 hKey, 441 _T("ProcessorNameString"), 442 CurMachineLine, 443 CurMachineLine + 1); 444 445 SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine); 446 CurMachineLine++; 447 } 448 449 /* Get total physical RAM */ 450 MemStat.dwLength = sizeof(MemStat); 451 452 if (GlobalMemoryStatusEx(&MemStat)) 453 { 454 TCHAR szStr[32]; 455 double dTotalPhys; 456 457 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024) 458 { 459 UINT i = 0; 460 static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE}; 461 462 // We're dealing with GBs or more 463 MemStat.ullTotalPhys /= 1024 * 1024; 464 465 if (MemStat.ullTotalPhys > 1024 * 1024) 466 { 467 // We're dealing with TBs or more 468 MemStat.ullTotalPhys /= 1024; 469 i++; 470 471 if (MemStat.ullTotalPhys > 1024 * 1024) 472 { 473 // We're dealing with PBs or more 474 MemStat.ullTotalPhys /= 1024; 475 i++; 476 477 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 478 } 479 else 480 { 481 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 482 } 483 } 484 else 485 { 486 dTotalPhys = (double)MemStat.ullTotalPhys / 1024; 487 } 488 489 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR)); 490 MakeFloatValueString(&dTotalPhys, Buf, szStr); 491 } 492 else 493 { 494 // We're dealing with MBs, don't show any decimals 495 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR)); 496 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr); 497 } 498 499 SetDlgItemText(hwnd, CurMachineLine, Buf); 500 } 501 } 502 503 static VOID GetSystemVersion(HWND hwnd) 504 { 505 HWND hRosVersion; 506 SIZE_T lenStr, lenVersion; 507 PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC); 508 PWSTR pwszStr; 509 510 lenVersion = wcslen(pwszVersion); 511 if (lenVersion == 0) 512 { 513 return; 514 } 515 516 hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION); 517 if (!hRosVersion) 518 { 519 return; 520 } 521 lenStr = GetWindowTextLengthW(hRosVersion); 522 lenStr += lenVersion + 1; 523 pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR)); 524 if (!pwszStr) 525 { 526 return; 527 } 528 GetWindowText(hRosVersion, pwszStr, lenStr); 529 530 StringCchCatW(pwszStr, lenStr, pwszVersion); 531 SetWindowText(hRosVersion, pwszStr); 532 533 HeapFree(GetProcessHeap(), 0, pwszStr); 534 } 535 536 /* Property page dialog callback */ 537 INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 538 { 539 UNREFERENCED_PARAMETER(lParam); 540 UNREFERENCED_PARAMETER(wParam); 541 542 switch (uMsg) 543 { 544 case WM_INITDIALOG: 545 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO)); 546 if (pImgInfo == NULL) 547 { 548 EndDialog(hwndDlg, 0); 549 return FALSE; 550 } 551 552 InitLogo(hwndDlg); 553 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc); 554 GetSystemInformation(hwndDlg); 555 GetSystemVersion(hwndDlg); 556 break; 557 558 case WM_DESTROY: 559 HeapFree(GetProcessHeap(), 0, pImgInfo); 560 break; 561 562 case WM_COMMAND: 563 if (LOWORD(wParam) == IDC_LICENCE) 564 { 565 DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc); 566 567 return TRUE; 568 } 569 break; 570 571 case WM_DRAWITEM: 572 { 573 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT) lParam; 574 575 if (lpDrawItem->CtlID == IDC_ROSIMG) 576 { 577 HDC hdcMem; 578 LONG left; 579 580 /* Position image in centre of dialog */ 581 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2; 582 583 hdcMem = CreateCompatibleDC(lpDrawItem->hDC); 584 if (hdcMem != NULL) 585 { 586 SelectObject(hdcMem, pImgInfo->hBitmap); 587 BitBlt(lpDrawItem->hDC, 588 left, 589 lpDrawItem->rcItem.top, 590 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left, 591 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 592 hdcMem, 593 0, 594 0, 595 SRCCOPY); 596 DeleteDC(hdcMem); 597 } 598 } 599 return TRUE; 600 } 601 602 case WM_NOTIFY: 603 { 604 NMHDR *nmhdr = (NMHDR *)lParam; 605 606 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK) 607 { 608 PNMLINK nml = (PNMLINK)nmhdr; 609 610 ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL); 611 } 612 break; 613 } 614 615 } 616 617 return FALSE; 618 } 619