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