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(IN K32_MBSTR_TO_WCSTR
* True
,
36 UNICODE_STRING
* DestStr
,
37 ANSI_STRING
* SourceStr
,
40 if(SourceStr
->Buffer
== NULL
)
42 DestStr
->Length
= DestStr
->MaximumLength
= 0;
43 DestStr
->Buffer
= NULL
;
44 return STATUS_SUCCESS
;
47 return True(DestStr
, SourceStr
, Allocate
);
50 VOID STDCALL
RtlRosR32AttribsToNativeAttribs(OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
51 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
)
53 NativeAttribs
->Length
= sizeof(*NativeAttribs
);
54 NativeAttribs
->ObjectName
= NULL
;
55 NativeAttribs
->RootDirectory
= NULL
;
56 NativeAttribs
->Attributes
= 0;
57 NativeAttribs
->SecurityQualityOfService
= NULL
;
60 if(Ros32Attribs
!= NULL
&& Ros32Attribs
->nLength
>= sizeof(*Ros32Attribs
))
62 NativeAttribs
->SecurityDescriptor
= Ros32Attribs
->lpSecurityDescriptor
;
64 if(Ros32Attribs
->bInheritHandle
)
66 NativeAttribs
->Attributes
|= OBJ_INHERIT
;
71 NativeAttribs
->SecurityDescriptor
= NULL
;
75 VOID STDCALL
RtlRosR32AttribsToNativeAttribsNamed(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
)
81 if(!NativeAttribs
) return;
83 RtlRosR32AttribsToNativeAttribs(NativeAttribs
, Ros32Attribs
);
85 if(Ros32Name
!= NULL
&& NativeName
!= NULL
)
87 RtlInitUnicodeString(NativeName
, Ros32Name
);
89 NativeAttribs
->ObjectName
= NativeName
;
90 NativeAttribs
->RootDirectory
= Ros32NameRoot
;
91 NativeAttribs
->Attributes
|= OBJ_CASE_INSENSITIVE
;
99 BOOL STDCALL
CreateProcessA(LPCSTR lpApplicationName
,
101 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
102 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
103 BOOL bInheritHandles
,
104 DWORD dwCreationFlags
,
105 LPVOID lpEnvironment
,
106 LPCSTR lpCurrentDirectory
,
107 LPSTARTUPINFOA lpStartupInfo
,
108 LPPROCESS_INFORMATION lpProcessInformation
)
110 * FUNCTION: The CreateProcess function creates a new process and its
111 * primary thread. The new process executes the specified executable file
114 * lpApplicationName = Pointer to name of executable module
115 * lpCommandLine = Pointer to command line string
116 * lpProcessAttributes = Process security attributes
117 * lpThreadAttributes = Thread security attributes
118 * bInheritHandles = Handle inheritance flag
119 * dwCreationFlags = Creation flags
120 * lpEnvironment = Pointer to new environment block
121 * lpCurrentDirectory = Pointer to current directory name
122 * lpStartupInfo = Pointer to startup info
123 * lpProcessInformation = Pointer to process information
126 UNICODE_STRING wstrApplicationName
;
127 UNICODE_STRING wstrCurrentDirectory
;
128 UNICODE_STRING wstrCommandLine
;
129 UNICODE_STRING wstrReserved
;
130 UNICODE_STRING wstrDesktop
;
131 UNICODE_STRING wstrTitle
;
132 UNICODE_STRING wstrEnvVar
;
133 ANSI_STRING strApplicationName
;
134 ANSI_STRING strCurrentDirectory
;
135 ANSI_STRING strCommandLine
;
136 ANSI_STRING strReserved
;
137 ANSI_STRING strDesktop
;
138 ANSI_STRING strTitle
;
140 STARTUPINFOW wsiStartupInfo
;
142 NTSTATUS
STDCALL_FUNC (*pTrue
)(UNICODE_STRING
*,
146 ULONG
STDCALL_FUNC (*pRtlMbStringToUnicodeSize
)(ANSI_STRING
*);
148 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
149 "lpStartupInfo %x, lpProcessInformation %x\n",
150 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
151 lpStartupInfo
, lpProcessInformation
);
153 /* multibyte strings are ANSI */
156 pTrue
= RtlAnsiStringToUnicodeString
;
157 pRtlMbStringToUnicodeSize
= RtlAnsiStringToUnicodeSize
;
159 /* multibyte strings are OEM */
162 pTrue
= RtlOemStringToUnicodeString
;
163 pRtlMbStringToUnicodeSize
= RtlOemStringToUnicodeSize
;
166 /* invalid parameter */
167 if(lpStartupInfo
== NULL
)
169 SetLastError(ERROR_INVALID_PARAMETER
);
173 /* convert the environment */
174 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
178 ANSI_STRING strEnvVar
;
181 /* scan the environment to calculate its Unicode size */
182 pcScan
= lpEnvironment
;
185 pcScan
+= strlen(pcScan
) + 1;
189 nEnvLen
= (ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ 1;
191 /* environment too large */
192 if(nEnvLen
> ~((USHORT
)0))
194 SetLastError(ERROR_OUTOFMEMORY
);
198 strEnvVar
.Buffer
= lpEnvironment
;
199 strEnvVar
.MaximumLength
= strEnvVar
.Length
= nEnvLen
;
201 Status
= K32MbStrToWcStr(pTrue
, &wstrEnvVar
, &strEnvVar
, TRUE
);
204 if (!NT_SUCCESS(Status
))
206 SetLastError(ERROR_OUTOFMEMORY
);
212 /* convert the strings */
213 RtlInitAnsiString(&strCommandLine
, lpCommandLine
);
214 RtlInitAnsiString(&strApplicationName
, (LPSTR
)lpApplicationName
);
215 RtlInitAnsiString(&strCurrentDirectory
, (LPSTR
)lpCurrentDirectory
);
216 RtlInitAnsiString(&strReserved
, (LPSTR
)lpStartupInfo
->lpReserved
);
217 RtlInitAnsiString(&strDesktop
, (LPSTR
)lpStartupInfo
->lpDesktop
);
218 RtlInitAnsiString(&strTitle
, (LPSTR
)lpStartupInfo
->lpTitle
);
220 K32MbStrToWcStr(pTrue
, &wstrCommandLine
, &strCommandLine
, TRUE
);
221 K32MbStrToWcStr(pTrue
, &wstrApplicationName
, &strApplicationName
, TRUE
);
222 K32MbStrToWcStr(pTrue
, &wstrCurrentDirectory
, &strCurrentDirectory
, TRUE
);
223 K32MbStrToWcStr(pTrue
, &wstrReserved
, &strReserved
, TRUE
);
224 K32MbStrToWcStr(pTrue
, &wstrDesktop
, &strDesktop
, TRUE
);
225 K32MbStrToWcStr(pTrue
, &wstrTitle
, &strTitle
, TRUE
);
227 /* convert the startup information */
228 memcpy(&wsiStartupInfo
, lpStartupInfo
, sizeof(wsiStartupInfo
));
230 wsiStartupInfo
.lpReserved
= wstrReserved
.Buffer
;
231 wsiStartupInfo
.lpDesktop
= wstrDesktop
.Buffer
;
232 wsiStartupInfo
.lpTitle
= wstrTitle
.Buffer
;
234 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName
);
235 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine
);
236 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory
);
237 DPRINT("wstrReserved %wZ\n", &wstrReserved
);
238 DPRINT("wstrDesktop %wZ\n", &wstrDesktop
);
239 DPRINT("wstrTitle %wZ\n", &wstrTitle
);
241 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName
.Buffer
);
242 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine
.Buffer
);
243 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory
.Buffer
);
244 DPRINT("wstrReserved.Buffer %p\n", wstrReserved
.Buffer
);
245 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop
.Buffer
);
246 DPRINT("wstrTitle.Buffer %p\n", wstrTitle
.Buffer
);
248 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA
));
249 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW
));
251 /* call the Unicode function */
252 bRetVal
= CreateProcessW(wstrApplicationName
.Buffer
,
253 wstrCommandLine
.Buffer
,
258 !lpEnvironment
|| (dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
) ? lpEnvironment
: wstrEnvVar
.Buffer
,
259 wstrCurrentDirectory
.Buffer
,
261 lpProcessInformation
);
263 RtlFreeUnicodeString(&wstrApplicationName
);
264 RtlFreeUnicodeString(&wstrCommandLine
);
265 RtlFreeUnicodeString(&wstrCurrentDirectory
);
266 RtlFreeUnicodeString(&wstrReserved
);
267 RtlFreeUnicodeString(&wstrDesktop
);
268 RtlFreeUnicodeString(&wstrTitle
);
270 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
272 RtlFreeUnicodeString(&wstrEnvVar
);
279 static EXCEPTION_DISPOSITION __cdecl
280 _except_handler(EXCEPTION_RECORD
*ExceptionRecord
,
281 void * EstablisherFrame
,
282 CONTEXT
*ContextRecord
,
283 void * DispatcherContext
)
285 EXCEPTION_POINTERS ExceptionInfo
;
286 EXCEPTION_DISPOSITION ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
288 ExceptionInfo
.ExceptionRecord
= ExceptionRecord
;
289 ExceptionInfo
.ContextRecord
= ContextRecord
;
291 if (GlobalTopLevelExceptionFilter
!= NULL
)
295 ExceptionDisposition
= GlobalTopLevelExceptionFilter(&ExceptionInfo
);
299 ExceptionDisposition
= UnhandledExceptionFilter(&ExceptionInfo
);
304 if (ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
)
305 ExitProcess(ExceptionRecord
->ExceptionCode
);
307 /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
308 if (ExceptionDisposition
== EXCEPTION_CONTINUE_EXECUTION
)
310 return ExceptionContinueExecution
;
312 else if (ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
)
314 return ExceptionContinueSearch
;
317 return -1; /* unknown return from UnhandledExceptionFilter */
322 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
327 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
329 __try1(_except_handler
)
331 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
334 ExitProcess(uExitCode
);
338 HANDLE STDCALL
KlCreateFirstThread(HANDLE ProcessHandle
,
339 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
340 PSECTION_IMAGE_INFORMATION Sii
,
341 LPTHREAD_START_ROUTINE lpStartAddress
,
342 DWORD dwCreationFlags
,
345 OBJECT_ATTRIBUTES oaThreadAttribs
;
346 CLIENT_ID cidClientId
;
347 PVOID pTrueStartAddress
;
351 /* convert the thread attributes */
352 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs
, lpThreadAttributes
);
355 if(Sii
->Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
357 pTrueStartAddress
= (PVOID
)BaseProcessStart
;
362 pTrueStartAddress
= (PVOID
)RtlBaseProcessStartRoutine
;
365 DPRINT("RtlRosCreateUserThreadVa\n"
367 " ProcessHandle %p,\n"
368 " ObjectAttributes %p,\n"
369 " CreateSuspended %d,\n"
370 " StackZeroBits %d,\n"
371 " StackReserve %lu,\n"
372 " StackCommit %lu,\n"
373 " StartAddress %p,\n"
374 " ThreadHandle %p,\n"
376 " ParameterCount %u,\n"
377 " Parameters[0] %p,\n"
378 " Parameters[1] %p\n"
382 dwCreationFlags
& CREATE_SUSPENDED
,
393 /* create the first thread */
394 nErrCode
= RtlRosCreateUserThreadVa(ProcessHandle
,
396 dwCreationFlags
& CREATE_SUSPENDED
,
398 &(Sii
->StackReserve
),
404 (ULONG_PTR
)lpStartAddress
,
405 (ULONG_PTR
)PEB_BASE
);
407 if(!NT_SUCCESS(nErrCode
))
409 SetLastErrorByStatus(nErrCode
);
413 DPRINT("StackReserve %p\n"
416 "ClientId.UniqueThread %p\n",
420 cidClientId
.UniqueThread
);
423 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
427 HANDLE
KlMapFile(LPCWSTR lpApplicationName
)
430 IO_STATUS_BLOCK IoStatusBlock
;
431 UNICODE_STRING ApplicationNameString
;
432 OBJECT_ATTRIBUTES ObjectAttributes
;
433 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
440 * Find the application name
443 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
444 &ApplicationNameString
,
449 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
451 InitializeObjectAttributes(&ObjectAttributes
,
452 &ApplicationNameString
,
453 OBJ_CASE_INSENSITIVE
,
458 * Try to open the executable
461 Status
= NtOpenFile(&hFile
,
462 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
465 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
466 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
468 RtlFreeUnicodeString (&ApplicationNameString
);
470 if (!NT_SUCCESS(Status
))
472 DPRINT("Failed to open file\n");
473 SetLastErrorByStatus (Status
);
477 Status
= NtCreateSection(&hSection
,
486 if (!NT_SUCCESS(Status
))
488 DPRINT("Failed to create section\n");
489 SetLastErrorByStatus (Status
);
496 static NTSTATUS
KlInitPeb(HANDLE ProcessHandle
,
497 PRTL_USER_PROCESS_PARAMETERS Ppb
,
498 PVOID
* ImageBaseAddress
,
499 ULONG ImageSubSystem
)
506 PVOID ParentEnv
= NULL
;
509 ULONG EnvSize
= 0, EnvSize1
= 0;
511 /* create the Environment */
512 if (Ppb
->Environment
!= NULL
)
514 ParentEnv
= Ppb
->Environment
;
521 EnvSize
= (PVOID
)ptr
- ParentEnv
;
523 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
525 MEMORY_BASIC_INFORMATION MemInfo
;
526 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
528 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
530 MemoryBasicInformation
,
532 sizeof(MEMORY_BASIC_INFORMATION
),
534 if (!NT_SUCCESS(Status
))
538 EnvSize
= MemInfo
.RegionSize
;
540 DPRINT("EnvironmentSize %ld\n", EnvSize
);
542 /* allocate and initialize new environment block */
546 Status
= NtAllocateVirtualMemory(ProcessHandle
,
550 MEM_RESERVE
| MEM_COMMIT
,
552 if (!NT_SUCCESS(Status
))
557 NtWriteVirtualMemory(ProcessHandle
,
566 PpbSize
= Ppb
->AllocationSize
;
567 Status
= NtAllocateVirtualMemory(ProcessHandle
,
571 MEM_RESERVE
| MEM_COMMIT
,
573 if (!NT_SUCCESS(Status
))
578 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
579 NtWriteVirtualMemory(ProcessHandle
,
585 /* write pointer to environment */
586 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
587 NtWriteVirtualMemory(ProcessHandle
,
588 (PVOID
)(PpbBase
+ Offset
),
593 /* write pointer to process parameter block */
594 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
595 NtWriteVirtualMemory(ProcessHandle
,
596 (PVOID
)(PEB_BASE
+ Offset
),
601 /* Write image subsystem */
602 Offset
= FIELD_OFFSET(PEB
, ImageSubSystem
);
603 NtWriteVirtualMemory(ProcessHandle
,
604 (PVOID
)(PEB_BASE
+ Offset
),
606 sizeof(ImageSubSystem
),
609 /* Read image base address. */
610 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
611 NtReadVirtualMemory(ProcessHandle
,
612 (PVOID
)(PEB_BASE
+ Offset
),
617 return(STATUS_SUCCESS
);
621 /*************************************************************************
624 * Helper for CreateProcessW: retrieve the file name to load from the
625 * app name and command line. Store the file name in buffer, and
626 * return a possibly modified command line.
628 * FIXME: use CurDir to search for the executable file in the new working directory
630 static LPWSTR FASTCALL
631 GetFileName(LPCWSTR CurDir
, LPCWSTR AppName
, LPWSTR CmdLine
, LPWSTR Buffer
,
634 WCHAR
*Name
, *Pos
, *Ret
= NULL
;
637 /* if we have an app name, everything is easy */
641 /* use the unmodified app name as file name */
642 wcsncpy(Buffer
, AppName
, BufLen
);
644 if (NULL
== Ret
|| L
'\0' == CmdLine
[0])
646 /* no command-line, create one */
647 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName
) + 3) * sizeof(WCHAR
));
651 wcscpy(Ret
+ 1, AppName
);
660 SetLastError(ERROR_INVALID_PARAMETER
);
664 /* first check for a quoted file name */
665 if (L
'"' == CmdLine
[0] && NULL
!= (p
= wcschr(CmdLine
+ 1, L
'"')))
667 int Len
= p
- CmdLine
- 1;
668 /* extract the quoted portion as file name */
669 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (Len
+ 1) * sizeof(WCHAR
));
674 memcpy(Name
, CmdLine
+ 1, Len
* sizeof(WCHAR
));
677 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
679 Ret
= CmdLine
; /* no change necessary */
682 RtlFreeHeap(GetProcessHeap(), 0, Name
);
686 /* now try the command-line word by word */
687 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 1) * sizeof(WCHAR
));
701 while (L
'\0' != *p
&& L
' ' != *p
);
703 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
710 if (NULL
== Ret
|| NULL
== wcschr(Name
, L
' '))
712 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
716 /* now build a new command-line with quotes */
717 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 3) * sizeof(WCHAR
));
720 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
724 wcscpy(Ret
+ 1, Name
);
728 RtlFreeHeap(GetProcessHeap(), 0, Name
);
737 CreateProcessW(LPCWSTR lpApplicationName
,
738 LPWSTR lpCommandLine
,
739 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
740 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
741 BOOL bInheritHandles
,
742 DWORD dwCreationFlags
,
743 LPVOID lpEnvironment
,
744 LPCWSTR lpCurrentDirectory
,
745 LPSTARTUPINFOW lpStartupInfo
,
746 LPPROCESS_INFORMATION lpProcessInformation
)
748 HANDLE hSection
, hProcess
, hThread
;
750 WCHAR ImagePathName
[256];
751 UNICODE_STRING ImagePathName_U
;
752 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
754 PRTL_USER_PROCESS_PARAMETERS Ppb
;
755 UNICODE_STRING CommandLine_U
;
756 CSRSS_API_REQUEST CsrRequest
;
757 CSRSS_API_REPLY CsrReply
;
760 UNICODE_STRING CurrentDirectory_U
;
761 SECTION_IMAGE_INFORMATION Sii
;
762 WCHAR TempCurrentDirectoryW
[256];
763 WCHAR TempApplicationNameW
[256];
764 WCHAR TempCommandLineNameW
[256];
765 UNICODE_STRING RuntimeInfo_U
;
766 PVOID ImageBaseAddress
;
767 BOOL InputSet
, OutputSet
, ErrorSet
;
768 BOOL InputDup
= FALSE
, OutputDup
= FALSE
, ErrorDup
= FALSE
;
769 WCHAR Name
[MAX_PATH
];
771 BOOL IsBatchFile
= FALSE
;
772 PROCESS_PRIORITY_CLASS PriorityClass
;
773 OBJECT_ATTRIBUTES ProcObjectAttributes
;
774 ULONG ProcAttributes
= 0;
775 PVOID ProcSecurity
= NULL
;
777 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
778 lpApplicationName
, lpCommandLine
);
780 TidyCmdLine
= GetFileName(lpCurrentDirectory
, lpApplicationName
, lpCommandLine
, Name
,
781 sizeof(Name
) / sizeof(WCHAR
));
782 if (NULL
== TidyCmdLine
)
786 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
788 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
790 wcscpy (TempApplicationNameW
, lpApplicationName
);
791 i
= wcslen(TempApplicationNameW
);
792 if (TempApplicationNameW
[i
- 1] == L
'.')
794 TempApplicationNameW
[i
- 1] = 0;
798 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
801 s
= TempApplicationNameW
;
807 e
= wcsrchr(s
, L
'.');
811 e
= wcsrchr(s
, L
'.');
815 else if (L
'"' == TidyCmdLine
[0])
817 wcscpy(TempApplicationNameW
, TidyCmdLine
+ 1);
818 s
= wcschr(TempApplicationNameW
, L
'"');
827 wcscpy(TempApplicationNameW
, TidyCmdLine
);
828 s
= wcschr(TempApplicationNameW
, L
' ');
834 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
837 s
= TempApplicationNameW
;
839 s
= wcsrchr(s
, L
'.');
842 wcscat(TempApplicationNameW
, L
".exe");
845 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
850 e
= wcsrchr(s
, L
'.');
851 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
853 // the command is a batch file
855 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
857 // FIXME: use COMSPEC for the command interpreter
858 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
859 wcscat(TempCommandLineNameW
, lpApplicationName
);
860 lpCommandLine
= TempCommandLineNameW
;
861 wcscpy(TempApplicationNameW
, L
"cmd.exe");
862 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
874 * Process the application name and command line
876 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
877 RtlInitUnicodeString(&CommandLine_U
, IsBatchFile
? lpCommandLine
: TidyCmdLine
);
879 DPRINT("ImagePathName_U '%S'\n", ImagePathName_U
.Buffer
);
880 DPRINT("lpCommandLine '%S'\n", lpCommandLine
);
881 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
883 /* Initialize the current directory string */
884 if (lpCurrentDirectory
!= NULL
)
886 RtlInitUnicodeString(&CurrentDirectory_U
,
891 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
892 RtlInitUnicodeString(&CurrentDirectory_U
,
893 TempCurrentDirectoryW
);
897 * Create a section for the executable
900 hSection
= KlMapFile (ImagePathName
);
901 if (hSection
== NULL
)
903 /////////////////////////////////////////
905 * Inspect the image to determine executable flavour
907 IO_STATUS_BLOCK IoStatusBlock
;
908 UNICODE_STRING ApplicationNameString
;
909 OBJECT_ATTRIBUTES ObjectAttributes
;
910 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
911 IMAGE_DOS_HEADER DosHeader
;
912 IO_STATUS_BLOCK Iosb
;
913 LARGE_INTEGER Offset
;
915 DPRINT("Inspecting Image Header for image type id\n");
917 // Find the application name
918 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
919 &ApplicationNameString
, NULL
, NULL
))
923 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
925 InitializeObjectAttributes(&ObjectAttributes
,
926 &ApplicationNameString
,
927 OBJ_CASE_INSENSITIVE
,
931 // Try to open the executable
932 Status
= NtOpenFile(&hFile
,
933 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
936 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
937 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
939 RtlFreeUnicodeString(&ApplicationNameString
);
941 if (!NT_SUCCESS(Status
))
943 DPRINT("Failed to open file\n");
944 SetLastErrorByStatus(Status
);
948 // Read the dos header
950 Status
= ZwReadFile(hFile
,
960 if (!NT_SUCCESS(Status
))
962 DPRINT("Failed to read from file\n");
963 SetLastErrorByStatus(Status
);
966 if (Iosb
.Information
!= sizeof(DosHeader
))
968 DPRINT("Failed to read dos header from file\n");
969 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
973 // Check the DOS signature
974 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
976 DPRINT("Failed dos magic check\n");
977 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
982 DPRINT("Launching VDM...\n");
983 return CreateProcessW(L
"ntvdm.exe",
984 (LPWSTR
)lpApplicationName
,
992 lpProcessInformation
);
994 /////////////////////////////////////////
997 * Get some information about the executable
999 Status
= ZwQuerySection(hSection
,
1000 SectionImageInformation
,
1004 if (! NT_SUCCESS(Status
))
1007 DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status
);
1008 SetLastErrorByStatus(Status
);
1012 if (0 != (Sii
.Characteristics
& IMAGE_FILE_DLL
))
1015 DPRINT("Can't execute a DLL\n");
1016 SetLastError(ERROR_BAD_EXE_FORMAT
);
1020 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= Sii
.Subsystem
1021 && IMAGE_SUBSYSTEM_WINDOWS_CUI
!= Sii
.Subsystem
)
1024 DPRINT("Invalid subsystem %d\n", Sii
.Subsystem
);
1025 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
1030 * Initialize the process object attributes
1033 if(lpProcessAttributes
!= NULL
)
1035 if(lpProcessAttributes
->bInheritHandle
)
1037 ProcAttributes
|= OBJ_INHERIT
;
1039 ProcSecurity
= lpProcessAttributes
->lpSecurityDescriptor
;
1042 InitializeObjectAttributes(&ProcObjectAttributes
,
1048 * initialize the process priority class structure
1050 PriorityClass
.Foreground
= FALSE
;
1052 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
1054 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1056 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
1058 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1060 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
1062 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1064 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
1066 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1068 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
1070 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1072 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
1074 /* FIXME - This is a privileged operation. If we don't have the privilege we should
1075 rather use PROCESS_PRIORITY_CLASS_HIGH. */
1076 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
1080 /* FIXME - what to do in this case? */
1081 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1085 * Create a new process
1087 Status
= NtCreateProcess(&hProcess
,
1089 &ProcObjectAttributes
,
1095 /* FIXME - handle failure!!!!! */
1097 Status
= NtSetInformationProcess(hProcess
,
1098 ProcessPriorityClass
,
1100 sizeof(PROCESS_PRIORITY_CLASS
));
1101 /* FIXME - handle failure!!!!! */
1105 if (lpStartupInfo
->lpReserved2
)
1108 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1109 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1110 * If is possible that this function overwrite the last information in runtimeinfo
1111 * with the null terminator for the unicode string.
1113 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= ROUND_UP(lpStartupInfo
->cbReserved2
, 2) + 2;
1114 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
1115 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
1122 RtlCreateProcessParameters(&Ppb
,
1125 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
1131 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
1133 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
1134 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
1138 * Translate some handles for the new process
1140 if (Ppb
->CurrentDirectoryHandle
)
1142 Status
= NtDuplicateObject (NtCurrentProcess(),
1143 Ppb
->CurrentDirectoryHandle
,
1145 &Ppb
->CurrentDirectoryHandle
,
1148 DUPLICATE_SAME_ACCESS
);
1149 /* FIXME - handle failure!!!!! */
1158 * Get some information about the process
1160 NtQueryInformationProcess(hProcess
,
1161 ProcessBasicInformation
,
1163 sizeof(ProcessBasicInfo
),
1165 DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
1166 ProcessBasicInfo
.UniqueProcessId
);
1167 lpProcessInformation
->dwProcessId
= (DWORD
)ProcessBasicInfo
.UniqueProcessId
;
1170 * Tell the csrss server we are creating a new process
1172 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
1173 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
1174 ProcessBasicInfo
.UniqueProcessId
;
1175 if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1177 /* Do not create a console for GUI applications */
1178 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1179 dwCreationFlags
|= DETACHED_PROCESS
;
1181 else if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
1183 if (NULL
== Ppb
->hConsole
)
1185 dwCreationFlags
|= CREATE_NEW_CONSOLE
;
1188 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
1189 CsrRequest
.Data
.CreateProcessRequest
.CtrlDispatcher
= ConsoleControlDispatcher
;
1190 Status
= CsrClientCallServer(&CsrRequest
,
1192 sizeof(CSRSS_API_REQUEST
),
1193 sizeof(CSRSS_API_REPLY
));
1194 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1196 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1199 Ppb
->hConsole
= CsrReply
.Data
.CreateProcessReply
.Console
;
1205 /* Set the child console handles */
1207 /* First check if handles were passed in startup info */
1208 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
1210 if (lpStartupInfo
->hStdInput
)
1212 Ppb
->hStdInput
= lpStartupInfo
->hStdInput
;
1216 if (lpStartupInfo
->hStdOutput
)
1218 Ppb
->hStdOutput
= lpStartupInfo
->hStdOutput
;
1222 if (lpStartupInfo
->hStdError
)
1224 Ppb
->hStdError
= lpStartupInfo
->hStdError
;
1230 /* Check if new console was created, use it for input and output if
1232 if (0 != (dwCreationFlags
& CREATE_NEW_CONSOLE
)
1233 && NT_SUCCESS(Status
) && NT_SUCCESS(CsrReply
.Status
))
1237 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1243 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1249 Ppb
->hStdError
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1255 /* Use existing handles otherwise */
1258 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
1263 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
1268 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
1272 /* Now duplicate handles if required */
1273 if (InputDup
&& Ppb
->hStdInput
!= NULL
)
1275 if (IsConsoleHandle(Ppb
->hStdInput
))
1277 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1281 DPRINT("Duplicate input handle\n");
1282 Status
= NtDuplicateObject (NtCurrentProcess(),
1288 DUPLICATE_SAME_ACCESS
);
1289 if(!NT_SUCCESS(Status
))
1291 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1296 if (OutputDup
&& Ppb
->hStdOutput
!= NULL
)
1298 if (IsConsoleHandle(Ppb
->hStdOutput
))
1300 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1304 DPRINT("Duplicate output handle\n");
1305 Status
= NtDuplicateObject (NtCurrentProcess(),
1311 DUPLICATE_SAME_ACCESS
);
1312 if(!NT_SUCCESS(Status
))
1314 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1319 if (ErrorDup
&& Ppb
->hStdError
!= NULL
)
1321 if (IsConsoleHandle(Ppb
->hStdError
))
1323 CsrRequest
.Type
= CSRSS_DUPLICATE_HANDLE
;
1324 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1325 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1326 Status
= CsrClientCallServer(&CsrRequest
,
1328 sizeof(CSRSS_API_REQUEST
),
1329 sizeof(CSRSS_API_REPLY
));
1330 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1332 Ppb
->hStdError
= INVALID_HANDLE_VALUE
;
1336 Ppb
->hStdError
= CsrReply
.Data
.DuplicateHandleReply
.Handle
;
1341 DPRINT("Duplicate error handle\n");
1342 Status
= NtDuplicateObject (NtCurrentProcess(),
1348 DUPLICATE_SAME_ACCESS
);
1349 if(!NT_SUCCESS(Status
))
1351 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1357 * Initialize some other fields in the PPB
1361 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1362 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1364 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1368 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
1370 Ppb
->dwX
= lpStartupInfo
->dwX
;
1371 Ppb
->dwY
= lpStartupInfo
->dwY
;
1372 Ppb
->dwXSize
= lpStartupInfo
->dwXSize
;
1373 Ppb
->dwYSize
= lpStartupInfo
->dwYSize
;
1374 Ppb
->dwFillAttribute
= lpStartupInfo
->dwFillAttribute
;
1382 * Create Process Environment Block
1384 DPRINT("Creating peb\n");
1386 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
, Sii
.Subsystem
);
1388 RtlDestroyProcessParameters (Ppb
);
1391 * Create the thread for the kernel
1393 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1394 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ Sii
.EntryPoint
));
1395 hThread
= KlCreateFirstThread(hProcess
,
1398 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ Sii
.EntryPoint
),
1400 &lpProcessInformation
->dwThreadId
);
1401 if (hThread
== INVALID_HANDLE_VALUE
)
1406 lpProcessInformation
->hProcess
= hProcess
;
1407 lpProcessInformation
->hThread
= hThread
;