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