19149a18783615cd989b1d203d5d0d51f37a1fc8
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/process/create.c
5 * PURPOSE: Process functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 * Ariadne ( ariadne@xs4all.nl)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <k32.h>
13
14 #define NDEBUG
15 #include "../include/debug.h"
16
17 #define CMD_STRING L"cmd /c "
18
19 extern __declspec(noreturn)
20 VOID
21 CALLBACK
22 ConsoleControlDispatcher(DWORD CodeAndFlag);
23
24 /* INTERNAL FUNCTIONS *******************************************************/
25
26 _SEH_FILTER(BaseExceptionFilter)
27 {
28 EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
29 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
30
31 if (GlobalTopLevelExceptionFilter != NULL)
32 {
33 _SEH_TRY
34 {
35 ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
36 }
37 _SEH_HANDLE
38 {
39 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
40 }
41 _SEH_END;
42 }
43
44 return ExceptionDisposition;
45 }
46
47 VOID
48 STDCALL
49 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
50 {
51 UINT uExitCode = 0;
52
53 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
54
55 _SEH_TRY
56 {
57 /* Set our Start Address */
58 NtSetInformationThread(NtCurrentThread(),
59 ThreadQuerySetWin32StartAddress,
60 &lpStartAddress,
61 sizeof(PPROCESS_START_ROUTINE));
62
63 /* Call the Start Routine */
64 uExitCode = (lpStartAddress)();
65 }
66 _SEH_EXCEPT(BaseExceptionFilter)
67 {
68 /* Get the SEH Error */
69 uExitCode = _SEH_GetExceptionCode();
70 }
71 _SEH_END;
72
73 /* Exit the Process with our error */
74 ExitProcess(uExitCode);
75 }
76
77 /*
78 * Tells CSR that a new process was created
79 */
80 NTSTATUS
81 STDCALL
82 BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
83 IN HANDLE ProcessId,
84 IN ULONG SubsystemType,
85 OUT PHANDLE ConsoleHandle,
86 OUT PHANDLE InputHandle,
87 OUT PHANDLE OutputHandle)
88 {
89 ULONG Request = CREATE_PROCESS;
90 CSR_API_MESSAGE CsrRequest;
91 NTSTATUS Status;
92
93 DPRINT("BasepNotifyCsrOfCreation\n");
94
95 /* Some hacks (heck, this whole API is a hack) */
96 if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI)
97 {
98 dwCreationFlags = (dwCreationFlags &~ CREATE_NEW_CONSOLE) |
99 DETACHED_PROCESS;
100 }
101 else if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
102 {
103 dwCreationFlags |= CREATE_NEW_CONSOLE;
104 }
105
106 /* Fill out the request */
107 CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
108 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
109 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
110 CsrRequest.Data.CreateProcessRequest.InputHandle = 0;
111 CsrRequest.Data.CreateProcessRequest.OutputHandle = 0;
112 CsrRequest.Data.CreateProcessRequest.Console = 0;
113
114 /* Call CSR */
115 Status = CsrClientCallServer(&CsrRequest,
116 NULL,
117 MAKE_CSR_API(Request, CSR_NATIVE),
118 sizeof(CSR_API_MESSAGE));
119 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
120 {
121 DPRINT1("Failed to tell csrss about new process\n");
122 return CsrRequest.Status;
123 }
124 /* Return Handles */
125 *ConsoleHandle = CsrRequest.Data.CreateProcessRequest.Console;
126 *InputHandle = CsrRequest.Data.CreateProcessRequest.InputHandle;
127 *OutputHandle = CsrRequest.Data.CreateProcessRequest.OutputHandle;
128 DPRINT("CSR Created: %lx %lx\n", *InputHandle, *OutputHandle);
129
130 /* REturn Success */
131 return STATUS_SUCCESS;
132 }
133
134 /*
135 * Creates the first Thread in a Proces
136 */
137 HANDLE
138 STDCALL
139 BasepCreateFirstThread(HANDLE ProcessHandle,
140 LPSECURITY_ATTRIBUTES lpThreadAttributes,
141 PSECTION_IMAGE_INFORMATION SectionImageInfo,
142 PCLIENT_ID ClientId)
143 {
144 OBJECT_ATTRIBUTES LocalObjectAttributes;
145 POBJECT_ATTRIBUTES ObjectAttributes;
146 CONTEXT Context;
147 INITIAL_TEB InitialTeb;
148 NTSTATUS Status;
149 HANDLE hThread;
150
151 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
152
153 /* Create the Thread's Stack */
154 BasepCreateStack(ProcessHandle,
155 SectionImageInfo->MaximumStackSize,
156 SectionImageInfo->CommittedStackSize,
157 &InitialTeb);
158
159 /* Create the Thread's Context */
160 BasepInitializeContext(&Context,
161 NtCurrentPeb(),
162 SectionImageInfo->TransferAddress,
163 InitialTeb.StackBase,
164 0);
165
166 /* Convert the thread attributes */
167 ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
168 lpThreadAttributes,
169 NULL);
170
171 /* Create the Kernel Thread Object */
172 Status = NtCreateThread(&hThread,
173 THREAD_ALL_ACCESS,
174 ObjectAttributes,
175 ProcessHandle,
176 ClientId,
177 &Context,
178 &InitialTeb,
179 TRUE);
180
181 /* Success */
182 return hThread;
183 }
184
185 /*
186 * Converts ANSI to Unicode Environment
187 */
188 PVOID
189 STDCALL
190 BasepConvertUnicodeEnvironment(IN PVOID lpEnvironment)
191 {
192 PCHAR pcScan;
193 SIZE_T EnvSize = 0;
194 ANSI_STRING AnsiEnv;
195 UNICODE_STRING UnicodeEnv;
196 NTSTATUS Status;
197
198 DPRINT("BasepConvertUnicodeEnvironment\n");
199
200 /* Scan the environment to calculate its Unicode size */
201 AnsiEnv.Buffer = pcScan = lpEnvironment;
202 while (*pcScan) while (*pcScan++);
203
204 /* Create our ANSI String */
205 AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
206 AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
207
208 /* Allocate memory for the Unicode Environment */
209 UnicodeEnv.Buffer = NULL;
210 EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
211 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
212 (PVOID)&UnicodeEnv.Buffer,
213 0,
214 &EnvSize,
215 MEM_COMMIT,
216 PAGE_READWRITE);
217 /* Failure */
218 if (!NT_SUCCESS(Status))
219 {
220 SetLastError(Status);
221 return NULL;
222 }
223
224 /* Use the allocated size */
225 UnicodeEnv.MaximumLength = EnvSize;
226
227 /* Convert */
228 RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
229 return UnicodeEnv.Buffer;
230 }
231
232 /*
233 * Converts a Win32 Priority Class to NT
234 */
235 ULONG
236 STDCALL
237 BasepConvertPriorityClass(IN ULONG dwCreationFlags)
238 {
239 ULONG ReturnClass;
240
241 if(dwCreationFlags & IDLE_PRIORITY_CLASS)
242 {
243 ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
244 }
245 else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
246 {
247 ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
248 }
249 else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
250 {
251 ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
252 }
253 else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
254 {
255 ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
256 }
257 else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
258 {
259 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
260 }
261 else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
262 {
263 /* Check for Privilege First */
264 if (BasepCheckRealTimePrivilege())
265 {
266 ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
267 }
268 else
269 {
270 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
271 }
272 }
273 else
274 {
275 ReturnClass = 0 /* FIXME */;
276 }
277
278 return ReturnClass;
279 }
280
281 /*
282 * Duplicates a standard handle and writes it where requested.
283 */
284 VOID
285 STDCALL
286 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
287 IN HANDLE StandardHandle,
288 IN PHANDLE Address)
289 {
290 NTSTATUS Status;
291 HANDLE DuplicatedHandle;
292 ULONG Dummy;
293
294 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
295 "Address: %p\n", ProcessHandle, StandardHandle, Address);
296
297 /* Don't touch Console Handles */
298 if (IsConsoleHandle(StandardHandle)) return;
299
300 /* Duplicate the handle */
301 Status = NtDuplicateObject(NtCurrentProcess(),
302 StandardHandle,
303 ProcessHandle,
304 &DuplicatedHandle,
305 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
306 0,
307 0);
308 if (NT_SUCCESS(Status))
309 {
310 /* Write it */
311 NtWriteVirtualMemory(ProcessHandle,
312 Address,
313 &DuplicatedHandle,
314 sizeof(HANDLE),
315 &Dummy);
316 }
317 }
318
319 LPWSTR
320 STDCALL
321 BasepGetDllPath(LPWSTR FullPath,
322 PVOID Environment)
323 {
324 /* FIXME: Not yet implemented */
325 return NULL;
326 }
327
328 VOID
329 STDCALL
330 BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
331 IN PRTL_USER_PROCESS_PARAMETERS PebParams,
332 IN BOOL InheritHandles)
333 {
334 /* Copy the handle if we are inheriting or if it's a console handle */
335 if (InheritHandles || IsConsoleHandle(PebParams->StandardInput))
336 {
337 Params->StandardInput = PebParams->StandardInput;
338 }
339 if (InheritHandles || IsConsoleHandle(PebParams->StandardOutput))
340 {
341 Params->StandardOutput = PebParams->StandardOutput;
342 }
343 if (InheritHandles || IsConsoleHandle(PebParams->StandardError))
344 {
345 Params->StandardError = PebParams->StandardError;
346 }
347 }
348
349 NTSTATUS
350 STDCALL
351 BasepInitializeEnvironment(HANDLE ProcessHandle,
352 PPEB Peb,
353 LPWSTR ApplicationPathName,
354 LPWSTR lpCurrentDirectory,
355 LPWSTR lpCommandLine,
356 LPVOID Environment,
357 LPSTARTUPINFOW StartupInfo,
358 DWORD CreationFlags,
359 BOOL InheritHandles,
360 HANDLE hInput,
361 HANDLE hOutput)
362 {
363 WCHAR FullPath[MAX_PATH];
364 LPWSTR Remaining;
365 LPWSTR DllPathString;
366 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
367 PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
368 UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
369 UINT RetVal;
370 NTSTATUS Status;
371 PWCHAR ScanChar;
372 ULONG EnviroSize;
373 ULONG Size;
374 UNICODE_STRING Desktop, Shell, Runtime, Title;
375 PPEB OurPeb = NtCurrentPeb();
376
377 DPRINT("BasepInitializeEnvironment\n");
378
379 /* Get the full path name */
380 RetVal = GetFullPathNameW(ApplicationPathName,
381 MAX_PATH,
382 FullPath,
383 &Remaining);
384 DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName,
385 FullPath);
386
387 /* Get the DLL Path */
388 DllPathString = BasepGetDllPath(FullPath, Environment);
389
390 /* Initialize Strings */
391 RtlInitUnicodeString(&DllPath, DllPathString);
392 RtlInitUnicodeString(&ImageName, FullPath);
393 RtlInitUnicodeString(&CommandLine, lpCommandLine);
394 RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
395
396 /* Initialize more Strings from the Startup Info */
397 if (StartupInfo->lpDesktop)
398 {
399 RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
400 }
401 else
402 {
403 RtlInitUnicodeString(&Desktop, L"");
404 }
405 if (StartupInfo->lpReserved)
406 {
407 RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
408 }
409 else
410 {
411 RtlInitUnicodeString(&Shell, L"");
412 }
413 if (StartupInfo->lpTitle)
414 {
415 RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
416 }
417 else
418 {
419 RtlInitUnicodeString(&Title, L"");
420 }
421
422 /* This one is special because the length can differ */
423 Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
424 Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
425
426 /* Create the Parameter Block */
427 DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
428 &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
429 &Runtime);
430 Status = RtlCreateProcessParameters(&ProcessParameters,
431 &ImageName,
432 &DllPath,
433 lpCurrentDirectory ?
434 &CurrentDirectory : NULL,
435 &CommandLine,
436 Environment,
437 &Title,
438 &Desktop,
439 &Shell,
440 &Runtime);
441
442 if (!NT_SUCCESS(Status))
443 {
444 DPRINT1("Failed to create process parameters!\n");
445 return Status;
446 }
447
448 /* Check if we got an environment. If not, use ours */
449 if (Environment)
450 {
451 /* Save pointer and start lookup */
452 Environment = ScanChar = ProcessParameters->Environment;
453 }
454 else
455 {
456 /* Save pointer and start lookup */
457 Environment = ScanChar = OurPeb->ProcessParameters->Environment;
458 }
459
460 /* Find the environment size */
461 if (ScanChar)
462 {
463 while (*ScanChar) while (*ScanChar++);
464
465 /* Calculate the size of the block */
466 EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment);
467 DPRINT("EnvironmentSize %ld\n", EnviroSize);
468
469 /* Allocate and Initialize new Environment Block */
470 Size = EnviroSize;
471 ProcessParameters->Environment = NULL;
472 Status = ZwAllocateVirtualMemory(ProcessHandle,
473 (PVOID*)&ProcessParameters->Environment,
474 0,
475 &Size,
476 MEM_COMMIT,
477 PAGE_READWRITE);
478 if (!NT_SUCCESS(Status))
479 {
480 DPRINT1("Failed to allocate Environment Block\n");
481 return(Status);
482 }
483
484 /* Write the Environment Block */
485 ZwWriteVirtualMemory(ProcessHandle,
486 ProcessParameters->Environment,
487 Environment,
488 EnviroSize,
489 NULL);
490 }
491
492 /* Write new parameters */
493 ProcessParameters->StartingX = StartupInfo->dwX;
494 ProcessParameters->StartingY = StartupInfo->dwY;
495 ProcessParameters->CountX = StartupInfo->dwXSize;
496 ProcessParameters->CountY = StartupInfo->dwYSize;
497 ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
498 ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
499 ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
500 ProcessParameters->WindowFlags = StartupInfo->dwFlags;
501 ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
502
503 /* Write the handles only if we have to */
504 if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
505 {
506 ProcessParameters->StandardInput = StartupInfo->hStdInput;
507 ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
508 ProcessParameters->StandardError = StartupInfo->hStdError;
509 }
510
511 /* Use Special Flags for ConDllInitialize in Kernel32 */
512 if (CreationFlags & DETACHED_PROCESS)
513 {
514 ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
515 }
516 else if (CreationFlags & CREATE_NO_WINDOW)
517 {
518 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
519 }
520 else if (CreationFlags & CREATE_NEW_CONSOLE)
521 {
522 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
523 }
524 else
525 {
526 /* Inherit our Console Handle */
527 ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
528
529 /* Is the shell trampling on our Handles? */
530 if (!(StartupInfo->dwFlags &
531 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
532 {
533 /* Use handles from PEB, if inheriting or they are console */
534 BasepCopyHandles(ProcessParameters,
535 OurPeb->ProcessParameters,
536 InheritHandles);
537 }
538 }
539
540 /* Also set the Console Flag */
541 if (CreationFlags & CREATE_NEW_PROCESS_GROUP)
542 {
543 ProcessParameters->ConsoleFlags = 1;
544 }
545
546 /* Allocate memory for the parameter block */
547 Size = ProcessParameters->Length;
548 Status = NtAllocateVirtualMemory(ProcessHandle,
549 (PVOID*)&RemoteParameters,
550 0,
551 &Size,
552 MEM_COMMIT,
553 PAGE_READWRITE);
554 if (!NT_SUCCESS(Status))
555 {
556 DPRINT1("Failed to allocate Parameters Block\n");
557 return(Status);
558 }
559
560 /* Set the allocated size */
561 ProcessParameters->MaximumLength = Size;
562
563 /* Handle some Parameter Flags */
564 ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP);
565 ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
566 PPF_PROFILE_USER : 0;
567 ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
568 PPF_PROFILE_KERNEL : 0;
569 ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
570 PPF_PROFILE_SERVER : 0;
571 ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
572 PPF_DISABLE_HEAP_CHECKS);
573
574 /*
575 * FIXME: Our console init stuff is messy. See my comment in kernel32's
576 * DllMain.
577 */
578 if (!ProcessParameters->StandardInput) ProcessParameters->StandardInput = hInput;
579 if (!ProcessParameters->StandardOutput) ProcessParameters->StandardOutput = hOutput;
580 if (!ProcessParameters->StandardError) ProcessParameters->StandardError = hOutput;
581
582 /* Write the Parameter Block */
583 Status = NtWriteVirtualMemory(ProcessHandle,
584 RemoteParameters,
585 ProcessParameters,
586 ProcessParameters->Length,
587 NULL);
588
589 /* Write the PEB Pointer */
590 Status = NtWriteVirtualMemory(ProcessHandle,
591 &Peb->ProcessParameters,
592 &RemoteParameters,
593 sizeof(PVOID),
594 NULL);
595
596 /* Cleanup */
597 RtlFreeHeap(GetProcessHeap(), 0, DllPath.Buffer);
598 RtlDestroyProcessParameters(ProcessParameters);
599
600 DPRINT("Completed\n");
601 return STATUS_SUCCESS;
602 }
603
604 /* FUNCTIONS ****************************************************************/
605
606 /*
607 * FUNCTION: The CreateProcess function creates a new process and its
608 * primary thread. The new process executes the specified executable file
609 * ARGUMENTS:
610 *
611 * lpApplicationName = Pointer to name of executable module
612 * lpCommandLine = Pointer to command line string
613 * lpProcessAttributes = Process security attributes
614 * lpThreadAttributes = Thread security attributes
615 * bInheritHandles = Handle inheritance flag
616 * dwCreationFlags = Creation flags
617 * lpEnvironment = Pointer to new environment block
618 * lpCurrentDirectory = Pointer to current directory name
619 * lpStartupInfo = Pointer to startup info
620 * lpProcessInformation = Pointer to process information
621 *
622 * @implemented
623 */
624 BOOL
625 STDCALL
626 CreateProcessA(LPCSTR lpApplicationName,
627 LPSTR lpCommandLine,
628 LPSECURITY_ATTRIBUTES lpProcessAttributes,
629 LPSECURITY_ATTRIBUTES lpThreadAttributes,
630 BOOL bInheritHandles,
631 DWORD dwCreationFlags,
632 LPVOID lpEnvironment,
633 LPCSTR lpCurrentDirectory,
634 LPSTARTUPINFOA lpStartupInfo,
635 LPPROCESS_INFORMATION lpProcessInformation)
636 {
637 PUNICODE_STRING CommandLine = NULL;
638 UNICODE_STRING DummyString;
639 UNICODE_STRING LiveCommandLine;
640 UNICODE_STRING ApplicationName;
641 UNICODE_STRING CurrentDirectory;
642 BOOL bRetVal;
643 STARTUPINFOW StartupInfo;
644
645 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
646 "lpStartupInfo %x, lpProcessInformation %x\n",
647 dwCreationFlags, lpEnvironment, lpCurrentDirectory,
648 lpStartupInfo, lpProcessInformation);
649
650 /* Copy Startup Info */
651 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
652
653 /* Initialize all strings to nothing */
654 LiveCommandLine.Buffer = NULL;
655 DummyString.Buffer = NULL;
656 ApplicationName.Buffer = NULL;
657 CurrentDirectory.Buffer = NULL;
658 StartupInfo.lpDesktop = NULL;
659 StartupInfo.lpReserved = NULL;
660 StartupInfo.lpTitle = NULL;
661
662 /* Convert the Command line */
663 if (lpCommandLine)
664 {
665 /* If it's too long, then we'll have a problem */
666 if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
667 NtCurrentTeb()->StaticUnicodeString.MaximumLength)
668 {
669 /* Cache it in the TEB */
670 CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
671 }
672 else
673 {
674 /* Use a dynamic version */
675 Basep8BitStringToLiveUnicodeString(&LiveCommandLine,
676 lpCommandLine);
677 }
678 }
679 else
680 {
681 /* The logic below will use CommandLine, so we must make it valid */
682 CommandLine = &DummyString;
683 }
684
685 /* Convert the Name and Directory */
686 if (lpApplicationName)
687 {
688 Basep8BitStringToLiveUnicodeString(&ApplicationName,
689 lpApplicationName);
690 }
691 if (lpCurrentDirectory)
692 {
693 Basep8BitStringToLiveUnicodeString(&CurrentDirectory,
694 lpCurrentDirectory);
695 }
696
697 /* Now convert Startup Strings */
698 if (lpStartupInfo->lpReserved)
699 {
700 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
701 &StartupInfo.lpReserved);
702 }
703 if (lpStartupInfo->lpDesktop)
704 {
705 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
706 &StartupInfo.lpDesktop);
707 }
708 if (lpStartupInfo->lpTitle)
709 {
710 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
711 &StartupInfo.lpTitle);
712 }
713
714 /* Call the Unicode function */
715 bRetVal = CreateProcessW(ApplicationName.Buffer,
716 LiveCommandLine.Buffer ?
717 LiveCommandLine.Buffer : CommandLine->Buffer,
718 lpProcessAttributes,
719 lpThreadAttributes,
720 bInheritHandles,
721 dwCreationFlags,
722 lpEnvironment,
723 CurrentDirectory.Buffer,
724 &StartupInfo,
725 lpProcessInformation);
726
727 /* Clean up */
728 RtlFreeUnicodeString(&ApplicationName);
729 RtlFreeUnicodeString(&LiveCommandLine);
730 RtlFreeUnicodeString(&CurrentDirectory);
731 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop);
732 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved);
733 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle);
734
735 /* Return what Unicode did */
736 return bRetVal;
737 }
738
739 /*
740 * @implemented
741 */
742 BOOL
743 STDCALL
744 CreateProcessW(LPCWSTR lpApplicationName,
745 LPWSTR lpCommandLine,
746 LPSECURITY_ATTRIBUTES lpProcessAttributes,
747 LPSECURITY_ATTRIBUTES lpThreadAttributes,
748 BOOL bInheritHandles,
749 DWORD dwCreationFlags,
750 LPVOID lpEnvironment,
751 LPCWSTR lpCurrentDirectory,
752 LPSTARTUPINFOW lpStartupInfo,
753 LPPROCESS_INFORMATION lpProcessInformation)
754 {
755 NTSTATUS Status;
756 PROCESS_PRIORITY_CLASS PriorityClass;
757 BOOLEAN FoundQuotes = FALSE;
758 BOOLEAN QuotesNeeded = FALSE;
759 BOOLEAN CmdLineIsAppName = FALSE;
760 UNICODE_STRING ApplicationName;
761 OBJECT_ATTRIBUTES LocalObjectAttributes;
762 POBJECT_ATTRIBUTES ObjectAttributes;
763 HANDLE hSection, hProcess, hThread;
764 SECTION_IMAGE_INFORMATION SectionImageInfo;
765 LPWSTR CurrentDirectory = NULL;
766 LPWSTR CurrentDirectoryPart;
767 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
768 STARTUPINFOW StartupInfo;
769 ULONG Dummy;
770 LPWSTR BatchCommandLine;
771 ULONG CmdLineLength;
772 UNICODE_STRING CommandLineString;
773 LPWSTR TempBuffer;
774 PWCHAR Extension;
775 LPWSTR QuotedCmdLine = NULL;
776 LPWSTR ScanString;
777 LPWSTR NullBuffer;
778 LPWSTR NameBuffer = NULL;
779 WCHAR SaveChar;
780 ULONG RetVal;
781 UINT Error;
782 BOOLEAN SearchDone = FALSE;
783 HANDLE hConsole, hInput, hOutput;
784 CLIENT_ID ClientId;
785 PPEB OurPeb = NtCurrentPeb();
786 PPEB RemotePeb;
787
788 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
789 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
790 lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
791 dwCreationFlags);
792
793 /* Flags we don't handle yet */
794 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
795 {
796 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
797 }
798 if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
799 {
800 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
801 }
802 if (dwCreationFlags & CREATE_FORCEDOS)
803 {
804 DPRINT1("CREATE_FORCEDOS not handled\n");
805 }
806
807 /* Fail on this flag, it's only valid with the WithLogonW function */
808 if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
809 {
810 DPRINT1("Invalid flag used\n");
811 SetLastError(ERROR_INVALID_PARAMETER);
812 return FALSE;
813 }
814
815 /* This combination is illegal (see MSDN) */
816 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
817 (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
818 {
819 DPRINT1("Invalid flag combo used\n");
820 SetLastError(ERROR_INVALID_PARAMETER);
821 return FALSE;
822 }
823
824 /* Another illegal combo */
825 if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
826 (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
827 {
828 DPRINT1("Invalid flag combo used\n");
829 SetLastError(ERROR_INVALID_PARAMETER);
830 return FALSE;
831 }
832
833 /*
834 * We're going to modify and mask out flags and stuff in lpStartupInfo,
835 * so we'll use our own local copy for that.
836 */
837 StartupInfo = *lpStartupInfo;
838
839 /* FIXME: Use default Separate/Shared VDM Flag */
840
841 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
842 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
843 {
844 if (NtIsProcessInJob(NtCurrentProcess(), NULL))
845 {
846 /* Remove the shared flag and add the separate flag. */
847 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
848 CREATE_SEPARATE_WOW_VDM;
849 }
850 }
851
852 /*
853 * According to some sites, ShellExecuteEx uses an undocumented flag to
854 * send private handle data (such as HMONITOR or HICON). See:
855 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
856 * standard handles anymore since we'd be overwriting this private data
857 */
858 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
859 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
860 {
861 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
862 }
863
864 /* Start by zeroing out the fields */
865 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
866
867 /* Easy stuff first, convert the process priority class */
868 PriorityClass.Foreground = FALSE;
869 PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
870
871 /* Convert the environment */
872 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
873 {
874 lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment);
875 if (!lpEnvironment) return FALSE;
876 }
877
878 /* Get the application name and do all the proper formating necessary */
879 GetAppName:
880 /* See if we have an application name (oh please let us have one!) */
881 if (!lpApplicationName)
882 {
883 /* The fun begins */
884 NameBuffer = RtlAllocateHeap(GetProcessHeap(),
885 0,
886 MAX_PATH * sizeof(WCHAR));
887
888 /* This is all we have to work with :( */
889 lpApplicationName = lpCommandLine;
890
891 /* Initialize our friends at the beginning */
892 NullBuffer = (LPWSTR)lpApplicationName;
893 ScanString = (LPWSTR)lpApplicationName;
894
895 /* We will start by looking for a quote */
896 if (*ScanString == L'\"')
897 {
898 /* That was quick */
899 SearchDone = TRUE;
900
901 /* Advance past quote */
902 ScanString++;
903 lpApplicationName = ScanString;
904
905 /* Find the closing quote */
906 while (*ScanString)
907 {
908 if (*ScanString == L'\"')
909 {
910 /* Found it */
911 NullBuffer = ScanString;
912 FoundQuotes = TRUE;
913 break;
914 }
915
916 /* Keep looking */
917 ScanString++;
918 NullBuffer = ScanString;
919 }
920 }
921 else
922 {
923 /* No quotes, so we'll be looking for white space */
924 WhiteScan:
925 /* Reset the pointer */
926 lpApplicationName = lpCommandLine;
927
928 /* Find whitespace of Tab */
929 while (*ScanString)
930 {
931 if (*ScanString == ' ' || *ScanString == '\t')
932 {
933 /* Found it */
934 NullBuffer = ScanString;
935 break;
936 }
937
938 /* Keep looking */
939 ScanString++;
940 NullBuffer = ScanString;
941 }
942 }
943
944 /* Set the Null Buffer */
945 SaveChar = *NullBuffer;
946 *NullBuffer = UNICODE_NULL;
947
948 /* Do a search for the file */
949 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
950 RetVal = SearchPathW(NULL,
951 lpApplicationName,
952 L".exe",
953 MAX_PATH,
954 NameBuffer,
955 NULL) * sizeof(WCHAR);
956
957 /* Did it find something? */
958 if (RetVal)
959 {
960 /* Get file attributes */
961 ULONG Attributes = GetFileAttributesW(NameBuffer);
962 if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
963 {
964 /* Give it a length of 0 to fail, this was a directory. */
965 RetVal = 0;
966 }
967 else
968 {
969 /* It's a file! */
970 RetVal += sizeof(WCHAR);
971 }
972 }
973
974 /* Now check if we have a file, and if the path size is OK */
975 if (!RetVal || RetVal >= (MAX_PATH / sizeof(WCHAR)))
976 {
977 ULONG PathType;
978 HANDLE hFile;
979
980 /* We failed, try to get the Path Type */
981 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
982 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
983
984 /* If it's not relative, try to get the error */
985 if (PathType != RELATIVE_PATH)
986 {
987 /* This should fail, and give us a detailed LastError */
988 hFile = CreateFileW(lpApplicationName,
989 GENERIC_READ,
990 FILE_SHARE_READ | FILE_SHARE_WRITE,
991 NULL,
992 OPEN_EXISTING,
993 FILE_ATTRIBUTE_NORMAL,
994 NULL);
995
996 /* Did it actually NOT fail? */
997 if (hFile != INVALID_HANDLE_VALUE)
998 {
999 /* Fake the error */
1000 CloseHandle(hFile);
1001 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
1002 }
1003 }
1004 else
1005 {
1006 /* Immediately set the error */
1007 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
1008 }
1009
1010 /* Did we already fail once? */
1011 if (Error)
1012 {
1013 SetLastError(Error);
1014 }
1015 else
1016 {
1017 /* Not yet, cache it */
1018 Error = GetLastError();
1019 }
1020
1021 /* Put back the command line */
1022 *NullBuffer = SaveChar;
1023 lpApplicationName = NameBuffer;
1024
1025 /*
1026 * If the search isn't done and we still have cmdline
1027 * then start over. Ex: c:\ha ha ha\haha.exe
1028 */
1029 if (*ScanString && !SearchDone)
1030 {
1031 /* Move in the buffer */
1032 ScanString++;
1033 NullBuffer = ScanString;
1034
1035 /* We will have to add a quote, since there is a space*/
1036 QuotesNeeded = TRUE;
1037
1038 /* And we will also fake the fact we found one */
1039 FoundQuotes = TRUE;
1040
1041 /* Start over */
1042 goto WhiteScan;
1043 }
1044
1045 /* We totally failed */
1046 return FALSE;
1047 }
1048
1049 /* Put back the command line */
1050 *NullBuffer = SaveChar;
1051 lpApplicationName = NameBuffer;
1052 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
1053 }
1054 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
1055 {
1056 /* We have an app name (good!) but no command line */
1057 CmdLineIsAppName = TRUE;
1058 lpCommandLine = (LPWSTR)lpApplicationName;
1059 }
1060
1061 /* At this point the name has been toyed with enough to be openable */
1062 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
1063
1064 /* Check for failure */
1065 if (!NT_SUCCESS(Status))
1066 {
1067 /* Could be a non-PE File */
1068 switch (Status)
1069 {
1070 /* Check if the Kernel tells us it's not even valid MZ */
1071 case STATUS_INVALID_IMAGE_NE_FORMAT:
1072 case STATUS_INVALID_IMAGE_PROTECT:
1073 case STATUS_INVALID_IMAGE_NOT_MZ:
1074
1075 /* If it's a DOS app, use VDM
1076 if ((BasepCheckDosApp(&ApplicationName))) */
1077 {
1078 DPRINT1("Launching VDM...\n");
1079 RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1080 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1081 return CreateProcessW(L"ntvdm.exe",
1082 (LPWSTR)lpApplicationName,
1083 lpProcessAttributes,
1084 lpThreadAttributes,
1085 bInheritHandles,
1086 dwCreationFlags,
1087 lpEnvironment,
1088 lpCurrentDirectory,
1089 lpStartupInfo,
1090 lpProcessInformation);
1091 }
1092
1093 /* It's a batch file */
1094 Extension = &ApplicationName.Buffer[ApplicationName.Length /
1095 sizeof(WCHAR) - 4];
1096
1097 /* Make sure the extensions are correct */
1098 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
1099 {
1100 SetLastError(ERROR_BAD_EXE_FORMAT);
1101 return FALSE;
1102 }
1103
1104 /* Calculate the length of the command line */
1105 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
1106
1107 /* If we found quotes, then add them into the length size */
1108 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
1109 CmdLineLength *= sizeof(WCHAR);
1110
1111 /* Allocate space for the new command line */
1112 BatchCommandLine = RtlAllocateHeap(GetProcessHeap(),
1113 0,
1114 CmdLineLength);
1115
1116 /* Build it */
1117 wcscpy(BatchCommandLine, CMD_STRING);
1118 if (CmdLineIsAppName || FoundQuotes)
1119 {
1120 wcscat(BatchCommandLine, L"\"");
1121 }
1122 wcscat(BatchCommandLine, lpCommandLine);
1123 if (CmdLineIsAppName || FoundQuotes)
1124 {
1125 wcscat(BatchCommandLine, L"\"");
1126 }
1127
1128 /* Create it as a Unicode String */
1129 RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
1130
1131 /* Set the command line to this */
1132 lpCommandLine = CommandLineString.Buffer;
1133 lpApplicationName = NULL;
1134
1135 /* Free memory */
1136 RtlFreeHeap(GetProcessHeap(), 0, TempBuffer);
1137 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1138 ApplicationName.Buffer = NULL;
1139 TempBuffer = NULL;
1140 goto GetAppName;
1141 break;
1142
1143 case STATUS_INVALID_IMAGE_WIN_16:
1144
1145 /* It's a Win16 Image, use VDM */
1146 DPRINT1("Launching VDM...\n");
1147 RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1148 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1149 return CreateProcessW(L"ntvdm.exe",
1150 (LPWSTR)lpApplicationName,
1151 lpProcessAttributes,
1152 lpThreadAttributes,
1153 bInheritHandles,
1154 dwCreationFlags,
1155 lpEnvironment,
1156 lpCurrentDirectory,
1157 lpStartupInfo,
1158 lpProcessInformation);
1159
1160 default:
1161 /* Invalid Image Type */
1162 SetLastError(ERROR_BAD_EXE_FORMAT);
1163 return FALSE;
1164 }
1165 }
1166
1167 /* Use our desktop if we didn't get any */
1168 if (!StartupInfo.lpDesktop)
1169 {
1170 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
1171 }
1172
1173 /* FIXME: Check if Application is allowed to run */
1174
1175 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
1176
1177 /* Get some information about the executable */
1178 Status = ZwQuerySection(hSection,
1179 SectionImageInformation,
1180 &SectionImageInfo,
1181 sizeof(SectionImageInfo),
1182 NULL);
1183 if(!NT_SUCCESS(Status))
1184 {
1185 NtClose(hSection);
1186 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
1187 SetLastErrorByStatus(Status);
1188 return FALSE;
1189 }
1190
1191 /* Don't execute DLLs */
1192 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
1193 {
1194 NtClose(hSection);
1195 DPRINT1("Can't execute a DLL\n");
1196 SetLastError(ERROR_BAD_EXE_FORMAT);
1197 return FALSE;
1198 }
1199
1200 /* FIXME: Check for Debugger */
1201
1202 /* FIXME: Check if Machine Type and SubSys Version Match */
1203
1204 /* We don't support POSIX or anything else for now */
1205 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubsystemType &&
1206 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubsystemType)
1207 {
1208 NtClose(hSection);
1209 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubsystemType);
1210 SetLastError(ERROR_BAD_EXE_FORMAT);
1211 return FALSE;
1212 }
1213
1214 /* Initialize the process object attributes */
1215 ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
1216 lpProcessAttributes,
1217 NULL);
1218
1219 /* Create the Process */
1220 Status = NtCreateProcess(&hProcess,
1221 PROCESS_ALL_ACCESS,
1222 ObjectAttributes,
1223 NtCurrentProcess(),
1224 bInheritHandles,
1225 hSection,
1226 NULL,
1227 NULL);
1228 if(!NT_SUCCESS(Status))
1229 {
1230 NtClose(hSection);
1231 DPRINT1("Unable to create process, status 0x%x\n", Status);
1232 SetLastErrorByStatus(Status);
1233 return FALSE;
1234 }
1235
1236 /* Set new class */
1237 Status = NtSetInformationProcess(hProcess,
1238 ProcessPriorityClass,
1239 &PriorityClass,
1240 sizeof(PROCESS_PRIORITY_CLASS));
1241 if(!NT_SUCCESS(Status))
1242 {
1243 NtClose(hProcess);
1244 NtClose(hSection);
1245 DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
1246 SetLastErrorByStatus(Status);
1247 return FALSE;
1248 }
1249
1250 /* Set Error Mode */
1251 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
1252 {
1253 ULONG ErrorMode = SEM_FAILCRITICALERRORS;
1254 NtSetInformationProcess(hProcess,
1255 ProcessDefaultHardErrorMode,
1256 &ErrorMode,
1257 sizeof(ULONG));
1258 }
1259
1260 /* Convert the directory to a full path */
1261 if (lpCurrentDirectory)
1262 {
1263 /* Allocate a buffer */
1264 CurrentDirectory = RtlAllocateHeap(GetProcessHeap(),
1265 0,
1266 MAX_PATH * sizeof(WCHAR) + 2);
1267
1268 /* Get the length */
1269 if (GetFullPathNameW(lpCurrentDirectory,
1270 MAX_PATH,
1271 CurrentDirectory,
1272 &CurrentDirectoryPart) > MAX_PATH)
1273 {
1274 DPRINT1("Directory name too long\n");
1275 SetLastError(ERROR_DIRECTORY);
1276 return FALSE;
1277 }
1278 }
1279
1280 /* Insert quotes if needed */
1281 if (QuotesNeeded || CmdLineIsAppName)
1282 {
1283 /* Allocate a buffer */
1284 QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(),
1285 0,
1286 (wcslen(lpCommandLine) + 2 + 1) *
1287 sizeof(WCHAR));
1288
1289 /* Copy the first quote */
1290 wcscpy(QuotedCmdLine, L"\"");
1291
1292 /* Save a null char */
1293 if (QuotesNeeded)
1294 {
1295 SaveChar = *NullBuffer;
1296 *NullBuffer = UNICODE_NULL;
1297 }
1298
1299 /* Add the command line and the finishing quote */
1300 wcscat(QuotedCmdLine, lpCommandLine);
1301 wcscat(QuotedCmdLine, L"\"");
1302
1303 /* Add the null char */
1304 if (QuotesNeeded)
1305 {
1306 *NullBuffer = SaveChar;
1307 wcscat(QuotedCmdLine, NullBuffer);
1308 }
1309
1310 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
1311 }
1312
1313 /* Get the Process Information */
1314 Status = NtQueryInformationProcess(hProcess,
1315 ProcessBasicInformation,
1316 &ProcessBasicInfo,
1317 sizeof(ProcessBasicInfo),
1318 NULL);
1319
1320 /* Notify CSRSS */
1321 Status = BasepNotifyCsrOfCreation(dwCreationFlags,
1322 (HANDLE)ProcessBasicInfo.UniqueProcessId,
1323 SectionImageInfo.SubsystemType,
1324 &hConsole,
1325 &hInput,
1326 &hOutput);
1327
1328 if (!NT_SUCCESS(Status))
1329 {
1330 DPRINT1("CSR Notification Failed");
1331 SetLastErrorByStatus(Status);
1332 return FALSE;
1333 }
1334
1335 /* Create Process Environment */
1336 RemotePeb = ProcessBasicInfo.PebBaseAddress;
1337 Status = BasepInitializeEnvironment(hProcess,
1338 RemotePeb,
1339 (LPWSTR)lpApplicationName,
1340 CurrentDirectory,
1341 (QuotesNeeded || CmdLineIsAppName) ?
1342 QuotedCmdLine : lpCommandLine,
1343 lpEnvironment,
1344 lpStartupInfo,
1345 dwCreationFlags,
1346 bInheritHandles,
1347 hInput,
1348 hOutput);
1349 if (!NT_SUCCESS(Status))
1350 {
1351 DPRINT1("Could not initialize Process Environment\n");
1352 SetLastErrorByStatus(Status);
1353 return FALSE;
1354 }
1355
1356 /* Close the section */
1357 NtClose(hSection);
1358 hSection = NULL;
1359
1360 /* Duplicate the handles if needed */
1361 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
1362 SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1363 {
1364 PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
1365
1366 /* Get the remote parameters */
1367 Status = NtReadVirtualMemory(hProcess,
1368 &RemotePeb->ProcessParameters,
1369 &RemoteParameters,
1370 sizeof(PVOID),
1371 NULL);
1372 if (!NT_SUCCESS(Status))
1373 {
1374 DPRINT1("Failed to read memory\n");
1375 return FALSE;
1376 }
1377
1378 /* Duplicate and write the handles */
1379 BasepDuplicateAndWriteHandle(hProcess,
1380 OurPeb->ProcessParameters->StandardInput,
1381 &RemoteParameters->StandardInput);
1382 BasepDuplicateAndWriteHandle(hProcess,
1383 OurPeb->ProcessParameters->StandardOutput,
1384 &RemoteParameters->StandardOutput);
1385 BasepDuplicateAndWriteHandle(hProcess,
1386 OurPeb->ProcessParameters->StandardError,
1387 &RemoteParameters->StandardError);
1388 }
1389
1390 /* Create the first thread */
1391 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1392 SectionImageInfo.TransferAddress);
1393 hThread = BasepCreateFirstThread(hProcess,
1394 lpThreadAttributes,
1395 &SectionImageInfo,
1396 &ClientId);
1397
1398 if (hThread == NULL)
1399 {
1400 DPRINT1("Could not create Initial Thread\n");
1401 return FALSE;
1402 }
1403
1404 if (!(dwCreationFlags & CREATE_SUSPENDED))
1405 {
1406 NtResumeThread(hThread, &Dummy);
1407 }
1408
1409 /* Cleanup Environment */
1410 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
1411 {
1412 RtlDestroyEnvironment(lpEnvironment);
1413 }
1414
1415 /* Return Data */
1416 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
1417 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
1418 lpProcessInformation->hProcess = hProcess;
1419 lpProcessInformation->hThread = hThread;
1420 DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread,
1421 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
1422 hProcess = hThread = NULL;
1423
1424 /* De-allocate heap strings */
1425 if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1426 if (ApplicationName.Buffer)
1427 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1428 if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory);
1429 if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine);
1430
1431 /* Kill any handles still alive */
1432 if (hSection) NtClose(hSection);
1433 if (hThread)
1434 {
1435 /* We don't know any more details then this */
1436 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
1437 NtClose(hThread);
1438 }
1439 if (hProcess) NtClose(hProcess);
1440
1441 /* Return Success */
1442 return TRUE;
1443 }
1444
1445 /* EOF */