update for HEAD-2002110701
[reactos.git] / lib / kernel32 / process / create.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/kernel32/process/create.c
6  * PURPOSE:         Process functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <windows.h>
16 #include <kernel32/proc.h>
17 #include <kernel32/thread.h>
18 #include <wchar.h>
19 #include <string.h>
20 #include <napi/i386/segment.h>
21 #include <ntdll/ldr.h>
22 #include <napi/teb.h>
23 #include <ntdll/base.h>
24 #include <ntdll/rtl.h>
25 #include <csrss/csrss.h>
26 #include <ntdll/csr.h>
27
28 #define NDEBUG
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
31
32 /* FUNCTIONS ****************************************************************/
33
34 WINBOOL STDCALL
35 CreateProcessA (LPCSTR                  lpApplicationName,
36                 LPSTR                   lpCommandLine,
37                 LPSECURITY_ATTRIBUTES   lpProcessAttributes,
38                 LPSECURITY_ATTRIBUTES   lpThreadAttributes,
39                 WINBOOL                 bInheritHandles,
40                 DWORD                   dwCreationFlags,
41                 LPVOID                  lpEnvironment,
42                 LPCSTR                  lpCurrentDirectory,
43                 LPSTARTUPINFOA          lpStartupInfo,
44                 LPPROCESS_INFORMATION   lpProcessInformation)
45 /*
46  * FUNCTION: The CreateProcess function creates a new process and its
47  * primary thread. The new process executes the specified executable file
48  * ARGUMENTS:
49  * 
50  *     lpApplicationName = Pointer to name of executable module
51  *     lpCommandLine = Pointer to command line string
52  *     lpProcessAttributes = Process security attributes
53  *     lpThreadAttributes = Thread security attributes
54  *     bInheritHandles = Handle inheritance flag
55  *     dwCreationFlags = Creation flags
56  *     lpEnvironment = Pointer to new environment block
57  *     lpCurrentDirectory = Pointer to current directory name
58  *     lpStartupInfo = Pointer to startup info
59  *     lpProcessInformation = Pointer to process information
60  */
61 {
62         PWCHAR lpEnvironmentW = NULL;
63         UNICODE_STRING ApplicationNameU;
64         UNICODE_STRING CurrentDirectoryU;
65         UNICODE_STRING CommandLineU;
66         ANSI_STRING ApplicationName;
67         ANSI_STRING CurrentDirectory;
68         ANSI_STRING CommandLine;
69         WINBOOL Result;
70         CHAR TempCurrentDirectoryA[256];
71
72         DPRINT("CreateProcessA(%s)\n", lpApplicationName);
73         DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
74                 "lpStartupInfo %x, lpProcessInformation %x\n", dwCreationFlags, 
75                 lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
76
77         if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
78         {
79                 PCHAR ptr = lpEnvironment;
80                 ULONG len = 0;
81                 UNICODE_STRING EnvironmentU;
82                 ANSI_STRING EnvironmentA;
83                 while (*ptr)
84                 {
85                         RtlInitAnsiString(&EnvironmentA, ptr);
86                         if (bIsFileApiAnsi)
87                                 len += RtlAnsiStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
88                         else
89                                 len += RtlOemStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
90                         ptr += EnvironmentA.MaximumLength;
91                 }
92                 len += sizeof(WCHAR);
93                 lpEnvironmentW = (PWCHAR)RtlAllocateHeap(GetProcessHeap(),
94                                                          HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, 
95                                                          len);
96                 if (lpEnvironmentW == NULL)
97                 {
98                         return FALSE;
99                 }
100                 ptr = lpEnvironment;
101                 EnvironmentU.Buffer = lpEnvironmentW;
102                 EnvironmentU.Length = 0;
103                 EnvironmentU.MaximumLength = len;
104                 while (*ptr)
105                 {
106                         RtlInitAnsiString(&EnvironmentA, ptr);
107                         if (bIsFileApiAnsi)
108                                 RtlAnsiStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
109                         else
110                                 RtlOemStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
111                         ptr += EnvironmentA.MaximumLength;
112                         EnvironmentU.Buffer += (EnvironmentU.Length / sizeof(WCHAR) + 1);
113                         EnvironmentU.MaximumLength -= (EnvironmentU.Length + sizeof(WCHAR));
114                         EnvironmentU.Length = 0;
115                 }
116
117                 EnvironmentU.Buffer[0] = 0;     
118         }
119     
120         RtlInitAnsiString (&CommandLine,
121                            lpCommandLine);
122         RtlInitAnsiString (&ApplicationName,
123                            (LPSTR)lpApplicationName);
124         if (lpCurrentDirectory != NULL)
125           {
126             RtlInitAnsiString (&CurrentDirectory,
127                                (LPSTR)lpCurrentDirectory);
128           }
129
130         /* convert ansi (or oem) strings to unicode */
131         if (bIsFileApiAnsi)
132         {
133                 RtlAnsiStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
134                 RtlAnsiStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
135                 if (lpCurrentDirectory != NULL)
136                         RtlAnsiStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
137         }
138         else
139         {
140                 RtlOemStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
141                 RtlOemStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
142                 if (lpCurrentDirectory != NULL)  
143                         RtlOemStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
144         }
145
146         Result = CreateProcessW (ApplicationNameU.Buffer,
147                                  CommandLineU.Buffer,
148                                  lpProcessAttributes,
149                                  lpThreadAttributes,
150                                  bInheritHandles,
151                                  dwCreationFlags,
152                                  dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : lpEnvironmentW,
153                                  (lpCurrentDirectory == NULL) ? NULL : CurrentDirectoryU.Buffer,
154                                  (LPSTARTUPINFOW)lpStartupInfo,
155                                  lpProcessInformation);
156
157         RtlFreeUnicodeString (&ApplicationNameU);
158         RtlFreeUnicodeString (&CommandLineU);
159         if (lpCurrentDirectory != NULL)
160                 RtlFreeUnicodeString (&CurrentDirectoryU);
161
162         if (lpEnvironmentW)
163         {
164                 RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW);
165         }
166
167         return Result;
168 }
169
170 struct _CONTEXT;
171 struct __EXCEPTION_RECORD;
172
173 static
174 EXCEPTION_DISPOSITION
175 __cdecl
176 _except_handler(
177     struct _EXCEPTION_RECORD *ExceptionRecord,
178     void * EstablisherFrame,
179     struct _CONTEXT *ContextRecord,
180     void * DispatcherContext )
181 {
182         DPRINT("Process terminated abnormally...\n");
183
184         if (/* FIXME: */ TRUE) /* Not a service */
185         {
186                 ExitProcess(0);
187         }
188         else
189         {
190                 ExitThread(0);
191         }
192
193         /* We should not get to here */
194         return ExceptionContinueSearch;
195 }
196
197 VOID STDCALL
198 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
199                  DWORD lpParameter)
200 {
201         UINT uExitCode = 0;
202
203         __try1(_except_handler)
204         {
205                 uExitCode = (lpStartAddress)((PVOID)lpParameter);
206         } __except1
207         {
208         }
209
210         ExitThread(uExitCode);
211 }
212
213
214 HANDLE STDCALL 
215 KlCreateFirstThread(HANDLE ProcessHandle,
216                     LPSECURITY_ATTRIBUTES lpThreadAttributes,
217                     ULONG StackReserve,
218                     ULONG StackCommit,
219                     LPTHREAD_START_ROUTINE lpStartAddress,
220                     DWORD dwCreationFlags,
221                     LPDWORD lpThreadId)
222 {
223   NTSTATUS Status;
224   HANDLE ThreadHandle;
225   OBJECT_ATTRIBUTES ObjectAttributes;
226   CLIENT_ID ClientId;
227   CONTEXT ThreadContext;
228   INITIAL_TEB InitialTeb;
229   BOOLEAN CreateSuspended = FALSE;
230   ULONG OldPageProtection;
231   ULONG ResultLength;
232   ULONG InitialStack[6];
233
234   ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
235   ObjectAttributes.RootDirectory = NULL;
236   ObjectAttributes.ObjectName = NULL;
237   ObjectAttributes.Attributes = 0;
238   if (lpThreadAttributes != NULL) 
239     {
240       if (lpThreadAttributes->bInheritHandle) 
241         ObjectAttributes.Attributes = OBJ_INHERIT;
242       ObjectAttributes.SecurityDescriptor = 
243         lpThreadAttributes->lpSecurityDescriptor;
244     }
245   ObjectAttributes.SecurityQualityOfService = NULL;
246
247   if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
248     CreateSuspended = TRUE;
249   else
250     CreateSuspended = FALSE;
251
252   InitialTeb.StackReserve = (StackReserve < 0x100000) ? 0x100000 : StackReserve;
253   /* FIXME: use correct commit size */
254 #if 0
255   InitialTeb.StackCommit = (StackCommit < PAGE_SIZE) ? PAGE_SIZE : StackCommit;
256 #endif
257   InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
258
259   /* size of guard page */
260   InitialTeb.StackCommit += PAGE_SIZE;
261
262   /* Reserve stack */
263   InitialTeb.StackAllocate = NULL;
264   Status = NtAllocateVirtualMemory(ProcessHandle,
265                                    &InitialTeb.StackAllocate,
266                                    0,
267                                    &InitialTeb.StackReserve,
268                                    MEM_RESERVE,
269                                    PAGE_READWRITE);
270   if (!NT_SUCCESS(Status))
271     {
272       DPRINT("Error reserving stack space!\n");
273       SetLastErrorByStatus(Status);
274       return(NULL);
275     }
276
277   DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
278          InitialTeb.StackAllocate, InitialTeb.StackReserve);
279
280   InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
281   InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
282
283   DPRINT("StackBase: %p StackCommit: %p\n",
284          InitialTeb.StackBase, InitialTeb.StackCommit);
285
286   /* Commit stack page(s) */
287   Status = NtAllocateVirtualMemory(ProcessHandle,
288                                    &InitialTeb.StackLimit,
289                                    0,
290                                    &InitialTeb.StackCommit,
291                                    MEM_COMMIT,
292                                    PAGE_READWRITE);
293   if (!NT_SUCCESS(Status))
294     {
295       /* release the stack space */
296       NtFreeVirtualMemory(ProcessHandle,
297                           InitialTeb.StackAllocate,
298                           &InitialTeb.StackReserve,
299                           MEM_RELEASE);
300
301       DPRINT("Error comitting stack page(s)!\n");
302       SetLastErrorByStatus(Status);
303       return(INVALID_HANDLE_VALUE);
304     }
305
306   DPRINT("StackLimit: %p\n",
307          InitialTeb.StackLimit);
308
309   /* Protect guard page */
310   Status = NtProtectVirtualMemory(ProcessHandle,
311                                   InitialTeb.StackLimit,
312                                   PAGE_SIZE,
313                                   PAGE_GUARD | PAGE_READWRITE,
314                                   &OldPageProtection);
315   if (!NT_SUCCESS(Status))
316     {
317       /* release the stack space */
318       NtFreeVirtualMemory(ProcessHandle,
319                           InitialTeb.StackAllocate,
320                           &InitialTeb.StackReserve,
321                           MEM_RELEASE);
322
323       DPRINT("Error comitting guard page!\n");
324       SetLastErrorByStatus(Status);
325       return(INVALID_HANDLE_VALUE);
326     }
327
328   memset(&ThreadContext,0,sizeof(CONTEXT));
329   ThreadContext.Eip = (ULONG)BaseProcessStart;
330   ThreadContext.SegGs = USER_DS;
331   ThreadContext.SegFs = USER_DS;
332   ThreadContext.SegEs = USER_DS;
333   ThreadContext.SegDs = USER_DS;
334   ThreadContext.SegCs = USER_CS;
335   ThreadContext.SegSs = USER_DS;
336   ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 6*4;
337   ThreadContext.EFlags = (1<<1) + (1<<9);
338
339   DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
340
341   /*
342    * Write in the initial stack.
343    */
344   InitialStack[0] = 0;
345   InitialStack[1] = (DWORD)lpStartAddress;
346   InitialStack[2] = PEB_BASE;
347
348   Status = ZwWriteVirtualMemory(ProcessHandle,
349                                 (PVOID)ThreadContext.Esp,
350                                 InitialStack,
351                                 sizeof(InitialStack),
352                                 &ResultLength);
353   if (!NT_SUCCESS(Status))
354     {
355       DPRINT1("Failed to write initial stack.\n");
356       return(INVALID_HANDLE_VALUE);
357     }
358
359   Status = NtCreateThread(&ThreadHandle,
360                           THREAD_ALL_ACCESS,
361                           &ObjectAttributes,
362                           ProcessHandle,
363                           &ClientId,
364                           &ThreadContext,
365                           &InitialTeb,
366                           CreateSuspended);
367   if (!NT_SUCCESS(Status))
368     {
369       NtFreeVirtualMemory(ProcessHandle,
370                           InitialTeb.StackAllocate,
371                           &InitialTeb.StackReserve,
372                           MEM_RELEASE);
373       SetLastErrorByStatus(Status);
374       return(INVALID_HANDLE_VALUE);
375     }
376
377   if (lpThreadId != NULL)
378     {
379       memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
380     }
381
382   return(ThreadHandle);
383 }
384
385 HANDLE 
386 KlMapFile(LPCWSTR lpApplicationName)
387 {
388    HANDLE hFile;
389    IO_STATUS_BLOCK IoStatusBlock;
390    UNICODE_STRING ApplicationNameString;
391    OBJECT_ATTRIBUTES ObjectAttributes;
392    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
393    NTSTATUS Status;
394    HANDLE hSection;
395
396    hFile = NULL;
397
398    /*
399     * Find the application name
400     */
401
402    if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
403                                       &ApplicationNameString,
404                                       NULL,
405                                       NULL))
406         return NULL;
407
408    DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
409
410    InitializeObjectAttributes(&ObjectAttributes,
411                               &ApplicationNameString,
412                               OBJ_CASE_INSENSITIVE,
413                               NULL,
414                               SecurityDescriptor);
415
416    /*
417     * Try to open the executable
418     */
419
420    Status = NtOpenFile(&hFile,
421                         SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
422                         &ObjectAttributes,
423                         &IoStatusBlock,
424                         FILE_SHARE_DELETE|FILE_SHARE_READ,
425                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
426
427    RtlFreeUnicodeString (&ApplicationNameString);
428
429    if (!NT_SUCCESS(Status))
430      {
431         DPRINT("Failed to open file\n");
432         SetLastErrorByStatus (Status);
433         return(NULL);
434      }
435
436    Status = NtCreateSection(&hSection,
437                             SECTION_ALL_ACCESS,
438                             NULL,
439                             NULL,
440                             PAGE_EXECUTE,
441                             SEC_IMAGE,
442                             hFile);
443    NtClose(hFile);
444
445    if (!NT_SUCCESS(Status))
446      {
447         DPRINT("Failed to create section\n");
448         SetLastErrorByStatus (Status);
449         return(NULL);
450      }
451
452    return(hSection);
453 }
454
455 static NTSTATUS 
456 KlInitPeb (HANDLE ProcessHandle,
457            PRTL_USER_PROCESS_PARAMETERS Ppb,
458            PVOID* ImageBaseAddress)
459 {
460    NTSTATUS Status;
461    PVOID PpbBase;
462    ULONG PpbSize;
463    ULONG BytesWritten;
464    ULONG Offset;
465    PVOID ParentEnv = NULL;
466    PVOID EnvPtr = NULL;
467    PWCHAR ptr;
468    ULONG EnvSize = 0, EnvSize1 = 0;
469
470    /* create the Environment */
471    if (Ppb->Environment != NULL)
472    {
473       ParentEnv = Ppb->Environment;
474       ptr = ParentEnv;
475       while (*ptr)
476       {
477           while(*ptr++);
478       }
479       ptr++;
480       EnvSize = (PVOID)ptr - ParentEnv;
481    }
482    else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
483    {
484       MEMORY_BASIC_INFORMATION MemInfo;
485       ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
486
487         Status = NtQueryVirtualMemory (NtCurrentProcess (),
488                                        ParentEnv,
489                                        MemoryBasicInformation,
490                                        &MemInfo,
491                                        sizeof(MEMORY_BASIC_INFORMATION),
492                                        NULL);
493         if (!NT_SUCCESS(Status))
494           {
495              return Status;
496           }
497         EnvSize = MemInfo.RegionSize;
498      }
499    DPRINT("EnvironmentSize %ld\n", EnvSize);
500
501    /* allocate and initialize new environment block */
502    if (EnvSize != 0)
503      {
504         EnvSize1 = EnvSize;
505         Status = NtAllocateVirtualMemory(ProcessHandle,
506                                          &EnvPtr,
507                                          0,
508                                          &EnvSize1,
509                                          MEM_RESERVE | MEM_COMMIT,
510                                          PAGE_READWRITE);
511         if (!NT_SUCCESS(Status))
512           {
513              return(Status);
514           }
515
516         NtWriteVirtualMemory(ProcessHandle,
517                              EnvPtr,
518                              ParentEnv,
519                              EnvSize,
520                              &BytesWritten);
521      }
522
523    /* create the PPB */
524    PpbBase = NULL;
525    PpbSize = Ppb->AllocationSize;
526    Status = NtAllocateVirtualMemory(ProcessHandle,
527                                     &PpbBase,
528                                     0,
529                                     &PpbSize,
530                                     MEM_RESERVE | MEM_COMMIT,
531                                     PAGE_READWRITE);
532    if (!NT_SUCCESS(Status))
533      {
534         return(Status);
535      }
536
537    DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
538    NtWriteVirtualMemory(ProcessHandle,
539                         PpbBase,
540                         Ppb,
541                         Ppb->AllocationSize,
542                         &BytesWritten);
543
544    /* write pointer to environment */
545    Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
546    NtWriteVirtualMemory(ProcessHandle,
547                         (PVOID)(PpbBase + Offset),
548                         &EnvPtr,
549                         sizeof(EnvPtr),
550                         &BytesWritten);
551
552    /* write pointer to process parameter block */
553    Offset = FIELD_OFFSET(PEB, ProcessParameters);
554    NtWriteVirtualMemory(ProcessHandle,
555                         (PVOID)(PEB_BASE + Offset),
556                         &PpbBase,
557                         sizeof(PpbBase),
558                         &BytesWritten);
559
560    /* Read image base address. */
561    Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
562    NtReadVirtualMemory(ProcessHandle,
563                        (PVOID)(PEB_BASE + Offset),
564                        ImageBaseAddress,
565                        sizeof(PVOID),
566                        &BytesWritten);
567
568    return(STATUS_SUCCESS);
569 }
570
571
572 WINBOOL STDCALL 
573 CreateProcessW(LPCWSTR lpApplicationName,
574                LPWSTR lpCommandLine,
575                LPSECURITY_ATTRIBUTES lpProcessAttributes,
576                LPSECURITY_ATTRIBUTES lpThreadAttributes,
577                WINBOOL bInheritHandles,
578                DWORD dwCreationFlags,
579                LPVOID lpEnvironment,
580                LPCWSTR lpCurrentDirectory,
581                LPSTARTUPINFOW lpStartupInfo,
582                LPPROCESS_INFORMATION lpProcessInformation)
583 {
584    HANDLE hSection, hProcess, hThread;
585    NTSTATUS Status;
586    LPTHREAD_START_ROUTINE  lpStartAddress = NULL;
587    WCHAR ImagePathName[256];
588    UNICODE_STRING ImagePathName_U;
589    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
590    ULONG retlen;
591    PRTL_USER_PROCESS_PARAMETERS Ppb;
592    UNICODE_STRING CommandLine_U;
593    CSRSS_API_REQUEST CsrRequest;
594    CSRSS_API_REPLY CsrReply;
595    CHAR ImageFileName[8];
596    PWCHAR s, e;
597    ULONG i, len;
598    ANSI_STRING ProcedureName;
599    UNICODE_STRING CurrentDirectory_U;
600    SECTION_IMAGE_INFORMATION Sii;
601    WCHAR TempCurrentDirectoryW[256];
602    WCHAR TempApplicationNameW[256];
603    WCHAR TempCommandLineNameW[256];
604    UNICODE_STRING RuntimeInfo_U;
605    PVOID ImageBaseAddress;
606
607    DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
608            lpApplicationName, lpCommandLine);
609
610    if (lpApplicationName != NULL && lpApplicationName[0] != 0)
611    {
612       wcscpy (TempApplicationNameW, lpApplicationName);
613       i = wcslen(TempApplicationNameW);
614       if (TempApplicationNameW[i - 1] == L'.')
615       {
616          TempApplicationNameW[i - 1] = 0;
617       }
618       else
619       {
620          s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
621          if (s == NULL)
622          {
623             s = TempApplicationNameW;
624          }
625          else
626          {
627             s++;
628          }
629          e = wcsrchr(s, L'.');
630          if (e == NULL)
631          {
632             wcscat(s, L".exe");
633             e = wcsrchr(s, L'.');
634          }
635       }
636    }
637    else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
638    {
639       if (lpCommandLine[0] == L'"')
640       {
641          wcscpy(TempApplicationNameW, &lpCommandLine[0]);
642          s = wcschr(TempApplicationNameW, L'"');
643          if (s == NULL)
644          {
645            return FALSE;
646          }
647          *s = 0;
648       }
649       else
650       {
651          wcscpy(TempApplicationNameW, lpCommandLine);
652          s = wcschr(TempApplicationNameW, L' ');
653          if (s != NULL)
654          {
655            *s = 0;
656          }
657       }
658       s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
659       if (s == NULL)
660       {
661          s = TempApplicationNameW;
662       }
663       s = wcsrchr(s, L'.');
664       if (s == NULL)
665          wcscat(TempApplicationNameW, L".exe");
666    }
667    else
668    {
669       return FALSE;
670    }
671
672    if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
673    {
674      return FALSE;
675    }
676
677    e = wcsrchr(s, L'.');
678    if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
679    {
680        // the command is a batch file
681        if (lpApplicationName != NULL && lpApplicationName[0])
682        {
683           // FIXME: use COMSPEC for the command interpreter
684           wcscpy(TempCommandLineNameW, L"cmd /c ");
685           wcscat(TempCommandLineNameW, lpApplicationName);
686           lpCommandLine = TempCommandLineNameW;
687           wcscpy(TempApplicationNameW, L"cmd.exe");
688           if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
689           {
690              return FALSE;
691           }
692        }
693        else
694        {
695           return FALSE;
696        }
697    }
698
699    /*
700     * Store the image file name for the process
701     */
702    e = wcschr(s, L'.');
703    if (e != NULL)
704      {
705         *e = 0;
706      }
707    for (i = 0; i < 8; i++)
708      {
709         ImageFileName[i] = (CHAR)(s[i]);
710      }
711    if (e != NULL)
712      {
713         *e = '.';
714      }
715    
716    /*
717     * Process the application name and command line
718     */
719    RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
720    RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
721
722    DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
723    DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
724
725    /* Initialize the current directory string */
726    if (lpCurrentDirectory != NULL)
727      {
728        RtlInitUnicodeString(&CurrentDirectory_U,
729                             lpCurrentDirectory);
730      }
731    else
732      {
733        GetCurrentDirectoryW(256, TempCurrentDirectoryW);
734        RtlInitUnicodeString(&CurrentDirectory_U,
735                             TempCurrentDirectoryW);
736      }
737
738    
739    /*
740     * Create a section for the executable
741     */
742    
743    hSection = KlMapFile (ImagePathName);
744    if (hSection == NULL)
745    {
746         return FALSE;
747    }
748    
749    /*
750     * Create a new process
751     */
752    Status = NtCreateProcess(&hProcess,
753                             PROCESS_ALL_ACCESS,
754                             NULL,
755                             NtCurrentProcess(),
756                             bInheritHandles,
757                             hSection,
758                             NULL,
759                             NULL);
760    if (lpStartupInfo)
761    {
762       if (lpStartupInfo->lpReserved2)
763       {
764          ULONG i, Count = *(ULONG*)lpStartupInfo->lpReserved2;
765          HANDLE * hFile;  
766          HANDLE hTemp;
767          PRTL_USER_PROCESS_PARAMETERS CurrPpb = NtCurrentPeb()->ProcessParameters;  
768
769
770          /* FIXME:
771           *    ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
772           *    the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
773           *    If is possible that this function overwrite the last information in runtimeinfo
774           *    with the null terminator for the unicode string.
775           */
776          RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
777          RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
778          memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
779       }
780    } 
781
782    /*
783     * Create the PPB
784     */
785    RtlCreateProcessParameters(&Ppb,
786                               &ImagePathName_U,
787                               NULL,
788                               lpCurrentDirectory ? &CurrentDirectory_U : NULL,
789                               &CommandLine_U,
790                               lpEnvironment,
791                               NULL,
792                               NULL,
793                               NULL,
794                               lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
795
796    if (lpStartupInfo && lpStartupInfo->lpReserved2)
797         RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
798   
799
800    /*
801     * Translate some handles for the new process
802     */
803    if (Ppb->CurrentDirectoryHandle)
804    {
805       Status = NtDuplicateObject (NtCurrentProcess(), 
806                          Ppb->CurrentDirectoryHandle,
807                          hProcess,
808                          &Ppb->CurrentDirectoryHandle,
809                          0,
810                          TRUE,
811                          DUPLICATE_SAME_ACCESS);
812    }
813
814    if (Ppb->hConsole)
815    {
816       Status = NtDuplicateObject (NtCurrentProcess(), 
817                          Ppb->hConsole,
818                          hProcess,
819                          &Ppb->hConsole,
820                          0,
821                          TRUE,
822                          DUPLICATE_SAME_ACCESS);
823    }
824
825    /*
826     * Get some information about the executable
827     */
828    Status = ZwQuerySection(hSection,
829                            SectionImageInformation,
830                            &Sii,
831                            sizeof(Sii),
832                            &i);
833    /*
834     * Close the section
835     */
836    NtClose(hSection);
837
838    /*
839     * Get some information about the process
840     */
841    ZwQueryInformationProcess(hProcess,
842                              ProcessBasicInformation,
843                              &ProcessBasicInfo,
844                              sizeof(ProcessBasicInfo),
845                              &retlen);
846    DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
847           ProcessBasicInfo.UniqueProcessId);
848    lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
849    
850    /*
851     * Tell the csrss server we are creating a new process
852     */
853    CsrRequest.Type = CSRSS_CREATE_PROCESS;
854    CsrRequest.Data.CreateProcessRequest.NewProcessId = 
855      ProcessBasicInfo.UniqueProcessId;
856    CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
857    Status = CsrClientCallServer(&CsrRequest, 
858                                 &CsrReply,
859                                 sizeof(CSRSS_API_REQUEST),
860                                 sizeof(CSRSS_API_REPLY));
861    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
862      {
863         DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
864      }
865
866    // Set the child console handles 
867    Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
868    Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
869    Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
870
871    if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
872    {
873       if (lpStartupInfo->hStdInput)
874          Ppb->hStdInput = lpStartupInfo->hStdInput;
875       if (lpStartupInfo->hStdOutput)
876          Ppb->hStdOutput = lpStartupInfo->hStdOutput;
877       if (lpStartupInfo->hStdError)
878          Ppb->hStdError = lpStartupInfo->hStdError;
879    }
880
881    if (IsConsoleHandle(Ppb->hStdInput))
882    {
883       Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
884    }
885    else
886    {
887       DPRINT("Duplicate input handle\n");
888       Status = NtDuplicateObject (NtCurrentProcess(), 
889                                   Ppb->hStdInput,
890                                   hProcess,
891                                   &Ppb->hStdInput,
892                                   0,
893                                   TRUE,
894                                   DUPLICATE_SAME_ACCESS);
895       if(!NT_SUCCESS(Status))
896       {
897          DPRINT("NtDuplicateObject failed, status %x\n", Status);
898       }
899    }
900
901    if (IsConsoleHandle(Ppb->hStdOutput))
902    {
903       Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
904    }
905    else
906    {
907       DPRINT("Duplicate output handle\n");
908       Status = NtDuplicateObject (NtCurrentProcess(), 
909                                   Ppb->hStdOutput,
910                                   hProcess,
911                                   &Ppb->hStdOutput,
912                                   0,
913                                   TRUE,
914                                   DUPLICATE_SAME_ACCESS);
915       if(!NT_SUCCESS(Status))
916       {
917          DPRINT("NtDuplicateObject failed, status %x\n", Status);
918       }
919    }
920    if (IsConsoleHandle(Ppb->hStdError))
921    {
922       Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
923    }
924    else
925    {
926       DPRINT("Duplicate error handle\n");
927       Status = NtDuplicateObject (NtCurrentProcess(), 
928                                   Ppb->hStdError,
929                                   hProcess,
930                                   &Ppb->hStdError,
931                                   0,
932                                   TRUE,
933                                   DUPLICATE_SAME_ACCESS);
934       if(!NT_SUCCESS(Status))
935       {
936          DPRINT("NtDuplicateObject failed, status %x\n", Status);
937       }
938    }
939
940    /*
941     * Initialize some other fields in the PPB
942     */
943    if (lpStartupInfo)
944      {
945        Ppb->dwFlags = lpStartupInfo->dwFlags;
946        if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
947          {
948            Ppb->wShowWindow = lpStartupInfo->wShowWindow;
949          }
950        else
951          {
952            Ppb->wShowWindow = SW_SHOWDEFAULT;
953          }
954        Ppb->dwX = lpStartupInfo->dwX;
955        Ppb->dwY = lpStartupInfo->dwY;
956        Ppb->dwXSize = lpStartupInfo->dwXSize;
957        Ppb->dwYSize = lpStartupInfo->dwYSize;
958        Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
959      }
960    else
961      {
962        Ppb->Flags = 0;
963      }
964    
965    /*
966     * Create Process Environment Block
967     */
968    DPRINT("Creating peb\n");
969
970    KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
971
972    RtlDestroyProcessParameters (Ppb);
973
974    Status = NtSetInformationProcess(hProcess,
975                                     ProcessImageFileName,
976                                     ImageFileName,
977                                     8);
978    /*
979     * Create the thread for the kernel
980     */
981    DPRINT("Creating thread for process\n");
982    hThread =  KlCreateFirstThread(hProcess,
983                                   lpThreadAttributes,
984                                   Sii.StackReserve,
985                                   Sii.StackCommit,
986                                   ImageBaseAddress + (ULONG)Sii.EntryPoint,
987                                   dwCreationFlags,
988                                   &lpProcessInformation->dwThreadId);
989    if (hThread == INVALID_HANDLE_VALUE)
990      {
991         return FALSE;
992      }
993
994    lpProcessInformation->hProcess = hProcess;
995    lpProcessInformation->hThread = hThread;
996
997    return TRUE;
998 }
999
1000 /* EOF */