2002-08-08 David Welch <welch@computer2.darkstar.org>
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.47 2002/08/08 17:54:12 dwelch Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <windows.h>
16 #include <kernel32/proc.h>
17 #include <kernel32/thread.h>
18 #include <wchar.h>
19 #include <string.h>
20 #include <napi/i386/segment.h>
21 #include <ntdll/ldr.h>
22 #include <napi/teb.h>
23 #include <ntdll/base.h>
24 #include <ntdll/rtl.h>
25 #include <csrss/csrss.h>
26 #include <ntdll/csr.h>
27
28 #define NDEBUG
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
31
32 /* FUNCTIONS ****************************************************************/
33
34 WINBOOL STDCALL
35 CreateProcessA (LPCSTR lpApplicationName,
36 LPSTR lpCommandLine,
37 LPSECURITY_ATTRIBUTES lpProcessAttributes,
38 LPSECURITY_ATTRIBUTES lpThreadAttributes,
39 WINBOOL bInheritHandles,
40 DWORD dwCreationFlags,
41 LPVOID lpEnvironment,
42 LPCSTR lpCurrentDirectory,
43 LPSTARTUPINFOA lpStartupInfo,
44 LPPROCESS_INFORMATION lpProcessInformation)
45 /*
46 * FUNCTION: The CreateProcess function creates a new process and its
47 * primary thread. The new process executes the specified executable file
48 * ARGUMENTS:
49 *
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
60 */
61 {
62 PWCHAR lpEnvironmentW = NULL;
63 UNICODE_STRING ApplicationNameU;
64 UNICODE_STRING CurrentDirectoryU;
65 UNICODE_STRING CommandLineU;
66 ANSI_STRING ApplicationName;
67 ANSI_STRING CurrentDirectory;
68 ANSI_STRING CommandLine;
69 WINBOOL Result;
70 CHAR TempCurrentDirectoryA[256];
71
72 DPRINT("CreateProcessA(%s)\n", lpApplicationName);
73 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
74 "lpStartupInfo %x, lpProcessInformation %x\n", dwCreationFlags,
75 lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
76
77 if (lpEnvironment)
78 {
79 PCHAR ptr = lpEnvironment;
80 ULONG len = 0;
81 UNICODE_STRING EnvironmentU;
82 ANSI_STRING EnvironmentA;
83 while (*ptr)
84 {
85 RtlInitAnsiString(&EnvironmentA, ptr);
86 if (bIsFileApiAnsi)
87 len += RtlAnsiStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
88 else
89 len += RtlOemStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
90 ptr += EnvironmentA.MaximumLength;
91 }
92 len += sizeof(WCHAR);
93 lpEnvironmentW = (PWCHAR)RtlAllocateHeap(GetProcessHeap(),
94 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
95 len);
96 if (lpEnvironmentW == NULL)
97 {
98 return FALSE;
99 }
100 ptr = lpEnvironment;
101 EnvironmentU.Buffer = lpEnvironmentW;
102 EnvironmentU.Length = 0;
103 EnvironmentU.MaximumLength = len;
104 while (*ptr)
105 {
106 RtlInitAnsiString(&EnvironmentA, ptr);
107 if (bIsFileApiAnsi)
108 RtlAnsiStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
109 else
110 RtlOemStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
111 ptr += EnvironmentA.MaximumLength;
112 EnvironmentU.Buffer += (EnvironmentU.Length / sizeof(WCHAR) + 1);
113 EnvironmentU.MaximumLength -= (EnvironmentU.Length + sizeof(WCHAR));
114 EnvironmentU.Length = 0;
115 }
116
117 EnvironmentU.Buffer[0] = 0;
118 }
119
120 RtlInitAnsiString (&CommandLine,
121 lpCommandLine);
122 RtlInitAnsiString (&ApplicationName,
123 (LPSTR)lpApplicationName);
124 if (lpCurrentDirectory != NULL)
125 {
126 RtlInitAnsiString (&CurrentDirectory,
127 (LPSTR)lpCurrentDirectory);
128 }
129
130 /* convert ansi (or oem) strings to unicode */
131 if (bIsFileApiAnsi)
132 {
133 RtlAnsiStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
134 RtlAnsiStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
135 if (lpCurrentDirectory != NULL)
136 RtlAnsiStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
137 }
138 else
139 {
140 RtlOemStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
141 RtlOemStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
142 if (lpCurrentDirectory != NULL)
143 RtlOemStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
144 }
145
146 Result = CreateProcessW (ApplicationNameU.Buffer,
147 CommandLineU.Buffer,
148 lpProcessAttributes,
149 lpThreadAttributes,
150 bInheritHandles,
151 dwCreationFlags,
152 lpEnvironmentW,
153 (lpCurrentDirectory == NULL) ? NULL : CurrentDirectoryU.Buffer,
154 (LPSTARTUPINFOW)lpStartupInfo,
155 lpProcessInformation);
156
157 RtlFreeUnicodeString (&ApplicationNameU);
158 RtlFreeUnicodeString (&CommandLineU);
159 if (lpCurrentDirectory != NULL)
160 RtlFreeUnicodeString (&CurrentDirectoryU);
161
162 if (lpEnvironmentW)
163 {
164 RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW);
165 }
166
167 return Result;
168 }
169
170
171 HANDLE STDCALL
172 KlCreateFirstThread(HANDLE ProcessHandle,
173 LPSECURITY_ATTRIBUTES lpThreadAttributes,
174 ULONG StackReserve,
175 ULONG StackCommit,
176 LPTHREAD_START_ROUTINE lpStartAddress,
177 DWORD dwCreationFlags,
178 LPDWORD lpThreadId)
179 {
180 NTSTATUS Status;
181 HANDLE ThreadHandle;
182 OBJECT_ATTRIBUTES ObjectAttributes;
183 CLIENT_ID ClientId;
184 CONTEXT ThreadContext;
185 INITIAL_TEB InitialTeb;
186 BOOLEAN CreateSuspended = FALSE;
187 ULONG OldPageProtection;
188 ULONG ResultLength;
189 ULONG InitialStack[5];
190
191 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
192 ObjectAttributes.RootDirectory = NULL;
193 ObjectAttributes.ObjectName = NULL;
194 ObjectAttributes.Attributes = 0;
195 if (lpThreadAttributes != NULL)
196 {
197 if (lpThreadAttributes->bInheritHandle)
198 ObjectAttributes.Attributes = OBJ_INHERIT;
199 ObjectAttributes.SecurityDescriptor =
200 lpThreadAttributes->lpSecurityDescriptor;
201 }
202 ObjectAttributes.SecurityQualityOfService = NULL;
203
204 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
205 CreateSuspended = TRUE;
206 else
207 CreateSuspended = FALSE;
208
209 InitialTeb.StackReserve = (StackReserve < 0x100000) ? 0x100000 : StackReserve;
210 /* FIXME: use correct commit size */
211 #if 0
212 InitialTeb.StackCommit = (StackCommit < PAGESIZE) ? PAGESIZE : StackCommit;
213 #endif
214 InitialTeb.StackCommit = InitialTeb.StackReserve - PAGESIZE;
215
216 /* size of guard page */
217 InitialTeb.StackCommit += PAGESIZE;
218
219 /* Reserve stack */
220 InitialTeb.StackAllocate = NULL;
221 Status = NtAllocateVirtualMemory(ProcessHandle,
222 &InitialTeb.StackAllocate,
223 0,
224 &InitialTeb.StackReserve,
225 MEM_RESERVE,
226 PAGE_READWRITE);
227 if (!NT_SUCCESS(Status))
228 {
229 DPRINT("Error reserving stack space!\n");
230 SetLastErrorByStatus(Status);
231 return(NULL);
232 }
233
234 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
235 InitialTeb.StackAllocate, InitialTeb.StackReserve);
236
237 InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
238 InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
239
240 DPRINT("StackBase: %p StackCommit: %p\n",
241 InitialTeb.StackBase, InitialTeb.StackCommit);
242
243 /* Commit stack page(s) */
244 Status = NtAllocateVirtualMemory(ProcessHandle,
245 &InitialTeb.StackLimit,
246 0,
247 &InitialTeb.StackCommit,
248 MEM_COMMIT,
249 PAGE_READWRITE);
250 if (!NT_SUCCESS(Status))
251 {
252 /* release the stack space */
253 NtFreeVirtualMemory(ProcessHandle,
254 InitialTeb.StackAllocate,
255 &InitialTeb.StackReserve,
256 MEM_RELEASE);
257
258 DPRINT("Error comitting stack page(s)!\n");
259 SetLastErrorByStatus(Status);
260 return(NULL);
261 }
262
263 DPRINT("StackLimit: %p\n",
264 InitialTeb.StackLimit);
265
266 /* Protect guard page */
267 Status = NtProtectVirtualMemory(ProcessHandle,
268 InitialTeb.StackLimit,
269 PAGESIZE,
270 PAGE_GUARD | PAGE_READWRITE,
271 &OldPageProtection);
272 if (!NT_SUCCESS(Status))
273 {
274 /* release the stack space */
275 NtFreeVirtualMemory(ProcessHandle,
276 InitialTeb.StackAllocate,
277 &InitialTeb.StackReserve,
278 MEM_RELEASE);
279
280 DPRINT("Error comitting guard page!\n");
281 SetLastErrorByStatus(Status);
282 return(NULL);
283 }
284
285 memset(&ThreadContext,0,sizeof(CONTEXT));
286 ThreadContext.Eip = (ULONG)lpStartAddress;
287 ThreadContext.SegGs = USER_DS;
288 ThreadContext.SegFs = USER_DS;
289 ThreadContext.SegEs = USER_DS;
290 ThreadContext.SegDs = USER_DS;
291 ThreadContext.SegCs = USER_CS;
292 ThreadContext.SegSs = USER_DS;
293 ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 20;
294 ThreadContext.EFlags = (1<<1) + (1<<9);
295
296 DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
297
298 /*
299 * Write in the initial stack.
300 */
301 InitialStack[0] = 0;
302 InitialStack[1] = PEB_BASE;
303 Status = ZwWriteVirtualMemory(ProcessHandle,
304 (PVOID)ThreadContext.Esp,
305 InitialStack,
306 sizeof(InitialStack),
307 &ResultLength);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT1("Failed to write initial stack.\n");
311 return(Status);
312 }
313
314 Status = NtCreateThread(&ThreadHandle,
315 THREAD_ALL_ACCESS,
316 &ObjectAttributes,
317 ProcessHandle,
318 &ClientId,
319 &ThreadContext,
320 &InitialTeb,
321 CreateSuspended);
322 if (!NT_SUCCESS(Status))
323 {
324 NtFreeVirtualMemory(ProcessHandle,
325 InitialTeb.StackAllocate,
326 &InitialTeb.StackReserve,
327 MEM_RELEASE);
328 SetLastErrorByStatus(Status);
329 return(NULL);
330 }
331
332 if (lpThreadId != NULL)
333 {
334 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
335 }
336
337 return(ThreadHandle);
338 }
339
340 HANDLE
341 KlMapFile(LPCWSTR lpApplicationName)
342 {
343 HANDLE hFile;
344 IO_STATUS_BLOCK IoStatusBlock;
345 UNICODE_STRING ApplicationNameString;
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
348 NTSTATUS Status;
349 HANDLE hSection;
350
351 hFile = NULL;
352
353 /*
354 * Find the application name
355 */
356
357 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
358 &ApplicationNameString,
359 NULL,
360 NULL))
361 return NULL;
362
363 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
364
365 InitializeObjectAttributes(&ObjectAttributes,
366 &ApplicationNameString,
367 OBJ_CASE_INSENSITIVE,
368 NULL,
369 SecurityDescriptor);
370
371 /*
372 * Try to open the executable
373 */
374
375 Status = NtOpenFile(&hFile,
376 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
377 &ObjectAttributes,
378 &IoStatusBlock,
379 FILE_SHARE_DELETE|FILE_SHARE_READ,
380 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
381
382 RtlFreeUnicodeString (&ApplicationNameString);
383
384 if (!NT_SUCCESS(Status))
385 {
386 DPRINT("Failed to open file\n");
387 SetLastErrorByStatus (Status);
388 return(NULL);
389 }
390
391 Status = NtCreateSection(&hSection,
392 SECTION_ALL_ACCESS,
393 NULL,
394 NULL,
395 PAGE_EXECUTE,
396 SEC_IMAGE,
397 hFile);
398 NtClose(hFile);
399
400 if (!NT_SUCCESS(Status))
401 {
402 DPRINT("Failed to create section\n");
403 SetLastErrorByStatus (Status);
404 return(NULL);
405 }
406
407 return(hSection);
408 }
409
410 static NTSTATUS
411 KlInitPeb (HANDLE ProcessHandle,
412 PRTL_USER_PROCESS_PARAMETERS Ppb,
413 PVOID* ImageBaseAddress)
414 {
415 NTSTATUS Status;
416 PVOID PpbBase;
417 ULONG PpbSize;
418 ULONG BytesWritten;
419 ULONG Offset;
420 PVOID ParentEnv = NULL;
421 PVOID EnvPtr = NULL;
422 PWCHAR ptr;
423 ULONG EnvSize = 0, EnvSize1 = 0;
424
425 /* create the Environment */
426 if (Ppb->Environment != NULL)
427 {
428 ParentEnv = Ppb->Environment;
429 ptr = ParentEnv;
430 while (*ptr)
431 {
432 while(*ptr++);
433 }
434 ptr++;
435 EnvSize = (PVOID)ptr - ParentEnv;
436 }
437 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
438 {
439 MEMORY_BASIC_INFORMATION MemInfo;
440 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
441
442 Status = NtQueryVirtualMemory (NtCurrentProcess (),
443 ParentEnv,
444 MemoryBasicInformation,
445 &MemInfo,
446 sizeof(MEMORY_BASIC_INFORMATION),
447 NULL);
448 if (!NT_SUCCESS(Status))
449 {
450 return Status;
451 }
452 EnvSize = MemInfo.RegionSize;
453 }
454 DPRINT("EnvironmentSize %ld\n", EnvSize);
455
456 /* allocate and initialize new environment block */
457 if (EnvSize != 0)
458 {
459 EnvSize1 = EnvSize;
460 Status = NtAllocateVirtualMemory(ProcessHandle,
461 &EnvPtr,
462 0,
463 &EnvSize1,
464 MEM_RESERVE | MEM_COMMIT,
465 PAGE_READWRITE);
466 if (!NT_SUCCESS(Status))
467 {
468 return(Status);
469 }
470
471 NtWriteVirtualMemory(ProcessHandle,
472 EnvPtr,
473 ParentEnv,
474 EnvSize,
475 &BytesWritten);
476 }
477
478 /* create the PPB */
479 PpbBase = NULL;
480 PpbSize = Ppb->MaximumLength;
481 Status = NtAllocateVirtualMemory(ProcessHandle,
482 &PpbBase,
483 0,
484 &PpbSize,
485 MEM_RESERVE | MEM_COMMIT,
486 PAGE_READWRITE);
487 if (!NT_SUCCESS(Status))
488 {
489 return(Status);
490 }
491
492 DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
493 NtWriteVirtualMemory(ProcessHandle,
494 PpbBase,
495 Ppb,
496 Ppb->MaximumLength,
497 &BytesWritten);
498
499 /* write pointer to environment */
500 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
501 NtWriteVirtualMemory(ProcessHandle,
502 (PVOID)(PpbBase + Offset),
503 &EnvPtr,
504 sizeof(EnvPtr),
505 &BytesWritten);
506
507 /* write pointer to process parameter block */
508 Offset = FIELD_OFFSET(PEB, ProcessParameters);
509 NtWriteVirtualMemory(ProcessHandle,
510 (PVOID)(PEB_BASE + Offset),
511 &PpbBase,
512 sizeof(PpbBase),
513 &BytesWritten);
514
515 /* Read image base address. */
516 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
517 NtReadVirtualMemory(ProcessHandle,
518 (PVOID)(PEB_BASE + Offset),
519 ImageBaseAddress,
520 sizeof(PVOID),
521 &BytesWritten);
522
523 return(STATUS_SUCCESS);
524 }
525
526
527 WINBOOL STDCALL
528 CreateProcessW(LPCWSTR lpApplicationName,
529 LPWSTR lpCommandLine,
530 LPSECURITY_ATTRIBUTES lpProcessAttributes,
531 LPSECURITY_ATTRIBUTES lpThreadAttributes,
532 WINBOOL bInheritHandles,
533 DWORD dwCreationFlags,
534 LPVOID lpEnvironment,
535 LPCWSTR lpCurrentDirectory,
536 LPSTARTUPINFOW lpStartupInfo,
537 LPPROCESS_INFORMATION lpProcessInformation)
538 {
539 HANDLE hSection, hProcess, hThread;
540 NTSTATUS Status;
541 LPTHREAD_START_ROUTINE lpStartAddress = NULL;
542 WCHAR ImagePathName[256];
543 UNICODE_STRING ImagePathName_U;
544 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
545 ULONG retlen;
546 PRTL_USER_PROCESS_PARAMETERS Ppb;
547 UNICODE_STRING CommandLine_U;
548 CSRSS_API_REQUEST CsrRequest;
549 CSRSS_API_REPLY CsrReply;
550 CHAR ImageFileName[8];
551 PWCHAR s, e;
552 ULONG i, len;
553 ANSI_STRING ProcedureName;
554 UNICODE_STRING CurrentDirectory_U;
555 SECTION_IMAGE_INFORMATION Sii;
556 WCHAR TempCurrentDirectoryW[256];
557 WCHAR TempApplicationNameW[256];
558 WCHAR TempCommandLineNameW[256];
559 UNICODE_STRING RuntimeInfo_U;
560 PVOID ImageBaseAddress;
561
562 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
563 lpApplicationName, lpCommandLine);
564
565 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
566 {
567 wcscpy (TempApplicationNameW, lpApplicationName);
568 i = wcslen(TempApplicationNameW);
569 if (TempApplicationNameW[i - 1] == L'.')
570 {
571 TempApplicationNameW[i - 1] = 0;
572 }
573 else
574 {
575 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
576 if (s == NULL)
577 {
578 s = TempApplicationNameW;
579 }
580 else
581 {
582 s++;
583 }
584 e = wcsrchr(s, L'.');
585 if (e == NULL)
586 {
587 wcscat(s, L".exe");
588 e = wcsrchr(s, L'.');
589 }
590 }
591 }
592 else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
593 {
594 if (lpCommandLine[0] == L'"')
595 {
596 wcscpy(TempApplicationNameW, &lpCommandLine[0]);
597 s = wcschr(TempApplicationNameW, L'"');
598 if (s == NULL)
599 {
600 return FALSE;
601 }
602 *s = 0;
603 }
604 else
605 {
606 wcscpy(TempApplicationNameW, lpCommandLine);
607 s = wcschr(TempApplicationNameW, L' ');
608 if (s != NULL)
609 {
610 *s = 0;
611 }
612 }
613 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
614 if (s == NULL)
615 {
616 s = TempApplicationNameW;
617 }
618 s = wcsrchr(TempApplicationNameW, L'.');
619 if (s == NULL)
620 wcscat(TempApplicationNameW, L".exe");
621 }
622 else
623 {
624 return FALSE;
625 }
626
627 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
628 {
629 return FALSE;
630 }
631
632 e = wcsrchr(s, L'.');
633 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
634 {
635 // the command is a batch file
636 if (lpApplicationName != NULL && lpApplicationName[0])
637 {
638 // FIXME: use COMSPEC for the command interpreter
639 wcscpy(TempCommandLineNameW, L"cmd /c ");
640 wcscat(TempCommandLineNameW, lpApplicationName);
641 lpCommandLine = TempCommandLineNameW;
642 wcscpy(TempApplicationNameW, L"cmd.exe");
643 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
644 {
645 return FALSE;
646 }
647 }
648 else
649 {
650 return FALSE;
651 }
652 }
653
654 /*
655 * Store the image file name for the process
656 */
657 e = wcschr(s, L'.');
658 if (e != NULL)
659 {
660 *e = 0;
661 }
662 for (i = 0; i < 8; i++)
663 {
664 ImageFileName[i] = (CHAR)(s[i]);
665 }
666 if (e != NULL)
667 {
668 *e = '.';
669 }
670
671 /*
672 * Process the application name and command line
673 */
674 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
675 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
676
677 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
678 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
679
680 /* Initialize the current directory string */
681 if (lpCurrentDirectory != NULL)
682 {
683 RtlInitUnicodeString(&CurrentDirectory_U,
684 lpCurrentDirectory);
685 }
686 else
687 {
688 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
689 RtlInitUnicodeString(&CurrentDirectory_U,
690 TempCurrentDirectoryW);
691 }
692
693
694 /*
695 * Create a section for the executable
696 */
697
698 hSection = KlMapFile (ImagePathName);
699 if (hSection == NULL)
700 {
701 return FALSE;
702 }
703
704 /*
705 * Create a new process
706 */
707 Status = NtCreateProcess(&hProcess,
708 PROCESS_ALL_ACCESS,
709 NULL,
710 NtCurrentProcess(),
711 bInheritHandles,
712 hSection,
713 NULL,
714 NULL);
715 if (lpStartupInfo)
716 {
717 if (lpStartupInfo->lpReserved2)
718 {
719 ULONG i, Count = *(ULONG*)lpStartupInfo->lpReserved2;
720 HANDLE * hFile;
721 HANDLE hTemp;
722 PRTL_USER_PROCESS_PARAMETERS CurrPpb = NtCurrentPeb()->ProcessParameters;
723
724
725 /* FIXME:
726 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
727 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
728 * If is possible that this function overwrite the last information in runtimeinfo
729 * with the null terminator for the unicode string.
730 */
731 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
732 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
733 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
734 }
735 }
736
737 /*
738 * Create the PPB
739 */
740 RtlCreateProcessParameters(&Ppb,
741 &ImagePathName_U,
742 NULL,
743 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
744 &CommandLine_U,
745 lpEnvironment,
746 NULL,
747 NULL,
748 NULL,
749 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
750
751 if (lpStartupInfo && lpStartupInfo->lpReserved2)
752 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
753
754
755 /*
756 * Translate some handles for the new process
757 */
758 if (Ppb->CurrentDirectory.Handle)
759 {
760 Status = NtDuplicateObject (NtCurrentProcess(),
761 Ppb->CurrentDirectory.Handle,
762 hProcess,
763 &Ppb->CurrentDirectory.Handle,
764 0,
765 TRUE,
766 DUPLICATE_SAME_ACCESS);
767 }
768
769 if (Ppb->ConsoleHandle)
770 {
771 Status = NtDuplicateObject (NtCurrentProcess(),
772 Ppb->ConsoleHandle,
773 hProcess,
774 &Ppb->ConsoleHandle,
775 0,
776 TRUE,
777 DUPLICATE_SAME_ACCESS);
778 }
779
780 /*
781 * Get some information about the executable
782 */
783 Status = ZwQuerySection(hSection,
784 SectionImageInformation,
785 &Sii,
786 sizeof(Sii),
787 &i);
788 /*
789 * Close the section
790 */
791 NtClose(hSection);
792
793 /*
794 * Get some information about the process
795 */
796 ZwQueryInformationProcess(hProcess,
797 ProcessBasicInformation,
798 &ProcessBasicInfo,
799 sizeof(ProcessBasicInfo),
800 &retlen);
801 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
802 ProcessBasicInfo.UniqueProcessId);
803 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
804
805 /*
806 * Tell the csrss server we are creating a new process
807 */
808 CsrRequest.Type = CSRSS_CREATE_PROCESS;
809 CsrRequest.Data.CreateProcessRequest.NewProcessId =
810 ProcessBasicInfo.UniqueProcessId;
811 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
812 Status = CsrClientCallServer(&CsrRequest,
813 &CsrReply,
814 sizeof(CSRSS_API_REQUEST),
815 sizeof(CSRSS_API_REPLY));
816 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
817 {
818 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
819 }
820
821 // Set the child console handles
822 Ppb->InputHandle = NtCurrentPeb()->ProcessParameters->InputHandle;
823 Ppb->OutputHandle = NtCurrentPeb()->ProcessParameters->OutputHandle;
824 Ppb->ErrorHandle = NtCurrentPeb()->ProcessParameters->ErrorHandle;
825
826 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
827 {
828 if (lpStartupInfo->hStdInput)
829 Ppb->InputHandle = lpStartupInfo->hStdInput;
830 if (lpStartupInfo->hStdOutput)
831 Ppb->OutputHandle = lpStartupInfo->hStdOutput;
832 if (lpStartupInfo->hStdError)
833 Ppb->ErrorHandle = lpStartupInfo->hStdError;
834 }
835
836 if (IsConsoleHandle(Ppb->InputHandle))
837 {
838 Ppb->InputHandle = CsrReply.Data.CreateProcessReply.InputHandle;
839 }
840 else
841 {
842 DPRINT("Duplicate input handle\n");
843 Status = NtDuplicateObject (NtCurrentProcess(),
844 Ppb->InputHandle,
845 hProcess,
846 &Ppb->InputHandle,
847 0,
848 TRUE,
849 DUPLICATE_SAME_ACCESS);
850 if(!NT_SUCCESS(Status))
851 {
852 DPRINT("NtDuplicateObject failed, status %x\n", Status);
853 }
854 }
855
856 if (IsConsoleHandle(Ppb->OutputHandle))
857 {
858 Ppb->OutputHandle = CsrReply.Data.CreateProcessReply.OutputHandle;
859 }
860 else
861 {
862 DPRINT("Duplicate output handle\n");
863 Status = NtDuplicateObject (NtCurrentProcess(),
864 Ppb->OutputHandle,
865 hProcess,
866 &Ppb->OutputHandle,
867 0,
868 TRUE,
869 DUPLICATE_SAME_ACCESS);
870 if(!NT_SUCCESS(Status))
871 {
872 DPRINT("NtDuplicateObject failed, status %x\n", Status);
873 }
874 }
875 if (IsConsoleHandle(Ppb->ErrorHandle))
876 {
877 Ppb->ErrorHandle = CsrReply.Data.CreateProcessReply.OutputHandle;
878 }
879 else
880 {
881 DPRINT("Duplicate error handle\n");
882 Status = NtDuplicateObject (NtCurrentProcess(),
883 Ppb->ErrorHandle,
884 hProcess,
885 &Ppb->ErrorHandle,
886 0,
887 TRUE,
888 DUPLICATE_SAME_ACCESS);
889 if(!NT_SUCCESS(Status))
890 {
891 DPRINT("NtDuplicateObject failed, status %x\n", Status);
892 }
893 }
894
895 /*
896 * Create Process Environment Block
897 */
898 DPRINT("Creating peb\n");
899
900 KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
901
902 RtlDestroyProcessParameters (Ppb);
903
904 Status = NtSetInformationProcess(hProcess,
905 ProcessImageFileName,
906 ImageFileName,
907 8);
908 /*
909 * Create the thread for the kernel
910 */
911 DPRINT("Creating thread for process\n");
912 hThread = KlCreateFirstThread(hProcess,
913 lpThreadAttributes,
914 Sii.StackReserve,
915 Sii.StackCommit,
916 ImageBaseAddress + (ULONG)Sii.EntryPoint,
917 dwCreationFlags,
918 &lpProcessInformation->dwThreadId);
919 if (hThread == NULL)
920 {
921 return FALSE;
922 }
923
924 lpProcessInformation->hProcess = hProcess;
925 lpProcessInformation->hThread = hThread;
926
927 return TRUE;
928 }
929
930 /* EOF */