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