1 /* $Id: create.c,v 1.35 2001/02/10 22:51:08 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/proc/proc.c
6 * PURPOSE: Process functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
12 /* INCLUDES ****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <kernel32/proc.h>
17 #include <kernel32/thread.h>
20 #include <napi/i386/segment.h>
21 #include <ntdll/ldr.h>
23 #include <ntdll/base.h>
24 #include <ntdll/rtl.h>
25 #include <csrss/csrss.h>
26 #include <ntdll/csr.h>
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
32 /* FUNCTIONS ****************************************************************/
37 LPCSTR lpApplicationName
,
39 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
40 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
41 WINBOOL bInheritHandles
,
42 DWORD dwCreationFlags
,
44 LPCSTR lpCurrentDirectory
,
45 LPSTARTUPINFOA lpStartupInfo
,
46 LPPROCESS_INFORMATION lpProcessInformation
49 * FUNCTION: The CreateProcess function creates a new process and its
50 * primary thread. The new process executes the specified executable file
53 * lpApplicationName = Pointer to name of executable module
54 * lpCommandLine = Pointer to command line string
55 * lpProcessAttributes = Process security attributes
56 * lpThreadAttributes = Thread security attributes
57 * bInheritHandles = Handle inheritance flag
58 * dwCreationFlags = Creation flags
59 * lpEnvironment = Pointer to new environment block
60 * lpCurrentDirectory = Pointer to current directory name
61 * lpStartupInfo = Pointer to startup info
62 * lpProcessInformation = Pointer to process information
65 UNICODE_STRING ApplicationNameU
;
66 UNICODE_STRING CurrentDirectoryU
;
67 UNICODE_STRING CommandLineU
;
68 ANSI_STRING ApplicationName
;
69 ANSI_STRING CurrentDirectory
;
70 ANSI_STRING CommandLine
;
73 DPRINT("CreateProcessA\n");
75 RtlInitAnsiString (&CommandLine
,
77 RtlInitAnsiString (&ApplicationName
,
78 (LPSTR
)lpApplicationName
);
79 RtlInitAnsiString (&CurrentDirectory
,
80 (LPSTR
)lpCurrentDirectory
);
82 /* convert ansi (or oem) strings to unicode */
85 RtlAnsiStringToUnicodeString (&CommandLineU
,
88 RtlAnsiStringToUnicodeString (&ApplicationNameU
,
91 RtlAnsiStringToUnicodeString (&CurrentDirectoryU
,
97 RtlOemStringToUnicodeString (&CommandLineU
,
100 RtlOemStringToUnicodeString (&ApplicationNameU
,
103 RtlOemStringToUnicodeString (&CurrentDirectoryU
,
108 Result
= CreateProcessW (ApplicationNameU
.Buffer
,
115 (lpCurrentDirectory
== NULL
) ? NULL
: CurrentDirectoryU
.Buffer
,
116 (LPSTARTUPINFOW
)lpStartupInfo
,
117 lpProcessInformation
);
119 RtlFreeUnicodeString (&ApplicationNameU
);
120 RtlFreeUnicodeString (&CommandLineU
);
121 RtlFreeUnicodeString (&CurrentDirectoryU
);
127 HANDLE STDCALL
KlCreateFirstThread(HANDLE ProcessHandle
,
128 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
130 LPTHREAD_START_ROUTINE lpStartAddress
,
131 DWORD dwCreationFlags
,
136 OBJECT_ATTRIBUTES ObjectAttributes
;
138 CONTEXT ThreadContext
;
139 INITIAL_TEB InitialTeb
;
140 BOOLEAN CreateSuspended
= FALSE
;
143 ObjectAttributes
.Length
= sizeof(OBJECT_ATTRIBUTES
);
144 ObjectAttributes
.RootDirectory
= NULL
;
145 ObjectAttributes
.ObjectName
= NULL
;
146 ObjectAttributes
.Attributes
= 0;
147 if (lpThreadAttributes
!= NULL
)
149 if (lpThreadAttributes
->bInheritHandle
)
150 ObjectAttributes
.Attributes
= OBJ_INHERIT
;
151 ObjectAttributes
.SecurityDescriptor
=
152 lpThreadAttributes
->lpSecurityDescriptor
;
154 ObjectAttributes
.SecurityQualityOfService
= NULL
;
156 if ((dwCreationFlags
& CREATE_SUSPENDED
) == CREATE_SUSPENDED
)
157 CreateSuspended
= TRUE
;
159 CreateSuspended
= FALSE
;
161 /* Allocate thread stack */
163 Status
= NtAllocateVirtualMemory(ProcessHandle
,
166 (PULONG
)&dwStackSize
,
169 if (!NT_SUCCESS(Status
))
174 memset(&ThreadContext
,0,sizeof(CONTEXT
));
175 ThreadContext
.Eip
= (ULONG
)lpStartAddress
;
176 ThreadContext
.SegGs
= USER_DS
;
177 ThreadContext
.SegFs
= USER_DS
;
178 ThreadContext
.SegEs
= USER_DS
;
179 ThreadContext
.SegDs
= USER_DS
;
180 ThreadContext
.SegCs
= USER_CS
;
181 ThreadContext
.SegSs
= USER_DS
;
182 ThreadContext
.Esp
= (ULONG
)(BaseAddress
+ dwStackSize
- 20);
183 ThreadContext
.EFlags
= (1<<1) + (1<<9);
185 DPRINT("ThreadContext.Eip %x\n",ThreadContext
.Eip
);
187 Status
= NtCreateThread(&ThreadHandle
,
195 if (lpThreadId
!= NULL
)
197 memcpy(lpThreadId
, &ClientId
.UniqueThread
,sizeof(ULONG
));
200 return(ThreadHandle
);
203 HANDLE
KlMapFile(LPCWSTR lpApplicationName
,
204 LPCWSTR lpCommandLine
)
207 IO_STATUS_BLOCK IoStatusBlock
;
208 UNICODE_STRING ApplicationNameString
;
209 OBJECT_ATTRIBUTES ObjectAttributes
;
210 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
217 * Find the application name
220 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
221 &ApplicationNameString
,
226 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
228 InitializeObjectAttributes(&ObjectAttributes
,
229 &ApplicationNameString
,
230 OBJ_CASE_INSENSITIVE
,
235 * Try to open the executable
238 Status
= NtOpenFile(&hFile
,
239 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
242 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
243 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
245 RtlFreeUnicodeString (&ApplicationNameString
);
247 if (!NT_SUCCESS(Status
))
249 DPRINT("Failed to open file\n");
250 SetLastErrorByStatus (Status
);
254 Status
= NtCreateSection(&hSection
,
263 if (!NT_SUCCESS(Status
))
265 DPRINT("Failed to create section\n");
266 SetLastErrorByStatus (Status
);
273 static NTSTATUS
KlInitPeb (HANDLE ProcessHandle
,
274 PRTL_USER_PROCESS_PARAMETERS Ppb
)
281 PVOID ParentEnv
= NULL
;
285 /* create the Environment */
286 if (Ppb
->Environment
!= NULL
)
287 ParentEnv
= Ppb
->Environment
;
288 else if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
289 ParentEnv
= NtCurrentPeb()->ProcessParameters
->Environment
;
291 if (ParentEnv
!= NULL
)
293 MEMORY_BASIC_INFORMATION MemInfo
;
295 Status
= NtQueryVirtualMemory (NtCurrentProcess (),
297 MemoryBasicInformation
,
299 sizeof(MEMORY_BASIC_INFORMATION
),
301 if (!NT_SUCCESS(Status
))
305 EnvSize
= MemInfo
.RegionSize
;
307 DPRINT("EnvironmentSize %ld\n", EnvSize
);
309 /* allocate and initialize new environment block */
312 Status
= NtAllocateVirtualMemory(ProcessHandle
,
318 if (!NT_SUCCESS(Status
))
323 NtWriteVirtualMemory(ProcessHandle
,
331 PpbBase
= (PVOID
)PEB_STARTUPINFO
;
332 PpbSize
= Ppb
->MaximumLength
;
333 Status
= NtAllocateVirtualMemory(ProcessHandle
,
339 if (!NT_SUCCESS(Status
))
344 DPRINT("Ppb->MaximumLength %x\n", Ppb
->MaximumLength
);
345 NtWriteVirtualMemory(ProcessHandle
,
351 /* write pointer to environment */
352 Offset
= FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
);
353 NtWriteVirtualMemory(ProcessHandle
,
354 (PVOID
)(PpbBase
+ Offset
),
359 /* write pointer to process parameter block */
360 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
361 NtWriteVirtualMemory(ProcessHandle
,
362 (PVOID
)(PEB_BASE
+ Offset
),
367 return(STATUS_SUCCESS
);
371 WINBOOL STDCALL
CreateProcessW(LPCWSTR lpApplicationName
,
372 LPWSTR lpCommandLine
,
373 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
374 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
375 WINBOOL bInheritHandles
,
376 DWORD dwCreationFlags
,
377 LPVOID lpEnvironment
,
378 LPCWSTR lpCurrentDirectory
,
379 LPSTARTUPINFOW lpStartupInfo
,
380 LPPROCESS_INFORMATION lpProcessInformation
)
382 HANDLE hSection
, hProcess
, hThread
;
384 LPTHREAD_START_ROUTINE lpStartAddress
= NULL
;
385 WCHAR TempCommandLine
[256];
386 WCHAR ImagePathName
[256];
387 UNICODE_STRING ImagePathName_U
;
388 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
390 PRTL_USER_PROCESS_PARAMETERS Ppb
;
391 UNICODE_STRING CommandLine_U
;
392 CSRSS_API_REQUEST CsrRequest
;
393 CSRSS_API_REPLY CsrReply
;
394 CHAR ImageFileName
[8];
398 ANSI_STRING ProcedureName
;
399 UNICODE_STRING CurrentDirectoryW
;
401 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
402 lpApplicationName
,lpCommandLine
);
405 * Store the image file name for the process
407 s
= wcsrchr(lpApplicationName
, '\\');
410 s
= (PWCHAR
)lpApplicationName
;
421 for (i
= 0; i
< 8; i
++)
423 ImageFileName
[i
] = (CHAR
)(s
[i
]);
431 * Process the application name and command line
434 RtlGetFullPathName_U ((LPWSTR
)lpApplicationName
,
438 wcscpy(ImagePathName
, TempCommandLine
);
439 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
441 if (lpCommandLine
!= NULL
)
443 wcscat(TempCommandLine
, L
" ");
444 wcscat(TempCommandLine
, lpCommandLine
);
447 /* Initialize the current directory string */
448 RtlInitUnicodeString(&CurrentDirectoryW
,
455 RtlInitUnicodeString(&CommandLine_U
, TempCommandLine
);
457 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
459 RtlCreateProcessParameters(&Ppb
,
462 (lpCurrentDirectory
== NULL
) ? NULL
: &CurrentDirectoryW
,
471 * Create a section for the executable
474 hSection
= KlMapFile (lpApplicationName
, lpCommandLine
);
475 if (hSection
== NULL
)
477 RtlDestroyProcessParameters (Ppb
);
482 * Create a new process
484 Status
= NtCreateProcess(&hProcess
,
494 * Get some information about the process
496 ZwQueryInformationProcess(hProcess
,
497 ProcessBasicInformation
,
499 sizeof(ProcessBasicInfo
),
501 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
502 ProcessBasicInfo
.UniqueProcessId
);
503 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
506 * Tell the csrss server we are creating a new process
508 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
509 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
510 ProcessBasicInfo
.UniqueProcessId
;
511 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
512 Status
= CsrClientCallServer(&CsrRequest
,
514 sizeof(CSRSS_API_REQUEST
),
515 sizeof(CSRSS_API_REPLY
));
516 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
518 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
522 * Create Process Environment Block
524 DPRINT("Creating peb\n");
526 Ppb
->InputHandle
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
527 Ppb
->OutputHandle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;;
528 Ppb
->ErrorHandle
= Ppb
->OutputHandle
;
529 KlInitPeb(hProcess
, Ppb
);
531 RtlDestroyProcessParameters (Ppb
);
533 Status
= NtSetInformationProcess(hProcess
,
534 ProcessImageFileName
,
538 * Retrieve the start address
540 DPRINT("Retrieving entry point address\n");
541 RtlInitAnsiString (&ProcedureName
, "LdrInitializeThunk");
542 Status
= LdrGetProcedureAddress ((PVOID
)NTDLL_BASE
,
545 (PVOID
*)&lpStartAddress
);
546 if (!NT_SUCCESS(Status
))
548 DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status
);
551 DPRINT("lpStartAddress 0x%08lx\n", (ULONG
)lpStartAddress
);
554 * Create the thread for the kernel
556 DPRINT("Creating thread for process\n");
557 hThread
= KlCreateFirstThread(hProcess
,
559 // Headers.OptionalHeader.SizeOfStackReserve,
563 &lpProcessInformation
->dwThreadId
);
570 lpProcessInformation
->hProcess
= hProcess
;
571 lpProcessInformation
->hThread
= hThread
;