License: LGPL Changelog: * dlls/msvcrt/msvcrt.spec, dlls/msvcrt/process.c: Jaco Greeff <jaco@puxedo.org> - Implemented the Unicode version of system, the _wsystem call
diff -aurN msvcrt-B06/dlls/msvcrt/msvcrt.spec msvcrt-B07/dlls/msvcrt/msvcrt.spec --- msvcrt-B06/dlls/msvcrt/msvcrt.spec Tue Nov 5 12:30:09 2002 +++ msvcrt-B07/dlls/msvcrt/msvcrt.spec Tue Nov 5 14:05:40 2002 @@ -556,7 +556,7 @@ @ stub _wstati64 #(wstr ptr) @ stub _wstrdate #(wstr) @ stub _wstrtime #(wstr) -@ stub _wsystem #(wstr) +@ cdecl _wsystem(wstr) @ cdecl _wtempnam(wstr wstr) _wtempnam @ stub _wtmpnam #(wstr) @ forward -noimport _wtoi NTDLL._wtoi diff -aurN msvcrt-B06/dlls/msvcrt/process.c msvcrt-B07/dlls/msvcrt/process.c --- msvcrt-B06/dlls/msvcrt/process.c Tue Nov 5 13:04:49 2002 +++ msvcrt-B07/dlls/msvcrt/process.c Tue Nov 5 14:33:22 2002 @@ -38,10 +38,18 @@ #include "msvcrt/stdlib.h" #include "msvcrt/string.h" +#include "wine/unicode.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); +/* ASCII and Unicode representations of the COMSPEC variable + * name. This is used to extract it from the environment + */ +static const char szCOMSPEC[] = "COMSPEC"; +static const WCHAR wszCOMSPEC[] = {'C','O','M','S','P','E','C', 0}; + /* FIXME: Check file extensions for app to run */ static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e'; static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't'; @@ -98,6 +106,63 @@ return -1; /* can't reach here */ } +/* INTERNAL: Spawn a child process using WCHAR arguments + * (This is a direct "port" of the msvcrt_spawn function + * to support Unicode strings) + */ +static int msvcrt_spawnW(int flags, const WCHAR* wszExe, WCHAR *wszCmdline, WCHAR *wszEnv) +{ + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + /* FIXME: this is not a problem at present, but might become + * so in the future when we move to 64 bit and support Win64 + * (The same comment applies to msvcrt_spawn) + */ + if (sizeof(HANDLE) != sizeof(int)) + WARN("This call is unsuitable for your architecture\n"); + + if ((unsigned)flags > _P_DETACH) + { + *MSVCRT__errno() = MSVCRT_EINVAL; + return -1; + } + + FIXME(":must dup/kill streams for child process\n"); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + if (!CreateProcessW(wszExe, wszCmdline, NULL, NULL, TRUE, + flags == _P_DETACH ? DETACHED_PROCESS : 0, + wszEnv, NULL, &si, &pi)) + { + MSVCRT__set_errno(GetLastError()); + return -1; + } + + switch(flags) + { + case _P_WAIT: + WaitForSingleObject(pi.hProcess,-1); /* wait forvever */ + GetExitCodeProcess(pi.hProcess,&pi.dwProcessId); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return (int)pi.dwProcessId; + case _P_DETACH: + CloseHandle(pi.hProcess); + pi.hProcess = 0; + /* fall through */ + case _P_NOWAIT: + case _P_NOWAITO: + CloseHandle(pi.hThread); + return (int)pi.hProcess; + case _P_OVERLAY: + MSVCRT__exit(0); + } + return -1; /* can't reach here */ +} + /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an * extra '\0' to terminate it */ @@ -450,9 +515,9 @@ * default command interpreter. If the interpreter is * not available, fail. */ - if (!GetEnvironmentVariableA("COMSPEC", szComspec, 1024)) + if (!GetEnvironmentVariableA(szCOMSPEC, szComspec, 1024)) { - TRACE("COMSPEC not available, _system call fails\n"); + TRACE("COMSPEC not available, system call fails\n"); return -1; } @@ -462,13 +527,53 @@ */ if (!(cmdcopy = (char *)MSVCRT_malloc(strlen(szComspec)+strlen(szExec)+strlen(cmd)+1))) { - TRACE("Unable to allocate memory for _system call\n"); + TRACE("Unable to allocate memory for system call\n"); return -1; } sprintf(cmdcopy, "%s%s%s", szComspec, szExec, cmd); res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL); MSVCRT_free(cmdcopy); + return res; +} + +/********************************************************************* + * _wsystem (MSVCRT.@) + */ +int MSVCRT__wsystem(const WCHAR* wszCmd) +{ + static const WCHAR wszExec[] = {' ','/','c',' ', 0}; + WCHAR wszComspec[1024+1]; + WCHAR* wszCmdcopy; + int res, nLen; + + /* Get the value of COMSPEC which should point to our + * default command interpreter. If the interpreter is + * not available, fail. + */ + if (!GetEnvironmentVariableW(wszCOMSPEC, wszComspec, 1024)) + { + TRACE("COMSPEC not available, _wsystem call fails\n"); + return -1; + } + + /* Allocate enough memory to hold the interpreter + command + * string and set it. When using the command interpreter in + * this way, it is executed as "comspec /c command" + */ + nLen = strlenW(wszComspec)+strlenW(wszExec)+strlenW(wszCmd); + if (!(wszCmdcopy = (WCHAR *)MSVCRT_malloc(nLen+1))) + { + TRACE("Unable to allocate memory for _wsystem call\n"); + return -1; + } + wszCmdcopy[0] = 0; + strcatW(wszCmdcopy, wszComspec); + strcatW(wszCmdcopy, wszExec); + strcatW(wszCmdcopy, wszCmd); + + res=msvcrt_spawnW(_P_WAIT, NULL, wszCmdcopy, NULL); + MSVCRT_free(wszCmdcopy); return res; }