summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2014-12-19 10:07:47 (GMT)
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-01-08 05:29:18 (GMT)
commit18c5ff04103eadcb532d03d526714385943295ab (patch)
treee268d78f08a52493c176e2efd548b59e5763e82c
parent8d831f5f444802879ae416bd110184d5a6cf1b26 (diff)
downloadQt-18c5ff04103eadcb532d03d526714385943295ab.zip
Qt-18c5ff04103eadcb532d03d526714385943295ab.tar.gz
Qt-18c5ff04103eadcb532d03d526714385943295ab.tar.bz2
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> (cherry picked from qtbase/6796f2337ee31b4b4f07eaa54d868b999c39233a) Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/global/qglobal.cpp77
1 files changed, 67 insertions, 10 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index aaad58e..e46894c 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -48,6 +48,8 @@
#include "qstringlist.h"
#include "qdatetime.h"
+#include <private/qsystemlibrary_p.h>
+
#ifndef QT_NO_QOBJECT
#include <private/qthread_p.h>
#endif
@@ -1691,6 +1693,69 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qt_windows.h"
QT_END_INCLUDE_NAMESPACE
+# 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(QLatin1String("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 = 0;
+ 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'}};
@@ -1706,16 +1771,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;