2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/proc/proc.c
5 * PURPOSE: Process functions
6 * PROGRAMMERS: Ariadne (ariadne@xs4all.nl)
11 /* INCLUDES ****************************************************************/
18 /* GLOBALS *******************************************************************/
20 WaitForInputIdleType UserWaitForInputIdleRoutine
;
21 UNICODE_STRING BaseUnicodeCommandLine
;
22 ANSI_STRING BaseAnsiCommandLine
;
23 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
24 LPSTARTUPINFOA BaseAnsiStartupInfo
= NULL
;
25 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
26 BOOLEAN g_AppCertInitialized
;
27 BOOLEAN g_HaveAppCerts
;
28 LIST_ENTRY BasepAppCertDllsList
;
29 RTL_CRITICAL_SECTION gcsAppCert
;
30 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
31 NTSTATUS g_AppCertStatus
;
32 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
35 BasepConfigureAppCertDlls
,
38 &BasepAppCertDllsList
,
45 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
46 HMODULE gSaferHandle
= (HMODULE
)-1;
49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
51 #define CMD_STRING L"cmd /c "
53 /* FUNCTIONS ****************************************************************/
57 StuffStdHandle(IN HANDLE ProcessHandle
,
58 IN HANDLE StandardHandle
,
62 HANDLE DuplicatedHandle
;
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, as long as they're not newer than us */
127 return ((ImageMajorVersion
>= 3) &&
128 ((ImageMajorVersion
!= 3) ||
129 (ImageMinorVersion
>= 10)) &&
130 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
131 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
132 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
137 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
142 /* Get all the MD5 hashes */
143 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
144 if (!NT_SUCCESS(Status
)) return Status
;
146 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
147 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
149 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
151 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
153 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
155 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
157 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
160 /* Actually, fuck it, don't block anything, we're open source */
161 return STATUS_SUCCESS
;
166 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
167 IN PWCHAR ComponentName
,
170 /* Pretty much the only thing this key is used for, is malware */
172 return STATUS_NOT_IMPLEMENTED
;
177 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
180 IN ULONG ValueLength
,
182 IN PVOID EntryContext
)
184 /* Add this to the certification list */
185 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
190 BasepIsProcessAllowed(IN LPWSTR ApplicationName
)
192 NTSTATUS Status
, Status1
;
195 HMODULE TrustLibrary
;
196 PBASEP_APPCERT_ENTRY Entry
;
198 PLIST_ENTRY NextEntry
;
200 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
201 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
203 /* Try to initialize the certification subsystem */
204 while (!g_AppCertInitialized
)
207 Status
= STATUS_SUCCESS
;
210 /* Acquire the lock while initializing and see if we lost a race */
211 RtlEnterCriticalSection(&gcsAppCert
);
212 if (g_AppCertInitialized
) break;
214 /* On embedded, there is a special DLL */
215 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
217 /* Allocate a buffer for the name */
218 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
220 MAX_PATH
* sizeof(WCHAR
) +
221 sizeof(UNICODE_NULL
));
224 /* Fail if no memory */
225 Status
= STATUS_NO_MEMORY
;
229 /* Now get the system32 directory in our buffer, make sure it fits */
230 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
231 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
233 /* Add a slash if needed, and add the embedded cert DLL name */
234 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
235 RtlCopyMemory(&Buffer
[Length
],
237 sizeof(L
"EmbdTrst.DLL"));
240 TrustLibrary
= LoadLibraryW(Buffer
);
243 /* And extract the special function out of it */
244 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
245 "ImageOkToRunOnEmbeddedNT");
249 /* If we didn't get this far, set a failure code */
250 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
255 /* Other systems have a registry entry for this */
256 Status1
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
257 if (NT_SUCCESS(Status1
))
259 /* Close it, we'll query it through Rtl */
262 /* Do the query, which will call a special callback */
263 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
268 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
270 Status
= STATUS_SUCCESS
;
275 /* Free any buffer if we had one */
276 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
278 /* Check for errors, or a missing embedded/custom certification DLL */
279 if (!NT_SUCCESS(Status
) ||
280 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
282 /* The subsystem is not active on this machine, so give up */
283 g_HaveAppCerts
= FALSE
;
284 g_AppCertStatus
= Status
;
288 /* We have certification DLLs active, remember this */
289 g_HaveAppCerts
= TRUE
;
292 /* We are done the initialization phase, release the lock */
293 g_AppCertInitialized
= TRUE
;
294 RtlLeaveCriticalSection(&gcsAppCert
);
297 /* If there's no certification DLLs present, return the failure code */
298 if (!g_HaveAppCerts
) return g_AppCertStatus
;
300 /* Otherwise, assume success and make sure we have *something* */
301 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
302 Status
= STATUS_SUCCESS
;
304 /* If the something is an embedded certification DLL, call it and return */
305 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
307 /* Otherwise we have custom certification DLLs, parse them */
308 NextEntry
= BasepAppCertDllsList
.Flink
;
310 while (NextEntry
!= &BasepAppCertDllsList
)
312 /* Make sure the entry has a callback */
313 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
314 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
316 /* Call it and check if it failed */
317 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
318 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
321 NextEntry
= NextEntry
->Flink
;
324 /* Now loop them again */
325 NextEntry
= BasepAppCertDllsList
.Flink
;
326 while (NextEntry
!= &BasepAppCertDllsList
)
328 /* Make sure the entry has a callback */
329 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
330 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
332 /* Call it, this time with the flag from the loop above */
333 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
336 /* All done, return the status */
342 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
343 IN HANDLE ProcessHandle
,
344 IN HANDLE ThreadHandle
)
347 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
349 /* Enter the application certification lock */
350 RtlEnterCriticalSection(&gcsAppCert
);
352 /* Check if we already know the function */
353 if (g_SaferReplaceProcessThreadTokens
)
356 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
364 /* Check if the app certification DLL isn't loaded */
365 if (!(gSaferHandle
) ||
366 (gSaferHandle
== (HMODULE
)-1) ||
367 (gSaferHandle
== (HMODULE
)-2))
369 /* Then we can't call the function */
370 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
374 /* We have the DLL, find the address of the Safer function */
375 Status
= LdrGetProcedureAddress(gSaferHandle
,
376 &SaferiReplaceProcessThreadTokens
,
378 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
379 if (NT_SUCCESS(Status
))
381 /* Found it, now call it */
382 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
390 /* We couldn't find it, so this must be an unsupported DLL */
391 LdrUnloadDll(gSaferHandle
);
393 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
398 /* Release the lock and return the result */
399 RtlLeaveCriticalSection(&gcsAppCert
);
405 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
410 ASSERT(Handles
!= NULL
);
411 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
413 /* Close the file handle */
416 Status
= NtClose(Handles
->File
);
417 ASSERT(NT_SUCCESS(Status
));
420 /* Close the section handle */
421 if (Handles
->Section
)
423 Status
= NtClose(Handles
->Section
);
424 ASSERT(NT_SUCCESS(Status
));
427 /* Unmap the section view */
428 if (Handles
->ViewBase
.QuadPart
)
430 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
431 (PVOID
)Handles
->ViewBase
.LowPart
);
432 ASSERT(NT_SUCCESS(Status
));
437 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
439 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
440 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
441 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
443 if (RealFilter
!= NULL
)
447 ExceptionDisposition
= RealFilter(ExceptionInfo
);
449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
454 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
455 RealFilter
!= UnhandledExceptionFilter
)
457 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
460 return ExceptionDisposition
;
465 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
467 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
471 /* Set our Start Address */
472 NtSetInformationThread(NtCurrentThread(),
473 ThreadQuerySetWin32StartAddress
,
475 sizeof(PPROCESS_START_ROUTINE
));
477 /* Call the Start Routine */
478 ExitThread(lpStartAddress());
480 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
482 /* Get the Exit code from the SEH Handler */
483 if (!BaseRunningInServerProcess
)
485 /* Kill the whole process, usually */
486 ExitProcess(_SEH2_GetExceptionCode());
490 /* If running inside CSRSS, kill just this thread */
491 ExitThread(_SEH2_GetExceptionCode());
499 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
500 IN PCLIENT_ID ClientId
)
503 BASE_API_MESSAGE ApiMessage
;
504 PBASE_CREATE_THREAD CreateThreadRequest
= &ApiMessage
.Data
.CreateThreadRequest
;
506 DPRINT("BasepNotifyCsrOfThread: Thread: %p, Handle %p\n",
507 ClientId
->UniqueThread
, ThreadHandle
);
509 /* Fill out the request */
510 CreateThreadRequest
->ClientId
= *ClientId
;
511 CreateThreadRequest
->ThreadHandle
= ThreadHandle
;
514 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
516 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
517 sizeof(BASE_CREATE_THREAD
));
518 if (!NT_SUCCESS(Status
))
520 DPRINT1("Failed to tell CSRSS about new thread: %lx\n", Status
);
525 return STATUS_SUCCESS
;
530 BasePushProcessParameters(IN ULONG ParameterFlags
,
531 IN HANDLE ProcessHandle
,
533 IN LPCWSTR ApplicationPathName
,
534 IN LPWSTR lpCurrentDirectory
,
535 IN LPWSTR lpCommandLine
,
536 IN LPVOID lpEnvironment
,
537 IN LPSTARTUPINFOW StartupInfo
,
538 IN DWORD CreationFlags
,
539 IN BOOL InheritHandles
,
540 IN ULONG ImageSubsystem
,
541 IN PVOID AppCompatData
,
542 IN ULONG AppCompatDataSize
)
544 WCHAR FullPath
[MAX_PATH
+ 5];
545 PWCHAR Remaining
, DllPathString
, ScanChar
;
546 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
547 PVOID RemoteAppCompatData
;
548 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
549 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
553 BOOLEAN HavePebLock
= FALSE
, Result
;
554 PPEB Peb
= NtCurrentPeb();
556 /* Get the full path name */
557 Size
= GetFullPathNameW(ApplicationPathName
,
561 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
563 /* Get the DLL Path */
564 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
568 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
572 /* Initialize Strings */
573 RtlInitUnicodeString(&DllPath
, DllPathString
);
574 RtlInitUnicodeString(&ImageName
, FullPath
);
578 /* Couldn't get the path name. Just take the original path */
579 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
584 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
588 /* Initialize Strings */
589 RtlInitUnicodeString(&DllPath
, DllPathString
);
590 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
593 /* Initialize Strings */
594 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
595 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
597 /* Initialize more Strings from the Startup Info */
598 if (StartupInfo
->lpDesktop
)
600 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
604 RtlInitUnicodeString(&Desktop
, L
"");
606 if (StartupInfo
->lpReserved
)
608 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
612 RtlInitUnicodeString(&Shell
, L
"");
614 if (StartupInfo
->lpTitle
)
616 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
620 RtlInitUnicodeString(&Title
, ApplicationPathName
);
623 /* This one is special because the length can differ */
624 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
625 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
627 /* Enforce no app compat data if the pointer was NULL */
628 if (!AppCompatData
) AppCompatDataSize
= 0;
630 /* Create the Parameter Block */
631 ProcessParameters
= NULL
;
632 DPRINT("ImageName: '%wZ'\n", &ImageName
);
633 DPRINT("DllPath : '%wZ'\n", &DllPath
);
634 DPRINT("CurDir : '%wZ'\n", &CurrentDirectory
);
635 DPRINT("CmdLine : '%wZ'\n", &CommandLine
);
636 DPRINT("Title : '%wZ'\n", &Title
);
637 DPRINT("Desktop : '%wZ'\n", &Desktop
);
638 DPRINT("Shell : '%wZ'\n", &Shell
);
639 DPRINT("Runtime : '%wZ'\n", &Runtime
);
640 Status
= RtlCreateProcessParameters(&ProcessParameters
,
644 &CurrentDirectory
: NULL
,
651 if (!NT_SUCCESS(Status
)) goto FailPath
;
653 /* Clear the current directory handle if not inheriting */
654 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
656 /* Check if the user passed in an environment */
659 /* We should've made it part of the parameters block, enforce this */
660 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
661 lpEnvironment
= ProcessParameters
->Environment
;
665 /* The user did not, so use the one from the current PEB */
668 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
671 /* Save pointer and start lookup */
672 ScanChar
= lpEnvironment
;
675 /* Find the environment size */
676 while (*ScanChar
++) while (*ScanChar
++);
677 EnviroSize
= (ULONG
)((ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
);
679 /* Allocate and Initialize new Environment Block */
681 ProcessParameters
->Environment
= NULL
;
682 Status
= NtAllocateVirtualMemory(ProcessHandle
,
683 (PVOID
*)&ProcessParameters
->Environment
,
688 if (!NT_SUCCESS(Status
)) goto FailPath
;
690 /* Write the Environment Block */
691 Status
= NtWriteVirtualMemory(ProcessHandle
,
692 ProcessParameters
->Environment
,
697 /* No longer need the PEB lock anymore */
705 /* Check if the write failed */
706 if (!NT_SUCCESS(Status
)) goto FailPath
;
709 /* Write new parameters */
710 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
711 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
712 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
713 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
714 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
715 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
716 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
717 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
718 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
720 /* Write the handles only if we have to */
721 if (StartupInfo
->dwFlags
&
722 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
724 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
725 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
726 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
729 /* Use Special Flags for BasepInitConsole in Kernel32 */
730 if (CreationFlags
& DETACHED_PROCESS
)
732 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
734 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
736 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
738 else if (CreationFlags
& CREATE_NO_WINDOW
)
740 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
744 /* Inherit our Console Handle */
745 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
747 /* Make sure that the shell isn't trampling on our handles first */
748 if (!(StartupInfo
->dwFlags
&
749 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
751 /* Copy the handle if we are inheriting or if it's a console handle */
752 if ((InheritHandles
) ||
753 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
755 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
757 if ((InheritHandles
) ||
758 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
760 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
762 if ((InheritHandles
) ||
763 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
765 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
770 /* Also set the Console Flag */
771 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
772 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
774 ProcessParameters
->ConsoleFlags
= 1;
777 /* Check if there's a .local file present */
778 if (ParameterFlags
& 1)
780 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
;
783 /* Check if we failed to open the IFEO key */
784 if (ParameterFlags
& 2)
786 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
;
789 /* Allocate memory for the parameter block */
790 Size
= ProcessParameters
->Length
;
791 RemoteParameters
= NULL
;
792 Status
= NtAllocateVirtualMemory(ProcessHandle
,
793 (PVOID
*)&RemoteParameters
,
798 if (!NT_SUCCESS(Status
)) goto FailPath
;
800 /* Set the allocated size */
801 ProcessParameters
->MaximumLength
= Size
;
803 /* Handle some Parameter Flags */
804 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
805 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
806 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
807 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
808 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
809 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
810 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
811 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
813 /* Write the Parameter Block */
814 Status
= NtWriteVirtualMemory(ProcessHandle
,
817 ProcessParameters
->Length
,
819 if (!NT_SUCCESS(Status
)) goto FailPath
;
821 /* Write the PEB Pointer */
822 Status
= NtWriteVirtualMemory(ProcessHandle
,
823 &RemotePeb
->ProcessParameters
,
827 if (!NT_SUCCESS(Status
)) goto FailPath
;
829 /* Check if there's any app compat data to write */
830 RemoteAppCompatData
= NULL
;
833 /* Allocate some space for the application compatibility data */
834 Size
= AppCompatDataSize
;
835 Status
= NtAllocateVirtualMemory(ProcessHandle
,
836 &RemoteAppCompatData
,
841 if (!NT_SUCCESS(Status
)) goto FailPath
;
843 /* Write the application compatibility data */
844 Status
= NtWriteVirtualMemory(ProcessHandle
,
849 if (!NT_SUCCESS(Status
)) goto FailPath
;
852 /* Write the PEB Pointer to the app compat data (might be NULL) */
853 Status
= NtWriteVirtualMemory(ProcessHandle
,
854 &RemotePeb
->pShimData
,
855 &RemoteAppCompatData
,
858 if (!NT_SUCCESS(Status
)) goto FailPath
;
860 /* Now write Peb->ImageSubSystem */
863 NtWriteVirtualMemory(ProcessHandle
,
864 &RemotePeb
->ImageSubsystem
,
866 sizeof(ImageSubsystem
),
875 if (HavePebLock
) RtlReleasePebLock();
876 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
877 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
880 DPRINT1("Failure to create process parameters: %lx\n", Status
);
881 BaseSetLastNTError(Status
);
888 InitCommandLines(VOID
)
892 /* Read the UNICODE_STRING from the PEB */
893 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
895 /* Convert to ANSI_STRING for the *A callers */
896 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
897 &BaseUnicodeCommandLine
,
899 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
902 /* PUBLIC FUNCTIONS ***********************************************************/
909 GetProcessAffinityMask(IN HANDLE hProcess
,
910 OUT PDWORD_PTR lpProcessAffinityMask
,
911 OUT PDWORD_PTR lpSystemAffinityMask
)
913 PROCESS_BASIC_INFORMATION ProcessInfo
;
916 /* Query information on the process from the kernel */
917 Status
= NtQueryInformationProcess(hProcess
,
918 ProcessBasicInformation
,
920 sizeof(PROCESS_BASIC_INFORMATION
),
922 if (!NT_SUCCESS(Status
))
925 BaseSetLastNTError(Status
);
929 /* Copy the affinity mask, and get the system one from our shared data */
930 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
931 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
940 SetProcessAffinityMask(IN HANDLE hProcess
,
941 IN DWORD_PTR dwProcessAffinityMask
)
945 /* Directly set the affinity mask */
946 Status
= NtSetInformationProcess(hProcess
,
948 (PVOID
)&dwProcessAffinityMask
,
950 if (!NT_SUCCESS(Status
))
953 BaseSetLastNTError(Status
);
957 /* Everything was ok */
966 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
967 OUT LPDWORD lpdwFlags
)
970 BASE_API_MESSAGE ApiMessage
;
971 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
973 /* Ask CSRSS for shutdown information */
974 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
976 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
977 sizeof(BASE_GETSET_PROCESS_SHUTDOWN_PARAMS
));
978 if (!NT_SUCCESS(Status
))
980 /* Return the failure from CSRSS */
981 BaseSetLastNTError(Status
);
985 /* Get the data back */
986 *lpdwLevel
= ShutdownParametersRequest
->ShutdownLevel
;
987 *lpdwFlags
= ShutdownParametersRequest
->ShutdownFlags
;
996 SetProcessShutdownParameters(IN DWORD dwLevel
,
1000 BASE_API_MESSAGE ApiMessage
;
1001 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
1003 /* Write the data into the CSRSS request and send it */
1004 ShutdownParametersRequest
->ShutdownLevel
= dwLevel
;
1005 ShutdownParametersRequest
->ShutdownFlags
= dwFlags
;
1006 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1008 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1009 sizeof(BASE_GETSET_PROCESS_SHUTDOWN_PARAMS
));
1010 if (!NT_SUCCESS(Status
))
1012 /* Return the failure from CSRSS */
1013 BaseSetLastNTError(Status
);
1026 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1027 OUT PSIZE_T lpMinimumWorkingSetSize
,
1028 OUT PSIZE_T lpMaximumWorkingSetSize
,
1031 QUOTA_LIMITS_EX QuotaLimits
;
1034 /* Query the kernel about this */
1035 Status
= NtQueryInformationProcess(hProcess
,
1038 sizeof(QUOTA_LIMITS_EX
),
1040 if (!NT_SUCCESS(Status
))
1043 BaseSetLastNTError(Status
);
1047 /* Copy the quota information out */
1048 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1049 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1050 *Flags
= QuotaLimits
.Flags
;
1059 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1060 OUT PSIZE_T lpMinimumWorkingSetSize
,
1061 OUT PSIZE_T lpMaximumWorkingSetSize
)
1064 return GetProcessWorkingSetSizeEx(hProcess
,
1065 lpMinimumWorkingSetSize
,
1066 lpMaximumWorkingSetSize
,
1075 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1076 IN SIZE_T dwMinimumWorkingSetSize
,
1077 IN SIZE_T dwMaximumWorkingSetSize
,
1080 QUOTA_LIMITS_EX QuotaLimits
;
1081 NTSTATUS Status
, ReturnStatus
;
1084 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1086 /* Zero out the input structure */
1087 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1089 /* Check if the caller sent any limits */
1090 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1092 /* Write the quota information */
1093 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1094 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1095 QuotaLimits
.Flags
= Flags
;
1097 /* Acquire the required privilege */
1098 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1100 /* Request the new quotas */
1101 ReturnStatus
= NtSetInformationProcess(hProcess
,
1104 sizeof(QuotaLimits
));
1105 Result
= NT_SUCCESS(ReturnStatus
);
1106 if (NT_SUCCESS(Status
))
1108 /* Release the privilege and set succes code */
1109 ASSERT(State
!= NULL
);
1110 RtlReleasePrivilege(State
);
1116 /* No limits, fail the call */
1117 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1121 /* Return result code, set error code if this was a failure */
1122 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1131 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1132 IN SIZE_T dwMinimumWorkingSetSize
,
1133 IN SIZE_T dwMaximumWorkingSetSize
)
1135 /* Call the newer API */
1136 return SetProcessWorkingSetSizeEx(hProcess
,
1137 dwMinimumWorkingSetSize
,
1138 dwMaximumWorkingSetSize
,
1147 GetProcessTimes(IN HANDLE hProcess
,
1148 IN LPFILETIME lpCreationTime
,
1149 IN LPFILETIME lpExitTime
,
1150 IN LPFILETIME lpKernelTime
,
1151 IN LPFILETIME lpUserTime
)
1153 KERNEL_USER_TIMES Kut
;
1156 /* Query the times */
1157 Status
= NtQueryInformationProcess(hProcess
,
1162 if (!NT_SUCCESS(Status
))
1164 /* Handle failure */
1165 BaseSetLastNTError(Status
);
1169 /* Copy all the times and return success */
1170 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1171 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1172 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1173 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1174 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1175 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1176 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1177 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1186 GetCurrentProcess(VOID
)
1188 return (HANDLE
)NtCurrentProcess();
1196 GetCurrentThread(VOID
)
1198 return (HANDLE
)NtCurrentThread();
1206 GetCurrentProcessId(VOID
)
1208 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1216 GetExitCodeProcess(IN HANDLE hProcess
,
1217 IN LPDWORD lpExitCode
)
1219 PROCESS_BASIC_INFORMATION ProcessBasic
;
1222 /* Ask the kernel */
1223 Status
= NtQueryInformationProcess(hProcess
,
1224 ProcessBasicInformation
,
1226 sizeof(PROCESS_BASIC_INFORMATION
),
1228 if (!NT_SUCCESS(Status
))
1230 /* We failed, was this because this is a VDM process? */
1231 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1233 /* Not a VDM process, fail the call */
1234 BaseSetLastNTError(Status
);
1238 /* Succes case, return the exit code */
1239 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1248 GetProcessId(IN HANDLE Process
)
1250 PROCESS_BASIC_INFORMATION ProcessBasic
;
1253 /* Query the kernel */
1254 Status
= NtQueryInformationProcess(Process
,
1255 ProcessBasicInformation
,
1257 sizeof(PROCESS_BASIC_INFORMATION
),
1259 if (!NT_SUCCESS(Status
))
1261 /* Handle failure */
1262 BaseSetLastNTError(Status
);
1266 /* Return the PID */
1267 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1275 OpenProcess(IN DWORD dwDesiredAccess
,
1276 IN BOOL bInheritHandle
,
1277 IN DWORD dwProcessId
)
1280 HANDLE ProcessHandle
;
1281 OBJECT_ATTRIBUTES ObjectAttributes
;
1284 /* Setup the input client ID structure */
1285 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1286 ClientId
.UniqueThread
= 0;
1288 /* This is needed just to define the inheritance flags */
1289 InitializeObjectAttributes(&ObjectAttributes
,
1291 (bInheritHandle
? OBJ_INHERIT
: 0),
1295 /* Now try to open the process */
1296 Status
= NtOpenProcess(&ProcessHandle
,
1300 if (!NT_SUCCESS(Status
))
1302 /* Handle failure */
1303 BaseSetLastNTError(Status
);
1307 /* Otherwise return a handle to the process */
1308 return ProcessHandle
;
1316 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1318 /* Write the global function pointer */
1319 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1327 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1329 PRTL_USER_PROCESS_PARAMETERS Params
;
1331 /* Get the process parameters */
1332 Params
= NtCurrentPeb()->ProcessParameters
;
1334 /* Copy the data out of there */
1335 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1336 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1337 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1338 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1339 lpStartupInfo
->dwX
= Params
->StartingX
;
1340 lpStartupInfo
->dwY
= Params
->StartingY
;
1341 lpStartupInfo
->dwXSize
= Params
->CountX
;
1342 lpStartupInfo
->dwYSize
= Params
->CountY
;
1343 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1344 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1345 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1346 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1347 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1348 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1349 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1351 /* Check if the standard handles are being used for other features */
1352 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1354 STARTF_SHELLPRIVATE
))
1356 /* These are, so copy the standard handles too */
1357 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1358 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1359 lpStartupInfo
->hStdError
= Params
->StandardError
;
1368 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1370 PRTL_USER_PROCESS_PARAMETERS Params
;
1371 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1372 LPSTARTUPINFOA StartupInfo
;
1375 /* Get the cached information as well as the PEB parameters */
1376 StartupInfo
= BaseAnsiStartupInfo
;
1377 Params
= NtCurrentPeb()->ProcessParameters
;
1379 /* Check if this is the first time we have to get the cached version */
1380 while (!StartupInfo
)
1382 /* Create new ANSI startup info */
1383 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1385 sizeof(*StartupInfo
));
1388 /* Zero out string pointers in case we fail to create them */
1389 StartupInfo
->lpReserved
= 0;
1390 StartupInfo
->lpDesktop
= 0;
1391 StartupInfo
->lpTitle
= 0;
1394 StartupInfo
->cb
= sizeof(*StartupInfo
);
1396 /* Copy what's already stored in the PEB */
1397 StartupInfo
->dwX
= Params
->StartingX
;
1398 StartupInfo
->dwY
= Params
->StartingY
;
1399 StartupInfo
->dwXSize
= Params
->CountX
;
1400 StartupInfo
->dwYSize
= Params
->CountY
;
1401 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1402 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1403 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1404 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1405 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1406 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1407 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1408 StartupInfo
->hStdInput
= Params
->StandardInput
;
1409 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1410 StartupInfo
->hStdError
= Params
->StandardError
;
1412 /* Copy shell info string */
1413 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1416 if (NT_SUCCESS(Status
))
1419 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1421 /* Copy desktop info string */
1422 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1423 &Params
->DesktopInfo
,
1425 if (NT_SUCCESS(Status
))
1428 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1430 /* Copy window title string */
1431 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1432 &Params
->WindowTitle
,
1434 if (NT_SUCCESS(Status
))
1437 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1439 /* We finished with the ANSI version, try to cache it */
1440 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo
,
1444 /* We were the first thread through, use the data */
1448 /* Someone beat us to it, use their data instead */
1449 StartupInfo
= BaseAnsiStartupInfo
;
1450 Status
= STATUS_SUCCESS
;
1452 /* We're going to free our own stuff, but not raise */
1453 RtlFreeAnsiString(&TitleString
);
1455 RtlFreeAnsiString(&DesktopString
);
1457 RtlFreeAnsiString(&ShellString
);
1459 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1463 /* No memory, fail */
1464 Status
= STATUS_NO_MEMORY
;
1467 /* Raise an error unless we got here due to the race condition */
1468 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1471 /* Now copy from the cached ANSI version */
1472 lpStartupInfo
->cb
= StartupInfo
->cb
;
1473 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1474 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1475 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1476 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1477 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1478 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1479 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1480 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1481 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1482 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1483 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1484 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1485 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1486 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1488 /* Check if the shell is hijacking the handles for other features */
1489 if (lpStartupInfo
->dwFlags
&
1490 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1492 /* It isn't, so we can return the raw values */
1493 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1494 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1495 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1499 /* It is, so make sure nobody uses these as console handles */
1500 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1501 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1502 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1511 FlushInstructionCache(IN HANDLE hProcess
,
1512 IN LPCVOID lpBaseAddress
,
1517 /* Call the native function */
1518 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, dwSize
);
1519 if (!NT_SUCCESS(Status
))
1521 /* Handle failure case */
1522 BaseSetLastNTError(Status
);
1535 ExitProcess(IN UINT uExitCode
)
1537 BASE_API_MESSAGE ApiMessage
;
1538 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1540 ASSERT(!BaseRunningInServerProcess
);
1544 /* Acquire the PEB lock */
1545 RtlAcquirePebLock();
1547 /* Kill all the threads */
1548 NtTerminateProcess(NULL
, 0);
1550 /* Unload all DLLs */
1551 LdrShutdownProcess();
1553 /* Notify Base Server of process termination */
1554 ExitProcessRequest
->uExitCode
= uExitCode
;
1555 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1557 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1558 sizeof(BASE_EXIT_PROCESS
));
1560 /* Now do it again */
1561 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1565 /* Release the PEB lock */
1566 RtlReleasePebLock();
1570 /* should never get here */
1580 TerminateProcess(IN HANDLE hProcess
,
1585 /* Check if no handle was passed in */
1588 /* Set error code */
1589 SetLastError(ERROR_INVALID_HANDLE
);
1593 /* Otherwise, try to terminate the process */
1594 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1595 if (NT_SUCCESS(Status
)) return TRUE
;
1597 /* It failed, convert error code */
1598 BaseSetLastNTError(Status
);
1601 /* This is the failure path */
1610 FatalAppExitA(UINT uAction
,
1611 LPCSTR lpMessageText
)
1613 PUNICODE_STRING MessageTextU
;
1614 ANSI_STRING MessageText
;
1617 /* Initialize the string using the static TEB pointer */
1618 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1619 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1621 /* Convert to unicode and just exit normally if this failed */
1622 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1623 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1625 /* Call the Wide function */
1626 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1634 FatalAppExitW(IN UINT uAction
,
1635 IN LPCWSTR lpMessageText
)
1637 UNICODE_STRING UnicodeString
;
1641 /* Setup the string to print out */
1642 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1644 /* Display the hard error no matter what */
1645 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1648 (PULONG_PTR
)&UnicodeString
,
1652 /* Give the user a chance to abort */
1653 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1655 /* Otherwise kill the process */
1664 FatalExit(IN
int ExitCode
)
1667 /* On Checked builds, Windows gives you a nice little debugger UI */
1669 DbgPrint("FatalExit...\n");
1674 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1682 ExitProcess(ExitCode
);
1689 /* On other builds, just kill the process */
1690 ExitProcess(ExitCode
);
1698 GetPriorityClass(IN HANDLE hProcess
)
1701 PROCESS_PRIORITY_CLASS PriorityClass
;
1703 /* Query the kernel */
1704 Status
= NtQueryInformationProcess(hProcess
,
1705 ProcessPriorityClass
,
1707 sizeof(PROCESS_PRIORITY_CLASS
),
1709 if (NT_SUCCESS(Status
))
1711 /* Handle the conversion from NT to Win32 classes */
1712 switch (PriorityClass
.PriorityClass
)
1714 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1715 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1716 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1717 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1718 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1719 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1724 BaseSetLastNTError(Status
);
1733 SetPriorityClass(IN HANDLE hProcess
,
1734 IN DWORD dwPriorityClass
)
1738 PROCESS_PRIORITY_CLASS PriorityClass
;
1740 /* Handle conversion from Win32 to NT priority classes */
1741 switch (dwPriorityClass
)
1743 case IDLE_PRIORITY_CLASS
:
1744 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1747 case BELOW_NORMAL_PRIORITY_CLASS
:
1748 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1751 case NORMAL_PRIORITY_CLASS
:
1752 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1755 case ABOVE_NORMAL_PRIORITY_CLASS
:
1756 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1759 case HIGH_PRIORITY_CLASS
:
1760 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1763 case REALTIME_PRIORITY_CLASS
:
1764 /* Try to acquire the privilege. If it fails, just use HIGH */
1765 State
= BasepIsRealtimeAllowed(TRUE
);
1766 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1767 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1771 /* Unrecognized priority classes don't make it to the kernel */
1772 SetLastError(ERROR_INVALID_PARAMETER
);
1776 /* Send the request to the kernel, and don't touch the foreground flag */
1777 PriorityClass
.Foreground
= FALSE
;
1778 Status
= NtSetInformationProcess(hProcess
,
1779 ProcessPriorityClass
,
1781 sizeof(PROCESS_PRIORITY_CLASS
));
1783 /* Release the privilege if we had it */
1784 if (State
) RtlReleasePrivilege(State
);
1785 if (!NT_SUCCESS(Status
))
1787 /* Handle error path */
1788 BaseSetLastNTError(Status
);
1801 GetProcessVersion(IN DWORD ProcessId
)
1804 PIMAGE_NT_HEADERS NtHeader
;
1805 PIMAGE_DOS_HEADER DosHeader
;
1807 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1810 HANDLE ProcessHandle
= NULL
;
1812 USHORT VersionData
[2];
1815 /* We'll be accessing stuff that can fault, so protect everything with SEH */
1818 /* It this an in-process or out-of-process request? */
1819 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
1821 /* It's in-process, so just read our own header */
1822 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
1825 /* Unable to read the NT header, something is wrong here... */
1826 Status
= STATUS_INVALID_IMAGE_FORMAT
;
1830 /* Get the version straight out of the NT header */
1831 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
1832 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
1836 /* Out-of-process, so open it */
1837 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1840 if (!ProcessHandle
) _SEH2_YIELD(return 0);
1842 /* Try to find out where its PEB lives */
1843 Status
= NtQueryInformationProcess(ProcessHandle
,
1844 ProcessBasicInformation
,
1846 sizeof(ProcessBasicInfo
),
1849 if (!NT_SUCCESS(Status
)) goto Error
;
1850 Peb
= ProcessBasicInfo
.PebBaseAddress
;
1852 /* Now that we have the PEB, read the image base address out of it */
1853 Result
= ReadProcessMemory(ProcessHandle
,
1854 &Peb
->ImageBaseAddress
,
1856 sizeof(BaseAddress
),
1858 if (!Result
) goto Error
;
1860 /* Now read the e_lfanew (offset to NT header) from the base */
1861 DosHeader
= BaseAddress
;
1862 Result
= ReadProcessMemory(ProcessHandle
,
1863 &DosHeader
->e_lfanew
,
1867 if (!Result
) goto Error
;
1869 /* And finally, read the NT header itself by adding the offset */
1870 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
1871 Result
= ReadProcessMemory(ProcessHandle
,
1872 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
1874 sizeof(VersionData
),
1876 if (!Result
) goto Error
;
1878 /* Get the version straight out of the NT header */
1879 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
1882 /* If there was an error anywhere, set the last error */
1883 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
1888 /* Close the process handle */
1889 if (ProcessHandle
) CloseHandle(ProcessHandle
);
1893 /* And return the version data */
1902 GetProcessIoCounters(IN HANDLE hProcess
,
1903 OUT PIO_COUNTERS lpIoCounters
)
1907 /* Query the kernel. Structures are identical, so let it do the copy too. */
1908 Status
= NtQueryInformationProcess(hProcess
,
1911 sizeof(IO_COUNTERS
),
1913 if (!NT_SUCCESS(Status
))
1915 /* Handle error path */
1916 BaseSetLastNTError(Status
);
1929 GetProcessPriorityBoost(IN HANDLE hProcess
,
1930 OUT PBOOL pDisablePriorityBoost
)
1933 ULONG PriorityBoost
;
1935 /* Query the kernel */
1936 Status
= NtQueryInformationProcess(hProcess
,
1937 ProcessPriorityBoost
,
1941 if (NT_SUCCESS(Status
))
1943 /* Convert from ULONG to a BOOL */
1944 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
1948 /* Handle error path */
1949 BaseSetLastNTError(Status
);
1958 SetProcessPriorityBoost(IN HANDLE hProcess
,
1959 IN BOOL bDisablePriorityBoost
)
1962 ULONG PriorityBoost
;
1964 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
1965 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
1966 Status
= NtSetInformationProcess(hProcess
,
1967 ProcessPriorityBoost
,
1970 if (!NT_SUCCESS(Status
))
1972 /* Handle error path */
1973 BaseSetLastNTError(Status
);
1986 GetProcessHandleCount(IN HANDLE hProcess
,
1987 OUT PDWORD pdwHandleCount
)
1992 /* Query the kernel */
1993 Status
= NtQueryInformationProcess(hProcess
,
1998 if (NT_SUCCESS(Status
))
2000 /* Copy the count and return sucecss */
2001 *pdwHandleCount
= phc
;
2005 /* Handle error path */
2006 BaseSetLastNTError(Status
);
2015 IsWow64Process(IN HANDLE hProcess
,
2016 OUT PBOOL Wow64Process
)
2021 /* Query the kernel */
2022 Status
= NtQueryInformationProcess(hProcess
,
2023 ProcessWow64Information
,
2027 if (!NT_SUCCESS(Status
))
2029 /* Handle error path */
2030 BaseSetLastNTError(Status
);
2034 /* Enforce this is a BOOL, and return success */
2035 *Wow64Process
= (pbi
!= 0);
2044 GetCommandLineA(VOID
)
2046 return BaseAnsiCommandLine
.Buffer
;
2054 GetCommandLineW(VOID
)
2056 return BaseUnicodeCommandLine
.Buffer
;
2064 ReadProcessMemory(IN HANDLE hProcess
,
2065 IN LPCVOID lpBaseAddress
,
2068 OUT SIZE_T
* lpNumberOfBytesRead
)
2073 Status
= NtReadVirtualMemory(hProcess
,
2074 (PVOID
)lpBaseAddress
,
2079 /* In user-mode, this parameter is optional */
2080 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2081 if (!NT_SUCCESS(Status
))
2084 BaseSetLastNTError(Status
);
2088 /* Return success */
2097 WriteProcessMemory(IN HANDLE hProcess
,
2098 IN LPVOID lpBaseAddress
,
2099 IN LPCVOID lpBuffer
,
2101 OUT SIZE_T
*lpNumberOfBytesWritten
)
2109 /* Set parameters for protect call */
2111 Base
= lpBaseAddress
;
2113 /* Check the current status */
2114 Status
= NtProtectVirtualMemory(hProcess
,
2117 PAGE_EXECUTE_READWRITE
,
2119 if (NT_SUCCESS(Status
))
2121 /* Check if we are unprotecting */
2122 UnProtect
= OldValue
& (PAGE_READWRITE
|
2124 PAGE_EXECUTE_READWRITE
|
2125 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2128 /* Set the new protection */
2129 Status
= NtProtectVirtualMemory(hProcess
,
2135 /* Write the memory */
2136 Status
= NtWriteVirtualMemory(hProcess
,
2142 /* In Win32, the parameter is optional, so handle this case */
2143 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2145 if (!NT_SUCCESS(Status
))
2148 BaseSetLastNTError(Status
);
2152 /* Flush the ITLB */
2153 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2158 /* Check if we were read only */
2159 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2161 /* Restore protection and fail */
2162 NtProtectVirtualMemory(hProcess
,
2167 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2169 /* Note: This is what Windows returns and code depends on it */
2170 return STATUS_ACCESS_VIOLATION
;
2173 /* Otherwise, do the write */
2174 Status
= NtWriteVirtualMemory(hProcess
,
2180 /* In Win32, the parameter is optional, so handle this case */
2181 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2183 /* And restore the protection */
2184 NtProtectVirtualMemory(hProcess
,
2189 if (!NT_SUCCESS(Status
))
2192 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2194 /* Note: This is what Windows returns and code depends on it */
2195 return STATUS_ACCESS_VIOLATION
;
2198 /* Flush the ITLB */
2199 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2206 BaseSetLastNTError(Status
);
2216 ProcessIdToSessionId(IN DWORD dwProcessId
,
2217 OUT PDWORD pSessionId
)
2219 PROCESS_SESSION_INFORMATION SessionInformation
;
2220 OBJECT_ATTRIBUTES ObjectAttributes
;
2222 HANDLE ProcessHandle
;
2225 /* Do a quick check if the pointer is not writable */
2226 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2229 SetLastError(ERROR_INVALID_PARAMETER
);
2233 /* Open the process passed in by ID */
2234 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2235 ClientId
.UniqueThread
= 0;
2236 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2237 Status
= NtOpenProcess(&ProcessHandle
,
2238 PROCESS_QUERY_INFORMATION
,
2241 if (NT_SUCCESS(Status
))
2243 /* Query the session ID from the kernel */
2244 Status
= NtQueryInformationProcess(ProcessHandle
,
2245 ProcessSessionInformation
,
2246 &SessionInformation
,
2247 sizeof(SessionInformation
),
2250 /* Close the handle and check if we suceeded */
2251 NtClose(ProcessHandle
);
2252 if (NT_SUCCESS(Status
))
2254 /* Return the session ID */
2255 *pSessionId
= SessionInformation
.SessionId
;
2260 /* Set error code and fail */
2261 BaseSetLastNTError(Status
);
2266 #define AddToHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) | (y));
2267 #define RemoveFromHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) & ~(y));
2268 C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME
== (PROCESS_PRIORITY_CLASS_HIGH
+ 1));
2275 CreateProcessInternalW(IN HANDLE hUserToken
,
2276 IN LPCWSTR lpApplicationName
,
2277 IN LPWSTR lpCommandLine
,
2278 IN LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2279 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2280 IN BOOL bInheritHandles
,
2281 IN DWORD dwCreationFlags
,
2282 IN LPVOID lpEnvironment
,
2283 IN LPCWSTR lpCurrentDirectory
,
2284 IN LPSTARTUPINFOW lpStartupInfo
,
2285 IN LPPROCESS_INFORMATION lpProcessInformation
,
2286 OUT PHANDLE hNewToken
)
2289 // Core variables used for creating the initial process and thread
2291 SECURITY_ATTRIBUTES LocalThreadAttributes
, LocalProcessAttributes
;
2292 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2293 POBJECT_ATTRIBUTES ObjectAttributes
;
2294 SECTION_IMAGE_INFORMATION ImageInformation
;
2295 IO_STATUS_BLOCK IoStatusBlock
;
2297 ULONG NoWindow
, RegionSize
, StackSize
, ErrorCode
, Flags
;
2298 USHORT ImageMachine
;
2299 ULONG ParameterFlags
, PrivilegeValue
, HardErrorMode
, ErrorResponse
;
2300 ULONG_PTR ErrorParameters
[2];
2301 BOOLEAN InJob
, SaferNeeded
, UseLargePages
, HavePrivilege
;
2302 BOOLEAN QuerySection
, SkipSaferAndAppCompat
;
2304 BASE_API_MESSAGE CsrMsg
;
2305 PBASE_CREATE_PROCESS CreateProcessMsg
;
2306 PCSR_CAPTURE_BUFFER CaptureBuffer
;
2307 PVOID BaseAddress
, PrivilegeState
, RealTimePrivilegeState
;
2308 HANDLE DebugHandle
, TokenHandle
, JobHandle
, KeyHandle
, ThreadHandle
;
2309 HANDLE FileHandle
, SectionHandle
, ProcessHandle
;
2311 PROCESS_PRIORITY_CLASS PriorityClass
;
2312 NTSTATUS Status
, Status1
, ImageDbgStatus
;
2313 PPEB Peb
, RemotePeb
;
2315 INITIAL_TEB InitialTeb
;
2317 PIMAGE_NT_HEADERS NtHeaders
;
2318 STARTUPINFOW StartupInfo
;
2319 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
2320 UNICODE_STRING DebuggerString
;
2323 // Variables used for command-line and argument parsing
2328 ULONG Length
, CurdirLength
, CmdQuoteLength
;
2329 ULONG CmdLineLength
, ResultSize
;
2330 PWCHAR QuotedCmdLine
, AnsiCmdCommand
, ExtBuffer
, CurrentDirectory
;
2331 PWCHAR NullBuffer
, ScanString
, NameBuffer
, SearchPath
, DebuggerCmdLine
;
2332 ANSI_STRING AnsiEnv
;
2333 UNICODE_STRING UnicodeEnv
, PathName
;
2334 BOOLEAN SearchRetry
, QuotesNeeded
, CmdLineIsAppName
, HasQuotes
;
2337 // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2339 RTL_PATH_TYPE SxsPathType
, PathType
;
2340 #if _SXS_SUPPORT_ENABLED_
2341 PRTL_BUFFER ByteBuffer
;
2342 PRTL_UNICODE_STRING_BUFFER ThisBuffer
, Buffer
, SxsStaticBuffers
[5];
2343 PRTL_UNICODE_STRING_BUFFER
* BufferHead
, SxsStringBuffer
;
2344 RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath
, SxsNtManifestPath
;
2345 RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath
, SxsNtPolicyPath
;
2346 RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory
;
2347 BASE_MSG_SXS_HANDLES MappedHandles
, Handles
, FileHandles
;
2348 PVOID CapturedStrings
[3];
2349 SXS_WIN32_NT_PATH_PAIR ExePathPair
, ManifestPathPair
, PolicyPathPair
;
2350 SXS_OVERRIDE_MANIFEST OverrideMannifest
;
2351 UNICODE_STRING FreeString
, SxsNtExePath
;
2352 PWCHAR SxsConglomeratedBuffer
, StaticBuffer
;
2353 ULONG ConglomeratedBufferSizeBytes
, StaticBufferSize
, i
;
2358 // Variables used for path conversion (and partially Fusion/SxS)
2360 PWCHAR FilePart
, PathBuffer
, FreeBuffer
;
2361 BOOLEAN TranslationStatus
;
2362 RTL_RELATIVE_NAME_U SxsWin32RelativePath
;
2363 UNICODE_STRING PathBufferString
, SxsWin32ExePath
;
2366 // Variables used by Application Compatibility (and partially Fusion/SxS)
2368 PVOID AppCompatSxsData
, AppCompatData
;
2369 ULONG AppCompatSxsDataSize
, AppCompatDataSize
;
2371 // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2373 ULONG BinarySubType
, VdmBinaryType
, VdmTask
, VdmReserve
;
2375 BOOLEAN UseVdmReserve
;
2376 HANDLE VdmWaitObject
;
2377 ANSI_STRING VdmAnsiEnv
;
2378 UNICODE_STRING VdmString
, VdmUnicodeEnv
;
2380 PBASE_CHECK_VDM CheckVdmMsg
;
2382 /* Zero out the initial core variables and handles */
2383 QuerySection
= FALSE
;
2385 SkipSaferAndAppCompat
= TRUE
; // HACK for making .bat/.cmd launch working again.
2392 SectionHandle
= NULL
;
2393 ProcessHandle
= NULL
;
2394 ThreadHandle
= NULL
;
2395 BaseAddress
= (PVOID
)1;
2397 /* Zero out initial SxS and Application Compatibility state */
2398 AppCompatData
= NULL
;
2399 AppCompatDataSize
= 0;
2400 AppCompatSxsData
= NULL
;
2401 AppCompatSxsDataSize
= 0;
2402 CaptureBuffer
= NULL
;
2403 #if _SXS_SUPPORT_ENABLED_
2404 SxsConglomeratedBuffer
= NULL
;
2408 /* Zero out initial parsing variables -- others are initialized later */
2409 DebuggerCmdLine
= NULL
;
2415 CurrentDirectory
= NULL
;
2417 DebuggerString
.Buffer
= NULL
;
2419 QuotedCmdLine
= NULL
;
2421 /* Zero out initial VDM state */
2422 VdmAnsiEnv
.Buffer
= NULL
;
2423 VdmUnicodeEnv
.Buffer
= NULL
;
2424 VdmString
.Buffer
= NULL
;
2429 VdmWaitObject
= NULL
;
2430 UseVdmReserve
= FALSE
;
2433 /* Set message structures */
2434 CreateProcessMsg
= &CsrMsg
.Data
.CreateProcessRequest
;
2435 CheckVdmMsg
= &CsrMsg
.Data
.CheckVDMRequest
;
2437 /* Clear the more complex structures by zeroing out their entire memory */
2438 RtlZeroMemory(&Context
, sizeof(Context
));
2439 #if _SXS_SUPPORT_ENABLED_
2440 RtlZeroMemory(&FileHandles
, sizeof(FileHandles
));
2441 RtlZeroMemory(&MappedHandles
, sizeof(MappedHandles
));
2442 RtlZeroMemory(&Handles
, sizeof(Handles
));
2444 RtlZeroMemory(&CreateProcessMsg
->Sxs
, sizeof(CreateProcessMsg
->Sxs
));
2445 RtlZeroMemory(&LocalProcessAttributes
, sizeof(LocalProcessAttributes
));
2446 RtlZeroMemory(&LocalThreadAttributes
, sizeof(LocalThreadAttributes
));
2448 /* Zero out output arguments as well */
2449 RtlZeroMemory(lpProcessInformation
, sizeof(*lpProcessInformation
));
2450 if (hNewToken
) *hNewToken
= NULL
;
2452 /* Capture the special window flag */
2453 NoWindow
= dwCreationFlags
& CREATE_NO_WINDOW
;
2454 dwCreationFlags
&= ~CREATE_NO_WINDOW
;
2456 #if _SXS_SUPPORT_ENABLED_
2457 /* Setup the SxS static string arrays and buffers */
2458 SxsStaticBuffers
[0] = &SxsWin32ManifestPath
;
2459 SxsStaticBuffers
[1] = &SxsWin32PolicyPath
;
2460 SxsStaticBuffers
[2] = &SxsWin32AssemblyDirectory
;
2461 SxsStaticBuffers
[3] = &SxsNtManifestPath
;
2462 SxsStaticBuffers
[4] = &SxsNtPolicyPath
;
2463 ExePathPair
.Win32
= &SxsWin32ExePath
;
2464 ExePathPair
.Nt
= &SxsNtExePath
;
2465 ManifestPathPair
.Win32
= &SxsWin32ManifestPath
.String
;
2466 ManifestPathPair
.Nt
= &SxsNtManifestPath
.String
;
2467 PolicyPathPair
.Win32
= &SxsWin32PolicyPath
.String
;
2468 PolicyPathPair
.Nt
= &SxsNtPolicyPath
.String
;
2471 DPRINT("CreateProcessInternalW: %S %S %lx\n", lpApplicationName
, lpCommandLine
, dwCreationFlags
);
2473 /* Finally, set our TEB and PEB */
2474 Teb
= NtCurrentTeb();
2475 Peb
= NtCurrentPeb();
2477 /* This combination is illegal (see MSDN) */
2478 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2479 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2481 DPRINT1("Invalid flag combo used\n");
2482 SetLastError(ERROR_INVALID_PARAMETER
);
2486 /* Convert the priority class */
2487 if (dwCreationFlags
& IDLE_PRIORITY_CLASS
)
2489 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
2491 else if (dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
2493 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
2495 else if (dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
2497 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
2499 else if (dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
2501 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
2503 else if (dwCreationFlags
& HIGH_PRIORITY_CLASS
)
2505 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2507 else if (dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
2509 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2510 PriorityClass
.PriorityClass
+= (BasepIsRealtimeAllowed(FALSE
) != NULL
);
2514 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_INVALID
;
2517 /* Done with the priority masks, so get rid of them */
2518 PriorityClass
.Foreground
= FALSE
;
2519 dwCreationFlags
&= ~(NORMAL_PRIORITY_CLASS
|
2520 IDLE_PRIORITY_CLASS
|
2521 HIGH_PRIORITY_CLASS
|
2522 REALTIME_PRIORITY_CLASS
|
2523 BELOW_NORMAL_PRIORITY_CLASS
|
2524 ABOVE_NORMAL_PRIORITY_CLASS
);
2526 /* You cannot request both a shared and a separate WoW VDM */
2527 if ((dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2528 (dwCreationFlags
& CREATE_SHARED_WOW_VDM
))
2530 /* Fail such nonsensical attempts */
2531 DPRINT1("Invalid WOW flags\n");
2532 SetLastError(ERROR_INVALID_PARAMETER
);
2535 else if (!(dwCreationFlags
& CREATE_SHARED_WOW_VDM
) &&
2536 (BaseStaticServerData
->DefaultSeparateVDM
))
2538 /* A shared WoW VDM was not requested but system enforces separation */
2539 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
2542 /* If a shared WoW VDM is used, make sure the process isn't in a job */
2543 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2544 (NtIsProcessInJob(NtCurrentProcess(), NULL
)))
2546 /* Remove the shared flag and add the separate flag */
2547 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2548 CREATE_SEPARATE_WOW_VDM
;
2551 /* Convert the environment */
2552 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2554 /* Scan the environment to calculate its Unicode size */
2555 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
2556 while ((*pcScan
) || (*(pcScan
+ 1))) ++pcScan
;
2558 /* Create our ANSI String */
2559 AnsiEnv
.Length
= pcScan
- (PCHAR
)lpEnvironment
+ sizeof(ANSI_NULL
);
2560 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ sizeof(ANSI_NULL
);
2562 /* Allocate memory for the Unicode Environment */
2563 UnicodeEnv
.Buffer
= NULL
;
2564 RegionSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
2565 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
2566 (PVOID
)&UnicodeEnv
.Buffer
,
2571 if (!NT_SUCCESS(Status
))
2574 BaseSetLastNTError(Status
);
2578 /* Use the allocated size and convert */
2579 UnicodeEnv
.MaximumLength
= (USHORT
)RegionSize
;
2580 Status
= RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
2581 if (!NT_SUCCESS(Status
))
2584 NtFreeVirtualMemory(NtCurrentProcess(),
2585 (PVOID
)&UnicodeEnv
.Buffer
,
2588 BaseSetLastNTError(Status
);
2592 /* Now set the Unicode environment as the environment string pointer */
2593 lpEnvironment
= UnicodeEnv
.Buffer
;
2596 /* Make a copy of the caller's startup info since we'll modify it */
2597 StartupInfo
= *lpStartupInfo
;
2599 /* Check if private data is being sent on the same channel as std handles */
2600 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2601 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2603 /* Cannot use the std handles since we have monitor/hotkey values */
2604 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2607 /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2609 /* New iteration -- free any existing name buffer */
2612 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2616 /* New iteration -- free any existing free buffer */
2619 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
2623 /* New iteration -- close any existing file handle */
2626 NtClose(FileHandle
);
2630 /* Set the initial parsing state. This code can loop -- don't move this! */
2633 QuotesNeeded
= FALSE
;
2634 CmdLineIsAppName
= FALSE
;
2636 /* First check if we don't have an application name */
2637 if (!lpApplicationName
)
2639 /* This should be the first time we attempt creating one */
2640 ASSERT(NameBuffer
== NULL
);
2642 /* Allocate a buffer to hold it */
2643 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2645 MAX_PATH
* sizeof(WCHAR
));
2648 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2653 /* Initialize the application name and our parsing parameters */
2654 lpApplicationName
= NullBuffer
= ScanString
= lpCommandLine
;
2656 /* Check for an initial quote*/
2657 if (*lpCommandLine
== L
'\"')
2659 /* We found a quote, keep searching for another one */
2660 SearchRetry
= FALSE
;
2662 lpApplicationName
= ScanString
;
2665 /* Have we found the terminating quote? */
2666 if (*ScanString
== L
'\"')
2668 /* We're done, get out of here */
2669 NullBuffer
= ScanString
;
2674 /* Keep searching for the quote */
2676 NullBuffer
= ScanString
;
2682 /* We simply make the application name be the command line*/
2683 lpApplicationName
= lpCommandLine
;
2686 /* Check if it starts with a space or tab */
2687 if ((*ScanString
== L
' ') || (*ScanString
== L
'\t'))
2689 /* Break out of the search loop */
2690 NullBuffer
= ScanString
;
2694 /* Keep searching for a space or tab */
2696 NullBuffer
= ScanString
;
2700 /* We have found the end of the application name, terminate it */
2701 SaveChar
= *NullBuffer
;
2702 *NullBuffer
= UNICODE_NULL
;
2704 /* New iteration -- free any existing saved path */
2707 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
2711 /* Now compute the final EXE path based on the name */
2712 SearchPath
= BaseComputeProcessExePath((LPWSTR
)lpApplicationName
);
2713 DPRINT("Search Path: %S\n", SearchPath
);
2716 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2721 /* And search for the executable in the search path */
2722 Length
= SearchPathW(SearchPath
,
2729 /* Did we find it? */
2730 if ((Length
) && (Length
< MAX_PATH
))
2732 /* Get file attributes */
2733 CurdirLength
= GetFileAttributesW(NameBuffer
);
2734 if ((CurdirLength
!= 0xFFFFFFFF) &&
2735 (CurdirLength
& FILE_ATTRIBUTE_DIRECTORY
))
2737 /* This was a directory, fail later on */
2747 DPRINT("Length: %lu Buffer: %S\n", Length
, NameBuffer
);
2749 /* Check if there was a failure in SearchPathW */
2750 if ((Length
) && (Length
< MAX_PATH
))
2752 /* Everything looks good, restore the name */
2753 *NullBuffer
= SaveChar
;
2754 lpApplicationName
= NameBuffer
;
2758 /* Check if this was a relative path, which would explain it */
2759 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2760 if (PathType
!= RtlPathTypeRelative
)
2762 /* This should fail, and give us a detailed LastError */
2763 FileHandle
= CreateFileW(lpApplicationName
,
2769 FILE_ATTRIBUTE_NORMAL
,
2771 if (FileHandle
!= INVALID_HANDLE_VALUE
)
2773 /* It worked? Return a generic error */
2774 CloseHandle(FileHandle
);
2776 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2781 /* Path was absolute, which means it doesn't exist */
2782 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2785 /* Did we already fail once? */
2788 /* Set the error code */
2789 SetLastError(ErrorCode
);
2793 /* Not yet, cache it */
2794 ErrorCode
= GetLastError();
2797 /* Put back the command line */
2798 *NullBuffer
= SaveChar
;
2799 lpApplicationName
= NameBuffer
;
2801 /* It's possible there's whitespace in the directory name */
2802 if (!(*ScanString
) || !(SearchRetry
))
2804 /* Not the case, give up completely */
2809 /* There are spaces, so keep trying the next possibility */
2811 NullBuffer
= ScanString
;
2813 /* We will have to add a quote, since there is a space */
2814 QuotesNeeded
= TRUE
;
2819 else if (!(lpCommandLine
) || !(*lpCommandLine
))
2821 /* We don't have a command line, so just use the application name */
2822 CmdLineIsAppName
= TRUE
;
2823 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2826 /* Convert the application name to its NT path */
2827 TranslationStatus
= RtlDosPathNameToRelativeNtPathName_U(lpApplicationName
,
2830 &SxsWin32RelativePath
);
2831 if (!TranslationStatus
)
2833 /* Path must be invaild somehow, bail out */
2834 DPRINT1("Path translation for SxS failed\n");
2835 SetLastError(ERROR_PATH_NOT_FOUND
);
2840 /* Setup the buffer that needs to be freed at the end */
2841 ASSERT(FreeBuffer
== NULL
);
2842 FreeBuffer
= PathName
.Buffer
;
2844 /* Check what kind of path the application is, for SxS (Fusion) purposes */
2845 RtlInitUnicodeString(&SxsWin32ExePath
, lpApplicationName
);
2846 SxsPathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2847 if ((SxsPathType
!= RtlPathTypeDriveAbsolute
) &&
2848 (SxsPathType
!= RtlPathTypeLocalDevice
) &&
2849 (SxsPathType
!= RtlPathTypeRootLocalDevice
) &&
2850 (SxsPathType
!= RtlPathTypeUncAbsolute
))
2852 /* Relative-type path, get the full path */
2853 RtlInitEmptyUnicodeString(&PathBufferString
, NULL
, 0);
2854 Status
= RtlGetFullPathName_UstrEx(&SxsWin32ExePath
,
2862 if (!NT_SUCCESS(Status
))
2864 /* Fail the rest of the create */
2865 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2866 BaseSetLastNTError(Status
);
2871 /* Use this full path as the SxS path */
2872 SxsWin32ExePath
= PathBufferString
;
2873 PathBuffer
= PathBufferString
.Buffer
;
2874 PathBufferString
.Buffer
= NULL
;
2875 DPRINT("SxS Path: %S\n", PathBuffer
);
2878 /* Also set the .EXE path based on the path name */
2879 #if _SXS_SUPPORT_ENABLED_
2880 SxsNtExePath
= PathName
;
2882 if (SxsWin32RelativePath
.RelativeName
.Length
)
2884 /* If it's relative, capture the relative name */
2885 PathName
= SxsWin32RelativePath
.RelativeName
;
2889 /* Otherwise, it's absolute, make sure no relative dir is used */
2890 SxsWin32RelativePath
.ContainingDirectory
= NULL
;
2893 /* Now use the path name, and the root path, to try opening the app */
2894 DPRINT("Path: %wZ. Dir: %p\n", &PathName
, SxsWin32RelativePath
.ContainingDirectory
);
2895 InitializeObjectAttributes(&LocalObjectAttributes
,
2897 OBJ_CASE_INSENSITIVE
,
2898 SxsWin32RelativePath
.ContainingDirectory
,
2900 Status
= NtOpenFile(&FileHandle
,
2902 FILE_READ_ATTRIBUTES
|
2905 &LocalObjectAttributes
,
2907 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2908 FILE_SYNCHRONOUS_IO_NONALERT
|
2909 FILE_NON_DIRECTORY_FILE
);
2910 if (!NT_SUCCESS(Status
))
2912 /* Try to open the app just for execute purposes instead */
2913 Status
= NtOpenFile(&FileHandle
,
2914 SYNCHRONIZE
| FILE_EXECUTE
,
2915 &LocalObjectAttributes
,
2917 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2918 FILE_SYNCHRONOUS_IO_NONALERT
|
2919 FILE_NON_DIRECTORY_FILE
);
2922 /* Cleanup in preparation for failure or success */
2923 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2924 if (!NT_SUCCESS(Status
))
2926 /* Failure path, try to understand why */
2927 DPRINT1("Open file failed: %lx\n", Status
);
2928 if (RtlIsDosDeviceName_U(lpApplicationName
))
2930 /* If a device is being executed, return this special error code */
2931 SetLastError(ERROR_BAD_DEVICE
);
2937 /* Otherwise return the converted NT error code */
2938 BaseSetLastNTError(Status
);
2944 /* Did the caller specify a desktop? */
2945 if (!StartupInfo
.lpDesktop
)
2947 /* Use the one from the current process */
2948 StartupInfo
.lpDesktop
= Peb
->ProcessParameters
->DesktopInfo
.Buffer
;
2951 /* Create a section for this file */
2952 Status
= NtCreateSection(&SectionHandle
,
2959 DPRINT("Section status: %lx\n", Status
);
2960 if (NT_SUCCESS(Status
))
2962 /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2963 if (SharedUserData
->SuiteMask
& (VER_SUITE_EMBEDDEDNT
|
2964 VER_SUITE_DATACENTER
|
2965 VER_SUITE_PERSONAL
|
2968 /* These SKUs do not allow running certain applications */
2969 Status
= BasepCheckWebBladeHashes(FileHandle
);
2970 if (Status
== STATUS_ACCESS_DENIED
)
2972 /* And this is one of them! */
2973 DPRINT1("Invalid Blade hashes!\n");
2974 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE
);
2979 /* Did we get some other failure? */
2980 if (!NT_SUCCESS(Status
))
2982 /* If we couldn't check the hashes, assume nefariousness */
2983 DPRINT1("Tampered Blade hashes!\n");
2984 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
);
2990 /* Now do Winsafer, etc, checks */
2991 Status
= BasepIsProcessAllowed((LPWSTR
)lpApplicationName
);
2992 if (!NT_SUCCESS(Status
))
2994 /* Fail if we're not allowed to launch the process */
2995 DPRINT1("Process not allowed to launch: %lx\n", Status
);
2996 BaseSetLastNTError(Status
);
2999 NtClose(SectionHandle
);
3000 SectionHandle
= NULL
;
3006 /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
3007 if ((dwCreationFlags
& CREATE_FORCEDOS
) &&
3008 (BaseStaticServerData
->IsWowTaskReady
))
3010 /* This request can't be satisfied, instead, a separate VDM is needed */
3011 dwCreationFlags
&= ~(CREATE_FORCEDOS
| CREATE_SHARED_WOW_VDM
);
3012 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3014 /* Set a failure code, ask for VDM reservation */
3015 Status
= STATUS_INVALID_IMAGE_WIN_16
;
3016 UseVdmReserve
= TRUE
;
3018 /* Close the current handle */
3019 NtClose(SectionHandle
);
3020 SectionHandle
= NULL
;
3022 /* Don't query the section later */
3023 QuerySection
= FALSE
;
3027 /* Did we already do these checks? */
3028 if (!SkipSaferAndAppCompat
)
3030 /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3031 if ((NT_SUCCESS(Status
)) ||
3032 ((Status
== STATUS_INVALID_IMAGE_NOT_MZ
) &&
3033 !(BaseIsDosApplication(&PathName
, Status
))))
3035 /* Clear the machine type in case of failure */
3038 /* Clean any app compat data that may have accumulated */
3039 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
3040 AppCompatData
= NULL
;
3041 AppCompatSxsData
= NULL
;
3043 /* Do we have a section? */
3046 /* Have we already queried it? */
3050 Status
= STATUS_SUCCESS
;
3054 /* Get some information about the executable */
3055 Status
= NtQuerySection(SectionHandle
,
3056 SectionImageInformation
,
3058 sizeof(ImageInformation
),
3062 /* Do we have section information now? */
3063 if (NT_SUCCESS(Status
))
3065 /* Don't ask for it again, save the machine type */
3066 QuerySection
= TRUE
;
3067 ImageMachine
= ImageInformation
.Machine
;
3071 /* Is there a reason/Shim we shouldn't run this application? */
3072 Status
= BasepCheckBadapp(FileHandle
,
3079 &AppCompatSxsDataSize
,
3081 if (!NT_SUCCESS(Status
))
3083 /* This is usually the status we get back */
3084 DPRINT1("App compat launch failure: %lx\n", Status
);
3085 if (Status
== STATUS_ACCESS_DENIED
)
3087 /* Convert it to something more Win32-specific */
3088 SetLastError(ERROR_CANCELLED
);
3092 /* Some other error */
3093 BaseSetLastNTError(Status
);
3096 /* Did we have a section? */
3100 NtClose(SectionHandle
);
3101 SectionHandle
= NULL
;
3111 //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3113 /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3114 if (!(SkipSaferAndAppCompat
) &&
3115 ~(dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
))
3121 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3122 case STATUS_INVALID_IMAGE_PROTECT
:
3123 case STATUS_INVALID_IMAGE_WIN_16
:
3124 case STATUS_FILE_IS_OFFLINE
:
3125 /* For all DOS, 16-bit, OS/2 images, we do*/
3128 case STATUS_INVALID_IMAGE_NOT_MZ
:
3129 /* For invalid files, we don't, unless it's a .BAT file */
3130 if (BaseIsDosApplication(&PathName
, Status
)) break;
3133 /* Any other error codes we also don't */
3134 if (!NT_SUCCESS(Status
))
3136 SaferNeeded
= FALSE
;
3139 /* But for success, we do */
3143 /* Okay, so what did the checks above result in? */
3146 /* We have to call into the WinSafer library and actually check */
3147 Status
= BasepCheckWinSaferRestrictions(hUserToken
,
3148 (LPWSTR
)lpApplicationName
,
3153 if (Status
== 0xFFFFFFFF)
3155 /* Back in 2003, they didn't have an NTSTATUS for this... */
3156 DPRINT1("WinSafer blocking process launch\n");
3157 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY
);
3162 /* Other status codes are not-Safer related, just convert them */
3163 if (!NT_SUCCESS(Status
))
3165 DPRINT1("Error checking WinSafer: %lx\n", Status
);
3166 BaseSetLastNTError(Status
);
3173 /* The last step is to figure out why the section object was not created */
3176 case STATUS_INVALID_IMAGE_WIN_16
:
3178 /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3179 if (!(dwCreationFlags
& CREATE_FORCEDOS
))
3181 /* Remember that we're launching WOW */
3184 /* Create the VDM environment, it's valid for WOW too */
3185 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3190 DPRINT1("VDM environment for WOW app failed\n");
3194 /* We're going to try this twice, so do a loop */
3197 /* Pick which kind of WOW mode we want to run in */
3198 VdmBinaryType
= (dwCreationFlags
&
3199 CREATE_SEPARATE_WOW_VDM
) ?
3200 BINARY_TYPE_SEPARATE_WOW
: BINARY_TYPE_WOW
;
3202 /* Get all the VDM settings and current status */
3203 Status
= BaseCheckVDM(VdmBinaryType
,
3214 /* If it worked, no need to try again */
3215 if (NT_SUCCESS(Status
)) break;
3217 /* Check if it's disallowed or if it's our second time */
3218 BaseSetLastNTError(Status
);
3219 if ((Status
== STATUS_VDM_DISALLOWED
) ||
3220 (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
) ||
3221 (GetLastError() == ERROR_ACCESS_DENIED
))
3223 /* Fail the call -- we won't try again */
3224 DPRINT1("VDM message failure for WOW: %lx\n", Status
);
3229 /* Try one more time, but with a separate WOW instance */
3230 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3233 /* Check which VDM state we're currently in */
3234 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3238 case VDM_NOT_LOADED
:
3239 /* VDM is not fully loaded, so not that much to undo */
3240 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3242 /* Reset VDM reserve if needed */
3243 if (UseVdmReserve
) VdmReserve
= 1;
3245 /* Get the required parameters and names for launch */
3246 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3253 DPRINT1("VDM Configuration failed for WOW\n");
3254 BaseSetLastNTError(Status
);
3258 /* Update the command-line with the VDM one instead */
3259 lpCommandLine
= VdmString
.Buffer
;
3260 lpApplicationName
= NULL
;
3262 /* We don't want a console, detachment, nor a window */
3263 dwCreationFlags
|= CREATE_NO_WINDOW
;
3264 dwCreationFlags
&= ~(CREATE_NEW_CONSOLE
| DETACHED_PROCESS
);
3266 /* Force feedback on */
3267 StartupInfo
.dwFlags
|= STARTF_FORCEONFEEDBACK
;
3272 /* VDM is ready, so we have to undo everything */
3273 VdmUndoLevel
= VDM_UNDO_REUSE
;
3275 /* Check if CSRSS wants us to wait on VDM */
3276 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3280 /* Something is wrong with VDM, we'll fail the call */
3281 DPRINT1("VDM is not ready for WOW\n");
3282 SetLastError(ERROR_NOT_READY
);
3290 /* Since to get NULL, we allocate from 0x1, account for this */
3293 /* This implies VDM is ready, so skip everything else */
3294 if (VdmWaitObject
) goto VdmShortCircuit
;
3296 /* Don't inherit handles since we're doing VDM now */
3297 bInheritHandles
= FALSE
;
3299 /* Had the user passed in environment? If so, destroy it */
3300 if ((lpEnvironment
) &&
3301 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3303 RtlDestroyEnvironment(lpEnvironment
);
3306 /* We've already done all these checks, don't do them again */
3307 SkipSaferAndAppCompat
= TRUE
;
3311 // There is no break here on purpose, so FORCEDOS drops down!
3314 case STATUS_INVALID_IMAGE_PROTECT
:
3315 case STATUS_INVALID_IMAGE_NOT_MZ
:
3316 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3318 /* We're launching an executable application */
3319 BinarySubType
= BINARY_TYPE_EXE
;
3321 /* We can drop here from other "cases" above too, so check */
3322 if ((Status
== STATUS_INVALID_IMAGE_PROTECT
) ||
3323 (Status
== STATUS_INVALID_IMAGE_NE_FORMAT
) ||
3324 (BinarySubType
= BaseIsDosApplication(&PathName
, Status
)))
3326 /* We're launching a DOS application */
3327 VdmBinaryType
= BINARY_TYPE_DOS
;
3329 /* Based on the caller environment, create a VDM one */
3330 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3335 DPRINT1("VDM environment for DOS failed\n");
3339 /* Check the current state of the VDM subsystem */
3340 Status
= BaseCheckVDM(VdmBinaryType
| BinarySubType
,
3350 if (!NT_SUCCESS(Status
))
3352 /* Failed to inquire about VDM, fail the call */
3353 DPRINT1("VDM message failure for DOS: %lx\n", Status
);
3354 BaseSetLastNTError(Status
);
3359 /* Handle possible VDM states */
3360 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3364 case VDM_NOT_LOADED
:
3365 /* If VDM is not loaded, we'll do a partial undo */
3366 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3368 /* A VDM process can't also be detached, so fail */
3369 if (dwCreationFlags
& DETACHED_PROCESS
)
3371 DPRINT1("Detached process but no VDM, not allowed\n");
3372 SetLastError(ERROR_ACCESS_DENIED
);
3376 /* Get the required parameters and names for launch */
3377 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3384 DPRINT1("VDM Configuration failed for DOS\n");
3385 BaseSetLastNTError(Status
);
3389 /* Update the command-line to launch VDM instead */
3390 lpCommandLine
= VdmString
.Buffer
;
3391 lpApplicationName
= NULL
;
3395 /* VDM is ready, so we have to undo everything */
3396 VdmUndoLevel
= VDM_UNDO_REUSE
;
3398 /* Check if CSRSS wants us to wait on VDM */
3399 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3403 /* Something is wrong with VDM, we'll fail the call */
3404 DPRINT1("VDM is not ready for DOS\n");
3405 SetLastError(ERROR_NOT_READY
);
3413 /* Since to get NULL, we allocate from 0x1, account for this */
3416 /* This implies VDM is ready, so skip everything else */
3417 if (VdmWaitObject
) goto VdmShortCircuit
;
3419 /* Don't inherit handles since we're doing VDM now */
3420 bInheritHandles
= FALSE
;
3422 /* Had the user passed in environment? If so, destroy it */
3423 if ((lpEnvironment
) &&
3424 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3426 RtlDestroyEnvironment(lpEnvironment
);
3429 /* Use our VDM Unicode environment instead */
3430 lpEnvironment
= VdmUnicodeEnv
.Buffer
;
3434 /* It's a batch file, get the extension */
3435 ExtBuffer
= &PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 4];
3437 /* Make sure the extensions are correct */
3438 if ((PathName
.Length
< (4 * sizeof(WCHAR
))) ||
3439 ((_wcsnicmp(ExtBuffer
, L
".bat", 4)) &&
3440 (_wcsnicmp(ExtBuffer
, L
".cmd", 4))))
3442 DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName
);
3443 SetLastError(ERROR_BAD_EXE_FORMAT
);
3448 /* Check if we need to account for quotes around the path */
3449 CmdQuoteLength
= CmdLineIsAppName
|| HasQuotes
;
3450 if (!CmdLineIsAppName
)
3452 if (HasQuotes
) CmdQuoteLength
++;
3459 /* Calculate the length of the command line */
3460 CmdLineLength
= wcslen(lpCommandLine
);
3461 CmdLineLength
+= wcslen(CMD_STRING
);
3462 CmdLineLength
+= CmdQuoteLength
+ sizeof(ANSI_NULL
);
3463 CmdLineLength
*= sizeof(WCHAR
);
3465 /* Allocate space for the new command line */
3466 AnsiCmdCommand
= RtlAllocateHeap(RtlGetProcessHeap(),
3469 if (!AnsiCmdCommand
)
3471 BaseSetLastNTError(STATUS_NO_MEMORY
);
3477 wcscpy(AnsiCmdCommand
, CMD_STRING
);
3478 if ((CmdLineIsAppName
) || (HasQuotes
))
3480 wcscat(AnsiCmdCommand
, L
"\"");
3482 wcscat(AnsiCmdCommand
, lpCommandLine
);
3483 if ((CmdLineIsAppName
) || (HasQuotes
))
3485 wcscat(AnsiCmdCommand
, L
"\"");
3488 /* Create it as a Unicode String */
3489 RtlInitUnicodeString(&DebuggerString
, AnsiCmdCommand
);
3491 /* Set the command line to this */
3492 lpCommandLine
= DebuggerString
.Buffer
;
3493 lpApplicationName
= NULL
;
3494 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3497 /* We've already done all these checks, don't do them again */
3498 SkipSaferAndAppCompat
= TRUE
;
3502 case STATUS_INVALID_IMAGE_WIN_64
:
3504 /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3505 DPRINT1("64-bit binary, failing\n");
3506 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3511 case STATUS_FILE_IS_OFFLINE
:
3513 /* Set the correct last error for this */
3514 DPRINT1("File is offline, failing\n");
3515 SetLastError(ERROR_FILE_OFFLINE
);
3521 /* Any other error, convert it to a generic Win32 error */
3522 if (!NT_SUCCESS(Status
))
3524 DPRINT1("Failed to create section: %lx\n", Status
);
3525 SetLastError(ERROR_BAD_EXE_FORMAT
);
3530 /* Otherwise, this must be success */
3531 ASSERT(Status
== STATUS_SUCCESS
);
3536 /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3537 if (!(IsWowApp
) && (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
3539 /* Ignore the nonsensical request */
3540 dwCreationFlags
&= ~CREATE_SEPARATE_WOW_VDM
;
3543 /* Did we already check information for the section? */
3546 /* Get some information about the executable */
3547 Status
= NtQuerySection(SectionHandle
,
3548 SectionImageInformation
,
3550 sizeof(ImageInformation
),
3552 if (!NT_SUCCESS(Status
))
3554 /* We failed, bail out */
3555 DPRINT1("Section query failed\n");
3556 BaseSetLastNTError(Status
);
3561 /* Don't check this later */
3562 QuerySection
= TRUE
;
3565 /* Check if this was linked as a DLL */
3566 if (ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3568 /* These aren't valid images to try to execute! */
3569 DPRINT1("Trying to launch a DLL, failing\n");
3570 SetLastError(ERROR_BAD_EXE_FORMAT
);
3575 /* Don't let callers pass in this flag -- we'll only get it from IFRO */
3576 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3578 /* Clear the IFEO-missing flag, before we know for sure... */
3579 ParameterFlags
&= ~2;
3581 /* If the process is being debugged, only read IFEO if the PEB says so */
3582 if (!(dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
)) ||
3583 (NtCurrentPeb()->ReadImageFileExecOptions
))
3585 /* Let's do this! Attempt to open IFEO */
3586 Status1
= LdrOpenImageFileOptionsKey(&PathName
, 0, &KeyHandle
);
3587 if (!NT_SUCCESS(Status1
))
3589 /* We failed, set the flag so we store this in the parameters */
3590 if (Status1
== STATUS_OBJECT_NAME_NOT_FOUND
) ParameterFlags
|= 2;
3594 /* Was this our first time going through this path? */
3595 if (!DebuggerCmdLine
)
3597 /* Allocate a buffer for the debugger path */
3598 DebuggerCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3600 MAX_PATH
* sizeof(WCHAR
));
3601 if (!DebuggerCmdLine
)
3603 /* Close IFEO on failure */
3604 Status1
= NtClose(KeyHandle
);
3605 ASSERT(NT_SUCCESS(Status1
));
3608 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3614 /* Now query for the debugger */
3615 Status1
= LdrQueryImageFileKeyOption(KeyHandle
,
3619 MAX_PATH
* sizeof(WCHAR
),
3621 if (!(NT_SUCCESS(Status1
)) ||
3622 (ResultSize
< sizeof(WCHAR
)) ||
3623 (DebuggerCmdLine
[0] == UNICODE_NULL
))
3625 /* If it's not there, or too small, or invalid, ignore it */
3626 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3627 DebuggerCmdLine
= NULL
;
3630 /* Also query if we should map with large pages */
3631 Status1
= LdrQueryImageFileKeyOption(KeyHandle
,
3635 sizeof(UseLargePages
),
3637 if ((NT_SUCCESS(Status1
)) && (UseLargePages
))
3639 /* Do it! This is the only way this flag can be set */
3640 Flags
|= PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3643 /* We're done with IFEO, can close it now */
3644 Status1
= NtClose(KeyHandle
);
3645 ASSERT(NT_SUCCESS(Status1
));
3649 /* Make sure the image was compiled for this processor */
3650 if ((ImageInformation
.Machine
< SharedUserData
->ImageNumberLow
) ||
3651 (ImageInformation
.Machine
> SharedUserData
->ImageNumberHigh
))
3653 /* It was not -- raise a hard error */
3654 ErrorResponse
= ResponseOk
;
3655 ErrorParameters
[0] = (ULONG_PTR
)&PathName
;
3656 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
,
3662 if (Peb
->ImageSubsystemMajorVersion
<= 3)
3664 /* If it's really old, return this error */
3665 SetLastError(ERROR_BAD_EXE_FORMAT
);
3669 /* Otherwise, return a more modern error */
3670 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3673 /* Go to the failure path */
3674 DPRINT1("Invalid image architecture: %lx\n", ImageInformation
.Machine
);
3679 /* Check if this isn't a Windows image */
3680 if ((ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_GUI
) &&
3681 (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_CUI
))
3683 /* Get rid of section-related information since we'll retry */
3684 NtClose(SectionHandle
);
3685 SectionHandle
= NULL
;
3686 QuerySection
= FALSE
;
3688 /* The only other non-Windows image type we support here is POSIX */
3689 if (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_POSIX_CUI
)
3691 /* Bail out if it's something else */
3692 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
3697 /* Now build the command-line to have posix launch this image */
3698 Result
= BuildSubSysCommandLine(L
"POSIX /P ",
3704 /* Bail out if that failed */
3705 DPRINT1("Subsystem command line failed\n");
3709 /* And re-try launching the process, with the new command-line now */
3710 lpCommandLine
= DebuggerString
.Buffer
;
3711 lpApplicationName
= NULL
;
3713 /* We've already done all these checks, don't do them again */
3714 SkipSaferAndAppCompat
= TRUE
;
3715 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3719 /* Was this image built for a version of Windows whose images we can run? */
3720 Result
= BasepIsImageVersionOk(ImageInformation
.SubSystemMajorVersion
,
3721 ImageInformation
.SubSystemMinorVersion
);
3724 /* It was not, bail out */
3725 DPRINT1("Invalid subsystem version: %hu.%hu\n",
3726 ImageInformation
.SubSystemMajorVersion
,
3727 ImageInformation
.SubSystemMinorVersion
);
3728 SetLastError(ERROR_BAD_EXE_FORMAT
);
3732 /* Check if there is a debugger associated with the application */
3733 if (DebuggerCmdLine
)
3735 /* Get the length of the command line */
3736 n
= wcslen(lpCommandLine
);
3739 /* There's no command line, use the application name instead */
3740 lpCommandLine
= (LPWSTR
)lpApplicationName
;
3741 n
= wcslen(lpCommandLine
);
3744 /* Protect against overflow */
3745 if (n
> UNICODE_STRING_MAX_CHARS
)
3747 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3752 /* Now add the length of the debugger command-line */
3753 n
+= wcslen(DebuggerCmdLine
);
3755 /* Again make sure we don't overflow */
3756 if (n
> UNICODE_STRING_MAX_CHARS
)
3758 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3763 /* Account for the quotes and space between the two */
3764 n
+= sizeof("\" \"") - sizeof(ANSI_NULL
);
3766 /* Convert to bytes, and make sure we don't overflow */
3768 if (n
> UNICODE_STRING_MAX_BYTES
)
3770 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3775 /* Allocate space for the string */
3776 DebuggerString
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, n
);
3777 if (!DebuggerString
.Buffer
)
3779 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3784 /* Set the length */
3785 RtlInitEmptyUnicodeString(&DebuggerString
,
3786 DebuggerString
.Buffer
,
3789 /* Now perform the command line creation */
3790 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
,
3792 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3793 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, L
" ");
3794 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3795 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, lpCommandLine
);
3796 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3798 /* Make sure it all looks nice */
3799 DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString
);
3801 /* Update the command line and application name */
3802 lpCommandLine
= DebuggerString
.Buffer
;
3803 lpApplicationName
= NULL
;
3805 /* Close all temporary state */
3806 NtClose(SectionHandle
);
3807 SectionHandle
= NULL
;
3808 QuerySection
= FALSE
;
3810 /* Free all temporary memory */
3811 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3813 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
3815 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3816 DebuggerCmdLine
= NULL
;
3817 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3821 /* Initialize the process object attributes */
3822 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3823 lpProcessAttributes
,
3825 if ((hUserToken
) && (lpProcessAttributes
))
3827 /* Auggment them with information from the user */
3829 LocalProcessAttributes
= *lpProcessAttributes
;
3830 LocalProcessAttributes
.lpSecurityDescriptor
= NULL
;
3831 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3832 &LocalProcessAttributes
,
3836 /* Check if we're going to be debugged */
3837 if (dwCreationFlags
& DEBUG_PROCESS
)
3839 /* Set process flag */
3840 Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
3843 /* Check if we're going to be debugged */
3844 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3846 /* Connect to DbgUi */
3847 Status
= DbgUiConnectToDbg();
3848 if (!NT_SUCCESS(Status
))
3850 DPRINT1("Failed to connect to DbgUI!\n");
3851 BaseSetLastNTError(Status
);
3856 /* Get the debug object */
3857 DebugHandle
= DbgUiGetThreadDebugObject();
3859 /* Check if only this process will be debugged */
3860 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3862 /* Set process flag */
3863 Flags
|= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
;
3867 /* Set inherit flag */
3868 if (bInheritHandles
) Flags
|= PROCESS_CREATE_FLAGS_INHERIT_HANDLES
;
3870 /* Check if the process should be created with large pages */
3871 HavePrivilege
= FALSE
;
3872 PrivilegeState
= NULL
;
3873 if (Flags
& PROCESS_CREATE_FLAGS_LARGE_PAGES
)
3875 /* Acquire the required privilege so that the kernel won't fail the call */
3876 PrivilegeValue
= SE_LOCK_MEMORY_PRIVILEGE
;
3877 Status
= RtlAcquirePrivilege(&PrivilegeValue
, TRUE
, FALSE
, &PrivilegeState
);
3878 if (NT_SUCCESS(Status
))
3880 /* Remember to release it later */
3881 HavePrivilege
= TRUE
;
3885 /* Save the current TIB value since kernel overwrites it to store PEB */
3886 TibValue
= Teb
->NtTib
.ArbitraryUserPointer
;
3888 /* Tell the kernel to create the process */
3889 Status
= NtCreateProcessEx(&ProcessHandle
,
3899 /* Load the PEB address from the hacky location where the kernel stores it */
3900 RemotePeb
= Teb
->NtTib
.ArbitraryUserPointer
;
3902 /* And restore the old TIB value */
3903 Teb
->NtTib
.ArbitraryUserPointer
= TibValue
;
3905 /* Release the large page privilege if we had acquired it */
3906 if (HavePrivilege
) RtlReleasePrivilege(PrivilegeState
);
3908 /* And now check if the kernel failed to create the process */
3909 if (!NT_SUCCESS(Status
))
3911 /* Go to failure path */
3912 DPRINT1("Failed to create process: %lx\n", Status
);
3913 BaseSetLastNTError(Status
);
3918 /* Check if there is a priority class to set */
3919 if (PriorityClass
.PriorityClass
)
3921 /* Reset current privilege state */
3922 RealTimePrivilegeState
= NULL
;
3924 /* Is realtime priority being requested? */
3925 if (PriorityClass
.PriorityClass
== PROCESS_PRIORITY_CLASS_REALTIME
)
3927 /* Check if the caller has real-time access, and enable it if so */
3928 RealTimePrivilegeState
= BasepIsRealtimeAllowed(TRUE
);
3931 /* Set the new priority class and release the privilege */
3932 Status
= NtSetInformationProcess(ProcessHandle
,
3933 ProcessPriorityClass
,
3935 sizeof(PROCESS_PRIORITY_CLASS
));
3936 if (RealTimePrivilegeState
) RtlReleasePrivilege(RealTimePrivilegeState
);
3938 /* Check if we failed to set the priority class */
3939 if (!NT_SUCCESS(Status
))
3941 /* Bail out on failure */
3942 DPRINT1("Failed to set priority class: %lx\n", Status
);
3943 BaseSetLastNTError(Status
);
3949 /* Check if the caller wants the default error mode */
3950 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3952 /* Set Error Mode to only fail on critical errors */
3953 HardErrorMode
= SEM_FAILCRITICALERRORS
;
3954 NtSetInformationProcess(ProcessHandle
,
3955 ProcessDefaultHardErrorMode
,
3960 /* Check if this was a VDM binary */
3963 /* Update VDM by telling it the process has now been created */
3964 VdmWaitObject
= ProcessHandle
;
3965 Result
= BaseUpdateVDMEntry(VdmEntryUpdateProcess
,
3972 /* Bail out on failure */
3973 DPRINT1("Failed to update VDM with wait object\n");
3974 VdmWaitObject
= NULL
;
3978 /* At this point, a failure means VDM has to undo all the state */
3979 VdmUndoLevel
|= VDM_UNDO_FULL
;
3982 /* Check if VDM needed reserved low-memory */
3985 /* Reserve the requested allocation */
3986 Status
= NtAllocateVirtualMemory(ProcessHandle
,
3991 PAGE_EXECUTE_READWRITE
);
3992 if (!NT_SUCCESS(Status
))
3994 /* Bail out on failure */
3995 DPRINT1("Failed to reserved memory for VDM: %lx\n", Status
);
3996 BaseSetLastNTError(Status
);
4002 /* Check if we've already queried information on the section */
4005 /* We haven't, so get some information about the executable */
4006 Status
= NtQuerySection(SectionHandle
,
4007 SectionImageInformation
,
4009 sizeof(ImageInformation
),
4011 if (!NT_SUCCESS(Status
))
4013 /* Bail out on failure */
4014 DPRINT1("Failed to query section: %lx\n", Status
);
4015 BaseSetLastNTError(Status
);
4020 /* If we encounter a restart, don't re-query this information again */
4021 QuerySection
= TRUE
;
4024 /* Do we need to apply SxS to this image? */
4025 if (!(ImageInformation
.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
))
4027 /* Too bad, we don't support this yet */
4028 DPRINT1("Image should receive SxS Fusion Isolation\n");
4031 /* There's some SxS flag that we need to set if fusion flags have 1 set */
4032 if (FusionFlags
& 1) CreateProcessMsg
->Sxs
.Flags
|= 0x10;
4034 /* Check if we have a current directory */
4035 if (lpCurrentDirectory
)
4037 /* Allocate a buffer so we can keep a Unicode copy */
4038 DPRINT1("Current directory: %S\n", lpCurrentDirectory
);
4039 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
4041 (MAX_PATH
* sizeof(WCHAR
)) +
4042 sizeof(UNICODE_NULL
));
4043 if (!CurrentDirectory
)
4045 /* Bail out if this failed */
4046 BaseSetLastNTError(STATUS_NO_MEMORY
);
4051 /* Get the length in Unicode */
4052 Length
= GetFullPathNameW(lpCurrentDirectory
,
4056 if (Length
> MAX_PATH
)
4058 /* The directory is too long, so bail out */
4059 SetLastError(ERROR_DIRECTORY
);
4064 /* Make sure the directory is actually valid */
4065 CurdirLength
= GetFileAttributesW(CurrentDirectory
);
4066 if ((CurdirLength
== 0xffffffff) ||
4067 !(CurdirLength
& FILE_ATTRIBUTE_DIRECTORY
))
4069 /* It isn't, so bail out */
4070 DPRINT1("Current directory is invalid\n");
4071 SetLastError(ERROR_DIRECTORY
);
4077 /* Insert quotes if needed */
4078 if ((QuotesNeeded
) || (CmdLineIsAppName
))
4080 /* Allocate our buffer, plus enough space for quotes and a NULL */
4081 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
4083 (wcslen(lpCommandLine
) * sizeof(WCHAR
)) +
4084 (2 * sizeof(L
'\"') + sizeof(UNICODE_NULL
)));
4087 /* Copy the first quote */
4088 wcscpy(QuotedCmdLine
, L
"\"");
4090 /* Save the current null-character */
4093 SaveChar
= *NullBuffer
;
4094 *NullBuffer
= UNICODE_NULL
;
4097 /* Copy the command line and the final quote */
4098 wcscat(QuotedCmdLine
, lpCommandLine
);
4099 wcscat(QuotedCmdLine
, L
"\"");
4101 /* Copy the null-char back */
4104 *NullBuffer
= SaveChar
;
4105 wcscat(QuotedCmdLine
, NullBuffer
);
4110 /* We can't put quotes around the thing, so try it anyway */
4111 if (QuotesNeeded
) QuotesNeeded
= FALSE
;
4112 if (CmdLineIsAppName
) CmdLineIsAppName
= FALSE
;
4116 /* Use isolation if needed */
4117 if (CreateProcessMsg
->Sxs
.Flags
& 1) ParameterFlags
|= 1;
4119 /* Set the new command-line if needed */
4120 if ((QuotesNeeded
) || (CmdLineIsAppName
)) lpCommandLine
= QuotedCmdLine
;
4122 /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
4123 Result
= BasePushProcessParameters(ParameterFlags
,
4131 dwCreationFlags
| NoWindow
,
4133 IsWowApp
? IMAGE_SUBSYSTEM_WINDOWS_GUI
: 0,
4138 /* The remote process would have an undefined state, so fail the call */
4139 DPRINT1("BasePushProcessParameters failed\n");
4143 /* Free the VDM command line string as it's no longer needed */
4144 RtlFreeUnicodeString(&VdmString
);
4145 VdmString
.Buffer
= NULL
;
4147 /* Non-VDM console applications usually inherit handles unless specified */
4148 if (!(VdmBinaryType
) &&
4149 !(bInheritHandles
) &&
4150 !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
4151 !(dwCreationFlags
& (CREATE_NO_WINDOW
|
4152 CREATE_NEW_CONSOLE
|
4153 DETACHED_PROCESS
)) &&
4154 (ImageInformation
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
))
4156 /* Get the remote parameters */
4157 Status
= NtReadVirtualMemory(ProcessHandle
,
4158 &RemotePeb
->ProcessParameters
,
4160 sizeof(PRTL_USER_PROCESS_PARAMETERS
),
4162 if (NT_SUCCESS(Status
))
4164 /* Duplicate standard input unless it's a console handle */
4165 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
))
4167 StuffStdHandle(ProcessHandle
,
4168 Peb
->ProcessParameters
->StandardInput
,
4169 &ProcessParameters
->StandardInput
);
4172 /* Duplicate standard output unless it's a console handle */
4173 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
))
4175 StuffStdHandle(ProcessHandle
,
4176 Peb
->ProcessParameters
->StandardOutput
,
4177 &ProcessParameters
->StandardOutput
);
4180 /* Duplicate standard error unless it's a console handle */
4181 if (!IsConsoleHandle(Peb
->ProcessParameters
->StandardError
))
4183 StuffStdHandle(ProcessHandle
,
4184 Peb
->ProcessParameters
->StandardError
,
4185 &ProcessParameters
->StandardError
);
4190 /* Create the Thread's Stack */
4191 StackSize
= max(256 * 1024, ImageInformation
.MaximumStackSize
);
4192 Status
= BaseCreateStack(ProcessHandle
,
4193 ImageInformation
.CommittedStackSize
,
4196 if (!NT_SUCCESS(Status
))
4198 DPRINT1("Creating the thread stack failed: %lx\n", Status
);
4199 BaseSetLastNTError(Status
);
4204 /* Create the Thread's Context */
4205 BaseInitializeContext(&Context
,
4207 ImageInformation
.TransferAddress
,
4208 InitialTeb
.StackBase
,
4211 /* Convert the thread attributes */
4212 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4215 if ((hUserToken
) && (lpThreadAttributes
))
4217 /* If the caller specified a user token, zero the security descriptor */
4218 LocalThreadAttributes
= *lpThreadAttributes
;
4219 LocalThreadAttributes
.lpSecurityDescriptor
= NULL
;
4220 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
4221 &LocalThreadAttributes
,
4225 /* Create the Kernel Thread Object */
4226 Status
= NtCreateThread(&ThreadHandle
,
4234 if (!NT_SUCCESS(Status
))
4236 /* A process is not allowed to exist without a main thread, so fail */
4237 DPRINT1("Creating the main thread failed: %lx\n", Status
);
4238 BaseSetLastNTError(Status
);
4243 /* Begin filling out the CSRSS message, first with our IDs and handles */
4244 CreateProcessMsg
->ProcessHandle
= ProcessHandle
;
4245 CreateProcessMsg
->ThreadHandle
= ThreadHandle
;
4246 CreateProcessMsg
->ClientId
= ClientId
;
4248 /* Write the remote PEB address and clear it locally, we no longer use it */
4249 CreateProcessMsg
->PebAddressNative
= RemotePeb
;
4250 CreateProcessMsg
->PebAddressWow64
= (ULONG
)RemotePeb
;
4253 /* Now check what kind of architecture this image was made for */
4254 switch (ImageInformation
.Machine
)
4256 /* IA32, IA64 and AMD64 are supported in Server 2003 */
4257 case IMAGE_FILE_MACHINE_I386
:
4258 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_INTEL
;
4260 case IMAGE_FILE_MACHINE_IA64
:
4261 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_IA64
;
4263 case IMAGE_FILE_MACHINE_AMD64
:
4264 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_AMD64
;
4267 /* Anything else results in image unknown -- but no failure */
4269 DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
4270 ImageInformation
.Machine
);
4271 CreateProcessMsg
->ProcessorArchitecture
= PROCESSOR_ARCHITECTURE_UNKNOWN
;
4275 /* Write the input creation flags except any debugger-related flags */
4276 CreateProcessMsg
->CreationFlags
= dwCreationFlags
&
4277 ~(DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
);
4279 /* CSRSS needs to know if this is a GUI app or not */
4280 if ((ImageInformation
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_GUI
) ||
4284 * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
4285 * (basesrv in particular) to know whether or not this is a GUI or a
4288 AddToHandle(CreateProcessMsg
->ProcessHandle
, 2);
4290 /* Also check if the parent is also a GUI process */
4291 NtHeaders
= RtlImageNtHeader(GetModuleHandle(NULL
));
4293 (NtHeaders
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
))
4295 /* Let it know that it should display the hourglass mouse cursor */
4296 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4300 /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
4301 if (StartupInfo
.dwFlags
& STARTF_FORCEONFEEDBACK
)
4303 AddToHandle(CreateProcessMsg
->ProcessHandle
, 1);
4306 /* Likewise, the opposite holds as well */
4307 if (StartupInfo
.dwFlags
& STARTF_FORCEOFFFEEDBACK
)
4309 RemoveFromHandle(CreateProcessMsg
->ProcessHandle
, 1);
4312 /* Also store which kind of VDM app (if any) this is */
4313 CreateProcessMsg
->VdmBinaryType
= VdmBinaryType
;
4315 /* And if it really is a VDM app... */
4318 /* Store the task ID and VDM console handle */
4319 CreateProcessMsg
->hVDM
= VdmTask
? 0 : Peb
->ProcessParameters
->ConsoleHandle
;
4320 CreateProcessMsg
->VdmTask
= VdmTask
;
4322 else if (VdmReserve
)
4324 /* Extended VDM, set a flag */
4325 CreateProcessMsg
->VdmBinaryType
|= BINARY_TYPE_WOW_EX
;
4328 /* Check if there's side-by-side assembly data associated with the process */
4329 if (CreateProcessMsg
->Sxs
.Flags
)
4331 /* This should not happen in ReactOS yet */
4332 DPRINT1("This is an SxS Message -- should not happen yet\n");
4333 BaseSetLastNTError(STATUS_NOT_IMPLEMENTED
);
4334 NtTerminateProcess(ProcessHandle
, STATUS_NOT_IMPLEMENTED
);
4339 /* We are finally ready to call CSRSS to tell it about our new process! */
4340 CsrClientCallServer((PCSR_API_MESSAGE
)&CsrMsg
,
4342 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
,
4343 BasepCreateProcess
),
4344 sizeof(*CreateProcessMsg
));
4346 /* CSRSS has returned, free the capture buffer now if we had one */
4349 CsrFreeCaptureBuffer(CaptureBuffer
);
4350 CaptureBuffer
= NULL
;
4353 /* Check if CSRSS failed to accept ownership of the new Windows process */
4354 if (!NT_SUCCESS(CsrMsg
.Status
))
4356 /* Terminate the process and enter failure path with the CSRSS status */
4357 DPRINT1("Failed to tell csrss about new process\n");
4358 BaseSetLastNTError(CsrMsg
.Status
);
4359 NtTerminateProcess(ProcessHandle
, CsrMsg
.Status
);
4364 /* Check if we have a token due to Authz/Safer, not passed by the user */
4365 if ((TokenHandle
) && !(hUserToken
))
4367 /* Replace the process and/or thread token with the one from Safer */
4368 Status
= BasepReplaceProcessThreadTokens(TokenHandle
,
4371 if (!NT_SUCCESS(Status
))
4373 /* If this failed, kill the process and enter the failure path */
4374 DPRINT1("Failed to update process token: %lx\n", Status
);
4375 NtTerminateProcess(ProcessHandle
, Status
);
4376 BaseSetLastNTError(Status
);
4382 /* Check if a job was associated with this process */
4385 /* Bind the process and job together now */
4386 Status
= NtAssignProcessToJobObject(JobHandle
, ProcessHandle
);
4387 if (!NT_SUCCESS(Status
))
4389 /* Kill the process and enter the failure path if binding failed */
4390 DPRINT1("Failed to assign process to job: %lx\n", Status
);
4391 NtTerminateProcess(ProcessHandle
, STATUS_ACCESS_DENIED
);
4392 BaseSetLastNTError(Status
);
4398 /* Finally, resume the thread to actually get the process started */
4399 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
4401 NtResumeThread(ThreadHandle
, &ResumeCount
);
4405 /* We made it this far, meaning we have a fully created process and thread */
4408 /* Anyone doing a VDM undo should now undo everything, since we are done */
4409 if (VdmUndoLevel
) VdmUndoLevel
|= VDM_UNDO_COMPLETED
;
4411 /* Having a VDM wait object implies this must be a VDM process */
4414 /* Check if it's a 16-bit separate WOW process */
4415 if (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
)
4417 /* OR-in the special flag to indicate this, and return to caller */
4418 AddToHandle(VdmWaitObject
, 2);
4419 lpProcessInformation
->hProcess
= VdmWaitObject
;
4421 /* Check if this was a re-used VDM */
4422 if (VdmUndoLevel
& VDM_UNDO_REUSE
)
4424 /* No Client ID should be returned in this case */
4425 ClientId
.UniqueProcess
= 0;
4426 ClientId
.UniqueThread
= 0;
4431 /* OR-in the special flag to indicate this is not a separate VDM */
4432 AddToHandle(VdmWaitObject
, 1);
4434 /* Return handle to the caller */
4435 lpProcessInformation
->hProcess
= VdmWaitObject
;
4438 /* Close the original process handle, since it's not needed for VDM */
4439 if (ProcessHandle
) NtClose(ProcessHandle
);
4443 /* This is a regular process, so return the real process handle */
4444 lpProcessInformation
->hProcess
= ProcessHandle
;
4447 /* Return the rest of the process information based on what we have so far */
4448 lpProcessInformation
->hThread
= ThreadHandle
;
4449 lpProcessInformation
->dwProcessId
= HandleToUlong(ClientId
.UniqueProcess
);
4450 lpProcessInformation
->dwThreadId
= HandleToUlong(ClientId
.UniqueThread
);
4452 /* NULL these out here so we know to treat this as a success scenario */
4453 ProcessHandle
= NULL
;
4454 ThreadHandle
= NULL
;
4457 /* Free the debugger command line if one was allocated */
4458 if (DebuggerCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
4460 /* Check if an SxS full path as queried */
4463 /* Reinitialize the executable path */
4464 RtlInitEmptyUnicodeString(&SxsWin32ExePath
, NULL
, 0);
4465 SxsWin32ExePath
.Length
= 0;
4467 /* Free the path buffer */
4468 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
4471 #if _SXS_SUPPORT_ENABLED_
4472 /* Check if this was a non-VDM process */
4475 /* Then it must've had SxS data, so close the handles used for it */
4476 BasepSxsCloseHandles(&Handles
);
4477 BasepSxsCloseHandles(&FileHandles
);
4479 /* Check if we built SxS byte buffers for this create process request */
4480 if (SxsConglomeratedBuffer
)
4482 /* Loop all of them */
4483 for (i
= 0; i
< 5; i
++)
4485 /* Check if this one was allocated */
4486 ThisBuffer
= SxsStaticBuffers
[i
];
4489 /* Get the underlying RTL_BUFFER structure */
4490 ByteBuffer
= &ThisBuffer
->ByteBuffer
;
4491 if ((ThisBuffer
!= (PVOID
)-8) && (ByteBuffer
->Buffer
))
4493 /* Check if it was dynamic */
4494 if (ByteBuffer
->Buffer
!= ByteBuffer
->StaticBuffer
)
4496 /* Free it from the heap */
4497 FreeString
.Buffer
= (PWCHAR
)ByteBuffer
->Buffer
;
4498 RtlFreeUnicodeString(&FreeString
);
4501 /* Reset the buffer to its static data */
4502 ByteBuffer
->Buffer
= ByteBuffer
->StaticBuffer
;
4503 ByteBuffer
->Size
= ByteBuffer
->StaticSize
;
4506 /* Reset the string to the static buffer */
4507 RtlInitEmptyUnicodeString(&ThisBuffer
->String
,
4508 (PWCHAR
)ByteBuffer
->StaticBuffer
,
4509 ByteBuffer
->StaticSize
);
4510 if (ThisBuffer
->String
.Buffer
)
4512 /* Also NULL-terminate it */
4513 *ThisBuffer
->String
.Buffer
= UNICODE_NULL
;
4520 /* Check if an environment was passed in */
4521 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
4524 RtlDestroyEnvironment(lpEnvironment
);
4526 /* If this was the VDM environment too, clear that as well */
4527 if (VdmUnicodeEnv
.Buffer
== lpEnvironment
) VdmUnicodeEnv
.Buffer
= NULL
;
4528 lpEnvironment
= NULL
;
4531 /* Unconditionally free all the name parsing buffers we always allocate */
4532 RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
4533 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
4534 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
4535 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
4537 /* Close open file/section handles */
4538 if (FileHandle
) NtClose(FileHandle
);
4539 if (SectionHandle
) NtClose(SectionHandle
);
4541 /* If we have a thread handle, this was a failure path */
4544 /* So kill the process and close the thread handle */
4545 NtTerminateProcess(ProcessHandle
, 0);
4546 NtClose(ThreadHandle
);
4549 /* If we have a process handle, this was a failure path, so close it */
4550 if (ProcessHandle
) NtClose(ProcessHandle
);
4552 /* Thread/process handles, if any, are now processed. Now close this one. */
4553 if (JobHandle
) NtClose(JobHandle
);
4555 /* Check if we had created a token */
4558 /* And if the user asked for one */
4561 /* Then return it */
4562 *hNewToken
= TokenHandle
;
4566 /* User didn't want it, so we used it temporarily -- close it */
4567 NtClose(TokenHandle
);
4571 /* Free any temporary app compatibility data, it's no longer needed */
4572 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
4574 /* Free a few strings. The API takes care of these possibly being NULL */
4575 RtlFreeUnicodeString(&VdmString
);
4576 RtlFreeUnicodeString(&DebuggerString
);
4578 /* Check if we had built any sort of VDM environment */
4579 if ((VdmAnsiEnv
.Buffer
) || (VdmUnicodeEnv
.Buffer
))
4582 BaseDestroyVDMEnvironment(&VdmAnsiEnv
, &VdmUnicodeEnv
);
4585 /* Check if this was any kind of VDM application that we ended up creating */
4586 if ((VdmUndoLevel
) && (!(VdmUndoLevel
& VDM_UNDO_COMPLETED
)))
4589 BaseUpdateVDMEntry(VdmEntryUndo
,
4594 /* And close whatever VDM handle we were using for notifications */
4595 if (VdmWaitObject
) NtClose(VdmWaitObject
);
4598 /* Check if we ended up here with an allocated search path, and free it */
4599 if (SearchPath
) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
4601 /* Finally, return the API's result */
4610 CreateProcessW(LPCWSTR lpApplicationName
,
4611 LPWSTR lpCommandLine
,
4612 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4613 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4614 BOOL bInheritHandles
,
4615 DWORD dwCreationFlags
,
4616 LPVOID lpEnvironment
,
4617 LPCWSTR lpCurrentDirectory
,
4618 LPSTARTUPINFOW lpStartupInfo
,
4619 LPPROCESS_INFORMATION lpProcessInformation
)
4621 /* Call the internal (but exported) version */
4622 return CreateProcessInternalW(NULL
,
4625 lpProcessAttributes
,
4632 lpProcessInformation
,
4641 CreateProcessInternalA(HANDLE hToken
,
4642 LPCSTR lpApplicationName
,
4643 LPSTR lpCommandLine
,
4644 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4645 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4646 BOOL bInheritHandles
,
4647 DWORD dwCreationFlags
,
4648 LPVOID lpEnvironment
,
4649 LPCSTR lpCurrentDirectory
,
4650 LPSTARTUPINFOA lpStartupInfo
,
4651 LPPROCESS_INFORMATION lpProcessInformation
,
4654 PUNICODE_STRING CommandLine
= NULL
;
4655 UNICODE_STRING DummyString
;
4656 UNICODE_STRING LiveCommandLine
;
4657 UNICODE_STRING ApplicationName
;
4658 UNICODE_STRING CurrentDirectory
;
4660 STARTUPINFOW StartupInfo
;
4662 DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, "
4663 "lpStartupInfo %p, lpProcessInformation %p\n",
4664 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
4665 lpStartupInfo
, lpProcessInformation
);
4667 /* Copy Startup Info */
4668 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
4670 /* Initialize all strings to nothing */
4671 LiveCommandLine
.Buffer
= NULL
;
4672 DummyString
.Buffer
= NULL
;
4673 ApplicationName
.Buffer
= NULL
;
4674 CurrentDirectory
.Buffer
= NULL
;
4675 StartupInfo
.lpDesktop
= NULL
;
4676 StartupInfo
.lpReserved
= NULL
;
4677 StartupInfo
.lpTitle
= NULL
;
4679 /* Convert the Command line */
4682 /* If it's too long, then we'll have a problem */
4683 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
4684 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
4686 /* Cache it in the TEB */
4687 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
4691 /* Use a dynamic version */
4692 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
4698 /* The logic below will use CommandLine, so we must make it valid */
4699 CommandLine
= &DummyString
;
4702 /* Convert the Name and Directory */
4703 if (lpApplicationName
)
4705 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
4708 if (lpCurrentDirectory
)
4710 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
4711 lpCurrentDirectory
);
4714 /* Now convert Startup Strings */
4715 if (lpStartupInfo
->lpReserved
)
4717 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
4718 &StartupInfo
.lpReserved
);
4720 if (lpStartupInfo
->lpDesktop
)
4722 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
4723 &StartupInfo
.lpDesktop
);
4725 if (lpStartupInfo
->lpTitle
)
4727 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
4728 &StartupInfo
.lpTitle
);
4731 /* Call the Unicode function */
4732 bRetVal
= CreateProcessInternalW(hToken
,
4733 ApplicationName
.Buffer
,
4734 LiveCommandLine
.Buffer
?
4735 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
4736 lpProcessAttributes
,
4741 CurrentDirectory
.Buffer
,
4743 lpProcessInformation
,
4747 RtlFreeUnicodeString(&ApplicationName
);
4748 RtlFreeUnicodeString(&LiveCommandLine
);
4749 RtlFreeUnicodeString(&CurrentDirectory
);
4750 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
4751 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
4752 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
4754 /* Return what Unicode did */
4759 * FUNCTION: The CreateProcess function creates a new process and its
4760 * primary thread. The new process executes the specified executable file
4763 * lpApplicationName = Pointer to name of executable module
4764 * lpCommandLine = Pointer to command line string
4765 * lpProcessAttributes = Process security attributes
4766 * lpThreadAttributes = Thread security attributes
4767 * bInheritHandles = Handle inheritance flag
4768 * dwCreationFlags = Creation flags
4769 * lpEnvironment = Pointer to new environment block
4770 * lpCurrentDirectory = Pointer to current directory name
4771 * lpStartupInfo = Pointer to startup info
4772 * lpProcessInformation = Pointer to process information
4778 CreateProcessA(LPCSTR lpApplicationName
,
4779 LPSTR lpCommandLine
,
4780 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
4781 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
4782 BOOL bInheritHandles
,
4783 DWORD dwCreationFlags
,
4784 LPVOID lpEnvironment
,
4785 LPCSTR lpCurrentDirectory
,
4786 LPSTARTUPINFOA lpStartupInfo
,
4787 LPPROCESS_INFORMATION lpProcessInformation
)
4789 /* Call the internal (but exported) version */
4790 return CreateProcessInternalA(NULL
,
4793 lpProcessAttributes
,
4800 lpProcessInformation
,
4809 WinExec(LPCSTR lpCmdLine
,
4812 STARTUPINFOA StartupInfo
;
4813 PROCESS_INFORMATION ProcessInformation
;
4816 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
4817 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
4818 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
4819 StartupInfo
.dwFlags
= 0;
4821 if (!CreateProcessA(NULL
,
4830 &ProcessInformation
))
4832 dosErr
= GetLastError();
4833 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
4836 if (NULL
!= UserWaitForInputIdleRoutine
)
4838 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
4842 NtClose(ProcessInformation
.hProcess
);
4843 NtClose(ProcessInformation
.hThread
);
4845 return 33; /* Something bigger than 31 means success. */