+// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
+struct wxFindByPidParams
+{
+ 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()