2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/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
;
63 SIZE_T NumberOfBytesWritten
;
65 /* If there is no handle to duplicate, return immediately */
66 if (!StandardHandle
) return;
68 /* Duplicate the handle */
69 Status
= NtDuplicateObject(NtCurrentProcess(),
75 DUPLICATE_SAME_ACCESS
|
76 DUPLICATE_SAME_ATTRIBUTES
);
77 if (!NT_SUCCESS(Status
)) return;
80 NtWriteVirtualMemory(ProcessHandle
,
84 &NumberOfBytesWritten
);
89 BuildSubSysCommandLine(IN LPCWSTR SubsystemName
,
90 IN LPCWSTR ApplicationName
,
91 IN LPCWSTR CommandLine
,
92 OUT PUNICODE_STRING SubsysCommandLine
)
94 UNICODE_STRING CommandLineString
, ApplicationNameString
;
98 /* Convert to unicode strings */
99 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
100 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
102 /* Allocate buffer for the output string */
103 Length
= CommandLineString
.MaximumLength
+ ApplicationNameString
.MaximumLength
+ 32;
104 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
105 RtlInitEmptyUnicodeString(SubsysCommandLine
, Buffer
, (USHORT
)Length
);
108 /* Fail, no memory */
109 BaseSetLastNTError(STATUS_NO_MEMORY
);
113 /* Build the final subsystem command line */
114 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
115 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
116 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
117 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
123 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
124 IN ULONG ImageMinorVersion
)
126 /* Accept images for NT 3.1 or higher */
127 if (ImageMajorVersion
> 3 ||
128 (ImageMajorVersion
== 3 && ImageMinorVersion
>= 10))
130 /* ReactOS-specific: Accept images even if they are newer than our internal NT version. */
131 if (ImageMajorVersion
> SharedUserData
->NtMajorVersion
||
132 (ImageMajorVersion
== SharedUserData
->NtMajorVersion
&& ImageMinorVersion
> SharedUserData
->NtMinorVersion
))
134 DPRINT1("Accepting image version %lu.%lu, although ReactOS is an NT %hu.%hu OS!\n",
137 SharedUserData
->NtMajorVersion
,
138 SharedUserData
->NtMinorVersion
);
149 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
154 /* Get all the MD5 hashes */
155 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
156 if (!NT_SUCCESS(Status
)) return Status
;
158 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
159 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
161 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
163 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
165 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
167 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
169 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
172 /* Actually, fuck it, don't block anything, we're open source */
173 return STATUS_SUCCESS
;
178 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
179 IN PWCHAR ComponentName
,
182 /* Pretty much the only thing this key is used for, is malware */
184 return STATUS_NOT_IMPLEMENTED
;
189 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
192 IN ULONG ValueLength
,
194 IN PVOID EntryContext
)
196 /* Add this to the certification list */
197 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
202 BasepIsProcessAllowed(IN LPWSTR ApplicationName
)
204 NTSTATUS Status
, Status1
;
207 HMODULE TrustLibrary
;
208 PBASEP_APPCERT_ENTRY Entry
;
210 PLIST_ENTRY NextEntry
;
212 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
213 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
215 /* Try to initialize the certification subsystem */
216 while (!g_AppCertInitialized
)
219 Status
= STATUS_SUCCESS
;
222 /* Acquire the lock while initializing and see if we lost a race */
223 RtlEnterCriticalSection(&gcsAppCert
);
224 if (g_AppCertInitialized
) break;
226 /* On embedded, there is a special DLL */
227 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
229 /* Allocate a buffer for the name */
230 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
232 MAX_PATH
* sizeof(WCHAR
) +
233 sizeof(UNICODE_NULL
));
236 /* Fail if no memory */
237 Status
= STATUS_NO_MEMORY
;
241 /* Now get the system32 directory in our buffer, make sure it fits */
242 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
243 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
245 /* Add a slash if needed, and add the embedded cert DLL name */
246 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
247 RtlCopyMemory(&Buffer
[Length
],
249 sizeof(L
"EmbdTrst.DLL"));
252 TrustLibrary
= LoadLibraryW(Buffer
);
255 /* And extract the special function out of it */
256 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
257 "ImageOkToRunOnEmbeddedNT");
261 /* If we didn't get this far, set a failure code */
262 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
267 /* Other systems have a registry entry for this */
268 Status1
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
269 if (NT_SUCCESS(Status1
))
271 /* Close it, we'll query it through Rtl */
274 /* Do the query, which will call a special callback */
275 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
280 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
282 Status
= STATUS_SUCCESS
;
287 /* Free any buffer if we had one */
288 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
290 /* Check for errors, or a missing embedded/custom certification DLL */
291 if (!NT_SUCCESS(Status
) ||
292 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
294 /* The subsystem is not active on this machine, so give up */
295 g_HaveAppCerts
= FALSE
;
296 g_AppCertStatus
= Status
;
300 /* We have certification DLLs active, remember this */
301 g_HaveAppCerts
= TRUE
;
304 /* We are done the initialization phase, release the lock */
305 g_AppCertInitialized
= TRUE
;
306 RtlLeaveCriticalSection(&gcsAppCert
);
309 /* If there's no certification DLLs present, return the failure code */
310 if (!g_HaveAppCerts
) return g_AppCertStatus
;
312 /* Otherwise, assume success and make sure we have *something* */
313 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
314 Status
= STATUS_SUCCESS
;
316 /* If the something is an embedded certification DLL, call it and return */
317 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
319 /* Otherwise we have custom certification DLLs, parse them */
320 NextEntry
= BasepAppCertDllsList
.Flink
;
322 while (NextEntry
!= &BasepAppCertDllsList
)
324 /* Make sure the entry has a callback */
325 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
326 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
328 /* Call it and check if it failed */
329 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
330 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
333 NextEntry
= NextEntry
->Flink
;
336 /* Now loop them again */
337 NextEntry
= BasepAppCertDllsList
.Flink
;
338 while (NextEntry
!= &BasepAppCertDllsList
)
340 /* Make sure the entry has a callback */
341 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
342 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
344 /* Call it, this time with the flag from the loop above */
345 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
348 /* All done, return the status */
354 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
355 IN HANDLE ProcessHandle
,
356 IN HANDLE ThreadHandle
)
359 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
361 /* Enter the application certification lock */
362 RtlEnterCriticalSection(&gcsAppCert
);
364 /* Check if we already know the function */
365 if (g_SaferReplaceProcessThreadTokens
)
368 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
376 /* Check if the app certification DLL isn't loaded */
377 if (!(gSaferHandle
) ||
378 (gSaferHandle
== (HMODULE
)-1) ||
379 (gSaferHandle
== (HMODULE
)-2))
381 /* Then we can't call the function */
382 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
386 /* We have the DLL, find the address of the Safer function */
387 Status
= LdrGetProcedureAddress(gSaferHandle
,
388 &SaferiReplaceProcessThreadTokens
,
390 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
391 if (NT_SUCCESS(Status
))
393 /* Found it, now call it */
394 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
402 /* We couldn't find it, so this must be an unsupported DLL */
403 LdrUnloadDll(gSaferHandle
);
405 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
410 /* Release the lock and return the result */
411 RtlLeaveCriticalSection(&gcsAppCert
);
417 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
422 ASSERT(Handles
!= NULL
);
423 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
425 /* Close the file handle */
428 Status
= NtClose(Handles
->File
);
429 ASSERT(NT_SUCCESS(Status
));
432 /* Close the section handle */
433 if (Handles
->Section
)
435 Status
= NtClose(Handles
->Section
);
436 ASSERT(NT_SUCCESS(Status
));
439 /* Unmap the section view */
440 if (Handles
->ViewBase
.QuadPart
)
442 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
443 (PVOID
)(ULONG_PTR
)Handles
->ViewBase
.QuadPart
);
444 ASSERT(NT_SUCCESS(Status
));
452 _In_ PPROCESS_START_ROUTINE lpStartAddress
)
456 /* Set our Start Address */
457 NtSetInformationThread(NtCurrentThread(),
458 ThreadQuerySetWin32StartAddress
,
460 sizeof(PPROCESS_START_ROUTINE
));
462 /* Call the Start Routine */
463 ExitThread(lpStartAddress());
465 _SEH2_EXCEPT(UnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
467 /* Get the Exit code from the SEH Handler */
468 if (!BaseRunningInServerProcess
)
470 /* Kill the whole process, usually */
471 ExitProcess(_SEH2_GetExceptionCode());
475 /* If running inside CSRSS, kill just this thread */
476 ExitThread(_SEH2_GetExceptionCode());
484 BasePushProcessParameters(IN ULONG ParameterFlags
,
485 IN HANDLE ProcessHandle
,
487 IN LPCWSTR ApplicationPathName
,
488 IN LPWSTR lpCurrentDirectory
,
489 IN LPWSTR lpCommandLine
,
490 IN LPVOID lpEnvironment
,
491 IN LPSTARTUPINFOW StartupInfo
,
492 IN DWORD CreationFlags
,
493 IN BOOL InheritHandles
,
494 IN ULONG ImageSubsystem
,
495 IN PVOID AppCompatData
,
496 IN ULONG AppCompatDataSize
)
498 WCHAR FullPath
[MAX_PATH
+ 5];
499 PWCHAR Remaining
, DllPathString
, ScanChar
;
500 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
501 PVOID RemoteAppCompatData
;
502 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
503 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
507 BOOLEAN HavePebLock
= FALSE
, Result
;
508 PPEB Peb
= NtCurrentPeb();
510 /* Get the full path name */
511 Size
= GetFullPathNameW(ApplicationPathName
,
515 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
517 /* Get the DLL Path */
518 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
522 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
526 /* Initialize Strings */
527 RtlInitUnicodeString(&DllPath
, DllPathString
);
528 RtlInitUnicodeString(&ImageName
, FullPath
);
532 /* Couldn't get the path name. Just take the original path */
533 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
538 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
542 /* Initialize Strings */
543 RtlInitUnicodeString(&DllPath
, DllPathString
);
544 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
547 /* Initialize Strings */
548 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
549 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
551 /* Initialize more Strings from the Startup Info */
552 if (StartupInfo
->lpDesktop
)
554 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
558 RtlInitUnicodeString(&Desktop
, L
"");
560 if (StartupInfo
->lpReserved
)
562 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
566 RtlInitUnicodeString(&Shell
, L
"");
568 if (StartupInfo
->lpTitle
)
570 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
574 RtlInitUnicodeString(&Title
, ApplicationPathName
);
577 /* This one is special because the length can differ */
578 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
579 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
581 /* Enforce no app compat data if the pointer was NULL */
582 if (!AppCompatData
) AppCompatDataSize
= 0;
584 /* Create the Parameter Block */
585 ProcessParameters
= NULL
;
586 DPRINT("ImageName: '%wZ'\n", &ImageName
);
587 DPRINT("DllPath : '%wZ'\n", &DllPath
);
588 DPRINT("CurDir : '%wZ'\n", &CurrentDirectory
);
589 DPRINT("CmdLine : '%wZ'\n", &CommandLine
);
590 DPRINT("Title : '%wZ'\n", &Title
);
591 DPRINT("Desktop : '%wZ'\n", &Desktop
);
592 DPRINT("Shell : '%wZ'\n", &Shell
);
593 DPRINT("Runtime : '%wZ'\n", &Runtime
);
594 Status
= RtlCreateProcessParameters(&ProcessParameters
,
598 &CurrentDirectory
: NULL
,
605 if (!NT_SUCCESS(Status
)) goto FailPath
;
607 /* Clear the current directory handle if not inheriting */
608 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
610 /* Check if the user passed in an environment */
613 /* We should've made it part of the parameters block, enforce this */
614 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
615 lpEnvironment
= ProcessParameters
->Environment
;
619 /* The user did not, so use the one from the current PEB */
622 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
625 /* Save pointer and start lookup */
626 ScanChar
= lpEnvironment
;
629 /* Find the environment size */
630 while (*ScanChar
++) while (*ScanChar
++);
631 EnviroSize
= (ULONG
)((ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
);
633 /* Allocate and Initialize new Environment Block */
635 ProcessParameters
->Environment
= NULL
;
636 Status
= NtAllocateVirtualMemory(ProcessHandle
,
637 (PVOID
*)&ProcessParameters
->Environment
,
642 if (!NT_SUCCESS(Status
)) goto FailPath
;
644 /* Write the Environment Block */
645 Status
= NtWriteVirtualMemory(ProcessHandle
,
646 ProcessParameters
->Environment
,
651 /* No longer need the PEB lock anymore */
659 /* Check if the write failed */
660 if (!NT_SUCCESS(Status
)) goto FailPath
;
663 /* Write new parameters */
664 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
665 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
666 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
667 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
668 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
669 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
670 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
671 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
672 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
674 /* Write the handles only if we have to */
675 if (StartupInfo
->dwFlags
&
676 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
678 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
679 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
680 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
683 /* Use Special Flags for ConDllInitialize in Kernel32 */
684 if (CreationFlags
& DETACHED_PROCESS
)
686 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
688 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
690 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
692 else if (CreationFlags
& CREATE_NO_WINDOW
)
694 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
698 /* Inherit our Console Handle */
699 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
701 /* Make sure that the shell isn't trampling on our handles first */
702 if (!(StartupInfo
->dwFlags
&
703 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
705 /* Copy the handle if we are inheriting or if it's a console handle */
706 if ((InheritHandles
) ||
707 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
709 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
711 if ((InheritHandles
) ||
712 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
714 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
716 if ((InheritHandles
) ||
717 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
719 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
724 /* Also set the Console Flag */
725 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
726 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
728 ProcessParameters
->ConsoleFlags
= 1;
731 /* Check if there's a .local file present */
732 if (ParameterFlags
& 1)
734 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
;
737 /* Check if we failed to open the IFEO key */
738 if (ParameterFlags
& 2)
740 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
;
743 /* Allocate memory for the parameter block */
744 Size
= ProcessParameters
->Length
;
745 RemoteParameters
= NULL
;
746 Status
= NtAllocateVirtualMemory(ProcessHandle
,
747 (PVOID
*)&RemoteParameters
,
752 if (!NT_SUCCESS(Status
)) goto FailPath
;
754 /* Set the allocated size */
755 ProcessParameters
->MaximumLength
= Size
;
757 /* Handle some Parameter Flags */
758 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
759 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
760 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
761 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
762 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
763 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
764 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
765 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
767 /* Write the Parameter Block */
768 Status
= NtWriteVirtualMemory(ProcessHandle
,
771 ProcessParameters
->Length
,
773 if (!NT_SUCCESS(Status
)) goto FailPath
;
775 /* Write the PEB Pointer */
776 Status
= NtWriteVirtualMemory(ProcessHandle
,
777 &RemotePeb
->ProcessParameters
,
781 if (!NT_SUCCESS(Status
)) goto FailPath
;
783 /* Check if there's any app compat data to write */
784 RemoteAppCompatData
= NULL
;
787 /* Allocate some space for the application compatibility data */
788 Size
= AppCompatDataSize
;
789 Status
= NtAllocateVirtualMemory(ProcessHandle
,
790 &RemoteAppCompatData
,
795 if (!NT_SUCCESS(Status
)) goto FailPath
;
797 /* Write the application compatibility data */
798 Status
= NtWriteVirtualMemory(ProcessHandle
,
803 if (!NT_SUCCESS(Status
)) goto FailPath
;
806 /* Write the PEB Pointer to the app compat data (might be NULL) */
807 Status
= NtWriteVirtualMemory(ProcessHandle
,
808 &RemotePeb
->pShimData
,
809 &RemoteAppCompatData
,
812 if (!NT_SUCCESS(Status
)) goto FailPath
;
814 /* Now write Peb->ImageSubSystem */
817 NtWriteVirtualMemory(ProcessHandle
,
818 &RemotePeb
->ImageSubsystem
,
820 sizeof(ImageSubsystem
),
829 if (HavePebLock
) RtlReleasePebLock();
830 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
831 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
834 DPRINT1("Failure to create process parameters: %lx\n", Status
);
835 BaseSetLastNTError(Status
);
842 InitCommandLines(VOID
)
846 /* Read the UNICODE_STRING from the PEB */
847 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
849 /* Convert to ANSI_STRING for the *A callers */
850 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
851 &BaseUnicodeCommandLine
,
853 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
856 /* PUBLIC FUNCTIONS ***********************************************************/
863 GetProcessAffinityMask(IN HANDLE hProcess
,
864 OUT PDWORD_PTR lpProcessAffinityMask
,
865 OUT PDWORD_PTR lpSystemAffinityMask
)
867 PROCESS_BASIC_INFORMATION ProcessInfo
;
870 /* Query information on the process from the kernel */
871 Status
= NtQueryInformationProcess(hProcess
,
872 ProcessBasicInformation
,
876 if (!NT_SUCCESS(Status
))
879 BaseSetLastNTError(Status
);
883 /* Copy the affinity mask, and get the system one from our shared data */
884 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
885 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
894 SetProcessAffinityMask(IN HANDLE hProcess
,
895 IN DWORD_PTR dwProcessAffinityMask
)
899 /* Directly set the affinity mask */
900 Status
= NtSetInformationProcess(hProcess
,
902 (PVOID
)&dwProcessAffinityMask
,
903 sizeof(dwProcessAffinityMask
));
904 if (!NT_SUCCESS(Status
))
907 BaseSetLastNTError(Status
);
911 /* Everything was ok */
920 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
921 OUT LPDWORD lpdwFlags
)
923 BASE_API_MESSAGE ApiMessage
;
924 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
926 /* Ask CSRSS for shutdown information */
927 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
929 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
930 sizeof(*ShutdownParametersRequest
));
931 if (!NT_SUCCESS(ApiMessage
.Status
))
933 /* Return the failure from CSRSS */
934 BaseSetLastNTError(ApiMessage
.Status
);
938 /* Get the data back */
939 *lpdwLevel
= ShutdownParametersRequest
->ShutdownLevel
;
940 *lpdwFlags
= ShutdownParametersRequest
->ShutdownFlags
;
949 SetProcessShutdownParameters(IN DWORD dwLevel
,
952 BASE_API_MESSAGE ApiMessage
;
953 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
955 /* Write the data into the CSRSS request and send it */
956 ShutdownParametersRequest
->ShutdownLevel
= dwLevel
;
957 ShutdownParametersRequest
->ShutdownFlags
= dwFlags
;
958 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
960 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
961 sizeof(*ShutdownParametersRequest
));
962 if (!NT_SUCCESS(ApiMessage
.Status
))
964 /* Return the failure from CSRSS */
965 BaseSetLastNTError(ApiMessage
.Status
);
978 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
979 OUT PSIZE_T lpMinimumWorkingSetSize
,
980 OUT PSIZE_T lpMaximumWorkingSetSize
,
983 QUOTA_LIMITS_EX QuotaLimits
;
986 /* Query the kernel about this */
987 Status
= NtQueryInformationProcess(hProcess
,
992 if (!NT_SUCCESS(Status
))
995 BaseSetLastNTError(Status
);
999 /* Copy the quota information out */
1000 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1001 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1002 *Flags
= QuotaLimits
.Flags
;
1011 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1012 OUT PSIZE_T lpMinimumWorkingSetSize
,
1013 OUT PSIZE_T lpMaximumWorkingSetSize
)
1016 return GetProcessWorkingSetSizeEx(hProcess
,
1017 lpMinimumWorkingSetSize
,
1018 lpMaximumWorkingSetSize
,
1027 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1028 IN SIZE_T dwMinimumWorkingSetSize
,
1029 IN SIZE_T dwMaximumWorkingSetSize
,
1032 QUOTA_LIMITS_EX QuotaLimits
;
1033 NTSTATUS Status
, ReturnStatus
;
1036 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1038 /* Zero out the input structure */
1039 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1041 /* Check if the caller sent any limits */
1042 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1044 /* Write the quota information */
1045 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1046 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1047 QuotaLimits
.Flags
= Flags
;
1049 /* Acquire the required privilege */
1050 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1052 /* Request the new quotas */
1053 ReturnStatus
= NtSetInformationProcess(hProcess
,
1056 sizeof(QuotaLimits
));
1057 Result
= NT_SUCCESS(ReturnStatus
);
1058 if (NT_SUCCESS(Status
))
1060 /* Release the privilege and set succes code */
1061 ASSERT(State
!= NULL
);
1062 RtlReleasePrivilege(State
);
1068 /* No limits, fail the call */
1069 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1073 /* Return result code, set error code if this was a failure */
1074 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1083 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1084 IN SIZE_T dwMinimumWorkingSetSize
,
1085 IN SIZE_T dwMaximumWorkingSetSize
)
1087 /* Call the newer API */
1088 return SetProcessWorkingSetSizeEx(hProcess
,
1089 dwMinimumWorkingSetSize
,
1090 dwMaximumWorkingSetSize
,
1099 GetProcessTimes(IN HANDLE hProcess
,
1100 IN LPFILETIME lpCreationTime
,
1101 IN LPFILETIME lpExitTime
,
1102 IN LPFILETIME lpKernelTime
,
1103 IN LPFILETIME lpUserTime
)
1105 KERNEL_USER_TIMES Kut
;
1108 /* Query the times */
1109 Status
= NtQueryInformationProcess(hProcess
,
1114 if (!NT_SUCCESS(Status
))
1116 /* Handle failure */
1117 BaseSetLastNTError(Status
);
1121 /* Copy all the times and return success */
1122 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1123 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1124 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1125 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1126 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1127 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1128 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1129 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1138 GetCurrentProcess(VOID
)
1140 return (HANDLE
)NtCurrentProcess();
1148 GetCurrentThread(VOID
)
1150 return (HANDLE
)NtCurrentThread();
1158 GetCurrentProcessId(VOID
)
1160 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1168 GetExitCodeProcess(IN HANDLE hProcess
,
1169 IN LPDWORD lpExitCode
)
1171 PROCESS_BASIC_INFORMATION ProcessBasic
;
1174 /* Ask the kernel */
1175 Status
= NtQueryInformationProcess(hProcess
,
1176 ProcessBasicInformation
,
1178 sizeof(ProcessBasic
),
1180 if (!NT_SUCCESS(Status
))
1182 /* We failed, was this because this is a VDM process? */
1183 if (BaseCheckForVDM(hProcess
, lpExitCode
) != FALSE
) return TRUE
;
1185 /* Not a VDM process, fail the call */
1186 BaseSetLastNTError(Status
);
1190 /* Succes case, return the exit code */
1191 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1200 GetProcessId(IN HANDLE Process
)
1202 PROCESS_BASIC_INFORMATION ProcessBasic
;
1205 /* Query the kernel */
1206 Status
= NtQueryInformationProcess(Process
,
1207 ProcessBasicInformation
,
1209 sizeof(ProcessBasic
),
1211 if (!NT_SUCCESS(Status
))
1213 /* Handle failure */
1214 BaseSetLastNTError(Status
);
1218 /* Return the PID */
1219 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1227 OpenProcess(IN DWORD dwDesiredAccess
,
1228 IN BOOL bInheritHandle
,
1229 IN DWORD dwProcessId
)
1232 HANDLE ProcessHandle
;
1233 OBJECT_ATTRIBUTES ObjectAttributes
;
1236 /* Setup the input client ID structure */
1237 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1238 ClientId
.UniqueThread
= 0;
1240 /* This is needed just to define the inheritance flags */
1241 InitializeObjectAttributes(&ObjectAttributes
,
1243 (bInheritHandle
? OBJ_INHERIT
: 0),
1247 /* Now try to open the process */
1248 Status
= NtOpenProcess(&ProcessHandle
,
1252 if (!NT_SUCCESS(Status
))
1254 /* Handle failure */
1255 BaseSetLastNTError(Status
);
1259 /* Otherwise return a handle to the process */
1260 return ProcessHandle
;
1268 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1270 /* Write the global function pointer */
1271 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1279 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1281 PRTL_USER_PROCESS_PARAMETERS Params
;
1283 /* Get the process parameters */
1284 Params
= NtCurrentPeb()->ProcessParameters
;
1286 /* Copy the data out of there */
1287 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1288 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1289 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1290 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1291 lpStartupInfo
->dwX
= Params
->StartingX
;
1292 lpStartupInfo
->dwY
= Params
->StartingY
;
1293 lpStartupInfo
->dwXSize
= Params
->CountX
;
1294 lpStartupInfo
->dwYSize
= Params
->CountY
;
1295 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1296 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1297 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1298 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1299 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1300 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1301 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1303 /* Check if the standard handles are being used for other features */
1304 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1306 STARTF_SHELLPRIVATE
))
1308 /* These are, so copy the standard handles too */
1309 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1310 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1311 lpStartupInfo
->hStdError
= Params
->StandardError
;
1320 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1322 PRTL_USER_PROCESS_PARAMETERS Params
;
1323 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1324 LPSTARTUPINFOA StartupInfo
;
1327 /* Get the cached information as well as the PEB parameters */
1328 StartupInfo
= BaseAnsiStartupInfo
;
1329 Params
= NtCurrentPeb()->ProcessParameters
;
1331 /* Check if this is the first time we have to get the cached version */
1332 while (!StartupInfo
)
1334 /* Create new ANSI startup info */
1335 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1337 sizeof(*StartupInfo
));
1340 /* Zero out string pointers in case we fail to create them */
1341 StartupInfo
->lpReserved
= NULL
;
1342 StartupInfo
->lpDesktop
= NULL
;
1343 StartupInfo
->lpTitle
= NULL
;
1346 StartupInfo
->cb
= sizeof(*StartupInfo
);
1348 /* Copy what's already stored in the PEB */
1349 StartupInfo
->dwX
= Params
->StartingX
;
1350 StartupInfo
->dwY
= Params
->StartingY
;
1351 StartupInfo
->dwXSize
= Params
->CountX
;
1352 StartupInfo
->dwYSize
= Params
->CountY
;
1353 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1354 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1355 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1356 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1357 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1358 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1359 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1360 StartupInfo
->hStdInput
= Params
->StandardInput
;
1361 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1362 StartupInfo
->hStdError
= Params
->StandardError
;
1364 /* Copy shell info string */
1365 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1368 if (NT_SUCCESS(Status
))
1371 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1373 /* Copy desktop info string */
1374 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1375 &Params
->DesktopInfo
,
1377 if (NT_SUCCESS(Status
))
1380 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1382 /* Copy window title string */
1383 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1384 &Params
->WindowTitle
,
1386 if (NT_SUCCESS(Status
))
1389 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1391 /* We finished with the ANSI version, try to cache it */
1392 if (!InterlockedCompareExchangePointer((PVOID
*)&BaseAnsiStartupInfo
,
1396 /* We were the first thread through, use the data */
1400 /* Someone beat us to it, use their data instead */
1401 StartupInfo
= BaseAnsiStartupInfo
;
1402 Status
= STATUS_SUCCESS
;
1404 /* We're going to free our own stuff, but not raise */
1405 RtlFreeAnsiString(&TitleString
);
1407 RtlFreeAnsiString(&DesktopString
);
1409 RtlFreeAnsiString(&ShellString
);
1411 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1415 /* No memory, fail */
1416 Status
= STATUS_NO_MEMORY
;
1419 /* Raise an error unless we got here due to the race condition */
1420 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1423 /* Now copy from the cached ANSI version */
1424 lpStartupInfo
->cb
= StartupInfo
->cb
;
1425 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1426 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1427 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1428 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1429 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1430 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1431 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1432 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1433 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1434 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1435 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1436 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1437 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1438 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1440 /* Check if the shell is hijacking the handles for other features */
1441 if (lpStartupInfo
->dwFlags
&
1442 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1444 /* It isn't, so we can return the raw values */
1445 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1446 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1447 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1451 /* It is, so make sure nobody uses these as console handles */
1452 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1453 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1454 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1463 FlushInstructionCache(IN HANDLE hProcess
,
1464 IN LPCVOID lpBaseAddress
,
1469 /* Call the native function */
1470 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, nSize
);
1471 if (!NT_SUCCESS(Status
))
1473 /* Handle failure case */
1474 BaseSetLastNTError(Status
);
1487 ExitProcess(IN UINT uExitCode
)
1489 BASE_API_MESSAGE ApiMessage
;
1490 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1492 ASSERT(!BaseRunningInServerProcess
);
1496 /* Acquire the PEB lock */
1497 RtlAcquirePebLock();
1499 /* Kill all the threads */
1500 NtTerminateProcess(NULL
, uExitCode
);
1502 /* Unload all DLLs */
1503 LdrShutdownProcess();
1505 /* Notify Base Server of process termination */
1506 ExitProcessRequest
->uExitCode
= uExitCode
;
1507 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1509 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1510 sizeof(*ExitProcessRequest
));
1512 /* Now do it again */
1513 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1517 /* Release the PEB lock */
1518 RtlReleasePebLock();
1522 /* should never get here */
1532 TerminateProcess(IN HANDLE hProcess
,
1537 /* Check if no handle was passed in */
1540 /* Set error code */
1541 SetLastError(ERROR_INVALID_HANDLE
);
1545 /* Otherwise, try to terminate the process */
1546 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1547 if (NT_SUCCESS(Status
)) return TRUE
;
1549 /* It failed, convert error code */
1550 BaseSetLastNTError(Status
);
1553 /* This is the failure path */
1562 FatalAppExitA(UINT uAction
,
1563 LPCSTR lpMessageText
)
1565 PUNICODE_STRING MessageTextU
;
1566 ANSI_STRING MessageText
;
1569 /* Initialize the string using the static TEB pointer */
1570 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1571 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1573 /* Convert to unicode, or just exit normally if this failed */
1574 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1575 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1577 /* Call the Wide function */
1578 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1586 FatalAppExitW(IN UINT uAction
,
1587 IN LPCWSTR lpMessageText
)
1589 UNICODE_STRING UnicodeString
;
1593 /* Setup the string to print out */
1594 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1596 /* Display the hard error no matter what */
1597 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1600 (PULONG_PTR
)&UnicodeString
,
1602 /* On Checked builds, Windows allows the user to cancel the operation */
1609 /* Give the user a chance to abort */
1610 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
))
1615 /* Otherwise kill the process */
1624 FatalExit(IN
int ExitCode
)
1627 /* On Checked builds, Windows gives the user a nice little debugger UI */
1629 DbgPrint("FatalExit...\n\n");
1633 DbgPrompt("A (Abort), B (Break), I (Ignore)? ", Action
, sizeof(Action
));
1641 ExitProcess(ExitCode
);
1648 /* On other builds, just kill the process */
1649 ExitProcess(ExitCode
);
1657 GetPriorityClass(IN HANDLE hProcess
)
1660 PROCESS_PRIORITY_CLASS
DECLSPEC_ALIGN(4) PriorityClass
;
1662 /* Query the kernel */
1663 Status
= NtQueryInformationProcess(hProcess
,
1664 ProcessPriorityClass
,
1666 sizeof(PriorityClass
),
1668 if (NT_SUCCESS(Status
))
1670 /* Handle the conversion from NT to Win32 classes */
1671 switch (PriorityClass
.PriorityClass
)
1673 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1674 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1675 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1676 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1677 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1678 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1683 BaseSetLastNTError(Status
);
1692 SetPriorityClass(IN HANDLE hProcess
,
1693 IN DWORD dwPriorityClass
)
1697 PROCESS_PRIORITY_CLASS PriorityClass
;
1699 /* Handle conversion from Win32 to NT priority classes */
1700 switch (dwPriorityClass
)
1702 case IDLE_PRIORITY_CLASS
:
1703 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1706 case BELOW_NORMAL_PRIORITY_CLASS
:
1707 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1710 case NORMAL_PRIORITY_CLASS
:
1711 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1714 case ABOVE_NORMAL_PRIORITY_CLASS
:
1715 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1718 case HIGH_PRIORITY_CLASS
:
1719 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1722 case REALTIME_PRIORITY_CLASS
:
1723 /* Try to acquire the privilege. If it fails, just use HIGH */
1724 State
= BasepIsRealtimeAllowed(TRUE
);
1725 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1726 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1730 /* Unrecognized priority classes don't make it to the kernel */
1731 SetLastError(ERROR_INVALID_PARAMETER
);
1735 /* Send the request to the kernel, and don't touch the foreground flag */
1736 PriorityClass
.Foreground
= FALSE
;
1737 Status
= NtSetInformationProcess(hProcess
,
1738 ProcessPriorityClass
,
1740 sizeof(PROCESS_PRIORITY_CLASS
));
1742 /* Release the privilege if we had it */
1743 if (State
) RtlReleasePrivilege(State
);
1744 if (!NT_SUCCESS(Status
))
1746 /* Handle error path */
1747 BaseSetLastNTError(Status
);
1760 GetProcessVersion(IN DWORD ProcessId
)
1763 PIMAGE_NT_HEADERS NtHeader
;
1764 PIMAGE_DOS_HEADER DosHeader
;
1766 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1769 HANDLE ProcessHandle
= NULL
;
1771 USHORT VersionData
[2];
1774 /* We'll be accessing stuff that can fault, so protect everything with SEH */
1777 /* It this an in-process or out-of-process request? */
1778 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
1780 /* It's in-process, so just read our own header */
1781 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
1784 /* Unable to read the NT header, something is wrong here... */
1785 Status
= STATUS_INVALID_IMAGE_FORMAT
;
1789 /* Get the version straight out of the NT header */
1790 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
1791 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
1795 /* Out-of-process, so open it */
1796 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1799 if (!ProcessHandle
) _SEH2_YIELD(return 0);
1801 /* Try to find out where its PEB lives */
1802 Status
= NtQueryInformationProcess(ProcessHandle
,
1803 ProcessBasicInformation
,
1805 sizeof(ProcessBasicInfo
),
1808 if (!NT_SUCCESS(Status
)) goto Error
;
1809 Peb
= ProcessBasicInfo
.PebBaseAddress
;
1811 /* Now that we have the PEB, read the image base address out of it */
1812 Result
= ReadProcessMemory(ProcessHandle
,
1813 &Peb
->ImageBaseAddress
,
1815 sizeof(BaseAddress
),
1817 if (!Result
) goto Error
;
1819 /* Now read the e_lfanew (offset to NT header) from the base */
1820 DosHeader
= BaseAddress
;
1821 Result
= ReadProcessMemory(ProcessHandle
,
1822 &DosHeader
->e_lfanew
,
1826 if (!Result
) goto Error
;
1828 /* And finally, read the NT header itself by adding the offset */
1829 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
1830 Result
= ReadProcessMemory(ProcessHandle
,
1831 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
1833 sizeof(VersionData
),
1835 if (!Result
) goto Error
;
1837 /* Get the version straight out of the NT header */
1838 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
1841 /* If there was an error anywhere, set the last error */
1842 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
1847 /* Close the process handle */
1848 if (ProcessHandle
) CloseHandle(ProcessHandle
);
1852 /* And return the version data */
1861 GetProcessIoCounters(IN HANDLE hProcess
,
1862 OUT PIO_COUNTERS lpIoCounters
)
1866 /* Query the kernel. Structures are identical, so let it do the copy too. */
1867 Status
= NtQueryInformationProcess(hProcess
,
1870 sizeof(IO_COUNTERS
),
1872 if (!NT_SUCCESS(Status
))
1874 /* Handle error path */
1875 BaseSetLastNTError(Status
);
1888 GetProcessPriorityBoost(IN HANDLE hProcess
,
1889 OUT PBOOL pDisablePriorityBoost
)
1892 ULONG PriorityBoost
;
1894 /* Query the kernel */
1895 Status
= NtQueryInformationProcess(hProcess
,
1896 ProcessPriorityBoost
,
1898 sizeof(PriorityBoost
),
1900 if (NT_SUCCESS(Status
))
1902 /* Convert from ULONG to a BOOL */
1903 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
1907 /* Handle error path */
1908 BaseSetLastNTError(Status
);
1917 SetProcessPriorityBoost(IN HANDLE hProcess
,
1918 IN BOOL bDisablePriorityBoost
)
1921 ULONG PriorityBoost
;
1923 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
1924 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
1925 Status
= NtSetInformationProcess(hProcess
,
1926 ProcessPriorityBoost
,
1929 if (!NT_SUCCESS(Status
))
1931 /* Handle error path */
1932 BaseSetLastNTError(Status
);
1945 GetProcessHandleCount(IN HANDLE hProcess
,
1946 OUT PDWORD pdwHandleCount
)
1951 /* Query the kernel */
1952 Status
= NtQueryInformationProcess(hProcess
,
1957 if (NT_SUCCESS(Status
))
1959 /* Copy the count and return success */
1960 *pdwHandleCount
= phc
;
1964 /* Handle error path */
1965 BaseSetLastNTError(Status
);
1974 IsWow64Process(IN HANDLE hProcess
,
1975 OUT PBOOL Wow64Process
)
1980 /* Query the kernel */
1981 Status
= NtQueryInformationProcess(hProcess
,
1982 ProcessWow64Information
,
1986 if (!NT_SUCCESS(Status
))
1988 /* Handle error path */
1989 BaseSetLastNTError(Status
);
1993 /* Enforce this is a BOOL, and return success */
1994 *Wow64Process
= (pbi
!= 0);
2003 GetCommandLineA(VOID
)
2005 return BaseAnsiCommandLine
.Buffer
;
2013 GetCommandLineW(VOID
)
2015 return BaseUnicodeCommandLine
.Buffer
;
2023 ReadProcessMemory(IN HANDLE hProcess
,
2024 IN LPCVOID lpBaseAddress
,
2027 OUT SIZE_T
* lpNumberOfBytesRead
)
2032 Status
= NtReadVirtualMemory(hProcess
,
2033 (PVOID
)lpBaseAddress
,
2038 /* In user-mode, this parameter is optional */
2039 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2040 if (!NT_SUCCESS(Status
))
2043 BaseSetLastNTError(Status
);
2047 /* Return success */
2056 WriteProcessMemory(IN HANDLE hProcess
,
2057 IN LPVOID lpBaseAddress
,
2058 IN LPCVOID lpBuffer
,
2060 OUT SIZE_T
*lpNumberOfBytesWritten
)
2068 /* Set parameters for protect call */
2070 Base
= lpBaseAddress
;
2072 /* Check the current status */
2073 Status
= NtProtectVirtualMemory(hProcess
,
2076 PAGE_EXECUTE_READWRITE
,
2078 if (NT_SUCCESS(Status
))
2080 /* Check if we are unprotecting */
2081 UnProtect
= OldValue
& (PAGE_READWRITE
|
2083 PAGE_EXECUTE_READWRITE
|
2084 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2087 /* Set the new protection */
2088 Status
= NtProtectVirtualMemory(hProcess
,
2094 /* Write the memory */
2095 Status
= NtWriteVirtualMemory(hProcess
,
2101 /* In Win32, the parameter is optional, so handle this case */
2102 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2104 if (!NT_SUCCESS(Status
))
2107 BaseSetLastNTError(Status
);
2111 /* Flush the ITLB */
2112 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2117 /* Check if we were read only */
2118 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2120 /* Restore protection and fail */
2121 NtProtectVirtualMemory(hProcess
,
2126 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2128 /* Note: This is what Windows returns and code depends on it */
2129 return STATUS_ACCESS_VIOLATION
;
2132 /* Otherwise, do the write */
2133 Status
= NtWriteVirtualMemory(hProcess
,
2139 /* In Win32, the parameter is optional, so handle this case */
2140 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2142 /* And restore the protection */
2143 NtProtectVirtualMemory(hProcess
,
2148 if (!NT_SUCCESS(Status
))
2151 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2153 /* Note: This is what Windows returns and code depends on it */
2154 return STATUS_ACCESS_VIOLATION
;
2157 /* Flush the ITLB */
2158 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2165 BaseSetLastNTError(Status
);
2175 ProcessIdToSessionId(IN DWORD dwProcessId
,
2176 OUT PDWORD pSessionId
)
2178 PROCESS_SESSION_INFORMATION SessionInformation
;
2179 OBJECT_ATTRIBUTES ObjectAttributes
;
2181 HANDLE ProcessHandle
;
2184 /* Do a quick check if the pointer is not writable */
2185 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2188 SetLastError(ERROR_INVALID_PARAMETER
);
2192 /* Open the process passed in by ID */
2193 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2194 ClientId
.UniqueThread
= 0;
2195 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2196 Status
= NtOpenProcess(&ProcessHandle
,
2197 PROCESS_QUERY_INFORMATION
,
2200 if (NT_SUCCESS(Status
))
2202 /* Query the session ID from the kernel */
2203 Status
= NtQueryInformationProcess(ProcessHandle
,
2204 ProcessSessionInformation
,
2205 &SessionInformation
,
2206 sizeof(SessionInformation
),
2209 /* Close the handle and check if we succeeded */
2210 NtClose(ProcessHandle
);
2211 if (NT_SUCCESS(Status
))
2213 /* Return the session ID */
2214 *pSessionId
= SessionInformation
.SessionId
;
2219 /* Set error code and fail */
2220 BaseSetLastNTError(Status
);
2225 #define AddToHandle(x,y) ((x) = (HANDLE)((ULONG_PTR)(x) | (y)))
2226 #define RemoveFromHandle(x,y) ((x) = (HANDLE)((ULONG_PTR)(x) & ~(y)))
2227 C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME
== (PROCESS_PRIORITY_CLASS_HIGH
+ 1));
2234 CreateProcessInternalW(IN HANDLE hUserToken
,
2235 IN LPCWSTR lpApplicationName
,
2236 IN LPWSTR lpCommandLine
,
2237 IN LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2238 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2239 IN BOOL bInheritHandles
,
2240 IN DWORD dwCreationFlags
,
2241 IN LPVOID lpEnvironment
,
2242 IN LPCWSTR lpCurrentDirectory
,
2243 IN LPSTARTUPINFOW lpStartupInfo
,
2244 IN LPPROCESS_INFORMATION lpProcessInformation
,
2245 OUT PHANDLE hNewToken
)
2248 // Core variables used for creating the initial process and thread
2250 SECURITY_ATTRIBUTES LocalThreadAttributes
, LocalProcessAttributes
;
2251 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2252 POBJECT_ATTRIBUTES ObjectAttributes
;
2253 SECTION_IMAGE_INFORMATION ImageInformation
;
2254 IO_STATUS_BLOCK IoStatusBlock
;
2256 ULONG NoWindow
, StackSize
, ErrorCode
, Flags
;
2258 USHORT ImageMachine
;
2259 ULONG ParameterFlags
, PrivilegeValue
, HardErrorMode
, ErrorResponse
;
2260 ULONG_PTR ErrorParameters
[2];
2261 BOOLEAN InJob
, SaferNeeded
, UseLargePages
, HavePrivilege
;
2262 BOOLEAN QuerySection
, SkipSaferAndAppCompat
;
2264 BASE_API_MESSAGE CsrMsg
[2];
2265 PBASE_CREATE_PROCESS CreateProcessMsg
;
2266 PCSR_CAPTURE_BUFFER CaptureBuffer
;
2267 PVOID BaseAddress
, PrivilegeState
, RealTimePrivilegeState
;
2268 HANDLE DebugHandle
, TokenHandle
, JobHandle
, KeyHandle
, ThreadHandle
;
2269 HANDLE FileHandle
, SectionHandle
, ProcessHandle
;
2271 PROCESS_PRIORITY_CLASS PriorityClass
;
2272 NTSTATUS Status
, AppCompatStatus
, SaferStatus
, IFEOStatus
, ImageDbgStatus
;
2273 PPEB Peb
, RemotePeb
;
2275 INITIAL_TEB InitialTeb
;
2277 PIMAGE_NT_HEADERS NtHeaders
;
2278 STARTUPINFOW StartupInfo
;
2279 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
2280 UNICODE_STRING DebuggerString
;
2283 // Variables used for command-line and argument parsing
2288 ULONG Length
, FileAttribs
, CmdQuoteLength
;
2290 SIZE_T EnvironmentLength
, CmdLineLength
;
2291 PWCHAR QuotedCmdLine
, AnsiCmdCommand
, ExtBuffer
, CurrentDirectory
;
2292 PWCHAR NullBuffer
, ScanString
, NameBuffer
, SearchPath
, DebuggerCmdLine
;
2293 ANSI_STRING AnsiEnv
;
2294 UNICODE_STRING UnicodeEnv
, PathName
;
2295 BOOLEAN SearchRetry
, QuotesNeeded
, CmdLineIsAppName
, HasQuotes
;
2298 // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2300 RTL_PATH_TYPE SxsPathType
, PathType
;
2301 #if _SXS_SUPPORT_ENABLED_
2302 PRTL_BUFFER ByteBuffer
;
2303 PRTL_UNICODE_STRING_BUFFER ThisBuffer
, Buffer
, SxsStaticBuffers
[5];
2304 PRTL_UNICODE_STRING_BUFFER
* BufferHead
, SxsStringBuffer
;
2305 RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath
, SxsNtManifestPath
;
2306 RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath
, SxsNtPolicyPath
;
2307 RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory
;
2308 BASE_MSG_SXS_HANDLES MappedHandles
, Handles
, FileHandles
;
2309 PVOID CapturedStrings
[3];
2310 SXS_WIN32_NT_PATH_PAIR ExePathPair
, ManifestPathPair
, PolicyPathPair
;
2311 SXS_OVERRIDE_MANIFEST OverrideManifest
;
2312 UNICODE_STRING FreeString
, SxsNtExePath
;
2313 PWCHAR SxsConglomeratedBuffer
, StaticBuffer
;
2314 ULONG ConglomeratedBufferSizeBytes
, StaticBufferSize
, i
;
2319 // Variables used for path conversion (and partially Fusion/SxS)
2321 PWCHAR FilePart
, PathBuffer
, FreeBuffer
;
2322 BOOLEAN TranslationStatus
;
2323 RTL_RELATIVE_NAME_U SxsWin32RelativePath
;
2324 UNICODE_STRING PathBufferString
, SxsWin32ExePath
;
2327 // Variables used by Application Compatibility (and partially Fusion/SxS)
2329 PVOID AppCompatSxsData
, AppCompatData
;
2330 ULONG AppCompatSxsDataSize
, AppCompatDataSize
;
2332 // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2334 ULONG BinarySubType
, VdmBinaryType
, VdmTask
, VdmReserve
;
2336 BOOLEAN UseVdmReserve
;
2337 HANDLE VdmWaitObject
;
2338 ANSI_STRING VdmAnsiEnv
;
2339 UNICODE_STRING VdmString
, VdmUnicodeEnv
;
2341 PBASE_CHECK_VDM CheckVdmMsg
;
2343 /* Zero out the initial core variables and handles */
2344 QuerySection
= FALSE
;
2346 SkipSaferAndAppCompat
= FALSE
;
2353 SectionHandle
= NULL
;
2354 ProcessHandle
= NULL
;
2355 ThreadHandle
= NULL
;
2356 ClientId
.UniqueProcess
= ClientId
.UniqueThread
= 0;
2357 BaseAddress
= (PVOID
)1;
2359 /* Zero out initial SxS and Application Compatibility state */
2360 AppCompatData
= NULL
;
2361 AppCompatDataSize
= 0;
2362 AppCompatSxsData
= NULL
;
2363 AppCompatSxsDataSize
= 0;
2364 CaptureBuffer
= NULL
;
2365 #if _SXS_SUPPORT_ENABLED_
2366 SxsConglomeratedBuffer
= NULL
;
2370 /* Zero out initial parsing variables -- others are initialized later */
2371 DebuggerCmdLine
= NULL
;
2377 CurrentDirectory
= NULL
;
2379 DebuggerString
.Buffer
= NULL
;
2381 QuotedCmdLine
= NULL
;
2383 /* Zero out initial VDM state */
2384 VdmAnsiEnv
.Buffer
= NULL
;
2385 VdmUnicodeEnv
.Buffer
= NULL
;
2386 VdmString
.Buffer
= NULL
;
2391 VdmWaitObject
= NULL
;
2392 UseVdmReserve
= FALSE
;
2395 /* Set message structures */
2396 CreateProcessMsg
= &CsrMsg
[0].Data
.CreateProcessRequest
;
2397 CheckVdmMsg
= &CsrMsg
[1].Data
.CheckVDMRequest
;
2399 /* Clear the more complex structures by zeroing out their entire memory */
2400 RtlZeroMemory(&Context
, sizeof(Context
));
2401 #if _SXS_SUPPORT_ENABLED_
2402 RtlZeroMemory(&FileHandles
, sizeof(FileHandles
));
2403 RtlZeroMemory(&MappedHandles
, sizeof(MappedHandles
));
2404 RtlZeroMemory(&Handles
, sizeof(Handles
));
2406 RtlZeroMemory(&CreateProcessMsg
->Sxs
, sizeof(CreateProcessMsg
->Sxs
));
2407 RtlZeroMemory(&LocalProcessAttributes
, sizeof(LocalProcessAttributes
));
2408 RtlZeroMemory(&LocalThreadAttributes
, sizeof(LocalThreadAttributes
));
2410 /* Zero out output arguments as well */
2411 RtlZeroMemory(lpProcessInformation
, sizeof(*lpProcessInformation
));
2412 if (hNewToken
) *hNewToken
= NULL
;
2414 /* Capture the special window flag */
2415 NoWindow
= dwCreationFlags
& CREATE_NO_WINDOW
;
2416 dwCreationFlags
&= ~CREATE_NO_WINDOW
;
2418 #if _SXS_SUPPORT_ENABLED_
2419 /* Setup the SxS static string arrays and buffers */
2420 SxsStaticBuffers
[0] = &SxsWin32ManifestPath
;
2421 SxsStaticBuffers
[1] = &SxsWin32PolicyPath
;
2422 SxsStaticBuffers
[2] = &SxsWin32AssemblyDirectory
;
2423 SxsStaticBuffers
[3] = &SxsNtManifestPath
;
2424 SxsStaticBuffers
[4] = &SxsNtPolicyPath
;
2425 ExePathPair
.Win32
= &SxsWin32ExePath
;
2426 ExePathPair
.Nt
= &SxsNtExePath
;
2427 ManifestPathPair
.Win32
= &SxsWin32ManifestPath
.String
;
2428 ManifestPathPair
.Nt
= &SxsNtManifestPath
.String
;
2429 PolicyPathPair
.Win32
= &SxsWin32PolicyPath
.String
;
2430 PolicyPathPair
.Nt
= &SxsNtPolicyPath
.String
;
2433 DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName
, lpCommandLine
, dwCreationFlags
);
2435 /* Finally, set our TEB and PEB */
2436 Teb
= NtCurrentTeb();
2437 Peb
= NtCurrentPeb();
2439 /* This combination is illegal (see MSDN) */
2440 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2441 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2443 DPRINT1("Invalid flag combo used\n");
2444 SetLastError(ERROR_INVALID_PARAMETER
);
2448 /* Convert the priority class */
2449 if (dwCreationFlags
& IDLE_PRIORITY_CLASS
)
2451 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
2453 else if (dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
2455 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
2457 else if (dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
2459 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
2461 else if (dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
2463 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
2465 else if (dwCreationFlags
& HIGH_PRIORITY_CLASS
)
2467 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2469 else if (dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
2471 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2472 PriorityClass
.PriorityClass
+= (BasepIsRealtimeAllowed(FALSE
) != NULL
);
2476 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_INVALID
;
2479 /* Done with the priority masks, so get rid of them */
2480 PriorityClass
.Foreground
= FALSE
;
2481 dwCreationFlags
&= ~(NORMAL_PRIORITY_CLASS
|
2482 IDLE_PRIORITY_CLASS
|
2483 HIGH_PRIORITY_CLASS
|
2484 REALTIME_PRIORITY_CLASS
|
2485 BELOW_NORMAL_PRIORITY_CLASS
|
2486 ABOVE_NORMAL_PRIORITY_CLASS
);
2488 /* You cannot request both a shared and a separate WoW VDM */
2489 if ((dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2490 (dwCreationFlags
& CREATE_SHARED_WOW_VDM
))
2492 /* Fail such nonsensical attempts */
2493 DPRINT1("Invalid WOW flags\n");
2494 SetLastError(ERROR_INVALID_PARAMETER
);
2497 else if (!(dwCreationFlags
& CREATE_SHARED_WOW_VDM
) &&
2498 (BaseStaticServerData
->DefaultSeparateVDM
))
2500 /* A shared WoW VDM was not requested but system enforces separation */
2501 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
2504 /* If a shared WoW VDM is used, make sure the process isn't in a job */
2505 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2506 (NtIsProcessInJob(NtCurrentProcess(), NULL
)))
2508 /* Remove the shared flag and add the separate flag */
2509 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2510 CREATE_SEPARATE_WOW_VDM
;
2513 /* Convert the environment */
2514 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2516 /* Scan the environment to calculate its Unicode size */
2517 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
2518 while ((*pcScan
) || (*(pcScan
+ 1))) ++pcScan
;
2520 /* Make sure the environment is not too large */
2521 EnvironmentLength
= (pcScan
+ sizeof(ANSI_NULL
) - (PCHAR
)lpEnvironment
);
2522 if (EnvironmentLength
> MAXUSHORT
)
2525 SetLastError(ERROR_INVALID_PARAMETER
);
2529 /* Create our ANSI String */
2530 AnsiEnv
.Length
= (USHORT
)EnvironmentLength
;
2531 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ sizeof(ANSI_NULL
);
2533 /* Allocate memory for the Unicode Environment */
2534 UnicodeEnv
.Buffer
= NULL
;
2535 RegionSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
2536 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
2537 (PVOID
)&UnicodeEnv
.Buffer
,
2542 if (!NT_SUCCESS(Status
))
2545 BaseSetLastNTError(Status
);
2549 /* Use the allocated size and convert */
2550 UnicodeEnv
.MaximumLength
= (USHORT
)RegionSize
;
2551 Status
= RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
2552 if (!NT_SUCCESS(Status
))
2555 NtFreeVirtualMemory(NtCurrentProcess(),
2556 (PVOID
)&UnicodeEnv
.Buffer
,
2559 BaseSetLastNTError(Status
);
2563 /* Now set the Unicode environment as the environment string pointer */
2564 lpEnvironment
= UnicodeEnv
.Buffer
;
2567 /* Make a copy of the caller's startup info since we'll modify it */
2568 StartupInfo
= *lpStartupInfo
;
2570 /* Check if private data is being sent on the same channel as std handles */
2571 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2572 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2574 /* Cannot use the std handles since we have monitor/hotkey values */
2575 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2578 /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2580 /* New iteration -- free any existing name buffer */
2583 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2587 /* New iteration -- free any existing free buffer */
2590 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
2594 /* New iteration -- close any existing file handle */
2597 NtClose(FileHandle
);
2601 /* Set the initial parsing state. This code can loop -- don't move this! */
2604 QuotesNeeded
= FALSE
;
2605 CmdLineIsAppName
= FALSE
;
2607 /* First check if we don't have an application name */
2608 if (!lpApplicationName
)
2610 /* This should be the first time we attempt creating one */
2611 ASSERT(NameBuffer
== NULL
);
2613 /* Allocate a buffer to hold it */
2614 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2616 MAX_PATH
* sizeof(WCHAR
));
2619 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2624 /* Initialize the application name and our parsing parameters */
2625 lpApplicationName
= NullBuffer
= ScanString
= lpCommandLine
;
2627 /* Check for an initial quote*/
2628 if (*lpCommandLine
== L
'\"')
2630 /* We found a quote, keep searching for another one */
2631 SearchRetry
= FALSE
;
2633 lpApplicationName
= ScanString
;
2636 /* Have we found the terminating quote? */
2637 if (*ScanString
== L
'\"')
2639 /* We're done, get out of here */
2640 NullBuffer
= ScanString
;
2645 /* Keep searching for the quote */
2647 NullBuffer
= ScanString
;
2653 /* We simply make the application name be the command line*/
2654 lpApplicationName
= lpCommandLine
;
2657 /* Check if it starts with a space or tab */
2658 if ((*ScanString
== L
' ') || (*ScanString
== L
'\t'))
2660 /* Break out of the search loop */
2661 NullBuffer
= ScanString
;
2665 /* Keep searching for a space or tab */
2667 NullBuffer
= ScanString
;
2671 /* We have found the end of the application name, terminate it */
2672 SaveChar
= *NullBuffer
;
2673 *NullBuffer
= UNICODE_NULL
;
2675 /* New iteration -- free any existing saved path */
2678 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
2682 /* Now compute the final EXE path based on the name */
2683 SearchPath
= BaseComputeProcessExePath((LPWSTR
)lpApplicationName
);
2684 DPRINT("Search Path: %S\n", SearchPath
);
2687 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2692 /* And search for the executable in the search path */
2693 Length
= SearchPathW(SearchPath
,
2700 /* Did we find it? */
2701 if ((Length
) && (Length
< MAX_PATH
))
2703 /* Get file attributes */
2704 FileAttribs
= GetFileAttributesW(NameBuffer
);
2705 if ((FileAttribs
!= INVALID_FILE_ATTRIBUTES
) &&
2706 (FileAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
2708 /* This was a directory, fail later on */
2718 DPRINT("Length: %lu Buffer: %S\n", Length
, NameBuffer
);
2720 /* Check if there was a failure in SearchPathW */
2721 if ((Length
) && (Length
< MAX_PATH
))
2723 /* Everything looks good, restore the name */
2724 *NullBuffer
= SaveChar
;
2725 lpApplicationName
= NameBuffer
;
2729 /* Check if this was a relative path, which would explain it */
2730 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2731 if (PathType
!= RtlPathTypeRelative
)
2733 /* This should fail, and give us a detailed LastError */
2734 FileHandle
= CreateFileW(lpApplicationName
,
2740 FILE_ATTRIBUTE_NORMAL
,
2742 if (FileHandle
!= INVALID_HANDLE_VALUE
)
2744 /* It worked? Return a generic error */
2745 CloseHandle(FileHandle
);
2747 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2752 /* Path was absolute, which means it doesn't exist */
2753 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2756 /* Did we already fail once? */
2759 /* Set the error code */
2760 SetLastError(ErrorCode
);
2764 /* Not yet, cache it */
2765 ErrorCode
= GetLastError();
2768 /* Put back the command line */
2769 *NullBuffer
= SaveChar
;
2770 lpApplicationName
= NameBuffer
;
2772 /* It's possible there's whitespace in the directory name */
2773 if (!(*ScanString
) || !(SearchRetry
))
2775 /* Not the case, give up completely */
2780 /* There are spaces, so keep trying the next possibility */
2782 NullBuffer
= ScanString
;
2784 /* We will have to add a quote, since there is a space */
2785 QuotesNeeded
= TRUE
;
2790 else if (!(lpCommandLine
) || !(*lpCommandLine
))
2792 /* We don't have a command line, so just use the application name */
2793 CmdLineIsAppName
= TRUE
;
2794 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2797 /* Convert the application name to its NT path */
2798 TranslationStatus
= RtlDosPathNameToRelativeNtPathName_U(lpApplicationName
,
2801 &SxsWin32RelativePath
);
2802 if (!TranslationStatus
)
2804 /* Path must be invalid somehow, bail out */
2805 DPRINT1("Path translation for SxS failed\n");
2806 SetLastError(ERROR_PATH_NOT_FOUND
);
2811 /* Setup the buffer that needs to be freed at the end */
2812 ASSERT(FreeBuffer
== NULL
);
2813 FreeBuffer
= PathName
.Buffer
;
2815 /* Check what kind of path the application is, for SxS (Fusion) purposes */
2816 RtlInitUnicodeString(&SxsWin32ExePath
, lpApplicationName
);
2817 SxsPathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2818 if ((SxsPathType
!= RtlPathTypeDriveAbsolute
) &&
2819 (SxsPathType
!= RtlPathTypeLocalDevice
) &&
2820 (SxsPathType
!= RtlPathTypeRootLocalDevice
) &&
2821 (SxsPathType
!= RtlPathTypeUncAbsolute
))
2823 /* Relative-type path, get the full path */
2824 RtlInitEmptyUnicodeString(&PathBufferString
, NULL
, 0);
2825 Status
= RtlGetFullPathName_UstrEx(&SxsWin32ExePath
,
2833 if (!NT_SUCCESS(Status
))
2835 /* Fail the rest of the create */
2836 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2837 BaseSetLastNTError(Status
);
2842 /* Use this full path as the SxS path */
2843 SxsWin32ExePath
= PathBufferString
;
2844 PathBuffer
= PathBufferString
.Buffer
;
2845 PathBufferString
.Buffer
= NULL
;
2846 DPRINT("SxS Path: %S\n", PathBuffer
);
2849 /* Also set the .EXE path based on the path name */
2850 #if _SXS_SUPPORT_ENABLED_
2851 SxsNtExePath
= PathName
;
2853 if (SxsWin32RelativePath
.RelativeName
.Length
)
2855 /* If it's relative, capture the relative name */
2856 PathName
= SxsWin32RelativePath
.RelativeName
;
2860 /* Otherwise, it's absolute, make sure no relative dir is used */
2861 SxsWin32RelativePath
.ContainingDirectory
= NULL
;
2864 /* Now use the path name, and the root path, to try opening the app */
2865 DPRINT("Path: %wZ. Dir: %p\n", &PathName
, SxsWin32RelativePath
.ContainingDirectory
);
2866 InitializeObjectAttributes(&LocalObjectAttributes
,
2868 OBJ_CASE_INSENSITIVE
,
2869 SxsWin32RelativePath
.ContainingDirectory
,
2871 Status
= NtOpenFile(&FileHandle
,
2873 FILE_READ_ATTRIBUTES
|
2876 &LocalObjectAttributes
,
2878 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2879 FILE_SYNCHRONOUS_IO_NONALERT
|
2880 FILE_NON_DIRECTORY_FILE
);
2881 if (!NT_SUCCESS(Status
))
2883 /* Try to open the app just for execute purposes instead */
2884 Status
= NtOpenFile(&FileHandle
,
2885 SYNCHRONIZE
| FILE_EXECUTE
,
2886 &LocalObjectAttributes
,
2888 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2889 FILE_SYNCHRONOUS_IO_NONALERT
|
2890 FILE_NON_DIRECTORY_FILE
);
2893 /* Failure path, display which file failed to open */
2894 if (!NT_SUCCESS(Status
))
2895 DPRINT1("Open file failed: %lx (%wZ)\n", Status
, &PathName
);
2897 /* Cleanup in preparation for failure or success */
2898 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2900 if (!NT_SUCCESS(Status
))
2902 /* Failure path, try to understand why */
2903 if (RtlIsDosDeviceName_U(lpApplicationName
))
2905 /* If a device is being executed, return this special error code */
2906 SetLastError(ERROR_BAD_DEVICE
);
2912 /* Otherwise return the converted NT error code */
2913 BaseSetLastNTError(Status
);
2919 /* Did the caller specify a desktop? */
2920 if (!StartupInfo
.lpDesktop
)
2922 /* Use the one from the current process */
2923 StartupInfo
.lpDesktop
= Peb
->ProcessParameters
->DesktopInfo
.Buffer
;
2926 /* Create a section for this file */
2927 Status
= NtCreateSection(&SectionHandle
,
2934 DPRINT("Section status: %lx\n", Status
);
2935 if (NT_SUCCESS(Status
))
2937 /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2938 if (SharedUserData
->SuiteMask
& (VER_SUITE_EMBEDDEDNT
|
2939 VER_SUITE_DATACENTER
|
2940 VER_SUITE_PERSONAL
|
2943 /* These SKUs do not allow running certain applications */
2944 Status
= BasepCheckWebBladeHashes(FileHandle
);
2945 if (Status
== STATUS_ACCESS_DENIED
)
2947 /* And this is one of them! */
2948 DPRINT1("Invalid Blade hashes!\n");
2949 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE
);
2954 /* Did we get some other failure? */
2955 if (!NT_SUCCESS(Status
))
2957 /* If we couldn't check the hashes, assume nefariousness */
2958 DPRINT1("Tampered Blade hashes!\n");
2959 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
);
2965 /* Now do Winsafer, etc, checks */
2966 Status
= BasepIsProcessAllowed((LPWSTR
)lpApplicationName
);
2967 if (!NT_SUCCESS(Status
))
2969 /* Fail if we're not allowed to launch the process */
2970 DPRINT1("Process not allowed to launch: %lx\n", Status
);
2971 BaseSetLastNTError(Status
);
2974 NtClose(SectionHandle
);
2975 SectionHandle
= NULL
;
2981 /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
2982 if ((dwCreationFlags
& CREATE_FORCEDOS
) &&
2983 (BaseStaticServerData
->IsWowTaskReady
))
2985 /* This request can't be satisfied, instead, a separate VDM is needed */
2986 dwCreationFlags
&= ~(CREATE_FORCEDOS
| CREATE_SHARED_WOW_VDM
);
2987 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
2989 /* Set a failure code, ask for VDM reservation */
2990 Status
= STATUS_INVALID_IMAGE_WIN_16
;
2991 UseVdmReserve
= TRUE
;
2993 /* Close the current handle */
2994 NtClose(SectionHandle
);
2995 SectionHandle
= NULL
;
2997 /* Don't query the section later */
2998 QuerySection
= FALSE
;
3002 /* Did we already do these checks? */
3003 if (!SkipSaferAndAppCompat
)
3005 /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3006 if ((NT_SUCCESS(Status
)) ||
3007 ((Status
== STATUS_INVALID_IMAGE_NOT_MZ
) &&
3008 !(BaseIsDosApplication(&PathName
, Status
))))
3010 /* Clear the machine type in case of failure */
3013 /* Clean any app compat data that may have accumulated */
3014 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
3015 AppCompatData
= NULL
;
3016 AppCompatSxsData
= NULL
;
3018 /* Do we have a section? */
3021 /* Have we already queried it? */
3025 AppCompatStatus
= STATUS_SUCCESS
;
3029 /* Get some information about the executable */
3030 AppCompatStatus
= NtQuerySection(SectionHandle
,
3031 SectionImageInformation
,
3033 sizeof(ImageInformation
),
3037 /* Do we have section information now? */
3038 if (NT_SUCCESS(AppCompatStatus
))
3040 /* Don't ask for it again, save the machine type */
3041 QuerySection
= TRUE
;
3042 ImageMachine
= ImageInformation
.Machine
;
3046 /* Is there a reason/Shim we shouldn't run this application? */
3047 AppCompatStatus
= BasepCheckBadapp(FileHandle
,
3054 &AppCompatSxsDataSize
,
3056 if (!NT_SUCCESS(AppCompatStatus
))
3058 /* This is usually the status we get back */
3059 DPRINT1("App compat launch failure: %lx\n", AppCompatStatus
);
3060 if (AppCompatStatus
== STATUS_ACCESS_DENIED
)
3062 /* Convert it to something more Win32-specific */
3063 SetLastError(ERROR_CANCELLED
);
3067 /* Some other error */
3068 BaseSetLastNTError(AppCompatStatus
);
3071 /* Did we have a section? */
3075 NtClose(SectionHandle
);
3076 SectionHandle
= NULL
;
3086 //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3088 /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3089 if (!(SkipSaferAndAppCompat
) &&
3090 ~(dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
))
3096 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3097 case STATUS_INVALID_IMAGE_PROTECT
:
3098 case STATUS_INVALID_IMAGE_WIN_16
:
3099 case STATUS_FILE_IS_OFFLINE
:
3100 /* For all DOS, 16-bit, OS/2 images, we do*/
3103 case STATUS_INVALID_IMAGE_NOT_MZ
:
3104 /* For invalid files, we don't, unless it's a .BAT file */
3105 if (BaseIsDosApplication(&PathName
, Status
)) break;
3108 /* Any other error codes we also don't */
3109 if (!NT_SUCCESS(Status
))
3111 SaferNeeded
= FALSE
;
3114 /* But for success, we do */
3118 /* Okay, so what did the checks above result in? */
3121 /* We have to call into the WinSafer library and actually check */
3122 SaferStatus
= BasepCheckWinSaferRestrictions(hUserToken
,
3123 (LPWSTR
)lpApplicationName
,
3128 if (SaferStatus
== 0xFFFFFFFF)
3130 /* Back in 2003, they didn't have an NTSTATUS for this... */
3131 DPRINT1("WinSafer blocking process launch\n");
3132 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY
);
3137 /* Other status codes are not-Safer related, just convert them */
3138 if (!NT_SUCCESS(SaferStatus
))
3140 DPRINT1("Error checking WinSafer: %lx\n", SaferStatus
);
3141 BaseSetLastNTError(SaferStatus
);
3148 /* The last step is to figure out why the section object was not created */
3151 case STATUS_INVALID_IMAGE_WIN_16
:
3153 /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3154 if (!(dwCreationFlags
& CREATE_FORCEDOS
))
3156 /* Remember that we're launching WOW */
3159 /* Create the VDM environment, it's valid for WOW too */
3160 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3165 DPRINT1("VDM environment for WOW app failed\n");
3169 /* We're going to try this twice, so do a loop */
3172 /* Pick which kind of WOW mode we want to run in */
3173 VdmBinaryType
= (dwCreationFlags
&
3174 CREATE_SEPARATE_WOW_VDM
) ?
3175 BINARY_TYPE_SEPARATE_WOW
: BINARY_TYPE_WOW
;
3177 /* Get all the VDM settings and current status */
3178 Status
= BaseCheckVDM(VdmBinaryType
,
3189 /* If it worked, no need to try again */
3190 if (NT_SUCCESS(Status
)) break;
3192 /* Check if it's disallowed or if it's our second time */
3193 BaseSetLastNTError(Status
);
3194 if ((Status
== STATUS_VDM_DISALLOWED
) ||
3195 (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
) ||
3196 (GetLastError() == ERROR_ACCESS_DENIED
))
3198 /* Fail the call -- we won't try again */
3199 DPRINT1("VDM message failure for WOW: %lx\n", Status
);
3204 /* Try one more time, but with a separate WOW instance */
3205 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3208 /* Check which VDM state we're currently in */
3209 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3213 case VDM_NOT_LOADED
:
3214 /* VDM is not fully loaded, so not that much to undo */
3215 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3217 /* Reset VDM reserve if needed */
3218 if (UseVdmReserve
) VdmReserve
= 1;
3220 /* Get the required parameters and names for launch */
3221 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3228 DPRINT1("VDM Configuration failed for WOW\n");
3229 BaseSetLastNTError(Status
);
3233 /* Update the command-line with the VDM one instead */
3234 lpCommandLine
= VdmString
.Buffer
;
3235 lpApplicationName
= NULL
;
3237 /* We don't want a console, detachment, nor a window */
3238 dwCreationFlags
|= CREATE_NO_WINDOW
;
3239 dwCreationFlags
&= ~(CREATE_NEW_CONSOLE
| DETACHED_PROCESS
);
3241 /* Force feedback on */
3242 StartupInfo
.dwFlags
|= STARTF_FORCEONFEEDBACK
;
3247 /* VDM is ready, so we have to undo everything */
3248 VdmUndoLevel
= VDM_UNDO_REUSE
;
3250 /* Check if CSRSS wants us to wait on VDM */
3251 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3255 /* Something is wrong with VDM, we'll fail the call */
3256 DPRINT1("VDM is not ready for WOW\n");
3257 SetLastError(ERROR_NOT_READY
);
3265 /* Since to get NULL, we allocate from 0x1, account for this */
3268 /* This implies VDM is ready, so skip everything else */
3269 if (VdmWaitObject
) goto VdmShortCircuit
;
3271 /* Don't inherit handles since we're doing VDM now */
3272 bInheritHandles
= FALSE
;
3274 /* Had the user passed in environment? If so, destroy it */
3275 if ((lpEnvironment
) &&
3276 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3278 RtlDestroyEnvironment(lpEnvironment
);
3281 /* We've already done all these checks, don't do them again */
3282 SkipSaferAndAppCompat
= TRUE
;
3286 // There is no break here on purpose, so FORCEDOS drops down!
3289 case STATUS_INVALID_IMAGE_PROTECT
:
3290 case STATUS_INVALID_IMAGE_NOT_MZ
:
3291 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3293 /* We're launching an executable application */
3294 BinarySubType
= BINARY_TYPE_EXE
;
3296 /* We can drop here from other "cases" above too, so check */
3297 if ((Status
== STATUS_INVALID_IMAGE_PROTECT
) ||
3298 (Status
== STATUS_INVALID_IMAGE_NE_FORMAT
) ||
3299 (BinarySubType
= BaseIsDosApplication(&PathName
, Status
)))
3301 /* We're launching a DOS application */
3302 VdmBinaryType
= BINARY_TYPE_DOS
;
3304 /* Based on the caller environment, create a VDM one */
3305 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3310 DPRINT1("VDM environment for DOS failed\n");
3314 /* Check the current state of the VDM subsystem */
3315 Status
= BaseCheckVDM(VdmBinaryType
| BinarySubType
,
3325 if (!NT_SUCCESS(Status
))
3327 /* Failed to inquire about VDM, fail the call */
3328 DPRINT1("VDM message failure for DOS: %lx\n", Status
);
3329 BaseSetLastNTError(Status
);
3334 /* Handle possible VDM states */
3335 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3339 case VDM_NOT_LOADED
:
3340 /* If VDM is not loaded, we'll do a partial undo */
3341 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3343 /* A VDM process can't also be detached, so fail */
3344 if (dwCreationFlags
& DETACHED_PROCESS
)
3346 DPRINT1("Detached process but no VDM, not allowed\n");
3347 SetLastError(ERROR_ACCESS_DENIED
);
3351 /* Get the required parameters and names for launch */
3352 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3359 DPRINT1("VDM Configuration failed for DOS\n");
3360 BaseSetLastNTError(Status
);
3364 /* Update the command-line to launch VDM instead */
3365 lpCommandLine
= VdmString
.Buffer
;
3366 lpApplicationName
= NULL
;
3370 /* VDM is ready, so we have to undo everything */
3371 VdmUndoLevel
= VDM_UNDO_REUSE
;
3373 /* Check if CSRSS wants us to wait on VDM */
3374 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3378 /* Something is wrong with VDM, we'll fail the call */
3379 DPRINT1("VDM is not ready for DOS\n");
3380 SetLastError(ERROR_NOT_READY
);
3388 /* Since to get NULL, we allocate from 0x1, account for this */
3391 /* This implies VDM is ready, so skip everything else */
3392 if (VdmWaitObject
) goto VdmShortCircuit
;
3394 /* Don't inherit handles since we're doing VDM now */
3395 bInheritHandles
= FALSE
;
3397 /* Had the user passed in environment? If so, destroy it */
3398 if ((lpEnvironment
) &&
3399 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3401 RtlDestroyEnvironment(lpEnvironment
);
3404 /* Use our VDM Unicode environment instead */
3405 lpEnvironment
= VdmUnicodeEnv
.Buffer
;
3409 /* It's a batch file, get the extension */
3410 ExtBuffer
= &PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 4];
3412 /* Make sure the extensions are correct */
3413 if ((PathName
.Length
< (4 * sizeof(WCHAR
))) ||
3414 ((_wcsnicmp(ExtBuffer
, L
".bat", 4)) &&
3415 (_wcsnicmp(ExtBuffer
, L
".cmd", 4))))
3417 DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName
);
3418 SetLastError(ERROR_BAD_EXE_FORMAT
);
3423 /* Check if we need to account for quotes around the path */
3424 CmdQuoteLength
= CmdLineIsAppName
|| HasQuotes
;
3425 if (!CmdLineIsAppName
)
3427 if (HasQuotes
) CmdQuoteLength
++;
3434 /* Calculate the length of the command line */
3435 CmdLineLength
= wcslen(lpCommandLine
);
3436 CmdLineLength
+= wcslen(CMD_STRING
);
3437 CmdLineLength
+= CmdQuoteLength
+ sizeof(ANSI_NULL
);
3438 CmdLineLength
*= sizeof(WCHAR
);
3440 /* Allocate space for the new command line */
3441 AnsiCmdCommand
= RtlAllocateHeap(RtlGetProcessHeap(),
3444 if (!AnsiCmdCommand
)
3446 BaseSetLastNTError(STATUS_NO_MEMORY
);
3452 wcscpy(AnsiCmdCommand
, CMD_STRING
);
3453 if ((CmdLineIsAppName
) || (HasQuotes
))
3455 wcscat(AnsiCmdCommand
, L
"\"");
3457 wcscat(AnsiCmdCommand
, lpCommandLine
);
3458 if ((CmdLineIsAppName
) || (HasQuotes
))
3460 wcscat(AnsiCmdCommand
, L
"\"");
3463 /* Create it as a Unicode String */
3464 RtlInitUnicodeString(&DebuggerString
, AnsiCmdCommand
);
3466 /* Set the command line to this */
3467 lpCommandLine
= DebuggerString
.Buffer
;
3468 lpApplicationName
= NULL
;
3469 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3472 /* We've already done all these checks, don't do them again */
3473 SkipSaferAndAppCompat
= TRUE
;
3477 case STATUS_INVALID_IMAGE_WIN_64
:
3479 /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3480 DPRINT1("64-bit binary, failing\n");
3481 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3486 case STATUS_FILE_IS_OFFLINE
:
3488 /* Set the correct last error for this */
3489 DPRINT1("File is offline, failing\n");
3490 SetLastError(ERROR_FILE_OFFLINE
);
3496 /* Any other error, convert it to a generic Win32 error */
3497 if (!NT_SUCCESS(Status
))
3499 DPRINT1("Failed to create section: %lx\n", Status
);
3500 SetLastError(ERROR_BAD_EXE_FORMAT
);
3505 /* Otherwise, this must be success */
3506 ASSERT(Status
== STATUS_SUCCESS
);
3511 /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3512 if (!(IsWowApp
) && (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
3514 /* Ignore the nonsensical request */
3515 dwCreationFlags
&= ~CREATE_SEPARATE_WOW_VDM
;
3518 /* Did we already check information for the section? */
3521 /* Get some information about the executable */
3522 Status
= NtQuerySection(SectionHandle
,
3523 SectionImageInformation
,
3525 sizeof(ImageInformation
),
3527 if (!NT_SUCCESS(Status
))
3529 /* We failed, bail out */
3530 DPRINT1("Section query failed\n");
3531 BaseSetLastNTError(Status
);
3536 /* Don't check this later */
3537 QuerySection
= TRUE
;
3540 /* Check if this was linked as a DLL */
3541 if (ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3543 /* These aren't valid images to try to execute! */
3544 DPRINT1("Trying to launch a DLL, failing\n");
3545 SetLastError(ERROR_BAD_EXE_FORMAT
);
3550 /* Don't let callers pass in this flag -- we'll only get it from IFEO */
3551 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3553 /* Clear the IFEO-missing flag, before we know for sure... */
3554 ParameterFlags
&= ~2;
3556 /* If the process is being debugged, only read IFEO if the PEB says so */
3557 if (!(dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
)) ||
3558 (Peb
->ReadImageFileExecOptions
))
3560 /* Let's do this! Attempt to open IFEO */
3561 IFEOStatus
= LdrOpenImageFileOptionsKey(&PathName
, 0, &KeyHandle
);
3562 if (!NT_SUCCESS(IFEOStatus
))
3564 /* We failed, set the flag so we store this in the parameters */
3565 if (IFEOStatus
== STATUS_OBJECT_NAME_NOT_FOUND
) ParameterFlags
|= 2;
3569 /* Was this our first time going through this path? */
3570 if (!DebuggerCmdLine
)
3572 /* Allocate a buffer for the debugger path */
3573 DebuggerCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3575 MAX_PATH
* sizeof(WCHAR
));
3576 if (!DebuggerCmdLine
)
3578 /* Close IFEO on failure */
3579 IFEOStatus
= NtClose(KeyHandle
);
3580 ASSERT(NT_SUCCESS(IFEOStatus
));
3583 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3589 /* Now query for the debugger */
3590 IFEOStatus
= LdrQueryImageFileKeyOption(KeyHandle
,
3594 MAX_PATH
* sizeof(WCHAR
),
3596 if (!(NT_SUCCESS(IFEOStatus
)) ||
3597 (ResultSize
< sizeof(WCHAR
)) ||
3598 (DebuggerCmdLine
[0] == UNICODE_NULL
))
3600 /* If it's not there, or too small, or invalid, ignore it */
3601 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3602 DebuggerCmdLine
= NULL
;
3605 /* Also query if we should map with large pages */
3606 IFEOStatus
= LdrQueryImageFileKeyOption(KeyHandle
,
3610 sizeof(UseLargePages
),
3612 if ((NT_SUCCESS(IFEOStatus
)) && (UseLargePages
))
3614 /* Do it! This is the only way this flag can be set */
3615 Flags
|= PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3618 /* We're done with IFEO, can close it now */
3619 IFEOStatus
= NtClose(KeyHandle
);
3620 ASSERT(NT_SUCCESS(IFEOStatus
));
3624 /* Make sure the image was compiled for this processor */
3625 if ((ImageInformation
.Machine
< SharedUserData
->ImageNumberLow
) ||
3626 (ImageInformation
.Machine
> SharedUserData
->ImageNumberHigh
))
3628 /* It was not -- raise a hard error */
3629 ErrorResponse
= ResponseOk
;
3630 ErrorParameters
[0] = (ULONG_PTR
)&PathName
;
3631 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
,
3637 if (Peb
->ImageSubsystemMajorVersion
<= 3)
3639 /* If it's really old, return this error */
3640 SetLastError(ERROR_BAD_EXE_FORMAT
);
3644 /* Otherwise, return a more modern error */
3645 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3648 /* Go to the failure path */
3649 DPRINT1("Invalid image architecture: %lx\n", ImageInformation
.Machine
);
3654 /* Check if this isn't a Windows image */
3655 if ((ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_GUI
) &&
3656 (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_CUI
))
3658 /* Get rid of section-related information since we'll retry */
3659 NtClose(SectionHandle
);
3660 SectionHandle
= NULL
;
3661 QuerySection
= FALSE
;
3663 /* The only other non-Windows image type we support here is POSIX */
3664 if (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_POSIX_CUI
)
3666 /* Bail out if it's something else */
3667 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
3672 /* Now build the command-line to have posix launch this image */
3673 Result
= BuildSubSysCommandLine(L
"POSIX /P ",
3679 /* Bail out if that failed */
3680 DPRINT1("Subsystem command line failed\n");
3684 /* And re-try launching the process, with the new command-line now */
3685 lpCommandLine
= DebuggerString
.Buffer
;
3686 lpApplicationName
= NULL
;
3688 /* We've already done all these checks, don't do them again */
3689 SkipSaferAndAppCompat
= TRUE
;
3690 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3694 /* Was this image built for a version of Windows whose images we can run? */
3695 Result
= BasepIsImageVersionOk(ImageInformation
.SubSystemMajorVersion
,
3696 ImageInformation
.SubSystemMinorVersion
);
3699 /* It was not, bail out */
3700 DPRINT1("Invalid subsystem version: %hu.%hu\n",
3701 ImageInformation
.SubSystemMajorVersion
,
3702 ImageInformation
.SubSystemMinorVersion
);
3703 SetLastError(ERROR_BAD_EXE_FORMAT
);
3707 /* Check if there is a debugger associated with the application */
3708 if (DebuggerCmdLine
)
3710 /* Get the length of the command line */
3711 n
= wcslen(lpCommandLine
);
3714 /* There's no command line, use the application name instead */
3715 lpCommandLine
= (LPWSTR
)lpApplicationName
;
3716 n
= wcslen(lpCommandLine
);
3719 /* Protect against overflow */
3720 if (n
> UNICODE_STRING_MAX_CHARS
)
3722 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3727 /* Now add the length of the debugger command-line */
3728 n
+= wcslen(DebuggerCmdLine
);
3730 /* Again make sure we don't overflow */
3731 if (n
> UNICODE_STRING_MAX_CHARS
)
3733 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3738 /* Account for the quotes and space between the two */
3739 n
+= sizeof("\" \"") - sizeof(ANSI_NULL
);
3741 /* Convert to bytes, and make sure we don't overflow */
3743 if (n
> UNICODE_STRING_MAX_BYTES
)
3745 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3750 /* Allocate space for the string */
3751 DebuggerString
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, n
);
3752 if (!DebuggerString
.Buffer
)
3754 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3759 /* Set the length */
3760 RtlInitEmptyUnicodeString(&DebuggerString
,
3761 DebuggerString
.Buffer
,
3764 /* Now perform the command line creation */
3765 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
,
3767 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3768 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, L
" ");
3769 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3770 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, lpCommandLine
);
3771 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3773 /* Make sure it all looks nice */
3774 DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString
);
3776 /* Update the command line and application name */
3777 lpCommandLine
= DebuggerString
.Buffer
;
3778 lpApplicationName
= NULL
;
3780 /* Close all temporary state */
3781 NtClose(SectionHandle
);
3782 SectionHandle
= NULL
;
3783 QuerySection
= FALSE
;
3785 /* Free all temporary memory */
3786 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3788 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
3790 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3791 DebuggerCmdLine
= NULL
;
3792 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3796 /* Initialize the process object attributes */
3797 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3798 lpProcessAttributes
,
3800 if ((hUserToken
) && (lpProcessAttributes
))
3802 /* Augment them with information from the user */
3804 LocalProcessAttributes
= *lpProcessAttributes
;
3805 LocalProcessAttributes
.lpSecurityDescriptor
= NULL
;
3806 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3807 &LocalProcessAttributes
,
3811 /* Check if we're going to be debugged */
3812 if (dwCreationFlags
& DEBUG_PROCESS
)
3814 /* Set process flag */
3815 Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
3818 /* Check if we're going to be debugged */
3819 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3821 /* Connect to DbgUi */
3822 Status
= DbgUiConnectToDbg();
3823 if (!NT_SUCCESS(Status
))
3825 DPRINT1("Failed to connect to DbgUI!\n");
3826 BaseSetLastNTError(Status
);
3831 /* Get the debug object */
3832 DebugHandle
= DbgUiGetThreadDebugObject();
3834 /* Check if only this process will be debugged */
3835 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3837 /* Set process flag */
3838 Flags
|= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
;
3842 /* Set inherit flag */
3843 if (bInheritHandles
) Flags
|= PROCESS_CREATE_FLAGS_INHERIT_HANDLES
;
3845 /* Check if the process should be created with large pages */
3846 HavePrivilege
= FALSE
;
3847 PrivilegeState
= NULL
;
3848 if (Flags
& PROCESS_CREATE_FLAGS_LARGE_PAGES
)
3850 /* Acquire the required privilege so that the kernel won't fail the call */
3851 PrivilegeValue
= SE_LOCK_MEMORY_PRIVILEGE
;
3852 Status
= RtlAcquirePrivilege(&PrivilegeValue
, 1, 0, &PrivilegeState
);
3853 if (NT_SUCCESS(Status
))
3855 /* Remember to release it later */
3856 HavePrivilege
= TRUE
;
3860 /* Save the current TIB value since kernel overwrites it to store PEB */
3861 TibValue
= Teb
->NtTib
.ArbitraryUserPointer
;
3863 /* Tell the kernel to create the process */
3864 Status
= NtCreateProcessEx(&ProcessHandle
,
3874 /* Load the PEB address from the hacky location where the kernel stores it */
3875 RemotePeb
= Teb
->NtTib
.ArbitraryUserPointer
;
3877 /* And restore the old TIB value */
3878 Teb
->NtTib
.ArbitraryUserPointer
= TibValue
;
3880 /* Release the large page privilege if we had acquired it */
3881 if (HavePrivilege
) RtlReleasePrivilege(PrivilegeState
);
3883 /* And now check if the kernel failed to create the process */
3884 if (!NT_SUCCESS(Status
))
3886 /* Go to failure path */
3887 DPRINT1("Failed to create process: %lx\n", Status
);
3888 BaseSetLastNTError(Status
);
3893 /* Check if there is a priority class to set */
3894 if (PriorityClass
.PriorityClass
)
3896 /* Reset current privilege state */
3897 RealTimePrivilegeState
= NULL
;
3899 /* Is realtime priority being requested? */
3900 if (PriorityClass
.PriorityClass
== PROCESS_PRIORITY_CLASS_REALTIME
)
3902 /* Check if the caller has real-time access, and enable it if so */
3903 RealTimePrivilegeState
= BasepIsRealtimeAllowed(TRUE
);
3906 /* Set the new priority class and release the privilege */
3907 Status
= NtSetInformationProcess(ProcessHandle
,
3908 ProcessPriorityClass
,
3910 sizeof(PROCESS_PRIORITY_CLASS
));
3911 if (RealTimePrivilegeState
) RtlReleasePrivilege(RealTimePrivilegeState
);
3913 /* Check if we failed to set the priority class */
3914 if (!NT_SUCCESS(Status
))
3916 /* Bail out on failure */
3917 DPRINT1("Failed to set priority class: %lx\n", Status
);
3918 BaseSetLastNTError(Status
);
3924 /* Check if the caller wants the default error mode */
3925 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3927 /* Set Error Mode to only fail on critical errors */
3928 HardErrorMode
= SEM_FAILCRITICALERRORS
;
3929 NtSetInformationProcess(ProcessHandle
,
3930 ProcessDefaultHardErrorMode
,
3935 /* Check if this was a VDM binary */
3938 /* Update VDM by telling it the process has now been created */
3939 VdmWaitObject
= ProcessHandle
;
3940 Result
= BaseUpdateVDMEntry(VdmEntryUpdateProcess
,
3947 /* Bail out on failure */
3948 DPRINT1("Failed to update VDM with wait object\n");
3949 VdmWaitObject
= NULL
;
3953 /* At this point, a failure means VDM has to undo all the state */
3954 VdmUndoLevel
|= VDM_UNDO_FULL
;
3957 /* Check if VDM needed reserved low-memory */
3960 /* Reserve the requested allocation */
3961 RegionSize
= VdmReserve
;
3962 Status
= NtAllocateVirtualMemory(ProcessHandle
,
3967 PAGE_EXECUTE_READWRITE
);
3968 if (!NT_SUCCESS(Status
))
3970 /* Bail out on failure */
3971 DPRINT1("Failed to reserve memory for VDM: %lx\n", Status
);
3972 BaseSetLastNTError(Status
);
3977 VdmReserve
= (ULONG
)RegionSize
;
3980 /* Check if we've already queried information on the section */
3983 /* We haven't, so get some information about the executable */
3984 Status
= NtQuerySection(SectionHandle
,
3985 SectionImageInformation
,
3987 sizeof(ImageInformation
),
3989 if (!NT_SUCCESS(Status
))
3991 /* Bail out on failure */
3992 DPRINT1("Failed to query section: %lx\n", Status
);
3993 BaseSetLastNTError(Status
);
3998 /* If we encounter a restart, don't re-query this information again */
3999 QuerySection
= TRUE
;
4002 /* Do we need to apply SxS to this image? (On x86 this flag is set by PeFmtCreateSection) */
4003 if (!(ImageInformation
.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
))
4005 /* Too bad, we don't support this yet */
4006 DPRINT("Image should receive SxS Fusion Isolation\n");
4009 /* There's some SxS flag that we need to set if fusion flags have 1 set */
4010 if (FusionFlags
& 1) CreateProcessMsg
->Sxs
.Flags
|= 0x10;
4012 /* Check if we have a current directory */
4013 if (lpCurrentDirectory
)
4015 /* Allocate a buffer so we can keep a Unicode copy */
4016 DPRINT("Current directory: %S\n", lpCurrentDirectory
);
4017 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
4019 (MAX_PATH
* sizeof(WCHAR
)) +
4020 sizeof(UNICODE_NULL
));
4021 if (!CurrentDirectory
)
4023 /* Bail out if this failed */
4024 BaseSetLastNTError(STATUS_NO_MEMORY
);
4029 /* Get the length in Unicode */
4030 Length
= GetFullPathNameW(lpCurrentDirectory
,
4034 if (Length
> MAX_PATH
)
4036 /* The directory is too long, so bail out */
4037 SetLastError(ERROR_DIRECTORY
);
4042 /* Make sure the directory is actually valid */
4043 FileAttribs
= GetFileAttributesW(CurrentDirectory
);
4044 if ((FileAttribs
== INVALID_FILE_ATTRIBUTES
) ||
4045 !(FileAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
4047 /* It isn't, so bail out */
4048 DPRINT1("Current directory is invalid\n");
4049 SetLastError(ERROR_DIRECTORY
);
4055 /* Insert quotes if needed */
4056 if ((QuotesNeeded
) || (CmdLineIsAppName
))
4058 /* Allocate our buffer, plus enough space for quotes and a NULL */
4059 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
4061 (wcslen(lpCommandLine
) * sizeof(WCHAR
)) +
4062 (2 * sizeof(L
'\"') + sizeof(UNICODE_NULL
)));
4065 /* Copy the first quote */
4066 wcscpy(QuotedCmdLine
, L
"\"");
4068 /* Save the current null-character */
4071 SaveChar
= *NullBuffer
;
4072 *NullBuffer
= UNICODE_NULL
;
4075 /* Copy the command line and the final quote */
4076 wcscat(QuotedCmdLine
, lpCommandLine
);
4077 wcscat(QuotedCmdLine
, L
"\"");
4079 /* Copy the null-char back */
4082 *NullBuffer
= SaveChar
;
4083 wcscat(QuotedCmdLine
, NullBuffer
);
4088 /* We can't put quotes around the thing, so try it anyway */
4089 if (QuotesNeeded
) QuotesNeeded
= FALSE
;
4090 if (CmdLineIsAppName
) CmdLineIsAppName
= FALSE
;
4094 /* Use isolation if needed */
4095 if (CreateProcessMsg
->Sxs
.Flags
& 1) ParameterFlags
|= 1;
4097 /* Set the new command-line if needed */
4098 if ((QuotesNeeded
) || (CmdLineIsAppName
)) lpCommandLine
= QuotedCmdLine
;
4100 /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
4101 Result
= BasePushProcessParameters(ParameterFlags
,
4109 dwCreationFlags
| NoWindow
,
4111 IsWowApp
? IMAGE_SUBSYSTEM_WINDOWS_GUI
: 0,
4116 /* The remote process would have an undefined state, so fail the call */
4117 DPRINT1("BasePushProcessParameters failed\n");
4121 /* Free the VDM command line string as it's no longer needed */
4122 RtlFreeUnicodeString(&VdmString
);
4123 VdmString
.Buffer
= NULL
;
4125 /* Non-VDM console applications usually inherit handles unless specified */
4126 if (!(VdmBinaryType
) &&
4127 !(bInheritHandles
) &&
4128 !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
4129 !(dwCreationFlags
& (CREATE_NO_WINDOW
|
4130 CREATE_NEW_CONSOLE
|
4131 DETACHED_PROCESS
)) &&
4132 (ImageInformation
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
))
4134 /* Get the remote parameters */
4135 Status
= NtReadVirtualMemory(ProcessHandle
,
4136 &RemotePeb
->ProcessParameters
,
4138 sizeof(PRTL_USER_PROCESS_PARAMETERS
),
4140 if (NT_SUCCESS(Status
))
4142 /* Duplicate standard input unless it's a console handle */
4143 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
))
4145 StuffStdHandle(ProcessHandle
,
4146 Peb
->ProcessParameters
->StandardInput
,
4147 &ProcessParameters
->StandardInput
);
4150 /* Duplicate standard output unless it's a console handle */
4151 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
))
4153 StuffStdHandle(ProcessHandle
,
4154 Peb
->ProcessParameters
->StandardOutput
,
4155 &ProcessParameters
->StandardOutput
);
4158 /* Duplicate standard error unless it's a console handle */
4159 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardError
))
4161 StuffStdHandle(ProcessHandle
,
4162 Peb
->ProcessParameters
->StandardError
,
4163 &ProcessParameters
->StandardError
);
4168 /* Create the Thread's Stack */
4169 StackSize
= max(256 * 1024, ImageInformation
.MaximumStackSize
);
4170 Status
= BaseCreateStack(ProcessHandle
,
4171 ImageInformation
.CommittedStackSize
,
4174 if (!NT_SUCCESS(Status
))
4176 DPRINT1("Creating the thread stack failed: %lx\n", Status
);
4177 BaseSetLastNTError(Status
);
4182 /* Create the Thread's Context */
4183 BaseInitializeContext(&Context
,
4185 ImageInformation
.TransferAddress
,
4186 InitialTeb
.StackBase
,
4189 /* Convert the thread attributes */
4190 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4193 if ((hUserToken
) && (lpThreadAttributes
))
4195 /* If the caller specified a user token, zero the security descriptor */
4196 LocalThreadAttributes
= *lpThreadAttributes
;
4197 LocalThreadAttributes
.lpSecurityDescriptor
= NULL
;
4198 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4199 &LocalThreadAttributes
,
4203 /* Create the Kernel Thread Object */
4204 Status
= NtCreateThread(&ThreadHandle
,
4212 if (!NT_SUCCESS(Status
))
4214 /* A process is not allowed to exist without a main thread, so fail */
4215 DPRINT1("Creating the main thread failed: %lx\n", Status
);
4216 BaseSetLastNTError(Status
);
4221 /* Begin filling out the CSRSS message, first with our IDs and handles */
4222 CreateProcessMsg
->ProcessHandle
= ProcessHandle
;
4223 CreateProcessMsg
->ThreadHandle
= ThreadHandle
;
4224 CreateProcessMsg
->ClientId
= ClientId
;
4226 /* Write the remote PEB address and clear it locally, we no longer use it */
4227 CreateProcessMsg
->PebAddressNative
= RemotePeb
;
4229 DPRINT("TODO: WOW64 is not supported yet\n");
4230 CreateProcessMsg
->PebAddressWow64
= 0;
4232 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
) ||
4267 * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
4268 * (basesrv in particular) to know whether or not this is a GUI or a
4271 AddToHandle(CreateProcessMsg
->ProcessHandle
, 2);
4273 /* Also check if the parent is also a GUI process */
4274 NtHeaders
= RtlImageNtHeader(GetModuleHandle(NULL
));
4276 (NtHeaders
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
))
4278 /* Let it know that it should display the hourglass mouse cursor */
4279 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4283 /* For all apps, if this flag is on, the hourglass mouse cursor is shown.
4284 * Likewise, the opposite holds as well, and no-feedback has precedence. */
4285 if (StartupInfo
.dwFlags
& STARTF_FORCEONFEEDBACK
)
4287 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4289 if (StartupInfo
.dwFlags
& STARTF_FORCEOFFFEEDBACK
)
4291 RemoveFromHandle(CreateProcessMsg
->ProcessHandle
, 1);
4294 /* Also store which kind of VDM app (if any) this is */
4295 CreateProcessMsg
->VdmBinaryType
= VdmBinaryType
;
4297 /* And if it really is a VDM app... */
4300 /* Store the VDM console handle (none if inherited or WOW app) and the task ID */
4301 CreateProcessMsg
->hVDM
= VdmTask
? NULL
: Peb
->ProcessParameters
->ConsoleHandle
;
4302 CreateProcessMsg
->VdmTask
= VdmTask
;
4304 else if (VdmReserve
)
4306 /* Extended VDM, set a flag */
4307 CreateProcessMsg
->VdmBinaryType
|= BINARY_TYPE_WOW_EX
;
4310 /* Check if there's side-by-side assembly data associated with the process */
4311 if (CreateProcessMsg
->Sxs
.Flags
)
4313 /* This should not happen in ReactOS yet */
4314 DPRINT1("This is an SxS Message -- should not happen yet\n");
4315 BaseSetLastNTError(STATUS_NOT_IMPLEMENTED
);
4316 NtTerminateProcess(ProcessHandle
, STATUS_NOT_IMPLEMENTED
);
4321 /* We are finally ready to call CSRSS to tell it about our new process! */
4322 CsrClientCallServer((PCSR_API_MESSAGE
)&CsrMsg
[0],
4324 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
,
4325 BasepCreateProcess
),
4326 sizeof(*CreateProcessMsg
));
4328 /* CSRSS has returned, free the capture buffer now if we had one */
4331 CsrFreeCaptureBuffer(CaptureBuffer
);
4332 CaptureBuffer
= NULL
;
4335 /* Check if CSRSS failed to accept ownership of the new Windows process */
4336 if (!NT_SUCCESS(CsrMsg
[0].Status
))
4338 /* Terminate the process and enter failure path with the CSRSS status */
4339 DPRINT1("Failed to tell csrss about new process\n");
4340 BaseSetLastNTError(CsrMsg
[0].Status
);
4341 NtTerminateProcess(ProcessHandle
, CsrMsg
[0].Status
);
4346 /* Check if we have a token due to Authz/Safer, not passed by the user */
4347 if ((TokenHandle
) && !(hUserToken
))
4349 /* Replace the process and/or thread token with the one from Safer */
4350 Status
= BasepReplaceProcessThreadTokens(TokenHandle
,
4353 if (!NT_SUCCESS(Status
))
4355 /* If this failed, kill the process and enter the failure path */
4356 DPRINT1("Failed to update process token: %lx\n", Status
);
4357 NtTerminateProcess(ProcessHandle
, Status
);
4358 BaseSetLastNTError(Status
);
4364 /* Check if a job was associated with this process */
4367 /* Bind the process and job together now */
4368 Status
= NtAssignProcessToJobObject(JobHandle
, ProcessHandle
);
4369 if (!NT_SUCCESS(Status
))
4371 /* Kill the process and enter the failure path if binding failed */
4372 DPRINT1("Failed to assign process to job: %lx\n", Status
);
4373 NtTerminateProcess(ProcessHandle
, STATUS_ACCESS_DENIED
);
4374 BaseSetLastNTError(Status
);
4380 /* Finally, resume the thread to actually get the process started */
4381 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
4383 NtResumeThread(ThreadHandle
, &ResumeCount
);
4387 /* We made it this far, meaning we have a fully created process and thread */
4390 /* Anyone doing a VDM undo should now undo everything, since we are done */
4391 if (VdmUndoLevel
) VdmUndoLevel
|= VDM_UNDO_COMPLETED
;
4393 /* Having a VDM wait object implies this must be a VDM process */
4396 /* Check if it's a 16-bit separate WOW process */
4397 if (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
)
4399 /* OR-in the special flag to indicate this, and return to caller */
4400 AddToHandle(VdmWaitObject
, 2);
4401 lpProcessInformation
->hProcess
= VdmWaitObject
;
4403 /* Check if this was a re-used VDM */
4404 if (VdmUndoLevel
& VDM_UNDO_REUSE
)
4406 /* No Client ID should be returned in this case */
4407 ClientId
.UniqueProcess
= 0;
4408 ClientId
.UniqueThread
= 0;
4413 /* OR-in the special flag to indicate this is not a separate VDM,
4414 * and return the handle to the caller */
4415 AddToHandle(VdmWaitObject
, 1);
4416 lpProcessInformation
->hProcess
= VdmWaitObject
;
4419 /* Close the original process handle, since it's not needed for VDM */
4420 if (ProcessHandle
) NtClose(ProcessHandle
);
4424 /* This is a regular process, so return the real process handle */
4425 lpProcessInformation
->hProcess
= ProcessHandle
;
4428 /* Return the rest of the process information based on what we have so far */
4429 lpProcessInformation
->hThread
= ThreadHandle
;
4430 lpProcessInformation
->dwProcessId
= HandleToUlong(ClientId
.UniqueProcess
);
4431 lpProcessInformation
->dwThreadId
= HandleToUlong(ClientId
.UniqueThread
);
4433 /* NULL these out here so we know to treat this as a success scenario */
4434 ProcessHandle
= NULL
;
4435 ThreadHandle
= NULL
;
4438 /* Free the debugger command line if one was allocated */
4439 if (DebuggerCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
4441 /* Check if an SxS full path as queried */
4444 /* Reinitialize the executable path */
4445 RtlInitEmptyUnicodeString(&SxsWin32ExePath
, NULL
, 0);
4446 SxsWin32ExePath
.Length
= 0;
4448 /* Free the path buffer */
4449 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
4452 #if _SXS_SUPPORT_ENABLED_
4453 /* Check if this was a non-VDM process */
4456 /* Then it must've had SxS data, so close the handles used for it */
4457 BasepSxsCloseHandles(&Handles
);
4458 BasepSxsCloseHandles(&FileHandles
);
4460 /* Check if we built SxS byte buffers for this create process request */
4461 if (SxsConglomeratedBuffer
)
4463 /* Loop all of them */
4464 for (i
= 0; i
< 5; i
++)
4466 /* Check if this one was allocated */
4467 ThisBuffer
= SxsStaticBuffers
[i
];
4470 /* Get the underlying RTL_BUFFER structure */
4471 ByteBuffer
= &ThisBuffer
->ByteBuffer
;
4472 if ((ThisBuffer
!= (PVOID
)-8) && (ByteBuffer
->Buffer
))
4474 /* Check if it was dynamic */
4475 if (ByteBuffer
->Buffer
!= ByteBuffer
->StaticBuffer
)
4477 /* Free it from the heap */
4478 FreeString
.Buffer
= (PWCHAR
)ByteBuffer
->Buffer
;
4479 RtlFreeUnicodeString(&FreeString
);
4482 /* Reset the buffer to its static data */
4483 ByteBuffer
->Buffer
= ByteBuffer
->StaticBuffer
;
4484 ByteBuffer
->Size
= ByteBuffer
->StaticSize
;
4487 /* Reset the string to the static buffer */
4488 RtlInitEmptyUnicodeString(&ThisBuffer
->String
,
4489 (PWCHAR
)ByteBuffer
->StaticBuffer
,
4490 ByteBuffer
->StaticSize
);
4491 if (ThisBuffer
->String
.Buffer
)
4493 /* Also NULL-terminate it */
4494 *ThisBuffer
->String
.Buffer
= UNICODE_NULL
;
4501 /* Check if an environment was passed in */
4502 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
4505 RtlDestroyEnvironment(lpEnvironment
);
4507 /* If this was the VDM environment too, clear that as well */
4508 if (VdmUnicodeEnv
.Buffer
== lpEnvironment
) VdmUnicodeEnv
.Buffer
= NULL
;
4509 lpEnvironment
= NULL
;
4512 /* Unconditionally free all the name parsing buffers we always allocate */
4513 RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
4514 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
4515 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
4516 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
4518 /* Close open file/section handles */
4519 if (FileHandle
) NtClose(FileHandle
);
4520 if (SectionHandle
) NtClose(SectionHandle
);
4522 /* If we have a thread handle, this was a failure path */
4525 /* So kill the process and close the thread handle */
4526 NtTerminateProcess(ProcessHandle
, STATUS_SUCCESS
);
4527 NtClose(ThreadHandle
);
4530 /* If we have a process handle, this was a failure path, so close it */
4531 if (ProcessHandle
) NtClose(ProcessHandle
);
4533 /* Thread/process handles, if any, are now processed. Now close this one. */
4534 if (JobHandle
) NtClose(JobHandle
);
4536 /* Check if we had created a token */
4539 /* And if the user asked for one */
4542 /* Then return it */
4543 *hNewToken
= TokenHandle
;
4547 /* User didn't want it, so we used it temporarily -- close it */
4548 NtClose(TokenHandle
);
4552 /* Free any temporary app compatibility data, it's no longer needed */
4553 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
4555 /* Free a few strings. The API takes care of these possibly being NULL */
4556 RtlFreeUnicodeString(&VdmString
);
4557 RtlFreeUnicodeString(&DebuggerString
);
4559 /* Check if we had built any sort of VDM environment */
4560 if ((VdmAnsiEnv
.Buffer
) || (VdmUnicodeEnv
.Buffer
))
4563 BaseDestroyVDMEnvironment(&VdmAnsiEnv
, &VdmUnicodeEnv
);
4566 /* Check if this was any kind of VDM application that we ended up creating */
4567 if ((VdmUndoLevel
) && (!(VdmUndoLevel
& VDM_UNDO_COMPLETED
)))
4570 BaseUpdateVDMEntry(VdmEntryUndo
,
4575 /* And close whatever VDM handle we were using for notifications */
4576 if (VdmWaitObject
) NtClose(VdmWaitObject
);
4579 /* Check if we ended up here with an allocated search path, and free it */
4580 if (SearchPath
) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
4582 /* Finally, return the API's result */
4592 CreateProcessW(LPCWSTR lpApplicationName
,
4593 LPWSTR lpCommandLine
,
4594 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4595 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4596 BOOL bInheritHandles
,
4597 DWORD dwCreationFlags
,
4598 LPVOID lpEnvironment
,
4599 LPCWSTR lpCurrentDirectory
,
4600 LPSTARTUPINFOW lpStartupInfo
,
4601 LPPROCESS_INFORMATION lpProcessInformation
)
4603 /* Call the internal (but exported) version */
4604 return CreateProcessInternalW(NULL
,
4607 lpProcessAttributes
,
4614 lpProcessInformation
,
4623 CreateProcessInternalA(HANDLE hToken
,
4624 LPCSTR lpApplicationName
,
4625 LPSTR lpCommandLine
,
4626 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4627 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4628 BOOL bInheritHandles
,
4629 DWORD dwCreationFlags
,
4630 LPVOID lpEnvironment
,
4631 LPCSTR lpCurrentDirectory
,
4632 LPSTARTUPINFOA lpStartupInfo
,
4633 LPPROCESS_INFORMATION lpProcessInformation
,
4636 UNICODE_STRING CommandLine
;
4637 UNICODE_STRING ApplicationName
;
4638 UNICODE_STRING CurrentDirectory
;
4640 STARTUPINFOW StartupInfo
;
4642 DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, "
4643 "lpStartupInfo %p, lpProcessInformation %p\n",
4644 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
4645 lpStartupInfo
, lpProcessInformation
);
4647 /* Copy Startup Info */
4648 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
4650 /* Initialize all strings to nothing */
4651 CommandLine
.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 Basep8BitStringToDynamicUnicodeString(&CommandLine
,
4665 /* Convert the Name and Directory */
4666 if (lpApplicationName
)
4668 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
4671 if (lpCurrentDirectory
)
4673 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
4674 lpCurrentDirectory
);
4677 /* Now convert Startup Strings */
4678 if (lpStartupInfo
->lpReserved
)
4680 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
4681 &StartupInfo
.lpReserved
);
4683 if (lpStartupInfo
->lpDesktop
)
4685 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
4686 &StartupInfo
.lpDesktop
);
4688 if (lpStartupInfo
->lpTitle
)
4690 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
4691 &StartupInfo
.lpTitle
);
4694 /* Call the Unicode function */
4695 bRetVal
= CreateProcessInternalW(hToken
,
4696 ApplicationName
.Buffer
,
4698 lpProcessAttributes
,
4703 CurrentDirectory
.Buffer
,
4705 lpProcessInformation
,
4709 RtlFreeUnicodeString(&ApplicationName
);
4710 RtlFreeUnicodeString(&CommandLine
);
4711 RtlFreeUnicodeString(&CurrentDirectory
);
4712 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
4713 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
4714 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
4716 /* Return what Unicode did */
4721 * FUNCTION: The CreateProcess function creates a new process and its
4722 * primary thread. The new process executes the specified executable file
4725 * lpApplicationName = Pointer to name of executable module
4726 * lpCommandLine = Pointer to command line string
4727 * lpProcessAttributes = Process security attributes
4728 * lpThreadAttributes = Thread security attributes
4729 * bInheritHandles = Handle inheritance flag
4730 * dwCreationFlags = Creation flags
4731 * lpEnvironment = Pointer to new environment block
4732 * lpCurrentDirectory = Pointer to current directory name
4733 * lpStartupInfo = Pointer to startup info
4734 * lpProcessInformation = Pointer to process information
4741 CreateProcessA(LPCSTR lpApplicationName
,
4742 LPSTR lpCommandLine
,
4743 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4744 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4745 BOOL bInheritHandles
,
4746 DWORD dwCreationFlags
,
4747 LPVOID lpEnvironment
,
4748 LPCSTR lpCurrentDirectory
,
4749 LPSTARTUPINFOA lpStartupInfo
,
4750 LPPROCESS_INFORMATION lpProcessInformation
)
4752 /* Call the internal (but exported) version */
4753 return CreateProcessInternalA(NULL
,
4756 lpProcessAttributes
,
4763 lpProcessInformation
,
4773 WinExec(LPCSTR lpCmdLine
,
4776 STARTUPINFOA StartupInfo
;
4777 PROCESS_INFORMATION ProcessInformation
;
4780 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
4781 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
4782 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
4783 StartupInfo
.dwFlags
= 0;
4785 if (!CreateProcessA(NULL
,
4794 &ProcessInformation
))
4796 dosErr
= GetLastError();
4797 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
4800 if (NULL
!= UserWaitForInputIdleRoutine
)
4802 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
4806 NtClose(ProcessInformation
.hProcess
);
4807 NtClose(ProcessInformation
.hThread
);
4809 return 33; /* Something bigger than 31 means success. */