reactos/dll/cpl/sysdm/general.c
Joachim Henze b2d72aafb7 [0.4.13][SYSDM] Fix version string cutoff CORE-17429
The version string cutoff started to happen when we switched from SVN
with its short revision number to git with the longer hashes.
0.4.7-dev-502-gc2c66af was the first git-only rev (2017-Oct-03)

and brings the dialogs layout closer to XP.
Also fixes some other truncations for specific languages.
And unifies the touched text controls sizes for all languages.

The credits have been moved to readme.txt where they are more present and
we can avoid having to groom all languages files each time we want to add
a new dev (and sysdm.cpl to grow each time). Less maintenance.

sysdm.cpl binary size I18N=all
master before 925.696bytes  after 705.024bytes  gcc 8.4.0 dbg RosBE2.2.1
0.4.14 before 923.136bytes  after 702.464bytes  gcc 8.4.0 dbg RosBE2.2.1
0.4.13 before 904.192bytes  after 684.544bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4.12 before 881.664bytes  after 665.600bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4.11 before 836.096bytes  after 618.496bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4.10 before 806.912bytes  after 588.800bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4. 9 before 788.480bytes  after 585.728bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4. 8 before 788.480bytes  after 585.728bytes  gcc 4.7.2 dbg RosBE2.1.6
0.4. 7 before 788.992bytes  after 585.728bytes  gcc 4.7.2 dbg RosBE2.1.6

readme.txt still fits into a single NTFS cluster afterwards with 3702bytes

Also a very! soft update of some translations ported back.
2021-01-30 20:44:48 +01:00

585 lines
17 KiB
C

/*
* PROJECT: ReactOS System Control Panel Applet
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/cpl/sysdm/general.c
* PURPOSE: General System Information
* COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org>
* Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
* Copyright 2006-2007 Colin Finck <mail@colinfinck.de>
*
*/
#include "precomp.h"
#include <winnls.h>
#include <powrprof.h>
#include <buildno.h>
#include <strsafe.h>
typedef struct _IMGINFO
{
HBITMAP hBitmap;
INT cxSource;
INT cySource;
INT iPLanes;
INT iBits;
} IMGINFO, *PIMGINFO;
PIMGINFO pImgInfo = NULL;
BLENDFUNCTION BlendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
VOID ShowLastWin32Error(HWND hWndOwner)
{
LPTSTR lpMsg;
DWORD LastError;
LastError = GetLastError();
if (LastError == ERROR_SUCCESS)
return;
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
LastError,
LANG_USER_DEFAULT,
(LPTSTR)&lpMsg,
0, NULL))
{
return;
}
MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR);
LocalFree(lpMsg);
}
static VOID InitLogo(HWND hwndDlg)
{
BITMAP logoBitmap;
BITMAP maskBitmap;
BITMAPINFO bmpi;
HDC hDC = GetDC(hwndDlg);
HDC hDCLogo = CreateCompatibleDC(NULL);
HDC hDCMask = CreateCompatibleDC(NULL);
HBITMAP hMask, hLogo, hAlphaLogo = NULL;
COLORREF *pBits;
INT line, column;
ZeroMemory(pImgInfo, sizeof(*pImgInfo));
ZeroMemory(&bmpi, sizeof(bmpi));
hLogo = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSBMP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
hMask = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSMASK), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
if (hLogo != NULL && hMask != NULL)
{
GetObject(hLogo, sizeof(BITMAP), &logoBitmap);
GetObject(hMask, sizeof(BITMAP), &maskBitmap);
if(logoBitmap.bmHeight != maskBitmap.bmHeight || logoBitmap.bmWidth != maskBitmap.bmWidth)
return;
pImgInfo->cxSource = logoBitmap.bmWidth;
pImgInfo->cySource = logoBitmap.bmHeight;
bmpi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmpi.bmiHeader.biWidth = logoBitmap.bmWidth;
bmpi.bmiHeader.biHeight = logoBitmap.bmHeight;
bmpi.bmiHeader.biPlanes = 1;
bmpi.bmiHeader.biBitCount = 32;
bmpi.bmiHeader.biCompression = BI_RGB;
bmpi.bmiHeader.biSizeImage = 4 * logoBitmap.bmWidth * logoBitmap.bmHeight;
hAlphaLogo = CreateDIBSection(hDC, &bmpi, DIB_RGB_COLORS, (PVOID*)&pBits, 0, 0);
if(!hAlphaLogo)
return;
SelectObject(hDCLogo, hLogo);
SelectObject(hDCMask, hMask);
for(line = logoBitmap.bmHeight - 1; line >= 0; line--)
{
for(column = 0; column < logoBitmap.bmWidth; column++)
{
COLORREF alpha = GetPixel(hDCMask, column, line) & 0xFF;
COLORREF Color = GetPixel(hDCLogo, column, line);
DWORD r, g, b;
r = GetRValue(Color) * alpha / 255;
g = GetGValue(Color) * alpha / 255;
b = GetBValue(Color) * alpha / 255;
*pBits++ = b | g << 8 | r << 16 | alpha << 24;
}
}
}
pImgInfo->hBitmap = hAlphaLogo;
pImgInfo->cxSource = logoBitmap.bmWidth;
pImgInfo->cySource = logoBitmap.bmHeight;
pImgInfo->iBits = logoBitmap.bmBitsPixel;
pImgInfo->iPLanes = logoBitmap.bmPlanes;
DeleteObject(hLogo);
DeleteObject(hMask);
DeleteDC(hDCLogo);
DeleteDC(hDCMask);
}
LRESULT CALLBACK RosImageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT PS;
HDC hdcMem, hdc;
LONG left;
hdc = wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &PS);
GetClientRect(hwnd, &PS.rcPaint);
/* Position image in center of dialog */
left = (PS.rcPaint.right - pImgInfo->cxSource) / 2;
hdcMem = CreateCompatibleDC(hdc);
if (hdcMem != NULL)
{
SelectObject(hdcMem, pImgInfo->hBitmap);
/* FIXME: We should not rely on AlphaBlend and we should not import MSIMG32 solely for that function */
AlphaBlend(hdc, left, PS.rcPaint.top, pImgInfo->cxSource, pImgInfo->cySource, hdcMem, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
DeleteDC(hdcMem);
}
if (wParam == 0)
EndPaint(hwnd,&PS);
break;
}
}
return TRUE;
}
static VOID SetRegTextData(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
{
LPTSTR lpBuf = NULL;
DWORD BufSize = 0;
DWORD Type;
if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
{
lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
if (!lpBuf)
return;
if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
SetDlgItemText(hwnd, uID, lpBuf);
HeapFree(GetProcessHeap(), 0, lpBuf);
}
}
static INT SetProcNameString(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID1, UINT uID2)
{
LPTSTR lpBuf = NULL;
DWORD BufSize = 0;
DWORD Type;
INT Ret = 0;
TCHAR szBuf[31];
TCHAR* szLastSpace;
INT LastSpace = 0;
if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
{
lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
if (!lpBuf)
return 0;
if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
{
if (BufSize > ((30 + 1) * sizeof(TCHAR)))
{
/* Wrap the Processor Name String like XP does: *
* - Take the first 30 characters and look for the last space. *
* Then wrap the string after this space. *
* - If no space is found, wrap the string after character 30. *
* *
* For example the Processor Name String of a Pentium 4 is right-aligned. *
* With this wrapping the first line looks centered. */
_tcsncpy(szBuf, lpBuf, 30);
szBuf[30] = 0;
szLastSpace = _tcsrchr(szBuf, ' ');
if (szLastSpace == 0)
{
LastSpace = 30;
}
else
{
LastSpace = (szLastSpace - szBuf);
szBuf[LastSpace] = 0;
}
_tcsncpy(szBuf, lpBuf, LastSpace);
SetDlgItemText(hwnd, uID1, szBuf);
SetDlgItemText(hwnd, uID2, lpBuf+LastSpace+1);
/* Return the number of used lines */
Ret = 2;
}
else
{
SetDlgItemText(hwnd, uID1, lpBuf);
Ret = 1;
}
}
HeapFree(GetProcessHeap(), 0, lpBuf);
}
return Ret;
}
static VOID MakeFloatValueString(DOUBLE* dFloatValue, LPTSTR szOutput, LPTSTR szAppend)
{
TCHAR szDecimalSeparator[4];
/* Get the decimal separator for the current locale */
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0)
{
UCHAR uDecimals;
UINT uIntegral;
/* Show the value with two decimals */
uIntegral = (UINT)*dFloatValue;
uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100);
wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend);
}
}
static VOID SetProcSpeed(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
{
TCHAR szBuf[64], szHz[16];
DWORD BufSize = sizeof(DWORD);
DWORD Type = REG_SZ;
PROCESSOR_POWER_INFORMATION ppi;
ZeroMemory(&ppi, sizeof(ppi));
if ((CallNtPowerInformation(ProcessorInformation,
NULL,
0,
(PVOID)&ppi,
sizeof(ppi)) == STATUS_SUCCESS &&
ppi.CurrentMhz != 0) || RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)&ppi.CurrentMhz, &BufSize) == ERROR_SUCCESS)
{
if (ppi.CurrentMhz < 1000)
{
if (!LoadString(hApplet, IDS_MEGAHERTZ, szHz, _countof(szHz)))
{
return;
}
StringCchPrintf(szBuf, _countof(szBuf), _T("%lu %s"), ppi.CurrentMhz, szHz);
}
else
{
double flt = ppi.CurrentMhz / 1000.0;
if (!LoadString(hApplet, IDS_GIGAHERTZ, szHz, _countof(szHz)))
{
return;
}
MakeFloatValueString(&flt, szBuf, szHz);
}
SetDlgItemText(hwnd, uID, szBuf);
}
}
static VOID GetSystemInformation(HWND hwnd)
{
HKEY hKey;
TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
MEMORYSTATUSEX MemStat;
TCHAR Buf[32];
WCHAR SMBiosName[96];
INT CurMachineLine = IDC_MACHINELINE1;
/*
* Get hardware device name or motherboard name
* using information from raw SMBIOS data
*/
if (GetSystemName(SMBiosName, _countof(SMBiosName)))
{
SetDlgItemText(hwnd, CurMachineLine, SMBiosName);
CurMachineLine++;
}
/*
* Get Processor information
* although undocumented, this information is being pulled
* directly out of the registry instead of via setupapi as it
* contains all the info we need, and should remain static
*/
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine);
CurMachineLine++;
CurMachineLine += SetProcNameString(hwnd,
hKey,
_T("ProcessorNameString"),
CurMachineLine,
CurMachineLine + 1);
SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine);
CurMachineLine++;
}
/* Get total physical RAM */
MemStat.dwLength = sizeof(MemStat);
if (GlobalMemoryStatusEx(&MemStat))
{
TCHAR szStr[32];
double dTotalPhys;
if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
{
UINT i = 0;
static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE};
// We're dealing with GBs or more
MemStat.ullTotalPhys /= 1024 * 1024;
if (MemStat.ullTotalPhys > 1024 * 1024)
{
// We're dealing with TBs or more
MemStat.ullTotalPhys /= 1024;
i++;
if (MemStat.ullTotalPhys > 1024 * 1024)
{
// We're dealing with PBs or more
MemStat.ullTotalPhys /= 1024;
i++;
dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
}
else
{
dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
}
}
else
{
dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
}
LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR));
MakeFloatValueString(&dTotalPhys, Buf, szStr);
}
else
{
// We're dealing with MBs, don't show any decimals
LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR));
wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr);
}
SetDlgItemText(hwnd, CurMachineLine, Buf);
}
}
static VOID GetSystemVersion(HWND hwnd)
{
HWND hRosVersion;
SIZE_T lenStr, lenVersion;
PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC);
PWSTR pwszStr;
lenVersion = wcslen(pwszVersion);
if (lenVersion == 0)
{
return;
}
hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION);
if (!hRosVersion)
{
return;
}
lenStr = GetWindowTextLengthW(hRosVersion);
lenStr += lenVersion + 1;
pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR));
if (!pwszStr)
{
return;
}
GetWindowText(hRosVersion, pwszStr, lenStr);
StringCchCatW(pwszStr, lenStr, pwszVersion);
SetWindowText(hRosVersion, pwszStr);
HeapFree(GetProcessHeap(), 0, pwszStr);
}
ULONGLONG GetSecondsQPC(VOID)
{
LARGE_INTEGER Counter, Frequency;
QueryPerformanceCounter(&Counter);
QueryPerformanceFrequency(&Frequency);
return Counter.QuadPart / Frequency.QuadPart;
}
ULONGLONG GetSeconds(VOID)
{
ULONGLONG (WINAPI * pGetTickCount64)(VOID);
ULONGLONG Ticks64;
HMODULE hModule = GetModuleHandleW(L"kernel32.dll");
pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64");
if (pGetTickCount64)
{
return pGetTickCount64() / 1000;
}
hModule = LoadLibraryW(L"kernel32_vista.dll");
if (!hModule)
{
return GetSecondsQPC();
}
pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64");
if (pGetTickCount64)
{
Ticks64 = pGetTickCount64() / 1000;
}
else
{
Ticks64 = GetSecondsQPC();
}
FreeLibrary(hModule);
return Ticks64;
}
VOID GetSystemUptime(HWND hwnd)
{
HWND hRosUptime;
WCHAR szBuf[64], szStr[64];
ULONG cSeconds;
hRosUptime = GetDlgItem(hwnd, IDC_UPTIME);
if (!hRosUptime)
{
return;
}
if (!LoadStringW(hApplet, IDS_UPTIME_FORMAT, szStr, _countof(szStr)))
{
return;
}
cSeconds = GetSeconds();
StringCchPrintfW(szBuf, _countof(szBuf), szStr,
cSeconds / (60*60*24),
(cSeconds / (60*60)) % 24,
(cSeconds / 60) % 60,
cSeconds % 60);
SetWindowTextW(hRosUptime, szBuf);
}
/* Property page dialog callback */
INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(wParam);
switch (uMsg)
{
case WM_INITDIALOG:
pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO));
if (pImgInfo == NULL)
{
EndDialog(hwndDlg, 0);
return FALSE;
}
InitLogo(hwndDlg);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc);
GetSystemInformation(hwndDlg);
GetSystemVersion(hwndDlg);
GetSystemUptime(hwndDlg);
break;
case WM_DESTROY:
HeapFree(GetProcessHeap(), 0, pImgInfo);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_LICENCE)
{
DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc);
return TRUE;
}
break;
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
if (lpDrawItem->CtlID == IDC_ROSIMG)
{
HDC hdcMem;
LONG left;
/* Position image in centre of dialog */
left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2;
hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
if (hdcMem != NULL)
{
SelectObject(hdcMem, pImgInfo->hBitmap);
BitBlt(lpDrawItem->hDC,
left,
lpDrawItem->rcItem.top,
lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
hdcMem,
0,
0,
SRCCOPY);
DeleteDC(hdcMem);
}
}
return TRUE;
}
case WM_NOTIFY:
{
NMHDR *nmhdr = (NMHDR *)lParam;
if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
{
PNMLINK nml = (PNMLINK)nmhdr;
ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL);
}
break;
}
}
return FALSE;
}