843dc1f9ba44d591451da42ac6eb931fc1766f75
[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)) 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 WINAPI
320 BasepGetDllPath(LPWSTR FullPath,
321 PVOID Environment)
322 {
323 /* FIXME: Not yet implemented */
324 return NULL;
325 }
326
327 VOID
328 WINAPI
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 WINAPI
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 WINAPI
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, 0, NULL };
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 if (lpCurrentDirectory)
722 {
723 if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) ||
724 !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY))
725 {
726 SetLastError(ERROR_DIRECTORY);
727 return FALSE;
728 }
729 }
730
731 /*
732 * We're going to modify and mask out flags and stuff in lpStartupInfo,
733 * so we'll use our own local copy for that.
734 */
735 StartupInfo = *lpStartupInfo;
736
737 /* FIXME: Use default Separate/Shared VDM Flag */
738
739 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
740 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
741 {
742 if (NtIsProcessInJob(NtCurrentProcess(), NULL))
743 {
744 /* Remove the shared flag and add the separate flag. */
745 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
746 CREATE_SEPARATE_WOW_VDM;
747 }
748 }
749
750 /*
751 * According to some sites, ShellExecuteEx uses an undocumented flag to
752 * send private handle data (such as HMONITOR or HICON). See:
753 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
754 * standard handles anymore since we'd be overwriting this private data
755 */
756 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
757 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
758 {
759 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
760 }
761
762 /* Start by zeroing out the fields */
763 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
764
765 /* Easy stuff first, convert the process priority class */
766 PriorityClass.Foreground = FALSE;
767 PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags);
768
769 if (lpCommandLine)
770 {
771 /* Serach for escape sequences */
772 ScanString = lpCommandLine;
773 while (NULL != (ScanString = wcschr(ScanString, L'^')))
774 {
775 ScanString++;
776 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\"')
777 {
778 Escape = TRUE;
779 break;
780 }
781 }
782 }
783
784 /* Get the application name and do all the proper formating necessary */
785 GetAppName:
786 /* See if we have an application name (oh please let us have one!) */
787 if (!lpApplicationName)
788 {
789 /* The fun begins */
790 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
791 0,
792 MAX_PATH * sizeof(WCHAR));
793 if (NameBuffer == NULL)
794 {
795 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
796 goto Cleanup;
797 }
798
799 /* This is all we have to work with :( */
800 lpApplicationName = lpCommandLine;
801
802 /* Initialize our friends at the beginning */
803 NullBuffer = (LPWSTR)lpApplicationName;
804 ScanString = (LPWSTR)lpApplicationName;
805
806 /* We will start by looking for a quote */
807 if (*ScanString == L'\"')
808 {
809 /* That was quick */
810 SearchDone = TRUE;
811
812 /* Advance past quote */
813 ScanString++;
814 lpApplicationName = ScanString;
815
816 /* Find the closing quote */
817 while (*ScanString)
818 {
819 if (*ScanString == L'\"' && *(ScanString - 1) != L'^')
820 {
821 /* Found it */
822 NullBuffer = ScanString;
823 FoundQuotes = TRUE;
824 break;
825 }
826
827 /* Keep looking */
828 ScanString++;
829 NullBuffer = ScanString;
830 }
831 }
832 else
833 {
834 /* No quotes, so we'll be looking for white space */
835 WhiteScan:
836 /* Reset the pointer */
837 lpApplicationName = lpCommandLine;
838
839 /* Find whitespace of Tab */
840 while (*ScanString)
841 {
842 if (*ScanString == ' ' || *ScanString == '\t')
843 {
844 /* Found it */
845 NullBuffer = ScanString;
846 break;
847 }
848
849 /* Keep looking */
850 ScanString++;
851 NullBuffer = ScanString;
852 }
853 }
854
855 /* Set the Null Buffer */
856 SaveChar = *NullBuffer;
857 *NullBuffer = UNICODE_NULL;
858
859 /* Do a search for the file */
860 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
861 RetVal = SearchPathW(NULL,
862 lpApplicationName,
863 L".exe",
864 MAX_PATH,
865 NameBuffer,
866 NULL) * sizeof(WCHAR);
867
868 /* Did it find something? */
869 if (RetVal)
870 {
871 /* Get file attributes */
872 ULONG Attributes = GetFileAttributesW(NameBuffer);
873 if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
874 {
875 /* Give it a length of 0 to fail, this was a directory. */
876 RetVal = 0;
877 }
878 else
879 {
880 /* It's a file! */
881 RetVal += sizeof(WCHAR);
882 }
883 }
884
885 /* Now check if we have a file, and if the path size is OK */
886 if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR)))
887 {
888 ULONG PathType;
889 HANDLE hFile;
890
891 /* We failed, try to get the Path Type */
892 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
893 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
894
895 /* If it's not relative, try to get the error */
896 if (PathType != RtlPathTypeRelative)
897 {
898 /* This should fail, and give us a detailed LastError */
899 hFile = CreateFileW(lpApplicationName,
900 GENERIC_READ,
901 FILE_SHARE_READ | FILE_SHARE_WRITE,
902 NULL,
903 OPEN_EXISTING,
904 FILE_ATTRIBUTE_NORMAL,
905 NULL);
906
907 /* Did it actually NOT fail? */
908 if (hFile != INVALID_HANDLE_VALUE)
909 {
910 /* Fake the error */
911 CloseHandle(hFile);
912 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
913 }
914 }
915 else
916 {
917 /* Immediately set the error */
918 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
919 }
920
921 /* Did we already fail once? */
922 if (Error)
923 {
924 SetLastError(Error);
925 }
926 else
927 {
928 /* Not yet, cache it */
929 Error = GetLastError();
930 }
931
932 /* Put back the command line */
933 *NullBuffer = SaveChar;
934 lpApplicationName = NameBuffer;
935
936 /*
937 * If the search isn't done and we still have cmdline
938 * then start over. Ex: c:\ha ha ha\haha.exe
939 */
940 if (*ScanString && !SearchDone)
941 {
942 /* Move in the buffer */
943 ScanString++;
944 NullBuffer = ScanString;
945
946 /* We will have to add a quote, since there is a space*/
947 QuotesNeeded = TRUE;
948
949 /* And we will also fake the fact we found one */
950 FoundQuotes = TRUE;
951
952 /* Start over */
953 goto WhiteScan;
954 }
955
956 /* We totally failed */
957 goto Cleanup;
958 }
959
960 /* Put back the command line */
961 *NullBuffer = SaveChar;
962 lpApplicationName = NameBuffer;
963 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
964 }
965 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
966 {
967 /* We have an app name (good!) but no command line */
968 CmdLineIsAppName = TRUE;
969 lpCommandLine = (LPWSTR)lpApplicationName;
970 }
971
972 /* At this point the name has been toyed with enough to be openable */
973 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
974
975 /* Check for failure */
976 if (!NT_SUCCESS(Status))
977 {
978 /* Could be a non-PE File */
979 switch (Status)
980 {
981 /* Check if the Kernel tells us it's not even valid MZ */
982 case STATUS_INVALID_IMAGE_NE_FORMAT:
983 case STATUS_INVALID_IMAGE_PROTECT:
984 case STATUS_INVALID_IMAGE_NOT_MZ:
985
986 #if 0
987 /* If it's a DOS app, use VDM */
988 if ((BasepCheckDosApp(&ApplicationName)))
989 {
990 DPRINT1("Launching VDM...\n");
991 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
992 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
993 return CreateProcessW(L"ntvdm.exe",
994 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
995 lpProcessAttributes,
996 lpThreadAttributes,
997 bInheritHandles,
998 dwCreationFlags,
999 lpEnvironment,
1000 lpCurrentDirectory,
1001 &StartupInfo,
1002 lpProcessInformation);
1003 }
1004 #endif
1005 /* It's a batch file */
1006 Extension = &ApplicationName.Buffer[ApplicationName.Length /
1007 sizeof(WCHAR) - 4];
1008
1009 /* Make sure the extensions are correct */
1010 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
1011 {
1012 SetLastError(ERROR_BAD_EXE_FORMAT);
1013 return FALSE;
1014 }
1015
1016 /* Calculate the length of the command line */
1017 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
1018
1019 /* If we found quotes, then add them into the length size */
1020 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
1021 CmdLineLength *= sizeof(WCHAR);
1022
1023 /* Allocate space for the new command line */
1024 BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
1025 0,
1026 CmdLineLength);
1027 if (BatchCommandLine == NULL)
1028 {
1029 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1030 goto Cleanup;
1031 }
1032
1033 /* Build it */
1034 wcscpy(BatchCommandLine, CMD_STRING);
1035 if (CmdLineIsAppName || FoundQuotes)
1036 {
1037 wcscat(BatchCommandLine, L"\"");
1038 }
1039 wcscat(BatchCommandLine, lpCommandLine);
1040 if (CmdLineIsAppName || FoundQuotes)
1041 {
1042 wcscat(BatchCommandLine, L"\"");
1043 }
1044
1045 /* Create it as a Unicode String */
1046 RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
1047
1048 /* Set the command line to this */
1049 lpCommandLine = CommandLineString.Buffer;
1050 lpApplicationName = NULL;
1051
1052 /* Free memory */
1053 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
1054 ApplicationName.Buffer = NULL;
1055 goto GetAppName;
1056 break;
1057
1058 case STATUS_INVALID_IMAGE_WIN_16:
1059
1060 /* It's a Win16 Image, use VDM */
1061 DPRINT1("Launching VDM...\n");
1062 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
1063 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
1064 return CreateProcessW(L"ntvdm.exe",
1065 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
1066 lpProcessAttributes,
1067 lpThreadAttributes,
1068 bInheritHandles,
1069 dwCreationFlags,
1070 lpEnvironment,
1071 lpCurrentDirectory,
1072 &StartupInfo,
1073 lpProcessInformation);
1074
1075 case STATUS_OBJECT_NAME_NOT_FOUND:
1076 case STATUS_OBJECT_PATH_NOT_FOUND:
1077 SetLastErrorByStatus(Status);
1078 goto Cleanup;
1079
1080 default:
1081 /* Invalid Image Type */
1082 SetLastError(ERROR_BAD_EXE_FORMAT);
1083 goto Cleanup;
1084 }
1085 }
1086
1087 /* Use our desktop if we didn't get any */
1088 if (!StartupInfo.lpDesktop)
1089 {
1090 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
1091 }
1092
1093 /* FIXME: Check if Application is allowed to run */
1094
1095 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
1096
1097 /* Get some information about the executable */
1098 Status = ZwQuerySection(hSection,
1099 SectionImageInformation,
1100 &SectionImageInfo,
1101 sizeof(SectionImageInfo),
1102 NULL);
1103 if(!NT_SUCCESS(Status))
1104 {
1105 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
1106 SetLastErrorByStatus(Status);
1107 goto Cleanup;
1108 }
1109
1110 /* Don't execute DLLs */
1111 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
1112 {
1113 DPRINT1("Can't execute a DLL\n");
1114 SetLastError(ERROR_BAD_EXE_FORMAT);
1115 goto Cleanup;
1116 }
1117
1118 /* FIXME: Check for Debugger */
1119
1120 /* FIXME: Check if Machine Type and SubSys Version Match */
1121
1122 /* We don't support POSIX or anything else for now */
1123 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType &&
1124 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType)
1125 {
1126 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType);
1127 SetLastError(ERROR_BAD_EXE_FORMAT);
1128 goto Cleanup;
1129 }
1130
1131 if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType)
1132 {
1133 /* Do not create a console for GUI applications */
1134 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1135 dwCreationFlags |= DETACHED_PROCESS;
1136 }
1137
1138 /* Initialize the process object attributes */
1139 ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
1140 lpProcessAttributes,
1141 NULL);
1142
1143 /* Check if we're going to be debugged */
1144 if (dwCreationFlags & DEBUG_PROCESS)
1145 {
1146 /* FIXME: Set process flag */
1147 }
1148
1149 /* Check if we're going to be debugged */
1150 if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
1151 {
1152 /* Connect to DbgUi */
1153 Status = DbgUiConnectToDbg();
1154 if (!NT_SUCCESS(Status))
1155 {
1156 DPRINT1("Failed to connect to DbgUI!\n");
1157 SetLastErrorByStatus(Status);
1158 goto Cleanup;
1159 }
1160
1161 /* Get the debug object */
1162 hDebug = DbgUiGetThreadDebugObject();
1163
1164 /* Check if only this process will be debugged */
1165 if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1166 {
1167 /* FIXME: Set process flag */
1168 }
1169 }
1170
1171 /* Create the Process */
1172 Status = NtCreateProcess(&hProcess,
1173 PROCESS_ALL_ACCESS,
1174 ObjectAttributes,
1175 NtCurrentProcess(),
1176 (BOOLEAN)bInheritHandles,
1177 hSection,
1178 hDebug,
1179 NULL);
1180 if(!NT_SUCCESS(Status))
1181 {
1182 DPRINT1("Unable to create process, status 0x%x\n", Status);
1183 SetLastErrorByStatus(Status);
1184 goto Cleanup;
1185 }
1186
1187 if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID)
1188 {
1189 /* Set new class */
1190 Status = NtSetInformationProcess(hProcess,
1191 ProcessPriorityClass,
1192 &PriorityClass,
1193 sizeof(PROCESS_PRIORITY_CLASS));
1194 if(!NT_SUCCESS(Status))
1195 {
1196 DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
1197 SetLastErrorByStatus(Status);
1198 goto Cleanup;
1199 }
1200 }
1201
1202 /* Set Error Mode */
1203 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
1204 {
1205 ULONG ErrorMode = SEM_FAILCRITICALERRORS;
1206 NtSetInformationProcess(hProcess,
1207 ProcessDefaultHardErrorMode,
1208 &ErrorMode,
1209 sizeof(ULONG));
1210 }
1211
1212 /* Convert the directory to a full path */
1213 if (lpCurrentDirectory)
1214 {
1215 /* Allocate a buffer */
1216 CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
1217 0,
1218 (MAX_PATH + 1) * sizeof(WCHAR));
1219 if (CurrentDirectory == NULL)
1220 {
1221 DPRINT1("Cannot allocate memory for directory name\n");
1222 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1223 goto Cleanup;
1224 }
1225
1226 /* Get the length */
1227 if (GetFullPathNameW(lpCurrentDirectory,
1228 MAX_PATH,
1229 CurrentDirectory,
1230 &CurrentDirectoryPart) > MAX_PATH)
1231 {
1232 DPRINT1("Directory name too long\n");
1233 SetLastError(ERROR_DIRECTORY);
1234 goto Cleanup;
1235 }
1236 }
1237
1238 /* Insert quotes if needed */
1239 if (QuotesNeeded || CmdLineIsAppName)
1240 {
1241 /* Allocate a buffer */
1242 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
1243 0,
1244 (wcslen(lpCommandLine) + 2 + 1) *
1245 sizeof(WCHAR));
1246 if (QuotedCmdLine == NULL)
1247 {
1248 DPRINT1("Cannot allocate memory for quoted command line\n");
1249 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1250 goto Cleanup;
1251 }
1252
1253 /* Copy the first quote */
1254 wcscpy(QuotedCmdLine, L"\"");
1255
1256 /* Save a null char */
1257 if (QuotesNeeded)
1258 {
1259 SaveChar = *NullBuffer;
1260 *NullBuffer = UNICODE_NULL;
1261 }
1262
1263 /* Add the command line and the finishing quote */
1264 wcscat(QuotedCmdLine, lpCommandLine);
1265 wcscat(QuotedCmdLine, L"\"");
1266
1267 /* Add the null char */
1268 if (QuotesNeeded)
1269 {
1270 *NullBuffer = SaveChar;
1271 wcscat(QuotedCmdLine, NullBuffer);
1272 }
1273
1274 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
1275 }
1276
1277 if (Escape)
1278 {
1279 if (QuotedCmdLine == NULL)
1280 {
1281 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
1282 0,
1283 (wcslen(lpCommandLine) + 1) * sizeof(WCHAR));
1284 if (QuotedCmdLine == NULL)
1285 {
1286 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1287 goto Cleanup;
1288 }
1289 wcscpy(QuotedCmdLine, lpCommandLine);
1290 }
1291
1292 ScanString = QuotedCmdLine;
1293 while (NULL != (ScanString = wcschr(ScanString, L'^')))
1294 {
1295 ScanString++;
1296 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
1297 {
1298 memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR));
1299 }
1300 }
1301 }
1302
1303 /* Get the Process Information */
1304 Status = NtQueryInformationProcess(hProcess,
1305 ProcessBasicInformation,
1306 &ProcessBasicInfo,
1307 sizeof(ProcessBasicInfo),
1308 NULL);
1309
1310 /* Convert the environment */
1311 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
1312 {
1313 lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
1314 if (!lpEnvironment) goto Cleanup;
1315 }
1316
1317 /* Create Process Environment */
1318 RemotePeb = ProcessBasicInfo.PebBaseAddress;
1319 Status = BasepInitializeEnvironment(hProcess,
1320 RemotePeb,
1321 (LPWSTR)lpApplicationName,
1322 CurrentDirectory,
1323 (QuotesNeeded || CmdLineIsAppName || Escape) ?
1324 QuotedCmdLine : lpCommandLine,
1325 lpEnvironment,
1326 EnvSize,
1327 &StartupInfo,
1328 dwCreationFlags,
1329 bInheritHandles);
1330
1331 /* Cleanup Environment */
1332 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
1333 {
1334 RtlDestroyEnvironment(lpEnvironment);
1335 }
1336
1337 if (!NT_SUCCESS(Status))
1338 {
1339 DPRINT1("Could not initialize Process Environment\n");
1340 SetLastErrorByStatus(Status);
1341 goto Cleanup;
1342 }
1343
1344 /* Close the section */
1345 NtClose(hSection);
1346 hSection = NULL;
1347
1348 /* Duplicate the handles if needed */
1349 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
1350 SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1351 {
1352 PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
1353
1354 /* Get the remote parameters */
1355 Status = NtReadVirtualMemory(hProcess,
1356 &RemotePeb->ProcessParameters,
1357 &RemoteParameters,
1358 sizeof(PVOID),
1359 NULL);
1360 if (!NT_SUCCESS(Status))
1361 {
1362 DPRINT1("Failed to read memory\n");
1363 goto Cleanup;
1364 }
1365
1366 /* Duplicate and write the handles */
1367 BasepDuplicateAndWriteHandle(hProcess,
1368 OurPeb->ProcessParameters->StandardInput,
1369 &RemoteParameters->StandardInput);
1370 BasepDuplicateAndWriteHandle(hProcess,
1371 OurPeb->ProcessParameters->StandardOutput,
1372 &RemoteParameters->StandardOutput);
1373 BasepDuplicateAndWriteHandle(hProcess,
1374 OurPeb->ProcessParameters->StandardError,
1375 &RemoteParameters->StandardError);
1376 }
1377
1378 /* Create the first thread */
1379 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
1380 SectionImageInfo.TransferAddress);
1381 hThread = BasepCreateFirstThread(hProcess,
1382 lpThreadAttributes,
1383 &SectionImageInfo,
1384 &ClientId);
1385
1386 if (hThread == NULL)
1387 {
1388 DPRINT1("Could not create Initial Thread\n");
1389 /* FIXME - set last error code */
1390 goto Cleanup;
1391 }
1392
1393 /* Notify CSRSS */
1394 Status = BasepNotifyCsrOfCreation(dwCreationFlags,
1395 (HANDLE)ProcessBasicInfo.UniqueProcessId,
1396 bInheritHandles);
1397
1398 if (!NT_SUCCESS(Status))
1399 {
1400 DPRINT1("CSR Notification Failed");
1401 SetLastErrorByStatus(Status);
1402 goto Cleanup;
1403 }
1404
1405 if (!(dwCreationFlags & CREATE_SUSPENDED))
1406 {
1407 NtResumeThread(hThread, &Dummy);
1408 }
1409
1410 /* Return Data */
1411 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
1412 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
1413 lpProcessInformation->hProcess = hProcess;
1414 lpProcessInformation->hThread = hThread;
1415 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread,
1416 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
1417 hProcess = hThread = NULL;
1418 Ret = TRUE;
1419
1420 Cleanup:
1421 /* De-allocate heap strings */
1422 if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
1423 if (ApplicationName.Buffer)
1424 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
1425 if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
1426 if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
1427
1428 /* Kill any handles still alive */
1429 if (hSection) NtClose(hSection);
1430 if (hThread)
1431 {
1432 /* We don't know any more details then this */
1433 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
1434 NtClose(hThread);
1435 }
1436 if (hProcess) NtClose(hProcess);
1437
1438 /* Return Success */
1439 return Ret;
1440 }
1441
1442 /*
1443 * @implemented
1444 */
1445 BOOL
1446 WINAPI
1447 CreateProcessW(LPCWSTR lpApplicationName,
1448 LPWSTR lpCommandLine,
1449 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1450 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1451 BOOL bInheritHandles,
1452 DWORD dwCreationFlags,
1453 LPVOID lpEnvironment,
1454 LPCWSTR lpCurrentDirectory,
1455 LPSTARTUPINFOW lpStartupInfo,
1456 LPPROCESS_INFORMATION lpProcessInformation)
1457 {
1458 /* Call the internal (but exported) version */
1459 return CreateProcessInternalW(0,
1460 lpApplicationName,
1461 lpCommandLine,
1462 lpProcessAttributes,
1463 lpThreadAttributes,
1464 bInheritHandles,
1465 dwCreationFlags,
1466 lpEnvironment,
1467 lpCurrentDirectory,
1468 lpStartupInfo,
1469 lpProcessInformation,
1470 NULL);
1471 }
1472
1473 /*
1474 * @implemented
1475 */
1476 BOOL
1477 WINAPI
1478 CreateProcessInternalA(HANDLE hToken,
1479 LPCSTR lpApplicationName,
1480 LPSTR lpCommandLine,
1481 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1482 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1483 BOOL bInheritHandles,
1484 DWORD dwCreationFlags,
1485 LPVOID lpEnvironment,
1486 LPCSTR lpCurrentDirectory,
1487 LPSTARTUPINFOA lpStartupInfo,
1488 LPPROCESS_INFORMATION lpProcessInformation,
1489 PHANDLE hNewToken)
1490 {
1491 PUNICODE_STRING CommandLine = NULL;
1492 UNICODE_STRING DummyString;
1493 UNICODE_STRING LiveCommandLine;
1494 UNICODE_STRING ApplicationName;
1495 UNICODE_STRING CurrentDirectory;
1496 BOOL bRetVal;
1497 STARTUPINFOW StartupInfo;
1498
1499 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
1500 "lpStartupInfo %x, lpProcessInformation %x\n",
1501 dwCreationFlags, lpEnvironment, lpCurrentDirectory,
1502 lpStartupInfo, lpProcessInformation);
1503
1504 /* Copy Startup Info */
1505 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
1506
1507 /* Initialize all strings to nothing */
1508 LiveCommandLine.Buffer = NULL;
1509 DummyString.Buffer = NULL;
1510 ApplicationName.Buffer = NULL;
1511 CurrentDirectory.Buffer = NULL;
1512 StartupInfo.lpDesktop = NULL;
1513 StartupInfo.lpReserved = NULL;
1514 StartupInfo.lpTitle = NULL;
1515
1516 /* Convert the Command line */
1517 if (lpCommandLine)
1518 {
1519 /* If it's too long, then we'll have a problem */
1520 if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
1521 NtCurrentTeb()->StaticUnicodeString.MaximumLength)
1522 {
1523 /* Cache it in the TEB */
1524 CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
1525 }
1526 else
1527 {
1528 /* Use a dynamic version */
1529 Basep8BitStringToHeapUnicodeString(&LiveCommandLine,
1530 lpCommandLine);
1531 }
1532 }
1533 else
1534 {
1535 /* The logic below will use CommandLine, so we must make it valid */
1536 CommandLine = &DummyString;
1537 }
1538
1539 /* Convert the Name and Directory */
1540 if (lpApplicationName)
1541 {
1542 Basep8BitStringToHeapUnicodeString(&ApplicationName,
1543 lpApplicationName);
1544 }
1545 if (lpCurrentDirectory)
1546 {
1547 Basep8BitStringToHeapUnicodeString(&CurrentDirectory,
1548 lpCurrentDirectory);
1549 }
1550
1551 /* Now convert Startup Strings */
1552 if (lpStartupInfo->lpReserved)
1553 {
1554 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
1555 &StartupInfo.lpReserved);
1556 }
1557 if (lpStartupInfo->lpDesktop)
1558 {
1559 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
1560 &StartupInfo.lpDesktop);
1561 }
1562 if (lpStartupInfo->lpTitle)
1563 {
1564 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
1565 &StartupInfo.lpTitle);
1566 }
1567
1568 /* Call the Unicode function */
1569 bRetVal = CreateProcessInternalW(hToken,
1570 ApplicationName.Buffer,
1571 LiveCommandLine.Buffer ?
1572 LiveCommandLine.Buffer : CommandLine->Buffer,
1573 lpProcessAttributes,
1574 lpThreadAttributes,
1575 bInheritHandles,
1576 dwCreationFlags,
1577 lpEnvironment,
1578 CurrentDirectory.Buffer,
1579 &StartupInfo,
1580 lpProcessInformation,
1581 hNewToken);
1582
1583 /* Clean up */
1584 RtlFreeUnicodeString(&ApplicationName);
1585 RtlFreeUnicodeString(&LiveCommandLine);
1586 RtlFreeUnicodeString(&CurrentDirectory);
1587 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop);
1588 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved);
1589 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle);
1590
1591 /* Return what Unicode did */
1592 return bRetVal;
1593 }
1594
1595 /*
1596 * FUNCTION: The CreateProcess function creates a new process and its
1597 * primary thread. The new process executes the specified executable file
1598 * ARGUMENTS:
1599 *
1600 * lpApplicationName = Pointer to name of executable module
1601 * lpCommandLine = Pointer to command line string
1602 * lpProcessAttributes = Process security attributes
1603 * lpThreadAttributes = Thread security attributes
1604 * bInheritHandles = Handle inheritance flag
1605 * dwCreationFlags = Creation flags
1606 * lpEnvironment = Pointer to new environment block
1607 * lpCurrentDirectory = Pointer to current directory name
1608 * lpStartupInfo = Pointer to startup info
1609 * lpProcessInformation = Pointer to process information
1610 *
1611 * @implemented
1612 */
1613 BOOL
1614 WINAPI
1615 CreateProcessA(LPCSTR lpApplicationName,
1616 LPSTR lpCommandLine,
1617 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1618 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1619 BOOL bInheritHandles,
1620 DWORD dwCreationFlags,
1621 LPVOID lpEnvironment,
1622 LPCSTR lpCurrentDirectory,
1623 LPSTARTUPINFOA lpStartupInfo,
1624 LPPROCESS_INFORMATION lpProcessInformation)
1625 {
1626 /* Call the internal (but exported) version */
1627 return CreateProcessInternalA(0,
1628 lpApplicationName,
1629 lpCommandLine,
1630 lpProcessAttributes,
1631 lpThreadAttributes,
1632 bInheritHandles,
1633 dwCreationFlags,
1634 lpEnvironment,
1635 lpCurrentDirectory,
1636 lpStartupInfo,
1637 lpProcessInformation,
1638 NULL);
1639 }
1640
1641 /* EOF */