+ ExitCode rc = 0;
+
+ // Delete() is always safe to call, so consider all possible states
+
+ // we might need to resume the thread, but we might also not need to cancel
+ // it if it doesn't run yet
+ bool shouldResume = FALSE,
+ shouldCancel = TRUE,
+ isRunning = FALSE;
+
+ // check if the thread already started to run
+ {
+ wxCriticalSectionLocker lock(m_critsect);
+
+ if ( m_internal->GetState() == STATE_NEW )
+ {
+ // 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_internal->SetState(STATE_EXITED);
+
+ Resume(); // it knows about STATE_EXITED special case
+
+ shouldCancel = FALSE;
+ isRunning = TRUE;
+
+ // shouldResume is correctly set to FALSE here
+ }
+ else
+ {
+ shouldResume = IsPaused();
+ }
+ }
+
+ // resume the thread if it is paused
+ if ( shouldResume )
+ Resume();
+
+ HANDLE hThread = m_internal->GetHandle();
+
+ // does is still run?
+ if ( isRunning || IsRunning() )
+ {
+ if ( IsMain() )
+ {
+ // set flag for wxIsWaitingForThread()
+ gs_waitingForThread = TRUE;
+
+#if wxUSE_GUI
+ wxBeginBusyCursor();
+#endif // wxUSE_GUI
+ }
+
+ // ask the thread to terminate
+ if ( shouldCancel )
+ {
+ wxCriticalSectionLocker lock(m_critsect);
+
+ m_internal->Cancel();
+ }
+
+#if wxUSE_GUI
+ // 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
+ DWORD result;
+ do
+ {
+ result = ::MsgWaitForMultipleObjects
+ (
+ 1, // number of objects to wait for
+ &hThread, // the objects
+ FALSE, // don't wait for all objects
+ INFINITE, // no timeout
+ QS_ALLEVENTS // return as soon as there are any events
+ );
+
+ switch ( result )
+ {
+ case 0xFFFFFFFF:
+ // error
+ wxLogSysError(_("Can not 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
+ if ( !wxTheApp->DoMessage() )
+ {
+ // WM_QUIT received: kill the thread
+ Kill();
+
+ return wxTHREAD_KILLED;
+ }
+
+ if ( IsMain() )
+ {
+ // give the thread we're waiting for chance to exit
+ // from the GUI call it might have been in
+ if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
+ {
+ wxMutexGuiLeave();
+ }
+ }
+
+ break;
+
+ default:
+ wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
+ }
+ } while ( result != WAIT_OBJECT_0 );
+#else // !wxUSE_GUI
+ // simply wait for the thread to terminate
+ //
+ // OTOH, even console apps create windows (in wxExecute, for WinSock
+ // &c), so may be use MsgWaitForMultipleObject() too here?
+ if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
+ {
+ wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
+ }
+#endif // wxUSE_GUI/!wxUSE_GUI
+
+ if ( IsMain() )
+ {
+ gs_waitingForThread = FALSE;
+
+#if wxUSE_GUI
+ wxEndBusyCursor();
+#endif // wxUSE_GUI
+ }
+ }
+
+ if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
+ {
+ wxLogLastError(wxT("GetExitCodeThread"));
+
+ rc = (ExitCode)-1;
+ }
+
+ if ( IsDetached() )
+ {
+ // if the thread exits normally, this is done in WinThreadStart, but in
+ // this case it would have been too early because
+ // MsgWaitForMultipleObject() would fail if the thread handle was
+ // closed while we were waiting on it, so we must do it here
+ delete this;
+ }
+
+ wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
+ wxT("thread must be already terminated.") );
+
+ if ( pRc )
+ *pRc = rc;
+
+ return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;