1 /* $Id: create.c,v 1.39 2001/06/18 03:02:43 phreak 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 ****************************************************************/
35 CreateProcessA (LPCSTR lpApplicationName
,
37 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
38 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
39 WINBOOL bInheritHandles
,
40 DWORD dwCreationFlags
,
42 LPCSTR lpCurrentDirectory
,
43 LPSTARTUPINFOA lpStartupInfo
,
44 LPPROCESS_INFORMATION lpProcessInformation
)
46 * FUNCTION: The CreateProcess function creates a new process and its
47 * primary thread. The new process executes the specified executable file
50 * lpApplicationName = Pointer to name of executable module
51 * lpCommandLine = Pointer to command line string
52 * lpProcessAttributes = Process security attributes
53 * lpThreadAttributes = Thread security attributes
54 * bInheritHandles = Handle inheritance flag
55 * dwCreationFlags = Creation flags
56 * lpEnvironment = Pointer to new environment block
57 * lpCurrentDirectory = Pointer to current directory name
58 * lpStartupInfo = Pointer to startup info
59 * lpProcessInformation = Pointer to process information
62 UNICODE_STRING ApplicationNameU
;
63 UNICODE_STRING CurrentDirectoryU
;
64 UNICODE_STRING CommandLineU
;
65 ANSI_STRING ApplicationName
;
66 ANSI_STRING CurrentDirectory
;
67 ANSI_STRING CommandLine
;
70 DPRINT("CreateProcessA\n");
72 RtlInitAnsiString (&CommandLine
,
74 RtlInitAnsiString (&ApplicationName
,
75 (LPSTR
)lpApplicationName
);
76 RtlInitAnsiString (&CurrentDirectory
,
77 (LPSTR
)lpCurrentDirectory
);
79 /* convert ansi (or oem) strings to unicode */
82 RtlAnsiStringToUnicodeString (&CommandLineU
,
85 RtlAnsiStringToUnicodeString (&ApplicationNameU
,
88 RtlAnsiStringToUnicodeString (&CurrentDirectoryU
,
94 RtlOemStringToUnicodeString (&CommandLineU
,
97 RtlOemStringToUnicodeString (&ApplicationNameU
,
100 RtlOemStringToUnicodeString (&CurrentDirectoryU
,
105 Result
= CreateProcessW (ApplicationNameU
.Buffer
,
112 (lpCurrentDirectory
== NULL
) ? NULL
: CurrentDirectoryU
.Buffer
,
113 (LPSTARTUPINFOW
)lpStartupInfo
,
114 lpProcessInformation
);
116 RtlFreeUnicodeString (&ApplicationNameU
);
117 RtlFreeUnicodeString (&CommandLineU
);
118 RtlFreeUnicodeString (&CurrentDirectoryU
);
125 KlCreateFirstThread(HANDLE ProcessHandle
,
126 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
128 LPTHREAD_START_ROUTINE lpStartAddress
,
129 DWORD dwCreationFlags
,
134 OBJECT_ATTRIBUTES ObjectAttributes
;
136 CONTEXT ThreadContext
;
137 INITIAL_TEB InitialTeb
;
138 BOOLEAN CreateSuspended
= FALSE
;
141 ObjectAttributes
.Length
= sizeof(OBJECT_ATTRIBUTES
);
142 ObjectAttributes
.RootDirectory
= NULL
;
143 ObjectAttributes
.ObjectName
= NULL
;
144 ObjectAttributes
.Attributes
= 0;
145 if (lpThreadAttributes
!= NULL
)
147 if (lpThreadAttributes
->bInheritHandle
)
148 ObjectAttributes
.Attributes
= OBJ_INHERIT
;
149 ObjectAttributes
.SecurityDescriptor
=
150 lpThreadAttributes
->lpSecurityDescriptor
;
152 ObjectAttributes
.SecurityQualityOfService
= NULL
;
154 if ((dwCreationFlags
& CREATE_SUSPENDED
) == CREATE_SUSPENDED
)
155 CreateSuspended
= TRUE
;
157 CreateSuspended
= FALSE
;
159 /* Allocate thread stack */
161 Status
= NtAllocateVirtualMemory(ProcessHandle
,
164 (PULONG
)&dwStackSize
,
167 if (!NT_SUCCESS(Status
))
172 memset(&ThreadContext
,0,sizeof(CONTEXT
));
173 ThreadContext
.Eip
= (ULONG
)lpStartAddress
;
174 ThreadContext
.SegGs
= USER_DS
;
175 ThreadContext
.SegFs
= USER_DS
;
176 ThreadContext
.SegEs
= USER_DS
;
177 ThreadContext
.SegDs
= USER_DS
;
178 ThreadContext
.SegCs
= USER_CS
;
179 ThreadContext
.SegSs
= USER_DS
;
180 ThreadContext
.Esp
= (ULONG
)(BaseAddress
+ dwStackSize
- 20);
181 ThreadContext
.EFlags
= (1<<1) + (1<<9);
183 DPRINT("ThreadContext.Eip %x\n",ThreadContext
.Eip
);
185 Status
= NtCreateThread(&ThreadHandle
,
193 if (lpThreadId
!= NULL
)
195 memcpy(lpThreadId
, &ClientId
.UniqueThread
,sizeof(ULONG
));
198 return(ThreadHandle
);
202 KlMapFile(LPCWSTR lpApplicationName
,
203 LPCWSTR lpCommandLine
)
206 IO_STATUS_BLOCK IoStatusBlock
;
207 UNICODE_STRING ApplicationNameString
;
208 OBJECT_ATTRIBUTES ObjectAttributes
;
209 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
216 * Find the application name
219 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpApplicationName
,
220 &ApplicationNameString
,
225 DPRINT("ApplicationName %S\n",ApplicationNameString
.Buffer
);
227 InitializeObjectAttributes(&ObjectAttributes
,
228 &ApplicationNameString
,
229 OBJ_CASE_INSENSITIVE
,
234 * Try to open the executable
237 Status
= NtOpenFile(&hFile
,
238 SYNCHRONIZE
|FILE_EXECUTE
|FILE_READ_DATA
,
241 FILE_SHARE_DELETE
|FILE_SHARE_READ
,
242 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
);
244 RtlFreeUnicodeString (&ApplicationNameString
);
246 if (!NT_SUCCESS(Status
))
248 DPRINT("Failed to open file\n");
249 SetLastErrorByStatus (Status
);
253 Status
= NtCreateSection(&hSection
,
262 if (!NT_SUCCESS(Status
))
264 DPRINT("Failed to create section\n");
265 SetLastErrorByStatus (Status
);
273 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
);
372 CreateProcessW(LPCWSTR lpApplicationName
,
373 LPWSTR lpCommandLine
,
374 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
375 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
376 WINBOOL bInheritHandles
,
377 DWORD dwCreationFlags
,
378 LPVOID lpEnvironment
,
379 LPCWSTR lpCurrentDirectory
,
380 LPSTARTUPINFOW lpStartupInfo
,
381 LPPROCESS_INFORMATION lpProcessInformation
)
383 HANDLE hSection
, hProcess
, hThread
;
385 LPTHREAD_START_ROUTINE lpStartAddress
= NULL
;
386 WCHAR TempCommandLine
[256];
387 WCHAR ImagePathName
[256];
388 UNICODE_STRING ImagePathName_U
;
389 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
391 PRTL_USER_PROCESS_PARAMETERS Ppb
;
392 UNICODE_STRING CommandLine_U
;
393 CSRSS_API_REQUEST CsrRequest
;
394 CSRSS_API_REPLY CsrReply
;
395 CHAR ImageFileName
[8];
399 ANSI_STRING ProcedureName
;
400 UNICODE_STRING CurrentDirectoryW
;
401 SECTION_IMAGE_INFORMATION Sii
;
403 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
404 lpApplicationName
,lpCommandLine
);
407 * Store the image file name for the process
409 s
= wcsrchr(lpApplicationName
, '\\');
412 s
= (PWCHAR
)lpApplicationName
;
423 for (i
= 0; i
< 8; i
++)
425 ImageFileName
[i
] = (CHAR
)(s
[i
]);
433 * Process the application name and command line
436 RtlGetFullPathName_U ((LPWSTR
)lpApplicationName
,
440 wcscpy(ImagePathName
, TempCommandLine
);
441 RtlInitUnicodeString(&ImagePathName_U
, ImagePathName
);
443 if (lpCommandLine
!= NULL
)
445 wcscat(TempCommandLine
, L
" ");
446 wcscat(TempCommandLine
, lpCommandLine
);
449 /* Initialize the current directory string */
450 RtlInitUnicodeString(&CurrentDirectoryW
,
457 RtlInitUnicodeString(&CommandLine_U
, lpCommandLine
);
459 DPRINT("CommandLine_U %S\n", CommandLine_U
.Buffer
);
461 RtlCreateProcessParameters(&Ppb
,
464 (lpCurrentDirectory
== NULL
) ? NULL
: &CurrentDirectoryW
,
473 * Create a section for the executable
476 hSection
= KlMapFile (lpApplicationName
, lpCommandLine
);
477 if (hSection
== NULL
)
479 RtlDestroyProcessParameters (Ppb
);
484 * Create a new process
486 Status
= NtCreateProcess(&hProcess
,
496 * Get some information about the executable
498 Status
= ZwQuerySection(hSection
,
499 SectionImageInformation
,
510 * Get some information about the process
512 ZwQueryInformationProcess(hProcess
,
513 ProcessBasicInformation
,
515 sizeof(ProcessBasicInfo
),
517 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
518 ProcessBasicInfo
.UniqueProcessId
);
519 lpProcessInformation
->dwProcessId
= ProcessBasicInfo
.UniqueProcessId
;
522 * Tell the csrss server we are creating a new process
524 CsrRequest
.Type
= CSRSS_CREATE_PROCESS
;
525 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
=
526 ProcessBasicInfo
.UniqueProcessId
;
527 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
528 Status
= CsrClientCallServer(&CsrRequest
,
530 sizeof(CSRSS_API_REQUEST
),
531 sizeof(CSRSS_API_REPLY
));
532 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrReply
.Status
))
534 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
538 * Create Process Environment Block
540 DPRINT("Creating peb\n");
542 Ppb
->InputHandle
= CsrReply
.Data
.CreateProcessReply
.InputHandle
;
543 Ppb
->OutputHandle
= CsrReply
.Data
.CreateProcessReply
.OutputHandle
;;
544 Ppb
->ErrorHandle
= Ppb
->OutputHandle
;
545 KlInitPeb(hProcess
, Ppb
);
547 RtlDestroyProcessParameters (Ppb
);
549 Status
= NtSetInformationProcess(hProcess
,
550 ProcessImageFileName
,
554 * Retrieve the start address
556 DPRINT("Retrieving entry point address\n");
557 RtlInitAnsiString (&ProcedureName
, "LdrInitializeThunk");
558 Status
= LdrGetProcedureAddress ((PVOID
)NTDLL_BASE
,
561 (PVOID
*)&lpStartAddress
);
562 if (!NT_SUCCESS(Status
))
564 DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status
);
567 DPRINT("lpStartAddress 0x%08lx\n", (ULONG
)lpStartAddress
);
570 * Create the thread for the kernel
572 DPRINT("Creating thread for process\n");
573 hThread
= KlCreateFirstThread(hProcess
,
579 &lpProcessInformation
->dwThreadId
);
586 lpProcessInformation
->hProcess
= hProcess
;
587 lpProcessInformation
->hThread
= hThread
;