2003-03-16 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.63 2003/03/16 14:16:54 chorns 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 <k32.h>
15
16 #define NDEBUG
17 #include <kernel32/kernel32.h>
18
19 /* FUNCTIONS ****************************************************************/
20
21 __declspec(dllimport)
22 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine;
23
24 WINBOOL STDCALL
25 CreateProcessA (LPCSTR lpApplicationName,
26 LPSTR lpCommandLine,
27 LPSECURITY_ATTRIBUTES lpProcessAttributes,
28 LPSECURITY_ATTRIBUTES lpThreadAttributes,
29 WINBOOL bInheritHandles,
30 DWORD dwCreationFlags,
31 LPVOID lpEnvironment,
32 LPCSTR lpCurrentDirectory,
33 LPSTARTUPINFOA lpStartupInfo,
34 LPPROCESS_INFORMATION lpProcessInformation)
35 /*
36 * FUNCTION: The CreateProcess function creates a new process and its
37 * primary thread. The new process executes the specified executable file
38 * ARGUMENTS:
39 *
40 * lpApplicationName = Pointer to name of executable module
41 * lpCommandLine = Pointer to command line string
42 * lpProcessAttributes = Process security attributes
43 * lpThreadAttributes = Thread security attributes
44 * bInheritHandles = Handle inheritance flag
45 * dwCreationFlags = Creation flags
46 * lpEnvironment = Pointer to new environment block
47 * lpCurrentDirectory = Pointer to current directory name
48 * lpStartupInfo = Pointer to startup info
49 * lpProcessInformation = Pointer to process information
50 */
51 {
52 PWCHAR lpEnvironmentW = NULL;
53 UNICODE_STRING ApplicationNameU;
54 UNICODE_STRING CurrentDirectoryU;
55 UNICODE_STRING CommandLineU;
56 ANSI_STRING ApplicationName;
57 ANSI_STRING CurrentDirectory;
58 ANSI_STRING CommandLine;
59 WINBOOL Result;
60 CHAR TempCurrentDirectoryA[256];
61
62 DPRINT("CreateProcessA(%s)\n", lpApplicationName);
63 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
64 "lpStartupInfo %x, lpProcessInformation %x\n", dwCreationFlags,
65 lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
66
67 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
68 {
69 PCHAR ptr = lpEnvironment;
70 ULONG len = 0;
71 UNICODE_STRING EnvironmentU;
72 ANSI_STRING EnvironmentA;
73 while (*ptr)
74 {
75 RtlInitAnsiString(&EnvironmentA, ptr);
76 if (bIsFileApiAnsi)
77 len += RtlAnsiStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
78 else
79 len += RtlOemStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
80 ptr += EnvironmentA.MaximumLength;
81 }
82 len += sizeof(WCHAR);
83 lpEnvironmentW = (PWCHAR)RtlAllocateHeap(GetProcessHeap(),
84 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
85 len);
86 if (lpEnvironmentW == NULL)
87 {
88 return FALSE;
89 }
90 ptr = lpEnvironment;
91 EnvironmentU.Buffer = lpEnvironmentW;
92 EnvironmentU.Length = 0;
93 EnvironmentU.MaximumLength = len;
94 while (*ptr)
95 {
96 RtlInitAnsiString(&EnvironmentA, ptr);
97 if (bIsFileApiAnsi)
98 RtlAnsiStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
99 else
100 RtlOemStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
101 ptr += EnvironmentA.MaximumLength;
102 EnvironmentU.Buffer += (EnvironmentU.Length / sizeof(WCHAR) + 1);
103 EnvironmentU.MaximumLength -= (EnvironmentU.Length + sizeof(WCHAR));
104 EnvironmentU.Length = 0;
105 }
106
107 EnvironmentU.Buffer[0] = 0;
108 }
109
110 RtlInitAnsiString (&CommandLine,
111 lpCommandLine);
112 RtlInitAnsiString (&ApplicationName,
113 (LPSTR)lpApplicationName);
114 if (lpCurrentDirectory != NULL)
115 {
116 RtlInitAnsiString (&CurrentDirectory,
117 (LPSTR)lpCurrentDirectory);
118 }
119
120 /* convert ansi (or oem) strings to unicode */
121 if (bIsFileApiAnsi)
122 {
123 RtlAnsiStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
124 RtlAnsiStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
125 if (lpCurrentDirectory != NULL)
126 RtlAnsiStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
127 }
128 else
129 {
130 RtlOemStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
131 RtlOemStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
132 if (lpCurrentDirectory != NULL)
133 RtlOemStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
134 }
135
136 Result = CreateProcessW (ApplicationNameU.Buffer,
137 CommandLineU.Buffer,
138 lpProcessAttributes,
139 lpThreadAttributes,
140 bInheritHandles,
141 dwCreationFlags,
142 dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : lpEnvironmentW,
143 (lpCurrentDirectory == NULL) ? NULL : CurrentDirectoryU.Buffer,
144 (LPSTARTUPINFOW)lpStartupInfo,
145 lpProcessInformation);
146
147 RtlFreeUnicodeString (&ApplicationNameU);
148 RtlFreeUnicodeString (&CommandLineU);
149 if (lpCurrentDirectory != NULL)
150 RtlFreeUnicodeString (&CurrentDirectoryU);
151
152 if (lpEnvironmentW)
153 {
154 RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW);
155 }
156
157 return Result;
158 }
159
160 static int _except_recursion_trap = 0;
161
162 struct _CONTEXT;
163 struct __EXCEPTION_RECORD;
164
165 static
166 EXCEPTION_DISPOSITION
167 __cdecl
168 _except_handler(
169 struct _EXCEPTION_RECORD *ExceptionRecord,
170 void * EstablisherFrame,
171 struct _CONTEXT *ContextRecord,
172 void * DispatcherContext )
173 {
174 DPRINT("Process terminated abnormally...\n");
175
176 if (++_except_recursion_trap > 3) {
177 DPRINT("_except_handler(...) appears to be recursing.\n");
178 DPRINT("Process HALTED.\n");
179 for (;;) {}
180 }
181
182 if (/* FIXME: */ TRUE) /* Not a service */
183 {
184 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
185 //ExitProcess(0);
186 ExitThread(0);
187 }
188 else
189 {
190 DPRINT(" calling ExitThread(0) . . .\n");
191 ExitThread(0);
192 }
193
194 DPRINT(" We should not get to here !!!\n");
195 /* We should not get to here */
196 return ExceptionContinueSearch;
197 }
198
199 VOID STDCALL
200 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
201 DWORD lpParameter)
202 {
203 UINT uExitCode = 0;
204
205 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
206
207 __try1(_except_handler)
208 {
209 uExitCode = (lpStartAddress)((PVOID)lpParameter);
210 } __except1
211 {
212 }
213
214 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
215
216 ExitThread(uExitCode);
217 }
218
219
220 HANDLE STDCALL
221 KlCreateFirstThread(HANDLE ProcessHandle,
222 LPSECURITY_ATTRIBUTES lpThreadAttributes,
223 PSECTION_IMAGE_INFORMATION Sii,
224 LPTHREAD_START_ROUTINE lpStartAddress,
225 DWORD dwCreationFlags,
226 LPDWORD lpThreadId)
227 {
228 NTSTATUS Status;
229 HANDLE ThreadHandle;
230 OBJECT_ATTRIBUTES ObjectAttributes;
231 CLIENT_ID ClientId;
232 CONTEXT ThreadContext;
233 INITIAL_TEB InitialTeb;
234 BOOLEAN CreateSuspended = FALSE;
235 ULONG OldPageProtection;
236 ULONG ResultLength;
237 ULONG ThreadStartAddress;
238 ULONG InitialStack[6];
239
240 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
241 ObjectAttributes.RootDirectory = NULL;
242 ObjectAttributes.ObjectName = NULL;
243 ObjectAttributes.Attributes = 0;
244 if (lpThreadAttributes != NULL)
245 {
246 if (lpThreadAttributes->bInheritHandle)
247 ObjectAttributes.Attributes = OBJ_INHERIT;
248 ObjectAttributes.SecurityDescriptor =
249 lpThreadAttributes->lpSecurityDescriptor;
250 }
251 ObjectAttributes.SecurityQualityOfService = NULL;
252
253 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
254 CreateSuspended = TRUE;
255 else
256 CreateSuspended = FALSE;
257
258 InitialTeb.StackReserve = (Sii->StackReserve < 0x100000) ? 0x100000 : Sii->StackReserve;
259 /* FIXME: use correct commit size */
260 #if 0
261 InitialTeb.StackCommit = (Sii->StackCommit < PAGE_SIZE) ? PAGE_SIZE : Sii->StackCommit;
262 #endif
263 InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
264
265 /* size of guard page */
266 InitialTeb.StackCommit += PAGE_SIZE;
267
268 /* Reserve stack */
269 InitialTeb.StackAllocate = NULL;
270 Status = NtAllocateVirtualMemory(ProcessHandle,
271 &InitialTeb.StackAllocate,
272 0,
273 &InitialTeb.StackReserve,
274 MEM_RESERVE,
275 PAGE_READWRITE);
276 if (!NT_SUCCESS(Status))
277 {
278 DPRINT("Error reserving stack space!\n");
279 SetLastErrorByStatus(Status);
280 return(INVALID_HANDLE_VALUE);
281 }
282
283 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
284 InitialTeb.StackAllocate, InitialTeb.StackReserve);
285
286 InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
287 InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
288
289 DPRINT("StackBase: %p StackCommit: %p\n",
290 InitialTeb.StackBase, InitialTeb.StackCommit);
291
292 /* Commit stack page(s) */
293 Status = NtAllocateVirtualMemory(ProcessHandle,
294 &InitialTeb.StackLimit,
295 0,
296 &InitialTeb.StackCommit,
297 MEM_COMMIT,
298 PAGE_READWRITE);
299 if (!NT_SUCCESS(Status))
300 {
301 /* release the stack space */
302 NtFreeVirtualMemory(ProcessHandle,
303 InitialTeb.StackAllocate,
304 &InitialTeb.StackReserve,
305 MEM_RELEASE);
306
307 DPRINT("Error comitting stack page(s)!\n");
308 SetLastErrorByStatus(Status);
309 return(INVALID_HANDLE_VALUE);
310 }
311
312 DPRINT("StackLimit: %p\n",
313 InitialTeb.StackLimit);
314
315 /* Protect guard page */
316 Status = NtProtectVirtualMemory(ProcessHandle,
317 InitialTeb.StackLimit,
318 PAGE_SIZE,
319 PAGE_GUARD | PAGE_READWRITE,
320 &OldPageProtection);
321 if (!NT_SUCCESS(Status))
322 {
323 /* release the stack space */
324 NtFreeVirtualMemory(ProcessHandle,
325 InitialTeb.StackAllocate,
326 &InitialTeb.StackReserve,
327 MEM_RELEASE);
328
329 DPRINT("Error comitting guard page!\n");
330 SetLastErrorByStatus(Status);
331 return(INVALID_HANDLE_VALUE);
332 }
333
334 if (Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
335 {
336 ThreadStartAddress = (ULONG) BaseProcessStart;
337 }
338 else
339 {
340 ThreadStartAddress = (ULONG) RtlBaseProcessStartRoutine;
341 }
342
343 memset(&ThreadContext,0,sizeof(CONTEXT));
344 ThreadContext.Eip = ThreadStartAddress;
345 ThreadContext.SegGs = USER_DS;
346 ThreadContext.SegFs = USER_DS;
347 ThreadContext.SegEs = USER_DS;
348 ThreadContext.SegDs = USER_DS;
349 ThreadContext.SegCs = USER_CS;
350 ThreadContext.SegSs = USER_DS;
351 ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 6*4;
352 ThreadContext.EFlags = (1<<1) + (1<<9);
353
354 DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
355
356 /*
357 * Write in the initial stack.
358 */
359 InitialStack[0] = 0;
360 InitialStack[1] = (DWORD)lpStartAddress;
361 InitialStack[2] = PEB_BASE;
362
363 Status = ZwWriteVirtualMemory(ProcessHandle,
364 (PVOID)ThreadContext.Esp,
365 InitialStack,
366 sizeof(InitialStack),
367 &ResultLength);
368 if (!NT_SUCCESS(Status))
369 {
370 DPRINT1("Failed to write initial stack.\n");
371 return(INVALID_HANDLE_VALUE);
372 }
373
374 Status = NtCreateThread(&ThreadHandle,
375 THREAD_ALL_ACCESS,
376 &ObjectAttributes,
377 ProcessHandle,
378 &ClientId,
379 &ThreadContext,
380 &InitialTeb,
381 CreateSuspended);
382 if (!NT_SUCCESS(Status))
383 {
384 NtFreeVirtualMemory(ProcessHandle,
385 InitialTeb.StackAllocate,
386 &InitialTeb.StackReserve,
387 MEM_RELEASE);
388 SetLastErrorByStatus(Status);
389 return(INVALID_HANDLE_VALUE);
390 }
391
392 if (lpThreadId != NULL)
393 {
394 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
395 }
396
397 return(ThreadHandle);
398 }
399
400 HANDLE
401 KlMapFile(LPCWSTR lpApplicationName)
402 {
403 HANDLE hFile;
404 IO_STATUS_BLOCK IoStatusBlock;
405 UNICODE_STRING ApplicationNameString;
406 OBJECT_ATTRIBUTES ObjectAttributes;
407 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
408 NTSTATUS Status;
409 HANDLE hSection;
410
411 hFile = NULL;
412
413 /*
414 * Find the application name
415 */
416
417 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
418 &ApplicationNameString,
419 NULL,
420 NULL))
421 return NULL;
422
423 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
424
425 InitializeObjectAttributes(&ObjectAttributes,
426 &ApplicationNameString,
427 OBJ_CASE_INSENSITIVE,
428 NULL,
429 SecurityDescriptor);
430
431 /*
432 * Try to open the executable
433 */
434
435 Status = NtOpenFile(&hFile,
436 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
437 &ObjectAttributes,
438 &IoStatusBlock,
439 FILE_SHARE_DELETE|FILE_SHARE_READ,
440 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
441
442 RtlFreeUnicodeString (&ApplicationNameString);
443
444 if (!NT_SUCCESS(Status))
445 {
446 DPRINT("Failed to open file\n");
447 SetLastErrorByStatus (Status);
448 return(NULL);
449 }
450
451 Status = NtCreateSection(&hSection,
452 SECTION_ALL_ACCESS,
453 NULL,
454 NULL,
455 PAGE_EXECUTE,
456 SEC_IMAGE,
457 hFile);
458 NtClose(hFile);
459
460 if (!NT_SUCCESS(Status))
461 {
462 DPRINT("Failed to create section\n");
463 SetLastErrorByStatus (Status);
464 return(NULL);
465 }
466
467 return(hSection);
468 }
469
470 static NTSTATUS
471 KlInitPeb (HANDLE ProcessHandle,
472 PRTL_USER_PROCESS_PARAMETERS Ppb,
473 PVOID* ImageBaseAddress)
474 {
475 NTSTATUS Status;
476 PVOID PpbBase;
477 ULONG PpbSize;
478 ULONG BytesWritten;
479 ULONG Offset;
480 PVOID ParentEnv = NULL;
481 PVOID EnvPtr = NULL;
482 PWCHAR ptr;
483 ULONG EnvSize = 0, EnvSize1 = 0;
484
485 /* create the Environment */
486 if (Ppb->Environment != NULL)
487 {
488 ParentEnv = Ppb->Environment;
489 ptr = ParentEnv;
490 while (*ptr)
491 {
492 while(*ptr++);
493 }
494 ptr++;
495 EnvSize = (PVOID)ptr - ParentEnv;
496 }
497 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
498 {
499 MEMORY_BASIC_INFORMATION MemInfo;
500 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
501
502 Status = NtQueryVirtualMemory (NtCurrentProcess (),
503 ParentEnv,
504 MemoryBasicInformation,
505 &MemInfo,
506 sizeof(MEMORY_BASIC_INFORMATION),
507 NULL);
508 if (!NT_SUCCESS(Status))
509 {
510 return Status;
511 }
512 EnvSize = MemInfo.RegionSize;
513 }
514 DPRINT("EnvironmentSize %ld\n", EnvSize);
515
516 /* allocate and initialize new environment block */
517 if (EnvSize != 0)
518 {
519 EnvSize1 = EnvSize;
520 Status = NtAllocateVirtualMemory(ProcessHandle,
521 &EnvPtr,
522 0,
523 &EnvSize1,
524 MEM_RESERVE | MEM_COMMIT,
525 PAGE_READWRITE);
526 if (!NT_SUCCESS(Status))
527 {
528 return(Status);
529 }
530
531 NtWriteVirtualMemory(ProcessHandle,
532 EnvPtr,
533 ParentEnv,
534 EnvSize,
535 &BytesWritten);
536 }
537
538 /* create the PPB */
539 PpbBase = NULL;
540 PpbSize = Ppb->AllocationSize;
541 Status = NtAllocateVirtualMemory(ProcessHandle,
542 &PpbBase,
543 0,
544 &PpbSize,
545 MEM_RESERVE | MEM_COMMIT,
546 PAGE_READWRITE);
547 if (!NT_SUCCESS(Status))
548 {
549 return(Status);
550 }
551
552 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
553 NtWriteVirtualMemory(ProcessHandle,
554 PpbBase,
555 Ppb,
556 Ppb->AllocationSize,
557 &BytesWritten);
558
559 /* write pointer to environment */
560 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
561 NtWriteVirtualMemory(ProcessHandle,
562 (PVOID)(PpbBase + Offset),
563 &EnvPtr,
564 sizeof(EnvPtr),
565 &BytesWritten);
566
567 /* write pointer to process parameter block */
568 Offset = FIELD_OFFSET(PEB, ProcessParameters);
569 NtWriteVirtualMemory(ProcessHandle,
570 (PVOID)(PEB_BASE + Offset),
571 &PpbBase,
572 sizeof(PpbBase),
573 &BytesWritten);
574
575 /* Read image base address. */
576 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
577 NtReadVirtualMemory(ProcessHandle,
578 (PVOID)(PEB_BASE + Offset),
579 ImageBaseAddress,
580 sizeof(PVOID),
581 &BytesWritten);
582
583 return(STATUS_SUCCESS);
584 }
585
586
587 WINBOOL STDCALL
588 CreateProcessW(LPCWSTR lpApplicationName,
589 LPWSTR lpCommandLine,
590 LPSECURITY_ATTRIBUTES lpProcessAttributes,
591 LPSECURITY_ATTRIBUTES lpThreadAttributes,
592 WINBOOL bInheritHandles,
593 DWORD dwCreationFlags,
594 LPVOID lpEnvironment,
595 LPCWSTR lpCurrentDirectory,
596 LPSTARTUPINFOW lpStartupInfo,
597 LPPROCESS_INFORMATION lpProcessInformation)
598 {
599 HANDLE hSection, hProcess, hThread;
600 NTSTATUS Status;
601 LPTHREAD_START_ROUTINE lpStartAddress = NULL;
602 WCHAR ImagePathName[256];
603 UNICODE_STRING ImagePathName_U;
604 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
605 ULONG retlen;
606 PRTL_USER_PROCESS_PARAMETERS Ppb;
607 UNICODE_STRING CommandLine_U;
608 CSRSS_API_REQUEST CsrRequest;
609 CSRSS_API_REPLY CsrReply;
610 CHAR ImageFileName[8];
611 PWCHAR s, e;
612 ULONG i, len;
613 ANSI_STRING ProcedureName;
614 UNICODE_STRING CurrentDirectory_U;
615 SECTION_IMAGE_INFORMATION Sii;
616 WCHAR TempCurrentDirectoryW[256];
617 WCHAR TempApplicationNameW[256];
618 WCHAR TempCommandLineNameW[256];
619 UNICODE_STRING RuntimeInfo_U;
620 PVOID ImageBaseAddress;
621
622 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
623 lpApplicationName, lpCommandLine);
624
625 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
626 {
627 wcscpy (TempApplicationNameW, lpApplicationName);
628 i = wcslen(TempApplicationNameW);
629 if (TempApplicationNameW[i - 1] == L'.')
630 {
631 TempApplicationNameW[i - 1] = 0;
632 }
633 else
634 {
635 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
636 if (s == NULL)
637 {
638 s = TempApplicationNameW;
639 }
640 else
641 {
642 s++;
643 }
644 e = wcsrchr(s, L'.');
645 if (e == NULL)
646 {
647 wcscat(s, L".exe");
648 e = wcsrchr(s, L'.');
649 }
650 }
651 }
652 else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
653 {
654 if (lpCommandLine[0] == L'"')
655 {
656 wcscpy(TempApplicationNameW, lpCommandLine + 1);
657 s = wcschr(TempApplicationNameW, L'"');
658 if (s == NULL)
659 {
660 return FALSE;
661 }
662 *s = 0;
663 }
664 else
665 {
666 wcscpy(TempApplicationNameW, lpCommandLine);
667 s = wcschr(TempApplicationNameW, L' ');
668 if (s != NULL)
669 {
670 *s = 0;
671 }
672 }
673 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
674 if (s == NULL)
675 {
676 s = TempApplicationNameW;
677 }
678 s = wcsrchr(s, L'.');
679 if (s == NULL)
680 wcscat(TempApplicationNameW, L".exe");
681 }
682 else
683 {
684 return FALSE;
685 }
686
687 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
688 {
689 return FALSE;
690 }
691
692 e = wcsrchr(s, L'.');
693 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
694 {
695 // the command is a batch file
696 if (lpApplicationName != NULL && lpApplicationName[0])
697 {
698 // FIXME: use COMSPEC for the command interpreter
699 wcscpy(TempCommandLineNameW, L"cmd /c ");
700 wcscat(TempCommandLineNameW, lpApplicationName);
701 lpCommandLine = TempCommandLineNameW;
702 wcscpy(TempApplicationNameW, L"cmd.exe");
703 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
704 {
705 return FALSE;
706 }
707 }
708 else
709 {
710 return FALSE;
711 }
712 }
713
714 /*
715 * Store the image file name for the process
716 */
717 e = wcschr(s, L'.');
718 if (e != NULL)
719 {
720 *e = 0;
721 }
722 for (i = 0; i < 8; i++)
723 {
724 ImageFileName[i] = (CHAR)(s[i]);
725 }
726 if (e != NULL)
727 {
728 *e = '.';
729 }
730
731 /*
732 * Process the application name and command line
733 */
734 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
735 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
736
737 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
738 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
739
740 /* Initialize the current directory string */
741 if (lpCurrentDirectory != NULL)
742 {
743 RtlInitUnicodeString(&CurrentDirectory_U,
744 lpCurrentDirectory);
745 }
746 else
747 {
748 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
749 RtlInitUnicodeString(&CurrentDirectory_U,
750 TempCurrentDirectoryW);
751 }
752
753 /*
754 * Create a section for the executable
755 */
756
757 hSection = KlMapFile (ImagePathName);
758 if (hSection == NULL)
759 {
760 /////////////////////////////////////////
761 /*
762 * Inspect the image to determine executable flavour
763 */
764 IO_STATUS_BLOCK IoStatusBlock;
765 UNICODE_STRING ApplicationNameString;
766 OBJECT_ATTRIBUTES ObjectAttributes;
767 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
768 IMAGE_DOS_HEADER DosHeader;
769 IO_STATUS_BLOCK Iosb;
770 LARGE_INTEGER Offset;
771 HANDLE hFile = NULL;
772
773 DPRINT("Inspecting Image Header for image type id\n");
774
775 // Find the application name
776 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
777 &ApplicationNameString, NULL, NULL)) {
778 return FALSE;
779 }
780 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
781
782 InitializeObjectAttributes(&ObjectAttributes,
783 &ApplicationNameString,
784 OBJ_CASE_INSENSITIVE,
785 NULL,
786 SecurityDescriptor);
787
788 // Try to open the executable
789 Status = NtOpenFile(&hFile,
790 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
791 &ObjectAttributes,
792 &IoStatusBlock,
793 FILE_SHARE_DELETE|FILE_SHARE_READ,
794 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
795
796 RtlFreeUnicodeString(&ApplicationNameString);
797
798 if (!NT_SUCCESS(Status)) {
799 DPRINT("Failed to open file\n");
800 SetLastErrorByStatus(Status);
801 return FALSE;
802 }
803
804 // Read the dos header
805 Offset.QuadPart = 0;
806 Status = ZwReadFile(hFile,
807 NULL,
808 NULL,
809 NULL,
810 &Iosb,
811 &DosHeader,
812 sizeof(DosHeader),
813 &Offset,
814 0);
815
816 if (!NT_SUCCESS(Status)) {
817 DPRINT("Failed to read from file\n");
818 SetLastErrorByStatus(Status);
819 return FALSE;
820 }
821 if (Iosb.Information != sizeof(DosHeader)) {
822 DPRINT("Failed to read dos header from file\n");
823 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
824 return FALSE;
825 }
826
827 // Check the DOS signature
828 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
829 DPRINT("Failed dos magic check\n");
830 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
831 return FALSE;
832 }
833 NtClose(hFile);
834
835 DPRINT("Launching VDM...\n");
836 return CreateProcessW(L"ntvdm.exe",
837 (LPWSTR)lpApplicationName,
838 lpProcessAttributes,
839 lpThreadAttributes,
840 bInheritHandles,
841 dwCreationFlags,
842 lpEnvironment,
843 lpCurrentDirectory,
844 lpStartupInfo,
845 lpProcessInformation);
846 }
847 /////////////////////////////////////////
848 /*
849 * Create a new process
850 */
851 Status = NtCreateProcess(&hProcess,
852 PROCESS_ALL_ACCESS,
853 NULL,
854 NtCurrentProcess(),
855 bInheritHandles,
856 hSection,
857 NULL,
858 NULL);
859 if (lpStartupInfo)
860 {
861 if (lpStartupInfo->lpReserved2)
862 {
863 ULONG i, Count = *(ULONG*)lpStartupInfo->lpReserved2;
864 HANDLE * hFile;
865 HANDLE hTemp;
866 PRTL_USER_PROCESS_PARAMETERS CurrPpb = NtCurrentPeb()->ProcessParameters;
867
868
869 /* FIXME:
870 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
871 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
872 * If is possible that this function overwrite the last information in runtimeinfo
873 * with the null terminator for the unicode string.
874 */
875 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
876 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
877 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
878 }
879 }
880
881 /*
882 * Create the PPB
883 */
884 RtlCreateProcessParameters(&Ppb,
885 &ImagePathName_U,
886 NULL,
887 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
888 &CommandLine_U,
889 lpEnvironment,
890 NULL,
891 NULL,
892 NULL,
893 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
894
895 if (lpStartupInfo && lpStartupInfo->lpReserved2)
896 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
897
898
899 /*
900 * Translate some handles for the new process
901 */
902 if (Ppb->CurrentDirectoryHandle)
903 {
904 Status = NtDuplicateObject (NtCurrentProcess(),
905 Ppb->CurrentDirectoryHandle,
906 hProcess,
907 &Ppb->CurrentDirectoryHandle,
908 0,
909 TRUE,
910 DUPLICATE_SAME_ACCESS);
911 }
912
913 if (Ppb->hConsole)
914 {
915 Status = NtDuplicateObject (NtCurrentProcess(),
916 Ppb->hConsole,
917 hProcess,
918 &Ppb->hConsole,
919 0,
920 TRUE,
921 DUPLICATE_SAME_ACCESS);
922 }
923
924 /*
925 * Get some information about the executable
926 */
927 Status = ZwQuerySection(hSection,
928 SectionImageInformation,
929 &Sii,
930 sizeof(Sii),
931 &i);
932 /*
933 * Close the section
934 */
935 NtClose(hSection);
936
937 /*
938 * Get some information about the process
939 */
940 NtQueryInformationProcess(hProcess,
941 ProcessBasicInformation,
942 &ProcessBasicInfo,
943 sizeof(ProcessBasicInfo),
944 &retlen);
945 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
946 ProcessBasicInfo.UniqueProcessId);
947 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
948
949 /*
950 * Tell the csrss server we are creating a new process
951 */
952 CsrRequest.Type = CSRSS_CREATE_PROCESS;
953 CsrRequest.Data.CreateProcessRequest.NewProcessId =
954 ProcessBasicInfo.UniqueProcessId;
955 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
956 Status = CsrClientCallServer(&CsrRequest,
957 &CsrReply,
958 sizeof(CSRSS_API_REQUEST),
959 sizeof(CSRSS_API_REPLY));
960 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
961 {
962 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
963 }
964
965 // Set the child console handles
966 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
967 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
968 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
969
970 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
971 {
972 if (lpStartupInfo->hStdInput)
973 Ppb->hStdInput = lpStartupInfo->hStdInput;
974 if (lpStartupInfo->hStdOutput)
975 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
976 if (lpStartupInfo->hStdError)
977 Ppb->hStdError = lpStartupInfo->hStdError;
978 }
979
980 if (IsConsoleHandle(Ppb->hStdInput))
981 {
982 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
983 }
984 else
985 {
986 DPRINT("Duplicate input handle\n");
987 Status = NtDuplicateObject (NtCurrentProcess(),
988 Ppb->hStdInput,
989 hProcess,
990 &Ppb->hStdInput,
991 0,
992 TRUE,
993 DUPLICATE_SAME_ACCESS);
994 if(!NT_SUCCESS(Status))
995 {
996 DPRINT("NtDuplicateObject failed, status %x\n", Status);
997 }
998 }
999
1000 if (IsConsoleHandle(Ppb->hStdOutput))
1001 {
1002 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1003 }
1004 else
1005 {
1006 DPRINT("Duplicate output handle\n");
1007 Status = NtDuplicateObject (NtCurrentProcess(),
1008 Ppb->hStdOutput,
1009 hProcess,
1010 &Ppb->hStdOutput,
1011 0,
1012 TRUE,
1013 DUPLICATE_SAME_ACCESS);
1014 if(!NT_SUCCESS(Status))
1015 {
1016 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1017 }
1018 }
1019 if (IsConsoleHandle(Ppb->hStdError))
1020 {
1021 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1022 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1023 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1024 Status = CsrClientCallServer(&CsrRequest,
1025 &CsrReply,
1026 sizeof(CSRSS_API_REQUEST),
1027 sizeof(CSRSS_API_REPLY));
1028 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1029 {
1030 Ppb->hStdError = INVALID_HANDLE_VALUE;
1031 }
1032 else
1033 {
1034 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1035 }
1036 }
1037 else
1038 {
1039 DPRINT("Duplicate error handle\n");
1040 Status = NtDuplicateObject (NtCurrentProcess(),
1041 Ppb->hStdError,
1042 hProcess,
1043 &Ppb->hStdError,
1044 0,
1045 TRUE,
1046 DUPLICATE_SAME_ACCESS);
1047 if(!NT_SUCCESS(Status))
1048 {
1049 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1050 }
1051 }
1052
1053 /*
1054 * Initialize some other fields in the PPB
1055 */
1056 if (lpStartupInfo)
1057 {
1058 Ppb->dwFlags = lpStartupInfo->dwFlags;
1059 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1060 {
1061 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1062 }
1063 else
1064 {
1065 Ppb->wShowWindow = SW_SHOWDEFAULT;
1066 }
1067 Ppb->dwX = lpStartupInfo->dwX;
1068 Ppb->dwY = lpStartupInfo->dwY;
1069 Ppb->dwXSize = lpStartupInfo->dwXSize;
1070 Ppb->dwYSize = lpStartupInfo->dwYSize;
1071 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1072 }
1073 else
1074 {
1075 Ppb->Flags = 0;
1076 }
1077
1078 /*
1079 * Create Process Environment Block
1080 */
1081 DPRINT("Creating peb\n");
1082
1083 KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
1084
1085 RtlDestroyProcessParameters (Ppb);
1086
1087 Status = NtSetInformationProcess(hProcess,
1088 ProcessImageFileName,
1089 ImageFileName,
1090 8);
1091 /*
1092 * Create the thread for the kernel
1093 */
1094 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1095 ImageBaseAddress + (ULONG)Sii.EntryPoint);
1096 hThread = KlCreateFirstThread(hProcess,
1097 lpThreadAttributes,
1098 &Sii,
1099 ImageBaseAddress + (ULONG)Sii.EntryPoint,
1100 dwCreationFlags,
1101 &lpProcessInformation->dwThreadId);
1102 if (hThread == INVALID_HANDLE_VALUE)
1103 {
1104 return FALSE;
1105 }
1106
1107 lpProcessInformation->hProcess = hProcess;
1108 lpProcessInformation->hThread = hThread;
1109
1110 return TRUE;
1111 }
1112
1113 /* EOF */