1 /* $Id: create.c,v 1.68 2003/07/10 18:50:51 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
;
24 typedef NTSTATUS
STDCALL (K32_MBSTR_TO_WCSTR
)
31 NTSTATUS STDCALL K32MbStrToWcStr
33 IN K32_MBSTR_TO_WCSTR
* True
,
34 UNICODE_STRING
* DestStr
,
35 ANSI_STRING
* SourceStr
,
39 if(SourceStr
->Buffer
== NULL
)
41 DestStr
->Length
= DestStr
->MaximumLength
= 0;
42 DestStr
->Buffer
= NULL
;
43 return STATUS_SUCCESS
;
46 return True(DestStr
, SourceStr
, Allocate
);
49 VOID STDCALL RtlRosR32AttribsToNativeAttribs
51 OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
52 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
55 NativeAttribs
->Length
= sizeof(*NativeAttribs
);
56 NativeAttribs
->ObjectName
= NULL
;
57 NativeAttribs
->RootDirectory
= NULL
;
58 NativeAttribs
->Attributes
= 0;
59 NativeAttribs
->SecurityQualityOfService
= NULL
;
62 if(Ros32Attribs
!= NULL
&& Ros32Attribs
->nLength
>= sizeof(*Ros32Attribs
))
64 NativeAttribs
->SecurityDescriptor
= Ros32Attribs
->lpSecurityDescriptor
;
66 if(Ros32Attribs
->bInheritHandle
)
67 NativeAttribs
->Attributes
|= OBJ_INHERIT
;
70 NativeAttribs
->SecurityDescriptor
= NULL
;
73 VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed
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
82 if(!NativeAttribs
) return;
84 RtlRosR32AttribsToNativeAttribs(NativeAttribs
, Ros32Attribs
);
86 if(Ros32Name
!= NULL
&& NativeName
!= NULL
)
88 RtlInitUnicodeString(NativeName
, Ros32Name
);
90 NativeAttribs
->ObjectName
= NativeName
;
91 NativeAttribs
->RootDirectory
= Ros32NameRoot
;
92 NativeAttribs
->Attributes
|= OBJ_CASE_INSENSITIVE
;
100 BOOL STDCALL CreateProcessA
102 LPCSTR lpApplicationName
,
104 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
105 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
106 BOOL bInheritHandles
,
107 DWORD dwCreationFlags
,
108 LPVOID lpEnvironment
,
109 LPCSTR lpCurrentDirectory
,
110 LPSTARTUPINFOA lpStartupInfo
,
111 LPPROCESS_INFORMATION lpProcessInformation
114 * FUNCTION: The CreateProcess function creates a new process and its
115 * primary thread. The new process executes the specified executable file
118 * lpApplicationName = Pointer to name of executable module
119 * lpCommandLine = Pointer to command line string
120 * lpProcessAttributes = Process security attributes
121 * lpThreadAttributes = Thread security attributes
122 * bInheritHandles = Handle inheritance flag
123 * dwCreationFlags = Creation flags
124 * lpEnvironment = Pointer to new environment block
125 * lpCurrentDirectory = Pointer to current directory name
126 * lpStartupInfo = Pointer to startup info
127 * lpProcessInformation = Pointer to process information
130 PWCHAR pwcEnv
= NULL
;
131 UNICODE_STRING wstrApplicationName
;
132 UNICODE_STRING wstrCurrentDirectory
;
133 UNICODE_STRING wstrCommandLine
;
134 UNICODE_STRING wstrReserved
;
135 UNICODE_STRING wstrDesktop
;
136 UNICODE_STRING wstrTitle
;
137 ANSI_STRING strApplicationName
;
138 ANSI_STRING strCurrentDirectory
;
139 ANSI_STRING strCommandLine
;
140 ANSI_STRING strReserved
;
141 ANSI_STRING strDesktop
;
142 ANSI_STRING strTitle
;
144 STARTUPINFOW wsiStartupInfo
;
146 NTSTATUS
STDCALL (*pTrue
)
153 ULONG
STDCALL (*pRtlMbStringToUnicodeSize
)(ANSI_STRING
*);
155 DPRINT("CreateProcessA(%s)\n", lpApplicationName
);
159 "dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
160 "lpStartupInfo %x, lpProcessInformation %x\n",
168 /* invalid parameter */
169 if(lpStartupInfo
== NULL
)
171 SetLastError(ERROR_INVALID_PARAMETER
);
175 /* multibyte strings are ANSI */
178 pTrue
= RtlAnsiStringToUnicodeString
;
179 pRtlMbStringToUnicodeSize
= RtlAnsiStringToUnicodeSize
;
181 /* multibyte strings are OEM */
184 pTrue
= RtlOemStringToUnicodeString
;
185 pRtlMbStringToUnicodeSize
= RtlOemStringToUnicodeSize
;
188 /* convert the environment */
189 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
193 UNICODE_STRING wstrEnvVar
;
194 ANSI_STRING strEnvVar
;
196 /* scan the environment to calculate its Unicode size */
197 for(pcScan
= lpEnvironment
; *pcScan
; pcScan
+= strEnvVar
.MaximumLength
)
199 /* add the size of the current variable */
200 RtlInitAnsiString(&strEnvVar
, pcScan
);
201 nEnvLen
+= pRtlMbStringToUnicodeSize(&strEnvVar
) + sizeof(WCHAR
);
204 /* add the size of the final NUL character */
205 nEnvLen
+= sizeof(WCHAR
);
207 /* environment too large */
208 if(nEnvLen
> ~((USHORT
)0))
210 SetLastError(ERROR_OUTOFMEMORY
);
214 /* allocate the Unicode environment */
215 pwcEnv
= (PWCHAR
)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, nEnvLen
);
220 SetLastError(ERROR_OUTOFMEMORY
);
224 wstrEnvVar
.Buffer
= pwcEnv
;
225 wstrEnvVar
.Length
= 0;
226 wstrEnvVar
.MaximumLength
= nEnvLen
;
228 /* scan the environment to convert it */
229 for(pcScan
= lpEnvironment
; *pcScan
; pcScan
+= strEnvVar
.MaximumLength
)
231 /* convert the current variable */
232 RtlInitAnsiString(&strEnvVar
, pcScan
);
233 K32MbStrToWcStr(pTrue
, &wstrEnvVar
, &strEnvVar
, FALSE
);
235 /* advance the buffer to the next variable */
236 wstrEnvVar
.Buffer
+= (wstrEnvVar
.Length
/ sizeof(WCHAR
) + 1);
237 wstrEnvVar
.MaximumLength
-= (wstrEnvVar
.Length
+ sizeof(WCHAR
));
238 wstrEnvVar
.Length
= 0;
241 /* final NUL character */
242 wstrEnvVar
.Buffer
[0] = 0;
245 /* convert the strings */
246 RtlInitAnsiString(&strCommandLine
, lpCommandLine
);
247 RtlInitAnsiString(&strApplicationName
, (LPSTR
)lpApplicationName
);
248 RtlInitAnsiString(&strCurrentDirectory
, (LPSTR
)lpCurrentDirectory
);
249 RtlInitAnsiString(&strReserved
, (LPSTR
)lpStartupInfo
->lpReserved
);
250 RtlInitAnsiString(&strDesktop
, (LPSTR
)lpStartupInfo
->lpDesktop
);
251 RtlInitAnsiString(&strTitle
, (LPSTR
)lpStartupInfo
->lpTitle
);
253 K32MbStrToWcStr(pTrue
, &wstrCommandLine
, &strCommandLine
, TRUE
);
254 K32MbStrToWcStr(pTrue
, &wstrApplicationName
, &strApplicationName
, TRUE
);
255 K32MbStrToWcStr(pTrue
, &wstrCurrentDirectory
, &strCurrentDirectory
, TRUE
);
256 K32MbStrToWcStr(pTrue
, &wstrReserved
, &strReserved
, TRUE
);
257 K32MbStrToWcStr(pTrue
, &wstrDesktop
, &strDesktop
, TRUE
);
258 K32MbStrToWcStr(pTrue
, &wstrTitle
, &strTitle
, TRUE
);
260 /* convert the startup information */
261 memcpy(&wsiStartupInfo
, lpStartupInfo
, sizeof(wsiStartupInfo
));
263 wsiStartupInfo
.lpReserved
= wstrReserved
.Buffer
;
264 wsiStartupInfo
.lpDesktop
= wstrDesktop
.Buffer
;
265 wsiStartupInfo
.lpTitle
= wstrTitle
.Buffer
;
267 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName
);
268 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine
);
269 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory
);
270 DPRINT("wstrReserved %wZ\n", &wstrReserved
);
271 DPRINT("wstrDesktop %wZ\n", &wstrDesktop
);
272 DPRINT("wstrTitle %wZ\n", &wstrTitle
);
274 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName
.Buffer
);
275 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine
.Buffer
);
276 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory
.Buffer
);
277 DPRINT("wstrReserved.Buffer %p\n", wstrReserved
.Buffer
);
278 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop
.Buffer
);
279 DPRINT("wstrTitle.Buffer %p\n", wstrTitle
.Buffer
);
281 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA
));
282 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW
));
284 /* call the Unicode function */
285 bRetVal
= CreateProcessW
287 wstrApplicationName
.Buffer
,
288 wstrCommandLine
.Buffer
,
293 dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
? lpEnvironment
: pwcEnv
,
294 wstrCurrentDirectory
.Buffer
,
299 RtlFreeUnicodeString(&wstrApplicationName
);
300 RtlFreeUnicodeString(&wstrCommandLine
);
301 RtlFreeUnicodeString(&wstrCurrentDirectory
);
302 RtlFreeUnicodeString(&wstrReserved
);
303 RtlFreeUnicodeString(&wstrDesktop
);
304 RtlFreeUnicodeString(&wstrTitle
);
306 RtlFreeHeap(GetProcessHeap(), 0, pwcEnv
);
311 static int _except_recursion_trap
= 0;
314 struct __EXCEPTION_RECORD
;
317 EXCEPTION_DISPOSITION
320 struct _EXCEPTION_RECORD
*ExceptionRecord
,
321 void * EstablisherFrame
,
322 struct _CONTEXT
*ContextRecord
,
323 void * DispatcherContext
)
325 DPRINT1("Process terminated abnormally due to unhandled exception\n");
327 if (3 < ++_except_recursion_trap
)
329 DPRINT1("_except_handler(...) appears to be recursing.\n");
330 DPRINT1("Process HALTED.\n");
336 if (/* FIXME: */ TRUE
) /* Not a service */
338 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
339 /* ExitProcess(0); */
344 DPRINT(" calling ExitThread(0) . . .\n");
348 DPRINT1(" We should not get to here !!!\n");
349 /* We should not get to here */
350 return ExceptionContinueSearch
;
354 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
359 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
361 __try1(_except_handler
)
363 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
368 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
370 ExitThread(uExitCode
);
374 HANDLE STDCALL KlCreateFirstThread
376 HANDLE ProcessHandle
,
377 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
378 PSECTION_IMAGE_INFORMATION Sii
,
379 LPTHREAD_START_ROUTINE lpStartAddress
,
380 DWORD dwCreationFlags
,
384 OBJECT_ATTRIBUTES oaThreadAttribs
;
385 CLIENT_ID cidClientId
;
386 PVOID pTrueStartAddress
;
390 /* convert the thread attributes */
391 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs
, lpThreadAttributes
);
394 if(Sii
->Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
395 pTrueStartAddress
= (PVOID
)BaseProcessStart
;
398 pTrueStartAddress
= (PVOID
)RtlBaseProcessStartRoutine
;
402 "RtlRosCreateUserThreadVa\n"
404 " ProcessHandle %p,\n"
405 " ObjectAttributes %p,\n"
406 " CreateSuspended %d,\n"
407 " StackZeroBits %d,\n"
408 " StackReserve %lu,\n"
409 " StackCommit %lu,\n"
410 " StartAddress %p,\n"
411 " ThreadHandle %p,\n"
413 " ParameterCount %u,\n"
414 " Parameters[0] %p,\n"
415 " Parameters[1] %p\n"
419 dwCreationFlags
& CREATE_SUSPENDED
,
431 /* create the first thread */
432 nErrCode
= RtlRosCreateUserThreadVa
436 dwCreationFlags
& CREATE_SUSPENDED
,
438 &(Sii
->StackReserve
),
444 (ULONG_PTR
)lpStartAddress
,
449 if(!NT_SUCCESS(nErrCode
))
451 SetLastErrorByStatus(nErrCode
);
460 "ClientId.UniqueThread %p\n",
464 cidClientId
.UniqueThread
468 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
472 HANDLE
KlMapFile(LPCWSTR lpApplicationName
)
475 IO_STATUS_BLOCK IoStatusBlock
;
476 UNICODE_STRING ApplicationNameString
;
477 OBJECT_ATTRIBUTES ObjectAttributes
;
478 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
485 * Find the application name
488 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
489 &ApplicationNameString
,
494 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
496 InitializeObjectAttributes(&ObjectAttributes
,
497 &ApplicationNameString
,
498 OBJ_CASE_INSENSITIVE
,
503 * Try to open the executable
506 Status
= NtOpenFile(&hFile
,
507 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
510 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
511 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
513 RtlFreeUnicodeString (&ApplicationNameString
);
515 if (!NT_SUCCESS(Status
))
517 DPRINT("Failed to open file\n");
518 SetLastErrorByStatus (Status
);
522 Status
= NtCreateSection(&hSection
,
531 if (!NT_SUCCESS(Status
))
533 DPRINT("Failed to create section\n");
534 SetLastErrorByStatus (Status
);
541 static NTSTATUS KlInitPeb
543 HANDLE ProcessHandle
,
544 PRTL_USER_PROCESS_PARAMETERS Ppb
,
545 PVOID
* ImageBaseAddress
553 PVOID ParentEnv
= NULL
;
556 ULONG EnvSize
= 0, EnvSize1
= 0;
558 /* create the Environment */
559 if (Ppb
->Environment
!= NULL
)
561 ParentEnv
= Ppb
->Environment
;
568 EnvSize
= (PVOID
)ptr
- ParentEnv
;
570 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
572 MEMORY_BASIC_INFORMATION MemInfo
;
573 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
575 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
577 MemoryBasicInformation
,
579 sizeof(MEMORY_BASIC_INFORMATION
),
581 if (!NT_SUCCESS(Status
))
585 EnvSize
= MemInfo
.RegionSize
;
587 DPRINT("EnvironmentSize %ld\n", EnvSize
);
589 /* allocate and initialize new environment block */
593 Status
= NtAllocateVirtualMemory(ProcessHandle
,
597 MEM_RESERVE
| MEM_COMMIT
,
599 if (!NT_SUCCESS(Status
))
604 NtWriteVirtualMemory(ProcessHandle
,
613 PpbSize
= Ppb
->AllocationSize
;
614 Status
= NtAllocateVirtualMemory(ProcessHandle
,
618 MEM_RESERVE
| MEM_COMMIT
,
620 if (!NT_SUCCESS(Status
))
625 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
626 NtWriteVirtualMemory(ProcessHandle
,
632 /* write pointer to environment */
633 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
634 NtWriteVirtualMemory(ProcessHandle
,
635 (PVOID
)(PpbBase
+ Offset
),
640 /* write pointer to process parameter block */
641 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
642 NtWriteVirtualMemory(ProcessHandle
,
643 (PVOID
)(PEB_BASE
+ Offset
),
648 /* Read image base address. */
649 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
650 NtReadVirtualMemory(ProcessHandle
,
651 (PVOID
)(PEB_BASE
+ Offset
),
656 return(STATUS_SUCCESS
);
666 LPCWSTR lpApplicationName
,
667 LPWSTR lpCommandLine
,
668 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
669 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
670 WINBOOL bInheritHandles
,
671 DWORD dwCreationFlags
,
672 LPVOID lpEnvironment
,
673 LPCWSTR lpCurrentDirectory
,
674 LPSTARTUPINFOW lpStartupInfo
,
675 LPPROCESS_INFORMATION lpProcessInformation
678 HANDLE hSection
, hProcess
, hThread
;
680 LPTHREAD_START_ROUTINE lpStartAddress
= NULL
;
681 WCHAR ImagePathName
[256];
682 UNICODE_STRING ImagePathName_U
;
683 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
685 PRTL_USER_PROCESS_PARAMETERS Ppb
;
686 UNICODE_STRING CommandLine_U
;
687 CSRSS_API_REQUEST CsrRequest
;
688 CSRSS_API_REPLY CsrReply
;
689 CHAR ImageFileName
[8];
692 ANSI_STRING ProcedureName
;
693 UNICODE_STRING CurrentDirectory_U
;
694 SECTION_IMAGE_INFORMATION Sii
;
695 WCHAR TempCurrentDirectoryW
[256];
696 WCHAR TempApplicationNameW
[256];
697 WCHAR TempCommandLineNameW
[256];
698 UNICODE_STRING RuntimeInfo_U
;
699 PVOID ImageBaseAddress
;
701 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
702 lpApplicationName
, lpCommandLine
);
704 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
706 wcscpy (TempApplicationNameW
, lpApplicationName
);
707 i
= wcslen(TempApplicationNameW
);
708 if (TempApplicationNameW
[i
- 1] == L
'.')
710 TempApplicationNameW
[i
- 1] = 0;
714 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
717 s
= TempApplicationNameW
;
723 e
= wcsrchr(s
, L
'.');
727 e
= wcsrchr(s
, L
'.');
731 else if (lpCommandLine
!= NULL
&& lpCommandLine
[0] != 0)
733 if (lpCommandLine
[0] == L
'"')
735 wcscpy(TempApplicationNameW
, lpCommandLine
+ 1);
736 s
= wcschr(TempApplicationNameW
, L
'"');
745 wcscpy(TempApplicationNameW
, lpCommandLine
);
746 s
= wcschr(TempApplicationNameW
, L
' ');
752 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
755 s
= TempApplicationNameW
;
757 s
= wcsrchr(s
, L
'.');
759 wcscat(TempApplicationNameW
, L
".exe");
766 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
767 lpApplicationName
, lpCommandLine
);
769 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
774 e
= wcsrchr(s
, L
'.');
775 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
777 // the command is a batch file
778 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
780 // FIXME: use COMSPEC for the command interpreter
781 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
782 wcscat(TempCommandLineNameW
, lpApplicationName
);
783 lpCommandLine
= TempCommandLineNameW
;
784 wcscpy(TempApplicationNameW
, L
"cmd.exe");
785 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
797 * Store the image file name for the process
804 for (i
= 0; i
< 8; i
++)
806 ImageFileName
[i
] = (CHAR
)(s
[i
]);
814 * Process the application name and command line
816 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
817 RtlInitUnicodeString(&CommandLine_U
, lpCommandLine
);
819 DPRINT("ImagePathName_U %S\n", ImagePathName_U
.Buffer
);
820 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
822 /* Initialize the current directory string */
823 if (lpCurrentDirectory
!= NULL
)
825 RtlInitUnicodeString(&CurrentDirectory_U
,
830 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
831 RtlInitUnicodeString(&CurrentDirectory_U
,
832 TempCurrentDirectoryW
);
836 * Create a section for the executable
839 hSection
= KlMapFile (ImagePathName
);
840 if (hSection
== NULL
)
842 /////////////////////////////////////////
844 * Inspect the image to determine executable flavour
846 IO_STATUS_BLOCK IoStatusBlock
;
847 UNICODE_STRING ApplicationNameString
;
848 OBJECT_ATTRIBUTES ObjectAttributes
;
849 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
850 IMAGE_DOS_HEADER DosHeader
;
851 IO_STATUS_BLOCK Iosb
;
852 LARGE_INTEGER Offset
;
855 DPRINT("Inspecting Image Header for image type id\n");
857 // Find the application name
858 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
859 &ApplicationNameString
, NULL
, NULL
)) {
862 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
864 InitializeObjectAttributes(&ObjectAttributes
,
865 &ApplicationNameString
,
866 OBJ_CASE_INSENSITIVE
,
870 // Try to open the executable
871 Status
= NtOpenFile(&hFile
,
872 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
875 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
876 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
878 RtlFreeUnicodeString(&ApplicationNameString
);
880 if (!NT_SUCCESS(Status
)) {
881 DPRINT("Failed to open file\n");
882 SetLastErrorByStatus(Status
);
886 // Read the dos header
888 Status
= ZwReadFile(hFile
,
898 if (!NT_SUCCESS(Status
)) {
899 DPRINT("Failed to read from file\n");
900 SetLastErrorByStatus(Status
);
903 if (Iosb
.Information
!= sizeof(DosHeader
)) {
904 DPRINT("Failed to read dos header from file\n");
905 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
909 // Check the DOS signature
910 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) {
911 DPRINT("Failed dos magic check\n");
912 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
917 DPRINT("Launching VDM...\n");
918 return CreateProcessW(L
"ntvdm.exe",
919 (LPWSTR
)lpApplicationName
,
927 lpProcessInformation
);
929 /////////////////////////////////////////
931 * Create a new process
933 Status
= NtCreateProcess(&hProcess
,
943 if (lpStartupInfo
->lpReserved2
)
945 ULONG i
, Count
= *(ULONG
*)lpStartupInfo
->lpReserved2
;
948 PRTL_USER_PROCESS_PARAMETERS CurrPpb
= NtCurrentPeb()->ProcessParameters
;
952 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
953 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
954 * If is possible that this function overwrite the last information in runtimeinfo
955 * with the null terminator for the unicode string.
957 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= ROUND_UP(lpStartupInfo
->cbReserved2
, 2) + 2;
958 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
959 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
966 RtlCreateProcessParameters(&Ppb
,
969 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
975 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
977 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
978 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
982 * Translate some handles for the new process
984 if (Ppb
->CurrentDirectoryHandle
)
986 Status
= NtDuplicateObject (NtCurrentProcess(),
987 Ppb
->CurrentDirectoryHandle
,
989 &Ppb
->CurrentDirectoryHandle
,
992 DUPLICATE_SAME_ACCESS
);
997 Status
= NtDuplicateObject (NtCurrentProcess(),
1003 DUPLICATE_SAME_ACCESS
);
1007 * Get some information about the executable
1009 Status
= ZwQuerySection(hSection
,
1010 SectionImageInformation
,
1020 * Get some information about the process
1022 NtQueryInformationProcess(hProcess
,
1023 ProcessBasicInformation
,
1025 sizeof(ProcessBasicInfo
),
1027 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1028 ProcessBasicInfo
.UniqueProcessId
);
1029 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1032 * Tell the csrss server we are creating a new process
1034 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
1035 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
1036 ProcessBasicInfo
.UniqueProcessId
;
1037 if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1039 /* Do not create a console for GUI applications */
1040 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1041 dwCreationFlags
|= DETACHED_PROCESS
;
1043 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
1044 Status
= CsrClientCallServer(&CsrRequest
,
1046 sizeof(CSRSS_API_REQUEST
),
1047 sizeof(CSRSS_API_REPLY
));
1048 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1050 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1053 // Set the child console handles
1054 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
1055 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
1056 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
1058 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
1060 if (lpStartupInfo
->hStdInput
)
1061 Ppb
->hStdInput
= lpStartupInfo
->hStdInput
;
1062 if (lpStartupInfo
->hStdOutput
)
1063 Ppb
->hStdOutput
= lpStartupInfo
->hStdOutput
;
1064 if (lpStartupInfo
->hStdError
)
1065 Ppb
->hStdError
= lpStartupInfo
->hStdError
;
1068 if (IsConsoleHandle(Ppb
->hStdInput
))
1070 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1074 DPRINT("Duplicate input handle\n");
1075 Status
= NtDuplicateObject (NtCurrentProcess(),
1081 DUPLICATE_SAME_ACCESS
);
1082 if(!NT_SUCCESS(Status
))
1084 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1088 if (IsConsoleHandle(Ppb
->hStdOutput
))
1090 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1094 DPRINT("Duplicate output handle\n");
1095 Status
= NtDuplicateObject (NtCurrentProcess(),
1101 DUPLICATE_SAME_ACCESS
);
1102 if(!NT_SUCCESS(Status
))
1104 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1107 if (IsConsoleHandle(Ppb
->hStdError
))
1109 CsrRequest
.Type
= CSRSS_DUPLICATE_HANDLE
;
1110 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1111 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1112 Status
= CsrClientCallServer(&CsrRequest
,
1114 sizeof(CSRSS_API_REQUEST
),
1115 sizeof(CSRSS_API_REPLY
));
1116 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1118 Ppb
->hStdError
= INVALID_HANDLE_VALUE
;
1122 Ppb
->hStdError
= CsrReply
.Data
.DuplicateHandleReply
.Handle
;
1127 DPRINT("Duplicate error handle\n");
1128 Status
= NtDuplicateObject (NtCurrentProcess(),
1134 DUPLICATE_SAME_ACCESS
);
1135 if(!NT_SUCCESS(Status
))
1137 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1142 * Initialize some other fields in the PPB
1146 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1147 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1149 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1153 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
1155 Ppb
->dwX
= lpStartupInfo
->dwX
;
1156 Ppb
->dwY
= lpStartupInfo
->dwY
;
1157 Ppb
->dwXSize
= lpStartupInfo
->dwXSize
;
1158 Ppb
->dwYSize
= lpStartupInfo
->dwYSize
;
1159 Ppb
->dwFillAttribute
= lpStartupInfo
->dwFillAttribute
;
1167 * Create Process Environment Block
1169 DPRINT("Creating peb\n");
1171 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
);
1173 RtlDestroyProcessParameters (Ppb
);
1175 Status
= NtSetInformationProcess(hProcess
,
1176 ProcessImageFileName
,
1180 * Create the thread for the kernel
1182 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1183 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
);
1184 hThread
= KlCreateFirstThread(hProcess
,
1187 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
,
1189 &lpProcessInformation
->dwThreadId
);
1190 if (hThread
== INVALID_HANDLE_VALUE
)
1195 lpProcessInformation
->hProcess
= hProcess
;
1196 lpProcessInformation
->hThread
= hThread
;