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 static PIMGINFO pImgInfo
;
32 static const 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 if (hDC
== NULL
|| hDCLogo
== NULL
|| hDCMask
== NULL
)
75 ZeroMemory(pImgInfo
, sizeof(*pImgInfo
));
76 ZeroMemory(&bmpi
, sizeof(bmpi
));
78 hLogo
= (HBITMAP
)LoadImageW(hApplet
, MAKEINTRESOURCEW(IDB_ROSBMP
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
79 hMask
= (HBITMAP
)LoadImageW(hApplet
, MAKEINTRESOURCEW(IDB_ROSMASK
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
81 if (hLogo
!= NULL
&& hMask
!= NULL
)
83 GetObject(hLogo
, sizeof(logoBitmap
), &logoBitmap
);
84 GetObject(hMask
, sizeof(maskBitmap
), &maskBitmap
);
86 if (logoBitmap
.bmHeight
!= maskBitmap
.bmHeight
|| logoBitmap
.bmWidth
!= maskBitmap
.bmWidth
)
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 /* Create a premultiplied bitmap */
98 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);
121 pImgInfo
->hBitmap
= hAlphaLogo
;
122 pImgInfo
->cxSource
= logoBitmap
.bmWidth
;
123 pImgInfo
->cySource
= logoBitmap
.bmHeight
;
124 pImgInfo
->iBits
= logoBitmap
.bmBitsPixel
;
125 pImgInfo
->iPlanes
= logoBitmap
.bmPlanes
;
129 if (hMask
!= NULL
) DeleteObject(hMask
);
130 if (hLogo
!= NULL
) DeleteObject(hLogo
);
131 if (hDCMask
!= NULL
) DeleteDC(hDCMask
);
132 if (hDCLogo
!= NULL
) DeleteDC(hDCLogo
);
133 if (hDC
!= NULL
) ReleaseDC(hwndDlg
, hDC
);
136 LRESULT CALLBACK
RosImageProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
138 static UINT timerid
= 0, top
= 0, offset
;
139 static HBITMAP hCreditsBitmap
;
143 case WM_LBUTTONDBLCLK
:
144 if (wParam
& (MK_CONTROL
| MK_SHIFT
))
148 HDC hCreditsDC
, hLogoDC
;
149 HDC hDC
= GetDC(NULL
);
151 NONCLIENTMETRICS ncm
;
153 TCHAR szCredits
[2048];
161 hCreditsDC
= CreateCompatibleDC(hDC
);
162 hLogoDC
= CreateCompatibleDC(hCreditsDC
);
164 if (hCreditsDC
== NULL
|| hLogoDC
== NULL
)
167 SetRect(&rcCredits
, 0, 0, 0, 0);
169 ncm
.cbSize
= sizeof(NONCLIENTMETRICS
);
170 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &ncm
, 0);
172 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
175 SelectObject(hCreditsDC
, hFont
);
177 LoadString(hApplet
, IDS_DEVS
, szCredits
, sizeof(szCredits
) / sizeof(TCHAR
));
178 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CALCRECT
);
180 iDevsHeight
= rcCredits
.bottom
- rcCredits
.top
;
182 hCreditsBitmap
= CreateBitmap(pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1, pImgInfo
->iPlanes
, pImgInfo
->iBits
, NULL
);
187 SelectObject(hLogoDC
, pImgInfo
->hBitmap
);
188 SelectObject(hCreditsDC
, hCreditsBitmap
);
190 offset
+= pImgInfo
->cySource
;
192 SetRect(&rcCredits
, 0, 0, pImgInfo
->cxSource
, (2 * pImgInfo
->cySource
) + iDevsHeight
+ 1);
193 FillRect(hCreditsDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
195 SetRect(&rcCredits
, 0, offset
, pImgInfo
->cxSource
, offset
+ iDevsHeight
+ 1);
196 SetBkMode(hCreditsDC
, TRANSPARENT
);
198 OffsetRect(&rcCredits
, 1, 1);
199 SetTextColor(hCreditsDC
, GetSysColor(COLOR_BTNSHADOW
));
200 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
202 OffsetRect(&rcCredits
, -1, -1);
203 SetTextColor(hCreditsDC
, GetSysColor(COLOR_WINDOWTEXT
));
204 DrawText(hCreditsDC
, szCredits
, -1, &rcCredits
, DT_CENTER
);
206 offset
+= iDevsHeight
;
208 AlphaBlend(hCreditsDC
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, hLogoDC
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
209 AlphaBlend(hCreditsDC
, 0, offset
, pImgInfo
->cxSource
, pImgInfo
->cySource
, hLogoDC
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
211 timerid
= SetTimer(hwnd
, 1, ANIM_TIME
, NULL
);
214 if (hFont
!= NULL
) DeleteObject(hFont
);
215 if (hLogoDC
!= NULL
) DeleteDC(hLogoDC
);
216 if (hCreditsDC
!= NULL
) DeleteDC(hCreditsDC
);
217 if (hDC
!= NULL
) ReleaseDC(NULL
, hDC
);
225 HDC hDC
= GetDC(hwnd
);
228 GetClientRect(hwnd
, &rcCredits
);
229 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
230 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
231 ReleaseDC(hwnd
, hDC
);
233 KillTimer(hwnd
, timerid
);
234 if (hCreditsBitmap
!= NULL
)
235 DeleteObject(hCreditsBitmap
);
241 InvalidateRect(hwnd
, NULL
, FALSE
);
249 HDC hDC
= GetDC(hwnd
);
252 GetClientRect(hwnd
, &rcCredits
);
253 SetRect(&rcCredits
, 0, 0, rcCredits
.right
, pImgInfo
->cySource
);
254 FillRect(hDC
, &rcCredits
, GetSysColorBrush(COLOR_3DFACE
));
255 ReleaseDC(hwnd
, hDC
);
257 KillTimer(hwnd
, timerid
);
258 if (hCreditsBitmap
!= NULL
)
259 DeleteObject(hCreditsBitmap
);
265 InvalidateRect(hwnd
, NULL
, FALSE
);
273 hdc
= wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &PS
);
275 GetClientRect(hwnd
, &PS
.rcPaint
);
277 /* Position image in center of dialog */
278 left
= (PS
.rcPaint
.right
- pImgInfo
->cxSource
) / 2;
279 hdcMem
= CreateCompatibleDC(hdc
);
285 SelectObject(hdcMem
, hCreditsBitmap
);
286 BitBlt(hdc
, left
, PS
.rcPaint
.top
, PS
.rcPaint
.right
- PS
.rcPaint
.left
, PS
.rcPaint
.top
+ pImgInfo
->cySource
, hdcMem
, 0, top
, SRCCOPY
);
290 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
291 AlphaBlend(hdc
, left
, PS
.rcPaint
.top
, pImgInfo
->cxSource
, pImgInfo
->cySource
, hdcMem
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
305 static VOID
SetRegTextData(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
311 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
313 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
318 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
319 SetDlgItemText(hwnd
, uID
, lpBuf
);
321 HeapFree(GetProcessHeap(), 0, lpBuf
);
325 static INT
SetProcNameString(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID1
, UINT uID2
)
335 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
337 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
342 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
344 if (BufSize
> ((30 + 1) * sizeof(TCHAR
)))
346 /* Wrap the Processor Name String like XP does: *
347 * - Take the first 30 characters and look for the last space. *
348 * Then wrap the string after this space. *
349 * - If no space is found, wrap the string after character 30. *
351 * For example the Processor Name String of a Pentium 4 is right-aligned. *
352 * With this wrapping the first line looks centered. */
354 _tcsncpy(szBuf
, lpBuf
, 30);
356 szLastSpace
= _tcsrchr(szBuf
, ' ');
358 if (szLastSpace
== 0)
364 LastSpace
= (szLastSpace
- szBuf
);
365 szBuf
[LastSpace
] = 0;
368 _tcsncpy(szBuf
, lpBuf
, LastSpace
);
370 SetDlgItemText(hwnd
, uID1
, szBuf
);
371 SetDlgItemText(hwnd
, uID2
, lpBuf
+LastSpace
+1);
373 /* Return the number of used lines */
378 SetDlgItemText(hwnd
, uID1
, lpBuf
);
383 HeapFree(GetProcessHeap(), 0, lpBuf
);
389 static VOID
MakeFloatValueString(DOUBLE
* dFloatValue
, LPTSTR szOutput
, LPTSTR szAppend
)
391 TCHAR szDecimalSeparator
[4];
393 /* Get the decimal separator for the current locale */
394 if (GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, szDecimalSeparator
, sizeof(szDecimalSeparator
) / sizeof(TCHAR
)) > 0)
399 /* Show the value with two decimals */
400 uIntegral
= (UINT
)*dFloatValue
;
401 uDecimals
= (UCHAR
)((UINT
)(*dFloatValue
* 100) - uIntegral
* 100);
403 wsprintf(szOutput
, _T("%u%s%02u %s"), uIntegral
, szDecimalSeparator
, uDecimals
, szAppend
);
407 static VOID
SetProcSpeed(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
409 TCHAR szBuf
[64], szHz
[16];
410 DWORD BufSize
= sizeof(DWORD
);
412 PROCESSOR_POWER_INFORMATION ppi
;
414 ZeroMemory(&ppi
, sizeof(ppi
));
416 if ((CallNtPowerInformation(ProcessorInformation
,
420 sizeof(ppi
)) == STATUS_SUCCESS
&&
421 ppi
.CurrentMhz
!= 0) || RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)&ppi
.CurrentMhz
, &BufSize
) == ERROR_SUCCESS
)
423 if (ppi
.CurrentMhz
< 1000)
425 if (!LoadString(hApplet
, IDS_MEGAHERTZ
, szHz
, _countof(szHz
)))
429 StringCchPrintf(szBuf
, _countof(szBuf
), _T("%lu %s"), ppi
.CurrentMhz
, szHz
);
433 double flt
= ppi
.CurrentMhz
/ 1000.0;
434 if (!LoadString(hApplet
, IDS_GIGAHERTZ
, szHz
, _countof(szHz
)))
438 MakeFloatValueString(&flt
, szBuf
, szHz
);
441 SetDlgItemText(hwnd
, uID
, szBuf
);
445 static VOID
GetSystemInformation(HWND hwnd
)
448 TCHAR SysKey
[] = _T("HARDWARE\\DESCRIPTION\\System");
449 TCHAR ProcKey
[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
450 MEMORYSTATUSEX MemStat
;
452 WCHAR SMBiosName
[96];
453 INT CurMachineLine
= IDC_MACHINELINE1
;
456 * Get hardware device name or motherboard name
457 * using information from raw SMBIOS data
459 if (GetSystemName(SMBiosName
, _countof(SMBiosName
)))
461 SetDlgItemText(hwnd
, CurMachineLine
, SMBiosName
);
466 /* If SMBIOS is not available, use System Identifier */
467 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SysKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
469 SetRegTextData(hwnd
, hKey
, _T("Identifier"), CurMachineLine
);
475 * Get Processor information
476 * although undocumented, this information is being pulled
477 * directly out of the registry instead of via setupapi as it
478 * contains all the info we need, and should remain static
480 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ProcKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
484 SetRegTextData(hwnd
, hKey
, _T("VendorIdentifier"), CurMachineLine
);
487 PrevMachineLine
= CurMachineLine
;
488 CurMachineLine
+= SetProcNameString(hwnd
,
490 _T("ProcessorNameString"),
494 if (CurMachineLine
== PrevMachineLine
)
496 /* TODO: Try obtaining CPU name from WMI (i.e. CIM_Processor) */
498 /* Brand String is not available, use Identifier instead */
499 CurMachineLine
+= SetProcNameString(hwnd
,
506 SetProcSpeed(hwnd
, hKey
, _T("~MHz"), CurMachineLine
);
511 /* Get total physical RAM */
512 MemStat
.dwLength
= sizeof(MemStat
);
514 if (GlobalMemoryStatusEx(&MemStat
))
519 if (MemStat
.ullTotalPhys
> 1024 * 1024 * 1024)
522 static const UINT uStrId
[] = { IDS_GIGABYTE
, IDS_TERABYTE
, IDS_PETABYTE
};
524 // We're dealing with GBs or more
525 MemStat
.ullTotalPhys
/= 1024 * 1024;
527 if (MemStat
.ullTotalPhys
> 1024 * 1024)
529 // We're dealing with TBs or more
530 MemStat
.ullTotalPhys
/= 1024;
533 if (MemStat
.ullTotalPhys
> 1024 * 1024)
535 // We're dealing with PBs or more
536 MemStat
.ullTotalPhys
/= 1024;
539 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
543 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
548 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
551 LoadString(hApplet
, uStrId
[i
], szStr
, sizeof(szStr
) / sizeof(TCHAR
));
552 MakeFloatValueString(&dTotalPhys
, Buf
, szStr
);
556 // We're dealing with MBs, don't show any decimals
557 LoadString(hApplet
, IDS_MEGABYTE
, szStr
, sizeof(szStr
) / sizeof(TCHAR
));
558 wsprintf(Buf
, _T("%u %s"), (UINT
)MemStat
.ullTotalPhys
/ 1024 / 1024, szStr
);
561 SetDlgItemText(hwnd
, CurMachineLine
, Buf
);
565 static VOID
GetSystemVersion(HWND hwnd
)
568 SIZE_T lenStr
, lenVersion
;
569 PCWSTR pwszVersion
= L
" " TEXT(KERNEL_VERSION_RC
);
572 lenVersion
= wcslen(pwszVersion
);
578 hRosVersion
= GetDlgItem(hwnd
, IDC_ROSVERSION
);
583 lenStr
= GetWindowTextLengthW(hRosVersion
);
584 lenStr
+= lenVersion
+ 1;
585 pwszStr
= HeapAlloc(GetProcessHeap(), 0, lenStr
* sizeof(WCHAR
));
590 GetWindowText(hRosVersion
, pwszStr
, lenStr
);
592 StringCchCatW(pwszStr
, lenStr
, pwszVersion
);
593 SetWindowText(hRosVersion
, pwszStr
);
595 HeapFree(GetProcessHeap(), 0, pwszStr
);
598 ULONGLONG
GetSecondsQPC(VOID
)
600 LARGE_INTEGER Counter
, Frequency
;
602 QueryPerformanceCounter(&Counter
);
603 QueryPerformanceFrequency(&Frequency
);
605 return Counter
.QuadPart
/ Frequency
.QuadPart
;
608 ULONGLONG
GetSeconds(VOID
)
610 ULONGLONG (WINAPI
* pGetTickCount64
)(VOID
);
612 HMODULE hModule
= GetModuleHandleW(L
"kernel32.dll");
614 pGetTickCount64
= (PVOID
)GetProcAddress(hModule
, "GetTickCount64");
617 return pGetTickCount64() / 1000;
620 hModule
= LoadLibraryW(L
"kernel32_vista.dll");
624 return GetSecondsQPC();
627 pGetTickCount64
= (PVOID
)GetProcAddress(hModule
, "GetTickCount64");
631 Ticks64
= pGetTickCount64() / 1000;
635 Ticks64
= GetSecondsQPC();
638 FreeLibrary(hModule
);
642 VOID
GetSystemUptime(HWND hwnd
)
645 WCHAR szBuf
[64], szStr
[64];
648 hRosUptime
= GetDlgItem(hwnd
, IDC_UPTIME
);
653 if (!LoadStringW(hApplet
, IDS_UPTIME_FORMAT
, szStr
, _countof(szStr
)))
657 cSeconds
= GetSeconds();
658 StringCchPrintfW(szBuf
, _countof(szBuf
), szStr
,
659 cSeconds
/ (60*60*24),
660 (cSeconds
/ (60*60)) % 24,
661 (cSeconds
/ 60) % 60,
664 SetWindowTextW(hRosUptime
, szBuf
);
667 /* Property page dialog callback */
668 INT_PTR CALLBACK
GeneralPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
670 UNREFERENCED_PARAMETER(lParam
);
671 UNREFERENCED_PARAMETER(wParam
);
676 pImgInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IMGINFO
));
677 if (pImgInfo
== NULL
)
679 EndDialog(hwndDlg
, 0);
684 SetWindowLongPtr(GetDlgItem(hwndDlg
, IDC_ROSIMG
), GWLP_WNDPROC
, (LONG_PTR
)RosImageProc
);
685 GetSystemInformation(hwndDlg
);
686 GetSystemVersion(hwndDlg
);
687 GetSystemUptime(hwndDlg
);
691 HeapFree(GetProcessHeap(), 0, pImgInfo
);
695 if (LOWORD(wParam
) == IDC_LICENCE
)
697 DialogBox(hApplet
, MAKEINTRESOURCE(IDD_LICENCE
), hwndDlg
, LicenceDlgProc
);
705 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) lParam
;
707 if (lpDrawItem
->CtlID
== IDC_ROSIMG
)
712 /* Position image in centre of dialog */
713 left
= (lpDrawItem
->rcItem
.right
- pImgInfo
->cxSource
) / 2;
715 hdcMem
= CreateCompatibleDC(lpDrawItem
->hDC
);
718 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
719 BitBlt(lpDrawItem
->hDC
,
721 lpDrawItem
->rcItem
.top
,
722 lpDrawItem
->rcItem
.right
- lpDrawItem
->rcItem
.left
,
723 lpDrawItem
->rcItem
.bottom
- lpDrawItem
->rcItem
.top
,
736 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
738 if (nmhdr
->idFrom
== IDC_ROSHOMEPAGE_LINK
&& nmhdr
->code
== NM_CLICK
)
740 PNMLINK nml
= (PNMLINK
)nmhdr
;
742 ShellExecuteW(hwndDlg
, L
"open", nml
->item
.szUrl
, NULL
, NULL
, SW_SHOWNORMAL
);