summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2014-12-19 11:07:47 +0100
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-01-07 09:17:18 +0100
commit6796f2337ee31b4b4f07eaa54d868b999c39233a (patch)
treef61102ebe6c59b2c4851657ce9ec5d0d666045db /src
parentcf4b413fa4a81dbfaaaf50cb52f92ecc0d3c3f2a (diff)
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 <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qglobal.cpp78
1 files changed, 68 insertions, 10 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index ae3e86629e..997e804579 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -40,6 +40,8 @@
#include "qdir.h"
#include "qdatetime.h"
+#include <private/qsystemlibrary_p.h>
+
#ifndef QT_NO_QOBJECT
#include <private/qthread_p.h>
#endif
@@ -1865,6 +1867,70 @@ QT_BEGIN_INCLUDE_NAMESPACE
QT_END_INCLUDE_NAMESPACE
#ifndef Q_OS_WINRT
+
+# ifndef Q_OS_WINCE
+
+// Determine Windows versions >= 8 by querying the version of kernel32.dll.
+static inline bool determineWinOsVersionPost8(OSVERSIONINFO *result)
+{
+ typedef WORD (WINAPI* PtrGetFileVersionInfoSizeW)(LPCWSTR, LPDWORD);
+ typedef BOOL (WINAPI* PtrVerQueryValueW)(LPCVOID, LPCWSTR, LPVOID, PUINT);
+ typedef BOOL (WINAPI* PtrGetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID);
+
+ QSystemLibrary versionLib(QStringLiteral("version"));
+ if (!versionLib.load())
+ return false;
+ PtrGetFileVersionInfoSizeW getFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)versionLib.resolve("GetFileVersionInfoSizeW");
+ PtrVerQueryValueW verQueryValueW = (PtrVerQueryValueW)versionLib.resolve("VerQueryValueW");
+ PtrGetFileVersionInfoW getFileVersionInfoW = (PtrGetFileVersionInfoW)versionLib.resolve("GetFileVersionInfoW");
+ if (!getFileVersionInfoSizeW || !verQueryValueW || !getFileVersionInfoW)
+ return false;
+
+ const wchar_t kernel32Dll[] = L"kernel32.dll";
+ DWORD handle;
+ const DWORD size = getFileVersionInfoSizeW(kernel32Dll, &handle);
+ if (!size)
+ return false;
+ QScopedArrayPointer<BYTE> versionInfo(new BYTE[size]);
+ if (!getFileVersionInfoW(kernel32Dll, handle, size, versionInfo.data()))
+ return false;
+ UINT uLen;
+ VS_FIXEDFILEINFO *fileInfo = Q_NULLPTR;
+ if (!verQueryValueW(versionInfo.data(), L"\\", (LPVOID *)&fileInfo, &uLen))
+ return false;
+ const DWORD fileVersionMS = fileInfo->dwFileVersionMS;
+ const DWORD fileVersionLS = fileInfo->dwFileVersionLS;
+ result->dwMajorVersion = HIWORD(fileVersionMS);
+ result->dwMinorVersion = LOWORD(fileVersionMS);
+ result->dwBuildNumber = HIWORD(fileVersionLS);
+ return true;
+}
+
+// Fallback for determining Windows versions >= 8 by looping using the
+// version check macros. Note that it will return build number=0 to avoid
+// inefficient looping.
+static inline void determineWinOsVersionFallbackPost8(OSVERSIONINFO *result)
+{
+ result->dwBuildNumber = 0;
+ DWORDLONG conditionMask = 0;
+ VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
+ OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result->dwMajorVersion, 0,
+ result->dwBuildNumber, result->dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 };
+ for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMajorVersion)
+ result->dwMajorVersion = checkVersion.dwMajorVersion;
+ conditionMask = 0;
+ checkVersion.dwMajorVersion = result->dwMajorVersion;
+ checkVersion.dwMinorVersion = 0;
+ VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_EQUAL);
+ VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
+ for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion)
+ result->dwMinorVersion = checkVersion.dwMinorVersion;
+}
+
+# endif // !Q_OS_WINCE
+
static inline OSVERSIONINFO winOsVersion()
{
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0, {'\0'}};
@@ -1880,16 +1946,8 @@ static inline OSVERSIONINFO winOsVersion()
# endif
# ifndef Q_OS_WINCE
if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) {
- // This could be Windows 8.1 or higher. Note that as of Windows 9,
- // the major version needs to be checked as well.
- DWORDLONG conditionMask = 0;
- VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
- VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
- VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL);
- OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result.dwMajorVersion, result.dwMinorVersion,
- result.dwBuildNumber, result.dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 };
- for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion)
- result.dwMinorVersion = checkVersion.dwMinorVersion;
+ if (!determineWinOsVersionPost8(&result))
+ determineWinOsVersionFallbackPost8(&result);
}
# endif // !Q_OS_WINCE
return result;