comparison src/os_win32.c @ 10304:179794481db4 v8.0.0048

commit https://github.com/vim/vim/commit/a350bab042605422304161df462b173ffa31dcb9 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Oct 27 16:46:53 2016 +0200 patch 8.0.0048 Problem: On Windows job_stop() stops cmd.exe, not the processes it runs. (Linwei) Solution: Iterate over all processes and terminate the one where the parent is the job process. (Yasuhiro Matsumoto, closes #1184)
author Christian Brabandt <cb@256bit.org>
date Thu, 27 Oct 2016 17:00:04 +0200
parents c5c15c818bda
children 931422d27b69
comparison
equal deleted inserted replaced
10303:9b3b448e538e 10304:179794481db4
46 46
47 #ifndef PROTO 47 #ifndef PROTO
48 # if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32) 48 # if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
49 # include <shellapi.h> 49 # include <shellapi.h>
50 # endif 50 # endif
51 #endif
52
53 #ifdef FEAT_JOB_CHANNEL
54 # include <tlhelp32.h>
51 #endif 55 #endif
52 56
53 #ifdef __MINGW32__ 57 #ifdef __MINGW32__
54 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED 58 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED
55 # define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001 59 # define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
4794 void 4798 void
4795 mch_start_job(char *cmd, job_T *job, jobopt_T *options) 4799 mch_start_job(char *cmd, job_T *job, jobopt_T *options)
4796 { 4800 {
4797 STARTUPINFO si; 4801 STARTUPINFO si;
4798 PROCESS_INFORMATION pi; 4802 PROCESS_INFORMATION pi;
4799 HANDLE jo;
4800 SECURITY_ATTRIBUTES saAttr; 4803 SECURITY_ATTRIBUTES saAttr;
4801 channel_T *channel = NULL; 4804 channel_T *channel = NULL;
4802 HANDLE ifd[2]; 4805 HANDLE ifd[2];
4803 HANDLE ofd[2]; 4806 HANDLE ofd[2];
4804 HANDLE efd[2]; 4807 HANDLE efd[2];
4819 ofd[0] = INVALID_HANDLE_VALUE; 4822 ofd[0] = INVALID_HANDLE_VALUE;
4820 ofd[1] = INVALID_HANDLE_VALUE; 4823 ofd[1] = INVALID_HANDLE_VALUE;
4821 efd[0] = INVALID_HANDLE_VALUE; 4824 efd[0] = INVALID_HANDLE_VALUE;
4822 efd[1] = INVALID_HANDLE_VALUE; 4825 efd[1] = INVALID_HANDLE_VALUE;
4823 4826
4824 jo = CreateJobObject(NULL, NULL);
4825 if (jo == NULL)
4826 {
4827 job->jv_status = JOB_FAILED;
4828 goto failed;
4829 }
4830
4831 ZeroMemory(&pi, sizeof(pi)); 4827 ZeroMemory(&pi, sizeof(pi));
4832 ZeroMemory(&si, sizeof(si)); 4828 ZeroMemory(&si, sizeof(si));
4833 si.cb = sizeof(si); 4829 si.cb = sizeof(si);
4834 si.dwFlags |= STARTF_USESHOWWINDOW; 4830 si.dwFlags |= STARTF_USESHOWWINDOW;
4835 si.wShowWindow = SW_HIDE; 4831 si.wShowWindow = SW_HIDE;
4910 if (channel == NULL) 4906 if (channel == NULL)
4911 goto failed; 4907 goto failed;
4912 } 4908 }
4913 4909
4914 if (!vim_create_process(cmd, TRUE, 4910 if (!vim_create_process(cmd, TRUE,
4915 CREATE_SUSPENDED |
4916 CREATE_DEFAULT_ERROR_MODE | 4911 CREATE_DEFAULT_ERROR_MODE |
4917 CREATE_NEW_PROCESS_GROUP | 4912 CREATE_NEW_PROCESS_GROUP |
4918 CREATE_NEW_CONSOLE, 4913 CREATE_NEW_CONSOLE,
4919 &si, &pi)) 4914 &si, &pi))
4920 { 4915 {
4921 CloseHandle(jo);
4922 job->jv_status = JOB_FAILED; 4916 job->jv_status = JOB_FAILED;
4923 goto failed; 4917 goto failed;
4924 } 4918 }
4925 4919
4926 if (!AssignProcessToJobObject(jo, pi.hProcess))
4927 {
4928 /* if failing, switch the way to terminate
4929 * process with TerminateProcess. */
4930 CloseHandle(jo);
4931 jo = NULL;
4932 }
4933 ResumeThread(pi.hThread);
4934 CloseHandle(pi.hThread); 4920 CloseHandle(pi.hThread);
4935 job->jv_proc_info = pi; 4921 job->jv_proc_info = pi;
4936 job->jv_job_object = jo;
4937 job->jv_status = JOB_STARTED; 4922 job->jv_status = JOB_STARTED;
4938 4923
4939 CloseHandle(ifd[0]); 4924 CloseHandle(ifd[0]);
4940 CloseHandle(ofd[1]); 4925 CloseHandle(ofd[1]);
4941 if (!use_out_for_err && !use_null_for_err) 4926 if (!use_out_for_err && !use_null_for_err)
5018 } 5003 }
5019 } 5004 }
5020 return NULL; 5005 return NULL;
5021 } 5006 }
5022 5007
5008 static BOOL
5009 terminate_all(HANDLE process, int code)
5010 {
5011 PROCESSENTRY32 pe;
5012 HANDLE h = INVALID_HANDLE_VALUE;
5013 DWORD pid = GetProcessId(process);
5014
5015 if (pid != 0)
5016 {
5017 h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
5018 if (h == INVALID_HANDLE_VALUE)
5019 goto theend;
5020
5021 pe.dwSize = sizeof(PROCESSENTRY32);
5022 if (Process32First(h, &pe))
5023 {
5024 do
5025 {
5026 if (pe.th32ParentProcessID == pid)
5027 {
5028 HANDLE ph = OpenProcess(
5029 PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
5030 if (ph != NULL)
5031 {
5032 terminate_all(ph, code);
5033 CloseHandle(ph);
5034 }
5035 }
5036 } while (Process32Next(h, &pe));
5037 }
5038
5039 CloseHandle(h);
5040 }
5041
5042 theend:
5043 return TerminateProcess(process, code);
5044 }
5045
5023 int 5046 int
5024 mch_stop_job(job_T *job, char_u *how) 5047 mch_stop_job(job_T *job, char_u *how)
5025 { 5048 {
5026 int ret; 5049 int ret;
5027 5050
5028 if (STRCMP(how, "term") == 0 || STRCMP(how, "kill") == 0 || *how == NUL) 5051 if (STRCMP(how, "term") == 0 || STRCMP(how, "kill") == 0 || *how == NUL)
5029 { 5052 {
5030 if (job->jv_job_object != NULL) 5053 return terminate_all(job->jv_proc_info.hProcess, 0) ? OK : FAIL;
5031 return TerminateJobObject(job->jv_job_object, 0) ? OK : FAIL;
5032 else
5033 return TerminateProcess(job->jv_proc_info.hProcess, 0) ? OK : FAIL;
5034 } 5054 }
5035 5055
5036 if (!AttachConsole(job->jv_proc_info.dwProcessId)) 5056 if (!AttachConsole(job->jv_proc_info.dwProcessId))
5037 return FAIL; 5057 return FAIL;
5038 ret = GenerateConsoleCtrlEvent( 5058 ret = GenerateConsoleCtrlEvent(
5049 void 5069 void
5050 mch_clear_job(job_T *job) 5070 mch_clear_job(job_T *job)
5051 { 5071 {
5052 if (job->jv_status != JOB_FAILED) 5072 if (job->jv_status != JOB_FAILED)
5053 { 5073 {
5054 if (job->jv_job_object != NULL)
5055 CloseHandle(job->jv_job_object);
5056 CloseHandle(job->jv_proc_info.hProcess); 5074 CloseHandle(job->jv_proc_info.hProcess);
5057 } 5075 }
5058 } 5076 }
5059 #endif 5077 #endif
5060 5078