2 * msvcrt.dll spawn/exec functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * -File handles need some special handling. Sometimes children get
25 * open file handles, sometimes not. The docs are confusing
26 * -No check for maximum path/argument/environment size is done
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38 /* INTERNAL: Spawn a child process */
39 static MSVCRT_intptr_t msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
42 PROCESS_INFORMATION pi;
44 if ((unsigned)flags > MSVCRT__P_DETACH)
46 *MSVCRT__errno() = MSVCRT_EINVAL;
50 memset(&si, 0, sizeof(si));
52 msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2);
53 if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
54 flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
57 msvcrt_set_errno(GetLastError());
58 MSVCRT_free(si.lpReserved2);
62 MSVCRT_free(si.lpReserved2);
66 WaitForSingleObject(pi.hProcess, INFINITE);
67 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
68 CloseHandle(pi.hProcess);
69 CloseHandle(pi.hThread);
70 return pi.dwProcessId;
71 case MSVCRT__P_DETACH:
72 CloseHandle(pi.hProcess);
75 case MSVCRT__P_NOWAIT:
76 case MSVCRT__P_NOWAITO:
77 CloseHandle(pi.hThread);
78 return (MSVCRT_intptr_t)pi.hProcess;
79 case MSVCRT__P_OVERLAY:
82 return -1; /* can't reach here */
85 static MSVCRT_intptr_t msvcrt_spawn_wide(int flags, const MSVCRT_wchar_t* exe, MSVCRT_wchar_t* cmdline, MSVCRT_wchar_t* env)
88 PROCESS_INFORMATION pi;
90 if ((unsigned)flags > MSVCRT__P_DETACH)
92 *MSVCRT__errno() = MSVCRT_EINVAL;
96 memset(&si, 0, sizeof(si));
98 msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2);
99 if (!CreateProcessW(exe, cmdline, NULL, NULL, TRUE,
100 flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
101 env, NULL, &si, &pi))
103 msvcrt_set_errno(GetLastError());
104 MSVCRT_free(si.lpReserved2);
108 MSVCRT_free(si.lpReserved2);
112 WaitForSingleObject(pi.hProcess, INFINITE);
113 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
114 CloseHandle(pi.hProcess);
115 CloseHandle(pi.hThread);
116 return pi.dwProcessId;
117 case MSVCRT__P_DETACH:
118 CloseHandle(pi.hProcess);
121 case MSVCRT__P_NOWAIT:
122 case MSVCRT__P_NOWAITO:
123 CloseHandle(pi.hThread);
124 return (MSVCRT_intptr_t)pi.hProcess;
125 case MSVCRT__P_OVERLAY:
128 return -1; /* can't reach here */
131 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
132 * extra '\0' to terminate it
134 static char* msvcrt_argvtos(const char* const* arg, char delim)
136 const char* const* a;
143 /* Return NULL for an empty environment list */
152 size += strlen(*a) + 1;
156 ret = MSVCRT_malloc(size + 1);
165 int len = strlen(*a);
171 if (delim && p > ret) p[-1] = 0;
176 static MSVCRT_wchar_t* msvcrt_argvtos_wide(const MSVCRT_wchar_t* const* arg, MSVCRT_wchar_t delim)
178 const MSVCRT_wchar_t* const* a;
185 /* Return NULL for an empty environment list */
194 size += strlenW(*a) + 1;
198 ret = MSVCRT_malloc((size + 1) * sizeof(MSVCRT_wchar_t));
207 int len = strlenW(*a);
208 memcpy(p,*a,len * sizeof(MSVCRT_wchar_t));
213 if (delim && p > ret) p[-1] = 0;
218 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
219 * extra '\0' to terminate it
221 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
230 va_copy(alist2,alist);
232 # ifdef HAVE___VA_COPY
233 __va_copy(alist2,alist);
241 /* Return NULL for an empty environment list */
249 size += strlen(arg) + 1;
250 arg = va_arg(alist, char*);
251 } while (arg != NULL);
253 ret = MSVCRT_malloc(size + 1);
261 int len = strlen(arg);
265 arg = va_arg(alist2, char*);
266 } while (arg != NULL);
267 if (delim && p > ret) p[-1] = 0;
272 /*********************************************************************
275 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
277 HANDLE hPid = (HANDLE)pid;
280 action = action; /* Remove warning */
282 if (!WaitForSingleObject(hPid, INFINITE))
287 GetExitCodeProcess(hPid, &stat);
292 doserrno = GetLastError();
294 if (doserrno == ERROR_INVALID_HANDLE)
296 *MSVCRT__errno() = MSVCRT_ECHILD;
297 *MSVCRT___doserrno() = doserrno;
300 msvcrt_set_errno(doserrno);
302 return status ? *status = -1 : -1;
305 /*********************************************************************
308 * Like on Windows, this function does not handle arguments with spaces
311 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
318 args = msvcrt_valisttos(arg0, ap, ' ');
321 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
327 /*********************************************************************
330 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
336 /*********************************************************************
339 * Like on Windows, this function does not handle arguments with spaces
342 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
347 char fullname[MAX_PATH];
349 _searchenv(name, "PATH", fullname);
352 args = msvcrt_valisttos(arg0, ap, ' ');
355 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
361 /*********************************************************************
362 * _execlpe (MSVCRT.@)
364 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
370 /*********************************************************************
373 * Like on Windows, this function does not handle arguments with spaces
376 MSVCRT_intptr_t CDECL _execv(const char* name, char* const* argv)
378 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
381 /*********************************************************************
384 * Like on Windows, this function does not handle arguments with spaces
387 MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, char* const* argv, const char* const* envv)
389 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
392 /*********************************************************************
393 * _execvpe (MSVCRT.@)
395 * Like on Windows, this function does not handle arguments with spaces
398 MSVCRT_intptr_t CDECL _execvpe(const char* name, char* const* argv, const char* const* envv)
400 char fullname[MAX_PATH];
402 _searchenv(name, "PATH", fullname);
403 return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
404 (const char* const*) argv, envv);
407 /*********************************************************************
410 * Like on Windows, this function does not handle arguments with spaces
413 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
415 return _execvpe(name, argv, NULL);
418 /*********************************************************************
421 * Like on Windows, this function does not handle arguments with spaces
424 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
431 args = msvcrt_valisttos(arg0, ap, ' ');
434 ret = msvcrt_spawn(flags, name, args, NULL);
440 /*********************************************************************
441 * _spawnle (MSVCRT.@)
443 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
446 char *args, *envs = NULL;
447 const char * const *envp;
451 args = msvcrt_valisttos(arg0, ap, ' ');
455 while (va_arg( ap, char * ) != NULL) /*nothing*/;
456 envp = va_arg( ap, const char * const * );
457 if (envp) envs = msvcrt_argvtos(envp, 0);
460 ret = msvcrt_spawn(flags, name, args, envs);
468 /*********************************************************************
469 * _spawnlp (MSVCRT.@)
471 * Like on Windows, this function does not handle arguments with spaces
474 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
479 char fullname[MAX_PATH];
481 _searchenv(name, "PATH", fullname);
484 args = msvcrt_valisttos(arg0, ap, ' ');
487 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
493 /*********************************************************************
494 * _spawnlpe (MSVCRT.@)
496 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
499 char *args, *envs = NULL;
500 const char * const *envp;
502 char fullname[MAX_PATH];
504 _searchenv(name, "PATH", fullname);
507 args = msvcrt_valisttos(arg0, ap, ' ');
511 while (va_arg( ap, char * ) != NULL) /*nothing*/;
512 envp = va_arg( ap, const char * const * );
513 if (envp) envs = msvcrt_argvtos(envp, 0);
516 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
523 /*********************************************************************
524 * _spawnve (MSVCRT.@)
526 * Like on Windows, this function does not handle arguments with spaces
529 MSVCRT_intptr_t CDECL _spawnve(int flags, const char* name, const char* const* argv,
530 const char* const* envv)
532 char * args = msvcrt_argvtos(argv,' ');
533 char * envs = msvcrt_argvtos(envv,0);
534 char fullname[MAX_PATH];
537 MSVCRT_intptr_t ret = -1;
539 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name),debugstr_a(args),
540 envs?"Custom":"Null");
542 /* no check for NULL name.
543 native doesn't do it */
545 p = memchr(name, '\0', MAX_PATH);
547 p = name + MAX_PATH - 1;
550 /* extra-long names are silently truncated. */
551 memcpy(fullname, name, len);
553 for( p--; p >= name; p-- )
555 if( *p == '\\' || *p == '/' || *p == ':' || *p == '.' )
559 /* if no extension is given, assume .exe */
560 if( (p < name || *p != '.') && len <= MAX_PATH - 5 )
562 FIXME("only trying .exe when no extension given\n");
563 memcpy(fullname+len, ".exe", 4);
567 fullname[len] = '\0';
571 ret = msvcrt_spawn(flags, fullname, args, envs);
579 /*********************************************************************
580 * _wspawnve (MSVCRT.@)
582 * Unicode version of _spawnve
584 MSVCRT_intptr_t CDECL _wspawnve(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
585 const MSVCRT_wchar_t* const* envv)
587 MSVCRT_wchar_t * args = msvcrt_argvtos_wide(argv,' ');
588 MSVCRT_wchar_t * envs = msvcrt_argvtos_wide(envv,0);
589 MSVCRT_wchar_t fullname[MAX_PATH];
590 const MSVCRT_wchar_t *p;
592 MSVCRT_intptr_t ret = -1;
594 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_w(name),debugstr_w(args),
595 envs?"Custom":"Null");
597 /* no check for NULL name.
598 native doesn't do it */
600 p = memchrW(name, '\0', MAX_PATH);
602 p = name + MAX_PATH - 1;
605 /* extra-long names are silently truncated. */
606 memcpy(fullname, name, len * sizeof(MSVCRT_wchar_t));
608 for( p--; p >= name; p-- )
610 if( *p == '\\' || *p == '/' || *p == ':' || *p == '.' )
614 /* if no extension is given, assume .exe */
615 if( (p < name || *p != '.') && len <= MAX_PATH - 5 )
617 static const MSVCRT_wchar_t dotexe[] = {'.','e','x','e'};
619 FIXME("only trying .exe when no extension given\n");
620 memcpy(fullname+len, dotexe, 4 * sizeof(MSVCRT_wchar_t));
624 fullname[len] = '\0';
628 ret = msvcrt_spawn_wide(flags, fullname, args, envs);
636 /*********************************************************************
639 * Like on Windows, this function does not handle arguments with spaces
642 MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
644 return _spawnve(flags, name, argv, NULL);
647 /*********************************************************************
648 * _wspawnv (MSVCRT.@)
650 * Unicode version of _spawnv
652 MSVCRT_intptr_t CDECL _wspawnv(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
654 return _wspawnve(flags, name, argv, NULL);
657 /*********************************************************************
658 * _spawnvpe (MSVCRT.@)
660 * Like on Windows, this function does not handle arguments with spaces
663 MSVCRT_intptr_t CDECL _spawnvpe(int flags, const char* name, const char* const* argv,
664 const char* const* envv)
666 char fullname[MAX_PATH];
667 _searchenv(name, "PATH", fullname);
668 return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
671 /*********************************************************************
672 * _wspawnvpe (MSVCRT.@)
674 * Unicode version of _spawnvpe
676 MSVCRT_intptr_t CDECL _wspawnvpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
677 const MSVCRT_wchar_t* const* envv)
679 static const MSVCRT_wchar_t path[] = {'P','A','T','H',0};
680 MSVCRT_wchar_t fullname[MAX_PATH];
682 _wsearchenv(name, path, fullname);
683 return _wspawnve(flags, fullname[0] ? fullname : name, argv, envv);
686 /*********************************************************************
687 * _spawnvp (MSVCRT.@)
689 * Like on Windows, this function does not handle arguments with spaces
692 MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
694 return _spawnvpe(flags, name, argv, NULL);
697 /*********************************************************************
698 * _wspawnvp (MSVCRT.@)
700 * Unicode version of _spawnvp
702 MSVCRT_intptr_t CDECL _wspawnvp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
704 return _wspawnvpe(flags, name, argv, NULL);
707 /*********************************************************************
709 * FIXME: convert to _wpopen and call that from here instead? But it
710 * would have to convert the command back to ANSI to call msvcrt_spawn,
713 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
715 static const char wcmd[] = "cmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
717 BOOL readPipe = TRUE;
718 int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
723 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
725 if (!command || !mode)
728 textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
729 for (p = mode; *p; p++)
739 textmode |= MSVCRT__O_BINARY;
740 textmode &= ~MSVCRT__O_TEXT;
744 textmode |= MSVCRT__O_TEXT;
745 textmode &= ~MSVCRT__O_BINARY;
749 if (MSVCRT__pipe(fds, 0, textmode) == -1)
752 fdToDup = readPipe ? 1 : 0;
753 fdToOpen = readPipe ? 0 : 1;
755 if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
757 if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
761 if ((fdStdErr = MSVCRT__dup(MSVCRT_STDERR_FILENO)) == -1)
763 if (MSVCRT__dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
767 MSVCRT__close(fds[fdToDup]);
769 comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
771 comSpecLen = strlen(wcmd) + 1;
772 cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
774 if (!GetEnvironmentVariableA(comSpec, cmdcopy, comSpecLen))
775 strcpy(cmdcopy, wcmd);
776 strcat(cmdcopy, cmdFlag);
777 strcat(cmdcopy, command);
778 if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, cmdcopy, NULL) == -1)
780 MSVCRT__close(fds[fdToOpen]);
785 ret = MSVCRT__fdopen(fds[fdToOpen], mode);
787 MSVCRT__close(fds[fdToOpen]);
789 HeapFree(GetProcessHeap(), 0, cmdcopy);
790 MSVCRT__dup2(fdStdHandle, fdToDup);
791 MSVCRT__close(fdStdHandle);
794 MSVCRT__dup2(fdStdErr, MSVCRT_STDERR_FILENO);
795 MSVCRT__close(fdStdErr);
800 if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
801 if (fdStdErr != -1) MSVCRT__close(fdStdErr);
802 MSVCRT__close(fds[0]);
803 MSVCRT__close(fds[1]);
807 /*********************************************************************
810 MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
812 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
816 /*********************************************************************
819 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
821 return MSVCRT_fclose(file);
824 /*********************************************************************
827 int CDECL MSVCRT_system(const char* cmd)
832 /* Make a writable copy for CreateProcess */
833 cmdcopy=_strdup(cmd);
834 /* FIXME: should probably launch cmd interpreter in COMSPEC */
835 res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
836 MSVCRT_free(cmdcopy);
840 /*********************************************************************
841 * _loaddll (MSVCRT.@)
843 MSVCRT_intptr_t CDECL _loaddll(const char* dllname)
845 return (MSVCRT_intptr_t)LoadLibraryA(dllname);
848 /*********************************************************************
849 * _unloaddll (MSVCRT.@)
851 int CDECL _unloaddll(MSVCRT_intptr_t dll)
853 if (FreeLibrary((HMODULE)dll))
857 int err = GetLastError();
858 msvcrt_set_errno(err);
863 /*********************************************************************
864 * _getdllprocaddr (MSVCRT.@)
866 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
870 if (ordinal != -1) return NULL;
871 return GetProcAddress( (HMODULE)dll, name );
873 if (HIWORD(ordinal)) return NULL;
874 return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );