Added a first-cut version of MapVirtualKeyExW() that has the same
[wine] / dlls / crtdll / spawn.c
1 /*
2  * CRTDLL spawn functions
3  * 
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  *
9  * These functions differ in whether they pass arguments as an array
10  * (v in the name) or as varags (l in the name), whether they
11  * seach the path (p in the name) and/or whether they take an
12  * environment (e in the name) or pass the parents environment.
13  *                  Args as   Search   Take
14  * Name             varargs?  path?    environment?
15  * spawnl              N         N        N
16  * spawnle             N         N        Y
17  * spawnlp             N         Y        N
18  * spawnlpe            N         Y        Y
19  * spawnv              Y         N        N
20  * spawnve             Y         N        Y
21  * spawnvp             Y         Y        N
22  * spawnvpe            Y         Y        Y
23  *
24  * Implementation Notes:
25  * MT Safe - But only because of missing functionality.
26  * 
27  * After translating input arguments into the required format for
28  * CreateProcess(), the internal function __CRTDLL__spawn() is
29  * called to perform the actual spawning.
30  *
31  * FIXME:
32  * -File handles need some special handling. Sometimes children get
33  *  open file handles, sometimes not. The docs are confusing.
34  * -No check for maximum path/argument/environment size is done.
35  * -Wine has a "process.h" which is not the same as any crt version.
36  * Unresolved issues Uwe Bonnes 970904:
37  * -system-call calls another wine process, but without debugging arguments
38  *  and uses the first wine executable in the path
39  */
40
41 #include "crtdll.h"
42 #include <errno.h>
43 #include "process.h"
44 #include <stdlib.h>
45
46
47 DEFAULT_DEBUG_CHANNEL(crtdll);
48
49 /* Process creation flags */
50 #define _P_WAIT    0
51 #define _P_NOWAIT  1
52 #define _P_OVERLAY 2
53 #define _P_NOWAITO 3
54 #define _P_DETACH  4
55
56
57 extern void __CRTDLL__set_errno(ULONG err);
58 extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count);
59 extern VOID __cdecl CRTDLL_free(void *ptr);
60 extern VOID __cdecl CRTDLL__exit(LONG ret);
61 extern INT CRTDLL_doserrno;
62
63
64 /* INTERNAL: Spawn a child process */
65 static int __CRTDLL__spawn(INT flags, LPSTR exe, LPSTR args, LPSTR env);
66 static int __CRTDLL__spawn(INT flags, LPSTR exe, LPSTR args, LPSTR env)
67 {
68   STARTUPINFOA si;
69   PROCESS_INFORMATION pi;
70
71   if ((unsigned)flags > _P_DETACH)
72   {
73     CRTDLL_errno = EINVAL;
74     return -1;
75   }
76
77   FIXME(":must dup/kill streams for child process\n");
78
79   memset(&si, 0, sizeof(si));
80   si.cb = sizeof(si);
81
82   if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
83                       flags == _P_DETACH ? DETACHED_PROCESS : 0,
84                       env, NULL, &si, &pi))
85   {
86     __CRTDLL__set_errno(GetLastError());
87     return -1;
88   }
89
90   switch(flags)
91   {
92   case _P_WAIT:
93     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
94     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
95     CloseHandle(pi.hProcess);
96     CloseHandle(pi.hThread);
97     return pi.dwProcessId;
98   case _P_DETACH:
99     CloseHandle(pi.hProcess);
100     pi.hProcess = 0;
101     /* fall through */
102   case _P_NOWAIT:
103   case _P_NOWAITO:
104     CloseHandle(pi.hThread);
105     return pi.hProcess;
106   case  _P_OVERLAY:
107     CRTDLL__exit(0);
108   }
109   return -1; /* cant reach here */
110 }
111
112
113 /* INTERNAL: Convert argv list to a single 'delim'-seperated string */
114 static LPSTR __CRTDLL__argvtos(LPSTR *arg, CHAR delim);
115 static LPSTR __CRTDLL__argvtos(LPSTR *arg, CHAR delim)
116 {
117   LPSTR *search = arg;
118   LONG size = 0;
119   LPSTR ret;
120
121   if (!arg && !delim)
122     return NULL;
123
124   /* get length */
125   while(*search)
126   {
127     size += strlen(*search) + 1;
128     search++;
129   }
130
131   if (!(ret = (LPSTR)CRTDLL_calloc(size + 1, 1)))
132     return NULL;
133
134   /* fill string */
135   search = arg;
136   size = 0;
137   while(*search)
138   {
139     int strsize = strlen(*search);
140     memcpy(ret+size,*search,strsize);
141     ret[size+strsize] = delim;
142     size += strsize + 1;
143     search++;
144   }
145   return ret;
146 }
147
148
149 /*********************************************************************
150  *                  _spawnve    (CRTDLL.274)
151  *
152  * Spawn a process.
153  *
154  */
155 HANDLE __cdecl CRTDLL__spawnve(INT flags, LPSTR name, LPSTR *argv, LPSTR *envv)
156 {
157   LPSTR args = __CRTDLL__argvtos(argv,' ');
158   LPSTR envs = __CRTDLL__argvtos(envv,0);
159   LPSTR fullname = name;
160
161   FIXME(":not translating name %s to locate program\n",fullname);
162   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
163
164   if (args)
165   {
166     HANDLE ret = __CRTDLL__spawn(flags, fullname, args, envs);
167     CRTDLL_free(args);
168     CRTDLL_free(envs);
169     return ret;
170   }
171   if (envs)
172     CRTDLL_free(envs);
173
174   WARN(":No argv[0] passed - process will not be executed");
175   return -1;
176 }
177
178
179 /*********************************************************************
180  *                  system       (CRTDLL.485)
181  */
182 INT __cdecl CRTDLL_system(LPSTR x)
183 {
184     /* FIXME: should probably launch cmd interpreter in COMSPEC */
185     return __CRTDLL__spawn(_P_WAIT, NULL, x, NULL);
186 }