diff options
author | Jake Petroules <jake.petroules@petroules.com> | 2015-08-18 17:23:56 -0700 |
---|---|---|
committer | Jake Petroules <jake.petroules@theqtcompany.com> | 2015-09-06 02:23:14 +0000 |
commit | 5953109a04e16df1abb87d37a676a0a51e7a2eca (patch) | |
tree | eba38243eae0f9561b5641ab3d8fe967b64b0656 /src/corelib/global | |
parent | 4684c1afe5fdb3774d56d85a52b2feaab1b8de2c (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.cpp | 139 |
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)); |