comctl32/tests: Fix the control's size reporting in an error message.
[wine/multimedia.git] / dlls / msvcrt / process.c
blob14f8e9a28bd4bc3fe96d758c8626d49655df65b0
1 /*
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
23 * FIXME:
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
28 #include "config.h"
30 #include <stdarg.h>
32 #include "msvcrt.h"
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)
41 STARTUPINFOA si;
42 PROCESS_INFORMATION pi;
44 if ((unsigned)flags > MSVCRT__P_DETACH)
46 *MSVCRT__errno() = MSVCRT_EINVAL;
47 return -1;
50 memset(&si, 0, sizeof(si));
51 si.cb = 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,
55 env, NULL, &si, &pi))
57 msvcrt_set_errno(GetLastError());
58 MSVCRT_free(si.lpReserved2);
59 return -1;
62 MSVCRT_free(si.lpReserved2);
63 switch(flags)
65 case MSVCRT__P_WAIT:
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);
73 pi.hProcess = 0;
74 /* fall through */
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:
80 MSVCRT__exit(0);
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)
87 STARTUPINFOW si;
88 PROCESS_INFORMATION pi;
90 if ((unsigned)flags > MSVCRT__P_DETACH)
92 *MSVCRT__errno() = MSVCRT_EINVAL;
93 return -1;
96 memset(&si, 0, sizeof(si));
97 si.cb = 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);
105 return -1;
108 MSVCRT_free(si.lpReserved2);
109 switch(flags)
111 case MSVCRT__P_WAIT:
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);
119 pi.hProcess = 0;
120 /* fall through */
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:
126 MSVCRT__exit(0);
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;
137 long size;
138 char* p;
139 char* ret;
141 if (!arg && !delim)
143 /* Return NULL for an empty environment list */
144 return NULL;
147 /* get length */
148 a = arg;
149 size = 0;
150 while (*a)
152 size += strlen(*a) + 1;
153 a++;
156 ret = MSVCRT_malloc(size + 1);
157 if (!ret)
158 return NULL;
160 /* fill string */
161 a = arg;
162 p = ret;
163 while (*a)
165 int len = strlen(*a);
166 memcpy(p,*a,len);
167 p += len;
168 *p++ = delim;
169 a++;
171 if (delim && p > ret) p[-1] = 0;
172 else *p = 0;
173 return ret;
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;
179 long size;
180 MSVCRT_wchar_t* p;
181 MSVCRT_wchar_t* ret;
183 if (!arg && !delim)
185 /* Return NULL for an empty environment list */
186 return NULL;
189 /* get length */
190 a = arg;
191 size = 0;
192 while (*a)
194 size += strlenW(*a) + 1;
195 a++;
198 ret = MSVCRT_malloc((size + 1) * sizeof(MSVCRT_wchar_t));
199 if (!ret)
200 return NULL;
202 /* fill string */
203 a = arg;
204 p = ret;
205 while (*a)
207 int len = strlenW(*a);
208 memcpy(p,*a,len * sizeof(MSVCRT_wchar_t));
209 p += len;
210 *p++ = delim;
211 a++;
213 if (delim && p > ret) p[-1] = 0;
214 else *p = 0;
215 return ret;
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)
223 va_list alist2;
224 long size;
225 const char *arg;
226 char* p;
227 char *ret;
229 #ifdef HAVE_VA_COPY
230 va_copy(alist2,alist);
231 #else
232 # ifdef HAVE___VA_COPY
233 __va_copy(alist2,alist);
234 # else
235 alist2 = alist;
236 # endif
237 #endif
239 if (!arg0)
241 /* Return NULL for an empty environment list */
242 return NULL;
245 /* get length */
246 arg = arg0;
247 size = 0;
248 do {
249 size += strlen(arg) + 1;
250 arg = va_arg(alist, char*);
251 } while (arg != NULL);
253 ret = MSVCRT_malloc(size + 1);
254 if (!ret)
255 return NULL;
257 /* fill string */
258 arg = arg0;
259 p = ret;
260 do {
261 int len = strlen(arg);
262 memcpy(p,arg,len);
263 p += len;
264 *p++ = delim;
265 arg = va_arg(alist2, char*);
266 } while (arg != NULL);
267 if (delim && p > ret) p[-1] = 0;
268 else *p = 0;
269 return ret;
272 /*********************************************************************
273 * _cwait (MSVCRT.@)
275 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
277 HANDLE hPid = (HANDLE)pid;
278 int doserrno;
280 action = action; /* Remove warning */
282 if (!WaitForSingleObject(hPid, INFINITE))
284 if (status)
286 DWORD stat;
287 GetExitCodeProcess(hPid, &stat);
288 *status = (int)stat;
290 return pid;
292 doserrno = GetLastError();
294 if (doserrno == ERROR_INVALID_HANDLE)
296 *MSVCRT__errno() = MSVCRT_ECHILD;
297 *MSVCRT___doserrno() = doserrno;
299 else
300 msvcrt_set_errno(doserrno);
302 return status ? *status = -1 : -1;
305 /*********************************************************************
306 * _execl (MSVCRT.@)
308 * Like on Windows, this function does not handle arguments with spaces
309 * or double-quotes.
311 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
313 va_list ap;
314 char * args;
315 MSVCRT_intptr_t ret;
317 va_start(ap, arg0);
318 args = msvcrt_valisttos(arg0, ap, ' ');
319 va_end(ap);
321 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
322 MSVCRT_free(args);
324 return ret;
327 /*********************************************************************
328 * _execle (MSVCRT.@)
330 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
332 FIXME("stub\n");
333 return -1;
336 /*********************************************************************
337 * _execlp (MSVCRT.@)
339 * Like on Windows, this function does not handle arguments with spaces
340 * or double-quotes.
342 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
344 va_list ap;
345 char * args;
346 MSVCRT_intptr_t ret;
347 char fullname[MAX_PATH];
349 _searchenv(name, "PATH", fullname);
351 va_start(ap, arg0);
352 args = msvcrt_valisttos(arg0, ap, ' ');
353 va_end(ap);
355 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
356 MSVCRT_free(args);
358 return ret;
361 /*********************************************************************
362 * _execlpe (MSVCRT.@)
364 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
366 FIXME("stub\n");
367 return -1;
370 /*********************************************************************
371 * _execv (MSVCRT.@)
373 * Like on Windows, this function does not handle arguments with spaces
374 * or double-quotes.
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 /*********************************************************************
382 * _execve (MSVCRT.@)
384 * Like on Windows, this function does not handle arguments with spaces
385 * or double-quotes.
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
396 * or double-quotes.
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 /*********************************************************************
408 * _execvp (MSVCRT.@)
410 * Like on Windows, this function does not handle arguments with spaces
411 * or double-quotes.
413 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
415 return _execvpe(name, argv, NULL);
418 /*********************************************************************
419 * _spawnl (MSVCRT.@)
421 * Like on Windows, this function does not handle arguments with spaces
422 * or double-quotes.
424 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
426 va_list ap;
427 char * args;
428 MSVCRT_intptr_t ret;
430 va_start(ap, arg0);
431 args = msvcrt_valisttos(arg0, ap, ' ');
432 va_end(ap);
434 ret = msvcrt_spawn(flags, name, args, NULL);
435 MSVCRT_free(args);
437 return ret;
440 /*********************************************************************
441 * _spawnle (MSVCRT.@)
443 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
445 va_list ap;
446 char *args, *envs = NULL;
447 const char * const *envp;
448 MSVCRT_intptr_t ret;
450 va_start(ap, arg0);
451 args = msvcrt_valisttos(arg0, ap, ' ');
452 va_end(ap);
454 va_start(ap, arg0);
455 while (va_arg( ap, char * ) != NULL) /*nothing*/;
456 envp = va_arg( ap, const char * const * );
457 if (envp) envs = msvcrt_argvtos(envp, 0);
458 va_end(ap);
460 ret = msvcrt_spawn(flags, name, args, envs);
462 MSVCRT_free(args);
463 MSVCRT_free(envs);
464 return ret;
468 /*********************************************************************
469 * _spawnlp (MSVCRT.@)
471 * Like on Windows, this function does not handle arguments with spaces
472 * or double-quotes.
474 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
476 va_list ap;
477 char * args;
478 MSVCRT_intptr_t ret;
479 char fullname[MAX_PATH];
481 _searchenv(name, "PATH", fullname);
483 va_start(ap, arg0);
484 args = msvcrt_valisttos(arg0, ap, ' ');
485 va_end(ap);
487 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
488 MSVCRT_free(args);
490 return ret;
493 /*********************************************************************
494 * _spawnlpe (MSVCRT.@)
496 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
498 va_list ap;
499 char *args, *envs = NULL;
500 const char * const *envp;
501 MSVCRT_intptr_t ret;
502 char fullname[MAX_PATH];
504 _searchenv(name, "PATH", fullname);
506 va_start(ap, arg0);
507 args = msvcrt_valisttos(arg0, ap, ' ');
508 va_end(ap);
510 va_start(ap, arg0);
511 while (va_arg( ap, char * ) != NULL) /*nothing*/;
512 envp = va_arg( ap, const char * const * );
513 if (envp) envs = msvcrt_argvtos(envp, 0);
514 va_end(ap);
516 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
518 MSVCRT_free(args);
519 MSVCRT_free(envs);
520 return ret;
523 /*********************************************************************
524 * _spawnve (MSVCRT.@)
526 * Like on Windows, this function does not handle arguments with spaces
527 * or double-quotes.
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];
535 const char *p;
536 int len;
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);
546 if( !p )
547 p = name + MAX_PATH - 1;
548 len = p - name;
550 /* extra-long names are silently truncated. */
551 memcpy(fullname, name, len);
553 for( p--; p >= name; p-- )
555 if( *p == '\\' || *p == '/' || *p == ':' || *p == '.' )
556 break;
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);
564 len += 4;
567 fullname[len] = '\0';
569 if (args)
571 ret = msvcrt_spawn(flags, fullname, args, envs);
572 MSVCRT_free(args);
574 MSVCRT_free(envs);
576 return ret;
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;
591 int len;
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);
601 if( !p )
602 p = name + MAX_PATH - 1;
603 len = p - name;
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 == '.' )
611 break;
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));
621 len += 4;
624 fullname[len] = '\0';
626 if (args)
628 ret = msvcrt_spawn_wide(flags, fullname, args, envs);
629 MSVCRT_free(args);
631 MSVCRT_free(envs);
633 return ret;
636 /*********************************************************************
637 * _spawnv (MSVCRT.@)
639 * Like on Windows, this function does not handle arguments with spaces
640 * or double-quotes.
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
661 * or double-quotes.
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
690 * or double-quotes.
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 /*********************************************************************
708 * _popen (MSVCRT.@)
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,
711 * less than ideal.
713 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
715 static const char wcmd[] = "cmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
716 MSVCRT_FILE *ret;
717 BOOL readPipe = TRUE;
718 int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
719 const char *p;
720 char *cmdcopy;
721 DWORD comSpecLen;
723 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
725 if (!command || !mode)
726 return NULL;
728 textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
729 for (p = mode; *p; p++)
731 switch (*p)
733 case 'W':
734 case 'w':
735 readPipe = FALSE;
736 break;
737 case 'B':
738 case 'b':
739 textmode |= MSVCRT__O_BINARY;
740 textmode &= ~MSVCRT__O_TEXT;
741 break;
742 case 'T':
743 case 't':
744 textmode |= MSVCRT__O_TEXT;
745 textmode &= ~MSVCRT__O_BINARY;
746 break;
749 if (MSVCRT__pipe(fds, 0, textmode) == -1)
750 return NULL;
752 fdToDup = readPipe ? 1 : 0;
753 fdToOpen = readPipe ? 0 : 1;
755 if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
756 goto error;
757 if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
758 goto error;
759 if (readPipe)
761 if ((fdStdErr = MSVCRT__dup(MSVCRT_STDERR_FILENO)) == -1)
762 goto error;
763 if (MSVCRT__dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
764 goto error;
767 MSVCRT__close(fds[fdToDup]);
769 comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
770 if (!comSpecLen)
771 comSpecLen = strlen(wcmd) + 1;
772 cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
773 + strlen(command));
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]);
781 ret = NULL;
783 else
785 ret = MSVCRT__fdopen(fds[fdToOpen], mode);
786 if (!ret)
787 MSVCRT__close(fds[fdToOpen]);
789 HeapFree(GetProcessHeap(), 0, cmdcopy);
790 MSVCRT__dup2(fdStdHandle, fdToDup);
791 MSVCRT__close(fdStdHandle);
792 if (readPipe)
794 MSVCRT__dup2(fdStdErr, MSVCRT_STDERR_FILENO);
795 MSVCRT__close(fdStdErr);
797 return ret;
799 error:
800 if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
801 if (fdStdErr != -1) MSVCRT__close(fdStdErr);
802 MSVCRT__close(fds[0]);
803 MSVCRT__close(fds[1]);
804 return NULL;
807 /*********************************************************************
808 * _wpopen (MSVCRT.@)
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));
813 return NULL;
816 /*********************************************************************
817 * _pclose (MSVCRT.@)
819 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
821 return MSVCRT_fclose(file);
824 /*********************************************************************
825 * system (MSVCRT.@)
827 int CDECL MSVCRT_system(const char* cmd)
829 char* cmdcopy;
830 int res;
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);
837 return res;
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))
854 return 0;
855 else
857 int err = GetLastError();
858 msvcrt_set_errno(err);
859 return err;
863 /*********************************************************************
864 * _getdllprocaddr (MSVCRT.@)
866 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
868 if (name)
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 );