comparison src/os_win32.c @ 12043:2796a2c9fc17 v8.0.0902

patch 8.0.0902: cannot specify directory or environment for a job commit https://github.com/vim/vim/commit/05aafed54b50b602315ae55d83a7d089804cecb0 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Aug 11 19:12:11 2017 +0200 patch 8.0.0902: cannot specify directory or environment for a job Problem: Cannot specify directory or environment for a job. Solution: Add the "cwd" and "env" arguments to job options. (Yasuhiro Matsumoto, closes #1160)
author Christian Brabandt <cb@256bit.org>
date Fri, 11 Aug 2017 19:15:04 +0200
parents 85f0f557661e
children 779c9247cc0e
comparison
equal deleted inserted replaced
12042:3b09a43a3830 12043:2796a2c9fc17
3979 vim_create_process( 3979 vim_create_process(
3980 char *cmd, 3980 char *cmd,
3981 BOOL inherit_handles, 3981 BOOL inherit_handles,
3982 DWORD flags, 3982 DWORD flags,
3983 STARTUPINFO *si, 3983 STARTUPINFO *si,
3984 PROCESS_INFORMATION *pi) 3984 PROCESS_INFORMATION *pi,
3985 LPVOID *env,
3986 char *cwd)
3985 { 3987 {
3986 #ifdef FEAT_MBYTE 3988 #ifdef FEAT_MBYTE
3987 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) 3989 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3988 { 3990 {
3989 WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL); 3991 BOOL ret;
3990 3992 WCHAR *wcmd, *wcwd = NULL;
3991 if (wcmd != NULL) 3993
3992 { 3994 wcmd = enc_to_utf16((char_u *)cmd, NULL);
3993 BOOL ret; 3995 if (wcmd == NULL)
3994 ret = CreateProcessW( 3996 goto fallback;
3995 NULL, /* Executable name */ 3997 if (cwd != NULL)
3996 wcmd, /* Command to execute */ 3998 {
3997 NULL, /* Process security attributes */ 3999 wcwd = enc_to_utf16((char_u *)cwd, NULL);
3998 NULL, /* Thread security attributes */ 4000 if (wcwd == NULL)
3999 inherit_handles, /* Inherit handles */ 4001 {
4000 flags, /* Creation flags */ 4002 vim_free(wcmd);
4001 NULL, /* Environment */ 4003 goto fallback;
4002 NULL, /* Current directory */ 4004 }
4003 (LPSTARTUPINFOW)si, /* Startup information */ 4005 }
4004 pi); /* Process information */ 4006
4005 vim_free(wcmd); 4007 ret = CreateProcessW(
4006 return ret; 4008 NULL, /* Executable name */
4007 } 4009 wcmd, /* Command to execute */
4008 } 4010 NULL, /* Process security attributes */
4011 NULL, /* Thread security attributes */
4012 inherit_handles, /* Inherit handles */
4013 flags, /* Creation flags */
4014 env, /* Environment */
4015 wcwd, /* Current directory */
4016 (LPSTARTUPINFOW)si, /* Startup information */
4017 pi); /* Process information */
4018 vim_free(wcmd);
4019 if (wcwd != NULL)
4020 vim_free(wcwd);
4021 return ret;
4022 }
4023 fallback:
4009 #endif 4024 #endif
4010 return CreateProcess( 4025 return CreateProcess(
4011 NULL, /* Executable name */ 4026 NULL, /* Executable name */
4012 cmd, /* Command to execute */ 4027 cmd, /* Command to execute */
4013 NULL, /* Process security attributes */ 4028 NULL, /* Process security attributes */
4014 NULL, /* Thread security attributes */ 4029 NULL, /* Thread security attributes */
4015 inherit_handles, /* Inherit handles */ 4030 inherit_handles, /* Inherit handles */
4016 flags, /* Creation flags */ 4031 flags, /* Creation flags */
4017 NULL, /* Environment */ 4032 env, /* Environment */
4018 NULL, /* Current directory */ 4033 cwd, /* Current directory */
4019 si, /* Startup information */ 4034 si, /* Startup information */
4020 pi); /* Process information */ 4035 pi); /* Process information */
4021 } 4036 }
4022 4037
4023 4038
4077 si.cbReserved2 = 0; 4092 si.cbReserved2 = 0;
4078 si.lpReserved2 = NULL; 4093 si.lpReserved2 = NULL;
4079 4094
4080 /* Now, run the command */ 4095 /* Now, run the command */
4081 vim_create_process(cmd, FALSE, 4096 vim_create_process(cmd, FALSE,
4082 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, &si, &pi); 4097 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE,
4098 &si, &pi, NULL, NULL);
4083 4099
4084 /* Wait for the command to terminate before continuing */ 4100 /* Wait for the command to terminate before continuing */
4085 { 4101 {
4086 #ifdef FEAT_GUI 4102 #ifdef FEAT_GUI
4087 int delay = 1; 4103 int delay = 1;
4396 4412
4397 /* Now, run the command. 4413 /* Now, run the command.
4398 * About "Inherit handles" being TRUE: this command can be litigious, 4414 * About "Inherit handles" being TRUE: this command can be litigious,
4399 * handle inheritance was deactivated for pending temp file, but, if we 4415 * handle inheritance was deactivated for pending temp file, but, if we
4400 * deactivate it, the pipes don't work for some reason. */ 4416 * deactivate it, the pipes don't work for some reason. */
4401 vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE, &si, &pi); 4417 vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE,
4418 &si, &pi, NULL, NULL);
4402 4419
4403 if (p != cmd) 4420 if (p != cmd)
4404 vim_free(p); 4421 vim_free(p);
4405 4422
4406 /* Close our unused side of the pipes */ 4423 /* Close our unused side of the pipes */
4833 /* 4850 /*
4834 * Now, start the command as a process, so that it doesn't 4851 * Now, start the command as a process, so that it doesn't
4835 * inherit our handles which causes unpleasant dangling swap 4852 * inherit our handles which causes unpleasant dangling swap
4836 * files if we exit before the spawned process 4853 * files if we exit before the spawned process
4837 */ 4854 */
4838 if (vim_create_process((char *)newcmd, FALSE, flags, &si, &pi)) 4855 if (vim_create_process((char *)newcmd, FALSE, flags,
4856 &si, &pi, NULL, NULL))
4839 x = 0; 4857 x = 0;
4840 else if (vim_shell_execute((char *)newcmd, n_show_cmd) 4858 else if (vim_shell_execute((char *)newcmd, n_show_cmd)
4841 > (HINSTANCE)32) 4859 > (HINSTANCE)32)
4842 x = 0; 4860 x = 0;
4843 else 4861 else
4974 lpSecurityAttributes, dwCreationDisposition, 4992 lpSecurityAttributes, dwCreationDisposition,
4975 dwFlagsAndAttributes, NULL); 4993 dwFlagsAndAttributes, NULL);
4976 return h; 4994 return h;
4977 } 4995 }
4978 4996
4997 /*
4998 * Turn the dictionary "env" into a NUL separated list that can be used as the
4999 * environment argument of vim_create_process().
5000 */
5001 static void
5002 make_job_env(garray_T *gap, dict_T *env)
5003 {
5004 hashitem_T *hi;
5005 int todo = (int)env->dv_hashtab.ht_used;
5006 LPVOID base = GetEnvironmentStringsW();
5007
5008 /* for last \0 */
5009 if (ga_grow(gap, 1) == FAIL)
5010 return;
5011
5012 if (base)
5013 {
5014 WCHAR *p = (WCHAR*) base;
5015
5016 /* for last \0 */
5017 if (ga_grow(gap, 1) == FAIL)
5018 return;
5019
5020 while (*p != 0 || *(p + 1) != 0)
5021 {
5022 if (ga_grow(gap, 1) == OK)
5023 *((WCHAR*)gap->ga_data + gap->ga_len++) = *p;
5024 p++;
5025 }
5026 FreeEnvironmentStrings(base);
5027 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
5028 }
5029
5030 for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi)
5031 {
5032 if (!HASHITEM_EMPTY(hi))
5033 {
5034 typval_T *item = &dict_lookup(hi)->di_tv;
5035 WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL);
5036 WCHAR *wval = enc_to_utf16(get_tv_string(item), NULL);
5037 --todo;
5038 if (wkey != NULL && wval != NULL)
5039 {
5040 int n, lkey = wcslen(wkey), lval = wcslen(wval);
5041 if (ga_grow(gap, lkey + lval + 2) != OK)
5042 continue;
5043 for (n = 0; n < lkey; n++)
5044 *((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n];
5045 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'=';
5046 for (n = 0; n < lval; n++)
5047 *((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n];
5048 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
5049 }
5050 if (wkey != NULL) vim_free(wkey);
5051 if (wval != NULL) vim_free(wval);
5052 }
5053 }
5054
5055 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
5056 }
5057
4979 void 5058 void
4980 mch_job_start(char *cmd, job_T *job, jobopt_T *options) 5059 mch_job_start(char *cmd, job_T *job, jobopt_T *options)
4981 { 5060 {
4982 STARTUPINFO si; 5061 STARTUPINFO si;
4983 PROCESS_INFORMATION pi; 5062 PROCESS_INFORMATION pi;
4985 SECURITY_ATTRIBUTES saAttr; 5064 SECURITY_ATTRIBUTES saAttr;
4986 channel_T *channel = NULL; 5065 channel_T *channel = NULL;
4987 HANDLE ifd[2]; 5066 HANDLE ifd[2];
4988 HANDLE ofd[2]; 5067 HANDLE ofd[2];
4989 HANDLE efd[2]; 5068 HANDLE efd[2];
5069 garray_T ga;
4990 5070
4991 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; 5071 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
4992 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; 5072 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
4993 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL; 5073 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
4994 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; 5074 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
5003 ifd[1] = INVALID_HANDLE_VALUE; 5083 ifd[1] = INVALID_HANDLE_VALUE;
5004 ofd[0] = INVALID_HANDLE_VALUE; 5084 ofd[0] = INVALID_HANDLE_VALUE;
5005 ofd[1] = INVALID_HANDLE_VALUE; 5085 ofd[1] = INVALID_HANDLE_VALUE;
5006 efd[0] = INVALID_HANDLE_VALUE; 5086 efd[0] = INVALID_HANDLE_VALUE;
5007 efd[1] = INVALID_HANDLE_VALUE; 5087 efd[1] = INVALID_HANDLE_VALUE;
5088 ga_init2(&ga, (int)sizeof(wchar_t), 500);
5008 5089
5009 jo = CreateJobObject(NULL, NULL); 5090 jo = CreateJobObject(NULL, NULL);
5010 if (jo == NULL) 5091 if (jo == NULL)
5011 { 5092 {
5012 job->jv_status = JOB_FAILED; 5093 job->jv_status = JOB_FAILED;
5013 goto failed; 5094 goto failed;
5014 } 5095 }
5096
5097 if (options->jo_env != NULL)
5098 make_job_env(&ga, options->jo_env);
5015 5099
5016 ZeroMemory(&pi, sizeof(pi)); 5100 ZeroMemory(&pi, sizeof(pi));
5017 ZeroMemory(&si, sizeof(si)); 5101 ZeroMemory(&si, sizeof(si));
5018 si.cb = sizeof(si); 5102 si.cb = sizeof(si);
5019 si.dwFlags |= STARTF_USESHOWWINDOW; 5103 si.dwFlags |= STARTF_USESHOWWINDOW;
5098 5182
5099 if (!vim_create_process(cmd, TRUE, 5183 if (!vim_create_process(cmd, TRUE,
5100 CREATE_SUSPENDED | 5184 CREATE_SUSPENDED |
5101 CREATE_DEFAULT_ERROR_MODE | 5185 CREATE_DEFAULT_ERROR_MODE |
5102 CREATE_NEW_PROCESS_GROUP | 5186 CREATE_NEW_PROCESS_GROUP |
5187 CREATE_UNICODE_ENVIRONMENT |
5103 CREATE_NEW_CONSOLE, 5188 CREATE_NEW_CONSOLE,
5104 &si, &pi)) 5189 &si, &pi,
5190 ga.ga_data,
5191 (char *)options->jo_cwd))
5105 { 5192 {
5106 CloseHandle(jo); 5193 CloseHandle(jo);
5107 job->jv_status = JOB_FAILED; 5194 job->jv_status = JOB_FAILED;
5108 goto failed; 5195 goto failed;
5109 } 5196 }
5197
5198 ga_clear(&ga);
5110 5199
5111 if (!AssignProcessToJobObject(jo, pi.hProcess)) 5200 if (!AssignProcessToJobObject(jo, pi.hProcess))
5112 { 5201 {
5113 /* if failing, switch the way to terminate 5202 /* if failing, switch the way to terminate
5114 * process with TerminateProcess. */ 5203 * process with TerminateProcess. */
5146 CloseHandle(efd[0]); 5235 CloseHandle(efd[0]);
5147 CloseHandle(ifd[1]); 5236 CloseHandle(ifd[1]);
5148 CloseHandle(ofd[1]); 5237 CloseHandle(ofd[1]);
5149 CloseHandle(efd[1]); 5238 CloseHandle(efd[1]);
5150 channel_unref(channel); 5239 channel_unref(channel);
5240 ga_clear(&ga);
5151 } 5241 }
5152 5242
5153 char * 5243 char *
5154 mch_job_status(job_T *job) 5244 mch_job_status(job_T *job)
5155 { 5245 {