1 /* $Id: create.c,v 1.61 2003/01/22 02:24:10 ekohl Exp $
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)
12 /* INCLUDES ****************************************************************/
17 #include <kernel32/kernel32.h>
19 /* FUNCTIONS ****************************************************************/
22 CreateProcessA (LPCSTR lpApplicationName
,
24 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
25 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
26 WINBOOL bInheritHandles
,
27 DWORD dwCreationFlags
,
29 LPCSTR lpCurrentDirectory
,
30 LPSTARTUPINFOA lpStartupInfo
,
31 LPPROCESS_INFORMATION lpProcessInformation
)
33 * FUNCTION: The CreateProcess function creates a new process and its
34 * primary thread. The new process executes the specified executable file
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
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
;
57 CHAR TempCurrentDirectoryA
[256];
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
);
64 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
66 PCHAR ptr
= lpEnvironment
;
68 UNICODE_STRING EnvironmentU
;
69 ANSI_STRING EnvironmentA
;
72 RtlInitAnsiString(&EnvironmentA
, ptr
);
74 len
+= RtlAnsiStringToUnicodeSize(&EnvironmentA
) + sizeof(WCHAR
);
76 len
+= RtlOemStringToUnicodeSize(&EnvironmentA
) + sizeof(WCHAR
);
77 ptr
+= EnvironmentA
.MaximumLength
;
80 lpEnvironmentW
= (PWCHAR
)RtlAllocateHeap(GetProcessHeap(),
81 HEAP_GENERATE_EXCEPTIONS
|HEAP_ZERO_MEMORY
,
83 if (lpEnvironmentW
== NULL
)
88 EnvironmentU
.Buffer
= lpEnvironmentW
;
89 EnvironmentU
.Length
= 0;
90 EnvironmentU
.MaximumLength
= len
;
93 RtlInitAnsiString(&EnvironmentA
, ptr
);
95 RtlAnsiStringToUnicodeString(&EnvironmentU
, &EnvironmentA
, FALSE
);
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;
104 EnvironmentU
.Buffer
[0] = 0;
107 RtlInitAnsiString (&CommandLine
,
109 RtlInitAnsiString (&ApplicationName
,
110 (LPSTR
)lpApplicationName
);
111 if (lpCurrentDirectory
!= NULL
)
113 RtlInitAnsiString (&CurrentDirectory
,
114 (LPSTR
)lpCurrentDirectory
);
117 /* convert ansi (or oem) strings to unicode */
120 RtlAnsiStringToUnicodeString (&CommandLineU
, &CommandLine
, TRUE
);
121 RtlAnsiStringToUnicodeString (&ApplicationNameU
, &ApplicationName
, TRUE
);
122 if (lpCurrentDirectory
!= NULL
)
123 RtlAnsiStringToUnicodeString (&CurrentDirectoryU
, &CurrentDirectory
, TRUE
);
127 RtlOemStringToUnicodeString (&CommandLineU
, &CommandLine
, TRUE
);
128 RtlOemStringToUnicodeString (&ApplicationNameU
, &ApplicationName
, TRUE
);
129 if (lpCurrentDirectory
!= NULL
)
130 RtlOemStringToUnicodeString (&CurrentDirectoryU
, &CurrentDirectory
, TRUE
);
133 Result
= CreateProcessW (ApplicationNameU
.Buffer
,
139 dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
? lpEnvironment
: lpEnvironmentW
,
140 (lpCurrentDirectory
== NULL
) ? NULL
: CurrentDirectoryU
.Buffer
,
141 (LPSTARTUPINFOW
)lpStartupInfo
,
142 lpProcessInformation
);
144 RtlFreeUnicodeString (&ApplicationNameU
);
145 RtlFreeUnicodeString (&CommandLineU
);
146 if (lpCurrentDirectory
!= NULL
)
147 RtlFreeUnicodeString (&CurrentDirectoryU
);
151 RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW
);
157 static int _except_recursion_trap
= 0;
160 struct __EXCEPTION_RECORD
;
163 EXCEPTION_DISPOSITION
166 struct _EXCEPTION_RECORD
*ExceptionRecord
,
167 void * EstablisherFrame
,
168 struct _CONTEXT
*ContextRecord
,
169 void * DispatcherContext
)
171 DPRINT("Process terminated abnormally...\n");
173 if (++_except_recursion_trap
> 3) {
174 DPRINT("_except_handler(...) appears to be recursing.\n");
175 DPRINT("Process HALTED.\n");
179 if (/* FIXME: */ TRUE
) /* Not a service */
181 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
187 DPRINT(" calling ExitThread(0) . . .\n");
191 DPRINT(" We should not get to here !!!\n");
192 /* We should not get to here */
193 return ExceptionContinueSearch
;
197 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
202 DPRINT("\nBaseProcessStart(..) - setting up exception frame.\n\n");
204 __try1(_except_handler
)
206 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
211 DPRINT("\nBaseProcessStart(..) - cleaned up exception frame.\n\n");
213 ExitThread(uExitCode
);
218 KlCreateFirstThread(HANDLE ProcessHandle
,
219 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
222 LPTHREAD_START_ROUTINE lpStartAddress
,
223 DWORD dwCreationFlags
,
228 OBJECT_ATTRIBUTES ObjectAttributes
;
230 CONTEXT ThreadContext
;
231 INITIAL_TEB InitialTeb
;
232 BOOLEAN CreateSuspended
= FALSE
;
233 ULONG OldPageProtection
;
235 ULONG InitialStack
[6];
237 ObjectAttributes
.Length
= sizeof(OBJECT_ATTRIBUTES
);
238 ObjectAttributes
.RootDirectory
= NULL
;
239 ObjectAttributes
.ObjectName
= NULL
;
240 ObjectAttributes
.Attributes
= 0;
241 if (lpThreadAttributes
!= NULL
)
243 if (lpThreadAttributes
->bInheritHandle
)
244 ObjectAttributes
.Attributes
= OBJ_INHERIT
;
245 ObjectAttributes
.SecurityDescriptor
=
246 lpThreadAttributes
->lpSecurityDescriptor
;
248 ObjectAttributes
.SecurityQualityOfService
= NULL
;
250 if ((dwCreationFlags
& CREATE_SUSPENDED
) == CREATE_SUSPENDED
)
251 CreateSuspended
= TRUE
;
253 CreateSuspended
= FALSE
;
255 InitialTeb
.StackReserve
= (StackReserve
< 0x100000) ? 0x100000 : StackReserve
;
256 /* FIXME: use correct commit size */
258 InitialTeb
.StackCommit
= (StackCommit
< PAGE_SIZE
) ? PAGE_SIZE
: StackCommit
;
260 InitialTeb
.StackCommit
= InitialTeb
.StackReserve
- PAGE_SIZE
;
262 /* size of guard page */
263 InitialTeb
.StackCommit
+= PAGE_SIZE
;
266 InitialTeb
.StackAllocate
= NULL
;
267 Status
= NtAllocateVirtualMemory(ProcessHandle
,
268 &InitialTeb
.StackAllocate
,
270 &InitialTeb
.StackReserve
,
273 if (!NT_SUCCESS(Status
))
275 DPRINT("Error reserving stack space!\n");
276 SetLastErrorByStatus(Status
);
280 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
281 InitialTeb
.StackAllocate
, InitialTeb
.StackReserve
);
283 InitialTeb
.StackBase
= (PVOID
)((ULONG
)InitialTeb
.StackAllocate
+ InitialTeb
.StackReserve
);
284 InitialTeb
.StackLimit
= (PVOID
)((ULONG
)InitialTeb
.StackBase
- InitialTeb
.StackCommit
);
286 DPRINT("StackBase: %p StackCommit: %p\n",
287 InitialTeb
.StackBase
, InitialTeb
.StackCommit
);
289 /* Commit stack page(s) */
290 Status
= NtAllocateVirtualMemory(ProcessHandle
,
291 &InitialTeb
.StackLimit
,
293 &InitialTeb
.StackCommit
,
296 if (!NT_SUCCESS(Status
))
298 /* release the stack space */
299 NtFreeVirtualMemory(ProcessHandle
,
300 InitialTeb
.StackAllocate
,
301 &InitialTeb
.StackReserve
,
304 DPRINT("Error comitting stack page(s)!\n");
305 SetLastErrorByStatus(Status
);
306 return(INVALID_HANDLE_VALUE
);
309 DPRINT("StackLimit: %p\n",
310 InitialTeb
.StackLimit
);
312 /* Protect guard page */
313 Status
= NtProtectVirtualMemory(ProcessHandle
,
314 InitialTeb
.StackLimit
,
316 PAGE_GUARD
| PAGE_READWRITE
,
318 if (!NT_SUCCESS(Status
))
320 /* release the stack space */
321 NtFreeVirtualMemory(ProcessHandle
,
322 InitialTeb
.StackAllocate
,
323 &InitialTeb
.StackReserve
,
326 DPRINT("Error comitting guard page!\n");
327 SetLastErrorByStatus(Status
);
328 return(INVALID_HANDLE_VALUE
);
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);
342 DPRINT("ThreadContext.Eip %x\n",ThreadContext
.Eip
);
345 * Write in the initial stack.
348 InitialStack
[1] = (DWORD
)lpStartAddress
;
349 InitialStack
[2] = PEB_BASE
;
351 Status
= ZwWriteVirtualMemory(ProcessHandle
,
352 (PVOID
)ThreadContext
.Esp
,
354 sizeof(InitialStack
),
356 if (!NT_SUCCESS(Status
))
358 DPRINT1("Failed to write initial stack.\n");
359 return(INVALID_HANDLE_VALUE
);
362 Status
= NtCreateThread(&ThreadHandle
,
370 if (!NT_SUCCESS(Status
))
372 NtFreeVirtualMemory(ProcessHandle
,
373 InitialTeb
.StackAllocate
,
374 &InitialTeb
.StackReserve
,
376 SetLastErrorByStatus(Status
);
377 return(INVALID_HANDLE_VALUE
);
380 if (lpThreadId
!= NULL
)
382 memcpy(lpThreadId
, &ClientId
.UniqueThread
,sizeof(ULONG
));
385 return(ThreadHandle
);
389 KlMapFile(LPCWSTR lpApplicationName
)
392 IO_STATUS_BLOCK IoStatusBlock
;
393 UNICODE_STRING ApplicationNameString
;
394 OBJECT_ATTRIBUTES ObjectAttributes
;
395 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
402 * Find the application name
405 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
406 &ApplicationNameString
,
411 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
413 InitializeObjectAttributes(&ObjectAttributes
,
414 &ApplicationNameString
,
415 OBJ_CASE_INSENSITIVE
,
420 * Try to open the executable
423 Status
= NtOpenFile(&hFile
,
424 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
427 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
428 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
430 RtlFreeUnicodeString (&ApplicationNameString
);
432 if (!NT_SUCCESS(Status
))
434 DPRINT("Failed to open file\n");
435 SetLastErrorByStatus (Status
);
439 Status
= NtCreateSection(&hSection
,
448 if (!NT_SUCCESS(Status
))
450 DPRINT("Failed to create section\n");
451 SetLastErrorByStatus (Status
);
459 KlInitPeb (HANDLE ProcessHandle
,
460 PRTL_USER_PROCESS_PARAMETERS Ppb
,
461 PVOID
* ImageBaseAddress
)
468 PVOID ParentEnv
= NULL
;
471 ULONG EnvSize
= 0, EnvSize1
= 0;
473 /* create the Environment */
474 if (Ppb
->Environment
!= NULL
)
476 ParentEnv
= Ppb
->Environment
;
483 EnvSize
= (PVOID
)ptr
- ParentEnv
;
485 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
487 MEMORY_BASIC_INFORMATION MemInfo
;
488 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
490 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
492 MemoryBasicInformation
,
494 sizeof(MEMORY_BASIC_INFORMATION
),
496 if (!NT_SUCCESS(Status
))
500 EnvSize
= MemInfo
.RegionSize
;
502 DPRINT("EnvironmentSize %ld\n", EnvSize
);
504 /* allocate and initialize new environment block */
508 Status
= NtAllocateVirtualMemory(ProcessHandle
,
512 MEM_RESERVE
| MEM_COMMIT
,
514 if (!NT_SUCCESS(Status
))
519 NtWriteVirtualMemory(ProcessHandle
,
528 PpbSize
= Ppb
->AllocationSize
;
529 Status
= NtAllocateVirtualMemory(ProcessHandle
,
533 MEM_RESERVE
| MEM_COMMIT
,
535 if (!NT_SUCCESS(Status
))
540 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
541 NtWriteVirtualMemory(ProcessHandle
,
547 /* write pointer to environment */
548 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
549 NtWriteVirtualMemory(ProcessHandle
,
550 (PVOID
)(PpbBase
+ Offset
),
555 /* write pointer to process parameter block */
556 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
557 NtWriteVirtualMemory(ProcessHandle
,
558 (PVOID
)(PEB_BASE
+ Offset
),
563 /* Read image base address. */
564 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
565 NtReadVirtualMemory(ProcessHandle
,
566 (PVOID
)(PEB_BASE
+ Offset
),
571 return(STATUS_SUCCESS
);
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
)
587 HANDLE hSection
, hProcess
, hThread
;
589 LPTHREAD_START_ROUTINE lpStartAddress
= NULL
;
590 WCHAR ImagePathName
[256];
591 UNICODE_STRING ImagePathName_U
;
592 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
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];
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
;
610 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
611 lpApplicationName
, lpCommandLine
);
613 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
615 wcscpy (TempApplicationNameW
, lpApplicationName
);
616 i
= wcslen(TempApplicationNameW
);
617 if (TempApplicationNameW
[i
- 1] == L
'.')
619 TempApplicationNameW
[i
- 1] = 0;
623 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
626 s
= TempApplicationNameW
;
632 e
= wcsrchr(s
, L
'.');
636 e
= wcsrchr(s
, L
'.');
640 else if (lpCommandLine
!= NULL
&& lpCommandLine
[0] != 0)
642 if (lpCommandLine
[0] == L
'"')
644 wcscpy(TempApplicationNameW
, &lpCommandLine
[0]);
645 s
= wcschr(TempApplicationNameW
, L
'"');
654 wcscpy(TempApplicationNameW
, lpCommandLine
);
655 s
= wcschr(TempApplicationNameW
, L
' ');
661 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
664 s
= TempApplicationNameW
;
666 s
= wcsrchr(s
, L
'.');
668 wcscat(TempApplicationNameW
, L
".exe");
675 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
), ImagePathName
, &s
))
680 e
= wcsrchr(s
, L
'.');
681 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
683 // the command is a batch file
684 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
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
))
703 * Store the image file name for the process
710 for (i
= 0; i
< 8; i
++)
712 ImageFileName
[i
] = (CHAR
)(s
[i
]);
720 * Process the application name and command line
722 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
723 RtlInitUnicodeString(&CommandLine_U
, lpCommandLine
);
725 DPRINT("ImagePathName_U %S\n", ImagePathName_U
.Buffer
);
726 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
728 /* Initialize the current directory string */
729 if (lpCurrentDirectory
!= NULL
)
731 RtlInitUnicodeString(&CurrentDirectory_U
,
736 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
737 RtlInitUnicodeString(&CurrentDirectory_U
,
738 TempCurrentDirectoryW
);
743 * Create a section for the executable
746 hSection
= KlMapFile (ImagePathName
);
747 if (hSection
== NULL
)
749 /////////////////////////////////////////
751 * Inspect the image to determine executable flavour
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
;
762 DPRINT("Inspecting Image Header for image type id\n");
764 // Find the application name
765 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
766 &ApplicationNameString
, NULL
, NULL
)) {
769 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
771 InitializeObjectAttributes(&ObjectAttributes
,
772 &ApplicationNameString
,
773 OBJ_CASE_INSENSITIVE
,
777 // Try to open the executable
778 Status
= NtOpenFile(&hFile
,
779 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
782 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
783 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
785 RtlFreeUnicodeString(&ApplicationNameString
);
787 if (!NT_SUCCESS(Status
)) {
788 DPRINT("Failed to open file\n");
789 SetLastErrorByStatus(Status
);
793 // Read the dos header
795 Status
= ZwReadFile(hFile
,
805 if (!NT_SUCCESS(Status
)) {
806 DPRINT("Failed to read from file\n");
807 SetLastErrorByStatus(Status
);
810 if (Iosb
.Information
!= sizeof(DosHeader
)) {
811 DPRINT("Failed to read dos header from file\n");
812 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
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
);
824 DPRINT("Launching VDM...\n");
825 return CreateProcessW(L
"ntvdm.exe",
826 (LPWSTR
)lpApplicationName
,
834 lpProcessInformation
);
836 /////////////////////////////////////////
838 * Create a new process
840 Status
= NtCreateProcess(&hProcess
,
850 if (lpStartupInfo
->lpReserved2
)
852 ULONG i
, Count
= *(ULONG
*)lpStartupInfo
->lpReserved2
;
855 PRTL_USER_PROCESS_PARAMETERS CurrPpb
= NtCurrentPeb()->ProcessParameters
;
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.
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
);
873 RtlCreateProcessParameters(&Ppb
,
876 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
882 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
884 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
885 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
889 * Translate some handles for the new process
891 if (Ppb
->CurrentDirectoryHandle
)
893 Status
= NtDuplicateObject (NtCurrentProcess(),
894 Ppb
->CurrentDirectoryHandle
,
896 &Ppb
->CurrentDirectoryHandle
,
899 DUPLICATE_SAME_ACCESS
);
904 Status
= NtDuplicateObject (NtCurrentProcess(),
910 DUPLICATE_SAME_ACCESS
);
914 * Get some information about the executable
916 Status
= ZwQuerySection(hSection
,
917 SectionImageInformation
,
927 * Get some information about the process
929 ZwQueryInformationProcess(hProcess
,
930 ProcessBasicInformation
,
932 sizeof(ProcessBasicInfo
),
934 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
935 ProcessBasicInfo
.UniqueProcessId
);
936 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
939 * Tell the csrss server we are creating a new process
941 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
942 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
943 ProcessBasicInfo
.UniqueProcessId
;
944 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
945 Status
= CsrClientCallServer(&CsrRequest
,
947 sizeof(CSRSS_API_REQUEST
),
948 sizeof(CSRSS_API_REPLY
));
949 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
951 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
954 // Set the child console handles
955 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
956 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
957 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
959 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
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
;
969 if (IsConsoleHandle(Ppb
->hStdInput
))
971 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
975 DPRINT("Duplicate input handle\n");
976 Status
= NtDuplicateObject (NtCurrentProcess(),
982 DUPLICATE_SAME_ACCESS
);
983 if(!NT_SUCCESS(Status
))
985 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
989 if (IsConsoleHandle(Ppb
->hStdOutput
))
991 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
995 DPRINT("Duplicate output handle\n");
996 Status
= NtDuplicateObject (NtCurrentProcess(),
1002 DUPLICATE_SAME_ACCESS
);
1003 if(!NT_SUCCESS(Status
))
1005 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1008 if (IsConsoleHandle(Ppb
->hStdError
))
1010 Ppb
->hStdError
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1014 DPRINT("Duplicate error handle\n");
1015 Status
= NtDuplicateObject (NtCurrentProcess(),
1021 DUPLICATE_SAME_ACCESS
);
1022 if(!NT_SUCCESS(Status
))
1024 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1029 * Initialize some other fields in the PPB
1033 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1034 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1036 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1040 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
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
;
1054 * Create Process Environment Block
1056 DPRINT("Creating peb\n");
1058 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
);
1060 RtlDestroyProcessParameters (Ppb
);
1062 Status
= NtSetInformationProcess(hProcess
,
1063 ProcessImageFileName
,
1067 * Create the thread for the kernel
1069 DPRINT("Creating thread for process\n");
1070 hThread
= KlCreateFirstThread(hProcess
,
1074 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
,
1076 &lpProcessInformation
->dwThreadId
);
1077 if (hThread
== INVALID_HANDLE_VALUE
)
1082 lpProcessInformation
->hProcess
= hProcess
;
1083 lpProcessInformation
->hThread
= hThread
;