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