+ wxFindByPidParams() { hwnd = 0; pid = 0; }
+
+ // the HWND used to return the result
+ HWND hwnd;
+
+ // the PID we're looking from
+ DWORD pid;
+
+ DECLARE_NO_COPY_CLASS(wxFindByPidParams)
+};
+
+// wxKill helper: EnumWindows() callback which is used to find the first (top
+// level) window belonging to the given process
+BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
+{
+ DWORD pid;
+ (void)::GetWindowThreadProcessId(hwnd, &pid);
+
+ wxFindByPidParams *params = (wxFindByPidParams *)lParam;
+ if ( pid == params->pid )
+ {
+ // remember the window we found
+ params->hwnd = hwnd;
+
+ // return FALSE to stop the enumeration
+ return FALSE;
+ }
+
+ // continue enumeration
+ return TRUE;
+}
+
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
+
+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;
+}
+
+typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_t)(DWORD,DWORD);
+typedef BOOL (WINAPI *Process32_t)(HANDLE,LPPROCESSENTRY32);
+
+CreateToolhelp32Snapshot_t lpfCreateToolhelp32Snapshot;
+Process32_t lpfProcess32First, lpfProcess32Next;
+
+static void InitToolHelp32()
+{
+ static bool s_initToolHelpDone = false;
+
+ if (s_initToolHelpDone)
+ return;
+
+ s_initToolHelpDone = true;
+
+ lpfCreateToolhelp32Snapshot = NULL;
+ lpfProcess32First = NULL;
+ lpfProcess32Next = NULL;
+
+#if wxUSE_DYNLIB_CLASS
+
+ wxDynamicLibrary dllKernel(_T("kernel32.dll"), wxDL_VERBATIM);
+
+ // Get procedure addresses.
+ // We are linking to these functions of Kernel32
+ // explicitly, because otherwise a module using
+ // this code would fail to load under Windows NT,
+ // which does not have the Toolhelp32
+ // functions in the Kernel 32.
+ lpfCreateToolhelp32Snapshot =
+ (CreateToolhelp32Snapshot_t)dllKernel.RawGetSymbol(_T("CreateToolhelp32Snapshot"));
+
+ lpfProcess32First =
+ (Process32_t)dllKernel.RawGetSymbol(_T("Process32First"));
+
+ lpfProcess32Next =
+ (Process32_t)dllKernel.RawGetSymbol(_T("Process32Next"));
+
+#endif // wxUSE_DYNLIB_CLASS
+}
+
+// By John Skiff
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc)
+{
+ InitToolHelp32();
+
+ if (krc)
+ *krc = wxKILL_OK;
+
+ // If not implemented for this platform (e.g. NT 4.0), silently ignore
+ if (!lpfCreateToolhelp32Snapshot || !lpfProcess32First || !lpfProcess32Next)
+ return 0;
+
+ // Take a snapshot of all processes in the system.
+ HANDLE hProcessSnap = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcessSnap == INVALID_HANDLE_VALUE) {
+ if (krc)
+ *krc = wxKILL_ERROR;
+ return -1;
+ }
+
+ //Fill in the size of the structure before using it.
+ PROCESSENTRY32 pe;
+ wxZeroMemory(pe);
+ pe.dwSize = sizeof(PROCESSENTRY32);
+
+ // Walk the snapshot of the processes, and for each process,
+ // kill it if its parent is pid.
+ if (!lpfProcess32First(hProcessSnap, &pe)) {
+ // Can't get first process.
+ if (krc)
+ *krc = wxKILL_ERROR;
+ CloseHandle (hProcessSnap);
+ return -1;
+ }
+
+ do {
+ if (pe.th32ParentProcessID == (DWORD) pid) {
+ if (wxKill(pe.th32ProcessID, sig, krc))
+ return -1;
+ }
+ } while (lpfProcess32Next (hProcessSnap, &pe));
+