Skip to content

Commit 18c5ff0

Browse files
Friedemann KleintFriedemann Kleint
authored andcommitted
Windows: Fix OS version determination for Windows >= 8
First, try to determine the version of kernel32.dll by using the version API. If that fails, loop using the version macros, taking the major version into account. Hangs in the minor version loop have been observed, potentially related to the major version. Task-number: QTBUG-43413 Change-Id: I982e78873510e7598c7cf839177e59812acd86f6 Reviewed-by: Joerg Bornemann <[email protected]> (cherry picked from qtbase/6796f2337ee31b4b4f07eaa54d868b999c39233a) Reviewed-by: Thiago Macieira <[email protected]>
1 parent 8d831f5 commit 18c5ff0

File tree

1 file changed

+67
-10
lines changed

1 file changed

+67
-10
lines changed

src/corelib/global/qglobal.cpp

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
#include "qstringlist.h"
4949
#include "qdatetime.h"
5050

51+
#include <private/qsystemlibrary_p.h>
52+
5153
#ifndef QT_NO_QOBJECT
5254
#include <private/qthread_p.h>
5355
#endif
@@ -1691,6 +1693,69 @@ QT_BEGIN_INCLUDE_NAMESPACE
16911693
#include "qt_windows.h"
16921694
QT_END_INCLUDE_NAMESPACE
16931695

1696+
# ifndef Q_OS_WINCE
1697+
1698+
// Determine Windows versions >= 8 by querying the version of kernel32.dll.
1699+
static inline bool determineWinOsVersionPost8(OSVERSIONINFO *result)
1700+
{
1701+
typedef WORD (WINAPI* PtrGetFileVersionInfoSizeW)(LPCWSTR, LPDWORD);
1702+
typedef BOOL (WINAPI* PtrVerQueryValueW)(LPCVOID, LPCWSTR, LPVOID, PUINT);
1703+
typedef BOOL (WINAPI* PtrGetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID);
1704+
1705+
QSystemLibrary versionLib(QLatin1String("version"));
1706+
if (!versionLib.load())
1707+
return false;
1708+
PtrGetFileVersionInfoSizeW getFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)versionLib.resolve("GetFileVersionInfoSizeW");
1709+
PtrVerQueryValueW verQueryValueW = (PtrVerQueryValueW)versionLib.resolve("VerQueryValueW");
1710+
PtrGetFileVersionInfoW getFileVersionInfoW = (PtrGetFileVersionInfoW)versionLib.resolve("GetFileVersionInfoW");
1711+
if (!getFileVersionInfoSizeW || !verQueryValueW || !getFileVersionInfoW)
1712+
return false;
1713+
1714+
const wchar_t kernel32Dll[] = L"kernel32.dll";
1715+
DWORD handle;
1716+
const DWORD size = getFileVersionInfoSizeW(kernel32Dll, &handle);
1717+
if (!size)
1718+
return false;
1719+
QScopedArrayPointer<BYTE> versionInfo(new BYTE[size]);
1720+
if (!getFileVersionInfoW(kernel32Dll, handle, size, versionInfo.data()))
1721+
return false;
1722+
UINT uLen;
1723+
VS_FIXEDFILEINFO *fileInfo = 0;
1724+
if (!verQueryValueW(versionInfo.data(), L"\\", (LPVOID *)&fileInfo, &uLen))
1725+
return false;
1726+
const DWORD fileVersionMS = fileInfo->dwFileVersionMS;
1727+
const DWORD fileVersionLS = fileInfo->dwFileVersionLS;
1728+
result->dwMajorVersion = HIWORD(fileVersionMS);
1729+
result->dwMinorVersion = LOWORD(fileVersionMS);
1730+
result->dwBuildNumber = HIWORD(fileVersionLS);
1731+
return true;
1732+
}
1733+
1734+
// Fallback for determining Windows versions >= 8 by looping using the
1735+
// version check macros. Note that it will return build number=0 to avoid
1736+
// inefficient looping.
1737+
static inline void determineWinOsVersionFallbackPost8(OSVERSIONINFO *result)
1738+
{
1739+
result->dwBuildNumber = 0;
1740+
DWORDLONG conditionMask = 0;
1741+
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
1742+
VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
1743+
OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result->dwMajorVersion, 0,
1744+
result->dwBuildNumber, result->dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 };
1745+
for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMajorVersion)
1746+
result->dwMajorVersion = checkVersion.dwMajorVersion;
1747+
conditionMask = 0;
1748+
checkVersion.dwMajorVersion = result->dwMajorVersion;
1749+
checkVersion.dwMinorVersion = 0;
1750+
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_EQUAL);
1751+
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
1752+
VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
1753+
for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion)
1754+
result->dwMinorVersion = checkVersion.dwMinorVersion;
1755+
}
1756+
1757+
# endif // !Q_OS_WINCE
1758+
16941759
static inline OSVERSIONINFO winOsVersion()
16951760
{
16961761
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0, {'\0'}};
@@ -1706,16 +1771,8 @@ static inline OSVERSIONINFO winOsVersion()
17061771
# endif
17071772
# ifndef Q_OS_WINCE
17081773
if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) {
1709-
// This could be Windows 8.1 or higher. Note that as of Windows 9,
1710-
// the major version needs to be checked as well.
1711-
DWORDLONG conditionMask = 0;
1712-
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
1713-
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
1714-
VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
1715-
OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result.dwMajorVersion, result.dwMinorVersion,
1716-
result.dwBuildNumber, result.dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 };
1717-
for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion)
1718-
result.dwMinorVersion = checkVersion.dwMinorVersion;
1774+
if (!determineWinOsVersionPost8(&result))
1775+
determineWinOsVersionFallbackPost8(&result);
17191776
}
17201777
# endif // !Q_OS_WINCE
17211778
return result;

0 commit comments

Comments
 (0)