win: Prefer integers instead of strings for OS version comparison

* Add a WinOSVersionInfo struct holding the major and minor
  version and build number for a Windows release.
* Extract a static WinSalInstance::getWinOSVersionInfo from
  WinSalInstance::getOSVersion that returns a corresponding
  version info.
* Adjust the local getOSVersionString helper to take integers
  for major and minor version instead of an "NT version" string
  that is a dot-separated version number containing both of these.
* Use WinSalInstance::getWinOSVersionInfo in ImplDrawNativeControl
  to compare the major version + build number to identify Windows 11
  instead of relying on WinSalInstance::getOSVersion to return
  a string starting with "Windows 11".

Change-Id: I6fe727c1c0f928c03216e406cdb1b7735c1ab3ad
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176059
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
Michael Weghorn 2024-11-05 12:31:51 +00:00
parent 92f5913aef
commit a43b5e3de4
3 changed files with 55 additions and 36 deletions

View file

@ -24,9 +24,17 @@
#include <osl/conditn.hxx>
#include <salinst.hxx>
#include <win/salframe.h>
class SalYieldMutex;
struct WinOSVersionInfo
{
DWORD m_nMajorVersion = 0;
DWORD m_nMinorVersion = 0;
DWORD m_nBuildNumber = 0;
};
class WinSalInstance : public SalInstance
{
public:
@ -72,6 +80,7 @@ public:
virtual OUString GetConnectionIdentifier() override;
virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override;
static WinOSVersionInfo getWinOSVersionInfo();
virtual OUString getOSVersion() override;
virtual void BeforeAbort(const OUString&, bool) override;

View file

@ -1045,16 +1045,16 @@ static OUString getWinArch()
}
}
static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuildNumber)
static OUString getOSVersionString(DWORD nMajorVersion, DWORD nMinorVersion, DWORD nBuildNumber)
{
OUStringBuffer result = u"Windows";
if (aNtVersionString == "6.1")
if (nMajorVersion == 6 && nMinorVersion == 1)
result.append(" 7 Service Pack 1");
else if (aNtVersionString == "6.2")
else if (nMajorVersion == 6 && nMinorVersion == 2)
result.append(" 8");
else if (aNtVersionString == "6.3")
else if (nMajorVersion == 6 && nMinorVersion == 3)
result.append(" 8.1");
else if (aNtVersionString == "10.0")
else if (nMajorVersion == 10 && nMinorVersion == 0)
{
if (nBuildNumber >= 22000)
result.append(" 11");
@ -1066,12 +1066,12 @@ static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuil
result.append(getWinArch());
if (!aNtVersionString.isEmpty() || nBuildNumber)
if (nMajorVersion || nMinorVersion || nBuildNumber)
{
result.append(" (");
if (!aNtVersionString.isEmpty())
if (nMajorVersion || nMinorVersion)
{
result.append(aNtVersionString);
result.append(OUString::number(nMajorVersion) + u"." + OUString::number(nMinorVersion));
if (nBuildNumber)
result.append(" ");
}
@ -1083,10 +1083,11 @@ static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuil
return result.makeStringAndClear();
}
OUString WinSalInstance::getOSVersion()
WinOSVersionInfo WinSalInstance::getWinOSVersionInfo()
{
static const OUString result = []
static const WinOSVersionInfo aResult = []
{
WinOSVersionInfo aVersion;
// GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
// subject to manifest-based behavior since Windows 8.1, so give wrong results.
// Another approach would be to use NetWkstaGetInfo, but that has some small
@ -1094,7 +1095,6 @@ OUString WinSalInstance::getOSVersion()
// poor network connections.
// So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
bool bHaveVerFromKernel32 = false;
OUString aNtVersion;
if (HMODULE h_kernel32 = GetModuleHandleW(L"kernel32.dll"))
{
wchar_t szPath[MAX_PATH];
@ -1113,8 +1113,8 @@ OUString WinSalInstance::getOSVersion()
&& dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
{
VS_FIXEDFILEINFO* vi1 = static_cast<VS_FIXEDFILEINFO*>(pBlock);
aNtVersion = (OUString::number(HIWORD(vi1->dwProductVersionMS)) + "."
+ OUString::number(LOWORD(vi1->dwProductVersionMS)));
aVersion.m_nMajorVersion = HIWORD(vi1->dwProductVersionMS);
aVersion.m_nMinorVersion = LOWORD(vi1->dwProductVersionMS);
bHaveVerFromKernel32 = true;
}
}
@ -1123,7 +1123,6 @@ OUString WinSalInstance::getOSVersion()
}
// Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
// to get build number and SP info
DWORD nBuildNumber = 0;
if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
{
if (auto RtlGetVersion
@ -1134,15 +1133,23 @@ OUString WinSalInstance::getOSVersion()
if (STATUS_SUCCESS == RtlGetVersion(&vi2))
{
if (!bHaveVerFromKernel32) // we failed above; let's hope this would be useful
aNtVersion = (OUString::number(vi2.dwMajorVersion) + "."
+ OUString::number(vi2.dwMinorVersion));
nBuildNumber = vi2.dwBuildNumber;
{
aVersion.m_nMajorVersion = vi2.dwMajorVersion;
aVersion.m_nMinorVersion = vi2.dwMinorVersion;
}
aVersion.m_nBuildNumber = vi2.dwBuildNumber;
}
}
}
return getOSVersionString(aNtVersion, nBuildNumber);
return aVersion;
}();
return result;
return aResult;
}
OUString WinSalInstance::getOSVersion()
{
WinOSVersionInfo aInfo = getWinOSVersionInfo();
return getOSVersionString(aInfo.m_nMajorVersion, aInfo.m_nMinorVersion, aInfo.m_nBuildNumber);
}
void WinSalInstance::BeforeAbort(const OUString&, bool)

View file

@ -47,6 +47,7 @@
#include <win/salgdi.h>
#include <win/saldata.hxx>
#include <win/salframe.h>
#include <win/salinst.h>
#include <win/scoped_gdi.hxx>
#include <win/wingdiimpl.hxx>
@ -911,25 +912,27 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
else
iState = bChecked ? TS_CHECKED : TS_NORMAL;
if (bUseDarkMode && GetSalInstance()->getOSVersion().startsWith(u"Windows 11")
&& (bChecked
|| (nState & (ControlState::PRESSED) || (nState & ControlState::ROLLOVER))))
if (bUseDarkMode && (bChecked || (nState & (ControlState::PRESSED) || (nState & ControlState::ROLLOVER))))
{
// tdf#152534 workaround bug with Windows 11 Dark theme using
// light blue as highlight color which gives insufficient
// contrast for hovered-over or pressed/checked toolbar buttons:
// manually draw background (using color a bit lighter than background
// for non-highlighted items) and draw a frame around it
ScopedHBRUSH aBgColorBrush(CreateSolidBrush(RGB(38, 38, 38)));
FillRect(hDC, &rc, aBgColorBrush.get());
const Color aFrameColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
ScopedHBRUSH aFrameBrush(CreateSolidBrush(
RGB(aFrameColor.GetRed(), aFrameColor.GetGreen(), aFrameColor.GetBlue())));
FrameRect(hDC, &rc, aFrameBrush.get());
const WinOSVersionInfo aVersion = WinSalInstance::getWinOSVersionInfo();
if (aVersion.m_nMajorVersion == 10 && aVersion.m_nBuildNumber >= 22000)
{
// tdf#152534 workaround bug with Windows 11 Dark theme using
// light blue as highlight color which gives insufficient
// contrast for hovered-over or pressed/checked toolbar buttons:
// manually draw background (using color a bit lighter than background
// for non-highlighted items) and draw a frame around it
ScopedHBRUSH aBgColorBrush(CreateSolidBrush(RGB(38, 38, 38)));
FillRect(hDC, &rc, aBgColorBrush.get());
const Color aFrameColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
ScopedHBRUSH aFrameBrush(CreateSolidBrush(
RGB(aFrameColor.GetRed(), aFrameColor.GetGreen(), aFrameColor.GetBlue())));
FrameRect(hDC, &rc, aFrameBrush.get());
DrawThemeText(hTheme, hDC, iPart, iState, o3tl::toW(aCaption.getStr()), -1,
DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rc);
return true;
DrawThemeText(hTheme, hDC, iPart, iState, o3tl::toW(aCaption.getStr()), -1,
DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rc);
return true;
}
}
return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);