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