1 /* $Id: create.c,v 1.63 2003/03/16 14:16:54 chorns 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 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine
;
25 CreateProcessA (LPCSTR lpApplicationName
,
27 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
28 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
29 WINBOOL bInheritHandles
,
30 DWORD dwCreationFlags
,
32 LPCSTR lpCurrentDirectory
,
33 LPSTARTUPINFOA lpStartupInfo
,
34 LPPROCESS_INFORMATION lpProcessInformation
)
36 * FUNCTION: The CreateProcess function creates a new process and its
37 * primary thread. The new process executes the specified executable file
40 * lpApplicationName = Pointer to name of executable module
41 * lpCommandLine = Pointer to command line string
42 * lpProcessAttributes = Process security attributes
43 * lpThreadAttributes = Thread security attributes
44 * bInheritHandles = Handle inheritance flag
45 * dwCreationFlags = Creation flags
46 * lpEnvironment = Pointer to new environment block
47 * lpCurrentDirectory = Pointer to current directory name
48 * lpStartupInfo = Pointer to startup info
49 * lpProcessInformation = Pointer to process information
52 PWCHAR lpEnvironmentW
= NULL
;
53 UNICODE_STRING ApplicationNameU
;
54 UNICODE_STRING CurrentDirectoryU
;
55 UNICODE_STRING CommandLineU
;
56 ANSI_STRING ApplicationName
;
57 ANSI_STRING CurrentDirectory
;
58 ANSI_STRING CommandLine
;
60 CHAR TempCurrentDirectoryA
[256];
62 DPRINT("CreateProcessA(%s)\n", lpApplicationName
);
63 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
64 "lpStartupInfo %x, lpProcessInformation %x\n", dwCreationFlags
,
65 lpEnvironment
, lpCurrentDirectory
, lpStartupInfo
, lpProcessInformation
);
67 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
69 PCHAR ptr
= lpEnvironment
;
71 UNICODE_STRING EnvironmentU
;
72 ANSI_STRING EnvironmentA
;
75 RtlInitAnsiString(&EnvironmentA
, ptr
);
77 len
+= RtlAnsiStringToUnicodeSize(&EnvironmentA
) + sizeof(WCHAR
);
79 len
+= RtlOemStringToUnicodeSize(&EnvironmentA
) + sizeof(WCHAR
);
80 ptr
+= EnvironmentA
.MaximumLength
;
83 lpEnvironmentW
= (PWCHAR
)RtlAllocateHeap(GetProcessHeap(),
84 HEAP_GENERATE_EXCEPTIONS
|HEAP_ZERO_MEMORY
,
86 if (lpEnvironmentW
== NULL
)
91 EnvironmentU
.Buffer
= lpEnvironmentW
;
92 EnvironmentU
.Length
= 0;
93 EnvironmentU
.MaximumLength
= len
;
96 RtlInitAnsiString(&EnvironmentA
, ptr
);
98 RtlAnsiStringToUnicodeString(&EnvironmentU
, &EnvironmentA
, FALSE
);
100 RtlOemStringToUnicodeString(&EnvironmentU
, &EnvironmentA
, FALSE
);
101 ptr
+= EnvironmentA
.MaximumLength
;
102 EnvironmentU
.Buffer
+= (EnvironmentU
.Length
/ sizeof(WCHAR
) + 1);
103 EnvironmentU
.MaximumLength
-= (EnvironmentU
.Length
+ sizeof(WCHAR
));
104 EnvironmentU
.Length
= 0;
107 EnvironmentU
.Buffer
[0] = 0;
110 RtlInitAnsiString (&CommandLine
,
112 RtlInitAnsiString (&ApplicationName
,
113 (LPSTR
)lpApplicationName
);
114 if (lpCurrentDirectory
!= NULL
)
116 RtlInitAnsiString (&CurrentDirectory
,
117 (LPSTR
)lpCurrentDirectory
);
120 /* convert ansi (or oem) strings to unicode */
123 RtlAnsiStringToUnicodeString (&CommandLineU
, &CommandLine
, TRUE
);
124 RtlAnsiStringToUnicodeString (&ApplicationNameU
, &ApplicationName
, TRUE
);
125 if (lpCurrentDirectory
!= NULL
)
126 RtlAnsiStringToUnicodeString (&CurrentDirectoryU
, &CurrentDirectory
, TRUE
);
130 RtlOemStringToUnicodeString (&CommandLineU
, &CommandLine
, TRUE
);
131 RtlOemStringToUnicodeString (&ApplicationNameU
, &ApplicationName
, TRUE
);
132 if (lpCurrentDirectory
!= NULL
)
133 RtlOemStringToUnicodeString (&CurrentDirectoryU
, &CurrentDirectory
, TRUE
);
136 Result
= CreateProcessW (ApplicationNameU
.Buffer
,
142 dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
? lpEnvironment
: lpEnvironmentW
,
143 (lpCurrentDirectory
== NULL
) ? NULL
: CurrentDirectoryU
.Buffer
,
144 (LPSTARTUPINFOW
)lpStartupInfo
,
145 lpProcessInformation
);
147 RtlFreeUnicodeString (&ApplicationNameU
);
148 RtlFreeUnicodeString (&CommandLineU
);
149 if (lpCurrentDirectory
!= NULL
)
150 RtlFreeUnicodeString (&CurrentDirectoryU
);
154 RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW
);
160 static int _except_recursion_trap
= 0;
163 struct __EXCEPTION_RECORD
;
166 EXCEPTION_DISPOSITION
169 struct _EXCEPTION_RECORD
*ExceptionRecord
,
170 void * EstablisherFrame
,
171 struct _CONTEXT
*ContextRecord
,
172 void * DispatcherContext
)
174 DPRINT("Process terminated abnormally...\n");
176 if (++_except_recursion_trap
> 3) {
177 DPRINT("_except_handler(...) appears to be recursing.\n");
178 DPRINT("Process HALTED.\n");
182 if (/* FIXME: */ TRUE
) /* Not a service */
184 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
190 DPRINT(" calling ExitThread(0) . . .\n");
194 DPRINT(" We should not get to here !!!\n");
195 /* We should not get to here */
196 return ExceptionContinueSearch
;
200 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
205 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
207 __try1(_except_handler
)
209 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
214 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
216 ExitThread(uExitCode
);
221 KlCreateFirstThread(HANDLE ProcessHandle
,
222 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
223 PSECTION_IMAGE_INFORMATION Sii
,
224 LPTHREAD_START_ROUTINE lpStartAddress
,
225 DWORD dwCreationFlags
,
230 OBJECT_ATTRIBUTES ObjectAttributes
;
232 CONTEXT ThreadContext
;
233 INITIAL_TEB InitialTeb
;
234 BOOLEAN CreateSuspended
= FALSE
;
235 ULONG OldPageProtection
;
237 ULONG ThreadStartAddress
;
238 ULONG InitialStack
[6];
240 ObjectAttributes
.Length
= sizeof(OBJECT_ATTRIBUTES
);
241 ObjectAttributes
.RootDirectory
= NULL
;
242 ObjectAttributes
.ObjectName
= NULL
;
243 ObjectAttributes
.Attributes
= 0;
244 if (lpThreadAttributes
!= NULL
)
246 if (lpThreadAttributes
->bInheritHandle
)
247 ObjectAttributes
.Attributes
= OBJ_INHERIT
;
248 ObjectAttributes
.SecurityDescriptor
=
249 lpThreadAttributes
->lpSecurityDescriptor
;
251 ObjectAttributes
.SecurityQualityOfService
= NULL
;
253 if ((dwCreationFlags
& CREATE_SUSPENDED
) == CREATE_SUSPENDED
)
254 CreateSuspended
= TRUE
;
256 CreateSuspended
= FALSE
;
258 InitialTeb
.StackReserve
= (Sii
->StackReserve
< 0x100000) ? 0x100000 : Sii
->StackReserve
;
259 /* FIXME: use correct commit size */
261 InitialTeb
.StackCommit
= (Sii
->StackCommit
< PAGE_SIZE
) ? PAGE_SIZE
: Sii
->StackCommit
;
263 InitialTeb
.StackCommit
= InitialTeb
.StackReserve
- PAGE_SIZE
;
265 /* size of guard page */
266 InitialTeb
.StackCommit
+= PAGE_SIZE
;
269 InitialTeb
.StackAllocate
= NULL
;
270 Status
= NtAllocateVirtualMemory(ProcessHandle
,
271 &InitialTeb
.StackAllocate
,
273 &InitialTeb
.StackReserve
,
276 if (!NT_SUCCESS(Status
))
278 DPRINT("Error reserving stack space!\n");
279 SetLastErrorByStatus(Status
);
280 return(INVALID_HANDLE_VALUE
);
283 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
284 InitialTeb
.StackAllocate
, InitialTeb
.StackReserve
);
286 InitialTeb
.StackBase
= (PVOID
)((ULONG
)InitialTeb
.StackAllocate
+ InitialTeb
.StackReserve
);
287 InitialTeb
.StackLimit
= (PVOID
)((ULONG
)InitialTeb
.StackBase
- InitialTeb
.StackCommit
);
289 DPRINT("StackBase: %p StackCommit: %p\n",
290 InitialTeb
.StackBase
, InitialTeb
.StackCommit
);
292 /* Commit stack page(s) */
293 Status
= NtAllocateVirtualMemory(ProcessHandle
,
294 &InitialTeb
.StackLimit
,
296 &InitialTeb
.StackCommit
,
299 if (!NT_SUCCESS(Status
))
301 /* release the stack space */
302 NtFreeVirtualMemory(ProcessHandle
,
303 InitialTeb
.StackAllocate
,
304 &InitialTeb
.StackReserve
,
307 DPRINT("Error comitting stack page(s)!\n");
308 SetLastErrorByStatus(Status
);
309 return(INVALID_HANDLE_VALUE
);
312 DPRINT("StackLimit: %p\n",
313 InitialTeb
.StackLimit
);
315 /* Protect guard page */
316 Status
= NtProtectVirtualMemory(ProcessHandle
,
317 InitialTeb
.StackLimit
,
319 PAGE_GUARD
| PAGE_READWRITE
,
321 if (!NT_SUCCESS(Status
))
323 /* release the stack space */
324 NtFreeVirtualMemory(ProcessHandle
,
325 InitialTeb
.StackAllocate
,
326 &InitialTeb
.StackReserve
,
329 DPRINT("Error comitting guard page!\n");
330 SetLastErrorByStatus(Status
);
331 return(INVALID_HANDLE_VALUE
);
334 if (Sii
->Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
336 ThreadStartAddress
= (ULONG
) BaseProcessStart
;
340 ThreadStartAddress
= (ULONG
) RtlBaseProcessStartRoutine
;
343 memset(&ThreadContext
,0,sizeof(CONTEXT
));
344 ThreadContext
.Eip
= ThreadStartAddress
;
345 ThreadContext
.SegGs
= USER_DS
;
346 ThreadContext
.SegFs
= USER_DS
;
347 ThreadContext
.SegEs
= USER_DS
;
348 ThreadContext
.SegDs
= USER_DS
;
349 ThreadContext
.SegCs
= USER_CS
;
350 ThreadContext
.SegSs
= USER_DS
;
351 ThreadContext
.Esp
= (ULONG
)InitialTeb
.StackBase
- 6*4;
352 ThreadContext
.EFlags
= (1<<1) + (1<<9);
354 DPRINT("ThreadContext.Eip %x\n",ThreadContext
.Eip
);
357 * Write in the initial stack.
360 InitialStack
[1] = (DWORD
)lpStartAddress
;
361 InitialStack
[2] = PEB_BASE
;
363 Status
= ZwWriteVirtualMemory(ProcessHandle
,
364 (PVOID
)ThreadContext
.Esp
,
366 sizeof(InitialStack
),
368 if (!NT_SUCCESS(Status
))
370 DPRINT1("Failed to write initial stack.\n");
371 return(INVALID_HANDLE_VALUE
);
374 Status
= NtCreateThread(&ThreadHandle
,
382 if (!NT_SUCCESS(Status
))
384 NtFreeVirtualMemory(ProcessHandle
,
385 InitialTeb
.StackAllocate
,
386 &InitialTeb
.StackReserve
,
388 SetLastErrorByStatus(Status
);
389 return(INVALID_HANDLE_VALUE
);
392 if (lpThreadId
!= NULL
)
394 memcpy(lpThreadId
, &ClientId
.UniqueThread
,sizeof(ULONG
));
397 return(ThreadHandle
);
401 KlMapFile(LPCWSTR lpApplicationName
)
404 IO_STATUS_BLOCK IoStatusBlock
;
405 UNICODE_STRING ApplicationNameString
;
406 OBJECT_ATTRIBUTES ObjectAttributes
;
407 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
414 * Find the application name
417 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
418 &ApplicationNameString
,
423 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
425 InitializeObjectAttributes(&ObjectAttributes
,
426 &ApplicationNameString
,
427 OBJ_CASE_INSENSITIVE
,
432 * Try to open the executable
435 Status
= NtOpenFile(&hFile
,
436 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
439 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
440 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
442 RtlFreeUnicodeString (&ApplicationNameString
);
444 if (!NT_SUCCESS(Status
))
446 DPRINT("Failed to open file\n");
447 SetLastErrorByStatus (Status
);
451 Status
= NtCreateSection(&hSection
,
460 if (!NT_SUCCESS(Status
))
462 DPRINT("Failed to create section\n");
463 SetLastErrorByStatus (Status
);
471 KlInitPeb (HANDLE ProcessHandle
,
472 PRTL_USER_PROCESS_PARAMETERS Ppb
,
473 PVOID
* ImageBaseAddress
)
480 PVOID ParentEnv
= NULL
;
483 ULONG EnvSize
= 0, EnvSize1
= 0;
485 /* create the Environment */
486 if (Ppb
->Environment
!= NULL
)
488 ParentEnv
= Ppb
->Environment
;
495 EnvSize
= (PVOID
)ptr
- ParentEnv
;
497 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
499 MEMORY_BASIC_INFORMATION MemInfo
;
500 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
502 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
504 MemoryBasicInformation
,
506 sizeof(MEMORY_BASIC_INFORMATION
),
508 if (!NT_SUCCESS(Status
))
512 EnvSize
= MemInfo
.RegionSize
;
514 DPRINT("EnvironmentSize %ld\n", EnvSize
);
516 /* allocate and initialize new environment block */
520 Status
= NtAllocateVirtualMemory(ProcessHandle
,
524 MEM_RESERVE
| MEM_COMMIT
,
526 if (!NT_SUCCESS(Status
))
531 NtWriteVirtualMemory(ProcessHandle
,
540 PpbSize
= Ppb
->AllocationSize
;
541 Status
= NtAllocateVirtualMemory(ProcessHandle
,
545 MEM_RESERVE
| MEM_COMMIT
,
547 if (!NT_SUCCESS(Status
))
552 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
553 NtWriteVirtualMemory(ProcessHandle
,
559 /* write pointer to environment */
560 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
561 NtWriteVirtualMemory(ProcessHandle
,
562 (PVOID
)(PpbBase
+ Offset
),
567 /* write pointer to process parameter block */
568 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
569 NtWriteVirtualMemory(ProcessHandle
,
570 (PVOID
)(PEB_BASE
+ Offset
),
575 /* Read image base address. */
576 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
577 NtReadVirtualMemory(ProcessHandle
,
578 (PVOID
)(PEB_BASE
+ Offset
),
583 return(STATUS_SUCCESS
);
588 CreateProcessW(LPCWSTR lpApplicationName
,
589 LPWSTR lpCommandLine
,
590 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
591 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
592 WINBOOL bInheritHandles
,
593 DWORD dwCreationFlags
,
594 LPVOID lpEnvironment
,
595 LPCWSTR lpCurrentDirectory
,
596 LPSTARTUPINFOW lpStartupInfo
,
597 LPPROCESS_INFORMATION lpProcessInformation
)
599 HANDLE hSection
, hProcess
, hThread
;
601 LPTHREAD_START_ROUTINE lpStartAddress
= NULL
;
602 WCHAR ImagePathName
[256];
603 UNICODE_STRING ImagePathName_U
;
604 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
606 PRTL_USER_PROCESS_PARAMETERS Ppb
;
607 UNICODE_STRING CommandLine_U
;
608 CSRSS_API_REQUEST CsrRequest
;
609 CSRSS_API_REPLY CsrReply
;
610 CHAR ImageFileName
[8];
613 ANSI_STRING ProcedureName
;
614 UNICODE_STRING CurrentDirectory_U
;
615 SECTION_IMAGE_INFORMATION Sii
;
616 WCHAR TempCurrentDirectoryW
[256];
617 WCHAR TempApplicationNameW
[256];
618 WCHAR TempCommandLineNameW
[256];
619 UNICODE_STRING RuntimeInfo_U
;
620 PVOID ImageBaseAddress
;
622 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
623 lpApplicationName
, lpCommandLine
);
625 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
627 wcscpy (TempApplicationNameW
, lpApplicationName
);
628 i
= wcslen(TempApplicationNameW
);
629 if (TempApplicationNameW
[i
- 1] == L
'.')
631 TempApplicationNameW
[i
- 1] = 0;
635 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
638 s
= TempApplicationNameW
;
644 e
= wcsrchr(s
, L
'.');
648 e
= wcsrchr(s
, L
'.');
652 else if (lpCommandLine
!= NULL
&& lpCommandLine
[0] != 0)
654 if (lpCommandLine
[0] == L
'"')
656 wcscpy(TempApplicationNameW
, lpCommandLine
+ 1);
657 s
= wcschr(TempApplicationNameW
, L
'"');
666 wcscpy(TempApplicationNameW
, lpCommandLine
);
667 s
= wcschr(TempApplicationNameW
, L
' ');
673 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
676 s
= TempApplicationNameW
;
678 s
= wcsrchr(s
, L
'.');
680 wcscat(TempApplicationNameW
, L
".exe");
687 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
692 e
= wcsrchr(s
, L
'.');
693 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
695 // the command is a batch file
696 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
698 // FIXME: use COMSPEC for the command interpreter
699 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
700 wcscat(TempCommandLineNameW
, lpApplicationName
);
701 lpCommandLine
= TempCommandLineNameW
;
702 wcscpy(TempApplicationNameW
, L
"cmd.exe");
703 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
715 * Store the image file name for the process
722 for (i
= 0; i
< 8; i
++)
724 ImageFileName
[i
] = (CHAR
)(s
[i
]);
732 * Process the application name and command line
734 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
735 RtlInitUnicodeString(&CommandLine_U
, lpCommandLine
);
737 DPRINT("ImagePathName_U %S\n", ImagePathName_U
.Buffer
);
738 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
740 /* Initialize the current directory string */
741 if (lpCurrentDirectory
!= NULL
)
743 RtlInitUnicodeString(&CurrentDirectory_U
,
748 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
749 RtlInitUnicodeString(&CurrentDirectory_U
,
750 TempCurrentDirectoryW
);
754 * Create a section for the executable
757 hSection
= KlMapFile (ImagePathName
);
758 if (hSection
== NULL
)
760 /////////////////////////////////////////
762 * Inspect the image to determine executable flavour
764 IO_STATUS_BLOCK IoStatusBlock
;
765 UNICODE_STRING ApplicationNameString
;
766 OBJECT_ATTRIBUTES ObjectAttributes
;
767 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
768 IMAGE_DOS_HEADER DosHeader
;
769 IO_STATUS_BLOCK Iosb
;
770 LARGE_INTEGER Offset
;
773 DPRINT("Inspecting Image Header for image type id\n");
775 // Find the application name
776 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
777 &ApplicationNameString
, NULL
, NULL
)) {
780 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
782 InitializeObjectAttributes(&ObjectAttributes
,
783 &ApplicationNameString
,
784 OBJ_CASE_INSENSITIVE
,
788 // Try to open the executable
789 Status
= NtOpenFile(&hFile
,
790 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
793 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
794 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
796 RtlFreeUnicodeString(&ApplicationNameString
);
798 if (!NT_SUCCESS(Status
)) {
799 DPRINT("Failed to open file\n");
800 SetLastErrorByStatus(Status
);
804 // Read the dos header
806 Status
= ZwReadFile(hFile
,
816 if (!NT_SUCCESS(Status
)) {
817 DPRINT("Failed to read from file\n");
818 SetLastErrorByStatus(Status
);
821 if (Iosb
.Information
!= sizeof(DosHeader
)) {
822 DPRINT("Failed to read dos header from file\n");
823 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
827 // Check the DOS signature
828 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) {
829 DPRINT("Failed dos magic check\n");
830 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
835 DPRINT("Launching VDM...\n");
836 return CreateProcessW(L
"ntvdm.exe",
837 (LPWSTR
)lpApplicationName
,
845 lpProcessInformation
);
847 /////////////////////////////////////////
849 * Create a new process
851 Status
= NtCreateProcess(&hProcess
,
861 if (lpStartupInfo
->lpReserved2
)
863 ULONG i
, Count
= *(ULONG
*)lpStartupInfo
->lpReserved2
;
866 PRTL_USER_PROCESS_PARAMETERS CurrPpb
= NtCurrentPeb()->ProcessParameters
;
870 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
871 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
872 * If is possible that this function overwrite the last information in runtimeinfo
873 * with the null terminator for the unicode string.
875 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= ROUND_UP(lpStartupInfo
->cbReserved2
, 2) + 2;
876 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
877 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
884 RtlCreateProcessParameters(&Ppb
,
887 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
893 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
895 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
896 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
900 * Translate some handles for the new process
902 if (Ppb
->CurrentDirectoryHandle
)
904 Status
= NtDuplicateObject (NtCurrentProcess(),
905 Ppb
->CurrentDirectoryHandle
,
907 &Ppb
->CurrentDirectoryHandle
,
910 DUPLICATE_SAME_ACCESS
);
915 Status
= NtDuplicateObject (NtCurrentProcess(),
921 DUPLICATE_SAME_ACCESS
);
925 * Get some information about the executable
927 Status
= ZwQuerySection(hSection
,
928 SectionImageInformation
,
938 * Get some information about the process
940 NtQueryInformationProcess(hProcess
,
941 ProcessBasicInformation
,
943 sizeof(ProcessBasicInfo
),
945 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
946 ProcessBasicInfo
.UniqueProcessId
);
947 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
950 * Tell the csrss server we are creating a new process
952 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
953 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
954 ProcessBasicInfo
.UniqueProcessId
;
955 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
956 Status
= CsrClientCallServer(&CsrRequest
,
958 sizeof(CSRSS_API_REQUEST
),
959 sizeof(CSRSS_API_REPLY
));
960 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
962 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
965 // Set the child console handles
966 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
967 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
968 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
970 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
972 if (lpStartupInfo
->hStdInput
)
973 Ppb
->hStdInput
= lpStartupInfo
->hStdInput
;
974 if (lpStartupInfo
->hStdOutput
)
975 Ppb
->hStdOutput
= lpStartupInfo
->hStdOutput
;
976 if (lpStartupInfo
->hStdError
)
977 Ppb
->hStdError
= lpStartupInfo
->hStdError
;
980 if (IsConsoleHandle(Ppb
->hStdInput
))
982 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
986 DPRINT("Duplicate input handle\n");
987 Status
= NtDuplicateObject (NtCurrentProcess(),
993 DUPLICATE_SAME_ACCESS
);
994 if(!NT_SUCCESS(Status
))
996 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1000 if (IsConsoleHandle(Ppb
->hStdOutput
))
1002 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1006 DPRINT("Duplicate output handle\n");
1007 Status
= NtDuplicateObject (NtCurrentProcess(),
1013 DUPLICATE_SAME_ACCESS
);
1014 if(!NT_SUCCESS(Status
))
1016 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1019 if (IsConsoleHandle(Ppb
->hStdError
))
1021 CsrRequest
.Type
= CSRSS_DUPLICATE_HANDLE
;
1022 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1023 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1024 Status
= CsrClientCallServer(&CsrRequest
,
1026 sizeof(CSRSS_API_REQUEST
),
1027 sizeof(CSRSS_API_REPLY
));
1028 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1030 Ppb
->hStdError
= INVALID_HANDLE_VALUE
;
1034 Ppb
->hStdError
= CsrReply
.Data
.DuplicateHandleReply
.Handle
;
1039 DPRINT("Duplicate error handle\n");
1040 Status
= NtDuplicateObject (NtCurrentProcess(),
1046 DUPLICATE_SAME_ACCESS
);
1047 if(!NT_SUCCESS(Status
))
1049 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1054 * Initialize some other fields in the PPB
1058 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1059 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1061 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1065 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
1067 Ppb
->dwX
= lpStartupInfo
->dwX
;
1068 Ppb
->dwY
= lpStartupInfo
->dwY
;
1069 Ppb
->dwXSize
= lpStartupInfo
->dwXSize
;
1070 Ppb
->dwYSize
= lpStartupInfo
->dwYSize
;
1071 Ppb
->dwFillAttribute
= lpStartupInfo
->dwFillAttribute
;
1079 * Create Process Environment Block
1081 DPRINT("Creating peb\n");
1083 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
);
1085 RtlDestroyProcessParameters (Ppb
);
1087 Status
= NtSetInformationProcess(hProcess
,
1088 ProcessImageFileName
,
1092 * Create the thread for the kernel
1094 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1095 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
);
1096 hThread
= KlCreateFirstThread(hProcess
,
1099 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
,
1101 &lpProcessInformation
->dwThreadId
);
1102 if (hThread
== INVALID_HANDLE_VALUE
)
1107 lpProcessInformation
->hProcess
= hProcess
;
1108 lpProcessInformation
->hThread
= hThread
;