Display a nice ReactOS version desktop watermark (with different fonts) when the corresponding registry values are set.
See http://winaero.com/blog/a-new-way-to-display-the-windows-version-on-your-desktop/ for more details (which works on Windows 2003 too).
CORE-11349 #resolve

svn path=/trunk/; revision=71486
This commit is contained in:
Hermès Bélusca-Maïto 2016-06-01 15:24:38 +00:00
parent f61200c5d3
commit 30c8acce49
3 changed files with 305 additions and 52 deletions

View file

@ -3,7 +3,7 @@
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Desktops
* FILE: subsystems/win32/win32k/ntuser/desktop.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES ******************************************************************/
@ -246,41 +246,201 @@ InitDesktopImpl(VOID)
return STATUS_SUCCESS;
}
static INT GetSystemVersionString(PWSTR* buffer)
static NTSTATUS
GetSystemVersionString(OUT PWSTR pwszzVersion,
IN SIZE_T cchDest,
IN BOOLEAN InSafeMode,
IN BOOLEAN AppendNtSystemRoot)
{
static WCHAR wszVersion[256] = L"";
int len = 0;
NTSTATUS Status;
if (!*wszVersion)
{
#if 0 // Disabled until versioning in win32k gets correctly implemented (hbelusca, r66750).
RTL_OSVERSIONINFOEXW versionInfo;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
return 0;
if (versionInfo.dwMajorVersion <= 4)
len = swprintf(wszVersion,
L"ReactOS Version %lu.%lu %s Build %lu",
versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
versionInfo.szCSDVersion, versionInfo.dwBuildNumber & 0xFFFF);
else
len = swprintf(wszVersion,
L"ReactOS %s (Build %lu)",
versionInfo.szCSDVersion, versionInfo.dwBuildNumber & 0xFFFF);
#else
len = swprintf(wszVersion, L"ReactOS Version %S %S", KERNEL_VERSION_STR, KERNEL_VERSION_BUILD_STR);
RTL_OSVERSIONINFOEXW VerInfo;
UNICODE_STRING CSDVersionString;
#if 0
UNICODE_STRING CurBuildNmString;
#endif
RTL_QUERY_REGISTRY_TABLE VersionConfigurationTable[2] =
{
{
NULL,
RTL_QUERY_REGISTRY_DIRECT,
L"CSDVersion",
&CSDVersionString,
REG_NONE, NULL, 0
},
#if 0
{
NULL,
RTL_QUERY_REGISTRY_DIRECT,
L"CurrentBuildNumber",
&CurBuildNmString,
REG_NONE, NULL, 0
},
#endif
{0}
};
WCHAR VersionBuffer[256];
PWCHAR EndBuffer;
VerInfo.dwOSVersionInfoSize = sizeof(VerInfo);
/*
* This call is uniquely used to retrieve the current CSD numbers.
* All the rest (major, minor, ...) is either retrieved from the
* SharedUserData structure, or from the registry.
*/
RtlGetVersion((PRTL_OSVERSIONINFOW)&VerInfo);
/*
* In kernel-mode, szCSDVersion is not initialized. Initialize it
* and query its value from the registry.
*/
RtlZeroMemory(VerInfo.szCSDVersion, sizeof(VerInfo.szCSDVersion));
RtlInitEmptyUnicodeString(&CSDVersionString,
VerInfo.szCSDVersion,
sizeof(VerInfo.szCSDVersion));
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
L"",
VersionConfigurationTable,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
/* Indicate nothing is there */
CSDVersionString.Length = 0;
}
/* NULL-terminate */
CSDVersionString.Buffer[CSDVersionString.Length / sizeof(WCHAR)] = UNICODE_NULL;
EndBuffer = VersionBuffer;
if ( /* VerInfo.wServicePackMajor != 0 && */ CSDVersionString.Length)
{
/* Print the version string */
Status = RtlStringCbPrintfExW(VersionBuffer,
sizeof(VersionBuffer),
&EndBuffer,
NULL,
0,
L": %wZ",
&CSDVersionString);
if (!NT_SUCCESS(Status))
{
/* No version, NULL-terminate the string */
*EndBuffer = UNICODE_NULL;
}
}
else
{
len = wcslen(wszVersion);
/* No version, NULL-terminate the string */
*EndBuffer = UNICODE_NULL;
}
*buffer = wszVersion;
return len;
if (InSafeMode)
{
/* String for Safe Mode */
Status = RtlStringCchPrintfW(pwszzVersion,
cchDest,
L"ReactOS Version %S %S (NT %u.%u Build %u%s)\n",
KERNEL_VERSION_STR,
KERNEL_VERSION_BUILD_STR, // Same as the "BuildLab" string in the registry
SharedUserData->NtMajorVersion,
SharedUserData->NtMinorVersion,
(VerInfo.dwBuildNumber & 0xFFFF),
VersionBuffer);
if (AppendNtSystemRoot && NT_SUCCESS(Status))
{
Status = RtlStringCbPrintfW(VersionBuffer,
sizeof(VersionBuffer),
L" - %s\n",
SharedUserData->NtSystemRoot);
if (NT_SUCCESS(Status))
{
/* Replace the last newline by a NULL, before concatenating */
EndBuffer = wcsrchr(pwszzVersion, L'\n');
if (EndBuffer) *EndBuffer = UNICODE_NULL;
/* The concatenated string has a terminating newline */
Status = RtlStringCchCatW(pwszzVersion,
cchDest,
VersionBuffer);
if (!NT_SUCCESS(Status))
{
/* Concatenation failed, put back the newline */
if (EndBuffer) *EndBuffer = L'\n';
}
}
/* Override any failures as the NtSystemRoot string is optional */
Status = STATUS_SUCCESS;
}
}
else
{
/* Multi-string for Normal Mode */
Status = RtlStringCchPrintfW(pwszzVersion,
cchDest,
L"ReactOS Version %S\n"
L"Build %S\n"
L"Reporting NT %u.%u (Build %u%s)\n",
KERNEL_VERSION_STR,
KERNEL_VERSION_BUILD_STR, // Same as the "BuildLab" string in the registry
SharedUserData->NtMajorVersion,
SharedUserData->NtMinorVersion,
(VerInfo.dwBuildNumber & 0xFFFF),
VersionBuffer);
if (AppendNtSystemRoot && NT_SUCCESS(Status))
{
Status = RtlStringCbPrintfW(VersionBuffer,
sizeof(VersionBuffer),
L"%s\n",
SharedUserData->NtSystemRoot);
if (NT_SUCCESS(Status))
{
Status = RtlStringCchCatW(pwszzVersion,
cchDest,
VersionBuffer);
}
/* Override any failures as the NtSystemRoot string is optional */
Status = STATUS_SUCCESS;
}
}
if (!NT_SUCCESS(Status))
{
/* Fall-back string */
Status = RtlStringCchPrintfW(pwszzVersion,
cchDest,
L"ReactOS Version %S %S\n",
KERNEL_VERSION_STR,
KERNEL_VERSION_BUILD_STR);
if (!NT_SUCCESS(Status))
{
/* General failure, NULL-terminate the string */
pwszzVersion[0] = UNICODE_NULL;
}
}
/*
* Convert the string separators (newlines) into NULLs
* and NULL-terminate the multi-string.
*/
while (*pwszzVersion)
{
EndBuffer = wcschr(pwszzVersion, L'\n');
if (!EndBuffer) break;
pwszzVersion = EndBuffer;
*pwszzVersion++ = UNICODE_NULL;
}
*pwszzVersion = UNICODE_NULL;
return Status;
}
@ -1035,7 +1195,7 @@ IntPaintDesktop(HDC hDC)
return FALSE;
/* Retrieve the current SafeMode state */
InSafeMode = (UserGetSystemMetrics(SM_CLEANBOOT) != 0);
InSafeMode = (UserGetSystemMetrics(SM_CLEANBOOT) != 0); // gpsi->aiSysMet[SM_CLEANBOOT];
if (!InSafeMode)
{
@ -1160,15 +1320,21 @@ IntPaintDesktop(HDC hDC)
/*
* Display the system version on the desktop background
*/
if (g_PaintDesktopVersion || InSafeMode)
if (InSafeMode || g_AlwaysDisplayVersion || g_PaintDesktopVersion)
{
PWSTR pwszVersion;
NTSTATUS Status;
static WCHAR wszzVersion[1024] = L"\0";
/* Only used in normal mode */
// We expect at most 4 strings (3 for version, 1 for optional NtSystemRoot)
static POLYTEXTW VerStrs[4] = {{0},{0},{0},{0}};
INT i = 0;
INT len;
NONCLIENTMETRICSW ncm;
HFONT hFont = NULL, hOldFont = NULL;
HFONT hFont1 = NULL, hFont2 = NULL, hOldFont = NULL;
COLORREF crText, color_old;
UINT align_old;
int mode_old;
INT mode_old;
PDC pdc;
if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &Rect, 0))
@ -1177,18 +1343,22 @@ IntPaintDesktop(HDC hDC)
Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
}
/* Set up the font (use default one otherwise) */
ncm.cbSize = sizeof(ncm);
if (UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
{
hFont = GreCreateFontIndirectW(&ncm.lfCaptionFont);
if (hFont)
hOldFont = NtGdiSelectFont(hDC, hFont);
}
/*
* Set up the fonts (otherwise use default ones)
*/
/* Font for the principal version string */
hFont1 = GreCreateFontIndirectW(&gspv.ncm.lfCaptionFont);
/* Font for the secondary version strings */
hFont2 = GreCreateFontIndirectW(&gspv.ncm.lfMenuFont);
if (hFont1)
hOldFont = NtGdiSelectFont(hDC, hFont1);
if (gspv.hbmWallpaper == NULL)
{
/* Retrieve the brush fill colour */
// TODO: The following code constitutes "GreGetBrushColor".
PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
pdc = DC_LockDc(hDC);
if (pdc)
@ -1219,33 +1389,100 @@ IntPaintDesktop(HDC hDC)
mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
/* Display the system version information */
// FIXME: We need different strings for Safe Mode and regular mode.
len = GetSystemVersionString(&pwszVersion); // , InSafeMode);
if (len)
if (!*wszzVersion)
{
Status = GetSystemVersionString(wszzVersion,
ARRAYSIZE(wszzVersion),
InSafeMode,
g_AlwaysDisplayVersion);
if (!InSafeMode && NT_SUCCESS(Status) && *wszzVersion)
{
PWCHAR pstr = wszzVersion;
for (i = 0; (i < ARRAYSIZE(VerStrs)) && *pstr; ++i)
{
VerStrs[i].n = wcslen(pstr);
VerStrs[i].lpstr = pstr;
pstr += (VerStrs[i].n + 1);
}
}
}
else
{
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status) && *wszzVersion)
{
if (!InSafeMode)
{
GreExtTextOutW(hDC, Rect.right - 16, Rect.bottom - 48, 0, NULL, pwszVersion, len, NULL, 0);
SIZE Size = {0, 0};
LONG TotalHeight = 0;
/* Normal Mode: multiple version information text separated by newlines */
IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BOTTOM);
/* Compute the heights of the strings */
if (hFont1) NtGdiSelectFont(hDC, hFont1);
for (i = 0; i < ARRAYSIZE(VerStrs); ++i)
{
if (!VerStrs[i].lpstr || !*VerStrs[i].lpstr || (VerStrs[i].n == 0))
break;
GreGetTextExtentW(hDC, VerStrs[i].lpstr, VerStrs[i].n, &Size, 1);
VerStrs[i].y = Size.cy; // Store the string height
TotalHeight += Size.cy;
/* While the first string was using hFont1, all the others use hFont2 */
if (hFont2) NtGdiSelectFont(hDC, hFont2);
}
/* The total height must not exceed the screen height */
TotalHeight = min(TotalHeight, Rect.bottom);
/* Display the strings */
if (hFont1) NtGdiSelectFont(hDC, hFont1);
for (i = 0; i < ARRAYSIZE(VerStrs); ++i)
{
if (!VerStrs[i].lpstr || !*VerStrs[i].lpstr || (VerStrs[i].n == 0))
break;
TotalHeight -= VerStrs[i].y;
GreExtTextOutW(hDC,
Rect.right - 5,
Rect.bottom - TotalHeight - 5,
0, NULL,
VerStrs[i].lpstr,
VerStrs[i].n,
NULL, 0);
/* While the first string was using hFont1, all the others use hFont2 */
if (hFont2) NtGdiSelectFont(hDC, hFont2);
}
}
else
{
/* Safe Mode: version information text in top center */
if (hFont1) NtGdiSelectFont(hDC, hFont1);
/* Safe Mode: single version information text in top center */
len = wcslen(wszzVersion);
IntGdiSetTextAlign(hDC, TA_CENTER | TA_TOP);
GreExtTextOutW(hDC, (Rect.right + Rect.left)/2, Rect.top + 3, 0, NULL, pwszVersion, len, NULL, 0);
GreExtTextOutW(hDC, (Rect.right + Rect.left)/2, Rect.top + 3, 0, NULL, wszzVersion, len, NULL, 0);
}
}
if (InSafeMode)
{
if (hFont1) NtGdiSelectFont(hDC, hFont1);
/* Print Safe Mode text in corners */
len = wcslen(s_wszSafeMode);
IntGdiSetTextAlign(hDC, TA_LEFT | TA_TOP);
GreExtTextOutW(hDC, Rect.left, Rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
IntGdiSetTextAlign(hDC, TA_RIGHT | TA_TOP);
GreExtTextOutW(hDC, Rect.right, Rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
IntGdiSetTextAlign(hDC, TA_LEFT | TA_BASELINE);
IntGdiSetTextAlign(hDC, TA_LEFT | TA_BOTTOM);
GreExtTextOutW(hDC, Rect.left, Rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BASELINE);
IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BOTTOM);
GreExtTextOutW(hDC, Rect.right, Rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
}
@ -1253,10 +1490,13 @@ IntPaintDesktop(HDC hDC)
IntGdiSetTextAlign(hDC, align_old);
IntGdiSetTextColor(hDC, color_old);
if (hFont)
if (hFont2)
GreDeleteObject(hFont2);
if (hFont1)
{
NtGdiSelectFont(hDC, hOldFont);
GreDeleteObject(hFont);
GreDeleteObject(hFont1);
}
}

View file

@ -14,6 +14,7 @@ BOOL FASTCALL RegisterControlAtoms(VOID);
PTHREADINFO gptiCurrent = NULL;
PPROCESSINFO gppiInputProvider = NULL;
BOOL g_AlwaysDisplayVersion = FALSE;
ERESOURCE UserLock;
ATOM AtomMessage; // Window Message atom.
ATOM AtomWndObj; // Window Object atom.
@ -76,6 +77,7 @@ NTAPI
InitUserImpl(VOID)
{
NTSTATUS Status;
HKEY hKey;
ExInitializeResourceLite(&UserLock);
@ -94,6 +96,16 @@ InitUserImpl(VOID)
InitUserAtoms();
Status = RegOpenKey(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
&hKey);
if (NT_SUCCESS(Status))
{
DWORD dwValue = 0;
RegReadDWORD(hKey, L"DisplayVersion", &dwValue);
g_AlwaysDisplayVersion = !!dwValue;
ZwClose(hKey);
}
InitSysParams();
return STATUS_SUCCESS;

View file

@ -14,6 +14,7 @@ extern PTHREADINFO gptiCurrent;
extern PPROCESSINFO gppiList;
extern PPROCESSINFO ppiScrnSaver;
extern PPROCESSINFO gppiInputProvider;
extern BOOL g_AlwaysDisplayVersion;
extern ATOM gaGuiConsoleWndClass;
extern ATOM AtomDDETrack;
extern ATOM AtomQOS;