X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2FOSSupport_Win32.cpp;h=f4fc18e13882f247fa029ff929cb17d889ffabf2;hb=2e22f8ff4be79d764b5535f542f1465fb18b2f27;hp=dde3443aa6ae04f8638675f5f5f1571ba5f67e3b;hpb=670d4dc36c2f507d2443d88757d4e56fa2045573;p=mutilities%2FMUtilities.git diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp index dde3443..f4fc18e 100644 --- a/src/OSSupport_Win32.cpp +++ b/src/OSSupport_Win32.cpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // MuldeR's Utilities for Qt -// Copyright (C) 2004-2015 LoRd_MuldeR +// Copyright (C) 2004-2016 LoRd_MuldeR // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -284,7 +284,7 @@ g_os_version_lut[] = { MUtils::OS::Version::WINDOWS_WIN70, "Windows 7 or Windows Server 2008 R2" }, //7 { MUtils::OS::Version::WINDOWS_WIN80, "Windows 8 or Windows Server 2012" }, //8 { MUtils::OS::Version::WINDOWS_WIN81, "Windows 8.1 or Windows Server 2012 R2" }, //8.1 - { MUtils::OS::Version::WINDOWS_WN100, "Windows 10 or Windows Server 2014 (Preview)" }, //10 + { MUtils::OS::Version::WINDOWS_WN100, "Windows 10 or Windows Server 2016" }, //10 { MUtils::OS::Version::UNKNOWN_OPSYS, "N/A" } }; @@ -304,29 +304,88 @@ namespace MUtils bool os_version_t::operator<= (const os_version_t &rhs) const { return (type == rhs.type) && ((versionMajor < rhs.versionMajor) || ((versionMajor == rhs.versionMajor) && (versionMinor <= rhs.versionMinor))); } //Known Windows NT versions - const os_version_t WINDOWS_WIN2K = { OS_WINDOWS, 5, 0 }; // 2000 - const os_version_t WINDOWS_WINXP = { OS_WINDOWS, 5, 1 }; // XP - const os_version_t WINDOWS_XPX64 = { OS_WINDOWS, 5, 2 }; // XP_x64 - const os_version_t WINDOWS_VISTA = { OS_WINDOWS, 6, 0 }; // Vista - const os_version_t WINDOWS_WIN70 = { OS_WINDOWS, 6, 1 }; // 7 - const os_version_t WINDOWS_WIN80 = { OS_WINDOWS, 6, 2 }; // 8 - const os_version_t WINDOWS_WIN81 = { OS_WINDOWS, 6, 3 }; // 8.1 - const os_version_t WINDOWS_WN100 = { OS_WINDOWS, 10, 0 }; // 10 + const os_version_t WINDOWS_WIN2K = { OS_WINDOWS, 5, 0, 2195 }; // 2000 + const os_version_t WINDOWS_WINXP = { OS_WINDOWS, 5, 1, 2600 }; // XP + const os_version_t WINDOWS_XPX64 = { OS_WINDOWS, 5, 2, 3790 }; // XP_x64 + const os_version_t WINDOWS_VISTA = { OS_WINDOWS, 6, 0, 6000 }; // Vista + const os_version_t WINDOWS_WIN70 = { OS_WINDOWS, 6, 1, 7600 }; // 7 + const os_version_t WINDOWS_WIN80 = { OS_WINDOWS, 6, 2, 9200 }; // 8 + const os_version_t WINDOWS_WIN81 = { OS_WINDOWS, 6, 3, 9600 }; // 8.1 + const os_version_t WINDOWS_WN100 = { OS_WINDOWS, 10, 0, 10240 }; // 10 //Unknown OS - const os_version_t UNKNOWN_OPSYS = { OS_UNKNOWN, 0, 0 }; // N/A + const os_version_t UNKNOWN_OPSYS = { OS_UNKNOWN, 0, 0, 0 }; // N/A } } } +static inline DWORD SAFE_ADD(const DWORD &a, const DWORD &b, const DWORD &limit = MAXDWORD) +{ + return ((a >= limit) || (b >= limit) || ((limit - a) <= b)) ? limit : (a + b); +} + + +static void initialize_os_version(OSVERSIONINFOEXW *const osInfo) +{ + memset(osInfo, 0, sizeof(OSVERSIONINFOEXW)); + osInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); +} + +static inline DWORD initialize_step_size(const DWORD &limit) +{ + DWORD result = 1; + while (result < limit) + { + result = SAFE_ADD(result, result); + } + return result; +} + +static bool rtl_get_version(OSVERSIONINFOEXW *const osInfo) +{ + typedef LONG(__stdcall *RtlGetVersion)(LPOSVERSIONINFOEXW); + if (const HMODULE ntdll = GetModuleHandleW(L"ntdll")) + { + if (const RtlGetVersion pRtlGetVersion = (RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion")) + { + initialize_os_version(osInfo); + if (pRtlGetVersion(osInfo) == 0) + { + return true; + } + } + } + + //Fallback + initialize_os_version(osInfo); + return (GetVersionExW((LPOSVERSIONINFOW)osInfo) != FALSE); +} + +static bool rtl_verify_version(OSVERSIONINFOEXW *const osInfo, const ULONG typeMask, const ULONGLONG condMask) +{ + typedef LONG(__stdcall *RtlVerifyVersionInfo)(LPOSVERSIONINFOEXW, ULONG, ULONGLONG); + if (const HMODULE ntdll = GetModuleHandleW(L"ntdll")) + { + if (const RtlVerifyVersionInfo pRtlVerifyVersionInfo = (RtlVerifyVersionInfo)GetProcAddress(ntdll, "RtlVerifyVersionInfo")) + { + if (pRtlVerifyVersionInfo(osInfo, typeMask, condMask) == 0) + { + return true; + } + } + } + + //Fallback + return (VerifyVersionInfoW(osInfo, typeMask, condMask) != FALSE); +} + static bool verify_os_version(const DWORD major, const DWORD minor) { OSVERSIONINFOEXW osvi; DWORDLONG dwlConditionMask = 0; + initialize_os_version(&osvi); //Initialize the OSVERSIONINFOEX structure - memset(&osvi, 0, sizeof(OSVERSIONINFOEXW)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); osvi.dwMajorVersion = major; osvi.dwMinorVersion = minor; osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; @@ -337,7 +396,7 @@ static bool verify_os_version(const DWORD major, const DWORD minor) VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); // Perform the test - const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask); + const BOOL ret = rtl_verify_version(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask); //Error checking if(!ret) @@ -351,9 +410,41 @@ static bool verify_os_version(const DWORD major, const DWORD minor) return (ret != FALSE); } -static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride) +static bool verify_os_build(const DWORD build) +{ + OSVERSIONINFOEXW osvi; + DWORDLONG dwlConditionMask = 0; + initialize_os_version(&osvi); + + //Initialize the OSVERSIONINFOEX structure + osvi.dwBuildNumber = build; + osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; + + //Initialize the condition mask + VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); + + // Perform the test + const BOOL ret = rtl_verify_version(&osvi, VER_BUILDNUMBER | VER_PLATFORMID, dwlConditionMask); + + //Error checking + if (!ret) + { + if (GetLastError() != ERROR_OLD_WIN_VERSION) + { + qWarning("VerifyVersionInfo() system call has failed!"); + } + } + + return (ret != FALSE); +} + +static bool get_real_os_version(unsigned int *major, unsigned int *minor, unsigned int *build, bool *pbOverride) { - *major = *minor = 0; + static const DWORD MAX_VERSION = 0xFFFF; + static const DWORD MAX_BUILDNO = MAXINT; + + *major = *minor = *build = 0; *pbOverride = false; //Initialize local variables @@ -362,7 +453,7 @@ static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool * osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); //Try GetVersionEx() first - if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE) + if(rtl_get_version(&osvi) == FALSE) { qWarning("GetVersionEx() has failed, cannot detect Windows version!"); return false; @@ -373,52 +464,66 @@ static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool * { *major = osvi.dwMajorVersion; *minor = osvi.dwMinorVersion; + *build = osvi.dwBuildNumber; } else { - qWarning("Not running on Windows NT, unsupported operating system!"); - return false; + if (verify_os_version(4, 0)) + { + *major = 4; + *build = 1381; + *pbOverride = true; + } + else + { + qWarning("Not running on Windows NT, unsupported operating system!"); + return false; + } } - //Determine the real *major* version first - forever + //Major Version + for (DWORD nextMajor = (*major) + 1; nextMajor <= MAX_VERSION; nextMajor++) { - const DWORD nextMajor = (*major) + 1; - if(verify_os_version(nextMajor, 0)) + if (verify_os_version(nextMajor, 0)) { - *pbOverride = true; *major = nextMajor; *minor = 0; + *pbOverride = true; continue; } break; } - //Now also determine the real *minor* version - forever + //Minor Version + for (DWORD nextMinor = (*minor) + 1; nextMinor <= MAX_VERSION; nextMinor++) { - const DWORD nextMinor = (*minor) + 1; - if(verify_os_version((*major), nextMinor)) + if (verify_os_version((*major), nextMinor)) { - *pbOverride = true; *minor = nextMinor; + *pbOverride = true; continue; } break; } - //Workaround for the mess that is sometimes referred to as "Windows 10" - if(((*major) > 6) || (((*major) == 6) && ((*minor) >= 2))) + //Build Version + if (verify_os_build(SAFE_ADD((*build), 1, MAX_BUILDNO))) { - quint16 kernel32_major, kernel32_minor; - if(MUtils::OS::get_file_version(QLatin1String("kernel32"), &kernel32_major, &kernel32_minor)) + DWORD stepSize = initialize_step_size(MAX_BUILDNO); + for (DWORD nextBuildNo = SAFE_ADD((*build), stepSize, MAX_BUILDNO); (*build) < MAX_BUILDNO; nextBuildNo = SAFE_ADD((*build), stepSize, MAX_BUILDNO)) { - if((kernel32_major > (*major)) || ((kernel32_major == (*major)) && (kernel32_minor > (*minor)))) + if (verify_os_build(nextBuildNo)) { - *major = kernel32_major; - *minor = kernel32_minor; + *build = nextBuildNo; *pbOverride = true; + continue; + } + if (stepSize > 1) + { + stepSize = stepSize / 2; + continue; } + break; } } @@ -445,12 +550,13 @@ const MUtils::OS::Version::os_version_t &MUtils::OS::os_version(void) } //Detect OS version - unsigned int major, minor; bool overrideFlg; - if(get_real_os_version(&major, &minor, &overrideFlg)) + unsigned int major, minor, build; bool overrideFlg; + if(get_real_os_version(&major, &minor, &build, &overrideFlg)) { g_os_version_info.type = Version::OS_WINDOWS; g_os_version_info.versionMajor = major; g_os_version_info.versionMinor = minor; + g_os_version_info.versionBuild = build; g_os_version_info.overrideFlag = overrideFlg; } else @@ -728,9 +834,9 @@ static QString get_file_path_drive_list(void) return list; } -static QString &get_file_path_translate(QString &path) +static void get_file_path_translate(QString &path) { - static const DWORD BUFSIZE = 4096; + static const DWORD BUFSIZE = 2048; wchar_t buffer[BUFSIZE], drive[3]; const QString driveList = get_file_path_drive_list(); @@ -748,8 +854,6 @@ static QString &get_file_path_translate(QString &path) } } } - - return path; } static QString get_file_path_fallback(const HANDLE &hFile) @@ -759,20 +863,25 @@ static QString get_file_path_fallback(const HANDLE &hFile) const HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 1, NULL); if (hFileMap) { - void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); + void *const pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); if (pMem) { - static const DWORD BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]; - if (GetMappedFileNameW(GetCurrentProcess(), pMem, buffer, BUFSIZE)) + static const size_t BUFFSIZE = 2048; + wchar_t buffer[BUFFSIZE]; + if (GetMappedFileNameW(GetCurrentProcess(), pMem, buffer, BUFFSIZE) > 0) { - filePath = get_file_path_translate(MUTILS_QSTR(buffer)); + filePath = MUTILS_QSTR(buffer); } UnmapViewOfFile(pMem); } CloseHandle(hFileMap); } + if (!filePath.isEmpty()) + { + get_file_path_translate(filePath); + } + return filePath; } @@ -783,7 +892,6 @@ QString MUtils::OS::get_file_path(const int &fd) const GetPathNameByHandleFun getPathNameByHandleFun = MUtils::Win32Utils::resolve(QLatin1String("kernel32"), QLatin1String("GetFinalPathNameByHandleW")); if (!getPathNameByHandleFun) { - qWarning("MUtils::OS::get_file_path() --> fallback!"); return get_file_path_fallback((HANDLE)_get_osfhandle(fd)); } @@ -998,15 +1106,61 @@ void MUtils::OS::sleep_ms(const size_t &duration) // EXECUTABLE CHECK /////////////////////////////////////////////////////////////////////////////// +static int g_library_as_image_resource_supported = -1; +static QReadWriteLock g_library_as_image_resource_supported_lock; + +static bool library_as_image_resource_supported() +{ + QReadLocker readLocker(&g_library_as_image_resource_supported_lock); + if (g_library_as_image_resource_supported >= 0) + { + return (g_library_as_image_resource_supported > 0); + } + + readLocker.unlock(); + QWriteLocker writeLocker(&g_library_as_image_resource_supported_lock); + + if (g_library_as_image_resource_supported < 0) + { + g_library_as_image_resource_supported = 0; + OSVERSIONINFOEXW osvi; + if (rtl_get_version(&osvi)) + { + if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osvi.dwMajorVersion >= 6U)) + { + g_library_as_image_resource_supported = 1; + } + } + } + + return (g_library_as_image_resource_supported > 0); +} + bool MUtils::OS::is_executable_file(const QString &path) { - bool bIsExecutable = false; DWORD binaryType; if(GetBinaryType(MUTILS_WCHR(QDir::toNativeSeparators(path)), &binaryType)) { - bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY); + return ((binaryType == SCS_32BIT_BINARY) || (binaryType == SCS_64BIT_BINARY)); + } + + const DWORD errorCode = GetLastError(); + qWarning("GetBinaryType() failed with error: 0x%08X", errorCode); + return false; +} + +bool MUtils::OS::is_library_file(const QString &path) +{ + const DWORD flags = library_as_image_resource_supported() ? (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE) : (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES); + if (const HMODULE hMod = LoadLibraryEx(MUTILS_WCHR(QDir::toNativeSeparators(path)), NULL, flags)) + { + FreeLibrary(hMod); + return true; } - return bIsExecutable; + + const DWORD errorCode = GetLastError(); + qWarning("LoadLibraryEx() failed with error: 0x%08X", errorCode); + return false; } ///////////////////////////////////////////////////////////////////////////////