2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/proc/proc.c
5 * PURPOSE: Process functions
6 * PROGRAMMERS: Ariadne (ariadne@xs4all.nl)
11 /* INCLUDES ****************************************************************/
18 /* GLOBALS *******************************************************************/
20 WaitForInputIdleType UserWaitForInputIdleRoutine
;
21 UNICODE_STRING BaseUnicodeCommandLine
;
22 ANSI_STRING BaseAnsiCommandLine
;
23 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
24 LPSTARTUPINFOA BaseAnsiStartupInfo
= NULL
;
25 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
26 BOOLEAN g_AppCertInitialized
;
27 BOOLEAN g_HaveAppCerts
;
28 LIST_ENTRY BasepAppCertDllsList
;
29 RTL_CRITICAL_SECTION gcsAppCert
;
30 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
31 NTSTATUS g_AppCertStatus
;
32 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
35 BasepConfigureAppCertDlls
,
38 &BasepAppCertDllsList
,
45 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
46 HMODULE gSaferHandle
= (HMODULE
)-1;
49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
51 #define CMD_STRING L"cmd /c "
53 /* FUNCTIONS ****************************************************************/
57 StuffStdHandle(IN HANDLE ProcessHandle
,
58 IN HANDLE StandardHandle
,
62 HANDLE DuplicatedHandle
;
65 /* Is there a handle to duplicate? */
69 Status
= NtDuplicateObject(NtCurrentProcess(),
75 DUPLICATE_SAME_ACCESS
|
76 DUPLICATE_SAME_ATTRIBUTES
);
77 if (NT_SUCCESS(Status
))
80 NtWriteVirtualMemory(ProcessHandle
,
91 BuildSubSysCommandLine(IN LPCWSTR SubsystemName
,
92 IN LPCWSTR ApplicationName
,
93 IN LPCWSTR CommandLine
,
94 OUT PUNICODE_STRING SubsysCommandLine
)
96 UNICODE_STRING CommandLineString
, ApplicationNameString
;
100 /* Convert to unicode strings */
101 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
102 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
104 /* Allocate buffer for the output string */
105 Length
= CommandLineString
.MaximumLength
+ ApplicationNameString
.MaximumLength
+ 32;
106 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
107 RtlInitEmptyUnicodeString(SubsysCommandLine
, Buffer
, Length
);
110 /* Fail, no memory */
111 BaseSetLastNTError(STATUS_NO_MEMORY
);
115 /* Build the final subsystem command line */
116 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
117 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
118 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
119 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
125 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
126 IN ULONG ImageMinorVersion
)
128 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
129 return ((ImageMajorVersion
>= 3) &&
130 ((ImageMajorVersion
!= 3) ||
131 (ImageMinorVersion
>= 10)) &&
132 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
133 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
134 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
139 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
144 /* Get all the MD5 hashes */
145 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
146 if (!NT_SUCCESS(Status
)) return Status
;
148 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
149 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
151 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
153 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
155 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
157 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
159 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
162 /* Actually, fuck it, don't block anything, we're open source */
163 return STATUS_SUCCESS
;
168 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
169 IN PWCHAR ComponentName
,
172 /* Pretty much the only thing this key is used for, is malware */
174 return STATUS_NOT_IMPLEMENTED
;
179 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
182 IN ULONG ValueLength
,
184 IN PVOID EntryContext
)
186 /* Add this to the certification list */
187 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
192 BasepIsProcessAllowed(IN LPWSTR ApplicationName
)
194 NTSTATUS Status
, Status1
;
197 HMODULE TrustLibrary
;
198 PBASEP_APPCERT_ENTRY Entry
;
200 PLIST_ENTRY NextEntry
;
202 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
203 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
205 /* Try to initialize the certification subsystem */
206 while (!g_AppCertInitialized
)
209 Status
= STATUS_SUCCESS
;
212 /* Acquire the lock while initializing and see if we lost a race */
213 RtlEnterCriticalSection(&gcsAppCert
);
214 if (g_AppCertInitialized
) break;
216 /* On embedded, there is a special DLL */
217 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
219 /* Allocate a buffer for the name */
220 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
222 MAX_PATH
* sizeof(WCHAR
) +
223 sizeof(UNICODE_NULL
));
226 /* Fail if no memory */
227 Status
= STATUS_NO_MEMORY
;
231 /* Now get the system32 directory in our buffer, make sure it fits */
232 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
233 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
235 /* Add a slash if needed, and add the embedded cert DLL name */
236 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
237 RtlCopyMemory(&Buffer
[Length
],
239 sizeof(L
"EmbdTrst.DLL"));
242 TrustLibrary
= LoadLibraryW(Buffer
);
245 /* And extract the special function out of it */
246 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
247 "ImageOkToRunOnEmbeddedNT");
251 /* If we didn't get this far, set a failure code */
252 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
257 /* Other systems have a registry entry for this */
258 Status1
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
259 if (NT_SUCCESS(Status1
))
261 /* Close it, we'll query it through Rtl */
264 /* Do the query, which will call a special callback */
265 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
270 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
272 Status
= STATUS_SUCCESS
;
277 /* Free any buffer if we had one */
278 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
280 /* Check for errors, or a missing embedded/custom certification DLL */
281 if (!NT_SUCCESS(Status
) ||
282 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
284 /* The subsystem is not active on this machine, so give up */
285 g_HaveAppCerts
= FALSE
;
286 g_AppCertStatus
= Status
;
290 /* We have certification DLLs active, remember this */
291 g_HaveAppCerts
= TRUE
;
294 /* We are done the initialization phase, release the lock */
295 g_AppCertInitialized
= TRUE
;
296 RtlLeaveCriticalSection(&gcsAppCert
);
299 /* If there's no certification DLLs present, return the failure code */
300 if (!g_HaveAppCerts
) return g_AppCertStatus
;
302 /* Otherwise, assume success and make sure we have *something* */
303 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
304 Status
= STATUS_SUCCESS
;
306 /* If the something is an embedded certification DLL, call it and return */
307 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
309 /* Otherwise we have custom certification DLLs, parse them */
310 NextEntry
= BasepAppCertDllsList
.Flink
;
312 while (NextEntry
!= &BasepAppCertDllsList
)
314 /* Make sure the entry has a callback */
315 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
316 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
318 /* Call it and check if it failed */
319 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
320 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
323 NextEntry
= NextEntry
->Flink
;
326 /* Now loop them again */
327 NextEntry
= BasepAppCertDllsList
.Flink
;
328 while (NextEntry
!= &BasepAppCertDllsList
)
330 /* Make sure the entry has a callback */
331 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
332 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
334 /* Call it, this time with the flag from the loop above */
335 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
338 /* All done, return the status */
344 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
345 IN HANDLE ProcessHandle
,
346 IN HANDLE ThreadHandle
)
349 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
351 /* Enter the application certification lock */
352 RtlEnterCriticalSection(&gcsAppCert
);
354 /* Check if we already know the function */
355 if (g_SaferReplaceProcessThreadTokens
)
358 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
366 /* Check if the app certification DLL isn't loaded */
367 if (!(gSaferHandle
) ||
368 (gSaferHandle
== (HMODULE
)-1) ||
369 (gSaferHandle
== (HMODULE
)-2))
371 /* Then we can't call the function */
372 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
376 /* We have the DLL, find the address of the Safer function */
377 Status
= LdrGetProcedureAddress(gSaferHandle
,
378 &SaferiReplaceProcessThreadTokens
,
380 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
381 if (NT_SUCCESS(Status
))
383 /* Found it, now call it */
384 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
392 /* We couldn't find it, so this must be an unsupported DLL */
393 LdrUnloadDll(gSaferHandle
);
395 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
400 /* Release the lock and return the result */
401 RtlLeaveCriticalSection(&gcsAppCert
);
407 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
412 ASSERT(Handles
!= NULL
);
413 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
415 /* Close the file handle */
418 Status
= NtClose(Handles
->File
);
419 ASSERT(NT_SUCCESS(Status
));
422 /* Close the section handle */
423 if (Handles
->Section
)
425 Status
= NtClose(Handles
->Section
);
426 ASSERT(NT_SUCCESS(Status
));
429 /* Unmap the section view */
430 if (Handles
->ViewBase
.QuadPart
)
432 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
433 (PVOID
)Handles
->ViewBase
.LowPart
);
434 ASSERT(NT_SUCCESS(Status
));
439 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
441 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
442 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
443 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
445 if (RealFilter
!= NULL
)
449 ExceptionDisposition
= RealFilter(ExceptionInfo
);
451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
456 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
457 RealFilter
!= UnhandledExceptionFilter
)
459 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
462 return ExceptionDisposition
;
467 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
469 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
473 /* Set our Start Address */
474 NtSetInformationThread(NtCurrentThread(),
475 ThreadQuerySetWin32StartAddress
,
477 sizeof(PPROCESS_START_ROUTINE
));
479 /* Call the Start Routine */
480 ExitThread(lpStartAddress());
482 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
484 /* Get the Exit code from the SEH Handler */
485 if (!BaseRunningInServerProcess
)
487 /* Kill the whole process, usually */
488 ExitProcess(_SEH2_GetExceptionCode());
492 /* If running inside CSRSS, kill just this thread */
493 ExitThread(_SEH2_GetExceptionCode());
501 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
502 IN PCLIENT_ID ClientId
)
505 BASE_API_MESSAGE ApiMessage
;
506 PBASE_CREATE_THREAD CreateThreadRequest
= &ApiMessage
.Data
.CreateThreadRequest
;
508 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
509 ClientId
->UniqueThread
, ThreadHandle
);
511 /* Fill out the request */
512 CreateThreadRequest
->ClientId
= *ClientId
;
513 CreateThreadRequest
->ThreadHandle
= ThreadHandle
;
516 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
518 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
519 sizeof(BASE_CREATE_THREAD
));
520 if (!NT_SUCCESS(Status
))
522 DPRINT1("Failed to tell CSRSS about new thread: %lx\n", Status
);
527 return STATUS_SUCCESS
;
532 BasePushProcessParameters(IN ULONG ParameterFlags
,
533 IN HANDLE ProcessHandle
,
535 IN LPCWSTR ApplicationPathName
,
536 IN LPWSTR lpCurrentDirectory
,
537 IN LPWSTR lpCommandLine
,
538 IN LPVOID lpEnvironment
,
539 IN LPSTARTUPINFOW StartupInfo
,
540 IN DWORD CreationFlags
,
541 IN BOOL InheritHandles
,
542 IN ULONG ImageSubsystem
,
543 IN PVOID AppCompatData
,
544 IN ULONG AppCompatDataSize
)
546 WCHAR FullPath
[MAX_PATH
+ 5];
547 PWCHAR Remaining
, DllPathString
, ScanChar
;
548 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
549 PVOID RemoteAppCompatData
;
550 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
551 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
555 BOOLEAN HavePebLock
= FALSE
, Result
;
556 PPEB Peb
= NtCurrentPeb();
558 /* Get the full path name */
559 Size
= GetFullPathNameW(ApplicationPathName
,
563 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
565 /* Get the DLL Path */
566 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
570 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
574 /* Initialize Strings */
575 RtlInitUnicodeString(&DllPath
, DllPathString
);
576 RtlInitUnicodeString(&ImageName
, FullPath
);
580 /* Couldn't get the path name. Just take the original path */
581 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
586 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
590 /* Initialize Strings */
591 RtlInitUnicodeString(&DllPath
, DllPathString
);
592 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
595 /* Initialize Strings */
596 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
597 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
599 /* Initialize more Strings from the Startup Info */
600 if (StartupInfo
->lpDesktop
)
602 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
606 RtlInitUnicodeString(&Desktop
, L
"");
608 if (StartupInfo
->lpReserved
)
610 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
614 RtlInitUnicodeString(&Shell
, L
"");
616 if (StartupInfo
->lpTitle
)
618 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
622 RtlInitUnicodeString(&Title
, ApplicationPathName
);
625 /* This one is special because the length can differ */
626 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
627 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
629 /* Enforce no app compat data if the pointer was NULL */
630 if (!AppCompatData
) AppCompatDataSize
= 0;
632 /* Create the Parameter Block */
633 ProcessParameters
= NULL
;
634 DPRINT1("Image Name: %wZ Dll Path: %wZ current directory: %wZ, CmdLine: %wZ, Title: %wZ, Desktop: %wZ, Shell: %wZ, Runtime: %wZ\n",
635 &ImageName
, &DllPath
, &CurrentDirectory
, &CommandLine
, &Title
, &Desktop
, &Shell
, &Runtime
);
636 Status
= RtlCreateProcessParameters(&ProcessParameters
,
640 &CurrentDirectory
: NULL
,
647 if (!NT_SUCCESS(Status
)) goto FailPath
;
649 /* Clear the current directory handle if not inheriting */
650 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
652 /* Check if the user passed in an environment */
655 /* We should've made it part of the parameters block, enforce this */
656 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
657 lpEnvironment
= ProcessParameters
->Environment
;
661 /* The user did not, so use the one from the current PEB */
664 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
667 /* Save pointer and start lookup */
668 ScanChar
= lpEnvironment
;
671 /* Find the environment size */
672 while ((ScanChar
[0]) || (ScanChar
[1])) ++ScanChar
;
673 ScanChar
+= (2 * sizeof(UNICODE_NULL
));
674 EnviroSize
= (ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
;
676 /* Allocate and Initialize new Environment Block */
678 ProcessParameters
->Environment
= NULL
;
679 Status
= NtAllocateVirtualMemory(ProcessHandle
,
680 (PVOID
*)&ProcessParameters
->Environment
,
685 if (!NT_SUCCESS(Status
)) goto FailPath
;
687 /* Write the Environment Block */
688 Status
= NtWriteVirtualMemory(ProcessHandle
,
689 ProcessParameters
->Environment
,
694 /* No longer need the PEB lock anymore */
702 /* Check if the write failed */
703 if (!NT_SUCCESS(Status
)) goto FailPath
;
706 /* Write new parameters */
707 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
708 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
709 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
710 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
711 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
712 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
713 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
714 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
715 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
717 /* Write the handles only if we have to */
718 if (StartupInfo
->dwFlags
&
719 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
721 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
722 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
723 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
726 /* Use Special Flags for BasepInitConsole in Kernel32 */
727 if (CreationFlags
& DETACHED_PROCESS
)
729 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
731 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
733 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
735 else if (CreationFlags
& CREATE_NO_WINDOW
)
737 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
741 /* Inherit our Console Handle */
742 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
744 /* Make sure that the shell isn't trampling on our handles first */
745 if (!(StartupInfo
->dwFlags
&
746 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
748 /* Copy the handle if we are inheriting or if it's a console handle */
749 if ((InheritHandles
) ||
750 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
752 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
754 if ((InheritHandles
) ||
755 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
757 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
759 if ((InheritHandles
) ||
760 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
762 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
767 /* Also set the Console Flag */
768 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
769 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
771 ProcessParameters
->ConsoleFlags
= 1;
774 /* Check if there's a .local file present */
775 if (ParameterFlags
& 1)
777 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
;
780 /* Check if we failed to open the IFEO key */
781 if (ParameterFlags
& 2)
783 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
;
786 /* Allocate memory for the parameter block */
787 Size
= ProcessParameters
->Length
;
788 RemoteParameters
= NULL
;
789 Status
= NtAllocateVirtualMemory(ProcessHandle
,
790 (PVOID
*)&RemoteParameters
,
795 if (!NT_SUCCESS(Status
)) goto FailPath
;
797 /* Set the allocated size */
798 ProcessParameters
->MaximumLength
= Size
;
800 /* Handle some Parameter Flags */
801 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
802 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
803 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
804 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
805 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
806 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
807 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
808 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
810 /* Write the Parameter Block */
811 Status
= NtWriteVirtualMemory(ProcessHandle
,
814 ProcessParameters
->Length
,
816 if (!NT_SUCCESS(Status
)) goto FailPath
;
818 /* Write the PEB Pointer */
819 Status
= NtWriteVirtualMemory(ProcessHandle
,
820 &RemotePeb
->ProcessParameters
,
824 if (!NT_SUCCESS(Status
)) goto FailPath
;
826 /* Check if there's any app compat data to write */
827 RemoteAppCompatData
= NULL
;
830 /* Allocate some space for the application compatibility data */
831 Size
= AppCompatDataSize
;
832 Status
= NtAllocateVirtualMemory(ProcessHandle
,
833 &RemoteAppCompatData
,
838 if (!NT_SUCCESS(Status
)) goto FailPath
;
840 /* Write the application compatibility data */
841 Status
= NtWriteVirtualMemory(ProcessHandle
,
846 if (!NT_SUCCESS(Status
)) goto FailPath
;
849 /* Write the PEB Pointer to the app compat data (might be NULL) */
850 Status
= NtWriteVirtualMemory(ProcessHandle
,
851 &RemotePeb
->pShimData
,
852 &RemoteAppCompatData
,
855 if (!NT_SUCCESS(Status
)) goto FailPath
;
857 /* Now write Peb->ImageSubSystem */
860 NtWriteVirtualMemory(ProcessHandle
,
861 &RemotePeb
->ImageSubsystem
,
863 sizeof(ImageSubsystem
),
872 if (HavePebLock
) RtlReleasePebLock();
873 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
874 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
877 DPRINT1("Failure to create process parameters: %lx\n", Status
);
878 BaseSetLastNTError(Status
);
885 InitCommandLines(VOID
)
889 /* Read the UNICODE_STRING from the PEB */
890 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
892 /* Convert to ANSI_STRING for the *A callers */
893 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
894 &BaseUnicodeCommandLine
,
896 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
899 /* PUBLIC FUNCTIONS ***********************************************************/
906 GetProcessAffinityMask(IN HANDLE hProcess
,
907 OUT PDWORD_PTR lpProcessAffinityMask
,
908 OUT PDWORD_PTR lpSystemAffinityMask
)
910 PROCESS_BASIC_INFORMATION ProcessInfo
;
913 /* Query information on the process from the kernel */
914 Status
= NtQueryInformationProcess(hProcess
,
915 ProcessBasicInformation
,
917 sizeof(PROCESS_BASIC_INFORMATION
),
919 if (!NT_SUCCESS(Status
))
922 BaseSetLastNTError(Status
);
926 /* Copy the affinity mask, and get the system one from our shared data */
927 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
928 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
937 SetProcessAffinityMask(IN HANDLE hProcess
,
938 IN DWORD_PTR dwProcessAffinityMask
)
942 /* Directly set the affinity mask */
943 Status
= NtSetInformationProcess(hProcess
,
945 (PVOID
)&dwProcessAffinityMask
,
947 if (!NT_SUCCESS(Status
))
950 BaseSetLastNTError(Status
);
954 /* Everything was ok */
963 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
964 OUT LPDWORD lpdwFlags
)
967 BASE_API_MESSAGE ApiMessage
;
968 PBASE_GET_PROCESS_SHUTDOWN_PARAMS GetShutdownParametersRequest
= &ApiMessage
.Data
.GetShutdownParametersRequest
;
970 /* Ask CSRSS for shutdown information */
971 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
973 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
974 sizeof(BASE_GET_PROCESS_SHUTDOWN_PARAMS
));
975 if (!NT_SUCCESS(Status
))
977 /* Return the failure from CSRSS */
978 BaseSetLastNTError(Status
);
982 /* Get the data back */
983 *lpdwLevel
= GetShutdownParametersRequest
->Level
;
984 *lpdwFlags
= GetShutdownParametersRequest
->Flags
;
993 SetProcessShutdownParameters(IN DWORD dwLevel
,
997 BASE_API_MESSAGE ApiMessage
;
998 PBASE_SET_PROCESS_SHUTDOWN_PARAMS SetShutdownParametersRequest
= &ApiMessage
.Data
.SetShutdownParametersRequest
;
1000 /* Write the data into the CSRSS request and send it */
1001 SetShutdownParametersRequest
->Level
= dwLevel
;
1002 SetShutdownParametersRequest
->Flags
= dwFlags
;
1003 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1005 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1006 sizeof(BASE_SET_PROCESS_SHUTDOWN_PARAMS
));
1007 if (!NT_SUCCESS(Status
))
1009 /* Return the failure from CSRSS */
1010 BaseSetLastNTError(Status
);
1023 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1024 OUT PSIZE_T lpMinimumWorkingSetSize
,
1025 OUT PSIZE_T lpMaximumWorkingSetSize
,
1028 QUOTA_LIMITS_EX QuotaLimits
;
1031 /* Query the kernel about this */
1032 Status
= NtQueryInformationProcess(hProcess
,
1035 sizeof(QUOTA_LIMITS_EX
),
1037 if (!NT_SUCCESS(Status
))
1040 BaseSetLastNTError(Status
);
1044 /* Copy the quota information out */
1045 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1046 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1047 *Flags
= QuotaLimits
.Flags
;
1056 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1057 OUT PSIZE_T lpMinimumWorkingSetSize
,
1058 OUT PSIZE_T lpMaximumWorkingSetSize
)
1061 return GetProcessWorkingSetSizeEx(hProcess
,
1062 lpMinimumWorkingSetSize
,
1063 lpMaximumWorkingSetSize
,
1072 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1073 IN SIZE_T dwMinimumWorkingSetSize
,
1074 IN SIZE_T dwMaximumWorkingSetSize
,
1077 QUOTA_LIMITS_EX QuotaLimits
;
1078 NTSTATUS Status
, ReturnStatus
;
1081 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1083 /* Zero out the input structure */
1084 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1086 /* Check if the caller sent any limits */
1087 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1089 /* Write the quota information */
1090 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1091 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1092 QuotaLimits
.Flags
= Flags
;
1094 /* Acquire the required privilege */
1095 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1097 /* Request the new quotas */
1098 ReturnStatus
= NtSetInformationProcess(hProcess
,
1101 sizeof(QuotaLimits
));
1102 Result
= NT_SUCCESS(ReturnStatus
);
1103 if (NT_SUCCESS(Status
))
1105 /* Release the privilege and set succes code */
1106 ASSERT(State
!= NULL
);
1107 RtlReleasePrivilege(State
);
1113 /* No limits, fail the call */
1114 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1118 /* Return result code, set error code if this was a failure */
1119 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1128 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1129 IN SIZE_T dwMinimumWorkingSetSize
,
1130 IN SIZE_T dwMaximumWorkingSetSize
)
1132 /* Call the newer API */
1133 return SetProcessWorkingSetSizeEx(hProcess
,
1134 dwMinimumWorkingSetSize
,
1135 dwMaximumWorkingSetSize
,
1144 GetProcessTimes(IN HANDLE hProcess
,
1145 IN LPFILETIME lpCreationTime
,
1146 IN LPFILETIME lpExitTime
,
1147 IN LPFILETIME lpKernelTime
,
1148 IN LPFILETIME lpUserTime
)
1150 KERNEL_USER_TIMES Kut
;
1153 /* Query the times */
1154 Status
= NtQueryInformationProcess(hProcess
,
1159 if (!NT_SUCCESS(Status
))
1161 /* Handle failure */
1162 BaseSetLastNTError(Status
);
1166 /* Copy all the times and return success */
1167 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1168 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1169 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1170 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1171 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1172 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1173 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1174 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1183 GetCurrentProcess(VOID
)
1185 return (HANDLE
)NtCurrentProcess();
1193 GetCurrentThread(VOID
)
1195 return (HANDLE
)NtCurrentThread();
1203 GetCurrentProcessId(VOID
)
1205 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1213 GetExitCodeProcess(IN HANDLE hProcess
,
1214 IN LPDWORD lpExitCode
)
1216 PROCESS_BASIC_INFORMATION ProcessBasic
;
1219 /* Ask the kernel */
1220 Status
= NtQueryInformationProcess(hProcess
,
1221 ProcessBasicInformation
,
1223 sizeof(PROCESS_BASIC_INFORMATION
),
1225 if (!NT_SUCCESS(Status
))
1227 /* We failed, was this because this is a VDM process? */
1228 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1230 /* Not a VDM process, fail the call */
1231 BaseSetLastNTError(Status
);
1235 /* Succes case, return the exit code */
1236 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1245 GetProcessId(IN HANDLE Process
)
1247 PROCESS_BASIC_INFORMATION ProcessBasic
;
1250 /* Query the kernel */
1251 Status
= NtQueryInformationProcess(Process
,
1252 ProcessBasicInformation
,
1254 sizeof(PROCESS_BASIC_INFORMATION
),
1256 if (!NT_SUCCESS(Status
))
1258 /* Handle failure */
1259 BaseSetLastNTError(Status
);
1263 /* Return the PID */
1264 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1272 OpenProcess(IN DWORD dwDesiredAccess
,
1273 IN BOOL bInheritHandle
,
1274 IN DWORD dwProcessId
)
1277 HANDLE ProcessHandle
;
1278 OBJECT_ATTRIBUTES ObjectAttributes
;
1281 /* Setup the input client ID structure */
1282 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1283 ClientId
.UniqueThread
= 0;
1285 /* This is needed just to define the inheritance flags */
1286 InitializeObjectAttributes(&ObjectAttributes
,
1288 (bInheritHandle
? OBJ_INHERIT
: 0),
1292 /* Now try to open the process */
1293 Status
= NtOpenProcess(&ProcessHandle
,
1297 if (!NT_SUCCESS(Status
))
1299 /* Handle failure */
1300 BaseSetLastNTError(Status
);
1304 /* Otherwise return a handle to the process */
1305 return ProcessHandle
;
1313 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1315 /* Write the global function pointer */
1316 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1324 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1326 PRTL_USER_PROCESS_PARAMETERS Params
;
1328 /* Get the process parameters */
1329 Params
= NtCurrentPeb()->ProcessParameters
;
1331 /* Copy the data out of there */
1332 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1333 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1334 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1335 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1336 lpStartupInfo
->dwX
= Params
->StartingX
;
1337 lpStartupInfo
->dwY
= Params
->StartingY
;
1338 lpStartupInfo
->dwXSize
= Params
->CountX
;
1339 lpStartupInfo
->dwYSize
= Params
->CountY
;
1340 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1341 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1342 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1343 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1344 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1345 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1346 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1348 /* Check if the standard handles are being used for other features */
1349 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1351 STARTF_SHELLPRIVATE
))
1353 /* These are, so copy the standard handles too */
1354 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1355 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1356 lpStartupInfo
->hStdError
= Params
->StandardError
;
1365 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1367 PRTL_USER_PROCESS_PARAMETERS Params
;
1368 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1369 LPSTARTUPINFOA StartupInfo
;
1372 /* Get the cached information as well as the PEB parameters */
1373 StartupInfo
= BaseAnsiStartupInfo
;
1374 Params
= NtCurrentPeb()->ProcessParameters
;
1376 /* Check if this is the first time we have to get the cached version */
1377 while (!StartupInfo
)
1379 /* Create new ANSI startup info */
1380 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1382 sizeof(*StartupInfo
));
1385 /* Zero out string pointers in case we fail to create them */
1386 StartupInfo
->lpReserved
= 0;
1387 StartupInfo
->lpDesktop
= 0;
1388 StartupInfo
->lpTitle
= 0;
1391 StartupInfo
->cb
= sizeof(*StartupInfo
);
1393 /* Copy what's already stored in the PEB */
1394 StartupInfo
->dwX
= Params
->StartingX
;
1395 StartupInfo
->dwY
= Params
->StartingY
;
1396 StartupInfo
->dwXSize
= Params
->CountX
;
1397 StartupInfo
->dwYSize
= Params
->CountY
;
1398 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1399 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1400 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1401 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1402 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1403 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1404 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1405 StartupInfo
->hStdInput
= Params
->StandardInput
;
1406 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1407 StartupInfo
->hStdError
= Params
->StandardError
;
1409 /* Copy shell info string */
1410 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1413 if (NT_SUCCESS(Status
))
1416 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1418 /* Copy desktop info string */
1419 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1420 &Params
->DesktopInfo
,
1422 if (NT_SUCCESS(Status
))
1425 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1427 /* Copy window title string */
1428 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1429 &Params
->WindowTitle
,
1431 if (NT_SUCCESS(Status
))
1434 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1436 /* We finished with the ANSI version, try to cache it */
1437 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo
,
1441 /* We were the first thread through, use the data */
1445 /* Someone beat us to it, use their data instead */
1446 StartupInfo
= BaseAnsiStartupInfo
;
1447 Status
= STATUS_SUCCESS
;
1449 /* We're going to free our own stuff, but not raise */
1450 RtlFreeAnsiString(&TitleString
);
1452 RtlFreeAnsiString(&DesktopString
);
1454 RtlFreeAnsiString(&ShellString
);
1456 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1460 /* No memory, fail */
1461 Status
= STATUS_NO_MEMORY
;
1464 /* Raise an error unless we got here due to the race condition */
1465 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1468 /* Now copy from the cached ANSI version */
1469 lpStartupInfo
->cb
= StartupInfo
->cb
;
1470 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1471 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1472 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1473 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1474 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1475 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1476 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1477 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1478 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1479 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1480 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1481 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1482 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1483 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1485 /* Check if the shell is hijacking the handles for other features */
1486 if (lpStartupInfo
->dwFlags
&
1487 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1489 /* It isn't, so we can return the raw values */
1490 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1491 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1492 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1496 /* It is, so make sure nobody uses these as console handles */
1497 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1498 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1499 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1508 FlushInstructionCache(IN HANDLE hProcess
,
1509 IN LPCVOID lpBaseAddress
,
1514 /* Call the native function */
1515 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, dwSize
);
1516 if (!NT_SUCCESS(Status
))
1518 /* Handle failure case */
1519 BaseSetLastNTError(Status
);
1532 ExitProcess(IN UINT uExitCode
)
1534 BASE_API_MESSAGE ApiMessage
;
1535 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1537 ASSERT(!BaseRunningInServerProcess
);
1541 /* Acquire the PEB lock */
1542 RtlAcquirePebLock();
1544 /* Kill all the threads */
1545 NtTerminateProcess(NULL
, 0);
1547 /* Unload all DLLs */
1548 LdrShutdownProcess();
1550 /* Notify Base Server of process termination */
1551 ExitProcessRequest
->uExitCode
= uExitCode
;
1552 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1554 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1555 sizeof(BASE_EXIT_PROCESS
));
1557 /* Now do it again */
1558 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1562 /* Release the PEB lock */
1563 RtlReleasePebLock();
1567 /* should never get here */
1577 TerminateProcess(IN HANDLE hProcess
,
1582 /* Check if no handle was passed in */
1585 /* Set error code */
1586 SetLastError(ERROR_INVALID_HANDLE
);
1590 /* Otherwise, try to terminate the process */
1591 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1592 if (NT_SUCCESS(Status
)) return TRUE
;
1594 /* It failed, convert error code */
1595 BaseSetLastNTError(Status
);
1598 /* This is the failure path */
1607 FatalAppExitA(UINT uAction
,
1608 LPCSTR lpMessageText
)
1610 PUNICODE_STRING MessageTextU
;
1611 ANSI_STRING MessageText
;
1614 /* Initialize the string using the static TEB pointer */
1615 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1616 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1618 /* Convert to unicode and just exit normally if this failed */
1619 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1620 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1622 /* Call the Wide function */
1623 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1631 FatalAppExitW(IN UINT uAction
,
1632 IN LPCWSTR lpMessageText
)
1634 UNICODE_STRING UnicodeString
;
1638 /* Setup the string to print out */
1639 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1641 /* Display the hard error no matter what */
1642 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1645 (PULONG_PTR
)&UnicodeString
,
1649 /* Give the user a chance to abort */
1650 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1652 /* Otherwise kill the process */
1661 FatalExit(IN
int ExitCode
)
1664 /* On Checked builds, Windows gives you a nice little debugger UI */
1666 DbgPrint("FatalExit...\n");
1671 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1679 ExitProcess(ExitCode
);
1686 /* On other builds, just kill the process */
1687 ExitProcess(ExitCode
);
1695 GetPriorityClass(IN HANDLE hProcess
)
1698 PROCESS_PRIORITY_CLASS PriorityClass
;
1700 /* Query the kernel */
1701 Status
= NtQueryInformationProcess(hProcess
,
1702 ProcessPriorityClass
,
1704 sizeof(PROCESS_PRIORITY_CLASS
),
1706 if (NT_SUCCESS(Status
))
1708 /* Handle the conversion from NT to Win32 classes */
1709 switch (PriorityClass
.PriorityClass
)
1711 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1712 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1713 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1714 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1715 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1716 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1721 BaseSetLastNTError(Status
);
1730 SetPriorityClass(IN HANDLE hProcess
,
1731 IN DWORD dwPriorityClass
)
1735 PROCESS_PRIORITY_CLASS PriorityClass
;
1737 /* Handle conversion from Win32 to NT priority classes */
1738 switch (dwPriorityClass
)
1740 case IDLE_PRIORITY_CLASS
:
1741 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1744 case BELOW_NORMAL_PRIORITY_CLASS
:
1745 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1748 case NORMAL_PRIORITY_CLASS
:
1749 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1752 case ABOVE_NORMAL_PRIORITY_CLASS
:
1753 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1756 case HIGH_PRIORITY_CLASS
:
1757 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1760 case REALTIME_PRIORITY_CLASS
:
1761 /* Try to acquire the privilege. If it fails, just use HIGH */
1762 State
= BasepIsRealtimeAllowed(TRUE
);
1763 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1764 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1768 /* Unrecognized priority classes don't make it to the kernel */
1769 SetLastError(ERROR_INVALID_PARAMETER
);
1773 /* Send the request to the kernel, and don't touch the foreground flag */
1774 PriorityClass
.Foreground
= FALSE
;
1775 Status
= NtSetInformationProcess(hProcess
,
1776 ProcessPriorityClass
,
1778 sizeof(PROCESS_PRIORITY_CLASS
));
1780 /* Release the privilege if we had it */
1781 if (State
) RtlReleasePrivilege(State
);
1782 if (!NT_SUCCESS(Status
))
1784 /* Handle error path */
1785 BaseSetLastNTError(Status
);
1798 GetProcessVersion(IN DWORD ProcessId
)
1801 PIMAGE_NT_HEADERS NtHeader
;
1802 PIMAGE_DOS_HEADER DosHeader
;
1804 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1807 HANDLE ProcessHandle
= NULL
;
1809 USHORT VersionData
[2];
1812 /* We'll be accessing stuff that can fault, so protect everything with SEH */
1815 /* It this an in-process or out-of-process request? */
1816 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
1818 /* It's in-process, so just read our own header */
1819 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
1822 /* Unable to read the NT header, something is wrong here... */
1823 Status
= STATUS_INVALID_IMAGE_FORMAT
;
1827 /* Get the version straight out of the NT header */
1828 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
1829 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
1833 /* Out-of-process, so open it */
1834 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1837 if (!ProcessHandle
) return 0;
1839 /* Try to find out where its PEB lives */
1840 Status
= NtQueryInformationProcess(ProcessHandle
,
1841 ProcessBasicInformation
,
1843 sizeof(ProcessBasicInfo
),
1846 if (!NT_SUCCESS(Status
)) goto Error
;
1847 Peb
= ProcessBasicInfo
.PebBaseAddress
;
1849 /* Now that we have the PEB, read the image base address out of it */
1850 Result
= ReadProcessMemory(ProcessHandle
,
1851 &Peb
->ImageBaseAddress
,
1853 sizeof(BaseAddress
),
1855 if (!Result
) goto Error
;
1857 /* Now read the e_lfanew (offset to NT header) from the base */
1858 DosHeader
= BaseAddress
;
1859 Result
= ReadProcessMemory(ProcessHandle
,
1860 &DosHeader
->e_lfanew
,
1864 if (!Result
) goto Error
;
1866 /* And finally, read the NT header itself by adding the offset */
1867 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
1868 Result
= ReadProcessMemory(ProcessHandle
,
1869 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
1871 sizeof(VersionData
),
1873 if (!Result
) goto Error
;
1875 /* Get the version straight out of the NT header */
1876 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
1879 /* If there was an error anywhere, set the last error */
1880 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
1885 /* Close the process handle */
1886 if (ProcessHandle
) CloseHandle(ProcessHandle
);
1890 /* And return the version data */
1899 GetProcessIoCounters(IN HANDLE hProcess
,
1900 OUT PIO_COUNTERS lpIoCounters
)
1904 /* Query the kernel. Structures are identical, so let it do the copy too. */
1905 Status
= NtQueryInformationProcess(hProcess
,
1908 sizeof(IO_COUNTERS
),
1910 if (!NT_SUCCESS(Status
))
1912 /* Handle error path */
1913 BaseSetLastNTError(Status
);
1926 GetProcessPriorityBoost(IN HANDLE hProcess
,
1927 OUT PBOOL pDisablePriorityBoost
)
1930 ULONG PriorityBoost
;
1932 /* Query the kernel */
1933 Status
= NtQueryInformationProcess(hProcess
,
1934 ProcessPriorityBoost
,
1938 if (NT_SUCCESS(Status
))
1940 /* Convert from ULONG to a BOOL */
1941 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
1945 /* Handle error path */
1946 BaseSetLastNTError(Status
);
1955 SetProcessPriorityBoost(IN HANDLE hProcess
,
1956 IN BOOL bDisablePriorityBoost
)
1959 ULONG PriorityBoost
;
1961 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
1962 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
1963 Status
= NtSetInformationProcess(hProcess
,
1964 ProcessPriorityBoost
,
1967 if (!NT_SUCCESS(Status
))
1969 /* Handle error path */
1970 BaseSetLastNTError(Status
);
1983 GetProcessHandleCount(IN HANDLE hProcess
,
1984 OUT PDWORD pdwHandleCount
)
1989 /* Query the kernel */
1990 Status
= NtQueryInformationProcess(hProcess
,
1995 if (NT_SUCCESS(Status
))
1997 /* Copy the count and return sucecss */
1998 *pdwHandleCount
= phc
;
2002 /* Handle error path */
2003 BaseSetLastNTError(Status
);
2012 IsWow64Process(IN HANDLE hProcess
,
2013 OUT PBOOL Wow64Process
)
2018 /* Query the kernel */
2019 Status
= NtQueryInformationProcess(hProcess
,
2020 ProcessWow64Information
,
2024 if (!NT_SUCCESS(Status
))
2026 /* Handle error path */
2027 BaseSetLastNTError(Status
);
2031 /* Enforce this is a BOOL, and return success */
2032 *Wow64Process
= (pbi
!= 0);
2041 GetCommandLineA(VOID
)
2043 return BaseAnsiCommandLine
.Buffer
;
2051 GetCommandLineW(VOID
)
2053 return BaseUnicodeCommandLine
.Buffer
;
2061 ReadProcessMemory(IN HANDLE hProcess
,
2062 IN LPCVOID lpBaseAddress
,
2065 OUT SIZE_T
* lpNumberOfBytesRead
)
2070 Status
= NtReadVirtualMemory(hProcess
,
2071 (PVOID
)lpBaseAddress
,
2076 /* In user-mode, this parameter is optional */
2077 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2078 if (!NT_SUCCESS(Status
))
2081 BaseSetLastNTError(Status
);
2085 /* Return success */
2094 WriteProcessMemory(IN HANDLE hProcess
,
2095 IN LPVOID lpBaseAddress
,
2096 IN LPCVOID lpBuffer
,
2098 OUT SIZE_T
*lpNumberOfBytesWritten
)
2106 /* Set parameters for protect call */
2108 Base
= lpBaseAddress
;
2110 /* Check the current status */
2111 Status
= NtProtectVirtualMemory(hProcess
,
2114 PAGE_EXECUTE_READWRITE
,
2116 if (NT_SUCCESS(Status
))
2118 /* Check if we are unprotecting */
2119 UnProtect
= OldValue
& (PAGE_READWRITE
|
2121 PAGE_EXECUTE_READWRITE
|
2122 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2125 /* Set the new protection */
2126 Status
= NtProtectVirtualMemory(hProcess
,
2132 /* Write the memory */
2133 Status
= NtWriteVirtualMemory(hProcess
,
2139 /* In Win32, the parameter is optional, so handle this case */
2140 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2142 if (!NT_SUCCESS(Status
))
2145 BaseSetLastNTError(Status
);
2149 /* Flush the ITLB */
2150 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2155 /* Check if we were read only */
2156 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2158 /* Restore protection and fail */
2159 NtProtectVirtualMemory(hProcess
,
2164 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2166 /* Note: This is what Windows returns and code depends on it */
2167 return STATUS_ACCESS_VIOLATION
;
2170 /* Otherwise, do the write */
2171 Status
= NtWriteVirtualMemory(hProcess
,
2177 /* In Win32, the parameter is optional, so handle this case */
2178 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2180 /* And restore the protection */
2181 NtProtectVirtualMemory(hProcess
,
2186 if (!NT_SUCCESS(Status
))
2189 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2191 /* Note: This is what Windows returns and code depends on it */
2192 return STATUS_ACCESS_VIOLATION
;
2195 /* Flush the ITLB */
2196 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2203 BaseSetLastNTError(Status
);
2213 ProcessIdToSessionId(IN DWORD dwProcessId
,
2214 OUT PDWORD pSessionId
)
2216 PROCESS_SESSION_INFORMATION SessionInformation
;
2217 OBJECT_ATTRIBUTES ObjectAttributes
;
2219 HANDLE ProcessHandle
;
2222 /* Do a quick check if the pointer is not writable */
2223 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2226 SetLastError(ERROR_INVALID_PARAMETER
);
2230 /* Open the process passed in by ID */
2231 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2232 ClientId
.UniqueThread
= 0;
2233 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2234 Status
= NtOpenProcess(&ProcessHandle
,
2235 PROCESS_QUERY_INFORMATION
,
2238 if (NT_SUCCESS(Status
))
2240 /* Query the session ID from the kernel */
2241 Status
= NtQueryInformationProcess(ProcessHandle
,
2242 ProcessSessionInformation
,
2243 &SessionInformation
,
2244 sizeof(SessionInformation
),
2247 /* Close the handle and check if we suceeded */
2248 NtClose(ProcessHandle
);
2249 if (NT_SUCCESS(Status
))
2251 /* Return the session ID */
2252 *pSessionId
= SessionInformation
.SessionId
;
2257 /* Set error code and fail */
2258 BaseSetLastNTError(Status
);
2263 #define AddToHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) | (y));
2264 #define RemoveFromHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) & ~(y));
2265 C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME
== (PROCESS_PRIORITY_CLASS_HIGH
+ 1));
2272 CreateProcessInternalW(IN HANDLE hUserToken
,
2273 IN LPCWSTR lpApplicationName
,
2274 IN LPWSTR lpCommandLine
,
2275 IN LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2276 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2277 IN BOOL bInheritHandles
,
2278 IN DWORD dwCreationFlags
,
2279 IN LPVOID lpEnvironment
,
2280 IN LPCWSTR lpCurrentDirectory
,
2281 IN LPSTARTUPINFOW lpStartupInfo
,
2282 IN LPPROCESS_INFORMATION lpProcessInformation
,
2283 OUT PHANDLE hNewToken
)
2286 // Core variables used for creating the initial process and thread
2288 SECURITY_ATTRIBUTES LocalThreadAttributes
, LocalProcessAttributes
;
2289 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2290 POBJECT_ATTRIBUTES ObjectAttributes
;
2291 SECTION_IMAGE_INFORMATION ImageInformation
;
2292 IO_STATUS_BLOCK IoStatusBlock
;
2294 ULONG NoWindow
, RegionSize
, StackSize
, ImageMachine
, ErrorCode
, Flags
;
2295 ULONG ParameterFlags
, PrivilegeValue
, HardErrorMode
, ErrorResponse
;
2296 ULONG_PTR ErrorParameters
[2];
2297 BOOLEAN InJob
, SaferNeeded
, UseLargePages
, HavePrivilege
;
2298 BOOLEAN QuerySection
, SkipSaferAndAppCompat
;
2300 BASE_API_MESSAGE CsrMsg
;
2301 PBASE_CREATE_PROCESS CreateProcessMsg
;
2302 PCSR_CAPTURE_BUFFER CaptureBuffer
;
2303 PVOID BaseAddress
, PrivilegeState
, RealTimePrivilegeState
;
2304 HANDLE DebugHandle
, TokenHandle
, JobHandle
, KeyHandle
, ThreadHandle
;
2305 HANDLE FileHandle
, SectionHandle
, ProcessHandle
;
2307 PROCESS_PRIORITY_CLASS PriorityClass
;
2308 NTSTATUS Status
, Status1
, ImageDbgStatus
;
2309 PPEB Peb
, RemotePeb
;
2311 INITIAL_TEB InitialTeb
;
2313 PIMAGE_NT_HEADERS NtHeaders
;
2314 STARTUPINFOW StartupInfo
;
2315 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
2316 UNICODE_STRING DebuggerString
;
2319 // Variables used for command-line and argument parsing
2324 ULONG Length
, CurdirLength
, CmdQuoteLength
;
2325 ULONG CmdLineLength
, ResultSize
;
2326 PWCHAR QuotedCmdLine
, AnsiCmdCommand
, ExtBuffer
, CurrentDirectory
;
2327 PWCHAR NullBuffer
, ScanString
, NameBuffer
, SearchPath
, DebuggerCmdLine
;
2328 ANSI_STRING AnsiEnv
;
2329 UNICODE_STRING UnicodeEnv
, PathName
;
2330 BOOLEAN SearchRetry
, QuotesNeeded
, CmdLineIsAppName
, HasQuotes
;
2333 // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2335 RTL_PATH_TYPE SxsPathType
, PathType
;
2336 #if _SXS_SUPPORT_ENABLED_
2337 PRTL_BUFFER ByteBuffer
;
2338 PRTL_UNICODE_STRING_BUFFER ThisBuffer
, Buffer
, SxsStaticBuffers
[5];
2339 PRTL_UNICODE_STRING_BUFFER
* BufferHead
, SxsStringBuffer
;
2340 RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath
, SxsNtManifestPath
;
2341 RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath
, SxsNtPolicyPath
;
2342 RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory
;
2343 BASE_MSG_SXS_HANDLES MappedHandles
, Handles
, FileHandles
;
2344 PVOID CapturedStrings
[3];
2345 SXS_WIN32_NT_PATH_PAIR ExePathPair
, ManifestPathPair
, PolicyPathPair
;
2346 SXS_OVERRIDE_MANIFEST OverrideMannifest
;
2347 UNICODE_STRING FreeString
, SxsNtExePath
;
2348 PWCHAR SxsConglomeratedBuffer
, StaticBuffer
;
2349 ULONG ConglomeratedBufferSizeBytes
, StaticBufferSize
, i
;
2354 // Variables used for path conversion (and partially Fusion/SxS)
2356 PWCHAR FilePart
, PathBuffer
, FreeBuffer
;
2357 BOOLEAN TranslationStatus
;
2358 RTL_RELATIVE_NAME_U SxsWin32RelativePath
;
2359 UNICODE_STRING PathBufferString
, SxsWin32ExePath
;
2362 // Variables used by Application Compatibility (and partially Fusion/SxS)
2364 PVOID AppCompatSxsData
, AppCompatData
;
2365 ULONG AppCompatSxsDataSize
, AppCompatDataSize
;
2367 // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2369 ULONG BinarySubType
, VdmBinaryType
, VdmTask
, VdmReserve
;
2371 BOOLEAN UseVdmReserve
;
2372 HANDLE VdmWaitObject
;
2373 ANSI_STRING VdmAnsiEnv
;
2374 UNICODE_STRING VdmString
, VdmUnicodeEnv
;
2376 PBASE_CHECK_VDM VdmMsg
;
2378 /* Zero out the initial core variables and handles */
2379 QuerySection
= FALSE
;
2381 SkipSaferAndAppCompat
= FALSE
;
2388 SectionHandle
= NULL
;
2389 ProcessHandle
= NULL
;
2390 ThreadHandle
= NULL
;
2391 BaseAddress
= (PVOID
)1;
2393 /* Zero out initial SxS and Application Compatibility state */
2394 AppCompatData
= NULL
;
2395 AppCompatDataSize
= 0;
2396 AppCompatSxsData
= NULL
;
2397 AppCompatSxsDataSize
= 0;
2398 CaptureBuffer
= NULL
;
2399 #if _SXS_SUPPORT_ENABLED_
2400 SxsConglomeratedBuffer
= NULL
;
2404 /* Zero out initial parsing variables -- others are initialized later */
2405 DebuggerCmdLine
= NULL
;
2411 CurrentDirectory
= NULL
;
2413 DebuggerString
.Buffer
= NULL
;
2415 QuotedCmdLine
= NULL
;
2417 /* Zero out initial VDM state */
2418 VdmAnsiEnv
.Buffer
= NULL
;
2419 VdmUnicodeEnv
.Buffer
= NULL
;
2420 VdmString
.Buffer
= NULL
;
2425 VdmWaitObject
= NULL
;
2426 UseVdmReserve
= FALSE
;
2429 /* Set message structures */
2430 CreateProcessMsg
= &CsrMsg
.Data
.CreateProcessRequest
;
2431 VdmMsg
= &CsrMsg
.Data
.CheckVdm
;
2433 /* Clear the more complex structures by zeroing out their entire memory */
2434 RtlZeroMemory(&Context
, sizeof(Context
));
2435 #if _SXS_SUPPORT_ENABLED_
2436 RtlZeroMemory(&FileHandles
, sizeof(FileHandles
));
2437 RtlZeroMemory(&MappedHandles
, sizeof(MappedHandles
));
2438 RtlZeroMemory(&Handles
, sizeof(Handles
));
2440 RtlZeroMemory(&CreateProcessMsg
->Sxs
, sizeof(CreateProcessMsg
->Sxs
));
2441 RtlZeroMemory(&LocalProcessAttributes
, sizeof(LocalProcessAttributes
));
2442 RtlZeroMemory(&LocalThreadAttributes
, sizeof(LocalThreadAttributes
));
2444 /* Zero out output arguments as well */
2445 RtlZeroMemory(lpProcessInformation
, sizeof(*lpProcessInformation
));
2446 if (hNewToken
) *hNewToken
= NULL
;
2448 /* Capture the special window flag */
2449 NoWindow
= dwCreationFlags
& CREATE_NO_WINDOW
;
2450 dwCreationFlags
&= ~CREATE_NO_WINDOW
;
2452 #if _SXS_SUPPORT_ENABLED_
2453 /* Setup the SxS static string arrays and buffers */
2454 SxsStaticBuffers
[0] = &SxsWin32ManifestPath
;
2455 SxsStaticBuffers
[1] = &SxsWin32PolicyPath
;
2456 SxsStaticBuffers
[2] = &SxsWin32AssemblyDirectory
;
2457 SxsStaticBuffers
[3] = &SxsNtManifestPath
;
2458 SxsStaticBuffers
[4] = &SxsNtPolicyPath
;
2459 ExePathPair
.Win32
= &SxsWin32ExePath
;
2460 ExePathPair
.Nt
= &SxsNtExePath
;
2461 ManifestPathPair
.Win32
= &SxsWin32ManifestPath
.String
;
2462 ManifestPathPair
.Nt
= &SxsNtManifestPath
.String
;
2463 PolicyPathPair
.Win32
= &SxsWin32PolicyPath
.String
;
2464 PolicyPathPair
.Nt
= &SxsNtPolicyPath
.String
;
2467 DPRINT1("CreateProcessInternalW: %S %S %lx\n", lpApplicationName
, lpCommandLine
, dwCreationFlags
);
2469 /* Finally, set our TEB and PEB */
2470 Teb
= NtCurrentTeb();
2471 Peb
= NtCurrentPeb();
2473 /* This combination is illegal (see MSDN) */
2474 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2475 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2477 DPRINT1("Invalid flag combo used\n");
2478 SetLastError(ERROR_INVALID_PARAMETER
);
2482 /* Convert the priority class */
2483 if (dwCreationFlags
& IDLE_PRIORITY_CLASS
)
2485 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
2487 else if (dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
2489 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
2491 else if (dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
2493 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
2495 else if (dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
2497 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
2499 else if (dwCreationFlags
& HIGH_PRIORITY_CLASS
)
2501 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2503 else if (dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
2505 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2506 PriorityClass
.PriorityClass
+= (BasepIsRealtimeAllowed(0) != NULL
);
2510 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_INVALID
;
2513 /* Done with the priority masks, so get rid of them */
2514 PriorityClass
.Foreground
= FALSE
;
2515 dwCreationFlags
&= ~(NORMAL_PRIORITY_CLASS
|
2516 IDLE_PRIORITY_CLASS
|
2517 HIGH_PRIORITY_CLASS
|
2518 REALTIME_PRIORITY_CLASS
|
2519 BELOW_NORMAL_PRIORITY_CLASS
|
2520 ABOVE_NORMAL_PRIORITY_CLASS
);
2522 /* You cannot request both a shared and a separate WoW VDM */
2523 if ((dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2524 (dwCreationFlags
& CREATE_SHARED_WOW_VDM
))
2526 /* Fail such nonsensical attempts */
2527 DPRINT1("Invalid WOW flags\n");
2528 SetLastError(ERROR_INVALID_PARAMETER
);
2531 else if (!(dwCreationFlags
& CREATE_SHARED_WOW_VDM
) &&
2532 (BaseStaticServerData
->DefaultSeparateVDM
))
2534 /* A shared WoW VDM was not requested but system enforces separation */
2535 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
2538 /* If a shared WoW VDM is used, make sure the process isn't in a job */
2539 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2540 (NtIsProcessInJob(NtCurrentProcess(), NULL
)))
2542 /* Remove the shared flag and add the separate flag */
2543 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2544 CREATE_SEPARATE_WOW_VDM
;
2547 /* Convert the environment */
2548 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2550 /* Scan the environment to calculate its Unicode size */
2551 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
2552 while ((*pcScan
) || (*(pcScan
+ 1))) ++pcScan
;
2554 /* Create our ANSI String */
2555 AnsiEnv
.Length
= pcScan
- (PCHAR
)lpEnvironment
+ sizeof(ANSI_NULL
);
2556 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ sizeof(ANSI_NULL
);
2558 /* Allocate memory for the Unicode Environment */
2559 UnicodeEnv
.Buffer
= NULL
;
2560 RegionSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
2561 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
2562 (PVOID
)&UnicodeEnv
.Buffer
,
2567 if (!NT_SUCCESS(Status
))
2570 BaseSetLastNTError(Status
);
2574 /* Use the allocated size and convert */
2575 UnicodeEnv
.MaximumLength
= RegionSize
;
2576 Status
= RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
2577 if (!NT_SUCCESS(Status
))
2580 NtFreeVirtualMemory(NtCurrentProcess(),
2581 (PVOID
)&UnicodeEnv
.Buffer
,
2584 BaseSetLastNTError(Status
);
2588 /* Now set the Unicode environment as the environment string pointer */
2589 lpEnvironment
= UnicodeEnv
.Buffer
;
2592 /* Make a copy of the caller's startup info since we'll modify it */
2593 StartupInfo
= *lpStartupInfo
;
2595 /* Check if private data is being sent on the same channel as std handles */
2596 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2597 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2599 /* Cannot use the std handles since we have monitor/hotkey values */
2600 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2603 /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2605 /* New iteration -- free any existing name buffer */
2608 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2612 /* New iteration -- free any existing free buffer */
2615 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
2619 /* New iteration -- close any existing file handle */
2622 NtClose(FileHandle
);
2626 /* Set the initial parsing state. This code can loop -- don't move this! */
2629 QuotesNeeded
= FALSE
;
2630 CmdLineIsAppName
= FALSE
;
2632 /* First check if we don't have an application name */
2633 if (!lpApplicationName
)
2635 /* This should be the first time we attempt creating one */
2636 ASSERT(NameBuffer
== NULL
);
2638 /* Allocate a buffer to hold it */
2639 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2641 MAX_PATH
* sizeof(WCHAR
));
2644 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2649 /* Initialize the application name and our parsing parameters */
2650 lpApplicationName
= NullBuffer
= ScanString
= lpCommandLine
;
2652 /* Check for an initial quote*/
2653 if (*lpCommandLine
== L
'\"')
2655 /* We found a quote, keep searching for another one */
2656 SearchRetry
= FALSE
;
2658 lpApplicationName
= ScanString
;
2661 /* Have we found the terminating quote? */
2662 if (*ScanString
== L
'\"')
2664 /* We're done, get out of here */
2665 NullBuffer
= ScanString
;
2670 /* Keep searching for the quote */
2672 NullBuffer
= ScanString
;
2678 /* We simply make the application name be the command line*/
2679 lpApplicationName
= lpCommandLine
;
2682 /* Check if it starts with a space or tab */
2683 if ((*ScanString
== L
' ') || (*ScanString
== L
'\t'))
2685 /* Break out of the search loop */
2686 NullBuffer
= ScanString
;
2690 /* Keep searching for a space or tab */
2692 NullBuffer
= ScanString
;
2696 /* We have found the end of the application name, terminate it */
2697 SaveChar
= *NullBuffer
;
2698 *NullBuffer
= UNICODE_NULL
;
2700 /* New iteration -- free any existing saved path */
2703 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
2707 /* Now compute the final EXE path based on the name */
2708 SearchPath
= BaseComputeProcessExePath((LPWSTR
)lpApplicationName
);
2709 DPRINT1("Search Path: %S\n", SearchPath
);
2712 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2717 /* And search for the executable in the search path */
2718 Length
= SearchPathW(SearchPath
,
2725 /* Did we find it? */
2726 if ((Length
) && (Length
< MAX_PATH
))
2728 /* Get file attributes */
2729 CurdirLength
= GetFileAttributesW(NameBuffer
);
2730 if ((CurdirLength
!= 0xFFFFFFFF) &&
2731 (CurdirLength
& FILE_ATTRIBUTE_DIRECTORY
))
2733 /* This was a directory, fail later on */
2743 DPRINT1("Length: %lx Buffer: %S\n", Length
, NameBuffer
);
2745 /* Check if there was a failure in SearchPathW */
2746 if ((Length
) && (Length
< MAX_PATH
))
2748 /* Everything looks good, restore the name */
2749 *NullBuffer
= SaveChar
;
2750 lpApplicationName
= NameBuffer
;
2754 /* Check if this was a relative path, which would explain it */
2755 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2756 if (PathType
!= RtlPathTypeRelative
)
2758 /* This should fail, and give us a detailed LastError */
2759 FileHandle
= CreateFileW(lpApplicationName
,
2765 FILE_ATTRIBUTE_NORMAL
,
2767 if (FileHandle
!= INVALID_HANDLE_VALUE
)
2769 /* It worked? Return a generic error */
2770 CloseHandle(FileHandle
);
2772 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2777 /* Path was absolute, which means it doesn't exist */
2778 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2781 /* Did we already fail once? */
2784 /* Set the error code */
2785 SetLastError(ErrorCode
);
2789 /* Not yet, cache it */
2790 ErrorCode
= GetLastError();
2793 /* Put back the command line */
2794 *NullBuffer
= SaveChar
;
2795 lpApplicationName
= NameBuffer
;
2797 /* It's possible there's whitespace in the directory name */
2798 if (!(*ScanString
) || !(SearchRetry
))
2800 /* Not the case, give up completely */
2805 /* There are spaces, so keep trying the next possibility */
2807 NullBuffer
= ScanString
;
2809 /* We will have to add a quote, since there is a space */
2810 QuotesNeeded
= TRUE
;
2815 else if (!(lpCommandLine
) || !(*lpCommandLine
))
2817 /* We don't have a command line, so just use the application name */
2818 CmdLineIsAppName
= TRUE
;
2819 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2822 /* Convert the application name to its NT path */
2823 TranslationStatus
= RtlDosPathNameToRelativeNtPathName_U(lpApplicationName
,
2826 &SxsWin32RelativePath
);
2827 if (!TranslationStatus
)
2829 /* Path must be invaild somehow, bail out */
2830 DPRINT1("Path translation for SxS failed\n");
2831 SetLastError(ERROR_PATH_NOT_FOUND
);
2836 /* Setup the buffer that needs to be freed at the end */
2837 ASSERT(FreeBuffer
== NULL
);
2838 FreeBuffer
= PathName
.Buffer
;
2840 /* Check what kind of path the application is, for SxS (Fusion) purposes */
2841 RtlInitUnicodeString(&SxsWin32ExePath
, lpApplicationName
);
2842 SxsPathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2843 if ((SxsPathType
!= RtlPathTypeDriveAbsolute
) &&
2844 (SxsPathType
!= RtlPathTypeLocalDevice
) &&
2845 (SxsPathType
!= RtlPathTypeRootLocalDevice
) &&
2846 (SxsPathType
!= RtlPathTypeUncAbsolute
))
2848 /* Relative-type path, get the full path */
2849 RtlInitEmptyUnicodeString(&PathBufferString
, NULL
, 0);
2850 Status
= RtlGetFullPathName_UstrEx(&SxsWin32ExePath
,
2858 if (!NT_SUCCESS(Status
))
2860 /* Fail the rest of the create */
2861 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2862 BaseSetLastNTError(Status
);
2867 /* Use this full path as the SxS path */
2868 SxsWin32ExePath
= PathBufferString
;
2869 PathBuffer
= PathBufferString
.Buffer
;
2870 PathBufferString
.Buffer
= NULL
;
2871 DPRINT1("SxS Path: %S\n", PathBuffer
);
2874 /* Also set the .EXE path based on the path name */
2875 #if _SXS_SUPPORT_ENABLED_
2876 SxsNtExePath
= PathName
;
2878 if (SxsWin32RelativePath
.RelativeName
.Length
)
2880 /* If it's relative, capture the relative name */
2881 PathName
= SxsWin32RelativePath
.RelativeName
;
2885 /* Otherwise, it's absolute, make sure no relative dir is used */
2886 SxsWin32RelativePath
.ContainingDirectory
= NULL
;
2889 /* Now use the path name, and the root path, to try opening the app */
2890 DPRINT1("Path: %wZ. Dir: %lx\n", &PathName
, SxsWin32RelativePath
.ContainingDirectory
);
2891 InitializeObjectAttributes(&LocalObjectAttributes
,
2893 OBJ_CASE_INSENSITIVE
,
2894 SxsWin32RelativePath
.ContainingDirectory
,
2896 Status
= NtOpenFile(&FileHandle
,
2898 FILE_READ_ATTRIBUTES
|
2901 &LocalObjectAttributes
,
2903 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2904 FILE_SYNCHRONOUS_IO_NONALERT
|
2905 FILE_NON_DIRECTORY_FILE
);
2906 if (!NT_SUCCESS(Status
))
2908 /* Try to open the app just for execute purposes instead */
2909 Status
= NtOpenFile(&FileHandle
,
2910 SYNCHRONIZE
| FILE_EXECUTE
,
2911 &LocalObjectAttributes
,
2913 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2914 FILE_SYNCHRONOUS_IO_NONALERT
|
2915 FILE_NON_DIRECTORY_FILE
);
2918 /* Cleanup in preparation for failure or success */
2919 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2920 if (!NT_SUCCESS(Status
))
2922 /* Failure path, try to understand why */
2923 DPRINT1("Open file failed: %lx\n", Status
);
2924 if (RtlIsDosDeviceName_U(lpApplicationName
))
2926 /* If a device is being executed, return this special error code */
2927 SetLastError(ERROR_BAD_DEVICE
);
2933 /* Otherwise return the converted NT error code */
2934 BaseSetLastNTError(Status
);
2940 /* Did the caller specify a desktop? */
2941 if (!StartupInfo
.lpDesktop
)
2943 /* Use the one from the current process */
2944 StartupInfo
.lpDesktop
= Peb
->ProcessParameters
->DesktopInfo
.Buffer
;
2947 /* Create a section for this file */
2948 Status
= NtCreateSection(&SectionHandle
,
2955 DPRINT1("Section status: %lx\n", Status
);
2956 if (NT_SUCCESS(Status
))
2958 /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2959 if (SharedUserData
->SuiteMask
& (VER_SUITE_EMBEDDEDNT
|
2960 VER_SUITE_DATACENTER
|
2961 VER_SUITE_PERSONAL
|
2964 /* These SKUs do not allow running certain applications */
2965 Status
= BasepCheckWebBladeHashes(FileHandle
);
2966 if (Status
== STATUS_ACCESS_DENIED
)
2968 /* And this is one of them! */
2969 DPRINT1("Invalid Blade hashes!\n");
2970 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE
);
2975 /* Did we get some other failure? */
2976 if (!NT_SUCCESS(Status
))
2978 /* If we couldn't check the hashes, assume nefariousness */
2979 DPRINT1("Tampered Blade hashes!\n");
2980 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
);
2986 /* Now do Winsafer, etc, checks */
2987 Status
= BasepIsProcessAllowed((LPWSTR
)lpApplicationName
);
2988 if (!NT_SUCCESS(Status
))
2990 /* Fail if we're not allowed to launch the process */
2991 DPRINT1("Process not allowed to launch: %lx\n", Status
);
2992 BaseSetLastNTError(Status
);
2995 NtClose(SectionHandle
);
2996 SectionHandle
= NULL
;
3002 /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
3003 if ((dwCreationFlags
& CREATE_FORCEDOS
) &&
3004 (BaseStaticServerData
->IsWowTaskReady
))
3006 /* This request can't be satisifeed, instead, a separate VDM is needed */
3007 dwCreationFlags
&= ~(CREATE_FORCEDOS
| CREATE_SHARED_WOW_VDM
);
3008 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3010 /* Set a failure code, ask for VDM reservation */
3011 Status
= STATUS_INVALID_IMAGE_WIN_16
;
3012 UseVdmReserve
= TRUE
;
3014 /* Close the current handle */
3015 NtClose(SectionHandle
);
3016 SectionHandle
= NULL
;
3018 /* Don't query the section later */
3019 QuerySection
= FALSE
;
3023 /* Did we already do these checks? */
3024 if (!SkipSaferAndAppCompat
)
3026 /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3027 if ((NT_SUCCESS(Status
)) ||
3028 ((Status
== STATUS_INVALID_IMAGE_NOT_MZ
) &&
3029 !(BaseIsDosApplication(&PathName
, Status
))))
3031 /* Clear the machine type in case of failure */
3034 /* Clean any app compat data that may have accumulated */
3035 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
3036 AppCompatData
= NULL
;
3037 AppCompatSxsData
= NULL
;
3039 /* Do we have a section? */
3042 /* Have we already queried it? */
3046 Status
= STATUS_SUCCESS
;
3050 /* Get some information about the executable */
3051 Status
= NtQuerySection(SectionHandle
,
3052 SectionImageInformation
,
3054 sizeof(ImageInformation
),
3058 /* Do we have section information now? */
3059 if (NT_SUCCESS(Status
))
3061 /* Don't ask for it again, save the machine type */
3062 QuerySection
= TRUE
;
3063 ImageMachine
= ImageInformation
.Machine
;
3067 /* Is there a reason/Shim we shouldn't run this application? */
3068 Status
= BasepCheckBadapp(FileHandle
,
3075 &AppCompatSxsDataSize
,
3077 if (!NT_SUCCESS(Status
))
3079 /* This is usually the status we get back */
3080 DPRINT1("App compat launch failure: %lx\n", Status
);
3081 if (Status
== STATUS_ACCESS_DENIED
)
3083 /* Convert it to something more Win32-specific */
3084 SetLastError(ERROR_CANCELLED
);
3088 /* Some other error */
3089 BaseSetLastNTError(Status
);
3092 /* Did we have a section? */
3096 NtClose(SectionHandle
);
3097 SectionHandle
= NULL
;
3107 //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3109 /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3110 if (!(SkipSaferAndAppCompat
) &&
3111 ~(dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
))
3117 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3118 case STATUS_INVALID_IMAGE_PROTECT
:
3119 case STATUS_INVALID_IMAGE_WIN_16
:
3120 case STATUS_FILE_IS_OFFLINE
:
3121 /* For all DOS, 16-bit, OS/2 images, we do*/
3124 case STATUS_INVALID_IMAGE_NOT_MZ
:
3125 /* For invalid files, we don't, unless it's a .BAT file */
3126 if (BaseIsDosApplication(&PathName
, Status
)) break;
3129 /* Any other error codes we also don't */
3130 if (!NT_SUCCESS(Status
))
3132 SaferNeeded
= FALSE
;
3135 /* But for success, we do */
3139 /* Okay, so what did the checks above result in? */
3142 /* We have to call into the WinSafer library and actually check */
3143 Status
= BasepCheckWinSaferRestrictions(hUserToken
,
3144 (LPWSTR
)lpApplicationName
,
3149 if (Status
== 0xFFFFFFFF)
3151 /* Back in 2003, they didn't have an NTSTATUS for this... */
3152 DPRINT1("WinSafer blocking process launch\n");
3153 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY
);
3158 /* Other status codes are not-Safer related, just convert them */
3159 if (!NT_SUCCESS(Status
))
3161 DPRINT1("Error checking WinSafer: %lx\n", Status
);
3162 BaseSetLastNTError(Status
);
3169 /* The last step is to figure out why the section object was not created */
3172 case STATUS_INVALID_IMAGE_WIN_16
:
3173 /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3174 if (!(dwCreationFlags
& CREATE_FORCEDOS
))
3176 /* Remember that we're launching WOW */
3179 /* Create the VDM environment, it's valid for WOW too */
3180 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3185 DPRINT1("VDM environment for WOW app failed\n");
3189 /* We're going to try this twice, so do a loop */
3192 /* Pick which kind of WOW mode we want to run in */
3193 VdmBinaryType
= (dwCreationFlags
&
3194 CREATE_SEPARATE_WOW_VDM
) ?
3195 BINARY_TYPE_WOW
: BINARY_TYPE_SEPARATE_WOW
;
3197 /* Get all the VDM settings and current status */
3198 Status
= BaseCheckVDM(VdmBinaryType
,
3203 (PCSR_API_MESSAGE
)VdmMsg
,
3209 /* If it worked, no need to try again */
3210 if (NT_SUCCESS(Status
)) break;
3212 /* Check if it's disallowed or if it's our second time */
3213 BaseSetLastNTError(Status
);
3214 if ((Status
== STATUS_VDM_DISALLOWED
) ||
3215 (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
) ||
3216 (GetLastError() == ERROR_ACCESS_DENIED
))
3218 /* Fail the call -- we won't try again */
3219 DPRINT1("VDM message failure for WOW: %lx\n", Status
);
3224 /* Try one more time, but with a separate WOW instance */
3225 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3228 /* Check which VDM state we're currently in */
3229 switch (VdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3233 case VDM_NOT_LOADED
:
3234 /* VDM is not fully loaded, so not that much to undo */
3235 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3237 /* Reset VDM reserve if needed */
3238 if (UseVdmReserve
) VdmReserve
= 1;
3240 /* Get the required parameters and names for launch */
3241 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3248 DPRINT1("VDM Configuration failed for WOW\n");
3249 BaseSetLastNTError(Status
);
3253 /* Update the command-line with the VDM one instead */
3254 lpCommandLine
= VdmString
.Buffer
;
3255 lpApplicationName
= NULL
;
3257 /* We don't want a console, detachment, nor a window */
3258 dwCreationFlags
|= CREATE_NO_WINDOW
;
3259 dwCreationFlags
&= ~(CREATE_NEW_CONSOLE
| DETACHED_PROCESS
);
3261 /* Force feedback on */
3262 StartupInfo
.dwFlags
|= STARTF_FORCEONFEEDBACK
;
3267 /* VDM is ready, so we have to undo everything */
3268 VdmUndoLevel
= VDM_UNDO_REUSE
;
3270 /* Check if CSRSS wants us to wait on VDM */
3271 VdmWaitObject
= VdmMsg
->WaitObjectForParent
;
3275 /* Something is wrong with VDM, we'll fail the call */
3276 DPRINT1("VDM is not ready for WOW\n");
3277 SetLastError(ERROR_NOT_READY
);
3285 /* Since to get NULL, we allocate from 0x1, account for this */
3288 /* This implies VDM is ready, so skip everything else */
3289 if (VdmWaitObject
) goto VdmShortCircuit
;
3291 /* Don't inherit handles since we're doing VDM now */
3292 bInheritHandles
= FALSE
;
3294 /* Had the user passed in environment? If so, destroy it */
3295 if ((lpEnvironment
) &&
3296 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3298 RtlDestroyEnvironment(lpEnvironment
);
3301 /* We've already done all these checks, don't do them again */
3302 SkipSaferAndAppCompat
= TRUE
;
3306 // There is no break here on purpose, so FORCEDOS drops down!
3307 case STATUS_INVALID_IMAGE_PROTECT
:
3308 case STATUS_INVALID_IMAGE_NOT_MZ
:
3309 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3310 /* We're launching an executable application */
3311 BinarySubType
= BINARY_TYPE_EXE
;
3313 /* We can drop here from other "cases" above too, so check */
3314 if ((Status
== STATUS_INVALID_IMAGE_PROTECT
) ||
3315 (Status
== STATUS_INVALID_IMAGE_NE_FORMAT
) ||
3316 (BinarySubType
= BaseIsDosApplication(&PathName
, Status
)))
3318 /* We're launching a DOS application */
3319 VdmBinaryType
= BINARY_TYPE_DOS
;
3321 /* Based on the caller environment, create a VDM one */
3322 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3327 DPRINT1("VDM environment for DOS failed\n");
3331 /* Check the current state of the VDM subsystem */
3332 Status
= BaseCheckVDM(VdmBinaryType
| BinarySubType
,
3337 (PCSR_API_MESSAGE
)VdmMsg
,
3342 if (!NT_SUCCESS(Status
))
3344 /* Failed to inquire about VDM, fail the call */
3345 DPRINT1("VDM message failure for DOS: %lx\n", Status
);
3346 BaseSetLastNTError(Status
);
3351 /* Handle possible VDM states */
3352 switch (VdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3356 case VDM_NOT_LOADED
:
3357 /* If VDM is not loaded, we'll do a partial undo */
3358 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3360 /* A VDM process can't also be detached, so fail */
3361 if (dwCreationFlags
& DETACHED_PROCESS
)
3363 DPRINT1("Detached process but no VDM, not allowed\n");
3364 SetLastError(ERROR_ACCESS_DENIED
);
3368 /* Get the required parameters and names for launch */
3369 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3376 DPRINT1("VDM Configuration failed for DOS\n");
3377 BaseSetLastNTError(Status
);
3381 /* Update the command-line to launch VDM instead */
3382 lpCommandLine
= VdmString
.Buffer
;
3383 lpApplicationName
= NULL
;
3387 /* VDM is ready, so we have to undo everything */
3388 VdmUndoLevel
= VDM_UNDO_REUSE
;
3390 /* Check if CSRSS wants us to wait on VDM */
3391 VdmWaitObject
= VdmMsg
->WaitObjectForParent
;
3395 /* Something is wrong with VDM, we'll fail the call */
3396 DPRINT1("VDM is not ready for DOS\n");
3397 SetLastError(ERROR_NOT_READY
);
3405 /* Since to get NULL, we allocate from 0x1, account for this */
3408 /* This implies VDM is ready, so skip everything else */
3409 if (VdmWaitObject
) goto VdmShortCircuit
;
3411 /* Don't inherit handles since we're doing VDM now */
3412 bInheritHandles
= FALSE
;
3414 /* Had the user passed in environment? If so, destroy it */
3415 if ((lpEnvironment
) &&
3416 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3418 RtlDestroyEnvironment(lpEnvironment
);
3421 /* Use our VDM Unicode environment instead */
3422 lpEnvironment
= VdmUnicodeEnv
.Buffer
;
3426 /* It's a batch file, get the extension */
3427 ExtBuffer
= &PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 4];
3429 /* Make sure the extensions are correct */
3430 if ((PathName
.Length
< (4 * sizeof(WCHAR
))) ||
3431 ((_wcsnicmp(ExtBuffer
, L
".bat", 4)) &&
3432 (_wcsnicmp(ExtBuffer
, L
".cmd", 4))))
3434 DPRINT1("Invalid EXE, and not a batch or script file\n");
3435 SetLastError(ERROR_BAD_EXE_FORMAT
);
3440 /* Check if we need to account for quotes around the path */
3441 CmdQuoteLength
= CmdLineIsAppName
|| HasQuotes
;
3442 if (!CmdLineIsAppName
)
3444 if (HasQuotes
) CmdQuoteLength
++;
3451 /* Calculate the length of the command line */
3452 CmdLineLength
= wcslen(lpCommandLine
);
3453 CmdLineLength
+= wcslen(CMD_STRING
);
3454 CmdLineLength
+= CmdQuoteLength
+ sizeof(ANSI_NULL
);
3455 CmdLineLength
*= sizeof(WCHAR
);
3457 /* Allocate space for the new command line */
3458 AnsiCmdCommand
= RtlAllocateHeap(RtlGetProcessHeap(),
3461 if (!AnsiCmdCommand
)
3463 BaseSetLastNTError(STATUS_NO_MEMORY
);
3469 wcscpy(AnsiCmdCommand
, CMD_STRING
);
3470 if ((CmdLineIsAppName
) || (HasQuotes
))
3472 wcscat(AnsiCmdCommand
, L
"\"");
3474 wcscat(AnsiCmdCommand
, lpCommandLine
);
3475 if ((CmdLineIsAppName
) || (HasQuotes
))
3477 wcscat(AnsiCmdCommand
, L
"\"");
3480 /* Create it as a Unicode String */
3481 RtlInitUnicodeString(&DebuggerString
, AnsiCmdCommand
);
3483 /* Set the command line to this */
3484 lpCommandLine
= DebuggerString
.Buffer
;
3485 lpApplicationName
= NULL
;
3486 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3489 /* We've already done all these checks, don't do them again */
3490 SkipSaferAndAppCompat
= TRUE
;
3493 case STATUS_INVALID_IMAGE_WIN_64
:
3494 /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3495 DPRINT1("64-bit binary, failing\n");
3496 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3500 case STATUS_FILE_IS_OFFLINE
:
3501 /* Set the correct last error for this */
3502 DPRINT1("File is offline, failing\n");
3503 SetLastError(ERROR_FILE_OFFLINE
);
3507 /* Any other error, convert it to a generic Win32 error */
3508 if (!NT_SUCCESS(Status
))
3510 DPRINT1("Failed to create section: %lx\n", Status
);
3511 SetLastError(ERROR_BAD_EXE_FORMAT
);
3516 /* Otherwise, this must be success */
3517 ASSERT(Status
== STATUS_SUCCESS
);
3521 /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3522 if (!(IsWowApp
) && (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
3524 /* Ignore the nonsensical request */
3525 dwCreationFlags
&= ~CREATE_SEPARATE_WOW_VDM
;
3528 /* Did we already check information for the section? */
3531 /* Get some information about the executable */
3532 Status
= NtQuerySection(SectionHandle
,
3533 SectionImageInformation
,
3535 sizeof(ImageInformation
),
3537 if (!NT_SUCCESS(Status
))
3539 /* We failed, bail out */
3540 DPRINT1("Section query failed\n");
3541 BaseSetLastNTError(Status
);
3546 /* Don't check this later */
3547 QuerySection
= TRUE
;
3550 /* Check if this was linked as a DLL */
3551 if (ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3553 /* These aren't valid images to try to execute! */
3554 DPRINT1("Trying to launch a DLL, failing\n");
3555 SetLastError(ERROR_BAD_EXE_FORMAT
);
3560 /* Don't let callers pass in this flag -- we'll only get it from IFRO */
3561 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3563 /* Clear the IFEO-missing flag, before we know for sure... */
3564 ParameterFlags
&= ~2;
3566 /* If the process is being debugged, only read IFEO if the PEB says so */
3567 if (!(dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
)) ||
3568 (NtCurrentPeb()->ReadImageFileExecOptions
))
3570 /* Let's do this! Attempt to open IFEO */
3571 Status1
= LdrOpenImageFileOptionsKey(&PathName
, 0, &KeyHandle
);
3572 if (!NT_SUCCESS(Status1
))
3574 /* We failed, set the flag so we store this in the parameters */
3575 if (Status1
== STATUS_OBJECT_NAME_NOT_FOUND
) ParameterFlags
|= 2;
3579 /* Was this our first time going through this path? */
3580 if (!DebuggerCmdLine
)
3582 /* Allocate a buffer for the debugger path */
3583 DebuggerCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3585 MAX_PATH
* sizeof(WCHAR
));
3586 if (!DebuggerCmdLine
)
3588 /* Close IFEO on failure */
3589 Status1
= NtClose(KeyHandle
);
3590 ASSERT(NT_SUCCESS(Status1
));
3593 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3599 /* Now query for the debugger */
3600 Status1
= LdrQueryImageFileKeyOption(KeyHandle
,
3604 MAX_PATH
* sizeof(WCHAR
),
3606 if (!(NT_SUCCESS(Status1
)) ||
3607 (ResultSize
< sizeof(WCHAR
)) ||
3608 (DebuggerCmdLine
[0] == UNICODE_NULL
))
3610 /* If it's not there, or too small, or invalid, ignore it */
3611 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3612 DebuggerCmdLine
= NULL
;
3615 /* Also query if we should map with large pages */
3616 Status1
= LdrQueryImageFileKeyOption(KeyHandle
,
3620 sizeof(UseLargePages
),
3622 if ((NT_SUCCESS(Status1
)) && (UseLargePages
))
3624 /* Do it! This is the only way this flag can be set */
3625 Flags
|= PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3628 /* We're done with IFEO, can close it now */
3629 Status1
= NtClose(KeyHandle
);
3630 ASSERT(NT_SUCCESS(Status1
));
3634 /* Make sure the image was compiled for this processor */
3635 if ((ImageInformation
.Machine
< SharedUserData
->ImageNumberLow
) ||
3636 (ImageInformation
.Machine
> SharedUserData
->ImageNumberHigh
))
3638 /* It was not -- raise a hard error */
3639 ErrorResponse
= ResponseOk
;
3640 ErrorParameters
[0] = (ULONG_PTR
)&PathName
;
3641 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
,
3647 if (Peb
->ImageSubsystemMajorVersion
<= 3)
3649 /* If it's really old, return this error */
3650 SetLastError(ERROR_BAD_EXE_FORMAT
);
3654 /* Otherwise, return a more modern error */
3655 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3658 /* Go to the failure path */
3659 DPRINT1("Invalid image architecture: %lx\n", ImageInformation
.Machine
);
3664 /* Check if this isn't a Windows image */
3665 if ((ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_GUI
) &&
3666 (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_CUI
))
3668 /* Get rid of section-related information since we'll retry */
3669 NtClose(SectionHandle
);
3670 SectionHandle
= NULL
;
3671 QuerySection
= FALSE
;
3673 /* The only other non-Windows image type we support here is POSIX */
3674 if (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_POSIX_CUI
)
3676 /* Bail out if it's something else */
3677 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
3682 /* Now build the command-line to have posix launch this image */
3683 Result
= BuildSubSysCommandLine(L
"POSIX /P ",
3689 /* Bail out if that failed */
3690 DPRINT1("Subsystem command line failed\n");
3694 /* And re-try launching the process, with the new command-line now */
3695 lpCommandLine
= DebuggerString
.Buffer
;
3696 lpApplicationName
= NULL
;
3698 /* We've already done all these checks, don't do them again */
3699 SkipSaferAndAppCompat
= TRUE
;
3700 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3704 /* Was this image built for a version of Windows whose images we can run? */
3705 Result
= BasepIsImageVersionOk(ImageInformation
.SubSystemMajorVersion
,
3706 ImageInformation
.SubSystemMinorVersion
);
3709 /* It was not, bail out */
3710 DPRINT1("Invalid subsystem version: %d.%d\n",
3711 ImageInformation
.SubSystemMajorVersion
,
3712 ImageInformation
.SubSystemMinorVersion
);
3713 SetLastError(ERROR_BAD_EXE_FORMAT
);
3717 /* Check if there is a debugger associated with the application */
3718 if (DebuggerCmdLine
)
3720 /* Get the length of the command line */
3721 n
= wcslen(lpCommandLine
);
3724 /* There's no command line, use the application name instead */
3725 lpCommandLine
= (LPWSTR
)lpApplicationName
;
3726 n
= wcslen(lpCommandLine
);
3729 /* Protect against overflow */
3730 if (n
> UNICODE_STRING_MAX_CHARS
)
3732 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3737 /* Now add the length of the debugger command-line */
3738 n
+= wcslen(DebuggerCmdLine
);
3740 /* Again make sure we don't overflow */
3741 if (n
> UNICODE_STRING_MAX_CHARS
)
3743 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3748 /* Account for the quotes and space between the two */
3749 n
+= ((sizeof('""') * 2) + sizeof(' '));
3751 /* Convert to bytes, and make sure we don't overflow */
3753 if (n
> UNICODE_STRING_MAX_BYTES
)
3755 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3760 /* Allocate space for the string */
3761 DebuggerString
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, n
);
3762 if (!DebuggerString
.Buffer
)
3764 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3769 /* Set the length */
3770 RtlInitEmptyUnicodeString(&DebuggerString
,
3771 DebuggerString
.Buffer
,
3774 /* Now perform the command line creation */
3775 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
,
3777 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3778 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, L
" ");
3779 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3780 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, lpCommandLine
);
3781 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3783 /* Make sure it all looks nice */
3784 DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString
);
3786 /* Update the command line and application name */
3787 lpCommandLine
= DebuggerString
.Buffer
;
3788 lpApplicationName
= NULL
;
3790 /* Close all temporary state */
3791 NtClose(SectionHandle
);
3792 SectionHandle
= NULL
;
3793 QuerySection
= FALSE
;
3795 /* Free all temporary memory */
3796 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3798 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
3800 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3801 DebuggerCmdLine
= NULL
;
3802 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3806 /* Initialize the process object attributes */
3807 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3808 lpProcessAttributes
,
3810 if ((hUserToken
) && (lpProcessAttributes
))
3812 /* Auggment them with information from the user */
3814 LocalProcessAttributes
= *lpProcessAttributes
;
3815 LocalProcessAttributes
.lpSecurityDescriptor
= NULL
;
3816 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3817 &LocalProcessAttributes
,
3821 /* Check if we're going to be debugged */
3822 if (dwCreationFlags
& DEBUG_PROCESS
)
3824 /* Set process flag */
3825 Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
3828 /* Check if we're going to be debugged */
3829 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3831 /* Connect to DbgUi */
3832 Status
= DbgUiConnectToDbg();
3833 if (!NT_SUCCESS(Status
))
3835 DPRINT1("Failed to connect to DbgUI!\n");
3836 BaseSetLastNTError(Status
);
3841 /* Get the debug object */
3842 DebugHandle
= DbgUiGetThreadDebugObject();
3844 /* Check if only this process will be debugged */
3845 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3847 /* Set process flag */
3848 Flags
|= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
;
3852 /* Set inherit flag */
3853 if (bInheritHandles
) Flags
|= PROCESS_CREATE_FLAGS_INHERIT_HANDLES
;
3855 /* Check if the process should be created with large pages */
3856 HavePrivilege
= FALSE
;
3857 PrivilegeState
= NULL
;
3858 if (Flags
& PROCESS_CREATE_FLAGS_LARGE_PAGES
)
3860 /* Acquire the required privilege so that the kernel won't fail the call */
3861 PrivilegeValue
= SE_LOCK_MEMORY_PRIVILEGE
;
3862 Status
= RtlAcquirePrivilege(&PrivilegeValue
, TRUE
, FALSE
, &PrivilegeState
);
3863 if (NT_SUCCESS(Status
))
3865 /* Remember to release it later */
3866 HavePrivilege
= TRUE
;
3870 /* Save the current TIB value since kernel overwrites it to store PEB */
3871 TibValue
= Teb
->NtTib
.ArbitraryUserPointer
;
3873 /* Tell the kernel to create the process */
3874 Status
= NtCreateProcessEx(&ProcessHandle
,
3884 /* Load the PEB address from the hacky location where the kernel stores it */
3885 RemotePeb
= Teb
->NtTib
.ArbitraryUserPointer
;
3887 /* And restore the old TIB value */
3888 Teb
->NtTib
.ArbitraryUserPointer
= TibValue
;
3890 /* Release the large page privilege if we had acquired it */
3891 if (HavePrivilege
) RtlReleasePrivilege(PrivilegeState
);
3893 /* And now check if the kernel failed to create the process */
3894 if (!NT_SUCCESS(Status
))
3896 /* Go to failure path */
3897 DPRINT1("Failed to create process: %lx\n", Status
);
3898 BaseSetLastNTError(Status
);
3903 /* Check if there is a priority class to set */
3904 if (PriorityClass
.PriorityClass
)
3906 /* Reset current privilege state */
3907 RealTimePrivilegeState
= NULL
;
3909 /* Is realtime priority being requested? */
3910 if (PriorityClass
.PriorityClass
== REALTIME_PRIORITY_CLASS
)
3912 /* Check if the caller has real-time access, and enable it if so */
3913 RealTimePrivilegeState
= BasepIsRealtimeAllowed(TRUE
);
3916 /* Set the new priority class and release the privilege */
3917 Status
= NtSetInformationProcess(ProcessHandle
,
3918 ProcessPriorityClass
,
3920 sizeof(PROCESS_PRIORITY_CLASS
));
3921 if (RealTimePrivilegeState
) RtlReleasePrivilege(RealTimePrivilegeState
);
3923 /* Check if we failed to set the priority class */
3924 if (!NT_SUCCESS(Status
))
3926 /* Bail out on failure */
3927 DPRINT1("Failed to set priority class: %lx\n", Status
);
3928 BaseSetLastNTError(Status
);
3934 /* Check if the caller wants the default error mode */
3935 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3937 /* Set Error Mode to only fail on critical errors */
3938 HardErrorMode
= SEM_FAILCRITICALERRORS
;
3939 NtSetInformationProcess(ProcessHandle
,
3940 ProcessDefaultHardErrorMode
,
3945 /* Check if this was a VDM binary */
3948 /* Update VDM by telling it the process has now been created */
3949 VdmWaitObject
= ProcessHandle
;
3950 Result
= BaseUpdateVDMEntry(VdmEntryUpdateProcess
,
3955 /* Bail out on failure */
3956 DPRINT1("Failed to update VDM with wait object\n");
3957 VdmWaitObject
= NULL
;
3961 /* At this point, a failure means VDM has to undo all the state */
3962 VdmUndoLevel
|= VDM_UNDO_FULL
;
3965 /* Check if VDM needed reserved low-memory */
3968 /* Reserve the requested allocation */
3969 Status
= NtAllocateVirtualMemory(ProcessHandle
,
3974 PAGE_EXECUTE_READWRITE
);
3975 if (!NT_SUCCESS(Status
))
3977 /* Bail out on failure */
3978 DPRINT1("Failed to reserved memory for VDM: %lx\n", Status
);
3979 BaseSetLastNTError(Status
);
3985 /* Check if we've already queried information on the section */
3988 /* We haven't, so get some information about the executable */
3989 Status
= NtQuerySection(SectionHandle
,
3990 SectionImageInformation
,
3992 sizeof(ImageInformation
),
3994 if (!NT_SUCCESS(Status
))
3996 /* Bail out on failure */
3997 DPRINT1("Failed to query section: %lx\n", Status
);
3998 BaseSetLastNTError(Status
);
4003 /* If we encounter a restart, don't re-query this information again */
4004 QuerySection
= TRUE
;
4007 /* Do we need to apply SxS to this image? */
4008 if (!(ImageInformation
.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
))
4010 /* Too bad, we don't support this yet */
4011 DPRINT1("Image should receive SxS Fusion Isolation\n");
4014 /* There's some SxS flag that we need to set if fusion flags have 1 set */
4015 if (FusionFlags
& 1) CreateProcessMsg
->Sxs
.Flags
|= 0x10;
4017 /* Check if we have a current directory */
4018 if (lpCurrentDirectory
)
4020 /* Allocate a buffer so we can keep a Unicode copy */
4021 DPRINT1("Current directory: %S\n", lpCurrentDirectory
);
4022 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
4024 (MAX_PATH
* sizeof(WCHAR
)) +
4025 sizeof(UNICODE_NULL
));
4026 if (!CurrentDirectory
)
4028 /* Bail out if this failed */
4029 BaseSetLastNTError(STATUS_NO_MEMORY
);
4034 /* Get the length in Unicode */
4035 Length
= GetFullPathNameW(lpCurrentDirectory
,
4039 if (Length
> MAX_PATH
)
4041 /* The directory is too long, so bail out */
4042 SetLastError(ERROR_DIRECTORY
);
4047 /* Make sure the directory is actually valid */
4048 CurdirLength
= GetFileAttributesW(CurrentDirectory
);
4049 if ((CurdirLength
== 0xffffffff) ||
4050 !(CurdirLength
& FILE_ATTRIBUTE_DIRECTORY
))
4052 /* It isn't, so bail out */
4053 DPRINT1("Current directory is invalid\n");
4054 SetLastError(ERROR_DIRECTORY
);
4060 /* Insert quotes if needed */
4061 if ((QuotesNeeded
) || (CmdLineIsAppName
))
4063 /* Allocate our buffer, plus enough space for quotes and a NULL */
4064 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
4066 (wcslen(lpCommandLine
) * sizeof(WCHAR
)) +
4067 (2 * sizeof(L
'\"') + sizeof(UNICODE_NULL
)));
4070 /* Copy the first quote */
4071 wcscpy(QuotedCmdLine
, L
"\"");
4073 /* Save the current null-character */
4076 SaveChar
= *NullBuffer
;
4077 *NullBuffer
= UNICODE_NULL
;
4080 /* Copy the command line and the final quote */
4081 wcscat(QuotedCmdLine
, lpCommandLine
);
4082 wcscat(QuotedCmdLine
, L
"\"");
4084 /* Copy the null-char back */
4087 *NullBuffer
= SaveChar
;
4088 wcscat(QuotedCmdLine
, NullBuffer
);
4093 /* We can't put quotes around the thing, so try it anyway */
4094 if (QuotesNeeded
) QuotesNeeded
= FALSE
;
4095 if (CmdLineIsAppName
) CmdLineIsAppName
= FALSE
;
4099 /* Use isolation if needed */
4100 if (CreateProcessMsg
->Sxs
.Flags
& 1) ParameterFlags
|= 1;
4102 /* Set the new command-line if needed */
4103 if ((QuotesNeeded
) || (CmdLineIsAppName
)) lpCommandLine
= QuotedCmdLine
;
4105 /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
4106 Result
= BasePushProcessParameters(ParameterFlags
,
4114 dwCreationFlags
| NoWindow
,
4116 IsWowApp
? IMAGE_SUBSYSTEM_WINDOWS_GUI
: 0,
4121 /* The remote process would have an undefined state, so fail the call */
4122 DPRINT1("BasePushProcessParameters failed\n");
4126 /* Free the VDM command line string as it's no longer needed */
4127 RtlFreeUnicodeString(&VdmString
);
4128 VdmString
.Buffer
= NULL
;
4130 /* Non-VDM console applications usually inherit handles unless specified */
4131 if (!(VdmBinaryType
) &&
4132 !(bInheritHandles
) &&
4133 !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
4134 !(dwCreationFlags
& (CREATE_NO_WINDOW
|
4135 CREATE_NEW_CONSOLE
|
4136 DETACHED_PROCESS
)) &&
4137 (ImageInformation
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
))
4139 /* Get the remote parameters */
4140 Status
= NtReadVirtualMemory(ProcessHandle
,
4141 &RemotePeb
->ProcessParameters
,
4143 sizeof(PRTL_USER_PROCESS_PARAMETERS
),
4145 if (NT_SUCCESS(Status
))
4147 /* Duplicate standard input unless it's a console handle */
4148 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
))
4150 StuffStdHandle(ProcessHandle
,
4151 Peb
->ProcessParameters
->StandardInput
,
4152 &ProcessParameters
->StandardInput
);
4155 /* Duplicate standard output unless it's a console handle */
4156 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
))
4158 StuffStdHandle(ProcessHandle
,
4159 Peb
->ProcessParameters
->StandardOutput
,
4160 &ProcessParameters
->StandardOutput
);
4163 /* Duplicate standard error unless it's a console handle */
4164 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardError
))
4166 StuffStdHandle(ProcessHandle
,
4167 Peb
->ProcessParameters
->StandardError
,
4168 &ProcessParameters
->StandardError
);
4173 /* Create the Thread's Stack */
4174 StackSize
= max(256 * 1024, ImageInformation
.MaximumStackSize
);
4175 Status
= BaseCreateStack(ProcessHandle
,
4176 ImageInformation
.CommittedStackSize
,
4179 if (!NT_SUCCESS(Status
))
4181 DPRINT1("Creating the thread stack failed: %lx\n", Status
);
4182 BaseSetLastNTError(Status
);
4187 /* Create the Thread's Context */
4188 BaseInitializeContext(&Context
,
4190 ImageInformation
.TransferAddress
,
4191 InitialTeb
.StackBase
,
4194 /* Convert the thread attributes */
4195 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4198 if ((hUserToken
) && (lpThreadAttributes
))
4200 /* If the caller specified a user token, zero the security descriptor */
4201 LocalThreadAttributes
= *lpThreadAttributes
;
4202 LocalThreadAttributes
.lpSecurityDescriptor
= NULL
;
4203 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4204 &LocalThreadAttributes
,
4208 /* Create the Kernel Thread Object */
4209 Status
= NtCreateThread(&ThreadHandle
,
4217 if (!NT_SUCCESS(Status
))
4219 /* A process is not allowed to exist without a main thread, so fail */
4220 DPRINT1("Creating the main thread failed: %lx\n", Status
);
4221 BaseSetLastNTError(Status
);
4226 /* Begin filling out the CSRSS message, first with our IDs and handles */
4227 CreateProcessMsg
->ProcessHandle
= ProcessHandle
;
4228 CreateProcessMsg
->ThreadHandle
= ThreadHandle
;
4229 CreateProcessMsg
->ClientId
= ClientId
;
4231 /* Write the remote PEB address and clear it locally, we no longer use it */
4232 CreateProcessMsg
->PebAddressNative
= RemotePeb
;
4233 CreateProcessMsg
->PebAddressWow64
= (ULONG
)RemotePeb
;
4236 /* Now check what kind of architecture this image was made for */
4237 switch (ImageInformation
.Machine
)
4239 /* IA32, IA64 and AMD64 are supported in Server 2003 */
4240 case IMAGE_FILE_MACHINE_I386
:
4241 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_INTEL
;
4243 case IMAGE_FILE_MACHINE_IA64
:
4244 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_IA64
;
4246 case IMAGE_FILE_MACHINE_AMD64
:
4247 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_AMD64
;
4250 /* Anything else results in image unknown -- but no failure */
4252 DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
4253 ImageInformation
.Machine
);
4254 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_UNKNOWN
;
4258 /* Write the input creation flags except any debugger-related flags */
4259 CreateProcessMsg
->CreationFlags
= dwCreationFlags
&
4260 ~(DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
);
4262 /* CSRSS needs to know if this is a GUI app or not */
4263 if ((ImageInformation
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_GUI
) ||
4266 /* Some flag sent to CSRSS, not sure for what purpose */
4267 AddToHandle(CreateProcessMsg
->ProcessHandle
, 2);
4269 /* Also check if the parent is also a GUI process */
4270 NtHeaders
= RtlImageNtHeader(GetModuleHandle(NULL
));
4272 (NtHeaders
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
))
4274 /* Let it know that it should dislay the hourglass mouse cursor */
4275 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4279 /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
4280 if (StartupInfo
.dwFlags
& STARTF_FORCEONFEEDBACK
)
4282 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4285 /* Likewise, the opposite holds as well */
4286 if (StartupInfo
.dwFlags
& STARTF_FORCEOFFFEEDBACK
)
4288 RemoveFromHandle(CreateProcessMsg
->ProcessHandle
, 1);
4291 /* Also store which kind of VDM app (if any) this is */
4292 CreateProcessMsg
->VdmBinaryType
= VdmBinaryType
;
4294 /* And if it really is a VDM app... */
4297 /* Store the task ID and VDM console handle */
4298 CreateProcessMsg
->hVDM
= VdmTask
? 0 : Peb
->ProcessParameters
->ConsoleHandle
;
4299 CreateProcessMsg
->VdmTask
= VdmTask
;
4301 else if (VdmReserve
)
4303 /* Extended VDM, set a flag */
4304 CreateProcessMsg
->VdmBinaryType
|= BINARY_TYPE_WOW_EX
;
4307 /* Check if there's side-by-side assembly data associated with the process */
4308 if (CreateProcessMsg
->Sxs
.Flags
)
4310 /* This should not happen in ReactOS yet */
4311 DPRINT1("This is an SxS Message -- should not happen yet\n");
4312 BaseSetLastNTError(STATUS_NOT_IMPLEMENTED
);
4313 NtTerminateProcess(ProcessHandle
, STATUS_NOT_IMPLEMENTED
);
4318 /* We are finally ready to call CSRSS to tell it about our new process! */
4319 CsrClientCallServer((PCSR_API_MESSAGE
)&CsrMsg
,
4321 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
,
4322 BasepCreateProcess
),
4323 sizeof(*CreateProcessMsg
));
4325 /* CSRSS has returned, free the capture buffer now if we had one */
4328 CsrFreeCaptureBuffer(CaptureBuffer
);
4329 CaptureBuffer
= NULL
;
4332 /* Check if CSRSS failed to accept ownership of the new Windows process */
4333 if (!NT_SUCCESS(CsrMsg
.Status
))
4335 /* Terminate the process and enter failure path with the CSRSS status */
4336 DPRINT1("Failed to tell csrss about new process\n");
4337 BaseSetLastNTError(CsrMsg
.Status
);
4338 NtTerminateProcess(ProcessHandle
, CsrMsg
.Status
);
4343 /* Check if we have a token due to Authz/Safer, not passed by the user */
4344 if ((TokenHandle
) && !(hUserToken
))
4346 /* Replace the process and/or thread token with the one from Safer */
4347 Status
= BasepReplaceProcessThreadTokens(TokenHandle
,
4350 if (!NT_SUCCESS(Status
))
4352 /* If this failed, kill the process and enter the failure path */
4353 DPRINT1("Failed to update process token: %lx\n", Status
);
4354 NtTerminateProcess(ProcessHandle
, Status
);
4355 BaseSetLastNTError(Status
);
4361 /* Check if a job was associated with this process */
4364 /* Bind the process and job together now */
4365 Status
= NtAssignProcessToJobObject(JobHandle
, ProcessHandle
);
4366 if (!NT_SUCCESS(Status
))
4368 /* Kill the process and enter the failure path if binding failed */
4369 DPRINT1("Failed to assign process to job: %lx\n", Status
);
4370 NtTerminateProcess(ProcessHandle
, STATUS_ACCESS_DENIED
);
4371 BaseSetLastNTError(Status
);
4377 /* Finally, resume the thread to actually get the process started */
4378 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
4380 NtResumeThread(ThreadHandle
, &ResumeCount
);
4384 /* We made it this far, meaning we have a fully created process and thread */
4387 /* Anyone doing a VDM undo should now undo everything, since we are done */
4388 if (VdmUndoLevel
) VdmUndoLevel
|= VDM_UNDO_COMPLETED
;
4390 /* Having a VDM wait object implies this must be a VDM process */
4393 /* Check if it's a 16-bit separate WOW process */
4394 if (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
)
4396 /* OR-in the special flag to indicate this, and return to caller */
4397 AddToHandle(VdmWaitObject
, 2);
4398 lpProcessInformation
->hProcess
= VdmWaitObject
;
4400 /* Check if this was a re-used VDM */
4401 if (VdmUndoLevel
& VDM_UNDO_REUSE
)
4403 /* No Client ID should be returned in this case */
4404 ClientId
.UniqueProcess
= 0;
4405 ClientId
.UniqueThread
= 0;
4410 /* OR-in the special flag to indicate this is not a separate VDM */
4411 AddToHandle(VdmWaitObject
, 1);
4413 /* Return handle to the caller */
4414 lpProcessInformation
->hProcess
= VdmWaitObject
;
4417 /* Close the original process handle, since it's not needed for VDM */
4418 if (ProcessHandle
) NtClose(ProcessHandle
);
4422 /* This is a regular process, so return the real process handle */
4423 lpProcessInformation
->hProcess
= ProcessHandle
;
4426 /* Return the rest of the process information based on what we have so far */
4427 lpProcessInformation
->hThread
= ThreadHandle
;
4428 lpProcessInformation
->dwProcessId
= HandleToUlong(ClientId
.UniqueProcess
);
4429 lpProcessInformation
->dwThreadId
= HandleToUlong(ClientId
.UniqueThread
);
4431 /* NULL these out here so we know to treat this as a success scenario */
4432 ProcessHandle
= NULL
;
4433 ThreadHandle
= NULL
;
4436 /* Free the debugger command line if one was allocated */
4437 if (DebuggerCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
4439 /* Check if an SxS full path as queried */
4442 /* Reinitialize the executable path */
4443 RtlInitEmptyUnicodeString(&SxsWin32ExePath
, NULL
, 0);
4444 SxsWin32ExePath
.Length
= 0;
4446 /* Free the path buffer */
4447 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
4450 #if _SXS_SUPPORT_ENABLED_
4451 /* Check if this was a non-VDM process */
4454 /* Then it must've had SxS data, so close the handles used for it */
4455 BasepSxsCloseHandles(&Handles
);
4456 BasepSxsCloseHandles(&FileHandles
);
4458 /* Check if we built SxS byte buffers for this create process request */
4459 if (SxsConglomeratedBuffer
)
4461 /* Loop all of them */
4462 for (i
= 0; i
< 5; i
++)
4464 /* Check if this one was allocated */
4465 ThisBuffer
= SxsStaticBuffers
[i
];
4468 /* Get the underlying RTL_BUFFER structure */
4469 ByteBuffer
= &ThisBuffer
->ByteBuffer
;
4470 if ((ThisBuffer
!= (PVOID
)-8) && (ByteBuffer
->Buffer
))
4472 /* Check if it was dynamic */
4473 if (ByteBuffer
->Buffer
!= ByteBuffer
->StaticBuffer
)
4475 /* Free it from the heap */
4476 FreeString
.Buffer
= (PWCHAR
)ByteBuffer
->Buffer
;
4477 RtlFreeUnicodeString(&FreeString
);
4480 /* Reset the buffer to its static data */
4481 ByteBuffer
->Buffer
= ByteBuffer
->StaticBuffer
;
4482 ByteBuffer
->Size
= ByteBuffer
->StaticSize
;
4485 /* Reset the string to the static buffer */
4486 RtlInitEmptyUnicodeString(&ThisBuffer
->String
,
4487 (PWCHAR
)ByteBuffer
->StaticBuffer
,
4488 ByteBuffer
->StaticSize
);
4489 if (ThisBuffer
->String
.Buffer
)
4491 /* Also NULL-terminate it */
4492 *ThisBuffer
->String
.Buffer
= UNICODE_NULL
;
4499 /* Check if an environment was passed in */
4500 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
4503 RtlDestroyEnvironment(lpEnvironment
);
4505 /* If this was the VDM environment too, clear that as well */
4506 if (VdmUnicodeEnv
.Buffer
== lpEnvironment
) VdmUnicodeEnv
.Buffer
= NULL
;
4507 lpEnvironment
= NULL
;
4510 /* Unconditionally free all the name parsing buffers we always allocate */
4511 RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
4512 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
4513 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
4514 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
4516 /* Close open file/section handles */
4517 if (FileHandle
) NtClose(FileHandle
);
4518 if (SectionHandle
) NtClose(SectionHandle
);
4520 /* If we have a thread handle, this was a failure path */
4523 /* So kill the process and close the thread handle */
4524 NtTerminateProcess(ProcessHandle
, 0);
4525 NtClose(ThreadHandle
);
4528 /* If we have a process handle, this was a failure path, so close it */
4529 if (ProcessHandle
) NtClose(ProcessHandle
);
4531 /* Thread/process handles, if any, are now processed. Now close this one. */
4532 if (JobHandle
) NtClose(JobHandle
);
4534 /* Check if we had created a token */
4537 /* And if the user asked for one */
4540 /* Then return it */
4541 *hNewToken
= TokenHandle
;
4545 /* User didn't want it, so we used it temporarily -- close it */
4546 NtClose(TokenHandle
);
4550 /* Free any temporary app compatibility data, it's no longer needed */
4551 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
4553 /* Free a few strings. The API takes care of these possibly being NULL */
4554 RtlFreeUnicodeString(&VdmString
);
4555 RtlFreeUnicodeString(&DebuggerString
);
4557 /* Check if we had built any sort of VDM environment */
4558 if ((VdmAnsiEnv
.Buffer
) || (VdmUnicodeEnv
.Buffer
))
4561 BaseDestroyVDMEnvironment(&VdmAnsiEnv
, &VdmUnicodeEnv
);
4564 /* Check if this was any kind of VDM application that we ended up creating */
4565 if ((VdmUndoLevel
) && (!(VdmUndoLevel
& VDM_UNDO_COMPLETED
)))
4568 BaseUpdateVDMEntry(VdmEntryUndo
,
4573 /* And close whatever VDM handle we were using for notifications */
4574 if (VdmWaitObject
) NtClose(VdmWaitObject
);
4577 /* Check if we ended up here with an allocated search path, and free it */
4578 if (SearchPath
) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
4580 /* Finally, return the API's result */
4589 CreateProcessW(LPCWSTR lpApplicationName
,
4590 LPWSTR lpCommandLine
,
4591 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4592 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4593 BOOL bInheritHandles
,
4594 DWORD dwCreationFlags
,
4595 LPVOID lpEnvironment
,
4596 LPCWSTR lpCurrentDirectory
,
4597 LPSTARTUPINFOW lpStartupInfo
,
4598 LPPROCESS_INFORMATION lpProcessInformation
)
4600 /* Call the internal (but exported) version */
4601 return CreateProcessInternalW(NULL
,
4604 lpProcessAttributes
,
4611 lpProcessInformation
,
4620 CreateProcessInternalA(HANDLE hToken
,
4621 LPCSTR lpApplicationName
,
4622 LPSTR lpCommandLine
,
4623 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4624 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4625 BOOL bInheritHandles
,
4626 DWORD dwCreationFlags
,
4627 LPVOID lpEnvironment
,
4628 LPCSTR lpCurrentDirectory
,
4629 LPSTARTUPINFOA lpStartupInfo
,
4630 LPPROCESS_INFORMATION lpProcessInformation
,
4633 PUNICODE_STRING CommandLine
= NULL
;
4634 UNICODE_STRING DummyString
;
4635 UNICODE_STRING LiveCommandLine
;
4636 UNICODE_STRING ApplicationName
;
4637 UNICODE_STRING CurrentDirectory
;
4639 STARTUPINFOW StartupInfo
;
4641 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
4642 "lpStartupInfo %x, lpProcessInformation %x\n",
4643 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
4644 lpStartupInfo
, lpProcessInformation
);
4646 /* Copy Startup Info */
4647 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
4649 /* Initialize all strings to nothing */
4650 LiveCommandLine
.Buffer
= NULL
;
4651 DummyString
.Buffer
= NULL
;
4652 ApplicationName
.Buffer
= NULL
;
4653 CurrentDirectory
.Buffer
= NULL
;
4654 StartupInfo
.lpDesktop
= NULL
;
4655 StartupInfo
.lpReserved
= NULL
;
4656 StartupInfo
.lpTitle
= NULL
;
4658 /* Convert the Command line */
4661 /* If it's too long, then we'll have a problem */
4662 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
4663 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
4665 /* Cache it in the TEB */
4666 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
4670 /* Use a dynamic version */
4671 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
4677 /* The logic below will use CommandLine, so we must make it valid */
4678 CommandLine
= &DummyString
;
4681 /* Convert the Name and Directory */
4682 if (lpApplicationName
)
4684 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
4687 if (lpCurrentDirectory
)
4689 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
4690 lpCurrentDirectory
);
4693 /* Now convert Startup Strings */
4694 if (lpStartupInfo
->lpReserved
)
4696 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
4697 &StartupInfo
.lpReserved
);
4699 if (lpStartupInfo
->lpDesktop
)
4701 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
4702 &StartupInfo
.lpDesktop
);
4704 if (lpStartupInfo
->lpTitle
)
4706 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
4707 &StartupInfo
.lpTitle
);
4710 /* Call the Unicode function */
4711 bRetVal
= CreateProcessInternalW(hToken
,
4712 ApplicationName
.Buffer
,
4713 LiveCommandLine
.Buffer
?
4714 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
4715 lpProcessAttributes
,
4720 CurrentDirectory
.Buffer
,
4722 lpProcessInformation
,
4726 RtlFreeUnicodeString(&ApplicationName
);
4727 RtlFreeUnicodeString(&LiveCommandLine
);
4728 RtlFreeUnicodeString(&CurrentDirectory
);
4729 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
4730 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
4731 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
4733 /* Return what Unicode did */
4738 * FUNCTION: The CreateProcess function creates a new process and its
4739 * primary thread. The new process executes the specified executable file
4742 * lpApplicationName = Pointer to name of executable module
4743 * lpCommandLine = Pointer to command line string
4744 * lpProcessAttributes = Process security attributes
4745 * lpThreadAttributes = Thread security attributes
4746 * bInheritHandles = Handle inheritance flag
4747 * dwCreationFlags = Creation flags
4748 * lpEnvironment = Pointer to new environment block
4749 * lpCurrentDirectory = Pointer to current directory name
4750 * lpStartupInfo = Pointer to startup info
4751 * lpProcessInformation = Pointer to process information
4757 CreateProcessA(LPCSTR lpApplicationName
,
4758 LPSTR lpCommandLine
,
4759 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4760 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4761 BOOL bInheritHandles
,
4762 DWORD dwCreationFlags
,
4763 LPVOID lpEnvironment
,
4764 LPCSTR lpCurrentDirectory
,
4765 LPSTARTUPINFOA lpStartupInfo
,
4766 LPPROCESS_INFORMATION lpProcessInformation
)
4768 /* Call the internal (but exported) version */
4769 return CreateProcessInternalA(NULL
,
4772 lpProcessAttributes
,
4779 lpProcessInformation
,
4788 WinExec(LPCSTR lpCmdLine
,
4791 STARTUPINFOA StartupInfo
;
4792 PROCESS_INFORMATION ProcessInformation
;
4795 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
4796 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
4797 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
4798 StartupInfo
.dwFlags
= 0;
4800 if (!CreateProcessA(NULL
,
4809 &ProcessInformation
))
4811 dosErr
= GetLastError();
4812 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
4815 if (NULL
!= UserWaitForInputIdleRoutine
)
4817 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
4821 NtClose(ProcessInformation
.hProcess
);
4822 NtClose(ProcessInformation
.hThread
);
4824 return 33; /* Something bigger than 31 means success. */