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