From 30c8acce49a8f7812d71ece8c8536a46f1e249ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Wed, 1 Jun 2016 15:24:38 +0000 Subject: [PATCH] [WIN32K] 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 --- reactos/win32ss/user/ntuser/desktop.c | 344 ++++++++++++++++++++++---- reactos/win32ss/user/ntuser/ntuser.c | 12 + reactos/win32ss/user/ntuser/ntuser.h | 1 + 3 files changed, 305 insertions(+), 52 deletions(-) diff --git a/reactos/win32ss/user/ntuser/desktop.c b/reactos/win32ss/user/ntuser/desktop.c index 8ff44b94459..39147e3aafa 100644 --- a/reactos/win32ss/user/ntuser/desktop.c +++ b/reactos/win32ss/user/ntuser/desktop.c @@ -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); } } diff --git a/reactos/win32ss/user/ntuser/ntuser.c b/reactos/win32ss/user/ntuser/ntuser.c index 87a285aaa9e..275479c7b9c 100644 --- a/reactos/win32ss/user/ntuser/ntuser.c +++ b/reactos/win32ss/user/ntuser/ntuser.c @@ -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; diff --git a/reactos/win32ss/user/ntuser/ntuser.h b/reactos/win32ss/user/ntuser/ntuser.h index 06db1c2fb2a..6856fd4d1a0 100644 --- a/reactos/win32ss/user/ntuser/ntuser.h +++ b/reactos/win32ss/user/ntuser/ntuser.h @@ -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;