int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) { if (flags & wxKILL_CHILDREN) wxKillAllChildren(pid, sig, krc); // get the process handle to operate on HANDLE hProcess = ::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, // not inheritable (DWORD)pid); if ( hProcess == NULL ) { if ( krc ) { // recognize wxKILL_ACCESS_DENIED as special because this doesn't // mean that the process doesn't exist and this is important for // wxProcess::Exists() *krc = ::GetLastError() == ERROR_ACCESS_DENIED ? wxKILL_ACCESS_DENIED : wxKILL_NO_PROCESS; } return -1; } wxON_BLOCK_EXIT1(::CloseHandle, hProcess); bool ok = true; switch ( sig ) { case wxSIGKILL: // kill the process forcefully returning -1 as error code if ( !::TerminateProcess(hProcess, (UINT)-1) ) { wxLogSysError(_("Failed to kill process %d"), pid); if ( krc ) { // this is not supposed to happen if we could open the // process *krc = wxKILL_ERROR; } ok = false; } break; case wxSIGNONE: // do nothing, we just want to test for process existence if ( krc ) *krc = wxKILL_OK; return 0; default: // any other signal means "terminate" { wxFindByPidParams params; params.pid = (DWORD)pid; // EnumWindows() has nice semantics: it returns 0 if it found // something or if an error occurred and non zero if it // enumerated all the window if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)¶ms) ) { // did we find any window? if ( params.hwnd ) { // tell the app to close // // NB: this is the harshest way, the app won't have an // opportunity to save any files, for example, but // this is probably what we want here. If not we // can also use SendMesageTimeout(WM_CLOSE) if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) ) { wxLogLastError(_T("PostMessage(WM_QUIT)")); } } else // it was an error then { wxLogLastError(_T("EnumWindows")); ok = false; } } else // no windows for this PID { if ( krc ) *krc = wxKILL_ERROR; ok = false; } } } // the return code DWORD rc wxDUMMY_INITIALIZE(0); if ( ok ) { // as we wait for a short time, we can use just WaitForSingleObject() // and not MsgWaitForMultipleObjects() switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) ) { case WAIT_OBJECT_0: // process terminated if ( !::GetExitCodeProcess(hProcess, &rc) ) { wxLogLastError(_T("GetExitCodeProcess")); } break; default: wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") ); // fall through case WAIT_FAILED: wxLogLastError(_T("WaitForSingleObject")); // fall through case WAIT_TIMEOUT: if ( krc ) *krc = wxKILL_ERROR; rc = STILL_ACTIVE; break; } } // the return code is the same as from Unix kill(): 0 if killed // successfully or -1 on error if ( !ok || rc == STILL_ACTIVE ) return -1; if ( krc ) *krc = wxKILL_OK; return 0; }
int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) { if (flags & wxKILL_CHILDREN) wxKillAllChildren(pid, sig, krc); // get the process handle to operate on DWORD dwAccess = PROCESS_QUERY_INFORMATION | SYNCHRONIZE; if ( sig == wxSIGKILL ) dwAccess |= PROCESS_TERMINATE; HANDLE hProcess = ::OpenProcess(dwAccess, FALSE, (DWORD)pid); if ( hProcess == NULL ) { if ( krc ) { // recognize wxKILL_ACCESS_DENIED as special because this doesn't // mean that the process doesn't exist and this is important for // wxProcess::Exists() *krc = ::GetLastError() == ERROR_ACCESS_DENIED ? wxKILL_ACCESS_DENIED : wxKILL_NO_PROCESS; } return -1; } wxON_BLOCK_EXIT1(::CloseHandle, hProcess); // Default timeout for waiting for the process termination after killing // it. It should be long enough to allow the process to terminate even on a // busy system but short enough to avoid blocking the main thread for too // long. DWORD waitTimeout = 500; // ms bool ok = true; switch ( sig ) { case wxSIGKILL: // kill the process forcefully returning -1 as error code if ( !::TerminateProcess(hProcess, (UINT)-1) ) { wxLogSysError(_("Failed to kill process %d"), pid); if ( krc ) { // this is not supposed to happen if we could open the // process *krc = wxKILL_ERROR; } ok = false; } break; case wxSIGNONE: // Opening the process handle may succeed for a process even if it // doesn't run any more (typically because open handles to it still // exist elsewhere, possibly in this process itself if we're // killing a child process) so we still need check if it hasn't // terminated yet but, unlike when killing it, we don't need to // wait for any time at all. waitTimeout = 0; break; default: // any other signal means "terminate" { wxFindByPidParams params; params.pid = (DWORD)pid; // EnumWindows() has nice semantics: it returns 0 if it found // something or if an error occurred and non zero if it // enumerated all the window if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)¶ms) ) { // did we find any window? if ( params.hwnd ) { // tell the app to close // // NB: this is the harshest way, the app won't have an // opportunity to save any files, for example, but // this is probably what we want here. If not we // can also use SendMesageTimeout(WM_CLOSE) if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) ) { wxLogLastError(wxT("PostMessage(WM_QUIT)")); } } else // it was an error then { wxLogLastError(wxT("EnumWindows")); ok = false; } } else // no windows for this PID { if ( krc ) *krc = wxKILL_ERROR; ok = false; } } } // the return code if ( ok ) { // as we wait for a short time, we can use just WaitForSingleObject() // and not MsgWaitForMultipleObjects() switch ( ::WaitForSingleObject(hProcess, waitTimeout) ) { case WAIT_OBJECT_0: // Process terminated: normally this indicates that we // successfully killed it but when testing for the process // existence, this means failure. if ( sig == wxSIGNONE ) { if ( krc ) *krc = wxKILL_NO_PROCESS; ok = false; } break; default: wxFAIL_MSG( wxT("unexpected WaitForSingleObject() return") ); // fall through case WAIT_FAILED: wxLogLastError(wxT("WaitForSingleObject")); // fall through case WAIT_TIMEOUT: // Process didn't terminate: normally this is a failure but not // when we're just testing for its existence. if ( sig != wxSIGNONE ) { if ( krc ) *krc = wxKILL_ERROR; ok = false; } break; } } // the return code is the same as from Unix kill(): 0 if killed // successfully or -1 on error if ( !ok ) return -1; if ( krc ) *krc = wxKILL_OK; return 0; }