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