1 /* $Id: create.c,v 1.82 2004/05/01 18:09:53 tamlin 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 "../include/debug.h"
19 /* FUNCTIONS ****************************************************************/
21 extern __declspec(noreturn
)
22 VOID CALLBACK
ConsoleControlDispatcher(DWORD CodeAndFlag
);
25 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine
;
27 typedef NTSTATUS
STDCALL (K32_MBSTR_TO_WCSTR
)
34 NTSTATUS STDCALL K32MbStrToWcStr
36 IN K32_MBSTR_TO_WCSTR
* True
,
37 UNICODE_STRING
* DestStr
,
38 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
54 OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
55 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
58 NativeAttribs
->Length
= sizeof(*NativeAttribs
);
59 NativeAttribs
->ObjectName
= NULL
;
60 NativeAttribs
->RootDirectory
= NULL
;
61 NativeAttribs
->Attributes
= 0;
62 NativeAttribs
->SecurityQualityOfService
= NULL
;
65 if(Ros32Attribs
!= NULL
&& Ros32Attribs
->nLength
>= sizeof(*Ros32Attribs
))
67 NativeAttribs
->SecurityDescriptor
= Ros32Attribs
->lpSecurityDescriptor
;
69 if(Ros32Attribs
->bInheritHandle
)
70 NativeAttribs
->Attributes
|= OBJ_INHERIT
;
73 NativeAttribs
->SecurityDescriptor
= NULL
;
76 VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed
78 OUT OBJECT_ATTRIBUTES
* NativeAttribs
,
79 IN SECURITY_ATTRIBUTES
* Ros32Attribs OPTIONAL
,
80 OUT UNICODE_STRING
* NativeName OPTIONAL
,
81 IN WCHAR
* Ros32Name OPTIONAL
,
82 IN HANDLE Ros32NameRoot OPTIONAL
85 if(!NativeAttribs
) return;
87 RtlRosR32AttribsToNativeAttribs(NativeAttribs
, Ros32Attribs
);
89 if(Ros32Name
!= NULL
&& NativeName
!= NULL
)
91 RtlInitUnicodeString(NativeName
, Ros32Name
);
93 NativeAttribs
->ObjectName
= NativeName
;
94 NativeAttribs
->RootDirectory
= Ros32NameRoot
;
95 NativeAttribs
->Attributes
|= OBJ_CASE_INSENSITIVE
;
103 BOOL STDCALL CreateProcessA
105 LPCSTR lpApplicationName
,
107 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
108 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
109 BOOL bInheritHandles
,
110 DWORD dwCreationFlags
,
111 LPVOID lpEnvironment
,
112 LPCSTR lpCurrentDirectory
,
113 LPSTARTUPINFOA lpStartupInfo
,
114 LPPROCESS_INFORMATION lpProcessInformation
117 * FUNCTION: The CreateProcess function creates a new process and its
118 * primary thread. The new process executes the specified executable file
121 * lpApplicationName = Pointer to name of executable module
122 * lpCommandLine = Pointer to command line string
123 * lpProcessAttributes = Process security attributes
124 * lpThreadAttributes = Thread security attributes
125 * bInheritHandles = Handle inheritance flag
126 * dwCreationFlags = Creation flags
127 * lpEnvironment = Pointer to new environment block
128 * lpCurrentDirectory = Pointer to current directory name
129 * lpStartupInfo = Pointer to startup info
130 * lpProcessInformation = Pointer to process information
133 PWCHAR pwcEnv
= NULL
;
134 UNICODE_STRING wstrApplicationName
;
135 UNICODE_STRING wstrCurrentDirectory
;
136 UNICODE_STRING wstrCommandLine
;
137 UNICODE_STRING wstrReserved
;
138 UNICODE_STRING wstrDesktop
;
139 UNICODE_STRING wstrTitle
;
140 ANSI_STRING strApplicationName
;
141 ANSI_STRING strCurrentDirectory
;
142 ANSI_STRING strCommandLine
;
143 ANSI_STRING strReserved
;
144 ANSI_STRING strDesktop
;
145 ANSI_STRING strTitle
;
147 STARTUPINFOW wsiStartupInfo
;
149 NTSTATUS
STDCALL_FUNC (*pTrue
)
156 ULONG
STDCALL_FUNC (*pRtlMbStringToUnicodeSize
)(ANSI_STRING
*);
158 DPRINT("CreateProcessA(%s)\n", lpApplicationName
);
162 "dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
163 "lpStartupInfo %x, lpProcessInformation %x\n",
171 /* invalid parameter */
172 if(lpStartupInfo
== NULL
)
174 SetLastError(ERROR_INVALID_PARAMETER
);
178 /* multibyte strings are ANSI */
181 pTrue
= RtlAnsiStringToUnicodeString
;
182 pRtlMbStringToUnicodeSize
= RtlAnsiStringToUnicodeSize
;
184 /* multibyte strings are OEM */
187 pTrue
= RtlOemStringToUnicodeString
;
188 pRtlMbStringToUnicodeSize
= RtlOemStringToUnicodeSize
;
191 /* convert the environment */
192 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
196 UNICODE_STRING wstrEnvVar
;
197 ANSI_STRING strEnvVar
;
199 /* scan the environment to calculate its Unicode size */
200 for(pcScan
= lpEnvironment
; *pcScan
; pcScan
+= strEnvVar
.Length
+ sizeof(char))
202 /* add the size of the current variable */
203 RtlInitAnsiString(&strEnvVar
, pcScan
);
204 nEnvLen
+= pRtlMbStringToUnicodeSize(&strEnvVar
) + sizeof(WCHAR
);
207 /* add the size of the final NUL character */
208 nEnvLen
+= sizeof(WCHAR
);
210 /* environment too large */
211 if(nEnvLen
> ~((USHORT
)0))
213 SetLastError(ERROR_OUTOFMEMORY
);
217 /* allocate the Unicode environment */
218 pwcEnv
= (PWCHAR
)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, nEnvLen
);
223 SetLastError(ERROR_OUTOFMEMORY
);
227 wstrEnvVar
.Buffer
= pwcEnv
;
228 wstrEnvVar
.Length
= 0;
229 wstrEnvVar
.MaximumLength
= nEnvLen
;
231 /* scan the environment to convert it */
232 for(pcScan
= lpEnvironment
; *pcScan
; pcScan
+= strEnvVar
.Length
+ sizeof(char))
234 /* convert the current variable */
235 RtlInitAnsiString(&strEnvVar
, pcScan
);
236 K32MbStrToWcStr(pTrue
, &wstrEnvVar
, &strEnvVar
, FALSE
);
238 /* advance the buffer to the next variable */
239 wstrEnvVar
.Buffer
+= (wstrEnvVar
.Length
/ sizeof(WCHAR
) + 1);
240 wstrEnvVar
.MaximumLength
-= (wstrEnvVar
.Length
+ sizeof(WCHAR
));
241 wstrEnvVar
.Length
= 0;
244 /* final NUL character */
245 wstrEnvVar
.Buffer
[0] = 0;
248 /* convert the strings */
249 RtlInitAnsiString(&strCommandLine
, lpCommandLine
);
250 RtlInitAnsiString(&strApplicationName
, (LPSTR
)lpApplicationName
);
251 RtlInitAnsiString(&strCurrentDirectory
, (LPSTR
)lpCurrentDirectory
);
252 RtlInitAnsiString(&strReserved
, (LPSTR
)lpStartupInfo
->lpReserved
);
253 RtlInitAnsiString(&strDesktop
, (LPSTR
)lpStartupInfo
->lpDesktop
);
254 RtlInitAnsiString(&strTitle
, (LPSTR
)lpStartupInfo
->lpTitle
);
256 K32MbStrToWcStr(pTrue
, &wstrCommandLine
, &strCommandLine
, TRUE
);
257 K32MbStrToWcStr(pTrue
, &wstrApplicationName
, &strApplicationName
, TRUE
);
258 K32MbStrToWcStr(pTrue
, &wstrCurrentDirectory
, &strCurrentDirectory
, TRUE
);
259 K32MbStrToWcStr(pTrue
, &wstrReserved
, &strReserved
, TRUE
);
260 K32MbStrToWcStr(pTrue
, &wstrDesktop
, &strDesktop
, TRUE
);
261 K32MbStrToWcStr(pTrue
, &wstrTitle
, &strTitle
, TRUE
);
263 /* convert the startup information */
264 memcpy(&wsiStartupInfo
, lpStartupInfo
, sizeof(wsiStartupInfo
));
266 wsiStartupInfo
.lpReserved
= wstrReserved
.Buffer
;
267 wsiStartupInfo
.lpDesktop
= wstrDesktop
.Buffer
;
268 wsiStartupInfo
.lpTitle
= wstrTitle
.Buffer
;
270 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName
);
271 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine
);
272 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory
);
273 DPRINT("wstrReserved %wZ\n", &wstrReserved
);
274 DPRINT("wstrDesktop %wZ\n", &wstrDesktop
);
275 DPRINT("wstrTitle %wZ\n", &wstrTitle
);
277 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName
.Buffer
);
278 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine
.Buffer
);
279 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory
.Buffer
);
280 DPRINT("wstrReserved.Buffer %p\n", wstrReserved
.Buffer
);
281 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop
.Buffer
);
282 DPRINT("wstrTitle.Buffer %p\n", wstrTitle
.Buffer
);
284 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA
));
285 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW
));
287 /* call the Unicode function */
288 bRetVal
= CreateProcessW
290 wstrApplicationName
.Buffer
,
291 wstrCommandLine
.Buffer
,
296 dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
? lpEnvironment
: pwcEnv
,
297 wstrCurrentDirectory
.Buffer
,
302 RtlFreeUnicodeString(&wstrApplicationName
);
303 RtlFreeUnicodeString(&wstrCommandLine
);
304 RtlFreeUnicodeString(&wstrCurrentDirectory
);
305 RtlFreeUnicodeString(&wstrReserved
);
306 RtlFreeUnicodeString(&wstrDesktop
);
307 RtlFreeUnicodeString(&wstrTitle
);
309 RtlFreeHeap(GetProcessHeap(), 0, pwcEnv
);
316 * Private helper function to lookup the module name from a given address.
317 * The address can point to anywhere within the module.
320 _module_name_from_addr(const void* addr
, char* psz
, size_t nChars
)
322 MEMORY_BASIC_INFORMATION mbi
;
323 if (VirtualQuery(addr
, &mbi
, sizeof(mbi
)) != sizeof(mbi
) ||
324 !GetModuleFileNameA((HMODULE
)mbi
.AllocationBase
, psz
, nChars
))
331 static int _except_recursion_trap
= 0;
334 struct __EXCEPTION_RECORD
;
337 EXCEPTION_DISPOSITION
340 struct _EXCEPTION_RECORD
*ExceptionRecord
,
341 void * EstablisherFrame
,
342 struct _CONTEXT
*ContextRecord
,
343 void * DispatcherContext
)
346 char szMod
[128] = "";
348 DPRINT1("Thread terminated abnormally due to unhandled exception\n");
349 DPRINT1("Address:\n");
351 ExceptionRecord
->ExceptionAddress
,
352 _module_name_from_addr(ExceptionRecord
->ExceptionAddress
, szMod
, sizeof(szMod
)));
357 DPRINT1("Frames:\n");
358 Frame
= (PULONG
)((CONTEXT
*)ContextRecord
)->Ebp
;
359 while ((PVOID
)Frame
[1] != NULL
&& (PULONG
)Frame
[1] != (PULONG
)0xdeadbeef)
361 _module_name_from_addr((const void*)Frame
[1], szMod
, sizeof(szMod
));
362 DPRINT1("%8x %s\n", (PVOID
)Frame
[1], szMod
);
363 Frame
= (PULONG
)Frame
[0];
368 if (3 < ++_except_recursion_trap
)
370 DPRINT1("_except_handler(...) appears to be recursing.\n");
371 DPRINT1("Process HALTED.\n");
377 if (/* FIXME: */ TRUE
) /* Not a service */
379 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
380 /* ExitProcess(0); */
385 DPRINT(" calling ExitThread(0) . . .\n");
389 DPRINT1(" We should not get to here !!!\n");
390 /* We should not get to here */
391 return ExceptionContinueSearch
;
395 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress
,
400 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
402 __try1(_except_handler
)
404 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
409 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
411 ExitThread(uExitCode
);
415 HANDLE STDCALL KlCreateFirstThread
417 HANDLE ProcessHandle
,
418 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
419 PSECTION_IMAGE_INFORMATION Sii
,
420 LPTHREAD_START_ROUTINE lpStartAddress
,
421 DWORD dwCreationFlags
,
425 OBJECT_ATTRIBUTES oaThreadAttribs
;
426 CLIENT_ID cidClientId
;
427 PVOID pTrueStartAddress
;
431 /* convert the thread attributes */
432 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs
, lpThreadAttributes
);
435 if(Sii
->Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
436 pTrueStartAddress
= (PVOID
)BaseProcessStart
;
439 pTrueStartAddress
= (PVOID
)RtlBaseProcessStartRoutine
;
443 "RtlRosCreateUserThreadVa\n"
445 " ProcessHandle %p,\n"
446 " ObjectAttributes %p,\n"
447 " CreateSuspended %d,\n"
448 " StackZeroBits %d,\n"
449 " StackReserve %lu,\n"
450 " StackCommit %lu,\n"
451 " StartAddress %p,\n"
452 " ThreadHandle %p,\n"
454 " ParameterCount %u,\n"
455 " Parameters[0] %p,\n"
456 " Parameters[1] %p\n"
460 dwCreationFlags
& CREATE_SUSPENDED
,
472 /* create the first thread */
473 nErrCode
= RtlRosCreateUserThreadVa
477 dwCreationFlags
& CREATE_SUSPENDED
,
479 &(Sii
->StackReserve
),
485 (ULONG_PTR
)lpStartAddress
,
490 if(!NT_SUCCESS(nErrCode
))
492 SetLastErrorByStatus(nErrCode
);
501 "ClientId.UniqueThread %p\n",
505 cidClientId
.UniqueThread
509 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
513 HANDLE
KlMapFile(LPCWSTR lpApplicationName
)
516 IO_STATUS_BLOCK IoStatusBlock
;
517 UNICODE_STRING ApplicationNameString
;
518 OBJECT_ATTRIBUTES ObjectAttributes
;
519 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
526 * Find the application name
529 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
530 &ApplicationNameString
,
535 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
537 InitializeObjectAttributes(&ObjectAttributes
,
538 &ApplicationNameString
,
539 OBJ_CASE_INSENSITIVE
,
544 * Try to open the executable
547 Status
= NtOpenFile(&hFile
,
548 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
551 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
552 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
554 RtlFreeUnicodeString (&ApplicationNameString
);
556 if (!NT_SUCCESS(Status
))
558 DPRINT("Failed to open file\n");
559 SetLastErrorByStatus (Status
);
563 Status
= NtCreateSection(&hSection
,
572 if (!NT_SUCCESS(Status
))
574 DPRINT("Failed to create section\n");
575 SetLastErrorByStatus (Status
);
582 static NTSTATUS KlInitPeb
584 HANDLE ProcessHandle
,
585 PRTL_USER_PROCESS_PARAMETERS Ppb
,
586 PVOID
* ImageBaseAddress
,
595 PVOID ParentEnv
= NULL
;
598 ULONG EnvSize
= 0, EnvSize1
= 0;
600 /* create the Environment */
601 if (Ppb
->Environment
!= NULL
)
603 ParentEnv
= Ppb
->Environment
;
610 EnvSize
= (PVOID
)ptr
- ParentEnv
;
612 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
614 MEMORY_BASIC_INFORMATION MemInfo
;
615 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
617 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
619 MemoryBasicInformation
,
621 sizeof(MEMORY_BASIC_INFORMATION
),
623 if (!NT_SUCCESS(Status
))
627 EnvSize
= MemInfo
.RegionSize
;
629 DPRINT("EnvironmentSize %ld\n", EnvSize
);
631 /* allocate and initialize new environment block */
635 Status
= NtAllocateVirtualMemory(ProcessHandle
,
639 MEM_RESERVE
| MEM_COMMIT
,
641 if (!NT_SUCCESS(Status
))
646 NtWriteVirtualMemory(ProcessHandle
,
655 PpbSize
= Ppb
->AllocationSize
;
656 Status
= NtAllocateVirtualMemory(ProcessHandle
,
660 MEM_RESERVE
| MEM_COMMIT
,
662 if (!NT_SUCCESS(Status
))
667 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
668 NtWriteVirtualMemory(ProcessHandle
,
674 /* write pointer to environment */
675 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
676 NtWriteVirtualMemory(ProcessHandle
,
677 (PVOID
)(PpbBase
+ Offset
),
682 /* write pointer to process parameter block */
683 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
684 NtWriteVirtualMemory(ProcessHandle
,
685 (PVOID
)(PEB_BASE
+ Offset
),
690 /* Write image subsystem */
691 Offset
= FIELD_OFFSET(PEB
, ImageSubSystem
);
692 NtWriteVirtualMemory(ProcessHandle
,
693 (PVOID
)(PEB_BASE
+ Offset
),
695 sizeof(ImageSubSystem
),
698 /* Read image base address. */
699 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
700 NtReadVirtualMemory(ProcessHandle
,
701 (PVOID
)(PEB_BASE
+ Offset
),
706 return(STATUS_SUCCESS
);
710 /*************************************************************************
713 * Helper for CreateProcessW: retrieve the file name to load from the
714 * app name and command line. Store the file name in buffer, and
715 * return a possibly modified command line.
717 * FIXME: use CurDir to search for the executable file in the new working directory
719 static LPWSTR FASTCALL
720 GetFileName(LPCWSTR CurDir
, LPCWSTR AppName
, LPWSTR CmdLine
, LPWSTR Buffer
,
723 WCHAR
*Name
, *Pos
, *Ret
= NULL
;
726 /* if we have an app name, everything is easy */
730 /* use the unmodified app name as file name */
731 wcsncpy(Buffer
, AppName
, BufLen
);
733 if (NULL
== Ret
|| L
'\0' == CmdLine
[0])
735 /* no command-line, create one */
736 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName
) + 3) * sizeof(WCHAR
));
740 wcscpy(Ret
+ 1, AppName
);
749 SetLastError(ERROR_INVALID_PARAMETER
);
753 /* first check for a quoted file name */
754 if (L
'"' == CmdLine
[0] && NULL
!= (p
= wcschr(CmdLine
+ 1, L
'"')))
756 int Len
= p
- CmdLine
- 1;
757 /* extract the quoted portion as file name */
758 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (Len
+ 1) * sizeof(WCHAR
));
763 memcpy(Name
, CmdLine
+ 1, Len
* sizeof(WCHAR
));
766 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
768 Ret
= CmdLine
; /* no change necessary */
771 RtlFreeHeap(GetProcessHeap(), 0, Name
);
775 /* now try the command-line word by word */
776 Name
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 1) * sizeof(WCHAR
));
790 while (L
'\0' != *p
&& L
' ' != *p
);
792 if (SearchPathW(NULL
, Name
, L
".exe", BufLen
, Buffer
, NULL
))
799 if (NULL
== Ret
|| NULL
== wcschr(Name
, L
' '))
801 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
805 /* now build a new command-line with quotes */
806 Ret
= RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine
) + 3) * sizeof(WCHAR
));
809 RtlFreeHeap(GetProcessHeap(), 0, Name
); /* no change necessary */
813 wcscpy(Ret
+ 1, Name
);
817 RtlFreeHeap(GetProcessHeap(), 0, Name
);
828 LPCWSTR lpApplicationName
,
829 LPWSTR lpCommandLine
,
830 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
831 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
832 BOOL bInheritHandles
,
833 DWORD dwCreationFlags
,
834 LPVOID lpEnvironment
,
835 LPCWSTR lpCurrentDirectory
,
836 LPSTARTUPINFOW lpStartupInfo
,
837 LPPROCESS_INFORMATION lpProcessInformation
840 HANDLE hSection
, hProcess
, hThread
;
842 WCHAR ImagePathName
[256];
843 UNICODE_STRING ImagePathName_U
;
844 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
846 PRTL_USER_PROCESS_PARAMETERS Ppb
;
847 UNICODE_STRING CommandLine_U
;
848 CSRSS_API_REQUEST CsrRequest
;
849 CSRSS_API_REPLY CsrReply
;
850 CHAR ImageFileName
[8];
853 UNICODE_STRING CurrentDirectory_U
;
854 SECTION_IMAGE_INFORMATION Sii
;
855 WCHAR TempCurrentDirectoryW
[256];
856 WCHAR TempApplicationNameW
[256];
857 WCHAR TempCommandLineNameW
[256];
858 UNICODE_STRING RuntimeInfo_U
;
859 PVOID ImageBaseAddress
;
860 BOOL InputSet
, OutputSet
, ErrorSet
;
861 BOOL InputDup
, OutputDup
, ErrorDup
;
862 WCHAR Name
[MAX_PATH
];
865 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
866 lpApplicationName
, lpCommandLine
);
868 TidyCmdLine
= GetFileName(lpCurrentDirectory
, lpApplicationName
, lpCommandLine
, Name
,
869 sizeof(Name
) / sizeof(WCHAR
));
870 if (NULL
== TidyCmdLine
)
875 if (lpApplicationName
!= NULL
&& lpApplicationName
[0] != 0)
877 wcscpy (TempApplicationNameW
, lpApplicationName
);
878 i
= wcslen(TempApplicationNameW
);
879 if (TempApplicationNameW
[i
- 1] == L
'.')
881 TempApplicationNameW
[i
- 1] = 0;
885 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
888 s
= TempApplicationNameW
;
894 e
= wcsrchr(s
, L
'.');
898 e
= wcsrchr(s
, L
'.');
902 else if (L
'"' == TidyCmdLine
[0])
904 wcscpy(TempApplicationNameW
, TidyCmdLine
+ 1);
905 s
= wcschr(TempApplicationNameW
, L
'"');
914 wcscpy(TempApplicationNameW
, TidyCmdLine
);
915 s
= wcschr(TempApplicationNameW
, L
' ');
921 s
= max(wcsrchr(TempApplicationNameW
, L
'\\'), wcsrchr(TempApplicationNameW
, L
'/'));
924 s
= TempApplicationNameW
;
926 s
= wcsrchr(s
, L
'.');
929 wcscat(TempApplicationNameW
, L
".exe");
932 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
937 e
= wcsrchr(s
, L
'.');
938 if (e
!= NULL
&& (!_wcsicmp(e
, L
".bat") || !_wcsicmp(e
, L
".cmd")))
940 // the command is a batch file
941 if (lpApplicationName
!= NULL
&& lpApplicationName
[0])
943 // FIXME: use COMSPEC for the command interpreter
944 wcscpy(TempCommandLineNameW
, L
"cmd /c ");
945 wcscat(TempCommandLineNameW
, lpApplicationName
);
946 lpCommandLine
= TempCommandLineNameW
;
947 wcscpy(TempApplicationNameW
, L
"cmd.exe");
948 if (!SearchPathW(NULL
, TempApplicationNameW
, NULL
, sizeof(ImagePathName
)/sizeof(WCHAR
), ImagePathName
, &s
))
960 * Store the image file name for the process
967 for (i
= 0; i
< 8; i
++)
969 ImageFileName
[i
] = (CHAR
)(s
[i
]);
977 * Process the application name and command line
979 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
980 RtlInitUnicodeString(&CommandLine_U
, lpCommandLine
);
982 DPRINT("ImagePathName_U %S\n", ImagePathName_U
.Buffer
);
983 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
985 /* Initialize the current directory string */
986 if (lpCurrentDirectory
!= NULL
)
988 RtlInitUnicodeString(&CurrentDirectory_U
,
993 GetCurrentDirectoryW(256, TempCurrentDirectoryW
);
994 RtlInitUnicodeString(&CurrentDirectory_U
,
995 TempCurrentDirectoryW
);
999 * Create a section for the executable
1002 hSection
= KlMapFile (ImagePathName
);
1003 if (hSection
== NULL
)
1005 /////////////////////////////////////////
1007 * Inspect the image to determine executable flavour
1009 IO_STATUS_BLOCK IoStatusBlock
;
1010 UNICODE_STRING ApplicationNameString
;
1011 OBJECT_ATTRIBUTES ObjectAttributes
;
1012 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
1013 IMAGE_DOS_HEADER DosHeader
;
1014 IO_STATUS_BLOCK Iosb
;
1015 LARGE_INTEGER Offset
;
1016 HANDLE hFile
= NULL
;
1018 DPRINT("Inspecting Image Header for image type id\n");
1020 // Find the application name
1021 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)lpApplicationName
,
1022 &ApplicationNameString
, NULL
, NULL
)) {
1025 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
1027 InitializeObjectAttributes(&ObjectAttributes
,
1028 &ApplicationNameString
,
1029 OBJ_CASE_INSENSITIVE
,
1031 SecurityDescriptor
);
1033 // Try to open the executable
1034 Status
= NtOpenFile(&hFile
,
1035 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
1038 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
1039 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
1041 RtlFreeUnicodeString(&ApplicationNameString
);
1043 if (!NT_SUCCESS(Status
)) {
1044 DPRINT("Failed to open file\n");
1045 SetLastErrorByStatus(Status
);
1049 // Read the dos header
1050 Offset
.QuadPart
= 0;
1051 Status
= ZwReadFile(hFile
,
1061 if (!NT_SUCCESS(Status
)) {
1062 DPRINT("Failed to read from file\n");
1063 SetLastErrorByStatus(Status
);
1066 if (Iosb
.Information
!= sizeof(DosHeader
)) {
1067 DPRINT("Failed to read dos header from file\n");
1068 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
1072 // Check the DOS signature
1073 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) {
1074 DPRINT("Failed dos magic check\n");
1075 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT
);
1080 DPRINT("Launching VDM...\n");
1081 return CreateProcessW(L
"ntvdm.exe",
1082 (LPWSTR
)lpApplicationName
,
1083 lpProcessAttributes
,
1090 lpProcessInformation
);
1092 /////////////////////////////////////////
1094 * Create a new process
1096 Status
= NtCreateProcess(&hProcess
,
1106 if (lpStartupInfo
->lpReserved2
)
1109 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1110 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1111 * If is possible that this function overwrite the last information in runtimeinfo
1112 * with the null terminator for the unicode string.
1114 RuntimeInfo_U
.Length
= RuntimeInfo_U
.MaximumLength
= ROUND_UP(lpStartupInfo
->cbReserved2
, 2) + 2;
1115 RuntimeInfo_U
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Length
);
1116 memcpy(RuntimeInfo_U
.Buffer
, lpStartupInfo
->lpReserved2
, lpStartupInfo
->cbReserved2
);
1123 RtlCreateProcessParameters(&Ppb
,
1126 lpCurrentDirectory
? &CurrentDirectory_U
: NULL
,
1132 lpStartupInfo
&& lpStartupInfo
->lpReserved2
? &RuntimeInfo_U
: NULL
);
1134 if (lpStartupInfo
&& lpStartupInfo
->lpReserved2
)
1135 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U
.Buffer
);
1139 * Translate some handles for the new process
1141 if (Ppb
->CurrentDirectoryHandle
)
1143 Status
= NtDuplicateObject (NtCurrentProcess(),
1144 Ppb
->CurrentDirectoryHandle
,
1146 &Ppb
->CurrentDirectoryHandle
,
1149 DUPLICATE_SAME_ACCESS
);
1153 * Get some information about the executable
1155 Status
= ZwQuerySection(hSection
,
1156 SectionImageInformation
,
1166 * Get some information about the process
1168 NtQueryInformationProcess(hProcess
,
1169 ProcessBasicInformation
,
1171 sizeof(ProcessBasicInfo
),
1173 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1174 ProcessBasicInfo
.UniqueProcessId
);
1175 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1178 * Tell the csrss server we are creating a new process
1180 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
1181 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
1182 ProcessBasicInfo
.UniqueProcessId
;
1183 if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1185 /* Do not create a console for GUI applications */
1186 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1187 dwCreationFlags
|= DETACHED_PROCESS
;
1189 else if (Sii
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
1191 if (NULL
== Ppb
->hConsole
)
1193 dwCreationFlags
|= CREATE_NEW_CONSOLE
;
1196 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
1197 CsrRequest
.Data
.CreateProcessRequest
.CtrlDispatcher
= ConsoleControlDispatcher
;
1198 Status
= CsrClientCallServer(&CsrRequest
,
1200 sizeof(CSRSS_API_REQUEST
),
1201 sizeof(CSRSS_API_REPLY
));
1202 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1204 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1207 Ppb
->hConsole
= CsrReply
.Data
.CreateProcessReply
.Console
;
1213 /* Set the child console handles */
1215 /* First check if handles were passed in startup info */
1216 if (lpStartupInfo
&& (lpStartupInfo
->dwFlags
& STARTF_USESTDHANDLES
))
1218 if (lpStartupInfo
->hStdInput
)
1220 Ppb
->hStdInput
= lpStartupInfo
->hStdInput
;
1224 if (lpStartupInfo
->hStdOutput
)
1226 Ppb
->hStdOutput
= lpStartupInfo
->hStdOutput
;
1230 if (lpStartupInfo
->hStdError
)
1232 Ppb
->hStdError
= lpStartupInfo
->hStdError
;
1238 /* Check if new console was created, use it for input and output if
1240 if (0 != (dwCreationFlags
& CREATE_NEW_CONSOLE
)
1241 && NT_SUCCESS(Status
) && NT_SUCCESS(CsrReply
.Status
))
1245 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1251 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1257 Ppb
->hStdError
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1263 /* Use existing handles otherwise */
1266 Ppb
->hStdInput
= NtCurrentPeb()->ProcessParameters
->hStdInput
;
1271 Ppb
->hStdOutput
= NtCurrentPeb()->ProcessParameters
->hStdOutput
;
1276 Ppb
->hStdError
= NtCurrentPeb()->ProcessParameters
->hStdError
;
1280 /* Now duplicate handles if required */
1283 if (IsConsoleHandle(Ppb
->hStdInput
))
1285 Ppb
->hStdInput
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
1289 DPRINT("Duplicate input handle\n");
1290 Status
= NtDuplicateObject (NtCurrentProcess(),
1296 DUPLICATE_SAME_ACCESS
);
1297 if(!NT_SUCCESS(Status
))
1299 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1306 if (IsConsoleHandle(Ppb
->hStdOutput
))
1308 Ppb
->hStdOutput
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1312 DPRINT("Duplicate output handle\n");
1313 Status
= NtDuplicateObject (NtCurrentProcess(),
1319 DUPLICATE_SAME_ACCESS
);
1320 if(!NT_SUCCESS(Status
))
1322 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1329 if (IsConsoleHandle(Ppb
->hStdError
))
1331 CsrRequest
.Type
= CSRSS_DUPLICATE_HANDLE
;
1332 CsrRequest
.Data
.DuplicateHandleRequest
.ProcessId
= ProcessBasicInfo
.UniqueProcessId
;
1333 CsrRequest
.Data
.DuplicateHandleRequest
.Handle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;
1334 Status
= CsrClientCallServer(&CsrRequest
,
1336 sizeof(CSRSS_API_REQUEST
),
1337 sizeof(CSRSS_API_REPLY
));
1338 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
1340 Ppb
->hStdError
= INVALID_HANDLE_VALUE
;
1344 Ppb
->hStdError
= CsrReply
.Data
.DuplicateHandleReply
.Handle
;
1349 DPRINT("Duplicate error handle\n");
1350 Status
= NtDuplicateObject (NtCurrentProcess(),
1356 DUPLICATE_SAME_ACCESS
);
1357 if(!NT_SUCCESS(Status
))
1359 DPRINT("NtDuplicateObject failed, status %x\n", Status
);
1365 * Initialize some other fields in the PPB
1369 Ppb
->dwFlags
= lpStartupInfo
->dwFlags
;
1370 if (Ppb
->dwFlags
& STARTF_USESHOWWINDOW
)
1372 Ppb
->wShowWindow
= lpStartupInfo
->wShowWindow
;
1376 Ppb
->wShowWindow
= SW_SHOWDEFAULT
;
1378 Ppb
->dwX
= lpStartupInfo
->dwX
;
1379 Ppb
->dwY
= lpStartupInfo
->dwY
;
1380 Ppb
->dwXSize
= lpStartupInfo
->dwXSize
;
1381 Ppb
->dwYSize
= lpStartupInfo
->dwYSize
;
1382 Ppb
->dwFillAttribute
= lpStartupInfo
->dwFillAttribute
;
1390 * Create Process Environment Block
1392 DPRINT("Creating peb\n");
1394 KlInitPeb(hProcess
, Ppb
, &ImageBaseAddress
, Sii
.Subsystem
);
1396 RtlDestroyProcessParameters (Ppb
);
1398 Status
= NtSetInformationProcess(hProcess
,
1399 ProcessImageFileName
,
1403 * Create the thread for the kernel
1405 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1406 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
);
1407 hThread
= KlCreateFirstThread(hProcess
,
1410 ImageBaseAddress
+ (ULONG
)Sii
.EntryPoint
,
1412 &lpProcessInformation
->dwThreadId
);
1413 if (hThread
== INVALID_HANDLE_VALUE
)
1418 lpProcessInformation
->hProcess
= hProcess
;
1419 lpProcessInformation
->hThread
= hThread
;