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>
22 typedef struct _IMGINFO
31 PIMGINFO pImgInfo
= NULL
;
32 BLENDFUNCTION BlendFunc
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
34 VOID
ShowLastWin32Error(HWND hWndOwner
)
39 LastError
= GetLastError();
40 if (LastError
== ERROR_SUCCESS
)
43 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
44 FORMAT_MESSAGE_FROM_SYSTEM
|
45 FORMAT_MESSAGE_IGNORE_INSERTS
,
55 MessageBox(hWndOwner
, lpMsg
, NULL
, MB_OK
| MB_ICONERROR
);
60 static VOID
InitLogo(HWND hwndDlg
)
65 HDC hDC
= GetDC(hwndDlg
);
66 HDC hDCLogo
= CreateCompatibleDC(NULL
);
67 HDC hDCMask
= CreateCompatibleDC(NULL
);
68 HBITMAP hMask
, hLogo
, hAlphaLogo
= NULL
;
72 ZeroMemory(pImgInfo
, sizeof(*pImgInfo
));
73 ZeroMemory(&bmpi
, sizeof(bmpi
));
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
);
78 if (hLogo
!= NULL
&& hMask
!= NULL
)
80 GetObject(hLogo
, sizeof(BITMAP
), &logoBitmap
);
81 GetObject(hMask
, sizeof(BITMAP
), &maskBitmap
);
83 if(logoBitmap
.bmHeight
!= maskBitmap
.bmHeight
|| logoBitmap
.bmWidth
!= maskBitmap
.bmWidth
)
86 pImgInfo
->cxSource
= logoBitmap
.bmWidth
;
87 pImgInfo
->cySource
= logoBitmap
.bmHeight
;
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
;
97 hAlphaLogo
= CreateDIBSection(hDC
, &bmpi
, DIB_RGB_COLORS
, (PVOID
*)&pBits
, 0, 0);
102 SelectObject(hDCLogo
, hLogo
);
103 SelectObject(hDCMask
, hMask
);
105 for(line
= logoBitmap
.bmHeight
- 1; line
>= 0; line
--)
107 for(column
= 0; column
< logoBitmap
.bmWidth
; column
++)
109 COLORREF alpha
= GetPixel(hDCMask
, column
, line
) & 0xFF;
110 COLORREF Color
= GetPixel(hDCLogo
, column
, line
);
113 r
= GetRValue(Color
) * alpha
/ 255;
114 g
= GetGValue(Color
) * alpha
/ 255;
115 b
= GetBValue(Color
) * alpha
/ 255;
117 *pBits
++ = b
| g
<< 8 | r
<< 16 | alpha
<< 24;
122 pImgInfo
->hBitmap
= hAlphaLogo
;
123 pImgInfo
->cxSource
= logoBitmap
.bmWidth
;
124 pImgInfo
->cySource
= logoBitmap
.bmHeight
;
125 pImgInfo
->iBits
= logoBitmap
.bmBitsPixel
;
126 pImgInfo
->iPLanes
= logoBitmap
.bmPlanes
;
135 LRESULT CALLBACK
RosImageProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
137 static UINT timerid
= 0, top
= 0, offset
;
138 static HBITMAP hCreditsBitmap
;
142 case WM_LBUTTONDBLCLK
:
143 if (wParam
& (MK_CONTROL
| MK_SHIFT
))
147 HDC hCreditsDC
, hLogoDC
;
149 NONCLIENTMETRICS ncm
;
151 TCHAR szCredits
[2048];
156 hCreditsDC
= CreateCompatibleDC(GetDC(NULL
));
157 hLogoDC
= CreateCompatibleDC(hCreditsDC
);
159 if (hCreditsDC
== NULL
|| hLogoDC
== NULL
)
162 SetRect(&rcCredits
, 0, 0, 0, 0);
164 ncm
.cbSize
= sizeof(NONCLIENTMETRICS
);
165 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &ncm
, 0);
167 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
168 SelectObject(hCreditsDC
, hFont
);
170 LoadString(hApplet
, IDS_DEVS
, szCredits
, sizeof(szCredits
) / sizeof(TCHAR
));
171 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CALCRECT
);
173 iDevsHeight
= rcCredits
.bottom
- rcCredits
.top
;
175 hCreditsBitmap
= CreateBitmap(pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1, pImgInfo
->iPLanes
, pImgInfo
->iBits
, NULL
);
180 SelectObject(hLogoDC
, pImgInfo
->hBitmap
);
181 SelectObject(hCreditsDC
, hCreditsBitmap
);
183 offset
+= pImgInfo
->cySource
;
185 SetRect(&rcCredits
, 0, 0, pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1);
186 FillRect(hCreditsDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
188 SetRect(&rcCredits
, 0, offset
, pImgInfo
->cxSource
, offset
+ iDevsHeight
+ 1);
189 SetBkMode(hCreditsDC
, TRANSPARENT
);
191 OffsetRect(&rcCredits
, 1, 1);
192 SetTextColor(hCreditsDC
, GetSysColor(COLOR_BTNSHADOW
));
193 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
195 OffsetRect(&rcCredits
, -1, -1);
196 SetTextColor(hCreditsDC
, GetSysColor(COLOR_WINDOWTEXT
));
197 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
199 offset
+= iDevsHeight
;
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
);
205 DeleteDC(hCreditsDC
);
207 timerid
= SetTimer(hwnd
, 1, ANIM_TIME
, NULL
);
215 HDC hDC
= GetDC(hwnd
);
217 GetClientRect(hwnd
, &rcCredits
);
218 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
219 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
221 KillTimer(hwnd
, timerid
);
222 DeleteObject(hCreditsBitmap
);
223 InvalidateRect(hwnd
, NULL
, FALSE
);
235 HDC hDC
= GetDC(hwnd
);
237 GetClientRect(hwnd
, &rcCredits
);
238 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
239 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
241 KillTimer(hwnd
, timerid
);
242 DeleteObject(hCreditsBitmap
);
248 InvalidateRect(hwnd
, NULL
, FALSE
);
256 hdc
= wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &PS
);
258 GetClientRect(hwnd
, &PS
.rcPaint
);
260 /* Position image in center of dialog */
261 left
= (PS
.rcPaint
.right
- pImgInfo
->cxSource
) / 2;
262 hdcMem
= CreateCompatibleDC(hdc
);
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
);
273 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
274 AlphaBlend(hdc
, left
, PS
.rcPaint
.top
, pImgInfo
->cxSource
, pImgInfo
->cySource
, hdcMem
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
288 static VOID
SetRegTextData(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
294 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
296 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
301 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
302 SetDlgItemText(hwnd
, uID
, lpBuf
);
304 HeapFree(GetProcessHeap(), 0, lpBuf
);
308 static INT
SetProcNameString(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID1
, UINT uID2
)
318 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
320 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
325 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
327 if (BufSize
> ((30 + 1) * sizeof(TCHAR
)))
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. *
334 * For example the Processor Name String of a Pentium 4 is right-aligned. *
335 * With this wrapping the first line looks centered. */
337 _tcsncpy(szBuf
, lpBuf
, 30);
339 szLastSpace
= _tcsrchr(szBuf
, ' ');
341 if (szLastSpace
== 0)
347 LastSpace
= (szLastSpace
- szBuf
);
348 szBuf
[LastSpace
] = 0;
351 _tcsncpy(szBuf
, lpBuf
, LastSpace
);
353 SetDlgItemText(hwnd
, uID1
, szBuf
);
354 SetDlgItemText(hwnd
, uID2
, lpBuf
+LastSpace
+1);
356 /* Return the number of used lines */
361 SetDlgItemText(hwnd
, uID1
, lpBuf
);
366 HeapFree(GetProcessHeap(), 0, lpBuf
);
372 static VOID
MakeFloatValueString(DOUBLE
* dFloatValue
, LPTSTR szOutput
, LPTSTR szAppend
)
374 TCHAR szDecimalSeparator
[4];
376 /* Get the decimal separator for the current locale */
377 if (GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, szDecimalSeparator
, sizeof(szDecimalSeparator
) / sizeof(TCHAR
)) > 0)
382 /* Show the value with two decimals */
383 uIntegral
= (UINT
)*dFloatValue
;
384 uDecimals
= (UCHAR
)((UINT
)(*dFloatValue
* 100) - uIntegral
* 100);
386 wsprintf(szOutput
, _T("%u%s%02u %s"), uIntegral
, szDecimalSeparator
, uDecimals
, szAppend
);
390 static VOID
SetProcSpeed(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
392 TCHAR szBuf
[64], szHz
[16];
393 DWORD BufSize
= sizeof(DWORD
);
395 PROCESSOR_POWER_INFORMATION ppi
;
397 ZeroMemory(&ppi
, sizeof(ppi
));
399 if ((CallNtPowerInformation(ProcessorInformation
,
403 sizeof(ppi
)) == STATUS_SUCCESS
&&
404 ppi
.CurrentMhz
!= 0) || RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)&ppi
.CurrentMhz
, &BufSize
) == ERROR_SUCCESS
)
406 if (ppi
.CurrentMhz
< 1000)
408 if (!LoadString(hApplet
, IDS_MEGAHERTZ
, szHz
, _countof(szHz
)))
412 StringCchPrintf(szBuf
, _countof(szBuf
), _T("%lu %s"), ppi
.CurrentMhz
, szHz
);
416 double flt
= ppi
.CurrentMhz
/ 1000.0;
417 if (!LoadString(hApplet
, IDS_GIGAHERTZ
, szHz
, _countof(szHz
)))
421 MakeFloatValueString(&flt
, szBuf
, szHz
);
424 SetDlgItemText(hwnd
, uID
, szBuf
);
428 static VOID
GetSystemInformation(HWND hwnd
)
431 TCHAR ProcKey
[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
432 MEMORYSTATUSEX MemStat
;
434 WCHAR SMBiosName
[96];
435 INT CurMachineLine
= IDC_MACHINELINE1
;
438 * Get hardware device name or motherboard name
439 * using information from raw SMBIOS data
441 if (GetSystemName(SMBiosName
, _countof(SMBiosName
)))
443 SetDlgItemText(hwnd
, CurMachineLine
, SMBiosName
);
447 * Get Processor information
448 * although undocumented, this information is being pulled
449 * directly out of the registry instead of via setupapi as it
450 * contains all the info we need, and should remain static
452 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ProcKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
454 SetRegTextData(hwnd
, hKey
, _T("VendorIdentifier"), CurMachineLine
);
457 CurMachineLine
+= SetProcNameString(hwnd
,
459 _T("ProcessorNameString"),
463 SetProcSpeed(hwnd
, hKey
, _T("~MHz"), CurMachineLine
);
467 /* Get total physical RAM */
468 MemStat
.dwLength
= sizeof(MemStat
);
470 if (GlobalMemoryStatusEx(&MemStat
))
475 if (MemStat
.ullTotalPhys
> 1024 * 1024 * 1024)
478 static const UINT uStrId
[] = { IDS_GIGABYTE
, IDS_TERABYTE
, IDS_PETABYTE
};
480 // We're dealing with GBs or more
481 MemStat
.ullTotalPhys
/= 1024 * 1024;
483 if (MemStat
.ullTotalPhys
> 1024 * 1024)
485 // We're dealing with TBs or more
486 MemStat
.ullTotalPhys
/= 1024;
489 if (MemStat
.ullTotalPhys
> 1024 * 1024)
491 // We're dealing with PBs or more
492 MemStat
.ullTotalPhys
/= 1024;
495 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
499 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
504 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
507 LoadString(hApplet
, uStrId
[i
], szStr
, sizeof(szStr
) / sizeof(TCHAR
));
508 MakeFloatValueString(&dTotalPhys
, Buf
, szStr
);
512 // We're dealing with MBs, don't show any decimals
513 LoadString(hApplet
, IDS_MEGABYTE
, szStr
, sizeof(szStr
) / sizeof(TCHAR
));
514 wsprintf(Buf
, _T("%u %s"), (UINT
)MemStat
.ullTotalPhys
/ 1024 / 1024, szStr
);
517 SetDlgItemText(hwnd
, CurMachineLine
, Buf
);
521 static VOID
GetSystemVersion(HWND hwnd
)
524 SIZE_T lenStr
, lenVersion
;
525 PCWSTR pwszVersion
= L
" " TEXT(KERNEL_VERSION_RC
);
528 lenVersion
= wcslen(pwszVersion
);
534 hRosVersion
= GetDlgItem(hwnd
, IDC_ROSVERSION
);
539 lenStr
= GetWindowTextLengthW(hRosVersion
);
540 lenStr
+= lenVersion
+ 1;
541 pwszStr
= HeapAlloc(GetProcessHeap(), 0, lenStr
* sizeof(WCHAR
));
546 GetWindowText(hRosVersion
, pwszStr
, lenStr
);
548 StringCchCatW(pwszStr
, lenStr
, pwszVersion
);
549 SetWindowText(hRosVersion
, pwszStr
);
551 HeapFree(GetProcessHeap(), 0, pwszStr
);
554 /* Property page dialog callback */
555 INT_PTR CALLBACK
GeneralPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
557 UNREFERENCED_PARAMETER(lParam
);
558 UNREFERENCED_PARAMETER(wParam
);
563 pImgInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IMGINFO
));
564 if (pImgInfo
== NULL
)
566 EndDialog(hwndDlg
, 0);
571 SetWindowLongPtr(GetDlgItem(hwndDlg
, IDC_ROSIMG
), GWLP_WNDPROC
, (LONG_PTR
)RosImageProc
);
572 GetSystemInformation(hwndDlg
);
573 GetSystemVersion(hwndDlg
);
577 HeapFree(GetProcessHeap(), 0, pImgInfo
);
581 if (LOWORD(wParam
) == IDC_LICENCE
)
583 DialogBox(hApplet
, MAKEINTRESOURCE(IDD_LICENCE
), hwndDlg
, LicenceDlgProc
);
591 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) lParam
;
593 if (lpDrawItem
->CtlID
== IDC_ROSIMG
)
598 /* Position image in centre of dialog */
599 left
= (lpDrawItem
->rcItem
.right
- pImgInfo
->cxSource
) / 2;
601 hdcMem
= CreateCompatibleDC(lpDrawItem
->hDC
);
604 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
605 BitBlt(lpDrawItem
->hDC
,
607 lpDrawItem
->rcItem
.top
,
608 lpDrawItem
->rcItem
.right
- lpDrawItem
->rcItem
.left
,
609 lpDrawItem
->rcItem
.bottom
- lpDrawItem
->rcItem
.top
,
622 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
624 if (nmhdr
->idFrom
== IDC_ROSHOMEPAGE_LINK
&& nmhdr
->code
== NM_CLICK
)
626 PNMLINK nml
= (PNMLINK
)nmhdr
;
628 ShellExecuteW(hwndDlg
, L
"open", nml
->item
.szUrl
, NULL
, NULL
, SW_SHOWNORMAL
);