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
)
146 hdc
= wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &PS
);
148 GetClientRect(hwnd
, &PS
.rcPaint
);
150 /* Position image in center of dialog */
151 left
= (PS
.rcPaint
.right
- pImgInfo
->cxSource
) / 2;
152 hdcMem
= CreateCompatibleDC(hdc
);
156 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
157 /* FIXME: We should not rely on AlphaBlend and we should not import MSIMG32 solely for that function */
158 AlphaBlend(hdc
, left
, PS
.rcPaint
.top
, pImgInfo
->cxSource
, pImgInfo
->cySource
, hdcMem
, 0, 0, pImgInfo
->cxSource
, pImgInfo
->cySource
, BlendFunc
);
170 static VOID
SetRegTextData(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
176 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
178 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
183 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
184 SetDlgItemText(hwnd
, uID
, lpBuf
);
186 HeapFree(GetProcessHeap(), 0, lpBuf
);
190 static INT
SetProcNameString(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID1
, UINT uID2
)
200 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, NULL
, &BufSize
) == ERROR_SUCCESS
)
202 lpBuf
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
207 if (RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)lpBuf
, &BufSize
) == ERROR_SUCCESS
)
209 if (BufSize
> ((30 + 1) * sizeof(TCHAR
)))
211 /* Wrap the Processor Name String like XP does: *
212 * - Take the first 30 characters and look for the last space. *
213 * Then wrap the string after this space. *
214 * - If no space is found, wrap the string after character 30. *
216 * For example the Processor Name String of a Pentium 4 is right-aligned. *
217 * With this wrapping the first line looks centered. */
219 _tcsncpy(szBuf
, lpBuf
, 30);
221 szLastSpace
= _tcsrchr(szBuf
, ' ');
223 if (szLastSpace
== 0)
229 LastSpace
= (szLastSpace
- szBuf
);
230 szBuf
[LastSpace
] = 0;
233 _tcsncpy(szBuf
, lpBuf
, LastSpace
);
235 SetDlgItemText(hwnd
, uID1
, szBuf
);
236 SetDlgItemText(hwnd
, uID2
, lpBuf
+LastSpace
+1);
238 /* Return the number of used lines */
243 SetDlgItemText(hwnd
, uID1
, lpBuf
);
248 HeapFree(GetProcessHeap(), 0, lpBuf
);
254 static VOID
MakeFloatValueString(DOUBLE
* dFloatValue
, LPTSTR szOutput
, LPTSTR szAppend
)
256 TCHAR szDecimalSeparator
[4];
258 /* Get the decimal separator for the current locale */
259 if (GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, szDecimalSeparator
, sizeof(szDecimalSeparator
) / sizeof(TCHAR
)) > 0)
264 /* Show the value with two decimals */
265 uIntegral
= (UINT
)*dFloatValue
;
266 uDecimals
= (UCHAR
)((UINT
)(*dFloatValue
* 100) - uIntegral
* 100);
268 wsprintf(szOutput
, _T("%u%s%02u %s"), uIntegral
, szDecimalSeparator
, uDecimals
, szAppend
);
272 static VOID
SetProcSpeed(HWND hwnd
, HKEY hKey
, LPTSTR Value
, UINT uID
)
274 TCHAR szBuf
[64], szHz
[16];
275 DWORD BufSize
= sizeof(DWORD
);
277 PROCESSOR_POWER_INFORMATION ppi
;
279 ZeroMemory(&ppi
, sizeof(ppi
));
281 if ((CallNtPowerInformation(ProcessorInformation
,
285 sizeof(ppi
)) == STATUS_SUCCESS
&&
286 ppi
.CurrentMhz
!= 0) || RegQueryValueEx(hKey
, Value
, NULL
, &Type
, (PBYTE
)&ppi
.CurrentMhz
, &BufSize
) == ERROR_SUCCESS
)
288 if (ppi
.CurrentMhz
< 1000)
290 if (!LoadString(hApplet
, IDS_MEGAHERTZ
, szHz
, _countof(szHz
)))
294 StringCchPrintf(szBuf
, _countof(szBuf
), _T("%lu %s"), ppi
.CurrentMhz
, szHz
);
298 double flt
= ppi
.CurrentMhz
/ 1000.0;
299 if (!LoadString(hApplet
, IDS_GIGAHERTZ
, szHz
, _countof(szHz
)))
303 MakeFloatValueString(&flt
, szBuf
, szHz
);
306 SetDlgItemText(hwnd
, uID
, szBuf
);
310 static VOID
GetSystemInformation(HWND hwnd
)
313 TCHAR SysKey
[] = _T("HARDWARE\\DESCRIPTION\\System");
314 TCHAR ProcKey
[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
315 MEMORYSTATUSEX MemStat
;
317 WCHAR SMBiosName
[96];
318 INT CurMachineLine
= IDC_MACHINELINE1
;
321 * Get hardware device name or motherboard name
322 * using information from raw SMBIOS data
324 if (GetSystemName(SMBiosName
, _countof(SMBiosName
)))
326 SetDlgItemText(hwnd
, CurMachineLine
, SMBiosName
);
331 /* If SMBIOS is not available, use System Identifier */
332 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, SysKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
334 SetRegTextData(hwnd
, hKey
, _T("Identifier"), CurMachineLine
);
340 * Get Processor information
341 * although undocumented, this information is being pulled
342 * directly out of the registry instead of via setupapi as it
343 * contains all the info we need, and should remain static
345 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, ProcKey
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
349 SetRegTextData(hwnd
, hKey
, _T("VendorIdentifier"), CurMachineLine
);
352 PrevMachineLine
= CurMachineLine
;
353 CurMachineLine
+= SetProcNameString(hwnd
,
355 _T("ProcessorNameString"),
359 if (CurMachineLine
== PrevMachineLine
)
361 /* TODO: Try obtaining CPU name from WMI (i.e. CIM_Processor) */
363 /* Brand String is not available, use Identifier instead */
364 CurMachineLine
+= SetProcNameString(hwnd
,
371 SetProcSpeed(hwnd
, hKey
, _T("~MHz"), CurMachineLine
);
376 /* Get total physical RAM */
377 MemStat
.dwLength
= sizeof(MemStat
);
379 if (GlobalMemoryStatusEx(&MemStat
))
384 if (MemStat
.ullTotalPhys
> 1024 * 1024 * 1024)
387 static const UINT uStrId
[] = { IDS_GIGABYTE
, IDS_TERABYTE
, IDS_PETABYTE
};
389 // We're dealing with GBs or more
390 MemStat
.ullTotalPhys
/= 1024 * 1024;
392 if (MemStat
.ullTotalPhys
> 1024 * 1024)
394 // We're dealing with TBs or more
395 MemStat
.ullTotalPhys
/= 1024;
398 if (MemStat
.ullTotalPhys
> 1024 * 1024)
400 // We're dealing with PBs or more
401 MemStat
.ullTotalPhys
/= 1024;
404 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
408 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
413 dTotalPhys
= (double)MemStat
.ullTotalPhys
/ 1024;
416 LoadString(hApplet
, uStrId
[i
], szStr
, sizeof(szStr
) / sizeof(TCHAR
));
417 MakeFloatValueString(&dTotalPhys
, Buf
, szStr
);
421 // We're dealing with MBs, don't show any decimals
422 LoadString(hApplet
, IDS_MEGABYTE
, szStr
, sizeof(szStr
) / sizeof(TCHAR
));
423 wsprintf(Buf
, _T("%u %s"), (UINT
)MemStat
.ullTotalPhys
/ 1024 / 1024, szStr
);
426 SetDlgItemText(hwnd
, CurMachineLine
, Buf
);
430 static VOID
GetSystemVersion(HWND hwnd
)
433 SIZE_T lenStr
, lenVersion
;
434 PCWSTR pwszVersion
= L
" " TEXT(KERNEL_VERSION_RC
);
437 lenVersion
= wcslen(pwszVersion
);
443 hRosVersion
= GetDlgItem(hwnd
, IDC_ROSVERSION
);
448 lenStr
= GetWindowTextLengthW(hRosVersion
);
449 lenStr
+= lenVersion
+ 1;
450 pwszStr
= HeapAlloc(GetProcessHeap(), 0, lenStr
* sizeof(WCHAR
));
455 GetWindowText(hRosVersion
, pwszStr
, lenStr
);
457 StringCchCatW(pwszStr
, lenStr
, pwszVersion
);
458 SetWindowText(hRosVersion
, pwszStr
);
460 HeapFree(GetProcessHeap(), 0, pwszStr
);
463 ULONGLONG
GetSecondsQPC(VOID
)
465 LARGE_INTEGER Counter
, Frequency
;
467 QueryPerformanceCounter(&Counter
);
468 QueryPerformanceFrequency(&Frequency
);
470 return Counter
.QuadPart
/ Frequency
.QuadPart
;
473 ULONGLONG
GetSeconds(VOID
)
475 ULONGLONG (WINAPI
* pGetTickCount64
)(VOID
);
477 HMODULE hModule
= GetModuleHandleW(L
"kernel32.dll");
479 pGetTickCount64
= (PVOID
)GetProcAddress(hModule
, "GetTickCount64");
482 return pGetTickCount64() / 1000;
485 hModule
= LoadLibraryW(L
"kernel32_vista.dll");
489 return GetSecondsQPC();
492 pGetTickCount64
= (PVOID
)GetProcAddress(hModule
, "GetTickCount64");
496 Ticks64
= pGetTickCount64() / 1000;
500 Ticks64
= GetSecondsQPC();
503 FreeLibrary(hModule
);
507 VOID
GetSystemUptime(HWND hwnd
)
510 WCHAR szBuf
[64], szStr
[64];
513 hRosUptime
= GetDlgItem(hwnd
, IDC_UPTIME
);
518 if (!LoadStringW(hApplet
, IDS_UPTIME_FORMAT
, szStr
, _countof(szStr
)))
522 cSeconds
= GetSeconds();
523 StringCchPrintfW(szBuf
, _countof(szBuf
), szStr
,
524 cSeconds
/ (60*60*24),
525 (cSeconds
/ (60*60)) % 24,
526 (cSeconds
/ 60) % 60,
529 SetWindowTextW(hRosUptime
, szBuf
);
532 /* Property page dialog callback */
533 INT_PTR CALLBACK
GeneralPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
535 UNREFERENCED_PARAMETER(lParam
);
536 UNREFERENCED_PARAMETER(wParam
);
541 pImgInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IMGINFO
));
542 if (pImgInfo
== NULL
)
544 EndDialog(hwndDlg
, 0);
549 SetWindowLongPtr(GetDlgItem(hwndDlg
, IDC_ROSIMG
), GWLP_WNDPROC
, (LONG_PTR
)RosImageProc
);
550 GetSystemInformation(hwndDlg
);
551 GetSystemVersion(hwndDlg
);
552 GetSystemUptime(hwndDlg
);
556 HeapFree(GetProcessHeap(), 0, pImgInfo
);
560 if (LOWORD(wParam
) == IDC_LICENCE
)
562 DialogBox(hApplet
, MAKEINTRESOURCE(IDD_LICENCE
), hwndDlg
, LicenceDlgProc
);
570 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) lParam
;
572 if (lpDrawItem
->CtlID
== IDC_ROSIMG
)
577 /* Position image in centre of dialog */
578 left
= (lpDrawItem
->rcItem
.right
- pImgInfo
->cxSource
) / 2;
580 hdcMem
= CreateCompatibleDC(lpDrawItem
->hDC
);
583 SelectObject(hdcMem
, pImgInfo
->hBitmap
);
584 BitBlt(lpDrawItem
->hDC
,
586 lpDrawItem
->rcItem
.top
,
587 lpDrawItem
->rcItem
.right
- lpDrawItem
->rcItem
.left
,
588 lpDrawItem
->rcItem
.bottom
- lpDrawItem
->rcItem
.top
,
601 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
603 if (nmhdr
->idFrom
== IDC_ROSHOMEPAGE_LINK
&& nmhdr
->code
== NM_CLICK
)
605 PNMLINK nml
= (PNMLINK
)nmhdr
;
607 ShellExecuteW(hwndDlg
, L
"open", nml
->item
.szUrl
, NULL
, NULL
, SW_SHOWNORMAL
);