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