/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-11 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ // (This file gets included by juce_win32_NativeCode.cpp, rather than being // compiled on its own). #if JUCE_INCLUDED_FILE #if ! JUCE_ONLY_BUILD_CORE_LIBRARY extern HWND juce_messageWindowHandle; #endif //============================================================================== #if ! JUCE_USE_INTRINSICS // In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in // older ones we have to actually call the ops as win32 functions.. long juce_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); } long juce_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); } long juce_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); } long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); } long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); } __int64 juce_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept { jassertfalse; // This operation isn't available in old MS compiler versions! __int64 oldValue = *value; if (oldValue == valueToCompare) *value = newValue; return oldValue; } #endif //============================================================================== CriticalSection::CriticalSection() noexcept { // (just to check the MS haven't changed this structure and broken things...) #if JUCE_VC7_OR_EARLIER static_jassert (sizeof (CRITICAL_SECTION) <= 24); #else static_jassert (sizeof (CRITICAL_SECTION) <= sizeof (internal)); #endif InitializeCriticalSection ((CRITICAL_SECTION*) internal); } CriticalSection::~CriticalSection() noexcept { DeleteCriticalSection ((CRITICAL_SECTION*) internal); } void CriticalSection::enter() const noexcept { EnterCriticalSection ((CRITICAL_SECTION*) internal); } bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSection ((CRITICAL_SECTION*) internal) != FALSE; } void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) internal); } //============================================================================== WaitableEvent::WaitableEvent (const bool manualReset) noexcept : internal (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) { } WaitableEvent::~WaitableEvent() noexcept { CloseHandle (internal); } bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept { return WaitForSingleObject (internal, timeOutMillisecs) == WAIT_OBJECT_0; } void WaitableEvent::signal() const noexcept { SetEvent (internal); } void WaitableEvent::reset() const noexcept { ResetEvent (internal); } //============================================================================== void JUCE_API juce_threadEntryPoint (void*); static unsigned int __stdcall threadEntryProc (void* userData) { #if ! JUCE_ONLY_BUILD_CORE_LIBRARY AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0), GetCurrentThreadId(), TRUE); #endif juce_threadEntryPoint (userData); _endthreadex (0); return 0; } void Thread::launchThread() { unsigned int newThreadId; threadHandle_ = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId); threadId_ = (ThreadID) newThreadId; } void Thread::closeThreadHandle() { CloseHandle ((HANDLE) threadHandle_); threadId_ = 0; threadHandle_ = 0; } void Thread::killThread() { if (threadHandle_ != 0) { #if JUCE_DEBUG OutputDebugString (_T("** Warning - Forced thread termination **\n")); #endif TerminateThread (threadHandle_, 0); } } void Thread::setCurrentThreadName (const String& name) { #if JUCE_DEBUG && JUCE_MSVC struct { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; } info; info.dwType = 0x1000; info.szName = name.toUTF8(); info.dwThreadID = GetCurrentThreadId(); info.dwFlags = 0; __try { RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info); } __except (EXCEPTION_CONTINUE_EXECUTION) {} #else (void) name; #endif } Thread::ThreadID Thread::getCurrentThreadId() { return (ThreadID) (pointer_sized_int) GetCurrentThreadId(); } bool Thread::setThreadPriority (void* handle, int priority) { int pri = THREAD_PRIORITY_TIME_CRITICAL; if (priority < 1) pri = THREAD_PRIORITY_IDLE; else if (priority < 2) pri = THREAD_PRIORITY_LOWEST; else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL; else if (priority < 7) pri = THREAD_PRIORITY_NORMAL; else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; if (handle == 0) handle = GetCurrentThread(); return SetThreadPriority (handle, pri) != FALSE; } void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) { SetThreadAffinityMask (GetCurrentThread(), affinityMask); } //============================================================================== struct SleepEvent { SleepEvent() : handle (CreateEvent (0, 0, 0, #if JUCE_DEBUG _T("Juce Sleep Event"))) #else 0)) #endif { } HANDLE handle; }; static SleepEvent sleepEvent; void JUCE_CALLTYPE Thread::sleep (const int millisecs) { if (millisecs >= 10) { Sleep (millisecs); } else { // unlike Sleep() this is guaranteed to return to the current thread after // the time expires, so we'll use this for short waits, which are more likely // to need to be accurate WaitForSingleObject (sleepEvent.handle, millisecs); } } void Thread::yield() { Sleep (0); } //============================================================================== static int lastProcessPriority = -1; // called by WindowDriver because Windows does wierd things to process priority // when you swap apps, and this forces an update when the app is brought to the front. void juce_repeatLastProcessPriority() { if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..) { DWORD p; switch (lastProcessPriority) { case Process::LowPriority: p = IDLE_PRIORITY_CLASS; break; case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break; case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break; case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break; default: jassertfalse; return; // bad priority value } SetPriorityClass (GetCurrentProcess(), p); } } void Process::setPriority (ProcessPriority prior) { if (lastProcessPriority != (int) prior) { lastProcessPriority = (int) prior; juce_repeatLastProcessPriority(); } } JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() { return IsDebuggerPresent() != FALSE; } bool JUCE_CALLTYPE Process::isRunningUnderDebugger() { return juce_isRunningUnderDebugger(); } //============================================================================== void Process::raisePrivilege() { jassertfalse; // xxx not implemented } void Process::lowerPrivilege() { jassertfalse; // xxx not implemented } void Process::terminate() { #if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS _CrtDumpMemoryLeaks(); #endif // bullet in the head in case there's a problem shutting down.. ExitProcess (0); } //============================================================================== void* PlatformUtilities::loadDynamicLibrary (const String& name) { void* result = nullptr; JUCE_TRY { result = LoadLibrary (name.toWideCharPointer()); } JUCE_CATCH_ALL return result; } void PlatformUtilities::freeDynamicLibrary (void* h) { JUCE_TRY { if (h != nullptr) FreeLibrary ((HMODULE) h); } JUCE_CATCH_ALL } void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name) { return (h != nullptr) ? (void*) GetProcAddress ((HMODULE) h, name.toUTF8()) : nullptr; // (void* cast is required for mingw) } //============================================================================== class InterProcessLock::Pimpl { public: Pimpl (String name, const int timeOutMillisecs) : handle (0), refCount (1) { name = name.replaceCharacter ('\\', '/'); handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer()); // Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to // a local one. (A local one also sometimes fails on other machines so neither type appears to be // universally reliable) if (handle == 0) handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer()); if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS) { if (timeOutMillisecs == 0) { close(); return; } switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs)) { case WAIT_OBJECT_0: case WAIT_ABANDONED: break; case WAIT_TIMEOUT: default: close(); break; } } } ~Pimpl() { close(); } void close() { if (handle != 0) { ReleaseMutex (handle); CloseHandle (handle); handle = 0; } } HANDLE handle; int refCount; }; InterProcessLock::InterProcessLock (const String& name_) : name (name_) { } InterProcessLock::~InterProcessLock() { } bool InterProcessLock::enter (const int timeOutMillisecs) { const ScopedLock sl (lock); if (pimpl == nullptr) { pimpl = new Pimpl (name, timeOutMillisecs); if (pimpl->handle == 0) pimpl = nullptr; } else { pimpl->refCount++; } return pimpl != nullptr; } void InterProcessLock::exit() { const ScopedLock sl (lock); // Trying to release the lock too many times! jassert (pimpl != nullptr); if (pimpl != nullptr && --(pimpl->refCount) == 0) pimpl = nullptr; } #endif