diff options
Diffstat (limited to 'src/corelib/global/qglobal.cpp')
-rw-r--r-- | src/corelib/global/qglobal.cpp | 304 |
1 files changed, 197 insertions, 107 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index b5bdcedaa1..02220d0db2 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -42,6 +42,7 @@ #include <private/qlocale_tools_p.h> #include <private/qsystemlibrary_p.h> +#include <qmutex.h> #ifndef QT_NO_QOBJECT #include <private/qthread_p.h> @@ -64,12 +65,22 @@ # endif #endif -#if defined(Q_OS_VXWORKS) && defined(_WRS_KERNEL) -# include <envLib.h> +#ifdef Q_OS_WINRT +#include <wrl.h> +#include <windows.networking.h> +#include <windows.networking.sockets.h> +#include <windows.networking.connectivity.h> +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::Networking; +using namespace ABI::Windows::Networking::Connectivity; +using namespace ABI::Windows::Networking::Sockets; #endif -#if defined(Q_OS_MACX) -#include <CoreServices/CoreServices.h> +#if defined(Q_OS_VXWORKS) && defined(_WRS_KERNEL) +# include <envLib.h> #endif #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) @@ -89,6 +100,10 @@ #include <private/qcore_unix_p.h> #endif +#ifdef Q_OS_BSD4 +#include <sys/sysctl.h> +#endif + #include "archdetect.cpp" QT_BEGIN_NAMESPACE @@ -105,7 +120,9 @@ Q_CORE_EXPORT void *qMemSet(void *dest, int c, size_t n); // (if this list becomes too long, consider factoring into a separate file) Q_STATIC_ASSERT_X(sizeof(int) == 4, "Qt assumes that int is 32 bits"); Q_STATIC_ASSERT_X(UCHAR_MAX == 255, "Qt assumes that char is 8 bits"); - +#ifndef QT_BOOTSTRAPPED +Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "configure test ptrsize failed to correctly determine QT_POINTER_SIZE"); +#endif /*! \class QFlag @@ -1846,25 +1863,6 @@ QT_BEGIN_INCLUDE_NAMESPACE #include "qnamespace.h" QT_END_INCLUDE_NAMESPACE -#if defined(Q_OS_OSX) - -Q_CORE_EXPORT OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref) -{ - return FSPathMakeRef(reinterpret_cast<const UInt8 *>(file.toUtf8().constData()), fsref, 0); -} - -Q_CORE_EXPORT void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1) -{ - Q_UNUSED(encoding); - Q_UNUSED(len); - CFStringGetPascalString(QCFString(s), str, 256, CFStringGetSystemEncoding()); -} - -Q_CORE_EXPORT QString qt_mac_from_pascal_string(const Str255 pstr) { - return QCFString(CFStringCreateWithPascalString(0, pstr, CFStringGetSystemEncoding())); -} -#endif // defined(Q_OS_OSX) - QSysInfo::MacVersion QSysInfo::macVersion() { const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm @@ -1886,91 +1884,99 @@ 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) +# ifndef QT_BOOTSTRAPPED +class QWindowsSockInit { - typedef WORD (WINAPI* PtrGetFileVersionInfoSizeW)(LPCWSTR, LPDWORD); - typedef BOOL (WINAPI* PtrVerQueryValueW)(LPCVOID, LPCWSTR, LPVOID, PUINT); - typedef BOOL (WINAPI* PtrGetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID); +public: + QWindowsSockInit(); + ~QWindowsSockInit(); + int version; +}; - 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; +QWindowsSockInit::QWindowsSockInit() +: version(0) +{ + //### should we try for 2.2 on all platforms ?? + WSAData wsadata; - 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; + // IPv6 requires Winsock v2.0 or better. + if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) { + qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed."); + } else { + version = 0x20; + } } -// 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) +QWindowsSockInit::~QWindowsSockInit() { - 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; + WSACleanup(); } +Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit) +# endif // QT_BOOTSTRAPPED + +#endif // !Q_OS_WINRT -# endif // !Q_OS_WINCE +#ifdef Q_OS_WINRT +static inline HMODULE moduleHandleForFunction(LPCVOID address) +{ + // 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 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() { @@ -1990,11 +1996,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; @@ -2074,7 +2079,6 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() } } #endif -#endif // !Q_OS_WINRT return winver; } @@ -2545,10 +2549,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)); @@ -2774,6 +2775,82 @@ QString QSysInfo::prettyProductName() return unknownText(); } +#ifndef QT_BOOTSTRAPPED +/*! + \since 5.6 + + Returns this machine's host name, if one is configured. Note that hostnames + are not guaranteed to be globally unique, especially if they were + configured automatically. + + This function does not guarantee the returned host name is a Fully + Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the + returned name to an FQDN. + + This function returns the same as QHostInfo::localHostName(). + + \sa QHostInfo::localDomainName + */ +QString QSysInfo::machineHostName() +{ +#if defined(Q_OS_LINUX) + // gethostname(3) on Linux just calls uname(2), so do it ourselves + // and avoid a memcpy + struct utsname u; + if (uname(&u) == 0) + return QString::fromLocal8Bit(u.nodename); +#elif defined(Q_OS_WINRT) + ComPtr<INetworkInformationStatics> statics; + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &statics); + + ComPtr<IVectorView<HostName *>> hostNames; + statics->GetHostNames(&hostNames); + if (!hostNames) + return QString(); + + unsigned int size; + hostNames->get_Size(&size); + if (size == 0) + return QString(); + + for (unsigned int i = 0; i < size; ++i) { + ComPtr<IHostName> hostName; + hostNames->GetAt(i, &hostName); + HostNameType type; + hostName->get_Type(&type); + if (type != HostNameType_DomainName) + continue; + + HString name; + hostName->get_CanonicalName(name.GetAddressOf()); + UINT32 length; + PCWSTR rawString = name.GetRawBuffer(&length); + return QString::fromWCharArray(rawString, length); + } + ComPtr<IHostName> firstHost; + hostNames->GetAt(0, &firstHost); + + HString name; + firstHost->get_CanonicalName(name.GetAddressOf()); + UINT32 length; + PCWSTR rawString = name.GetRawBuffer(&length); + return QString::fromWCharArray(rawString, length); +#else +# ifdef Q_OS_WIN + // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll + winsockInit(); +# endif + + char hostName[512]; + if (gethostname(hostName, sizeof(hostName)) == -1) + return QString(); + hostName[sizeof(hostName) - 1] = '\0'; + return QString::fromLocal8Bit(hostName); +#endif + return QString(); +} +#endif // QT_BOOTSTRAPPED + /*! \macro void Q_ASSERT(bool test) \relates <QtGlobal> @@ -2885,12 +2962,15 @@ QString QSysInfo::prettyProductName() \macro void Q_CHECK_PTR(void *pointer) \relates <QtGlobal> - If \a pointer is 0, prints a warning message containing the source + If \a pointer is 0, prints a message containing the source code's file name and line number, saying that the program ran out - of memory. + of memory and aborts program execution. It throws \c std::bad_alloc instead + if exceptions are enabled. - Q_CHECK_PTR does nothing if \c QT_NO_DEBUG was defined during - compilation. + Q_CHECK_PTR does nothing if \c QT_NO_DEBUG and \c QT_NO_EXCEPTIONS were + defined during compilation. Therefore you must not use Q_CHECK_PTR to check + for successful memory allocations because the check will be disabled in + some cases. Example: @@ -3020,7 +3100,7 @@ namespace { // depending on the return type static inline Q_DECL_UNUSED QString fromstrerror_helper(int, const QByteArray &buf) { - return QString::fromLocal8Bit(buf); + return QString::fromLocal8Bit(buf.constData()); } static inline Q_DECL_UNUSED QString fromstrerror_helper(const char *str, const QByteArray &) { @@ -3098,6 +3178,10 @@ QString qt_error_string(int errorCode) return ret.trimmed(); } +// In the C runtime on all platforms access to the environment is not thread-safe. We +// add thread-safety for the Qt wrappers. +static QBasicMutex environmentMutex; + // getenv is declared as deprecated in VS2005. This function // makes use of the new secure getenv function. /*! @@ -3115,6 +3199,7 @@ QString qt_error_string(int errorCode) */ QByteArray qgetenv(const char *varName) { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 size_t requiredSize = 0; QByteArray buffer; @@ -3148,6 +3233,7 @@ QByteArray qgetenv(const char *varName) */ bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 // we provide a buffer that can only hold the empty string, so // when the env.var isn't empty, we'll get an ERANGE error (buffer @@ -3179,6 +3265,7 @@ bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT */ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 // we provide a buffer that can hold any int value: static const int NumBinaryDigitsPerOctalDigit = 3; @@ -3227,6 +3314,7 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT */ bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 size_t requiredSize = 0; (void)getenv_s(&requiredSize, 0, 0, varName); @@ -3256,6 +3344,7 @@ bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT */ bool qputenv(const char *varName, const QByteArray& value) { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 return _putenv_s(varName, value.constData()) == 0; #elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU) @@ -3286,6 +3375,7 @@ bool qputenv(const char *varName, const QByteArray& value) */ bool qunsetenv(const char *varName) { + QMutexLocker locker(&environmentMutex); #if defined(_MSC_VER) && _MSC_VER >= 1400 return _putenv_s(varName, "") == 0; #elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_BSD4) || defined(Q_OS_HAIKU) |