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