+ Free();
+
+ return wxTHREAD_NO_ERROR;
+}
+
+wxThreadError
+wxThreadInternal::WaitForTerminate(wxCriticalSection& cs,
+ wxThread::ExitCode *pRc,
+ wxThreadWait waitMode,
+ wxThread *threadToDelete)
+{
+ // prevent the thread C++ object from disappearing as long as we are using
+ // it here
+ wxThreadKeepAlive keepAlive(*this);
+
+
+ // we may either wait passively for the thread to terminate (when called
+ // from Wait()) or ask it to terminate (when called from Delete())
+ bool shouldDelete = threadToDelete != NULL;
+
+ DWORD rc = 0;
+
+ // we might need to resume the thread if it's currently stopped
+ bool shouldResume = false;
+
+ // as Delete() (which calls us) is always safe to call we need to consider
+ // all possible states
+ {
+ wxCriticalSectionLocker lock(cs);
+
+ if ( m_state == STATE_NEW )
+ {
+ if ( shouldDelete )
+ {
+ // WinThreadStart() will see it and terminate immediately, no
+ // need to cancel the thread -- but we still need to resume it
+ // to let it run
+ m_state = STATE_EXITED;
+
+ // we must call Resume() as the thread hasn't been initially
+ // resumed yet (and as Resume() it knows about STATE_EXITED
+ // special case, it won't touch it and WinThreadStart() will
+ // just exit immediately)
+ shouldResume = true;
+ shouldDelete = false;
+ }
+ //else: shouldResume is correctly set to false here, wait until
+ // someone else runs the thread and it finishes
+ }
+ else // running, paused, cancelled or even exited
+ {
+ shouldResume = m_state == STATE_PAUSED;
+ }
+ }
+
+ // resume the thread if it is paused
+ if ( shouldResume )
+ Resume();
+
+ // ask the thread to terminate
+ if ( shouldDelete )
+ {
+ wxCriticalSectionLocker lock(cs);
+
+ Cancel();
+ }
+
+ if ( threadToDelete )
+ threadToDelete->OnDelete();
+
+ // now wait for thread to finish
+ if ( wxThread::IsMain() )
+ {
+ // set flag for wxIsWaitingForThread()
+ gs_waitingForThread = true;
+ }
+
+ // we can't just wait for the thread to terminate because it might be
+ // calling some GUI functions and so it will never terminate before we
+ // process the Windows messages that result from these functions
+ // (note that even in console applications we might have to process
+ // messages if we use wxExecute() or timers or ...)
+ DWORD result wxDUMMY_INITIALIZE(0);
+ do
+ {
+ if ( wxThread::IsMain() )
+ {
+ // give the thread we're waiting for chance to do the GUI call
+ // it might be in
+ if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
+ {
+ wxMutexGuiLeave();
+ }
+ }
+
+ wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+ if ( traits )
+ {
+ result = traits->WaitForThread(m_hThread, waitMode);
+ }
+ else // can't wait for the thread
+ {
+ // so kill it below
+ result = 0xFFFFFFFF;
+ }
+
+ switch ( result )
+ {
+ case 0xFFFFFFFF:
+ // error
+ wxLogSysError(_("Cannot wait for thread termination"));
+ Kill();
+ return wxTHREAD_KILLED;
+
+ case WAIT_OBJECT_0:
+ // thread we're waiting for terminated
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ // new message arrived, process it -- but only if we're the
+ // main thread as we don't support processing messages in
+ // the other ones
+ //
+ // NB: we still must include QS_ALLINPUT even when waiting
+ // in a secondary thread because if it had created some
+ // window somehow (possible not even using wxWidgets)
+ // the system might dead lock then
+ if ( wxThread::IsMain() )
+ {
+ if ( traits && !traits->DoMessageFromThreadWait() )
+ {
+ // WM_QUIT received: kill the thread
+ Kill();
+
+ return wxTHREAD_KILLED;
+ }
+ }
+ break;
+
+ default:
+ wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
+ }
+ } while ( result != WAIT_OBJECT_0 );
+
+ if ( wxThread::IsMain() )
+ {
+ gs_waitingForThread = false;
+ }
+
+
+ // although the thread might be already in the EXITED state it might not
+ // have terminated yet and so we are not sure that it has actually
+ // terminated if the "if" above hadn't been taken
+ for ( ;; )
+ {
+ if ( !::GetExitCodeThread(m_hThread, &rc) )
+ {
+ wxLogLastError(wxT("GetExitCodeThread"));
+
+ rc = THREAD_ERROR_EXIT;
+
+ break;
+ }
+
+ if ( rc != STILL_ACTIVE )
+ break;
+
+ // give the other thread some time to terminate, otherwise we may be
+ // starving it
+ ::Sleep(1);
+ }
+
+ if ( pRc )
+ *pRc = wxUIntToPtr(rc);
+
+ // we don't need the thread handle any more in any case
+ Free();
+
+
+ return rc == THREAD_ERROR_EXIT ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;