- Final ROSRTL removal patch. The next patch will remove the actual library and code.
[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 <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 DPRINT("Foo\n");
652 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
653 DPRINT("Foo\n");
654
655 /* Initialize all strings to nothing */
656 LiveCommandLine.Buffer = NULL;
657 DummyString.Buffer = NULL;
658 ApplicationName.Buffer = NULL;
659 CurrentDirectory.Buffer = NULL;
660 StartupInfo.lpDesktop = NULL;
661 StartupInfo.lpReserved = NULL;
662 StartupInfo.lpTitle = NULL;
663
664 /* Convert the Command line */
665 if (lpCommandLine)
666 {
667 DPRINT("Foo\n");
668 /* If it's too long, then we'll have a problem */
669 if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
670 NtCurrentTeb()->StaticUnicodeString.MaximumLength)
671 {
672 /* Cache it in the TEB */
673 DPRINT("Foo\n");
674 CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
675 }
676 else
677 {
678 /* Use a dynamic version */
679 DPRINT("Foo\n");
680 Basep8BitStringToLiveUnicodeString(&LiveCommandLine,
681 lpCommandLine);
682 }
683 }
684 else
685 {
686 DPRINT("Foo\n");
687 /* The logic below will use CommandLine, so we must make it valid */
688 CommandLine = &DummyString;
689 }
690
691 /* Convert the Name and Directory */
692 if (lpApplicationName)
693 {
694 DPRINT("Foo\n");
695 Basep8BitStringToLiveUnicodeString(&ApplicationName,
696 lpApplicationName);
697 }
698 if (lpCurrentDirectory)
699 {
700 DPRINT("Foo\n");
701 Basep8BitStringToLiveUnicodeString(&CurrentDirectory,
702 lpCurrentDirectory);
703 }
704
705 /* Now convert Startup Strings */
706 if (lpStartupInfo->lpReserved)
707 {
708 DPRINT("Foo\n");
709 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
710 &StartupInfo.lpReserved);
711 }
712 if (lpStartupInfo->lpDesktop)
713 {
714 DPRINT("Foo\n");
715 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
716 &StartupInfo.lpDesktop);
717 }
718 if (lpStartupInfo->lpTitle)
719 {
720 DPRINT("Foo\n");
721 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
722 &StartupInfo.lpTitle);
723 }
724
725 /* Call the Unicode function */
726 bRetVal = CreateProcessW(ApplicationName.Buffer,
727 LiveCommandLine.Buffer ?
728 LiveCommandLine.Buffer : CommandLine->Buffer,
729 lpProcessAttributes,
730 lpThreadAttributes,
731 bInheritHandles,
732 dwCreationFlags,
733 lpEnvironment,
734 CurrentDirectory.Buffer,
735 &StartupInfo,
736 lpProcessInformation);
737
738 /* Clean up */
739 RtlFreeUnicodeString(&ApplicationName);
740 RtlFreeUnicodeString(&LiveCommandLine);
741 RtlFreeUnicodeString(&CurrentDirectory);
742 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop);
743 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved);
744 RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle);
745
746 /* Return what Unicode did */
747 return bRetVal;
748 }
749
750 /*
751 * @implemented
752 */
753 BOOL
754 STDCALL
755 CreateProcessW(LPCWSTR lpApplicationName,
756 LPWSTR lpCommandLine,
757 LPSECURITY_ATTRIBUTES lpProcessAttributes,
758 LPSECURITY_ATTRIBUTES lpThreadAttributes,
759 BOOL bInheritHandles,
760 DWORD dwCreationFlags,
761 LPVOID lpEnvironment,
762 LPCWSTR lpCurrentDirectory,
763 LPSTARTUPINFOW lpStartupInfo,
764 LPPROCESS_INFORMATION lpProcessInformation)
765 {
766 NTSTATUS Status;
767 PROCESS_PRIORITY_CLASS PriorityClass;
768 BOOLEAN FoundQuotes = FALSE;
769 BOOLEAN QuotesNeeded = FALSE;
770 BOOLEAN CmdLineIsAppName = FALSE;
771 UNICODE_STRING ApplicationName;
772 OBJECT_ATTRIBUTES LocalObjectAttributes;
773 POBJECT_ATTRIBUTES ObjectAttributes;
774 HANDLE hSection, hProcess, hThread;
775 SECTION_IMAGE_INFORMATION SectionImageInfo;
776 LPWSTR CurrentDirectory = NULL;
777 LPWSTR CurrentDirectoryPart;
778 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
779 STARTUPINFOW StartupInfo;
780 ULONG Dummy;
781 LPWSTR QuotedCmdLine = NULL;
782 LPWSTR ScanString;
783 LPWSTR NullBuffer;
784 LPWSTR NameBuffer = NULL;
785 WCHAR SaveChar;
786 ULONG RetVal;
787 UINT Error;
788 BOOLEAN SearchDone = FALSE;
789 HANDLE hConsole, hInput, hOutput;
790 CLIENT_ID ClientId;
791 PPEB OurPeb = NtCurrentPeb();
792 PPEB RemotePeb;
793
794 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
795 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
796 lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
797 dwCreationFlags);
798
799 /* Flags we don't handle yet */
800 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
801 {
802 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
803 }
804 if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
805 {
806 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
807 }
808 if (dwCreationFlags & CREATE_FORCEDOS)
809 {
810 DPRINT1("CREATE_FORCEDOS not handled\n");
811 }
812
813 /* Fail on this flag, it's only valid with the WithLogonW function */
814 if (dwCreationFlags & CREATE_WITH_USERPROFILE)
815 {
816 DPRINT1("Invalid flag used\n");
817 SetLastError(ERROR_INVALID_PARAMETER);
818 return FALSE;
819 }
820
821 /* This combination is illegal (see MSDN) */
822 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
823 (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
824 {
825 DPRINT1("Invalid flag combo used\n");
826 SetLastError(ERROR_INVALID_PARAMETER);
827 return FALSE;
828 }
829
830 /* Another illegal combo */
831 if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
832 (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
833 {
834 DPRINT1("Invalid flag combo used\n");
835 SetLastError(ERROR_INVALID_PARAMETER);
836 return FALSE;
837 }
838 DPRINT("Foo\n");
839 /*
840 * We're going to modify and mask out flags and stuff in lpStartupInfo,
841 * so we'll use our own local copy for that.
842 */
843 StartupInfo = *lpStartupInfo;
844 DPRINT("Foo\n");
845 /* FIXME: Use default Separate/Shared VDM Flag */
846
847 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
848 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
849 {
850 if (NtIsProcessInJob(NtCurrentProcess(), NULL))
851 {
852 /* Remove the shared flag and add the separate flag. */
853 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
854 CREATE_SEPARATE_WOW_VDM;
855 }
856 }
857 DPRINT("Foo\n");
858 /*
859 * According to some sites, ShellExecuteEx uses an undocumented flag to
860 * send private handle data (such as HMONITOR or HICON). See:
861 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
862 * standard handles anymore since we'd be overwriting this private data
863 */
864 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
865 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
866 {
867 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
868 }
869 DPRINT("Foo\n");
870 /* Start by zeroing out the fields */
871 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
872 DPRINT("Foo\n");
873 /* Easy stuff first, convert the process priority class */
874 PriorityClass.Foreground = FALSE;
875 PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
876 DPRINT("Foo\n");
877 /* Convert the environment */
878 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
879 {
880 lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment);
881 if (!lpEnvironment) return FALSE;
882 }
883 DPRINT("Foo\n");
884 /* Get the application name and do all the proper formating necessary */
885 GetAppName:
886 /* See if we have an application name (oh please let us have one!) */
887 if (!lpApplicationName)
888 {
889 /* The fun begins */
890 NameBuffer = RtlAllocateHeap(GetProcessHeap(),
891 0,
892 MAX_PATH * sizeof(WCHAR));
893
894 /* This is all we have to work with :( */
895 lpApplicationName = lpCommandLine;
896
897 /* Initialize our friends at the beginning */
898 NullBuffer = (LPWSTR)lpApplicationName;
899 ScanString = (LPWSTR)lpApplicationName;
900
901 /* We will start by looking for a quote */
902 if (*ScanString == L'\"')
903 {
904 /* That was quick */
905 SearchDone = TRUE;
906
907 /* Advance past quote */
908 ScanString++;
909 lpApplicationName = ScanString;
910 DPRINT("Foo\n");
911 /* Find the closing quote */
912 while (*ScanString)
913 {
914 if (*ScanString == L'\"')
915 {
916 /* Found it */
917 NullBuffer = ScanString;
918 FoundQuotes = TRUE;
919 break;
920 }
921 DPRINT("Foo\n");
922 /* Keep looking */
923 ScanString++;
924 NullBuffer = ScanString;
925 }
926 }
927 else
928 {
929 /* No quotes, so we'll be looking for white space */
930 WhiteScan:
931 /* Reset the pointer */
932 lpApplicationName = lpCommandLine;
933 DPRINT("Foo\n");
934 /* Find whitespace of Tab */
935 while (*ScanString)
936 {
937 if (*ScanString == ' ' || *ScanString == '\t')
938 {
939 /* Found it */
940 NullBuffer = ScanString;
941 break;
942 }
943 DPRINT("Foo\n");
944 /* Keep looking */
945 ScanString++;
946 NullBuffer = ScanString;
947 }
948 }
949
950 /* Set the Null Buffer */
951 SaveChar = *NullBuffer;
952 *NullBuffer = UNICODE_NULL;
953
954 /* Do a search for the file */
955 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
956 RetVal = SearchPathW(NULL,
957 lpApplicationName,
958 L".exe",
959 MAX_PATH,
960 NameBuffer,
961 NULL) * sizeof(WCHAR);
962
963 /* Did it find something? */
964 if (RetVal)
965 {
966 /* Get file attributes */
967 ULONG Attributes = GetFileAttributesW(NameBuffer);
968 if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
969 {
970 /* Give it a length of 0 to fail, this was a directory. */
971 RetVal = 0;
972 }
973 else
974 {
975 /* It's a file! */
976 RetVal += sizeof(WCHAR);
977 }
978 }
979
980 /* Now check if we have a file, and if the path size is OK */
981 if (!RetVal || RetVal >= (MAX_PATH / sizeof(WCHAR)))
982 {
983 ULONG PathType;
984 HANDLE hFile;
985
986 /* We failed, try to get the Path Type */
987 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
988 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
989
990 /* If it's not relative, try to get the error */
991 if (PathType != RELATIVE_PATH)
992 {
993 /* This should fail, and give us a detailed LastError */
994 hFile = CreateFileW(lpApplicationName,
995 GENERIC_READ,
996 FILE_SHARE_READ | FILE_SHARE_WRITE,
997 NULL,
998 OPEN_EXISTING,
999 FILE_ATTRIBUTE_NORMAL,
1000 NULL);
1001
1002 /* Did it actually NOT fail? */
1003 if (hFile != INVALID_HANDLE_VALUE)
1004 {
1005 /* Fake the error */
1006 CloseHandle(hFile);
1007 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
1008 }
1009 }
1010 else
1011 {
1012 /* Immediately set the error */
1013 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
1014 }
1015
1016 /* Did we already fail once? */
1017 if (Error)
1018 {
1019 SetLastError(Error);
1020 }
1021 else
1022 {
1023 /* Not yet, cache it */
1024 Error = GetLastError();
1025 }
1026
1027 /* Put back the command line */
1028 *NullBuffer = SaveChar;
1029 lpApplicationName = NameBuffer;
1030
1031 /*
1032 * If the search isn't done and we still have cmdline
1033 * then start over. Ex: c:\ha ha ha\haha.exe
1034 */
1035 if (*ScanString && !SearchDone)
1036 {
1037 /* Move in the buffer */
1038 ScanString++;
1039 NullBuffer = ScanString;
1040
1041 /* We will have to add a quote, since there is a space*/
1042 QuotesNeeded = TRUE;
1043
1044 /* And we will also fake the fact we found one */
1045 FoundQuotes = TRUE;
1046
1047 /* Start over */
1048 goto WhiteScan;
1049 }
1050
1051 /* We totally failed */
1052 return FALSE;
1053 }
1054
1055 /* Put back the command line */
1056 *NullBuffer = SaveChar;
1057 lpApplicationName = NameBuffer;
1058 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
1059 }
1060 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
1061 {
1062 /* We have an app name (good!) but no command line */
1063 CmdLineIsAppName = TRUE;
1064 lpCommandLine = (LPWSTR)lpApplicationName;
1065 }
1066
1067 /* At this point the name has been toyed with enough to be openable */
1068 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
1069
1070 /* Check for failure */
1071 if (!NT_SUCCESS(Status))
1072 {
1073 /* Could be a non-PE File */
1074 switch (Status)
1075 {
1076 /* Check if the Kernel tells us it's not even valid MZ */
1077 case STATUS_INVALID_IMAGE_NE_FORMAT:
1078 case STATUS_INVALID_IMAGE_PROTECT:
1079 case STATUS_INVALID_IMAGE_NOT_MZ:
1080
1081 /* If it's a DOS app, use VDM */
1082 //if ((BasepCheckDosApp(&ApplicationName)))
1083 {
1084 DPRINT1("Launching VDM...\n");
1085 RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1086 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1087 return CreateProcessW(L"ntvdm.exe",
1088 (LPWSTR)lpApplicationName,
1089 lpProcessAttributes,
1090 lpThreadAttributes,
1091 bInheritHandles,
1092 dwCreationFlags,
1093 lpEnvironment,
1094 lpCurrentDirectory,
1095 lpStartupInfo,
1096 lpProcessInformation);
1097 }
1098
1099 /* It's a batch file */
1100 LPWSTR BatchCommandLine;
1101 ULONG CmdLineLength;
1102 UNICODE_STRING CommandLineString;
1103 LPWSTR TempBuffer;
1104 PWCHAR Extension =
1105 &ApplicationName.Buffer[ApplicationName.Length / sizeof(WCHAR) - 4];
1106
1107 /* Make sure the extensions are correct */
1108 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
1109 {
1110 SetLastError(ERROR_BAD_EXE_FORMAT);
1111 return FALSE;
1112 }
1113
1114 /* Calculate the length of the command line */
1115 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
1116
1117 /* If we found quotes, then add them into the length size */
1118 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
1119 CmdLineLength *= sizeof(WCHAR);
1120
1121 /* Allocate space for the new command line */
1122 BatchCommandLine = RtlAllocateHeap(GetProcessHeap(),
1123 0,
1124 CmdLineLength);
1125
1126 /* Build it */
1127 wcscpy(BatchCommandLine, CMD_STRING);
1128 if (CmdLineIsAppName || FoundQuotes)
1129 {
1130 wcscat(BatchCommandLine, L"\"");
1131 }
1132 wcscat(BatchCommandLine, lpCommandLine);
1133 if (CmdLineIsAppName || FoundQuotes)
1134 {
1135 wcscat(BatchCommandLine, L"\"");
1136 }
1137
1138 /* Create it as a Unicode String */
1139 RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
1140
1141 /* Set the command line to this */
1142 lpCommandLine = CommandLineString.Buffer;
1143 lpApplicationName = NULL;
1144
1145 /* Free memory */
1146 RtlFreeHeap(GetProcessHeap(), 0, TempBuffer);
1147 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1148 ApplicationName.Buffer = NULL;
1149 TempBuffer = NULL;
1150 goto GetAppName;
1151 break;
1152
1153 case STATUS_INVALID_IMAGE_WIN_16:
1154
1155 /* It's a Win16 Image, use VDM */
1156 DPRINT1("Launching VDM...\n");
1157 RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1158 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1159 return CreateProcessW(L"ntvdm.exe",
1160 (LPWSTR)lpApplicationName,
1161 lpProcessAttributes,
1162 lpThreadAttributes,
1163 bInheritHandles,
1164 dwCreationFlags,
1165 lpEnvironment,
1166 lpCurrentDirectory,
1167 lpStartupInfo,
1168 lpProcessInformation);
1169
1170 default:
1171 /* Invalid Image Type */
1172 SetLastError(ERROR_BAD_EXE_FORMAT);
1173 return FALSE;
1174 }
1175 }
1176
1177 /* Use our desktop if we didn't get any */
1178 if (!StartupInfo.lpDesktop)
1179 {
1180 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
1181 }
1182
1183 /* FIXME: Check if Application is allowed to run */
1184
1185 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
1186
1187 /* Get some information about the executable */
1188 Status = ZwQuerySection(hSection,
1189 SectionImageInformation,
1190 &SectionImageInfo,
1191 sizeof(SectionImageInfo),
1192 NULL);
1193 if(!NT_SUCCESS(Status))
1194 {
1195 NtClose(hSection);
1196 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
1197 SetLastErrorByStatus(Status);
1198 return FALSE;
1199 }
1200
1201 /* Don't execute DLLs */
1202 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
1203 {
1204 NtClose(hSection);
1205 DPRINT1("Can't execute a DLL\n");
1206 SetLastError(ERROR_BAD_EXE_FORMAT);
1207 return FALSE;
1208 }
1209
1210 /* FIXME: Check for Debugger */
1211
1212 /* FIXME: Check if Machine Type and SubSys Version Match */
1213
1214 /* We don't support POSIX or anything else for now */
1215 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubsystemType &&
1216 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubsystemType)
1217 {
1218 NtClose(hSection);
1219 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubsystemType);
1220 SetLastError(ERROR_BAD_EXE_FORMAT);
1221 return FALSE;
1222 }
1223
1224 /* Initialize the process object attributes */
1225 ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
1226 lpProcessAttributes,
1227 NULL);
1228
1229 /* Create the Process */
1230 Status = NtCreateProcess(&hProcess,
1231 PROCESS_ALL_ACCESS,
1232 ObjectAttributes,
1233 NtCurrentProcess(),
1234 bInheritHandles,
1235 hSection,
1236 NULL,
1237 NULL);
1238 if(!NT_SUCCESS(Status))
1239 {
1240 NtClose(hSection);
1241 DPRINT1("Unable to create process, status 0x%x\n", Status);
1242 SetLastErrorByStatus(Status);
1243 return FALSE;
1244 }
1245
1246 /* Set new class */
1247 Status = NtSetInformationProcess(hProcess,
1248 ProcessPriorityClass,
1249 &PriorityClass,
1250 sizeof(PROCESS_PRIORITY_CLASS));
1251 if(!NT_SUCCESS(Status))
1252 {
1253 NtClose(hProcess);
1254 NtClose(hSection);
1255 DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
1256 SetLastErrorByStatus(Status);
1257 return FALSE;
1258 }
1259
1260 /* Set Error Mode */
1261 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
1262 {
1263 ULONG ErrorMode = SEM_FAILCRITICALERRORS;
1264 NtSetInformationProcess(hProcess,
1265 ProcessDefaultHardErrorMode,
1266 &ErrorMode,
1267 sizeof(ULONG));
1268 }
1269
1270 /* Convert the directory to a full path */
1271 if (lpCurrentDirectory)
1272 {
1273 /* Allocate a buffer */
1274 CurrentDirectory = RtlAllocateHeap(GetProcessHeap(),
1275 0,
1276 MAX_PATH * sizeof(WCHAR) + 2);
1277
1278 /* Get the length */
1279 if (GetFullPathNameW(lpCurrentDirectory,
1280 MAX_PATH,
1281 CurrentDirectory,
1282 &CurrentDirectoryPart) > MAX_PATH)
1283 {
1284 DPRINT1("Directory name too long\n");
1285 SetLastError(ERROR_DIRECTORY);
1286 return FALSE;
1287 }
1288 }
1289
1290 /* Insert quotes if needed */
1291 if (QuotesNeeded || CmdLineIsAppName)
1292 {
1293 /* Allocate a buffer */
1294 QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(),
1295 0,
1296 (wcslen(lpCommandLine) + 2 + 1) *
1297 sizeof(WCHAR));
1298
1299 /* Copy the first quote */
1300 wcscpy(QuotedCmdLine, L"\"");
1301
1302 /* Save a null char */
1303 if (QuotesNeeded)
1304 {
1305 SaveChar = *NullBuffer;
1306 *NullBuffer = UNICODE_NULL;
1307 }
1308
1309 /* Add the command line and the finishing quote */
1310 wcscat(QuotedCmdLine, lpCommandLine);
1311 wcscat(QuotedCmdLine, L"\"");
1312
1313 /* Add the null char */
1314 if (QuotesNeeded)
1315 {
1316 *NullBuffer = SaveChar;
1317 wcscat(QuotedCmdLine, NullBuffer);
1318 }
1319
1320 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
1321 }
1322
1323 /* Get the Process Information */
1324 Status = NtQueryInformationProcess(hProcess,
1325 ProcessBasicInformation,
1326 &ProcessBasicInfo,
1327 sizeof(ProcessBasicInfo),
1328 NULL);
1329
1330 /* Notify CSRSS */
1331 Status = BasepNotifyCsrOfCreation(dwCreationFlags,
1332 (HANDLE)ProcessBasicInfo.UniqueProcessId,
1333 SectionImageInfo.SubsystemType,
1334 &hConsole,
1335 &hInput,
1336 &hOutput);
1337
1338 if (!NT_SUCCESS(Status))
1339 {
1340 DPRINT1("CSR Notification Failed");
1341 SetLastErrorByStatus(Status);
1342 return FALSE;
1343 }
1344
1345 /* Create Process Environment */
1346 RemotePeb = ProcessBasicInfo.PebBaseAddress;
1347 Status = BasepInitializeEnvironment(hProcess,
1348 RemotePeb,
1349 (LPWSTR)lpApplicationName,
1350 CurrentDirectory,
1351 (QuotesNeeded || CmdLineIsAppName) ?
1352 QuotedCmdLine : lpCommandLine,
1353 lpEnvironment,
1354 lpStartupInfo,
1355 dwCreationFlags,
1356 bInheritHandles,
1357 hInput,
1358 hOutput);
1359 if (!NT_SUCCESS(Status))
1360 {
1361 DPRINT1("Could not initialize Process Environment\n");
1362 SetLastErrorByStatus(Status);
1363 return FALSE;
1364 }
1365
1366 /* Close the section */
1367 NtClose(hSection);
1368 hSection = NULL;
1369
1370 /* Duplicate the handles if needed */
1371 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
1372 SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1373 {
1374 PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
1375
1376 /* Get the remote parameters */
1377 Status = NtReadVirtualMemory(hProcess,
1378 &RemotePeb->ProcessParameters,
1379 &RemoteParameters,
1380 sizeof(PVOID),
1381 NULL);
1382 if (!NT_SUCCESS(Status))
1383 {
1384 DPRINT1("Failed to read memory\n");
1385 return FALSE;
1386 }
1387
1388 /* Duplicate and write the handles */
1389 BasepDuplicateAndWriteHandle(hProcess,
1390 OurPeb->ProcessParameters->StandardInput,
1391 &RemoteParameters->StandardInput);
1392 BasepDuplicateAndWriteHandle(hProcess,
1393 OurPeb->ProcessParameters->StandardOutput,
1394 &RemoteParameters->StandardOutput);
1395 BasepDuplicateAndWriteHandle(hProcess,
1396 OurPeb->ProcessParameters->StandardError,
1397 &RemoteParameters->StandardError);
1398 }
1399
1400 /* Create the first thread */
1401 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1402 SectionImageInfo.TransferAddress);
1403 hThread = BasepCreateFirstThread(hProcess,
1404 lpThreadAttributes,
1405 &SectionImageInfo,
1406 &ClientId);
1407
1408 if (hThread == NULL)
1409 {
1410 DPRINT1("Could not create Initial Thread\n");
1411 return FALSE;
1412 }
1413
1414 if (!(dwCreationFlags & CREATE_SUSPENDED))
1415 {
1416 NtResumeThread(hThread, &Dummy);
1417 }
1418
1419 /* Cleanup Environment */
1420 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
1421 {
1422 RtlDestroyEnvironment(lpEnvironment);
1423 }
1424
1425 /* Return Data */
1426 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
1427 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
1428 lpProcessInformation->hProcess = hProcess;
1429 lpProcessInformation->hThread = hThread;
1430 DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread,
1431 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
1432 hProcess = hThread = NULL;
1433
1434 /* De-allocate heap strings */
1435 if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
1436 if (ApplicationName.Buffer)
1437 RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
1438 if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory);
1439 if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine);
1440
1441 /* Kill any handles still alive */
1442 if (hSection) NtClose(hSection);
1443 if (hThread)
1444 {
1445 /* We don't know any more details then this */
1446 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
1447 NtClose(hThread);
1448 }
1449 if (hProcess) NtClose(hProcess);
1450
1451 /* Return Success */
1452 return TRUE;
1453 }
1454
1455 /* EOF */