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 <rosrtl/thread.h>
20 #include "../include/debug.h"
22 /* FUNCTIONS ****************************************************************/
24 extern __declspec(noreturn
)
25 VOID CALLBACK
ConsoleControlDispatcher(DWORD CodeAndFlag
);
28 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine
;
30 typedef NTSTATUS
STDCALL (K32_MBSTR_TO_WCSTR
)
37 NTSTATUS STDCALL
K32MbStrToWcStr(IN K32_MBSTR_TO_WCSTR
* True
,
38 UNICODE_STRING
* DestStr
,
39 ANSI_STRING
* SourceStr
,
42 if(SourceStr
->Buffer
== NULL
)
44 DestStr
->Length
= DestStr
->MaximumLength
= 0;
45 DestStr
->Buffer
= NULL
;
46 return STATUS_SUCCESS
;
49 return True(DestStr
, SourceStr
, Allocate
);
52 VOID STDCALL
RtlRosR32AttribsToNativeAttribs(OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
53 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
)
68 NativeAttribs
->Attributes
|= OBJ_INHERIT
;
73 NativeAttribs
->SecurityDescriptor
= NULL
;
77 VOID STDCALL
RtlRosR32AttribsToNativeAttribsNamed(OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
78 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
,
79 OUT UNICODE_STRING
* NativeName OPTIONAL
,
80 IN WCHAR
* Ros32Name OPTIONAL
,
81 IN HANDLE Ros32NameRoot OPTIONAL
)
83 if(!NativeAttribs
) return;
85 RtlRosR32AttribsToNativeAttribs(NativeAttribs
, Ros32Attribs
);
87 if(Ros32Name
!= NULL
&& NativeName
!= NULL
)
89 RtlInitUnicodeString(NativeName
, Ros32Name
);
91 NativeAttribs
->ObjectName
= NativeName
;
92 NativeAttribs
->RootDirectory
= Ros32NameRoot
;
93 NativeAttribs
->Attributes
|= OBJ_CASE_INSENSITIVE
;
101 BOOL STDCALL
CreateProcessA(LPCSTR lpApplicationName
,
103 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
104 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
105 BOOL bInheritHandles
,
106 DWORD dwCreationFlags
,
107 LPVOID lpEnvironment
,
108 LPCSTR lpCurrentDirectory
,
109 LPSTARTUPINFOA lpStartupInfo
,
110 LPPROCESS_INFORMATION lpProcessInformation
)
112 * FUNCTION: The CreateProcess function creates a new process and its
113 * primary thread. The new process executes the specified executable file
116 * lpApplicationName = Pointer to name of executable module
117 * lpCommandLine = Pointer to command line string
118 * lpProcessAttributes = Process security attributes
119 * lpThreadAttributes = Thread security attributes
120 * bInheritHandles = Handle inheritance flag
121 * dwCreationFlags = Creation flags
122 * lpEnvironment = Pointer to new environment block
123 * lpCurrentDirectory = Pointer to current directory name
124 * lpStartupInfo = Pointer to startup info
125 * lpProcessInformation = Pointer to process information
128 UNICODE_STRING wstrApplicationName
;
129 UNICODE_STRING wstrCurrentDirectory
;
130 UNICODE_STRING wstrCommandLine
;
131 UNICODE_STRING wstrReserved
;
132 UNICODE_STRING wstrDesktop
;
133 UNICODE_STRING wstrTitle
;
134 UNICODE_STRING wstrEnvVar
;
135 ANSI_STRING strApplicationName
;
136 ANSI_STRING strCurrentDirectory
;
137 ANSI_STRING strCommandLine
;
138 ANSI_STRING strReserved
;
139 ANSI_STRING strDesktop
;
140 ANSI_STRING strTitle
;
142 STARTUPINFOW wsiStartupInfo
;
144 NTSTATUS (STDCALL
*pTrue
)(UNICODE_STRING
*,
148 ULONG (STDCALL
*pRtlMbStringToUnicodeSize
)(ANSI_STRING
*);
150 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
151 "lpStartupInfo %x, lpProcessInformation %x\n",
152 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
153 lpStartupInfo
, lpProcessInformation
);
155 /* multibyte strings are ANSI */
158 pTrue
= RtlAnsiStringToUnicodeString
;
159 pRtlMbStringToUnicodeSize
= RtlAnsiStringToUnicodeSize
;
161 /* multibyte strings are OEM */
164 pTrue
= RtlOemStringToUnicodeString
;
165 pRtlMbStringToUnicodeSize
= RtlOemStringToUnicodeSize
;
168 /* invalid parameter */
169 if(lpStartupInfo
== NULL
)
171 SetLastError(ERROR_INVALID_PARAMETER
);
175 /* convert the environment */
176 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
180 ANSI_STRING strEnvVar
;
183 /* scan the environment to calculate its Unicode size */
184 pcScan
= lpEnvironment
;
187 pcScan
+= strlen(pcScan
) + 1;
191 nEnvLen
= (ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ 1;
193 /* environment too large */
194 if(nEnvLen
> (SIZE_T
)((USHORT
)~0))
196 SetLastError(ERROR_OUTOFMEMORY
);
200 strEnvVar
.Buffer
= lpEnvironment
;
201 strEnvVar
.MaximumLength
= strEnvVar
.Length
= nEnvLen
;
203 Status
= K32MbStrToWcStr(pTrue
, &wstrEnvVar
, &strEnvVar
, TRUE
);
206 if (!NT_SUCCESS(Status
))
208 SetLastError(ERROR_OUTOFMEMORY
);
214 /* convert the strings */
215 RtlInitAnsiString(&strCommandLine
, lpCommandLine
);
216 RtlInitAnsiString(&strApplicationName
, (LPSTR
)lpApplicationName
);
217 RtlInitAnsiString(&strCurrentDirectory
, (LPSTR
)lpCurrentDirectory
);
218 RtlInitAnsiString(&strReserved
, (LPSTR
)lpStartupInfo
->lpReserved
);
219 RtlInitAnsiString(&strDesktop
, (LPSTR
)lpStartupInfo
->lpDesktop
);
220 RtlInitAnsiString(&strTitle
, (LPSTR
)lpStartupInfo
->lpTitle
);
222 K32MbStrToWcStr(pTrue
, &wstrCommandLine
, &strCommandLine
, TRUE
);
223 K32MbStrToWcStr(pTrue
, &wstrApplicationName
, &strApplicationName
, TRUE
);
224 K32MbStrToWcStr(pTrue
, &wstrCurrentDirectory
, &strCurrentDirectory
, TRUE
);
225 K32MbStrToWcStr(pTrue
, &wstrReserved
, &strReserved
, TRUE
);
226 K32MbStrToWcStr(pTrue
, &wstrDesktop
, &strDesktop
, TRUE
);
227 K32MbStrToWcStr(pTrue
, &wstrTitle
, &strTitle
, TRUE
);
229 /* convert the startup information */
230 memcpy(&wsiStartupInfo
, lpStartupInfo
, sizeof(wsiStartupInfo
));
232 wsiStartupInfo
.lpReserved
= wstrReserved
.Buffer
;
233 wsiStartupInfo
.lpDesktop
= wstrDesktop
.Buffer
;
234 wsiStartupInfo
.lpTitle
= wstrTitle
.Buffer
;
236 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName
);
237 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine
);
238 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory
);
239 DPRINT("wstrReserved %wZ\n", &wstrReserved
);
240 DPRINT("wstrDesktop %wZ\n", &wstrDesktop
);
241 DPRINT("wstrTitle %wZ\n", &wstrTitle
);
243 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName
.Buffer
);
244 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine
.Buffer
);
245 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory
.Buffer
);
246 DPRINT("wstrReserved.Buffer %p\n", wstrReserved
.Buffer
);
247 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop
.Buffer
);
248 DPRINT("wstrTitle.Buffer %p\n", wstrTitle
.Buffer
);
250 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA
));
251 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW
));
253 /* call the Unicode function */
254 bRetVal
= CreateProcessW(wstrApplicationName
.Buffer
,
255 wstrCommandLine
.Buffer
,
260 !lpEnvironment
|| (dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
) ? lpEnvironment
: wstrEnvVar
.Buffer
,
261 wstrCurrentDirectory
.Buffer
,
263 lpProcessInformation
);
265 RtlFreeUnicodeString(&wstrApplicationName
);
266 RtlFreeUnicodeString(&wstrCommandLine
);
267 RtlFreeUnicodeString(&wstrCurrentDirectory
);
268 RtlFreeUnicodeString(&wstrReserved
);
269 RtlFreeUnicodeString(&wstrDesktop
);
270 RtlFreeUnicodeString(&wstrTitle
);
272 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
274 RtlFreeUnicodeString(&wstrEnvVar
);
281 _SEH_FILTER(BaseExceptionFilter
)
283 EXCEPTION_POINTERS
* ExceptionInfo
= _SEH_GetExceptionPointers();
284 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
286 if (GlobalTopLevelExceptionFilter
!= NULL
)
290 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
294 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
299 return ExceptionDisposition
;
304 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
309 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
313 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
315 _SEH_EXCEPT(BaseExceptionFilter
)
317 uExitCode
= _SEH_GetExceptionCode();
321 ExitProcess(uExitCode
);
325 HANDLE STDCALL
KlCreateFirstThread(HANDLE ProcessHandle
,
326 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
327 PSECTION_IMAGE_INFORMATION Sii
,
328 LPTHREAD_START_ROUTINE lpStartAddress
,
329 DWORD dwCreationFlags
,
332 OBJECT_ATTRIBUTES oaThreadAttribs
;
333 CLIENT_ID cidClientId
;
334 PVOID pTrueStartAddress
;
338 /* convert the thread attributes */
339 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs
, lpThreadAttributes
);
342 if(Sii
->SubsystemType
!= IMAGE_SUBSYSTEM_NATIVE
)
344 pTrueStartAddress
= (PVOID
)BaseProcessStart
;
349 pTrueStartAddress
= (PVOID
)RtlBaseProcessStartRoutine
;
352 DPRINT("RtlRosCreateUserThreadVa\n"
354 " ProcessHandle %p,\n"
355 " ObjectAttributes %p,\n"
356 " CreateSuspended %d,\n"
357 " StackZeroBits %d,\n"
358 " StackReserve %lu,\n"
359 " StackCommit %lu,\n"
360 " StartAddress %p,\n"
361 " ThreadHandle %p,\n"
363 " ParameterCount %u,\n"
364 " Parameters[0] %p,\n"
365 " Parameters[1] %p\n"
369 dwCreationFlags
& CREATE_SUSPENDED
,
371 Sii
->MaximumStackSize
,
372 Sii
->CommittedStackSize
,
380 /* create the first thread */
381 nErrCode
= RtlRosCreateUserThreadVa(ProcessHandle
,
383 dwCreationFlags
& CREATE_SUSPENDED
,
385 &(Sii
->MaximumStackSize
),
386 &(Sii
->CommittedStackSize
),
391 (ULONG_PTR
)lpStartAddress
,
392 (ULONG_PTR
)PEB_BASE
);
394 if(!NT_SUCCESS(nErrCode
))
396 SetLastErrorByStatus(nErrCode
);
400 DPRINT("StackReserve %p\n"
403 "ClientId.UniqueThread %p\n",
404 Sii
->MaximumStackSize
,
405 Sii
->CommittedStackSize
,
407 cidClientId
.UniqueThread
);
410 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
414 HANDLE
KlMapFile(LPCWSTR lpApplicationName
)
417 IO_STATUS_BLOCK IoStatusBlock
;
418 UNICODE_STRING ApplicationNameString
;
419 OBJECT_ATTRIBUTES ObjectAttributes
;
420 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
427 * Find the application name
430 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
431 &ApplicationNameString
,
436 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
438 InitializeObjectAttributes(&ObjectAttributes
,
439 &ApplicationNameString
,
440 OBJ_CASE_INSENSITIVE
,
445 * Try to open the executable
448 Status
= NtOpenFile(&hFile
,
449 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
452 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
453 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
455 RtlFreeUnicodeString (&ApplicationNameString
);
457 if (!NT_SUCCESS(Status
))
459 DPRINT("Failed to open file\n");
460 SetLastErrorByStatus (Status
);
464 Status
= NtCreateSection(&hSection
,
473 if (!NT_SUCCESS(Status
))
475 DPRINT("Failed to create section\n");
476 SetLastErrorByStatus (Status
);
483 static NTSTATUS
KlInitPeb(HANDLE ProcessHandle
,
484 PRTL_USER_PROCESS_PARAMETERS Ppb
,
485 PVOID
* ImageBaseAddress
,
486 ULONG ImageSubSystem
)
493 PVOID ParentEnv
= NULL
;
496 ULONG EnvSize
= 0, EnvSize1
= 0;
498 /* create the Environment */
499 if (Ppb
->Environment
!= NULL
)
501 ParentEnv
= Ppb
->Environment
;
508 EnvSize
= (ULONG
)((ULONG_PTR
)ptr
- (ULONG_PTR
)ParentEnv
);
510 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
512 MEMORY_BASIC_INFORMATION MemInfo
;
513 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
515 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
517 MemoryBasicInformation
,
519 sizeof(MEMORY_BASIC_INFORMATION
),
521 if (!NT_SUCCESS(Status
))
525 EnvSize
= MemInfo
.RegionSize
;
527 DPRINT("EnvironmentSize %ld\n", EnvSize
);
529 /* allocate and initialize new environment block */
533 Status
= NtAllocateVirtualMemory(ProcessHandle
,
537 MEM_RESERVE
| MEM_COMMIT
,
539 if (!NT_SUCCESS(Status
))
544 NtWriteVirtualMemory(ProcessHandle
,
553 PpbSize
= Ppb
->MaximumLength
;
554 Status
= NtAllocateVirtualMemory(ProcessHandle
,
558 MEM_RESERVE
| MEM_COMMIT
,
560 if (!NT_SUCCESS(Status
))
565 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
566 NtWriteVirtualMemory(ProcessHandle
,
572 /* write pointer to environment */
573 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
574 NtWriteVirtualMemory(ProcessHandle
,
575 (PVOID
)((ULONG_PTR
)PpbBase
+ Offset
),
580 /* write pointer to process parameter block */
581 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
582 NtWriteVirtualMemory(ProcessHandle
,
583 (PVOID
)(PEB_BASE
+ Offset
),
588 /* Write image subsystem */
589 Offset
= FIELD_OFFSET(PEB
, ImageSubSystem
);
590 NtWriteVirtualMemory(ProcessHandle
,
591 (PVOID
)(PEB_BASE
+ Offset
),
593 sizeof(ImageSubSystem
),
596 /* Read image base address. */
597 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
598 NtReadVirtualMemory(ProcessHandle
,
599 (PVOID
)(PEB_BASE
+ Offset
),
604 return(STATUS_SUCCESS
);
608 /*************************************************************************
611 * Helper for CreateProcessW: retrieve the file name to load from the
612 * app name and command line. Store the file name in buffer, and
613 * return a possibly modified command line.
615 * FIXME: use CurDir to search for the executable file in the new working directory
617 static LPWSTR FASTCALL
618 GetFileName(LPCWSTR CurDir
, LPCWSTR AppName
, LPWSTR CmdLine
, LPWSTR Buffer
,
621 WCHAR
*Name
, *Pos
, *Ret
= NULL
;
624 /* if we have an app name, everything is easy */
628 /* use the unmodified app name as file name */
629 wcsncpy(Buffer
, AppName
, BufLen
);
631 if (NULL
== Ret
|| L
'\0' == CmdLine
[0])
633 /* no command-line, create one */
634 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName
) + 3) * sizeof(WCHAR
));
638 wcscpy(Ret
+ 1, AppName
);
647 SetLastError(ERROR_INVALID_PARAMETER
);
651 /* first check for a quoted file name */
652 if (L
'"' == CmdLine
[0] && NULL
!= (p
= wcschr(CmdLine
+ 1, L
'"')))
654 int Len
= p
- CmdLine
- 1;
655 /* extract the quoted portion as file name */
656 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (Len
+ 1) * sizeof(WCHAR
));
661 memcpy(Name
, CmdLine
+ 1, Len
* sizeof(WCHAR
));
664 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
666 Ret
= CmdLine
; /* no change necessary */
669 RtlFreeHeap(GetProcessHeap(), 0, Name
);
673 /* now try the command-line word by word */
674 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 1) * sizeof(WCHAR
));
688 while (L
'\0' != *p
&& L
' ' != *p
);
690 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
697 if (NULL
== Ret
|| NULL
== wcschr(Name
, L
' '))
699 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
703 /* now build a new command-line with quotes */
704 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 3) * sizeof(WCHAR
));
707 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
711 wcscpy(Ret
+ 1, Name
);
715 RtlFreeHeap(GetProcessHeap(), 0, Name
);
724 CreateProcessW(LPCWSTR lpApplicationName
,
725 LPWSTR lpCommandLine
,
726 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
727 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
728 BOOL bInheritHandles
,
729 DWORD dwCreationFlags
,
730 LPVOID lpEnvironment
,
731 LPCWSTR lpCurrentDirectory
,
732 LPSTARTUPINFOW lpStartupInfo
,
733 LPPROCESS_INFORMATION lpProcessInformation
)
735 HANDLE hSection
, hProcess
, hThread
;
737 WCHAR ImagePathName
[256];
738 UNICODE_STRING ImagePathName_U
;
739 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
741 PRTL_USER_PROCESS_PARAMETERS Ppb
;
742 UNICODE_STRING CommandLine_U
;
743 CSR_API_MESSAGE CsrRequest
;
747 UNICODE_STRING CurrentDirectory_U
;
748 SECTION_IMAGE_INFORMATION Sii
;
749 WCHAR TempCurrentDirectoryW
[256];
750 WCHAR TempApplicationNameW
[256];
751 WCHAR TempCommandLineNameW
[256];
752 UNICODE_STRING RuntimeInfo_U
;
753 PVOID ImageBaseAddress
;
754 BOOL InputSet
, OutputSet
, ErrorSet
;
755 BOOL InputDup
= FALSE
, OutputDup
= FALSE
, ErrorDup
= FALSE
;
756 WCHAR Name
[MAX_PATH
];
758 BOOL IsBatchFile
= FALSE
;
759 PROCESS_PRIORITY_CLASS PriorityClass
;
760 OBJECT_ATTRIBUTES ProcObjectAttributes
;
761 ULONG ProcAttributes
= 0;
762 PVOID ProcSecurity
= NULL
;
764 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
765 lpApplicationName
, lpCommandLine
);
767 TidyCmdLine
= GetFileName(lpCurrentDirectory
, lpApplicationName
, lpCommandLine
, Name
,
768 sizeof(Name
) / sizeof(WCHAR
));
769 if (NULL
== TidyCmdLine
)
773 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
775 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
777 wcscpy (TempApplicationNameW
, lpApplicationName
);
778 i
= wcslen(TempApplicationNameW
);
779 if (TempApplicationNameW
[i
- 1] == L
'.')
781 TempApplicationNameW
[i
- 1] = 0;
785 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
788 s
= TempApplicationNameW
;
794 e
= wcsrchr(s
, L
'.');
798 e
= wcsrchr(s
, L
'.');
802 else if (L
'"' == TidyCmdLine
[0])
804 wcscpy(TempApplicationNameW
, TidyCmdLine
+ 1);
805 s
= wcschr(TempApplicationNameW
, L
'"');
814 wcscpy(TempApplicationNameW
, TidyCmdLine
);
815 s
= wcschr(TempApplicationNameW
, L
' ');
821 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
824 s
= TempApplicationNameW
;
826 s
= wcsrchr(s
, L
'.');
829 wcscat(TempApplicationNameW
, L
".exe");
832 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
837 e
= wcsrchr(s
, L
'.');
838 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
840 // the command is a batch file
842 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
844 // FIXME: use COMSPEC for the command interpreter
845 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
846 wcscat(TempCommandLineNameW
, lpApplicationName
);
847 lpCommandLine
= TempCommandLineNameW
;
848 wcscpy(TempApplicationNameW
, L
"cmd.exe");
849 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
861 * Process the application name and command line
863 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
864 RtlInitUnicodeString(&CommandLine_U
, IsBatchFile
? lpCommandLine
: TidyCmdLine
);
866 DPRINT("ImagePathName_U '%S'\n", ImagePathName_U
.Buffer
);
867 DPRINT("lpCommandLine '%S'\n", lpCommandLine
);
868 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine
);
870 /* Initialize the current directory string */
871 if (lpCurrentDirectory
!= NULL
)
873 RtlInitUnicodeString(&CurrentDirectory_U
,
878 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
879 RtlInitUnicodeString(&CurrentDirectory_U
,
880 TempCurrentDirectoryW
);
884 * Create a section for the executable
887 hSection
= KlMapFile (ImagePathName
);
888 if (hSection
== NULL
)
890 /////////////////////////////////////////
892 * Inspect the image to determine executable flavour
894 IO_STATUS_BLOCK IoStatusBlock
;
895 UNICODE_STRING ApplicationNameString
;
896 OBJECT_ATTRIBUTES ObjectAttributes
;
897 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
898 IMAGE_DOS_HEADER DosHeader
;
899 IO_STATUS_BLOCK Iosb
;
900 LARGE_INTEGER Offset
;
902 DPRINT("Inspecting Image Header for image type id\n");
904 // Find the application name
905 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
906 &ApplicationNameString
, NULL
, NULL
))
910 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
912 InitializeObjectAttributes(&ObjectAttributes
,
913 &ApplicationNameString
,
914 OBJ_CASE_INSENSITIVE
,
918 // Try to open the executable
919 Status
= NtOpenFile(&hFile
,
920 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
923 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
924 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
926 RtlFreeUnicodeString(&ApplicationNameString
);
928 if (!NT_SUCCESS(Status
))
930 DPRINT("Failed to open file\n");
931 SetLastErrorByStatus(Status
);
935 // Read the dos header
937 Status
= ZwReadFile(hFile
,
947 if (!NT_SUCCESS(Status
))
949 DPRINT("Failed to read from file\n");
950 SetLastErrorByStatus(Status
);
953 if (Iosb
.Information
!= sizeof(DosHeader
))
955 DPRINT("Failed to read dos header from file\n");
956 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
960 // Check the DOS signature
961 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
963 DPRINT("Failed dos magic check\n");
964 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
969 DPRINT("Launching VDM...\n");
970 return CreateProcessW(L
"ntvdm.exe",
971 (LPWSTR
)lpApplicationName
,
979 lpProcessInformation
);
981 /////////////////////////////////////////
984 * Get some information about the executable
986 Status
= ZwQuerySection(hSection
,
987 SectionImageInformation
,
991 if (! NT_SUCCESS(Status
))
994 DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status
);
995 SetLastErrorByStatus(Status
);
999 if (0 != (Sii
.ImageCharacteristics
& IMAGE_FILE_DLL
))
1002 DPRINT("Can't execute a DLL\n");
1003 SetLastError(ERROR_BAD_EXE_FORMAT
);
1007 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= Sii
.SubsystemType
1008 && IMAGE_SUBSYSTEM_WINDOWS_CUI
!= Sii
.SubsystemType
)
1011 DPRINT("Invalid subsystem %d\n", Sii
.SubsystemType
);
1012 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
1017 * Initialize the process object attributes
1020 if(lpProcessAttributes
!= NULL
)
1022 if(lpProcessAttributes
->bInheritHandle
)
1024 ProcAttributes
|= OBJ_INHERIT
;
1026 ProcSecurity
= lpProcessAttributes
->lpSecurityDescriptor
;
1029 InitializeObjectAttributes(&ProcObjectAttributes
,
1035 * initialize the process priority class structure
1037 PriorityClass
.Foreground
= FALSE
;
1039 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
1041 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1043 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
1045 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1047 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
1049 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1051 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
1053 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1055 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
1057 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1059 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
1061 /* FIXME - This is a privileged operation. If we don't have the privilege we should
1062 rather use PROCESS_PRIORITY_CLASS_HIGH. */
1063 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
1067 /* FIXME - what to do in this case? */
1068 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1072 * Create a new process
1074 Status
= NtCreateProcess(&hProcess
,
1076 &ProcObjectAttributes
,
1082 /* FIXME - handle failure!!!!! */
1084 Status
= NtSetInformationProcess(hProcess
,
1085 ProcessPriorityClass
,
1087 sizeof(PROCESS_PRIORITY_CLASS
));
1088 /* FIXME - handle failure!!!!! */
1092 if (lpStartupInfo
->lpReserved2
)
1095 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1096 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1097 * If is possible that this function overwrite the last information in runtimeinfo
1098 * with the null terminator for the unicode string.
1100 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= (lpStartupInfo
->cbReserved2
+ 1) & ~1;
1101 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
1102 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
1109 RtlCreateProcessParameters(&Ppb
,
1112 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
1118 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
1120 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
1121 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
1125 * Translate some handles for the new process
1127 if (Ppb
->CurrentDirectory
.Handle
)
1129 Status
= NtDuplicateObject (NtCurrentProcess(),
1130 Ppb
->CurrentDirectory
.Handle
,
1132 &Ppb
->CurrentDirectory
.Handle
,
1135 DUPLICATE_SAME_ACCESS
);
1136 /* FIXME - handle failure!!!!! */
1145 * Get some information about the process
1147 NtQueryInformationProcess(hProcess
,
1148 ProcessBasicInformation
,
1150 sizeof(ProcessBasicInfo
),
1152 DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
1153 ProcessBasicInfo
.UniqueProcessId
);
1154 lpProcessInformation
->dwProcessId
= (DWORD
)ProcessBasicInfo
.UniqueProcessId
;
1157 * Tell the csrss server we are creating a new process
1159 Request
= CREATE_PROCESS
;
1160 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
1161 (HANDLE
)ProcessBasicInfo
.UniqueProcessId
;
1162 if (Sii
.SubsystemType
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1164 /* Do not create a console for GUI applications */
1165 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1166 dwCreationFlags
|= DETACHED_PROCESS
;
1168 else if (Sii
.SubsystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
1170 if (NULL
== Ppb
->ConsoleHandle
)
1172 dwCreationFlags
|= CREATE_NEW_CONSOLE
;
1175 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
1176 CsrRequest
.Data
.CreateProcessRequest
.CtrlDispatcher
= ConsoleControlDispatcher
;
1177 Status
= CsrClientCallServer(&CsrRequest
,
1179 MAKE_CSR_API(Request
, CSR_NATIVE
),
1180 sizeof(CSR_API_MESSAGE
));
1181 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1183 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1186 Ppb
->ConsoleHandle
= CsrRequest
.Data
.CreateProcessRequest
.Console
;
1192 /* Set the child console handles */
1194 /* First check if handles were passed in startup info */
1195 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
1197 if (lpStartupInfo
->hStdInput
)
1199 Ppb
->StandardInput
= lpStartupInfo
->hStdInput
;
1203 if (lpStartupInfo
->hStdOutput
)
1205 Ppb
->StandardOutput
= lpStartupInfo
->hStdOutput
;
1209 if (lpStartupInfo
->hStdError
)
1211 Ppb
->StandardError
= lpStartupInfo
->hStdError
;
1217 /* Check if new console was created, use it for input and output if
1219 if (0 != (dwCreationFlags
& CREATE_NEW_CONSOLE
)
1220 && NT_SUCCESS(Status
) && NT_SUCCESS(CsrRequest
.Status
))
1224 Ppb
->StandardInput
= CsrRequest
.Data
.CreateProcessRequest
.InputHandle
;
1230 Ppb
->StandardOutput
= CsrRequest
.Data
.CreateProcessRequest
.OutputHandle
;
1236 Ppb
->StandardError
= CsrRequest
.Data
.CreateProcessRequest
.OutputHandle
;
1242 /* Use existing handles otherwise */
1245 Ppb
->StandardInput
= NtCurrentPeb()->ProcessParameters
->StandardInput
;
1250 Ppb
->StandardOutput
= NtCurrentPeb()->ProcessParameters
->StandardOutput
;
1255 Ppb
->StandardError
= NtCurrentPeb()->ProcessParameters
->StandardError
;
1259 /* Now duplicate handles if required */
1260 if (InputDup
&& Ppb
->StandardInput
!= NULL
)
1262 if (IsConsoleHandle(Ppb
->StandardInput
))
1264 Ppb
->StandardInput
= CsrRequest
.Data
.CreateProcessRequest
.InputHandle
;
1268 DPRINT("Duplicate input handle\n");
1269 Status
= NtDuplicateObject (NtCurrentProcess(),
1272 &Ppb
->StandardInput
,
1275 DUPLICATE_SAME_ACCESS
);
1276 if(!NT_SUCCESS(Status
))
1278 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1283 if (OutputDup
&& Ppb
->StandardOutput
!= NULL
)
1285 if (IsConsoleHandle(Ppb
->StandardOutput
))
1287 Ppb
->StandardOutput
= CsrRequest
.Data
.CreateProcessRequest
.OutputHandle
;
1291 DPRINT("Duplicate output handle\n");
1292 Status
= NtDuplicateObject (NtCurrentProcess(),
1293 Ppb
->StandardOutput
,
1295 &Ppb
->StandardOutput
,
1298 DUPLICATE_SAME_ACCESS
);
1299 if(!NT_SUCCESS(Status
))
1301 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1306 if (ErrorDup
&& Ppb
->StandardError
!= NULL
)
1308 if (IsConsoleHandle(Ppb
->StandardError
))
1310 Request
= DUPLICATE_HANDLE
;
1311 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= (HANDLE
)ProcessBasicInfo
.UniqueProcessId
;
1312 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrRequest
.Data
.CreateProcessRequest
.OutputHandle
;
1313 Status
= CsrClientCallServer(&CsrRequest
,
1315 MAKE_CSR_API(Request
, CSR_NATIVE
),
1316 sizeof(CSR_API_MESSAGE
));
1317 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1319 Ppb
->StandardError
= INVALID_HANDLE_VALUE
;
1323 Ppb
->StandardError
= CsrRequest
.Data
.DuplicateHandleRequest
.Handle
;
1328 DPRINT("Duplicate error handle\n");
1329 Status
= NtDuplicateObject (NtCurrentProcess(),
1332 &Ppb
->StandardError
,
1335 DUPLICATE_SAME_ACCESS
);
1336 if(!NT_SUCCESS(Status
))
1338 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1344 * Initialize some other fields in the PPB
1348 Ppb
->Flags
= lpStartupInfo
->dwFlags
;
1349 if (Ppb
->Flags
& STARTF_USESHOWWINDOW
)
1351 Ppb
->ShowWindowFlags
= lpStartupInfo
->wShowWindow
;
1355 Ppb
->ShowWindowFlags
= SW_SHOWDEFAULT
;
1357 Ppb
->StartingX
= lpStartupInfo
->dwX
;
1358 Ppb
->StartingY
= lpStartupInfo
->dwY
;
1359 Ppb
->CountX
= lpStartupInfo
->dwXSize
;
1360 Ppb
->CountY
= lpStartupInfo
->dwYSize
;
1361 Ppb
->FillAttribute
= lpStartupInfo
->dwFillAttribute
;
1369 * Create Process Environment Block
1371 DPRINT("Creating peb\n");
1373 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
, Sii
.SubsystemType
);
1375 RtlDestroyProcessParameters (Ppb
);
1378 * Create the thread for the kernel
1380 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1381 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ (ULONG_PTR
)Sii
.TransferAddress
));
1382 hThread
= KlCreateFirstThread(hProcess
,
1385 (PVOID
)((ULONG_PTR
)ImageBaseAddress
+ (ULONG_PTR
)Sii
.TransferAddress
),
1387 &lpProcessInformation
->dwThreadId
);
1388 if (hThread
== NULL
)
1393 lpProcessInformation
->hProcess
= hProcess
;
1394 lpProcessInformation
->hThread
= hThread
;