summaryrefslogtreecommitdiffstats
path: root/src/corelib/global
diff options
context:
space:
mode:
authorJake Petroules <jake.petroules@petroules.com>2015-08-18 17:23:56 -0700
committerJake Petroules <jake.petroules@theqtcompany.com>2015-09-06 02:23:14 +0000
commit5953109a04e16df1abb87d37a676a0a51e7a2eca (patch)
treeeba38243eae0f9561b5641ab3d8fe967b64b0656 /src/corelib/global
parent4684c1afe5fdb3774d56d85a52b2feaab1b8de2c (diff)
Fix QSysInfo::windowsVersion() for good.
Task-number: QTBUG-38439 Task-number: QTBUG-43444 Change-Id: I9870200806f2ca378b0977dee0674d89e2c6836c Reviewed-by: Andrew Knight <andrew.knight@intopalo.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/global')
-rw-r--r--src/corelib/global/qglobal.cpp139
1 files changed, 56 insertions, 83 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 77ac53f7e9..f0208846aa 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1935,91 +1935,69 @@ QWindowsSockInit::~QWindowsSockInit()
Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
# endif // QT_BOOTSTRAPPED
-# 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;
-}
+#endif // !Q_OS_WINRT
-// 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)
+#ifdef Q_OS_WINRT
+static inline HMODULE moduleHandleForFunction(LPCVOID address)
{
- 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;
+ // This is a widely used, decades-old technique for retrieving the handle
+ // of a module and is effectively equivalent to GetModuleHandleEx
+ // (which is unavailable on WinRT)
+ MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
+ if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
+ return 0;
+ return reinterpret_cast<HMODULE>(mbi.AllocationBase);
}
-
-# endif // !Q_OS_WINCE
+#endif
static inline OSVERSIONINFO winOsVersion()
{
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0, {'\0'}};
+
+#ifndef Q_OS_WINCE
+#define GetProcAddressA GetProcAddress
+#endif
+
+ // GetModuleHandle is not supported in WinRT and linking to it at load time
+ // will not pass the Windows App Certification Kit... but it exists and is functional,
+ // so use some unusual but widely used techniques to get a pointer to it
+#ifdef Q_OS_WINRT
+ // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
+ HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
+ if (Q_UNLIKELY(!kernelModule))
+ return result;
+
+ // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
+ typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
+ GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
+ GetProcAddressA(kernelModule, "GetModuleHandleW"));
+ if (Q_UNLIKELY(!pGetModuleHandle))
+ return result;
+#else
+#define pGetModuleHandle GetModuleHandleW
+#endif
+
+ HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
+ if (Q_UNLIKELY(!ntdll))
+ return result;
+
+ // NTSTATUS is not defined on WinRT
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
+
+ // RtlGetVersion is documented public API but we must load it dynamically
+ // because linking to it at load time will not pass the Windows App Certification Kit
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
+ RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
+ GetProcAddressA(ntdll, "RtlGetVersion"));
+ if (Q_UNLIKELY(!pRtlGetVersion))
+ return result;
+
// GetVersionEx() has been deprecated in Windows 8.1 and will return
- // only Windows 8 from that version on.
-# if defined(_MSC_VER) && _MSC_VER >= 1800
-# pragma warning( push )
-# pragma warning( disable : 4996 )
-# endif
- GetVersionEx(&result);
-# if defined(_MSC_VER) && _MSC_VER >= 1800
-# pragma warning( pop )
-# endif
-# ifndef Q_OS_WINCE
- if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) {
- if (!determineWinOsVersionPost8(&result))
- determineWinOsVersionFallbackPost8(&result);
- }
-# endif // !Q_OS_WINCE
+ // only Windows 8 from that version on, so use the kernel API function.
+ pRtlGetVersion(&result); // always returns STATUS_SUCCESS
return result;
}
-#endif // !Q_OS_WINRT
QSysInfo::WinVersion QSysInfo::windowsVersion()
{
@@ -2039,11 +2017,10 @@ QSysInfo::WinVersion QSysInfo::windowsVersion()
static QSysInfo::WinVersion winver;
if (winver)
return winver;
-#ifdef Q_OS_WINRT
- winver = QSysInfo::WV_WINDOWS8_1;
-#else
winver = QSysInfo::WV_NT;
const OSVERSIONINFO osver = winOsVersion();
+ if (osver.dwMajorVersion == 0)
+ return QSysInfo::WV_None;
#ifdef Q_OS_WINCE
DWORD qt_cever = 0;
qt_cever = osver.dwMajorVersion * 100;
@@ -2123,7 +2100,6 @@ QSysInfo::WinVersion QSysInfo::windowsVersion()
}
}
#endif
-#endif // !Q_OS_WINRT
return winver;
}
@@ -2594,10 +2570,7 @@ QString QSysInfo::kernelType()
*/
QString QSysInfo::kernelVersion()
{
-#ifdef Q_OS_WINRT
- // TBD
- return QString();
-#elif defined(Q_OS_WIN)
+#ifdef Q_OS_WIN
const OSVERSIONINFO osver = winOsVersion();
return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion))
+ QLatin1Char('.') + QString::number(int(osver.dwBuildNumber));