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)
10 /* INCLUDES ****************************************************************/
17 #define CMD_STRING L"cmd /c "
19 extern __declspec(noreturn
)
22 ConsoleControlDispatcher(DWORD CodeAndFlag
);
24 /* INTERNAL FUNCTIONS *******************************************************/
27 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
29 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
31 if (GlobalTopLevelExceptionFilter
!= NULL
)
35 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
37 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
42 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
43 GlobalTopLevelExceptionFilter
!= UnhandledExceptionFilter
)
45 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
48 return ExceptionDisposition
;
53 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
57 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
61 /* Set our Start Address */
62 NtSetInformationThread(NtCurrentThread(),
63 ThreadQuerySetWin32StartAddress
,
65 sizeof(PPROCESS_START_ROUTINE
));
67 /* Call the Start Routine */
68 uExitCode
= (lpStartAddress
)();
70 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
72 /* Get the SEH Error */
73 uExitCode
= _SEH2_GetExceptionCode();
77 /* Exit the Process with our error */
78 ExitProcess(uExitCode
);
82 * Tells CSR that a new process was created
86 BasepNotifyCsrOfCreation(ULONG dwCreationFlags
,
88 IN BOOL InheritHandles
)
90 ULONG Request
= CREATE_PROCESS
;
91 CSR_API_MESSAGE CsrRequest
;
94 DPRINT("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
95 ProcessId
, dwCreationFlags
);
97 /* Fill out the request */
98 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
= ProcessId
;
99 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
100 CsrRequest
.Data
.CreateProcessRequest
.bInheritHandles
= InheritHandles
;
103 Status
= CsrClientCallServer(&CsrRequest
,
105 MAKE_CSR_API(Request
, CSR_NATIVE
),
106 sizeof(CSR_API_MESSAGE
));
107 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
109 DPRINT1("Failed to tell csrss about new process\n");
110 return CsrRequest
.Status
;
114 return STATUS_SUCCESS
;
119 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
120 IN PCLIENT_ID ClientId
)
122 ULONG Request
= CREATE_THREAD
;
123 CSR_API_MESSAGE CsrRequest
;
126 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
127 ClientId
->UniqueThread
, ThreadHandle
);
129 /* Fill out the request */
130 CsrRequest
.Data
.CreateThreadRequest
.ClientId
= *ClientId
;
131 CsrRequest
.Data
.CreateThreadRequest
.ThreadHandle
= ThreadHandle
;
134 Status
= CsrClientCallServer(&CsrRequest
,
136 MAKE_CSR_API(Request
, CSR_NATIVE
),
137 sizeof(CSR_API_MESSAGE
));
138 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
140 DPRINT1("Failed to tell csrss about new thread\n");
141 return CsrRequest
.Status
;
145 return STATUS_SUCCESS
;
149 * Creates the first Thread in a Proces
153 BasepCreateFirstThread(HANDLE ProcessHandle
,
154 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
155 PSECTION_IMAGE_INFORMATION SectionImageInfo
,
158 OBJECT_ATTRIBUTES LocalObjectAttributes
;
159 POBJECT_ATTRIBUTES ObjectAttributes
;
161 INITIAL_TEB InitialTeb
;
165 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
167 /* Create the Thread's Stack */
168 BasepCreateStack(ProcessHandle
,
169 SectionImageInfo
->MaximumStackSize
,
170 SectionImageInfo
->CommittedStackSize
,
173 /* Create the Thread's Context */
174 BasepInitializeContext(&Context
,
176 SectionImageInfo
->TransferAddress
,
177 InitialTeb
.StackBase
,
180 /* Convert the thread attributes */
181 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
185 /* Create the Kernel Thread Object */
186 Status
= NtCreateThread(&hThread
,
194 if (!NT_SUCCESS(Status
))
199 Status
= BasepNotifyCsrOfThread(hThread
, ClientId
);
200 if (!NT_SUCCESS(Status
))
210 * Converts ANSI to Unicode Environment
214 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
215 IN PVOID lpEnvironment
)
219 UNICODE_STRING UnicodeEnv
;
222 DPRINT("BasepConvertUnicodeEnvironment\n");
224 /* Scan the environment to calculate its Unicode size */
225 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
228 pcScan
+= strlen(pcScan
) + 1;
231 /* Create our ANSI String */
232 if (pcScan
== (PCHAR
)lpEnvironment
)
234 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
239 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
241 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
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
,
253 if (!NT_SUCCESS(Status
))
255 SetLastError(Status
);
260 /* Use the allocated size */
261 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
264 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
265 return UnicodeEnv
.Buffer
;
269 * Converts a Win32 Priority Class to NT
273 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
277 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
279 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
281 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
283 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
285 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
287 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
289 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
291 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
293 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
295 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
297 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
299 /* Check for Privilege First */
300 if (BasepCheckRealTimePrivilege())
302 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
306 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
311 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
318 * Duplicates a standard handle and writes it where requested.
322 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
323 IN HANDLE StandardHandle
,
327 HANDLE DuplicatedHandle
;
330 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
331 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
333 /* Don't touch Console Handles */
334 if (IsConsoleHandle(StandardHandle
)) return;
336 /* Duplicate the handle */
337 Status
= NtDuplicateObject(NtCurrentProcess(),
341 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
344 if (NT_SUCCESS(Status
))
347 NtWriteVirtualMemory(ProcessHandle
,
357 BasepGetDllPath(LPWSTR FullPath
,
360 /* FIXME: Not yet implemented */
366 BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params
,
367 IN PRTL_USER_PROCESS_PARAMETERS PebParams
,
368 IN BOOL InheritHandles
)
370 DPRINT("BasepCopyHandles %p %p, %d\n", Params
, PebParams
, InheritHandles
);
372 /* Copy the handle if we are inheriting or if it's a console handle */
373 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardInput
))
375 Params
->StandardInput
= PebParams
->StandardInput
;
377 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardOutput
))
379 Params
->StandardOutput
= PebParams
->StandardOutput
;
381 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardError
))
383 Params
->StandardError
= PebParams
->StandardError
;
389 BasepInitializeEnvironment(HANDLE ProcessHandle
,
391 LPWSTR ApplicationPathName
,
392 LPWSTR lpCurrentDirectory
,
393 LPWSTR lpCommandLine
,
394 LPVOID lpEnvironment
,
396 LPSTARTUPINFOW StartupInfo
,
400 WCHAR FullPath
[MAX_PATH
];
402 LPWSTR DllPathString
;
403 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
404 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
= NULL
;
405 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
411 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
412 PPEB OurPeb
= NtCurrentPeb();
413 LPVOID Environment
= lpEnvironment
;
415 DPRINT("BasepInitializeEnvironment\n");
417 /* Get the full path name */
418 RetVal
= GetFullPathNameW(ApplicationPathName
,
422 DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName
,
425 /* Get the DLL Path */
426 DllPathString
= BasepGetDllPath(FullPath
, Environment
);
428 /* Initialize Strings */
429 RtlInitUnicodeString(&DllPath
, DllPathString
);
430 RtlInitUnicodeString(&ImageName
, FullPath
);
431 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
432 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
434 /* Initialize more Strings from the Startup Info */
435 if (StartupInfo
->lpDesktop
)
437 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
441 RtlInitUnicodeString(&Desktop
, L
"");
443 if (StartupInfo
->lpReserved
)
445 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
449 RtlInitUnicodeString(&Shell
, L
"");
451 if (StartupInfo
->lpTitle
)
453 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
457 RtlInitUnicodeString(&Title
, L
"");
460 /* This one is special because the length can differ */
461 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
462 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
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
,
468 Status
= RtlCreateProcessParameters(&ProcessParameters
,
472 &CurrentDirectory
: NULL
,
480 if (!NT_SUCCESS(Status
))
482 DPRINT1("Failed to create process parameters!\n");
486 /* Check if we got an environment. If not, use ours */
489 /* Save pointer and start lookup */
490 Environment
= ScanChar
= ProcessParameters
->Environment
;
494 /* Save pointer and start lookup */
495 Environment
= ScanChar
= OurPeb
->ProcessParameters
->Environment
;
498 /* Find the environment size */
501 if (EnvSize
&& Environment
== lpEnvironment
)
503 /* its a converted ansi environment, bypass the length calculation */
504 EnviroSize
= EnvSize
;
510 ScanChar
+= wcslen(ScanChar
) + 1;
513 /* Calculate the size of the block */
514 if (ScanChar
== Environment
)
516 EnviroSize
= 2 * sizeof(WCHAR
);
520 EnviroSize
= (ULONG
)((ULONG_PTR
)ScanChar
- (ULONG_PTR
)Environment
+ sizeof(WCHAR
));
523 DPRINT("EnvironmentSize %ld\n", EnviroSize
);
525 /* Allocate and Initialize new Environment Block */
527 ProcessParameters
->Environment
= NULL
;
528 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
529 (PVOID
*)&ProcessParameters
->Environment
,
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("Failed to allocate Environment Block\n");
540 /* Write the Environment Block */
541 ZwWriteVirtualMemory(ProcessHandle
,
542 ProcessParameters
->Environment
,
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
;
559 /* Write the handles only if we have to */
560 if (StartupInfo
->dwFlags
& STARTF_USESTDHANDLES
)
562 DPRINT("Using Standard Handles\n");
563 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
564 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
565 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
568 /* Use Special Flags for ConDllInitialize in Kernel32 */
569 if (CreationFlags
& DETACHED_PROCESS
)
571 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
573 else if (CreationFlags
& CREATE_NO_WINDOW
)
575 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
577 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
579 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
583 /* Inherit our Console Handle */
584 ProcessParameters
->ConsoleHandle
= OurPeb
->ProcessParameters
->ConsoleHandle
;
586 /* Is the shell trampling on our Handles? */
587 if (!(StartupInfo
->dwFlags
&
588 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
590 /* Use handles from PEB, if inheriting or they are console */
591 DPRINT("Copying handles from parent\n");
592 BasepCopyHandles(ProcessParameters
,
593 OurPeb
->ProcessParameters
,
598 /* Also set the Console Flag */
599 if (CreationFlags
& CREATE_NEW_PROCESS_GROUP
)
601 ProcessParameters
->ConsoleFlags
= 1;
604 /* Allocate memory for the parameter block */
605 Size
= ProcessParameters
->Length
;
606 Status
= NtAllocateVirtualMemory(ProcessHandle
,
607 (PVOID
*)&RemoteParameters
,
612 if (!NT_SUCCESS(Status
))
614 DPRINT1("Failed to allocate Parameters Block\n");
618 /* Set the allocated size */
619 ProcessParameters
->MaximumLength
= Size
;
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
);
632 /* Write the Parameter Block */
633 Status
= NtWriteVirtualMemory(ProcessHandle
,
636 ProcessParameters
->Length
,
639 /* Write the PEB Pointer */
640 Status
= NtWriteVirtualMemory(ProcessHandle
,
641 &Peb
->ProcessParameters
,
647 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
648 RtlDestroyProcessParameters(ProcessParameters
);
650 DPRINT("Completed\n");
651 return STATUS_SUCCESS
;
654 /* FUNCTIONS ****************************************************************/
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
,
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
;
689 LPWSTR BatchCommandLine
;
691 UNICODE_STRING CommandLineString
;
693 LPWSTR QuotedCmdLine
= NULL
;
695 LPWSTR NullBuffer
= NULL
;
696 LPWSTR NameBuffer
= NULL
;
700 BOOLEAN SearchDone
= FALSE
;
701 BOOLEAN Escape
= FALSE
;
703 PPEB OurPeb
= NtCurrentPeb();
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)
713 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
714 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
715 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
718 /* Flags we don't handle yet */
719 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
721 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
723 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
725 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
727 if (dwCreationFlags
& CREATE_FORCEDOS
)
729 DPRINT1("CREATE_FORCEDOS not handled\n");
732 /* Fail on this flag, it's only valid with the WithLogonW function */
733 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
735 DPRINT1("Invalid flag used\n");
736 SetLastError(ERROR_INVALID_PARAMETER
);
740 /* This combination is illegal (see MSDN) */
741 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
742 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
744 DPRINT1("Invalid flag combo used\n");
745 SetLastError(ERROR_INVALID_PARAMETER
);
749 /* Another illegal combo */
750 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
751 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
753 DPRINT1("Invalid flag combo used\n");
754 SetLastError(ERROR_INVALID_PARAMETER
);
758 if (lpCurrentDirectory
)
760 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
761 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
763 SetLastError(ERROR_DIRECTORY
);
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.
772 StartupInfo
= *lpStartupInfo
;
774 /* FIXME: Use default Separate/Shared VDM Flag */
776 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
777 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
779 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
781 /* Remove the shared flag and add the separate flag. */
782 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
783 CREATE_SEPARATE_WOW_VDM
;
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
793 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
794 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
796 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
799 /* Start by zeroing out the fields */
800 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
802 /* Easy stuff first, convert the process priority class */
803 PriorityClass
.Foreground
= FALSE
;
804 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
808 /* Search for escape sequences */
809 ScanString
= lpCommandLine
;
810 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
813 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\"')
821 /* Get the application name and do all the proper formating necessary */
823 /* See if we have an application name (oh please let us have one!) */
824 if (!lpApplicationName
)
827 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
829 MAX_PATH
* sizeof(WCHAR
));
830 if (NameBuffer
== NULL
)
832 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
836 /* This is all we have to work with :( */
837 lpApplicationName
= lpCommandLine
;
839 /* Initialize our friends at the beginning */
840 NullBuffer
= (LPWSTR
)lpApplicationName
;
841 ScanString
= (LPWSTR
)lpApplicationName
;
843 /* We will start by looking for a quote */
844 if (*ScanString
== L
'\"')
849 /* Advance past quote */
851 lpApplicationName
= ScanString
;
853 /* Find the closing quote */
856 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
859 NullBuffer
= ScanString
;
866 NullBuffer
= ScanString
;
871 /* No quotes, so we'll be looking for white space */
873 /* Reset the pointer */
874 lpApplicationName
= lpCommandLine
;
876 /* Find whitespace of Tab */
879 if (*ScanString
== ' ' || *ScanString
== '\t')
882 NullBuffer
= ScanString
;
888 NullBuffer
= ScanString
;
892 /* Set the Null Buffer */
893 SaveChar
= *NullBuffer
;
894 *NullBuffer
= UNICODE_NULL
;
896 /* Do a search for the file */
897 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
898 RetVal
= SearchPathW(NULL
,
903 NULL
) * sizeof(WCHAR
);
905 /* Did it find something? */
908 /* Get file attributes */
909 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
910 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
912 /* Give it a length of 0 to fail, this was a directory. */
918 RetVal
+= sizeof(WCHAR
);
922 /* Now check if we have a file, and if the path size is OK */
923 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
928 /* We failed, try to get the Path Type */
929 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
930 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
932 /* If it's not relative, try to get the error */
933 if (PathType
!= RtlPathTypeRelative
)
935 /* This should fail, and give us a detailed LastError */
936 hFile
= CreateFileW(lpApplicationName
,
938 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
941 FILE_ATTRIBUTE_NORMAL
,
944 /* Did it actually NOT fail? */
945 if (hFile
!= INVALID_HANDLE_VALUE
)
949 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND
);
954 /* Immediately set the error */
955 SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND
);
958 /* Did we already fail once? */
965 /* Not yet, cache it */
966 Error
= GetLastError();
969 /* Put back the command line */
970 *NullBuffer
= SaveChar
;
971 lpApplicationName
= NameBuffer
;
974 * If the search isn't done and we still have cmdline
975 * then start over. Ex: c:\ha ha ha\haha.exe
977 if (*ScanString
&& !SearchDone
)
979 /* Move in the buffer */
981 NullBuffer
= ScanString
;
983 /* We will have to add a quote, since there is a space*/
986 /* And we will also fake the fact we found one */
993 /* We totally failed */
997 /* Put back the command line */
998 *NullBuffer
= SaveChar
;
999 lpApplicationName
= NameBuffer
;
1000 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
1002 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
1004 /* We have an app name (good!) but no command line */
1005 CmdLineIsAppName
= TRUE
;
1006 lpCommandLine
= (LPWSTR
)lpApplicationName
;
1009 /* At this point the name has been toyed with enough to be openable */
1010 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
1012 /* Check for failure */
1013 if (!NT_SUCCESS(Status
))
1015 /* Could be a non-PE File */
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
:
1024 /* If it's a DOS app, use VDM */
1025 if ((BasepCheckDosApp(&ApplicationName
)))
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
,
1039 lpProcessInformation
);
1042 /* It's a batch file */
1043 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
1046 /* Make sure the extensions are correct */
1047 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
1049 SetLastError(ERROR_BAD_EXE_FORMAT
);
1053 /* Calculate the length of the command line */
1054 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
1056 /* If we found quotes, then add them into the length size */
1057 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
1058 CmdLineLength
*= sizeof(WCHAR
);
1060 /* Allocate space for the new command line */
1061 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
1064 if (BatchCommandLine
== NULL
)
1066 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1071 wcscpy(BatchCommandLine
, CMD_STRING
);
1072 if (CmdLineIsAppName
|| FoundQuotes
)
1074 wcscat(BatchCommandLine
, L
"\"");
1076 wcscat(BatchCommandLine
, lpCommandLine
);
1077 if (CmdLineIsAppName
|| FoundQuotes
)
1079 wcscat(BatchCommandLine
, L
"\"");
1082 /* Create it as a Unicode String */
1083 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
1085 /* Set the command line to this */
1086 lpCommandLine
= CommandLineString
.Buffer
;
1087 lpApplicationName
= NULL
;
1090 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
1091 ApplicationName
.Buffer
= NULL
;
1095 case STATUS_INVALID_IMAGE_WIN_16
:
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
,
1110 lpProcessInformation
);
1112 case STATUS_OBJECT_NAME_NOT_FOUND
:
1113 case STATUS_OBJECT_PATH_NOT_FOUND
:
1114 SetLastErrorByStatus(Status
);
1118 /* Invalid Image Type */
1119 SetLastError(ERROR_BAD_EXE_FORMAT
);
1124 /* Use our desktop if we didn't get any */
1125 if (!StartupInfo
.lpDesktop
)
1127 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
1130 /* FIXME: Check if Application is allowed to run */
1132 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
1134 /* Get some information about the executable */
1135 Status
= ZwQuerySection(hSection
,
1136 SectionImageInformation
,
1138 sizeof(SectionImageInfo
),
1140 if(!NT_SUCCESS(Status
))
1142 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
1143 SetLastErrorByStatus(Status
);
1147 /* Don't execute DLLs */
1148 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
1150 DPRINT1("Can't execute a DLL\n");
1151 SetLastError(ERROR_BAD_EXE_FORMAT
);
1155 /* FIXME: Check for Debugger */
1157 /* FIXME: Check if Machine Type and SubSys Version Match */
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
)
1163 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
1164 SetLastError(ERROR_BAD_EXE_FORMAT
);
1168 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
1170 /* Do not create a console for GUI applications */
1171 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
1172 dwCreationFlags
|= DETACHED_PROCESS
;
1175 /* Initialize the process object attributes */
1176 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
1177 lpProcessAttributes
,
1180 /* Check if we're going to be debugged */
1181 if (dwCreationFlags
& DEBUG_PROCESS
)
1183 /* FIXME: Set process flag */
1186 /* Check if we're going to be debugged */
1187 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
1189 /* Connect to DbgUi */
1190 Status
= DbgUiConnectToDbg();
1191 if (!NT_SUCCESS(Status
))
1193 DPRINT1("Failed to connect to DbgUI!\n");
1194 SetLastErrorByStatus(Status
);
1198 /* Get the debug object */
1199 hDebug
= DbgUiGetThreadDebugObject();
1201 /* Check if only this process will be debugged */
1202 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
1204 /* FIXME: Set process flag */
1208 /* Create the Process */
1209 Status
= NtCreateProcess(&hProcess
,
1213 (BOOLEAN
)bInheritHandles
,
1217 if (!NT_SUCCESS(Status
))
1219 DPRINT1("Unable to create process, status 0x%x\n", Status
);
1220 SetLastErrorByStatus(Status
);
1224 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
1227 Status
= NtSetInformationProcess(hProcess
,
1228 ProcessPriorityClass
,
1230 sizeof(PROCESS_PRIORITY_CLASS
));
1231 if(!NT_SUCCESS(Status
))
1233 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
1234 SetLastErrorByStatus(Status
);
1239 /* Set Error Mode */
1240 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
1242 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
1243 NtSetInformationProcess(hProcess
,
1244 ProcessDefaultHardErrorMode
,
1249 /* Convert the directory to a full path */
1250 if (lpCurrentDirectory
)
1252 /* Allocate a buffer */
1253 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
1255 (MAX_PATH
+ 1) * sizeof(WCHAR
));
1256 if (CurrentDirectory
== NULL
)
1258 DPRINT1("Cannot allocate memory for directory name\n");
1259 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1263 /* Get the length */
1264 if (GetFullPathNameW(lpCurrentDirectory
,
1267 &CurrentDirectoryPart
) > MAX_PATH
)
1269 DPRINT1("Directory name too long\n");
1270 SetLastError(ERROR_DIRECTORY
);
1275 /* Insert quotes if needed */
1276 if (QuotesNeeded
|| CmdLineIsAppName
)
1278 /* Allocate a buffer */
1279 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
1281 (wcslen(lpCommandLine
) + 2 + 1) *
1283 if (QuotedCmdLine
== NULL
)
1285 DPRINT1("Cannot allocate memory for quoted command line\n");
1286 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1290 /* Copy the first quote */
1291 wcscpy(QuotedCmdLine
, L
"\"");
1293 /* Save a null char */
1296 SaveChar
= *NullBuffer
;
1297 *NullBuffer
= UNICODE_NULL
;
1300 /* Add the command line and the finishing quote */
1301 wcscat(QuotedCmdLine
, lpCommandLine
);
1302 wcscat(QuotedCmdLine
, L
"\"");
1304 /* Add the null char */
1307 *NullBuffer
= SaveChar
;
1308 wcscat(QuotedCmdLine
, NullBuffer
);
1311 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
1316 if (QuotedCmdLine
== NULL
)
1318 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
1320 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
1321 if (QuotedCmdLine
== NULL
)
1323 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1326 wcscpy(QuotedCmdLine
, lpCommandLine
);
1329 ScanString
= QuotedCmdLine
;
1330 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
1333 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
1335 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
1340 /* Get the Process Information */
1341 Status
= NtQueryInformationProcess(hProcess
,
1342 ProcessBasicInformation
,
1344 sizeof(ProcessBasicInfo
),
1347 /* Convert the environment */
1348 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
1350 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
1351 if (!lpEnvironment
) goto Cleanup
;
1354 /* Create Process Environment */
1355 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
1356 Status
= BasepInitializeEnvironment(hProcess
,
1358 (LPWSTR
)lpApplicationName
,
1360 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
1361 QuotedCmdLine
: lpCommandLine
,
1368 /* Cleanup Environment */
1369 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
1371 RtlDestroyEnvironment(lpEnvironment
);
1374 if (!NT_SUCCESS(Status
))
1376 DPRINT1("Could not initialize Process Environment\n");
1377 SetLastErrorByStatus(Status
);
1381 /* Close the section */
1385 /* Duplicate the handles if needed */
1386 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
1387 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
1389 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
1391 /* Get the remote parameters */
1392 Status
= NtReadVirtualMemory(hProcess
,
1393 &RemotePeb
->ProcessParameters
,
1397 if (!NT_SUCCESS(Status
))
1399 DPRINT1("Failed to read memory\n");
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
);
1416 Status
= BasepNotifyCsrOfCreation(dwCreationFlags
,
1417 (HANDLE
)ProcessBasicInfo
.UniqueProcessId
,
1420 if (!NT_SUCCESS(Status
))
1422 DPRINT1("CSR Notification Failed");
1423 SetLastErrorByStatus(Status
);
1427 /* Create the first thread */
1428 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
1429 SectionImageInfo
.TransferAddress
);
1430 hThread
= BasepCreateFirstThread(hProcess
,
1435 if (hThread
== NULL
)
1437 DPRINT1("Could not create Initial Thread\n");
1438 /* FIXME - set last error code */
1442 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
1444 NtResumeThread(hThread
, &Dummy
);
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
;
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
);
1465 /* Kill any handles still alive */
1466 if (hSection
) NtClose(hSection
);
1469 /* We don't know any more details then this */
1470 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
1473 if (hProcess
) NtClose(hProcess
);
1475 /* Return Success */
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
)
1495 /* Call the internal (but exported) version */
1496 return CreateProcessInternalW(0,
1499 lpProcessAttributes
,
1506 lpProcessInformation
,
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
,
1528 PUNICODE_STRING CommandLine
= NULL
;
1529 UNICODE_STRING DummyString
;
1530 UNICODE_STRING LiveCommandLine
;
1531 UNICODE_STRING ApplicationName
;
1532 UNICODE_STRING CurrentDirectory
;
1534 STARTUPINFOW StartupInfo
;
1536 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
1537 "lpStartupInfo %x, lpProcessInformation %x\n",
1538 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
1539 lpStartupInfo
, lpProcessInformation
);
1541 /* Copy Startup Info */
1542 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
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
;
1553 /* Convert the Command line */
1556 /* If it's too long, then we'll have a problem */
1557 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
1558 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
1560 /* Cache it in the TEB */
1561 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
1565 /* Use a dynamic version */
1566 Basep8BitStringToHeapUnicodeString(&LiveCommandLine
,
1572 /* The logic below will use CommandLine, so we must make it valid */
1573 CommandLine
= &DummyString
;
1576 /* Convert the Name and Directory */
1577 if (lpApplicationName
)
1579 Basep8BitStringToHeapUnicodeString(&ApplicationName
,
1582 if (lpCurrentDirectory
)
1584 Basep8BitStringToHeapUnicodeString(&CurrentDirectory
,
1585 lpCurrentDirectory
);
1588 /* Now convert Startup Strings */
1589 if (lpStartupInfo
->lpReserved
)
1591 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
1592 &StartupInfo
.lpReserved
);
1594 if (lpStartupInfo
->lpDesktop
)
1596 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
1597 &StartupInfo
.lpDesktop
);
1599 if (lpStartupInfo
->lpTitle
)
1601 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
1602 &StartupInfo
.lpTitle
);
1605 /* Call the Unicode function */
1606 bRetVal
= CreateProcessInternalW(hToken
,
1607 ApplicationName
.Buffer
,
1608 LiveCommandLine
.Buffer
?
1609 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
1610 lpProcessAttributes
,
1615 CurrentDirectory
.Buffer
,
1617 lpProcessInformation
,
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
);
1628 /* Return what Unicode did */
1633 * FUNCTION: The CreateProcess function creates a new process and its
1634 * primary thread. The new process executes the specified executable file
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
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
)
1663 /* Call the internal (but exported) version */
1664 return CreateProcessInternalA(0,
1667 lpProcessAttributes
,
1674 lpProcessInformation
,