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 ****************************************************************/
15 #include <pseh/framebased.h>
18 #include "../include/debug.h"
20 /* FUNCTIONS ****************************************************************/
22 extern __declspec(noreturn
)
23 VOID CALLBACK
ConsoleControlDispatcher(DWORD CodeAndFlag
);
26 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine
;
28 typedef NTSTATUS
STDCALL (K32_MBSTR_TO_WCSTR
)
35 NTSTATUS STDCALL K32MbStrToWcStr
37 IN K32_MBSTR_TO_WCSTR
* True
,
38 UNICODE_STRING
* DestStr
,
39 ANSI_STRING
* SourceStr
,
43 if(SourceStr
->Buffer
== NULL
)
45 DestStr
->Length
= DestStr
->MaximumLength
= 0;
46 DestStr
->Buffer
= NULL
;
47 return STATUS_SUCCESS
;
50 return True(DestStr
, SourceStr
, Allocate
);
53 VOID STDCALL RtlRosR32AttribsToNativeAttribs
55 OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
56 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
59 NativeAttribs
->Length
= sizeof(*NativeAttribs
);
60 NativeAttribs
->ObjectName
= NULL
;
61 NativeAttribs
->RootDirectory
= NULL
;
62 NativeAttribs
->Attributes
= 0;
63 NativeAttribs
->SecurityQualityOfService
= NULL
;
66 if(Ros32Attribs
!= NULL
&& Ros32Attribs
->nLength
>= sizeof(*Ros32Attribs
))
68 NativeAttribs
->SecurityDescriptor
= Ros32Attribs
->lpSecurityDescriptor
;
70 if(Ros32Attribs
->bInheritHandle
)
71 NativeAttribs
->Attributes
|= OBJ_INHERIT
;
74 NativeAttribs
->SecurityDescriptor
= NULL
;
77 VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed
79 OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
80 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
,
81 OUT UNICODE_STRING
* NativeName OPTIONAL
,
82 IN WCHAR
* Ros32Name OPTIONAL
,
83 IN HANDLE Ros32NameRoot OPTIONAL
86 if(!NativeAttribs
) return;
88 RtlRosR32AttribsToNativeAttribs(NativeAttribs
, Ros32Attribs
);
90 if(Ros32Name
!= NULL
&& NativeName
!= NULL
)
92 RtlInitUnicodeString(NativeName
, Ros32Name
);
94 NativeAttribs
->ObjectName
= NativeName
;
95 NativeAttribs
->RootDirectory
= Ros32NameRoot
;
96 NativeAttribs
->Attributes
|= OBJ_CASE_INSENSITIVE
;
104 BOOL STDCALL
CreateProcessA(LPCSTR lpApplicationName
,
106 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
107 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
108 BOOL bInheritHandles
,
109 DWORD dwCreationFlags
,
110 LPVOID lpEnvironment
,
111 LPCSTR lpCurrentDirectory
,
112 LPSTARTUPINFOA lpStartupInfo
,
113 LPPROCESS_INFORMATION lpProcessInformation
)
115 * FUNCTION: The CreateProcess function creates a new process and its
116 * primary thread. The new process executes the specified executable file
119 * lpApplicationName = Pointer to name of executable module
120 * lpCommandLine = Pointer to command line string
121 * lpProcessAttributes = Process security attributes
122 * lpThreadAttributes = Thread security attributes
123 * bInheritHandles = Handle inheritance flag
124 * dwCreationFlags = Creation flags
125 * lpEnvironment = Pointer to new environment block
126 * lpCurrentDirectory = Pointer to current directory name
127 * lpStartupInfo = Pointer to startup info
128 * lpProcessInformation = Pointer to process information
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 UNICODE_STRING wstrEnvVar
;
138 ANSI_STRING strApplicationName
;
139 ANSI_STRING strCurrentDirectory
;
140 ANSI_STRING strCommandLine
;
141 ANSI_STRING strReserved
;
142 ANSI_STRING strDesktop
;
143 ANSI_STRING strTitle
;
145 STARTUPINFOW wsiStartupInfo
;
147 NTSTATUS
STDCALL_FUNC (*pTrue
)
154 ULONG
STDCALL_FUNC (*pRtlMbStringToUnicodeSize
)(ANSI_STRING
*);
156 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
157 "lpStartupInfo %x, lpProcessInformation %x\n",
158 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
159 lpStartupInfo
, lpProcessInformation
);
161 /* multibyte strings are ANSI */
164 pTrue
= RtlAnsiStringToUnicodeString
;
165 pRtlMbStringToUnicodeSize
= RtlAnsiStringToUnicodeSize
;
167 /* multibyte strings are OEM */
170 pTrue
= RtlOemStringToUnicodeString
;
171 pRtlMbStringToUnicodeSize
= RtlOemStringToUnicodeSize
;
174 /* invalid parameter */
175 if(lpStartupInfo
== NULL
)
177 SetLastError(ERROR_INVALID_PARAMETER
);
181 /* convert the environment */
182 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
186 ANSI_STRING strEnvVar
;
189 /* scan the environment to calculate its Unicode size */
190 pcScan
= lpEnvironment
;
193 pcScan
+= strlen(pcScan
) + 1;
197 nEnvLen
= (ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ 1;
199 /* environment too large */
200 if(nEnvLen
> ~((USHORT
)0))
202 SetLastError(ERROR_OUTOFMEMORY
);
206 strEnvVar
.Buffer
= lpEnvironment
;
207 strEnvVar
.MaximumLength
= strEnvVar
.Length
= nEnvLen
;
209 Status
= K32MbStrToWcStr(pTrue
, &wstrEnvVar
, &strEnvVar
, TRUE
);
212 if (!NT_SUCCESS(Status
))
214 SetLastError(ERROR_OUTOFMEMORY
);
220 /* convert the strings */
221 RtlInitAnsiString(&strCommandLine
, lpCommandLine
);
222 RtlInitAnsiString(&strApplicationName
, (LPSTR
)lpApplicationName
);
223 RtlInitAnsiString(&strCurrentDirectory
, (LPSTR
)lpCurrentDirectory
);
224 RtlInitAnsiString(&strReserved
, (LPSTR
)lpStartupInfo
->lpReserved
);
225 RtlInitAnsiString(&strDesktop
, (LPSTR
)lpStartupInfo
->lpDesktop
);
226 RtlInitAnsiString(&strTitle
, (LPSTR
)lpStartupInfo
->lpTitle
);
228 K32MbStrToWcStr(pTrue
, &wstrCommandLine
, &strCommandLine
, TRUE
);
229 K32MbStrToWcStr(pTrue
, &wstrApplicationName
, &strApplicationName
, TRUE
);
230 K32MbStrToWcStr(pTrue
, &wstrCurrentDirectory
, &strCurrentDirectory
, TRUE
);
231 K32MbStrToWcStr(pTrue
, &wstrReserved
, &strReserved
, TRUE
);
232 K32MbStrToWcStr(pTrue
, &wstrDesktop
, &strDesktop
, TRUE
);
233 K32MbStrToWcStr(pTrue
, &wstrTitle
, &strTitle
, TRUE
);
235 /* convert the startup information */
236 memcpy(&wsiStartupInfo
, lpStartupInfo
, sizeof(wsiStartupInfo
));
238 wsiStartupInfo
.lpReserved
= wstrReserved
.Buffer
;
239 wsiStartupInfo
.lpDesktop
= wstrDesktop
.Buffer
;
240 wsiStartupInfo
.lpTitle
= wstrTitle
.Buffer
;
242 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName
);
243 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine
);
244 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory
);
245 DPRINT("wstrReserved %wZ\n", &wstrReserved
);
246 DPRINT("wstrDesktop %wZ\n", &wstrDesktop
);
247 DPRINT("wstrTitle %wZ\n", &wstrTitle
);
249 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName
.Buffer
);
250 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine
.Buffer
);
251 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory
.Buffer
);
252 DPRINT("wstrReserved.Buffer %p\n", wstrReserved
.Buffer
);
253 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop
.Buffer
);
254 DPRINT("wstrTitle.Buffer %p\n", wstrTitle
.Buffer
);
256 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA
));
257 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW
));
259 /* call the Unicode function */
260 bRetVal
= CreateProcessW(wstrApplicationName
.Buffer
,
261 wstrCommandLine
.Buffer
,
266 !lpEnvironment
|| (dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
) ? lpEnvironment
: wstrEnvVar
.Buffer
,
267 wstrCurrentDirectory
.Buffer
,
269 lpProcessInformation
);
271 RtlFreeUnicodeString(&wstrApplicationName
);
272 RtlFreeUnicodeString(&wstrCommandLine
);
273 RtlFreeUnicodeString(&wstrCurrentDirectory
);
274 RtlFreeUnicodeString(&wstrReserved
);
275 RtlFreeUnicodeString(&wstrDesktop
);
276 RtlFreeUnicodeString(&wstrTitle
);
278 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
280 RtlFreeUnicodeString(&wstrEnvVar
);
287 static EXCEPTION_DISPOSITION __cdecl
288 _except_handler(EXCEPTION_RECORD
*ExceptionRecord
,
289 void * EstablisherFrame
,
290 CONTEXT
*ContextRecord
,
291 void * DispatcherContext
)
293 EXCEPTION_POINTERS ExceptionInfo
;
294 EXCEPTION_DISPOSITION ExceptionDisposition
;
296 ExceptionInfo
.ExceptionRecord
= ExceptionRecord
;
297 ExceptionInfo
.ContextRecord
= ContextRecord
;
299 if (GlobalTopLevelExceptionFilter
!= NULL
)
303 ExceptionDisposition
= GlobalTopLevelExceptionFilter(&ExceptionInfo
);
307 ExceptionDisposition
= UnhandledExceptionFilter(&ExceptionInfo
);
313 ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
316 if (ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
)
317 ExitProcess(ExceptionRecord
->ExceptionCode
);
319 /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
320 if (ExceptionDisposition
== EXCEPTION_CONTINUE_EXECUTION
)
321 return ExceptionContinueExecution
;
322 else if (ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
)
323 return ExceptionContinueSearch
;
325 return -1; /* unknown return from UnhandledExceptionFilter */
330 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
335 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
337 __try1(_except_handler
)
339 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
342 ExitProcess(uExitCode
);
346 HANDLE STDCALL KlCreateFirstThread
348 HANDLE ProcessHandle
,
349 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
350 PSECTION_IMAGE_INFORMATION Sii
,
351 LPTHREAD_START_ROUTINE lpStartAddress
,
352 DWORD dwCreationFlags
,
356 OBJECT_ATTRIBUTES oaThreadAttribs
;
357 CLIENT_ID cidClientId
;
358 PVOID pTrueStartAddress
;
362 /* convert the thread attributes */
363 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs
, lpThreadAttributes
);
366 if(Sii
->Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
367 pTrueStartAddress
= (PVOID
)BaseProcessStart
;
370 pTrueStartAddress
= (PVOID
)RtlBaseProcessStartRoutine
;
374 "RtlRosCreateUserThreadVa\n"
376 " ProcessHandle %p,\n"
377 " ObjectAttributes %p,\n"
378 " CreateSuspended %d,\n"
379 " StackZeroBits %d,\n"
380 " StackReserve %lu,\n"
381 " StackCommit %lu,\n"
382 " StartAddress %p,\n"
383 " ThreadHandle %p,\n"
385 " ParameterCount %u,\n"
386 " Parameters[0] %p,\n"
387 " Parameters[1] %p\n"
391 dwCreationFlags
& CREATE_SUSPENDED
,
403 /* create the first thread */
404 nErrCode
= RtlRosCreateUserThreadVa
408 dwCreationFlags
& CREATE_SUSPENDED
,
410 &(Sii
->StackReserve
),
416 (ULONG_PTR
)lpStartAddress
,
421 if(!NT_SUCCESS(nErrCode
))
423 SetLastErrorByStatus(nErrCode
);
432 "ClientId.UniqueThread %p\n",
436 cidClientId
.UniqueThread
440 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
444 HANDLE
KlMapFile(LPCWSTR lpApplicationName
)
447 IO_STATUS_BLOCK IoStatusBlock
;
448 UNICODE_STRING ApplicationNameString
;
449 OBJECT_ATTRIBUTES ObjectAttributes
;
450 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
457 * Find the application name
460 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
461 &ApplicationNameString
,
466 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
468 InitializeObjectAttributes(&ObjectAttributes
,
469 &ApplicationNameString
,
470 OBJ_CASE_INSENSITIVE
,
475 * Try to open the executable
478 Status
= NtOpenFile(&hFile
,
479 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
482 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
483 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
485 RtlFreeUnicodeString (&ApplicationNameString
);
487 if (!NT_SUCCESS(Status
))
489 DPRINT("Failed to open file\n");
490 SetLastErrorByStatus (Status
);
494 Status
= NtCreateSection(&hSection
,
503 if (!NT_SUCCESS(Status
))
505 DPRINT("Failed to create section\n");
506 SetLastErrorByStatus (Status
);
513 static NTSTATUS KlInitPeb
515 HANDLE ProcessHandle
,
516 PRTL_USER_PROCESS_PARAMETERS Ppb
,
517 PVOID
* ImageBaseAddress
,
526 PVOID ParentEnv
= NULL
;
529 ULONG EnvSize
= 0, EnvSize1
= 0;
531 /* create the Environment */
532 if (Ppb
->Environment
!= NULL
)
534 ParentEnv
= Ppb
->Environment
;
541 EnvSize
= (PVOID
)ptr
- ParentEnv
;
543 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
545 MEMORY_BASIC_INFORMATION MemInfo
;
546 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
548 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
550 MemoryBasicInformation
,
552 sizeof(MEMORY_BASIC_INFORMATION
),
554 if (!NT_SUCCESS(Status
))
558 EnvSize
= MemInfo
.RegionSize
;
560 DPRINT("EnvironmentSize %ld\n", EnvSize
);
562 /* allocate and initialize new environment block */
566 Status
= NtAllocateVirtualMemory(ProcessHandle
,
570 MEM_RESERVE
| MEM_COMMIT
,
572 if (!NT_SUCCESS(Status
))
577 NtWriteVirtualMemory(ProcessHandle
,
586 PpbSize
= Ppb
->AllocationSize
;
587 Status
= NtAllocateVirtualMemory(ProcessHandle
,
591 MEM_RESERVE
| MEM_COMMIT
,
593 if (!NT_SUCCESS(Status
))
598 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
599 NtWriteVirtualMemory(ProcessHandle
,
605 /* write pointer to environment */
606 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
607 NtWriteVirtualMemory(ProcessHandle
,
608 (PVOID
)(PpbBase
+ Offset
),
613 /* write pointer to process parameter block */
614 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
615 NtWriteVirtualMemory(ProcessHandle
,
616 (PVOID
)(PEB_BASE
+ Offset
),
621 /* Write image subsystem */
622 Offset
= FIELD_OFFSET(PEB
, ImageSubSystem
);
623 NtWriteVirtualMemory(ProcessHandle
,
624 (PVOID
)(PEB_BASE
+ Offset
),
626 sizeof(ImageSubSystem
),
629 /* Read image base address. */
630 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
631 NtReadVirtualMemory(ProcessHandle
,
632 (PVOID
)(PEB_BASE
+ Offset
),
637 return(STATUS_SUCCESS
);
641 /*************************************************************************
644 * Helper for CreateProcessW: retrieve the file name to load from the
645 * app name and command line. Store the file name in buffer, and
646 * return a possibly modified command line.
648 * FIXME: use CurDir to search for the executable file in the new working directory
650 static LPWSTR FASTCALL
651 GetFileName(LPCWSTR CurDir
, LPCWSTR AppName
, LPWSTR CmdLine
, LPWSTR Buffer
,
654 WCHAR
*Name
, *Pos
, *Ret
= NULL
;
657 /* if we have an app name, everything is easy */
661 /* use the unmodified app name as file name */
662 wcsncpy(Buffer
, AppName
, BufLen
);
664 if (NULL
== Ret
|| L
'\0' == CmdLine
[0])
666 /* no command-line, create one */
667 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName
) + 3) * sizeof(WCHAR
));
671 wcscpy(Ret
+ 1, AppName
);
680 SetLastError(ERROR_INVALID_PARAMETER
);
684 /* first check for a quoted file name */
685 if (L
'"' == CmdLine
[0] && NULL
!= (p
= wcschr(CmdLine
+ 1, L
'"')))
687 int Len
= p
- CmdLine
- 1;
688 /* extract the quoted portion as file name */
689 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (Len
+ 1) * sizeof(WCHAR
));
694 memcpy(Name
, CmdLine
+ 1, Len
* sizeof(WCHAR
));
697 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
699 Ret
= CmdLine
; /* no change necessary */
702 RtlFreeHeap(GetProcessHeap(), 0, Name
);
706 /* now try the command-line word by word */
707 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 1) * sizeof(WCHAR
));
721 while (L
'\0' != *p
&& L
' ' != *p
);
723 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
730 if (NULL
== Ret
|| NULL
== wcschr(Name
, L
' '))
732 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
736 /* now build a new command-line with quotes */
737 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 3) * sizeof(WCHAR
));
740 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
744 wcscpy(Ret
+ 1, Name
);
748 RtlFreeHeap(GetProcessHeap(), 0, Name
);
759 LPCWSTR lpApplicationName
,
760 LPWSTR lpCommandLine
,
761 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
762 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
763 BOOL bInheritHandles
,
764 DWORD dwCreationFlags
,
765 LPVOID lpEnvironment
,
766 LPCWSTR lpCurrentDirectory
,
767 LPSTARTUPINFOW lpStartupInfo
,
768 LPPROCESS_INFORMATION lpProcessInformation
771 HANDLE hSection
, hProcess
, hThread
;
773 WCHAR ImagePathName
[256];
774 UNICODE_STRING ImagePathName_U
;
775 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
777 PRTL_USER_PROCESS_PARAMETERS Ppb
;
778 UNICODE_STRING CommandLine_U
;
779 CSRSS_API_REQUEST CsrRequest
;
780 CSRSS_API_REPLY CsrReply
;
783 UNICODE_STRING CurrentDirectory_U
;
784 SECTION_IMAGE_INFORMATION Sii
;
785 WCHAR TempCurrentDirectoryW
[256];
786 WCHAR TempApplicationNameW
[256];
787 WCHAR TempCommandLineNameW
[256];
788 UNICODE_STRING RuntimeInfo_U
;
789 PVOID ImageBaseAddress
;
790 BOOL InputSet
, OutputSet
, ErrorSet
;
791 BOOL InputDup
= FALSE
, OutputDup
= FALSE
, ErrorDup
= FALSE
;
792 WCHAR Name
[MAX_PATH
];
794 BOOL IsBatchFile
= FALSE
;
795 PROCESS_PRIORITY_CLASS PriorityClass
;
796 OBJECT_ATTRIBUTES ProcObjectAttributes
;
797 ULONG ProcAttributes
= 0;
798 PVOID ProcSecurity
= NULL
;
800 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
801 lpApplicationName
, lpCommandLine
);
803 TidyCmdLine
= GetFileName(lpCurrentDirectory
, lpApplicationName
, lpCommandLine
, Name
,
804 sizeof(Name
) / sizeof(WCHAR
));
805 if (NULL
== TidyCmdLine
)
809 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
811 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
813 wcscpy (TempApplicationNameW
, lpApplicationName
);
814 i
= wcslen(TempApplicationNameW
);
815 if (TempApplicationNameW
[i
- 1] == L
'.')
817 TempApplicationNameW
[i
- 1] = 0;
821 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
824 s
= TempApplicationNameW
;
830 e
= wcsrchr(s
, L
'.');
834 e
= wcsrchr(s
, L
'.');
838 else if (L
'"' == TidyCmdLine
[0])
840 wcscpy(TempApplicationNameW
, TidyCmdLine
+ 1);
841 s
= wcschr(TempApplicationNameW
, L
'"');
850 wcscpy(TempApplicationNameW
, TidyCmdLine
);
851 s
= wcschr(TempApplicationNameW
, L
' ');
857 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
860 s
= TempApplicationNameW
;
862 s
= wcsrchr(s
, L
'.');
865 wcscat(TempApplicationNameW
, L
".exe");
868 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
873 e
= wcsrchr(s
, L
'.');
874 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
876 // the command is a batch file
878 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
880 // FIXME: use COMSPEC for the command interpreter
881 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
882 wcscat(TempCommandLineNameW
, lpApplicationName
);
883 lpCommandLine
= TempCommandLineNameW
;
884 wcscpy(TempApplicationNameW
, L
"cmd.exe");
885 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
897 * Process the application name and command line
899 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
900 RtlInitUnicodeString(&CommandLine_U
, IsBatchFile
? lpCommandLine
: TidyCmdLine
);
902 DPRINT("ImagePathName_U '%S'\n", ImagePathName_U
.Buffer
);
903 DPRINT("lpCommandLine '%S'\n", lpCommandLine
);
904 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
906 /* Initialize the current directory string */
907 if (lpCurrentDirectory
!= NULL
)
909 RtlInitUnicodeString(&CurrentDirectory_U
,
914 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
915 RtlInitUnicodeString(&CurrentDirectory_U
,
916 TempCurrentDirectoryW
);
920 * Create a section for the executable
923 hSection
= KlMapFile (ImagePathName
);
924 if (hSection
== NULL
)
926 /////////////////////////////////////////
928 * Inspect the image to determine executable flavour
930 IO_STATUS_BLOCK IoStatusBlock
;
931 UNICODE_STRING ApplicationNameString
;
932 OBJECT_ATTRIBUTES ObjectAttributes
;
933 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
934 IMAGE_DOS_HEADER DosHeader
;
935 IO_STATUS_BLOCK Iosb
;
936 LARGE_INTEGER Offset
;
939 DPRINT("Inspecting Image Header for image type id\n");
941 // Find the application name
942 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
943 &ApplicationNameString
, NULL
, NULL
)) {
946 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
948 InitializeObjectAttributes(&ObjectAttributes
,
949 &ApplicationNameString
,
950 OBJ_CASE_INSENSITIVE
,
954 // Try to open the executable
955 Status
= NtOpenFile(&hFile
,
956 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
959 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
960 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
962 RtlFreeUnicodeString(&ApplicationNameString
);
964 if (!NT_SUCCESS(Status
)) {
965 DPRINT("Failed to open file\n");
966 SetLastErrorByStatus(Status
);
970 // Read the dos header
972 Status
= ZwReadFile(hFile
,
982 if (!NT_SUCCESS(Status
)) {
983 DPRINT("Failed to read from file\n");
984 SetLastErrorByStatus(Status
);
987 if (Iosb
.Information
!= sizeof(DosHeader
)) {
988 DPRINT("Failed to read dos header from file\n");
989 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
993 // Check the DOS signature
994 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) {
995 DPRINT("Failed dos magic check\n");
996 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
1001 DPRINT("Launching VDM...\n");
1002 return CreateProcessW(L
"ntvdm.exe",
1003 (LPWSTR
)lpApplicationName
,
1004 lpProcessAttributes
,
1011 lpProcessInformation
);
1013 /////////////////////////////////////////
1016 * Get some information about the executable
1018 Status
= ZwQuerySection(hSection
,
1019 SectionImageInformation
,
1023 if (! NT_SUCCESS(Status
))
1026 DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status
);
1027 SetLastErrorByStatus(Status
);
1031 if (0 != (Sii
.Characteristics
& IMAGE_FILE_DLL
))
1034 DPRINT("Can't execute a DLL\n");
1035 SetLastError(ERROR_BAD_EXE_FORMAT
);
1039 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= Sii
.Subsystem
1040 && IMAGE_SUBSYSTEM_WINDOWS_CUI
!= Sii
.Subsystem
)
1043 DPRINT("Invalid subsystem %d\n", Sii
.Subsystem
);
1044 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
1049 * Initialize the process object attributes
1052 if(lpProcessAttributes
!= NULL
)
1054 if(lpProcessAttributes
->bInheritHandle
)
1056 ProcAttributes
|= OBJ_INHERIT
;
1058 ProcSecurity
= lpProcessAttributes
->lpSecurityDescriptor
;
1061 InitializeObjectAttributes(&ProcObjectAttributes
,
1067 * initialize the process priority class structure
1069 PriorityClass
.Foreground
= FALSE
;
1071 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
1073 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1075 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
1077 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1079 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
1081 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1083 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
1085 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1087 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
1089 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1091 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
1093 /* FIXME - This is a privileged operation. If we don't have the privilege we should
1094 rather use PROCESS_PRIORITY_CLASS_HIGH. */
1095 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
1099 /* FIXME - what to do in this case? */
1100 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1104 * Create a new process
1106 Status
= NtCreateProcess(&hProcess
,
1108 &ProcObjectAttributes
,
1114 /* FIXME - handle failure!!!!! */
1116 Status
= NtSetInformationProcess(hProcess
,
1117 ProcessPriorityClass
,
1119 sizeof(PROCESS_PRIORITY_CLASS
));
1120 /* FIXME - handle failure!!!!! */
1124 if (lpStartupInfo
->lpReserved2
)
1127 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1128 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1129 * If is possible that this function overwrite the last information in runtimeinfo
1130 * with the null terminator for the unicode string.
1132 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= ROUND_UP(lpStartupInfo
->cbReserved2
, 2) + 2;
1133 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
1134 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
1141 RtlCreateProcessParameters(&Ppb
,
1144 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
1150 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
1152 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
1153 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
1157 * Translate some handles for the new process
1159 if (Ppb
->CurrentDirectoryHandle
)
1161 Status
= NtDuplicateObject (NtCurrentProcess(),
1162 Ppb
->CurrentDirectoryHandle
,
1164 &Ppb
->CurrentDirectoryHandle
,
1167 DUPLICATE_SAME_ACCESS
);
1168 /* FIXME - handle failure!!!!! */
1177 * Get some information about the process
1179 NtQueryInformationProcess(hProcess
,
1180 ProcessBasicInformation
,
1182 sizeof(ProcessBasicInfo
),
1184 DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
1185 ProcessBasicInfo
.UniqueProcessId
);
1186 lpProcessInformation
->dwProcessId
= (DWORD
)ProcessBasicInfo
.UniqueProcessId
;
1189 * Tell the csrss server we are creating a new process
1191 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
1192 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
1193 ProcessBasicInfo
.UniqueProcessId
;
1194 if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1196 /* Do not create a console for GUI applications */
1197 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1198 dwCreationFlags
|= DETACHED_PROCESS
;
1200 else if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
1202 if (NULL
== Ppb
->hConsole
)
1204 dwCreationFlags
|= CREATE_NEW_CONSOLE
;
1207 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
1208 CsrRequest
.Data
.CreateProcessRequest
.CtrlDispatcher
= ConsoleControlDispatcher
;
1209 Status
= CsrClientCallServer(&CsrRequest
,
1211 sizeof(CSRSS_API_REQUEST
),
1212 sizeof(CSRSS_API_REPLY
));
1213 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1215 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1218 Ppb
->hConsole
= CsrReply
.Data
.CreateProcessReply
.Console
;
1224 /* Set the child console handles */
1226 /* First check if handles were passed in startup info */
1227 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
1229 if (lpStartupInfo
->hStdInput
)
1231 Ppb
->hStdInput
= lpStartupInfo
->hStdInput
;
1235 if (lpStartupInfo
->hStdOutput
)
1237 Ppb
->hStdOutput
= lpStartupInfo
->hStdOutput
;
1241 if (lpStartupInfo
->hStdError
)
1243 Ppb
->hStdError
= lpStartupInfo
->hStdError
;
1249 /* Check if new console was created, use it for input and output if
1251 if (0 != (dwCreationFlags
& CREATE_NEW_CONSOLE
)
1252 && NT_SUCCESS(Status
) && NT_SUCCESS(CsrReply
.Status
))
1256 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1262 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1268 Ppb
->hStdError
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1274 /* Use existing handles otherwise */
1277 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
1282 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
1287 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
1291 /* Now duplicate handles if required */
1294 if (IsConsoleHandle(Ppb
->hStdInput
))
1296 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1300 DPRINT("Duplicate input handle\n");
1301 Status
= NtDuplicateObject (NtCurrentProcess(),
1307 DUPLICATE_SAME_ACCESS
);
1308 if(!NT_SUCCESS(Status
))
1310 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1317 if (IsConsoleHandle(Ppb
->hStdOutput
))
1319 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1323 DPRINT("Duplicate output handle\n");
1324 Status
= NtDuplicateObject (NtCurrentProcess(),
1330 DUPLICATE_SAME_ACCESS
);
1331 if(!NT_SUCCESS(Status
))
1333 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1340 if (IsConsoleHandle(Ppb
->hStdError
))
1342 CsrRequest
.Type
= CSRSS_DUPLICATE_HANDLE
;
1343 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1344 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1345 Status
= CsrClientCallServer(&CsrRequest
,
1347 sizeof(CSRSS_API_REQUEST
),
1348 sizeof(CSRSS_API_REPLY
));
1349 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1351 Ppb
->hStdError
= INVALID_HANDLE_VALUE
;
1355 Ppb
->hStdError
= CsrReply
.Data
.DuplicateHandleReply
.Handle
;
1360 DPRINT("Duplicate error handle\n");
1361 Status
= NtDuplicateObject (NtCurrentProcess(),
1367 DUPLICATE_SAME_ACCESS
);
1368 if(!NT_SUCCESS(Status
))
1370 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1376 * Initialize some other fields in the PPB
1380 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1381 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1383 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1387 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
1389 Ppb
->dwX
= lpStartupInfo
->dwX
;
1390 Ppb
->dwY
= lpStartupInfo
->dwY
;
1391 Ppb
->dwXSize
= lpStartupInfo
->dwXSize
;
1392 Ppb
->dwYSize
= lpStartupInfo
->dwYSize
;
1393 Ppb
->dwFillAttribute
= lpStartupInfo
->dwFillAttribute
;
1401 * Create Process Environment Block
1403 DPRINT("Creating peb\n");
1405 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
, Sii
.Subsystem
);
1407 RtlDestroyProcessParameters (Ppb
);
1410 * Create the thread for the kernel
1412 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1413 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ Sii
.EntryPoint
));
1414 hThread
= KlCreateFirstThread(hProcess
,
1417 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ Sii
.EntryPoint
),
1419 &lpProcessInformation
->dwThreadId
);
1420 if (hThread
== INVALID_HANDLE_VALUE
)
1425 lpProcessInformation
->hProcess
= hProcess
;
1426 lpProcessInformation
->hThread
= hThread
;