Use DrawFrameControl instead of bitmaps in certain cases.
[wine] / dlls / msvcrt / process.c
1 /*
2  * msvcrt.dll spawn/exec 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  * FIXME:
10  * -File handles need some special handling. Sometimes children get
11  *  open file handles, sometimes not. The docs are confusing
12  * -No check for maximum path/argument/environment size is done
13  */
14 #include "msvcrt.h"
15 #include "ms_errno.h"
16
17 #include "msvcrt/process.h"
18 #include "msvcrt/stdlib.h"
19 #include "msvcrt/string.h"
20
21 DEFAULT_DEBUG_CHANNEL(msvcrt);
22
23 /* FIXME: Check file extensions for app to run */
24 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
25 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
26 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
27 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
28
29 /* INTERNAL: Spawn a child process */
30 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
31 {
32   STARTUPINFOA si;
33   PROCESS_INFORMATION pi;
34
35   if (sizeof(HANDLE) != sizeof(int))
36     WARN("This call is unsuitable for your architecture\n");
37
38   if ((unsigned)flags > _P_DETACH)
39   {
40     SET_THREAD_VAR(errno,MSVCRT_EINVAL);
41     return -1;
42   }
43
44   FIXME(":must dup/kill streams for child process\n");
45
46   memset(&si, 0, sizeof(si));
47   si.cb = sizeof(si);
48
49   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
50                      flags == _P_DETACH ? DETACHED_PROCESS : 0,
51                      env, NULL, &si, &pi))
52   {
53     MSVCRT__set_errno(GetLastError());
54     return -1;
55   }
56
57   switch(flags)
58   {
59   case _P_WAIT:
60     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
61     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
62     CloseHandle(pi.hProcess);
63     CloseHandle(pi.hThread);
64     return (int)pi.dwProcessId;
65   case _P_DETACH:
66     CloseHandle(pi.hProcess);
67     pi.hProcess = 0;
68     /* fall through */
69   case _P_NOWAIT:
70   case _P_NOWAITO:
71     CloseHandle(pi.hThread);
72     return (int)pi.hProcess;
73   case  _P_OVERLAY:
74     MSVCRT__exit(0);
75   }
76   return -1; /* can't reach here */
77 }
78
79 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
80  * extra '\0' to terminate it
81  */
82 static char* msvcrt_argvtos(const char* const* arg, char delim)
83 {
84   const char* const* a;
85   long size;
86   char* p;
87   char* ret;
88
89   if (!arg && !delim)
90   {
91       /* Return NULL for an empty environment list */
92       return NULL;
93   }
94
95   /* get length */
96   a = arg;
97   size = 0;
98   while (*a)
99   {
100     size += strlen(*a) + 1;
101     a++;
102   }
103
104   ret = (char*)MSVCRT_malloc(size + 1);
105   if (!ret)
106     return NULL;
107
108   /* fill string */
109   a = arg;
110   p = ret;
111   while (*a)
112   {
113     int len = strlen(*a);
114     memcpy(ret+size,*a,len);
115     p += len;
116     *p++ = delim;
117     a++;
118   }
119   *p='\0';
120   return ret;
121 }
122
123 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
124  * extra '\0' to terminate it
125  */
126 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
127 {
128   va_list alist2 = alist;
129   long size;
130   const char *arg;
131   char* p;
132   char *ret;
133
134   if (!arg0 && !delim)
135   {
136       /* Return NULL for an empty environment list */
137       return NULL;
138   }
139
140   /* get length */
141   arg = arg0;
142   size = 0;
143   do {
144       size += strlen(arg) + 1;
145       arg = va_arg(alist, char*);
146   } while (arg != NULL);
147
148   ret = (char*)MSVCRT_malloc(size + 1);
149   if (!ret)
150     return NULL;
151
152   /* fill string */
153   arg = arg0;
154   p = ret;
155   do {
156       int len = strlen(arg);
157       memcpy(p,arg,len);
158       p += len;
159       *p++ = delim;
160       arg = va_arg(alist2, char*);
161   } while (arg != NULL);
162   *p = '\0';
163   return ret;
164 }
165
166 /*********************************************************************
167  *              _cwait (MSVCRT.@)
168  */
169 int _cwait(int *status, int pid, int action)
170 {
171   HANDLE hPid = (HANDLE)pid;
172   int doserrno;
173
174   action = action; /* Remove warning */
175
176   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
177   {
178     if (status)
179     {
180       DWORD stat;
181       GetExitCodeProcess(hPid, &stat);
182       *status = (int)stat;
183     }
184     return (int)pid;
185   }
186   doserrno = GetLastError();
187
188   if (doserrno == ERROR_INVALID_HANDLE)
189   {
190     SET_THREAD_VAR(errno, MSVCRT_ECHILD);
191     SET_THREAD_VAR(doserrno,doserrno);
192   }
193   else
194     MSVCRT__set_errno(doserrno);
195
196   return status ? *status = -1 : -1;
197 }
198
199 /*********************************************************************
200  *              _execl (MSVCRT.@)
201  *
202  * Like on Windows, this function does not handle arguments with spaces 
203  * or double-quotes.
204  */
205 int _execl(const char* name, const char* arg0, ...)
206 {
207   va_list ap;
208   char * args;
209   int ret;
210
211   va_start(ap, arg0);
212   args = msvcrt_valisttos(arg0, ap, ' ');
213   va_end(ap);
214
215   ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
216   MSVCRT_free(args);
217
218   return ret;
219 }
220
221 /*********************************************************************
222  *              _execlp (MSVCRT.@)
223  *
224  * Like on Windows, this function does not handle arguments with spaces 
225  * or double-quotes.
226  */
227 int _execlp(const char* name, const char* arg0, ...)
228 {
229   va_list ap;
230   char * args;
231   int ret;
232   char fullname[MAX_PATH];
233
234   _searchenv(name, "PATH", fullname);
235
236   va_start(ap, arg0);
237   args = msvcrt_valisttos(arg0, ap, ' ');
238   va_end(ap);
239
240   ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
241   MSVCRT_free(args);
242
243   return ret;
244 }
245
246 /*********************************************************************
247  *              _execv (MSVCRT.@)
248  *
249  * Like on Windows, this function does not handle arguments with spaces 
250  * or double-quotes.
251  */
252 int _execv(const char* name, char* const* argv)
253 {
254   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
255 }
256
257 /*********************************************************************
258  *              _execve (MSVCRT.@)
259  *
260  * Like on Windows, this function does not handle arguments with spaces 
261  * or double-quotes.
262  */
263 int _execve(const char* name, char* const* argv, const char* const* envv)
264 {
265   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
266 }
267
268 /*********************************************************************
269  *              _execvpe (MSVCRT.@)
270  *
271  * Like on Windows, this function does not handle arguments with spaces 
272  * or double-quotes.
273  */
274 int _execvpe(const char* name, char* const* argv, const char* const* envv)
275 {
276   char fullname[MAX_PATH];
277
278   _searchenv(name, "PATH", fullname);
279   return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
280                   (const char* const*) argv, envv);
281 }
282
283 /*********************************************************************
284  *              _execvp (MSVCRT.@)
285  *
286  * Like on Windows, this function does not handle arguments with spaces 
287  * or double-quotes.
288  */
289 int _execvp(const char* name, char* const* argv)
290 {
291   return _execvpe(name, argv, NULL);
292 }
293
294 /*********************************************************************
295  *              _spawnl (MSVCRT.@)
296  *
297  * Like on Windows, this function does not handle arguments with spaces 
298  * or double-quotes.
299  */
300 int _spawnl(int flags, const char* name, const char* arg0, ...)
301 {
302   va_list ap;
303   char * args;
304   int ret;
305
306   va_start(ap, arg0);
307   args = msvcrt_valisttos(arg0, ap, ' ');
308   va_end(ap);
309
310   ret = msvcrt_spawn(flags, name, args, NULL);
311   MSVCRT_free(args);
312
313   return ret;
314 }
315
316 /*********************************************************************
317  *              _spawnlp (MSVCRT.@)
318  *
319  * Like on Windows, this function does not handle arguments with spaces 
320  * or double-quotes.
321  */
322 int _spawnlp(int flags, const char* name, const char* arg0, ...)
323 {
324   va_list ap;
325   char * args;
326   int ret;
327   char fullname[MAX_PATH];
328
329   _searchenv(name, "PATH", fullname);
330
331   va_start(ap, arg0);
332   args = msvcrt_valisttos(arg0, ap, ' ');
333   va_end(ap);
334
335   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
336   MSVCRT_free(args);
337
338   return ret;
339 }
340
341 /*********************************************************************
342  *              _spawnve (MSVCRT.@)
343  *
344  * Like on Windows, this function does not handle arguments with spaces 
345  * or double-quotes.
346  */
347 int _spawnve(int flags, const char* name, const char* const* argv,
348                             const char* const* envv)
349 {
350   char * args = msvcrt_argvtos(argv,' ');
351   char * envs = msvcrt_argvtos(envv,0);
352   const char *fullname = name;
353   int ret = -1;
354
355   FIXME(":not translating name %s to locate program\n",fullname);
356   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
357
358   if (args)
359   {
360     ret = msvcrt_spawn(flags, fullname, args, envs);
361     MSVCRT_free(args);
362   }
363   if (envs)
364     MSVCRT_free(envs);
365
366   return ret;
367 }
368
369 /*********************************************************************
370  *              _spawnv (MSVCRT.@)
371  *
372  * Like on Windows, this function does not handle arguments with spaces 
373  * or double-quotes.
374  */
375 int _spawnv(int flags, const char* name, const char* const* argv)
376 {
377   return _spawnve(flags, name, argv, NULL);
378 }
379
380 /*********************************************************************
381  *              _spawnvpe (MSVCRT.@)
382  *
383  * Like on Windows, this function does not handle arguments with spaces 
384  * or double-quotes.
385  */
386 int _spawnvpe(int flags, const char* name, const char* const* argv,
387                             const char* const* envv)
388 {
389   char fullname[MAX_PATH];
390   _searchenv(name, "PATH", fullname);
391   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
392 }
393
394 /*********************************************************************
395  *              _spawnvp (MSVCRT.@)
396  *
397  * Like on Windows, this function does not handle arguments with spaces 
398  * or double-quotes.
399  */
400 int _spawnvp(int flags, const char* name, const char* const* argv)
401 {
402   return _spawnvpe(flags, name, argv, NULL);
403 }
404
405 /*********************************************************************
406  *              system (MSVCRT.@)
407  */
408 int MSVCRT_system(const char* cmd)
409 {
410     char* cmdcopy;
411     int res;
412
413     /* Make a writable copy for CreateProcess */
414     cmdcopy=_strdup(cmd);
415     /* FIXME: should probably launch cmd interpreter in COMSPEC */
416     res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
417     MSVCRT_free(cmdcopy);
418     return res;
419 }
420
421 /*********************************************************************
422  *              _loaddll (MSVCRT.@)
423  */
424 int _loaddll(const char* dllname)
425 {
426   return LoadLibraryA(dllname);
427 }
428
429 /*********************************************************************
430  *              _unloaddll (MSVCRT.@)
431  */
432 int _unloaddll(int dll)
433 {
434   if (FreeLibrary((HANDLE)dll))
435     return 0;
436   else
437   {
438     int err = GetLastError();
439     MSVCRT__set_errno(err);
440     return err;
441   }
442 }
443