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