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>
20 typedef struct _IMGINFO
29 PIMGINFO pImgInfo
= NULL
;
30 BLENDFUNCTION BlendFunc
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
32 VOID
ShowLastWin32Error(HWND hWndOwner
)
37 LastError
= GetLastError();
39 if ((LastError
== 0) ||
40 !FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
41 FORMAT_MESSAGE_FROM_SYSTEM
,
44 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
52 MessageBox(hWndOwner
, lpMsg
, NULL
, MB_OK
| MB_ICONERROR
);
54 LocalFree((LPVOID
)lpMsg
);
58 static VOID
InitLogo(HWND hwndDlg
)
63 HDC hDC
= GetDC(hwndDlg
);
64 HDC hDCLogo
= CreateCompatibleDC(NULL
);
65 HDC hDCMask
= CreateCompatibleDC(NULL
);
66 HBITMAP hMask
, hLogo
, hAlphaLogo
= NULL
;
70 ZeroMemory(pImgInfo
, sizeof(*pImgInfo
));
71 ZeroMemory(&bmpi
, sizeof(bmpi
));
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
);
76 if (hLogo
!= NULL
&& hMask
!= NULL
)
78 GetObject(hLogo
, sizeof(BITMAP
), &logoBitmap
);
79 GetObject(hMask
, sizeof(BITMAP
), &maskBitmap
);
81 if(logoBitmap
.bmHeight
!= maskBitmap
.bmHeight
|| logoBitmap
.bmWidth
!= maskBitmap
.bmWidth
)
84 pImgInfo
->cxSource
= logoBitmap
.bmWidth
;
85 pImgInfo
->cySource
= logoBitmap
.bmHeight
;
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
;
95 hAlphaLogo
= CreateDIBSection(hDC
, &bmpi
, DIB_RGB_COLORS
, (PVOID
*)&pBits
, 0, 0);
100 SelectObject(hDCLogo
, hLogo
);
101 SelectObject(hDCMask
, hMask
);
103 for(line
= logoBitmap
.bmHeight
- 1; line
>= 0; line
--)
105 for(column
= 0; column
< logoBitmap
.bmWidth
; column
++)
107 COLORREF alpha
= GetPixel(hDCMask
, column
, line
) & 0xFF;
108 COLORREF Color
= GetPixel(hDCLogo
, column
, line
);
111 r
= GetRValue(Color
) * alpha
/ 255;
112 g
= GetGValue(Color
) * alpha
/ 255;
113 b
= GetBValue(Color
) * alpha
/ 255;
115 *pBits
++ = b
| g
<< 8 | r
<< 16 | alpha
<< 24;
120 pImgInfo
->hBitmap
= hAlphaLogo
;
121 pImgInfo
->cxSource
= logoBitmap
.bmWidth
;
122 pImgInfo
->cySource
= logoBitmap
.bmHeight
;
123 pImgInfo
->iBits
= logoBitmap
.bmBitsPixel
;
124 pImgInfo
->iPLanes
= logoBitmap
.bmPlanes
;
133 LRESULT CALLBACK
RosImageProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
135 static UINT timerid
= 0, top
= 0, offset
;
136 static HBITMAP hCreditsBitmap
;
140 case WM_LBUTTONDBLCLK
:
141 if (wParam
& (MK_CONTROL
| MK_SHIFT
))
145 HDC hCreditsDC
, hLogoDC
;
147 NONCLIENTMETRICS ncm
;
149 TCHAR szCredits
[2048];
154 hCreditsDC
= CreateCompatibleDC(GetDC(NULL
));
155 hLogoDC
= CreateCompatibleDC(hCreditsDC
);
157 if (hCreditsDC
== NULL
|| hLogoDC
== NULL
)
160 SetRect(&rcCredits
, 0, 0, 0, 0);
162 ncm
.cbSize
= sizeof(NONCLIENTMETRICS
);
163 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &ncm
, 0);
165 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
166 SelectObject(hCreditsDC
, hFont
);
168 LoadString(hApplet
, IDS_DEVS
, szCredits
, sizeof(szCredits
) / sizeof(TCHAR
));
169 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CALCRECT
);
171 iDevsHeight
= rcCredits
.bottom
- rcCredits
.top
;
173 hCreditsBitmap
= CreateBitmap(pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1, pImgInfo
->iPLanes
, pImgInfo
->iBits
, NULL
);
178 SelectObject(hLogoDC
, pImgInfo
->hBitmap
);
179 SelectObject(hCreditsDC
, hCreditsBitmap
);
181 offset
+= pImgInfo
->cySource
;
183 SetRect(&rcCredits
, 0, 0, pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1);
184 FillRect(hCreditsDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
186 SetRect(&rcCredits
, 0, offset
, pImgInfo
->cxSource
, offset
+ iDevsHeight
+ 1);
187 SetBkMode(hCreditsDC
, TRANSPARENT
);
189 OffsetRect(&rcCredits
, 1, 1);
190 SetTextColor(hCreditsDC
, GetSysColor(COLOR_BTNSHADOW
));
191 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
193 OffsetRect(&rcCredits
, -1, -1);
194 SetTextColor(hCreditsDC
, GetSysColor(COLOR_WINDOWTEXT
));
195 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
197 offset
+= iDevsHeight
;
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
);
203 DeleteDC(hCreditsDC
);
205 timerid
= SetTimer(hwnd
, 1, ANIM_TIME
, NULL
);
213 HDC hDC
= GetDC(hwnd
);
215 GetClientRect(hwnd
, &rcCredits
);
216 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
217 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
219 KillTimer(hwnd
, timerid
);
220 DeleteObject(hCreditsBitmap
);
221 InvalidateRect(hwnd
, NULL
, FALSE
);
233 HDC hDC
= GetDC(hwnd
);
235 GetClientRect(hwnd
, &rcCredits
);
236 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
237 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
239 KillTimer(hwnd
, timerid
);
240 DeleteObject(hCreditsBitmap
);
246 InvalidateRect(hwnd
, NULL
, FALSE
);
254 hdc
= wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &PS
);
256 GetClientRect(hwnd
, &PS
.rcPaint
);
258 /* Position image in center of dialog */
259 left
= (PS
.rcPaint
.right
- pImgInfo
->cxSource
) / 2;
260 hdcMem
= CreateCompatibleDC(hdc
);
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
);
271 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
272 AlphaBlend(hdc
, left
, PS
.rcPaint
.top
, pImgInfo
->cxSource
, pImgInfo
->cySource
, hdcMem
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
286 static VOID
SetRegTextData(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
292 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
294 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
299 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
300 SetDlgItemText(hwnd
, uID
, lpBuf
);
302 HeapFree(GetProcessHeap(), 0, lpBuf
);
306 static INT
SetProcNameString(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID1
, UINT uID2
)
316 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
318 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
323 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
325 if (BufSize
> ((30 + 1) * sizeof(TCHAR
)))
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. *
332 * For example the Processor Name String of a Pentium 4 is right-aligned. *
333 * With this wrapping the first line looks centered. */
335 _tcsncpy(szBuf
, lpBuf
, 30);
337 szLastSpace
= _tcsrchr(szBuf
, ' ');
339 if (szLastSpace
== 0)
345 LastSpace
= (szLastSpace
- szBuf
);
346 szBuf
[LastSpace
] = 0;
349 _tcsncpy(szBuf
, lpBuf
, LastSpace
);
351 SetDlgItemText(hwnd
, uID1
, szBuf
);
352 SetDlgItemText(hwnd
, uID2
, lpBuf
+LastSpace
+1);
354 /* Return the number of used lines */
359 SetDlgItemText(hwnd
, uID1
, lpBuf
);
364 HeapFree(GetProcessHeap(), 0, lpBuf
);
370 static VOID
MakeFloatValueString(DOUBLE
* dFloatValue
, LPTSTR szOutput
, LPTSTR szAppend
)
372 TCHAR szDecimalSeparator
[4];
374 /* Get the decimal separator for the current locale */
375 if (GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, szDecimalSeparator
, sizeof(szDecimalSeparator
) / sizeof(TCHAR
)) > 0)
380 /* Show the value with two decimals */
381 uIntegral
= (UINT
)*dFloatValue
;
382 uDecimals
= (UCHAR
)((UINT
)(*dFloatValue
* 100) - uIntegral
* 100);
384 wsprintf(szOutput
, _T("%u%s%02u %s"), uIntegral
, szDecimalSeparator
, uDecimals
, szAppend
);
388 static VOID
SetProcSpeed(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
391 DWORD BufSize
= sizeof(DWORD
);
393 PROCESSOR_POWER_INFORMATION ppi
;
395 ZeroMemory(&ppi
, sizeof(ppi
));
397 if ((CallNtPowerInformation(ProcessorInformation
,
401 sizeof(ppi
)) == STATUS_SUCCESS
&&
402 ppi
.CurrentMhz
!= 0) || RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)&ppi
.CurrentMhz
, &BufSize
) == ERROR_SUCCESS
)
404 if (ppi
.CurrentMhz
< 1000)
406 wsprintf(szBuf
, _T("%lu MHz"), ppi
.CurrentMhz
);
410 double flt
= ppi
.CurrentMhz
/ 1000.0;
411 MakeFloatValueString(&flt
, szBuf
, _T("GHz"));
414 SetDlgItemText(hwnd
, uID
, szBuf
);
418 static VOID
GetSystemInformation(HWND hwnd
)
421 TCHAR ProcKey
[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
422 MEMORYSTATUSEX MemStat
;
424 INT CurMachineLine
= IDC_MACHINELINE1
;
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
432 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ProcKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
434 SetRegTextData(hwnd
, hKey
, _T("VendorIdentifier"), CurMachineLine
);
437 CurMachineLine
+= SetProcNameString(hwnd
,
439 _T("ProcessorNameString"),
443 SetProcSpeed(hwnd
, hKey
, _T("~MHz"), CurMachineLine
);
447 /* Get total physical RAM */
448 MemStat
.dwLength
= sizeof(MemStat
);
450 if (GlobalMemoryStatusEx(&MemStat
))
455 if (MemStat
.ullTotalPhys
> 1024 * 1024 * 1024)
458 static const UINT uStrId
[] = { IDS_GIGABYTE
, IDS_TERABYTE
, IDS_PETABYTE
};
460 // We're dealing with GBs or more
461 MemStat
.ullTotalPhys
/= 1024 * 1024;
463 if (MemStat
.ullTotalPhys
> 1024 * 1024)
465 // We're dealing with TBs or more
466 MemStat
.ullTotalPhys
/= 1024;
469 if (MemStat
.ullTotalPhys
> 1024 * 1024)
471 // We're dealing with PBs or more
472 MemStat
.ullTotalPhys
/= 1024;
475 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
479 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
484 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
487 LoadString(hApplet
, uStrId
[i
], szStr
, sizeof(szStr
) / sizeof(TCHAR
));
488 MakeFloatValueString(&dTotalPhys
, Buf
, szStr
);
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
);
497 SetDlgItemText(hwnd
, CurMachineLine
, Buf
);
502 /* Property page dialog callback */
503 INT_PTR CALLBACK
GeneralPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
505 UNREFERENCED_PARAMETER(lParam
);
506 UNREFERENCED_PARAMETER(wParam
);
511 pImgInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IMGINFO
));
512 if (pImgInfo
== NULL
)
514 EndDialog(hwndDlg
, 0);
519 SetWindowLongPtr(GetDlgItem(hwndDlg
, IDC_ROSIMG
), GWL_WNDPROC
, (LONG
)RosImageProc
);
520 GetSystemInformation(hwndDlg
);
524 HeapFree(GetProcessHeap(), 0, pImgInfo
);
528 if (LOWORD(wParam
) == IDC_LICENCE
)
530 DialogBox(hApplet
, MAKEINTRESOURCE(IDD_LICENCE
), hwndDlg
, LicenceDlgProc
);
538 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) lParam
;
540 if (lpDrawItem
->CtlID
== IDC_ROSIMG
)
545 /* Position image in centre of dialog */
546 left
= (lpDrawItem
->rcItem
.right
- pImgInfo
->cxSource
) / 2;
548 hdcMem
= CreateCompatibleDC(lpDrawItem
->hDC
);
551 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
552 BitBlt(lpDrawItem
->hDC
,
554 lpDrawItem
->rcItem
.top
,
555 lpDrawItem
->rcItem
.right
- lpDrawItem
->rcItem
.left
,
556 lpDrawItem
->rcItem
.bottom
- lpDrawItem
->rcItem
.top
,
569 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
571 if (nmhdr
->idFrom
== IDC_ROSHOMEPAGE_LINK
&& nmhdr
->code
== NM_CLICK
)
573 PNMLINK nml
= (PNMLINK
)nmhdr
;
575 ShellExecuteW(hwndDlg
, L
"open", nml
->item
.szUrl
, NULL
, NULL
, SW_SHOWNORMAL
);