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