1 /* $Id: proc.c 57086 2012-08-16 15:39:40Z akhaldi $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/proc/proc.c
6 * PURPOSE: Process functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
12 /* INCLUDES ****************************************************************/
19 /* GLOBALS *******************************************************************/
21 WaitForInputIdleType UserWaitForInputIdleRoutine
;
22 UNICODE_STRING BaseUnicodeCommandLine
;
23 ANSI_STRING BaseAnsiCommandLine
;
24 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
25 LPSTARTUPINFOA BaseAnsiStartupInfo
= NULL
;
26 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
27 BOOLEAN g_AppCertInitialized
;
28 BOOLEAN g_HaveAppCerts
;
29 LIST_ENTRY BasepAppCertDllsList
;
30 RTL_CRITICAL_SECTION gcsAppCert
;
31 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
32 NTSTATUS g_AppCertStatus
;
33 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
36 BasepConfigureAppCertDlls
,
39 &BasepAppCertDllsList
,
46 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
47 HMODULE gSaferHandle
= (HMODULE
)-1;
50 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
52 #define CMD_STRING L"cmd /c "
54 /* FUNCTIONS ****************************************************************/
58 StuffStdHandle(IN HANDLE ProcessHandle
,
59 IN HANDLE StandardHandle
,
63 HANDLE DuplicatedHandle
;
66 /* Duplicate the handle */
67 Status
= NtDuplicateObject(NtCurrentProcess(),
71 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
74 if (NT_SUCCESS(Status
))
77 NtWriteVirtualMemory(ProcessHandle
,
87 BuildSubSysCommandLine(IN LPWSTR SubsystemName
,
88 IN LPWSTR ApplicationName
,
89 IN LPWSTR CommandLine
,
90 OUT PUNICODE_STRING SubsysCommandLine
)
92 UNICODE_STRING CommandLineString
, ApplicationNameString
;
96 /* Convert to unicode strings */
97 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
98 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
100 /* Allocate buffer for the output string */
101 Length
= CommandLineString
.MaximumLength
+ ApplicationNameString
.MaximumLength
+ 32;
102 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
103 RtlInitEmptyUnicodeString(SubsysCommandLine
, Buffer
, Length
);
106 /* Fail, no memory */
107 BaseSetLastNTError(STATUS_NO_MEMORY
);
111 /* Build the final subsystem command line */
112 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
113 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
114 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
115 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
121 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
122 IN ULONG ImageMinorVersion
)
124 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
125 return ((ImageMajorVersion
>= 3) &&
126 ((ImageMajorVersion
!= 3) ||
127 (ImageMinorVersion
>= 10)) &&
128 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
129 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
130 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
135 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
140 /* Get all the MD5 hashes */
141 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
142 if (!NT_SUCCESS(Status
)) return Status
;
144 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
145 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
147 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
149 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
151 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
153 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
155 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
158 /* Actually, fuck it, don't block anything, we're open source */
159 return STATUS_SUCCESS
;
164 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
165 IN PWCHAR ComponentName
,
168 /* Pretty much the only thing this key is used for, is malware */
170 return STATUS_NOT_IMPLEMENTED
;
175 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
178 IN ULONG ValueLength
,
180 IN PVOID EntryContext
)
182 /* Add this to the certification list */
183 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
188 BasepIsProcessAllowed(IN PCHAR ApplicationName
)
193 HMODULE TrustLibrary
;
194 PBASEP_APPCERT_ENTRY Entry
;
196 PLIST_ENTRY NextEntry
;
198 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
199 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
201 /* Try to initialize the certification subsystem */
202 while (!g_AppCertInitialized
)
205 Status
= STATUS_SUCCESS
;
208 /* Acquire the lock while initializing and see if we lost a race */
209 RtlEnterCriticalSection(&gcsAppCert
);
210 if (g_AppCertInitialized
) break;
212 /* On embedded, there is a special DLL */
213 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
215 /* Allocate a buffer for the name */
216 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
218 MAX_PATH
* sizeof(WCHAR
) +
219 sizeof(UNICODE_NULL
));
222 /* Fail if no memory */
223 Status
= STATUS_NO_MEMORY
;
227 /* Now get the system32 directory in our buffer, make sure it fits */
228 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
229 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
231 /* Add a slash if needed, and add the embedded cert DLL name */
232 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
233 RtlCopyMemory(&Buffer
[Length
],
235 sizeof(L
"EmbdTrst.DLL"));
238 TrustLibrary
= LoadLibraryW(Buffer
);
241 /* And extract the special function out of it */
242 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
243 "ImageOkToRunOnEmbeddedNT");
247 /* If we didn't get this far, set a failure code */
248 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
253 /* Other systems have a registry entry for this */
254 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
255 if (NT_SUCCESS(Status
))
257 /* Close it, we'll query it through Rtl */
260 /* Do the query, which will call a special callback */
261 Status
= RtlQueryRegistryValues(2,
266 if (Status
== 0xC0000034) Status
= STATUS_SUCCESS
;
270 /* Free any buffer if we had one */
271 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
273 /* Check for errors, or a missing embedded/custom certification DLL */
274 if (!NT_SUCCESS(Status
) ||
275 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
277 /* The subsystem is not active on this machine, so give up */
278 g_HaveAppCerts
= FALSE
;
279 g_AppCertStatus
= Status
;
283 /* We have certification DLLs active, remember this */
284 g_HaveAppCerts
= TRUE
;
287 /* We are done the initialization phase, release the lock */
288 g_AppCertInitialized
= TRUE
;
289 RtlLeaveCriticalSection(&gcsAppCert
);
292 /* If there's no certification DLLs present, return the failure code */
293 if (!g_HaveAppCerts
) return g_AppCertStatus
;
295 /* Otherwise, assume success and make sure we have *something* */
296 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
297 Status
= STATUS_SUCCESS
;
299 /* If the something is an embedded certification DLL, call it and return */
300 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
302 /* Otherwise we have custom certification DLLs, parse them */
303 NextEntry
= BasepAppCertDllsList
.Flink
;
305 while (NextEntry
!= &BasepAppCertDllsList
)
307 /* Make sure the entry has a callback */
308 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
309 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
311 /* Call it and check if it failed */
312 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
313 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
316 NextEntry
= NextEntry
->Flink
;
319 /* Now loop them again */
320 NextEntry
= BasepAppCertDllsList
.Flink
;
321 while (NextEntry
!= &BasepAppCertDllsList
)
323 /* Make sure the entry has a callback */
324 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
325 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
327 /* Call it, this time with the flag from the loop above */
328 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
331 /* All done, return the status */
337 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
338 IN HANDLE ProcessHandle
,
339 IN HANDLE ThreadHandle
)
342 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
344 /* Enter the application certification lock */
345 RtlEnterCriticalSection(&gcsAppCert
);
347 /* Check if we already know the function */
348 if (g_SaferReplaceProcessThreadTokens
)
351 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
359 /* Check if the app certification DLL isn't loaded */
360 if (!(gSaferHandle
) ||
361 (gSaferHandle
== (HMODULE
)-1) ||
362 (gSaferHandle
== (HMODULE
)-2))
364 /* Then we can't call the function */
365 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
369 /* We have the DLL, find the address of the Safer function */
370 Status
= LdrGetProcedureAddress(gSaferHandle
,
371 &SaferiReplaceProcessThreadTokens
,
373 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
374 if (NT_SUCCESS(Status
))
376 /* Found it, now call it */
377 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
385 /* We couldn't find it, so this must be an unsupported DLL */
386 LdrUnloadDll(gSaferHandle
);
388 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
393 /* Release the lock and return the result */
394 RtlLeaveCriticalSection(&gcsAppCert
);
400 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
405 ASSERT(Handles
!= NULL
);
406 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
408 /* Close the file handle */
411 Status
= NtClose(Handles
->File
);
412 ASSERT(NT_SUCCESS(Status
));
415 /* Close the section handle */
416 if (Handles
->Section
)
418 Status
= NtClose(Handles
->Section
);
419 ASSERT(NT_SUCCESS(Status
));
422 /* Unmap the section view */
423 if (Handles
->ViewBase
.QuadPart
)
425 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
426 (PVOID
)Handles
->ViewBase
.LowPart
);
427 ASSERT(NT_SUCCESS(Status
));
432 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
434 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
435 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
436 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
438 if (RealFilter
!= NULL
)
442 ExceptionDisposition
= RealFilter(ExceptionInfo
);
444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
449 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
450 RealFilter
!= UnhandledExceptionFilter
)
452 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
455 return ExceptionDisposition
;
460 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
462 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
466 /* Set our Start Address */
467 NtSetInformationThread(NtCurrentThread(),
468 ThreadQuerySetWin32StartAddress
,
470 sizeof(PPROCESS_START_ROUTINE
));
472 /* Call the Start Routine */
473 ExitThread(lpStartAddress());
475 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
477 /* Get the Exit code from the SEH Handler */
478 if (!BaseRunningInServerProcess
)
480 /* Kill the whole process, usually */
481 ExitProcess(_SEH2_GetExceptionCode());
485 /* If running inside CSRSS, kill just this thread */
486 ExitThread(_SEH2_GetExceptionCode());
494 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
495 IN PCLIENT_ID ClientId
)
497 CSR_API_MESSAGE CsrRequest
;
500 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
501 ClientId
->UniqueThread
, ThreadHandle
);
503 /* Fill out the request */
504 CsrRequest
.Data
.CreateThreadRequest
.ClientId
= *ClientId
;
505 CsrRequest
.Data
.CreateThreadRequest
.ThreadHandle
= ThreadHandle
;
508 Status
= CsrClientCallServer(&CsrRequest
,
510 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
511 sizeof(CSR_API_MESSAGE
));
512 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
514 DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status
, CsrRequest
.Status
);
515 return CsrRequest
.Status
;
519 return STATUS_SUCCESS
;
523 * Creates the first Thread in a Proces
527 BasepCreateFirstThread(HANDLE ProcessHandle
,
528 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
529 PSECTION_IMAGE_INFORMATION SectionImageInfo
,
531 BOOLEAN InheritHandles
,
532 DWORD dwCreationFlags
)
534 OBJECT_ATTRIBUTES LocalObjectAttributes
;
535 POBJECT_ATTRIBUTES ObjectAttributes
;
537 INITIAL_TEB InitialTeb
;
540 CSR_API_MESSAGE CsrRequest
;
541 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
543 /* Create the Thread's Stack */
544 BaseCreateStack(ProcessHandle
,
545 SectionImageInfo
->MaximumStackSize
,
546 SectionImageInfo
->CommittedStackSize
,
549 /* Create the Thread's Context */
550 BaseInitializeContext(&Context
,
552 SectionImageInfo
->TransferAddress
,
553 InitialTeb
.StackBase
,
556 /* Convert the thread attributes */
557 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
561 /* Create the Kernel Thread Object */
562 Status
= NtCreateThread(&hThread
,
570 if (!NT_SUCCESS(Status
))
575 /* Fill out the request to notify CSRSS */
576 CsrRequest
.Data
.CreateProcessRequest
.ClientId
= *ClientId
;
577 CsrRequest
.Data
.CreateProcessRequest
.ProcessHandle
= ProcessHandle
;
578 CsrRequest
.Data
.CreateProcessRequest
.ThreadHandle
= hThread
;
579 CsrRequest
.Data
.CreateProcessRequest
.CreationFlags
= dwCreationFlags
;
580 CsrRequest
.Data
.CreateProcessRequest
.bInheritHandles
= InheritHandles
;
583 Status
= CsrClientCallServer(&CsrRequest
,
585 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateProcess
),
586 sizeof(CSR_API_MESSAGE
));
587 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
589 DPRINT1("Failed to tell csrss about new process: %lx %lx\n", Status
, CsrRequest
.Status
);
598 * Converts ANSI to Unicode Environment
602 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
603 IN PVOID lpEnvironment
)
607 UNICODE_STRING UnicodeEnv
;
610 DPRINT("BasepConvertUnicodeEnvironment\n");
612 /* Scan the environment to calculate its Unicode size */
613 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
616 pcScan
+= strlen(pcScan
) + 1;
619 /* Create our ANSI String */
620 if (pcScan
== (PCHAR
)lpEnvironment
)
622 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
627 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
629 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
631 /* Allocate memory for the Unicode Environment */
632 UnicodeEnv
.Buffer
= NULL
;
633 *EnvSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
634 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
635 (PVOID
)&UnicodeEnv
.Buffer
,
641 if (!NT_SUCCESS(Status
))
643 SetLastError(Status
);
648 /* Use the allocated size */
649 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
652 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
653 return UnicodeEnv
.Buffer
;
657 * Converts a Win32 Priority Class to NT
661 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
665 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
667 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
669 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
671 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
673 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
675 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
677 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
679 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
681 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
683 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
685 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
687 /* Check for Privilege First */
688 if (BasepIsRealtimeAllowed(TRUE
))
690 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
694 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
699 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
706 * Duplicates a standard handle and writes it where requested.
710 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
711 IN HANDLE StandardHandle
,
715 HANDLE DuplicatedHandle
;
718 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
719 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
721 /* Don't touch Console Handles */
722 if (IsConsoleHandle(StandardHandle
)) return;
724 /* Duplicate the handle */
725 Status
= NtDuplicateObject(NtCurrentProcess(),
729 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
732 if (NT_SUCCESS(Status
))
735 NtWriteVirtualMemory(ProcessHandle
,
745 BasePushProcessParameters(IN ULONG ParameterFlags
,
746 IN HANDLE ProcessHandle
,
748 IN LPCWSTR ApplicationPathName
,
749 IN LPWSTR lpCurrentDirectory
,
750 IN LPWSTR lpCommandLine
,
751 IN LPVOID lpEnvironment
,
752 IN LPSTARTUPINFOW StartupInfo
,
753 IN DWORD CreationFlags
,
754 IN BOOL InheritHandles
,
755 IN ULONG ImageSubsystem
,
756 IN PVOID AppCompatData
,
757 IN ULONG AppCompatDataSize
)
759 WCHAR FullPath
[MAX_PATH
+ 5];
760 PWCHAR Remaining
, DllPathString
, ScanChar
;
761 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
762 PVOID RemoteAppCompatData
;
763 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
764 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
768 BOOLEAN HavePebLock
= FALSE
, Result
;
769 PPEB Peb
= NtCurrentPeb();
771 /* Get the full path name */
772 Size
= GetFullPathNameW(ApplicationPathName
,
776 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
778 /* Get the DLL Path */
779 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
783 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
787 /* Initialize Strings */
788 RtlInitUnicodeString(&DllPath
, DllPathString
);
789 RtlInitUnicodeString(&ImageName
, FullPath
);
793 /* Couldn't get the path name. Just take the original path */
794 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
799 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
803 /* Initialize Strings */
804 RtlInitUnicodeString(&DllPath
, DllPathString
);
805 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
808 /* Initialize Strings */
809 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
810 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
812 /* Initialize more Strings from the Startup Info */
813 if (StartupInfo
->lpDesktop
)
815 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
819 RtlInitUnicodeString(&Desktop
, L
"");
821 if (StartupInfo
->lpReserved
)
823 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
827 RtlInitUnicodeString(&Shell
, L
"");
829 if (StartupInfo
->lpTitle
)
831 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
835 RtlInitUnicodeString(&Title
, ApplicationPathName
);
838 /* This one is special because the length can differ */
839 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
840 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
842 /* Enforce no app compat data if the pointer was NULL */
843 if (!AppCompatData
) AppCompatDataSize
= 0;
845 /* Create the Parameter Block */
846 ProcessParameters
= NULL
;
847 Status
= RtlCreateProcessParameters(&ProcessParameters
,
851 &CurrentDirectory
: NULL
,
858 if (!NT_SUCCESS(Status
)) goto FailPath
;
860 /* Clear the current directory handle if not inheriting */
861 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
863 /* Check if the user passed in an environment */
866 /* We should've made it part of the parameters block, enforce this */
867 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
868 lpEnvironment
= ProcessParameters
->Environment
;
872 /* The user did not, so use the one from the current PEB */
875 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
878 /* Save pointer and start lookup */
879 ScanChar
= lpEnvironment
;
882 /* Find the environment size */
883 while ((ScanChar
[0]) || (ScanChar
[1])) ++ScanChar
;
884 ScanChar
+= (2 * sizeof(UNICODE_NULL
));
885 EnviroSize
= (ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
;
887 /* Allocate and Initialize new Environment Block */
889 ProcessParameters
->Environment
= NULL
;
890 Status
= NtAllocateVirtualMemory(ProcessHandle
,
891 (PVOID
*)&ProcessParameters
->Environment
,
896 if (!NT_SUCCESS(Status
)) goto FailPath
;
898 /* Write the Environment Block */
899 Status
= NtWriteVirtualMemory(ProcessHandle
,
900 ProcessParameters
->Environment
,
905 /* No longer need the PEB lock anymore */
913 /* Check if the write failed */
914 if (!NT_SUCCESS(Status
)) goto FailPath
;
917 /* Write new parameters */
918 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
919 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
920 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
921 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
922 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
923 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
924 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
925 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
926 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
928 /* Write the handles only if we have to */
929 if (StartupInfo
->dwFlags
&
930 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
932 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
933 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
934 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
937 /* Use Special Flags for ConDllInitialize in Kernel32 */
938 if (CreationFlags
& DETACHED_PROCESS
)
940 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
942 else if (CreationFlags
& CREATE_NO_WINDOW
)
944 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
946 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
948 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
952 /* Inherit our Console Handle */
953 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
955 /* Make sure that the shell isn't trampling on our handles first */
956 if (!(StartupInfo
->dwFlags
&
957 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
959 /* Copy the handle if we are inheriting or if it's a console handle */
960 if ((InheritHandles
) ||
961 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
963 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
965 if ((InheritHandles
) ||
966 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
968 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
970 if ((InheritHandles
) ||
971 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
973 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
978 /* Also set the Console Flag */
979 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
980 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
982 ProcessParameters
->ConsoleFlags
= 1;
985 /* See if the first 1MB should be reserved */
986 if (ParameterFlags
& 1)
988 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB
;
991 /* See if the first 16MB should be reserved */
992 if (ParameterFlags
& 2)
994 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB
;
997 /* Allocate memory for the parameter block */
998 Size
= ProcessParameters
->Length
;
999 RemoteParameters
= NULL
;
1000 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1001 (PVOID
*)&RemoteParameters
,
1006 if (!NT_SUCCESS(Status
)) goto FailPath
;
1008 /* Set the allocated size */
1009 ProcessParameters
->MaximumLength
= Size
;
1011 /* Handle some Parameter Flags */
1012 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
1013 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
1014 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
1015 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
1016 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
1017 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
1018 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
1019 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
1021 /* Write the Parameter Block */
1022 Status
= NtWriteVirtualMemory(ProcessHandle
,
1025 ProcessParameters
->Length
,
1027 if (!NT_SUCCESS(Status
)) goto FailPath
;
1029 /* Write the PEB Pointer */
1030 Status
= NtWriteVirtualMemory(ProcessHandle
,
1031 &RemotePeb
->ProcessParameters
,
1035 if (!NT_SUCCESS(Status
)) goto FailPath
;
1037 /* Check if there's any app compat data to write */
1038 RemoteAppCompatData
= NULL
;
1041 /* Allocate some space for the application compatibility data */
1042 Size
= AppCompatDataSize
;
1043 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1044 &RemoteAppCompatData
,
1049 if (!NT_SUCCESS(Status
)) goto FailPath
;
1051 /* Write the application compatibility data */
1052 Status
= NtWriteVirtualMemory(ProcessHandle
,
1053 RemoteAppCompatData
,
1057 if (!NT_SUCCESS(Status
)) goto FailPath
;
1060 /* Write the PEB Pointer to the app compat data (might be NULL) */
1061 Status
= NtWriteVirtualMemory(ProcessHandle
,
1062 &RemotePeb
->pShimData
,
1063 &RemoteAppCompatData
,
1066 if (!NT_SUCCESS(Status
)) goto FailPath
;
1068 /* Now write Peb->ImageSubSystem */
1071 NtWriteVirtualMemory(ProcessHandle
,
1072 &RemotePeb
->ImageSubsystem
,
1074 sizeof(ImageSubsystem
),
1083 if (HavePebLock
) RtlReleasePebLock();
1084 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
1085 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
1088 DPRINT1("Failure to create proecss parameters: %lx\n", Status
);
1089 BaseSetLastNTError(Status
);
1096 InitCommandLines(VOID
)
1100 /* Read the UNICODE_STRING from the PEB */
1101 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
1103 /* Convert to ANSI_STRING for the *A callers */
1104 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
1105 &BaseUnicodeCommandLine
,
1107 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
1110 /* PUBLIC FUNCTIONS ***********************************************************/
1117 GetProcessAffinityMask(IN HANDLE hProcess
,
1118 OUT PDWORD_PTR lpProcessAffinityMask
,
1119 OUT PDWORD_PTR lpSystemAffinityMask
)
1121 PROCESS_BASIC_INFORMATION ProcessInfo
;
1124 /* Query information on the process from the kernel */
1125 Status
= NtQueryInformationProcess(hProcess
,
1126 ProcessBasicInformation
,
1127 (PVOID
)&ProcessInfo
,
1128 sizeof(PROCESS_BASIC_INFORMATION
),
1130 if (!NT_SUCCESS(Status
))
1133 BaseSetLastNTError(Status
);
1137 /* Copy the affinity mask, and get the system one from our shared data */
1138 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
1139 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
1148 SetProcessAffinityMask(IN HANDLE hProcess
,
1149 IN DWORD_PTR dwProcessAffinityMask
)
1153 /* Directly set the affinity mask */
1154 Status
= NtSetInformationProcess(hProcess
,
1155 ProcessAffinityMask
,
1156 (PVOID
)&dwProcessAffinityMask
,
1158 if (!NT_SUCCESS(Status
))
1160 /* Handle failure */
1161 BaseSetLastNTError(Status
);
1165 /* Everything was ok */
1174 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
1175 OUT LPDWORD lpdwFlags
)
1177 CSR_API_MESSAGE CsrRequest
;
1180 /* Ask CSRSS for shutdown information */
1181 Status
= CsrClientCallServer(&CsrRequest
,
1183 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
1184 sizeof(CSR_API_MESSAGE
));
1185 if (!(NT_SUCCESS(Status
)) || !(NT_SUCCESS(CsrRequest
.Status
)))
1187 /* Return the failure from CSRSS */
1188 BaseSetLastNTError(CsrRequest
.Status
);
1192 /* Get the data out of the LCP reply */
1193 *lpdwLevel
= CsrRequest
.Data
.GetShutdownParametersRequest
.Level
;
1194 *lpdwFlags
= CsrRequest
.Data
.GetShutdownParametersRequest
.Flags
;
1203 SetProcessShutdownParameters(IN DWORD dwLevel
,
1206 CSR_API_MESSAGE CsrRequest
;
1209 /* Write the data into the CSRSS request and send it */
1210 CsrRequest
.Data
.SetShutdownParametersRequest
.Level
= dwLevel
;
1211 CsrRequest
.Data
.SetShutdownParametersRequest
.Flags
= dwFlags
;
1212 Status
= CsrClientCallServer(&CsrRequest
,
1214 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1215 sizeof(CSR_API_MESSAGE
));
1216 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1218 /* Return the failure from CSRSS */
1219 BaseSetLastNTError(CsrRequest
.Status
);
1232 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1233 OUT PSIZE_T lpMinimumWorkingSetSize
,
1234 OUT PSIZE_T lpMaximumWorkingSetSize
,
1237 QUOTA_LIMITS_EX QuotaLimits
;
1240 /* Query the kernel about this */
1241 Status
= NtQueryInformationProcess(hProcess
,
1244 sizeof(QUOTA_LIMITS_EX
),
1246 if (!NT_SUCCESS(Status
))
1249 BaseSetLastNTError(Status
);
1253 /* Copy the quota information out */
1254 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1255 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1256 *Flags
= QuotaLimits
.Flags
;
1265 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1266 OUT PSIZE_T lpMinimumWorkingSetSize
,
1267 OUT PSIZE_T lpMaximumWorkingSetSize
)
1270 return GetProcessWorkingSetSizeEx(hProcess
,
1271 lpMinimumWorkingSetSize
,
1272 lpMaximumWorkingSetSize
,
1281 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1282 IN SIZE_T dwMinimumWorkingSetSize
,
1283 IN SIZE_T dwMaximumWorkingSetSize
,
1286 QUOTA_LIMITS_EX QuotaLimits
;
1287 NTSTATUS Status
, ReturnStatus
;
1290 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1292 /* Zero out the input structure */
1293 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1295 /* Check if the caller sent any limits */
1296 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1298 /* Write the quota information */
1299 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1300 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1301 QuotaLimits
.Flags
= Flags
;
1303 /* Acquire the required privilege */
1304 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1306 /* Request the new quotas */
1307 ReturnStatus
= NtSetInformationProcess(hProcess
,
1310 sizeof(QuotaLimits
));
1311 Result
= NT_SUCCESS(ReturnStatus
);
1312 if (NT_SUCCESS(Status
))
1314 /* Release the privilege and set succes code */
1315 ASSERT(State
!= NULL
);
1316 RtlReleasePrivilege(State
);
1322 /* No limits, fail the call */
1323 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1327 /* Return result code, set error code if this was a failure */
1328 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1337 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1338 IN SIZE_T dwMinimumWorkingSetSize
,
1339 IN SIZE_T dwMaximumWorkingSetSize
)
1341 /* Call the newer API */
1342 return SetProcessWorkingSetSizeEx(hProcess
,
1343 dwMinimumWorkingSetSize
,
1344 dwMaximumWorkingSetSize
,
1353 GetProcessTimes(IN HANDLE hProcess
,
1354 IN LPFILETIME lpCreationTime
,
1355 IN LPFILETIME lpExitTime
,
1356 IN LPFILETIME lpKernelTime
,
1357 IN LPFILETIME lpUserTime
)
1359 KERNEL_USER_TIMES Kut
;
1362 /* Query the times */
1363 Status
= NtQueryInformationProcess(hProcess
,
1368 if (!NT_SUCCESS(Status
))
1370 /* Handle failure */
1371 BaseSetLastNTError(Status
);
1375 /* Copy all the times and return success */
1376 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1377 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1378 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1379 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1380 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1381 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1382 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1383 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1392 GetCurrentProcess(VOID
)
1394 return (HANDLE
)NtCurrentProcess();
1402 GetCurrentThread(VOID
)
1404 return (HANDLE
)NtCurrentThread();
1412 GetCurrentProcessId(VOID
)
1414 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1422 GetExitCodeProcess(IN HANDLE hProcess
,
1423 IN LPDWORD lpExitCode
)
1425 PROCESS_BASIC_INFORMATION ProcessBasic
;
1428 /* Ask the kernel */
1429 Status
= NtQueryInformationProcess(hProcess
,
1430 ProcessBasicInformation
,
1432 sizeof(PROCESS_BASIC_INFORMATION
),
1434 if (!NT_SUCCESS(Status
))
1436 /* We failed, was this because this is a VDM process? */
1437 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1439 /* Not a VDM process, fail the call */
1440 BaseSetLastNTError(Status
);
1444 /* Succes case, return the exit code */
1445 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1454 GetProcessId(IN HANDLE Process
)
1456 PROCESS_BASIC_INFORMATION ProcessBasic
;
1459 /* Query the kernel */
1460 Status
= NtQueryInformationProcess(Process
,
1461 ProcessBasicInformation
,
1463 sizeof(PROCESS_BASIC_INFORMATION
),
1465 if (!NT_SUCCESS(Status
))
1467 /* Handle failure */
1468 BaseSetLastNTError(Status
);
1472 /* Return the PID */
1473 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1481 OpenProcess(IN DWORD dwDesiredAccess
,
1482 IN BOOL bInheritHandle
,
1483 IN DWORD dwProcessId
)
1486 HANDLE ProcessHandle
;
1487 OBJECT_ATTRIBUTES ObjectAttributes
;
1490 /* Setup the input client ID structure */
1491 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1492 ClientId
.UniqueThread
= 0;
1494 /* This is needed just to define the inheritance flags */
1495 InitializeObjectAttributes(&ObjectAttributes
,
1497 (bInheritHandle
? OBJ_INHERIT
: 0),
1501 /* Now try to open the process */
1502 Status
= NtOpenProcess(&ProcessHandle
,
1506 if (!NT_SUCCESS(Status
))
1508 /* Handle failure */
1509 BaseSetLastNTError(Status
);
1513 /* Otherwise return a handle to the process */
1514 return ProcessHandle
;
1522 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1524 /* Write the global function pointer */
1525 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1533 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1535 PRTL_USER_PROCESS_PARAMETERS Params
;
1537 /* Get the process parameters */
1538 Params
= NtCurrentPeb()->ProcessParameters
;
1540 /* Copy the data out of there */
1541 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1542 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1543 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1544 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1545 lpStartupInfo
->dwX
= Params
->StartingX
;
1546 lpStartupInfo
->dwY
= Params
->StartingY
;
1547 lpStartupInfo
->dwXSize
= Params
->CountX
;
1548 lpStartupInfo
->dwYSize
= Params
->CountY
;
1549 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1550 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1551 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1552 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1553 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1554 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1555 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1557 /* Check if the standard handles are being used for other features */
1558 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1560 STARTF_SHELLPRIVATE
))
1562 /* These are, so copy the standard handles too */
1563 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1564 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1565 lpStartupInfo
->hStdError
= Params
->StandardError
;
1574 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1576 PRTL_USER_PROCESS_PARAMETERS Params
;
1577 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1578 LPSTARTUPINFOA StartupInfo
;
1581 /* Get the cached information as well as the PEB parameters */
1582 StartupInfo
= BaseAnsiStartupInfo
;
1583 Params
= NtCurrentPeb()->ProcessParameters
;
1585 /* Check if this is the first time we have to get the cached version */
1586 while (!StartupInfo
)
1588 /* Create new ANSI startup info */
1589 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1591 sizeof(*StartupInfo
));
1594 /* Zero out string pointers in case we fail to create them */
1595 StartupInfo
->lpReserved
= 0;
1596 StartupInfo
->lpDesktop
= 0;
1597 StartupInfo
->lpTitle
= 0;
1600 StartupInfo
->cb
= sizeof(*StartupInfo
);
1602 /* Copy what's already stored in the PEB */
1603 StartupInfo
->dwX
= Params
->StartingX
;
1604 StartupInfo
->dwY
= Params
->StartingY
;
1605 StartupInfo
->dwXSize
= Params
->CountX
;
1606 StartupInfo
->dwYSize
= Params
->CountY
;
1607 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1608 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1609 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1610 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1611 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1612 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1613 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1614 StartupInfo
->hStdInput
= Params
->StandardInput
;
1615 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1616 StartupInfo
->hStdError
= Params
->StandardError
;
1618 /* Copy shell info string */
1619 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1622 if (NT_SUCCESS(Status
))
1625 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1627 /* Copy desktop info string */
1628 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1629 &Params
->DesktopInfo
,
1631 if (NT_SUCCESS(Status
))
1634 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1636 /* Copy window title string */
1637 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1638 &Params
->WindowTitle
,
1640 if (NT_SUCCESS(Status
))
1643 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1645 /* We finished with the ANSI version, try to cache it */
1646 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo
,
1650 /* We were the first thread through, use the data */
1654 /* Someone beat us to it, use their data instead */
1655 StartupInfo
= BaseAnsiStartupInfo
;
1656 Status
= STATUS_SUCCESS
;
1658 /* We're going to free our own stuff, but not raise */
1659 RtlFreeAnsiString(&TitleString
);
1661 RtlFreeAnsiString(&DesktopString
);
1663 RtlFreeAnsiString(&ShellString
);
1665 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1669 /* No memory, fail */
1670 Status
= STATUS_NO_MEMORY
;
1673 /* Raise an error unless we got here due to the race condition */
1674 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1677 /* Now copy from the cached ANSI version */
1678 lpStartupInfo
->cb
= StartupInfo
->cb
;
1679 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1680 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1681 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1682 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1683 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1684 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1685 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1686 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1687 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1688 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1689 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1690 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1691 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1692 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1694 /* Check if the shell is hijacking the handles for other features */
1695 if (lpStartupInfo
->dwFlags
&
1696 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1698 /* It isn't, so we can return the raw values */
1699 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1700 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1701 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1705 /* It is, so make sure nobody uses these as console handles */
1706 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1707 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1708 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1717 FlushInstructionCache(IN HANDLE hProcess
,
1718 IN LPCVOID lpBaseAddress
,
1723 /* Call the native function */
1724 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, dwSize
);
1725 if (!NT_SUCCESS(Status
))
1727 /* Handle failure case */
1728 BaseSetLastNTError(Status
);
1741 ExitProcess(IN UINT uExitCode
)
1743 CSR_API_MESSAGE CsrRequest
;
1744 ASSERT(!BaseRunningInServerProcess
);
1748 /* Acquire the PEB lock */
1749 RtlAcquirePebLock();
1751 /* Kill all the threads */
1752 NtTerminateProcess(NULL
, 0);
1754 /* Unload all DLLs */
1755 LdrShutdownProcess();
1757 /* Notify Base Server of process termination */
1758 CsrRequest
.Data
.TerminateProcessRequest
.uExitCode
= uExitCode
;
1759 CsrClientCallServer(&CsrRequest
,
1761 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1762 sizeof(CSR_API_MESSAGE
));
1764 /* Now do it again */
1765 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1769 /* Release the PEB lock */
1770 RtlReleasePebLock();
1774 /* should never get here */
1784 TerminateProcess(IN HANDLE hProcess
,
1789 /* Check if no handle was passed in */
1792 /* Set error code */
1793 SetLastError(ERROR_INVALID_HANDLE
);
1797 /* Otherwise, try to terminate the process */
1798 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1799 if (NT_SUCCESS(Status
)) return TRUE
;
1801 /* It failed, convert error code */
1802 BaseSetLastNTError(Status
);
1805 /* This is the failure path */
1814 FatalAppExitA(UINT uAction
,
1815 LPCSTR lpMessageText
)
1817 PUNICODE_STRING MessageTextU
;
1818 ANSI_STRING MessageText
;
1821 /* Initialize the string using the static TEB pointer */
1822 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1823 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1825 /* Convert to unicode and just exit normally if this failed */
1826 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1827 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1829 /* Call the Wide function */
1830 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1838 FatalAppExitW(IN UINT uAction
,
1839 IN LPCWSTR lpMessageText
)
1841 UNICODE_STRING UnicodeString
;
1845 /* Setup the stirng to print out */
1846 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1848 /* Display the hard error no matter what */
1849 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1852 (PULONG_PTR
)&UnicodeString
,
1856 /* Give the user a chance to abort */
1857 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1859 /* Otherwise kill the process */
1868 FatalExit(IN
int ExitCode
)
1871 /* On Checked builds, Windows gives you a nice little debugger UI */
1873 DbgPrint("FatalExit...\n");
1878 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1886 ExitProcess(ExitCode
);
1893 /* On other builds, just kill the process */
1894 ExitProcess(ExitCode
);
1902 GetPriorityClass(IN HANDLE hProcess
)
1905 PROCESS_PRIORITY_CLASS PriorityClass
;
1907 /* Query the kernel */
1908 Status
= NtQueryInformationProcess(hProcess
,
1909 ProcessPriorityClass
,
1911 sizeof(PROCESS_PRIORITY_CLASS
),
1913 if (NT_SUCCESS(Status
))
1915 /* Handle the conversion from NT to Win32 classes */
1916 switch (PriorityClass
.PriorityClass
)
1918 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1919 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1920 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1921 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1922 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1923 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1928 BaseSetLastNTError(Status
);
1937 SetPriorityClass(IN HANDLE hProcess
,
1938 IN DWORD dwPriorityClass
)
1942 PROCESS_PRIORITY_CLASS PriorityClass
;
1944 /* Handle conversion from Win32 to NT priority classes */
1945 switch (dwPriorityClass
)
1947 case IDLE_PRIORITY_CLASS
:
1948 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1951 case BELOW_NORMAL_PRIORITY_CLASS
:
1952 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1955 case NORMAL_PRIORITY_CLASS
:
1956 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1959 case ABOVE_NORMAL_PRIORITY_CLASS
:
1960 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1963 case HIGH_PRIORITY_CLASS
:
1964 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1967 case REALTIME_PRIORITY_CLASS
:
1968 /* Try to acquire the privilege. If it fails, just use HIGH */
1969 State
= BasepIsRealtimeAllowed(TRUE
);
1970 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1971 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1975 /* Unrecognized priority classes don't make it to the kernel */
1976 SetLastError(ERROR_INVALID_PARAMETER
);
1980 /* Send the request to the kernel, and don't touch the foreground flag */
1981 PriorityClass
.Foreground
= FALSE
;
1982 Status
= NtSetInformationProcess(hProcess
,
1983 ProcessPriorityClass
,
1985 sizeof(PROCESS_PRIORITY_CLASS
));
1987 /* Release the privilege if we had it */
1988 if (State
) RtlReleasePrivilege(State
);
1989 if (!NT_SUCCESS(Status
))
1991 /* Handle error path */
1992 BaseSetLastNTError(Status
);
2005 GetProcessVersion(IN DWORD ProcessId
)
2008 PIMAGE_NT_HEADERS NtHeader
;
2009 PIMAGE_DOS_HEADER DosHeader
;
2011 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2014 HANDLE ProcessHandle
= NULL
;
2016 USHORT VersionData
[2];
2019 /* We'll be accessing stuff that can fault, so protect everything with SEH */
2022 /* It this an in-process or out-of-process request? */
2023 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
2025 /* It's in-process, so just read our own header */
2026 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
2029 /* Unable to read the NT header, something is wrong here... */
2030 Status
= STATUS_INVALID_IMAGE_FORMAT
;
2034 /* Get the version straight out of the NT header */
2035 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
2036 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
2040 /* Out-of-process, so open it */
2041 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
2044 if (!ProcessHandle
) return 0;
2046 /* Try to find out where its PEB lives */
2047 Status
= NtQueryInformationProcess(ProcessHandle
,
2048 ProcessBasicInformation
,
2050 sizeof(ProcessBasicInfo
),
2053 if (!NT_SUCCESS(Status
)) goto Error
;
2054 Peb
= ProcessBasicInfo
.PebBaseAddress
;
2056 /* Now that we have the PEB, read the image base address out of it */
2057 Result
= ReadProcessMemory(ProcessHandle
,
2058 &Peb
->ImageBaseAddress
,
2060 sizeof(BaseAddress
),
2062 if (!Result
) goto Error
;
2064 /* Now read the e_lfanew (offset to NT header) from the base */
2065 DosHeader
= BaseAddress
;
2066 Result
= ReadProcessMemory(ProcessHandle
,
2067 &DosHeader
->e_lfanew
,
2071 if (!Result
) goto Error
;
2073 /* And finally, read the NT header itself by adding the offset */
2074 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
2075 Result
= ReadProcessMemory(ProcessHandle
,
2076 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
2078 sizeof(VersionData
),
2080 if (!Result
) goto Error
;
2082 /* Get the version straight out of the NT header */
2083 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
2086 /* If there was an error anywhere, set the last error */
2087 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
2092 /* Close the process handle */
2093 if (ProcessHandle
) CloseHandle(ProcessHandle
);
2097 /* And return the version data */
2106 GetProcessIoCounters(IN HANDLE hProcess
,
2107 OUT PIO_COUNTERS lpIoCounters
)
2111 /* Query the kernel. Structures are identical, so let it do the copy too. */
2112 Status
= NtQueryInformationProcess(hProcess
,
2115 sizeof(IO_COUNTERS
),
2117 if (!NT_SUCCESS(Status
))
2119 /* Handle error path */
2120 BaseSetLastNTError(Status
);
2133 GetProcessPriorityBoost(IN HANDLE hProcess
,
2134 OUT PBOOL pDisablePriorityBoost
)
2137 ULONG PriorityBoost
;
2139 /* Query the kernel */
2140 Status
= NtQueryInformationProcess(hProcess
,
2141 ProcessPriorityBoost
,
2145 if (NT_SUCCESS(Status
))
2147 /* Convert from ULONG to a BOOL */
2148 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
2152 /* Handle error path */
2153 BaseSetLastNTError(Status
);
2162 SetProcessPriorityBoost(IN HANDLE hProcess
,
2163 IN BOOL bDisablePriorityBoost
)
2166 ULONG PriorityBoost
;
2168 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
2169 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
2170 Status
= NtSetInformationProcess(hProcess
,
2171 ProcessPriorityBoost
,
2174 if (!NT_SUCCESS(Status
))
2176 /* Handle error path */
2177 BaseSetLastNTError(Status
);
2190 GetProcessHandleCount(IN HANDLE hProcess
,
2191 OUT PDWORD pdwHandleCount
)
2196 /* Query the kernel */
2197 Status
= NtQueryInformationProcess(hProcess
,
2202 if (NT_SUCCESS(Status
))
2204 /* Copy the count and return sucecss */
2205 *pdwHandleCount
= phc
;
2209 /* Handle error path */
2210 BaseSetLastNTError(Status
);
2219 IsWow64Process(IN HANDLE hProcess
,
2220 OUT PBOOL Wow64Process
)
2225 /* Query the kernel */
2226 Status
= NtQueryInformationProcess(hProcess
,
2227 ProcessWow64Information
,
2231 if (!NT_SUCCESS(Status
))
2233 /* Handle error path */
2234 BaseSetLastNTError(Status
);
2238 /* Enforce this is a BOOL, and return success */
2239 *Wow64Process
= (pbi
!= 0);
2248 GetCommandLineA(VOID
)
2250 return BaseAnsiCommandLine
.Buffer
;
2258 GetCommandLineW(VOID
)
2260 return BaseUnicodeCommandLine
.Buffer
;
2268 ReadProcessMemory(IN HANDLE hProcess
,
2269 IN LPCVOID lpBaseAddress
,
2272 OUT SIZE_T
* lpNumberOfBytesRead
)
2277 Status
= NtReadVirtualMemory(hProcess
,
2278 (PVOID
)lpBaseAddress
,
2283 /* In user-mode, this parameter is optional */
2284 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2285 if (!NT_SUCCESS(Status
))
2288 BaseSetLastNTError(Status
);
2292 /* Return success */
2301 WriteProcessMemory(IN HANDLE hProcess
,
2302 IN LPVOID lpBaseAddress
,
2303 IN LPCVOID lpBuffer
,
2305 OUT SIZE_T
*lpNumberOfBytesWritten
)
2313 /* Set parameters for protect call */
2315 Base
= lpBaseAddress
;
2317 /* Check the current status */
2318 Status
= NtProtectVirtualMemory(hProcess
,
2321 PAGE_EXECUTE_READWRITE
,
2323 if (NT_SUCCESS(Status
))
2325 /* Check if we are unprotecting */
2326 UnProtect
= OldValue
& (PAGE_READWRITE
|
2328 PAGE_EXECUTE_READWRITE
|
2329 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2332 /* Set the new protection */
2333 Status
= NtProtectVirtualMemory(hProcess
,
2339 /* Write the memory */
2340 Status
= NtWriteVirtualMemory(hProcess
,
2346 /* In Win32, the parameter is optional, so handle this case */
2347 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2349 if (!NT_SUCCESS(Status
))
2352 BaseSetLastNTError(Status
);
2356 /* Flush the ITLB */
2357 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2362 /* Check if we were read only */
2363 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2365 /* Restore protection and fail */
2366 NtProtectVirtualMemory(hProcess
,
2371 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2373 /* Note: This is what Windows returns and code depends on it */
2374 return STATUS_ACCESS_VIOLATION
;
2377 /* Otherwise, do the write */
2378 Status
= NtWriteVirtualMemory(hProcess
,
2384 /* In Win32, the parameter is optional, so handle this case */
2385 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2387 /* And restore the protection */
2388 NtProtectVirtualMemory(hProcess
,
2393 if (!NT_SUCCESS(Status
))
2396 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2398 /* Note: This is what Windows returns and code depends on it */
2399 return STATUS_ACCESS_VIOLATION
;
2402 /* Flush the ITLB */
2403 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2410 BaseSetLastNTError(Status
);
2420 ProcessIdToSessionId(IN DWORD dwProcessId
,
2421 OUT PDWORD pSessionId
)
2423 PROCESS_SESSION_INFORMATION SessionInformation
;
2424 OBJECT_ATTRIBUTES ObjectAttributes
;
2426 HANDLE ProcessHandle
;
2429 /* Do a quick check if the pointer is not writable */
2430 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2433 SetLastError(ERROR_INVALID_PARAMETER
);
2437 /* Open the process passed in by ID */
2438 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2439 ClientId
.UniqueThread
= 0;
2440 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2441 Status
= NtOpenProcess(&ProcessHandle
,
2442 PROCESS_QUERY_INFORMATION
,
2445 if (NT_SUCCESS(Status
))
2447 /* Query the session ID from the kernel */
2448 Status
= NtQueryInformationProcess(ProcessHandle
,
2449 ProcessSessionInformation
,
2450 &SessionInformation
,
2451 sizeof(SessionInformation
),
2454 /* Close the handle and check if we suceeded */
2455 NtClose(ProcessHandle
);
2456 if (NT_SUCCESS(Status
))
2458 /* Return the session ID */
2459 *pSessionId
= SessionInformation
.SessionId
;
2464 /* Set error code and fail */
2465 BaseSetLastNTError(Status
);
2474 CreateProcessInternalW(HANDLE hToken
,
2475 LPCWSTR lpApplicationName
,
2476 LPWSTR lpCommandLine
,
2477 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2478 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2479 BOOL bInheritHandles
,
2480 DWORD dwCreationFlags
,
2481 LPVOID lpEnvironment
,
2482 LPCWSTR lpCurrentDirectory
,
2483 LPSTARTUPINFOW lpStartupInfo
,
2484 LPPROCESS_INFORMATION lpProcessInformation
,
2488 PROCESS_PRIORITY_CLASS PriorityClass
;
2489 BOOLEAN FoundQuotes
= FALSE
;
2490 BOOLEAN QuotesNeeded
= FALSE
;
2491 BOOLEAN CmdLineIsAppName
= FALSE
;
2492 UNICODE_STRING ApplicationName
= { 0, 0, NULL
};
2493 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2494 POBJECT_ATTRIBUTES ObjectAttributes
;
2495 HANDLE hSection
= NULL
, hProcess
= NULL
, hThread
= NULL
, hDebug
= NULL
;
2496 SECTION_IMAGE_INFORMATION SectionImageInfo
;
2497 LPWSTR CurrentDirectory
= NULL
;
2498 LPWSTR CurrentDirectoryPart
;
2499 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2500 STARTUPINFOW StartupInfo
;
2502 LPWSTR BatchCommandLine
;
2503 ULONG CmdLineLength
;
2504 UNICODE_STRING CommandLineString
;
2506 LPWSTR QuotedCmdLine
= NULL
;
2508 LPWSTR NullBuffer
= NULL
;
2509 LPWSTR NameBuffer
= NULL
;
2513 BOOLEAN SearchDone
= FALSE
;
2514 BOOLEAN Escape
= FALSE
;
2516 PPEB OurPeb
= NtCurrentPeb();
2521 /* FIXME should process
2522 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2523 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2526 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2527 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2528 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
2531 /* Flags we don't handle yet */
2532 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
2534 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2536 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
2538 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2540 if (dwCreationFlags
& CREATE_FORCEDOS
)
2542 DPRINT1("CREATE_FORCEDOS not handled\n");
2545 /* Fail on this flag, it's only valid with the WithLogonW function */
2546 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
2548 DPRINT1("Invalid flag used\n");
2549 SetLastError(ERROR_INVALID_PARAMETER
);
2553 /* This combination is illegal (see MSDN) */
2554 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2555 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2557 DPRINT1("Invalid flag combo used\n");
2558 SetLastError(ERROR_INVALID_PARAMETER
);
2562 /* Another illegal combo */
2563 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
2564 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
2566 DPRINT1("Invalid flag combo used\n");
2567 SetLastError(ERROR_INVALID_PARAMETER
);
2571 if (lpCurrentDirectory
)
2573 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
2574 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
2576 SetLastError(ERROR_DIRECTORY
);
2582 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2583 * so we'll use our own local copy for that.
2585 StartupInfo
= *lpStartupInfo
;
2587 /* FIXME: Use default Separate/Shared VDM Flag */
2589 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2590 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
2592 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
2594 /* Remove the shared flag and add the separate flag. */
2595 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2596 CREATE_SEPARATE_WOW_VDM
;
2601 * According to some sites, ShellExecuteEx uses an undocumented flag to
2602 * send private handle data (such as HMONITOR or HICON). See:
2603 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2604 * standard handles anymore since we'd be overwriting this private data
2606 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2607 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2609 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2612 /* Start by zeroing out the fields */
2613 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
2615 /* Easy stuff first, convert the process priority class */
2616 PriorityClass
.Foreground
= FALSE
;
2617 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
2621 /* Search for escape sequences */
2622 ScanString
= lpCommandLine
;
2623 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2626 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\"')
2634 /* Get the application name and do all the proper formating necessary */
2636 /* See if we have an application name (oh please let us have one!) */
2637 if (!lpApplicationName
)
2639 /* The fun begins */
2640 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2642 MAX_PATH
* sizeof(WCHAR
));
2643 if (NameBuffer
== NULL
)
2645 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2649 /* This is all we have to work with :( */
2650 lpApplicationName
= lpCommandLine
;
2652 /* Initialize our friends at the beginning */
2653 NullBuffer
= (LPWSTR
)lpApplicationName
;
2654 ScanString
= (LPWSTR
)lpApplicationName
;
2656 /* We will start by looking for a quote */
2657 if (*ScanString
== L
'\"')
2659 /* That was quick */
2662 /* Advance past quote */
2664 lpApplicationName
= ScanString
;
2666 /* Find the closing quote */
2669 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
2672 NullBuffer
= ScanString
;
2679 NullBuffer
= ScanString
;
2684 /* No quotes, so we'll be looking for white space */
2686 /* Reset the pointer */
2687 lpApplicationName
= lpCommandLine
;
2689 /* Find whitespace of Tab */
2692 if (*ScanString
== ' ' || *ScanString
== '\t')
2695 NullBuffer
= ScanString
;
2701 NullBuffer
= ScanString
;
2705 /* Set the Null Buffer */
2706 SaveChar
= *NullBuffer
;
2707 *NullBuffer
= UNICODE_NULL
;
2709 /* Do a search for the file */
2710 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
2711 RetVal
= SearchPathW(NULL
,
2716 NULL
) * sizeof(WCHAR
);
2718 /* Did it find something? */
2721 /* Get file attributes */
2722 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
2723 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2725 /* Give it a length of 0 to fail, this was a directory. */
2731 RetVal
+= sizeof(WCHAR
);
2735 /* Now check if we have a file, and if the path size is OK */
2736 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
2741 /* We failed, try to get the Path Type */
2742 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
2743 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2745 /* If it's not relative, try to get the error */
2746 if (PathType
!= RtlPathTypeRelative
)
2748 /* This should fail, and give us a detailed LastError */
2749 hFile
= CreateFileW(lpApplicationName
,
2751 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2754 FILE_ATTRIBUTE_NORMAL
,
2757 /* Did it actually NOT fail? */
2758 if (hFile
!= INVALID_HANDLE_VALUE
)
2760 /* Fake the error */
2762 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2767 /* Immediately set the error */
2768 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2771 /* Did we already fail once? */
2774 SetLastError(Error
);
2778 /* Not yet, cache it */
2779 Error
= GetLastError();
2782 /* Put back the command line */
2783 *NullBuffer
= SaveChar
;
2784 lpApplicationName
= NameBuffer
;
2787 * If the search isn't done and we still have cmdline
2788 * then start over. Ex: c:\ha ha ha\haha.exe
2790 if (*ScanString
&& !SearchDone
)
2792 /* Move in the buffer */
2794 NullBuffer
= ScanString
;
2796 /* We will have to add a quote, since there is a space*/
2797 QuotesNeeded
= TRUE
;
2799 /* And we will also fake the fact we found one */
2806 /* We totally failed */
2810 /* Put back the command line */
2811 *NullBuffer
= SaveChar
;
2812 lpApplicationName
= NameBuffer
;
2813 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
2815 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
2817 /* We have an app name (good!) but no command line */
2818 CmdLineIsAppName
= TRUE
;
2819 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2822 /* At this point the name has been toyed with enough to be openable */
2823 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
2825 /* Check for failure */
2826 if (!NT_SUCCESS(Status
))
2828 /* Could be a non-PE File */
2831 /* Check if the Kernel tells us it's not even valid MZ */
2832 case STATUS_INVALID_IMAGE_NE_FORMAT
:
2833 case STATUS_INVALID_IMAGE_PROTECT
:
2834 case STATUS_INVALID_IMAGE_NOT_MZ
:
2837 /* If it's a DOS app, use VDM */
2838 if ((BasepCheckDosApp(&ApplicationName
)))
2840 DPRINT1("Launching VDM...\n");
2841 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2842 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2843 return CreateProcessW(L
"ntvdm.exe",
2844 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2845 lpProcessAttributes
,
2852 lpProcessInformation
);
2855 /* It's a batch file */
2856 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
2859 /* Make sure the extensions are correct */
2860 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
2862 SetLastError(ERROR_BAD_EXE_FORMAT
);
2866 /* Calculate the length of the command line */
2867 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
2869 /* If we found quotes, then add them into the length size */
2870 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
2871 CmdLineLength
*= sizeof(WCHAR
);
2873 /* Allocate space for the new command line */
2874 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2877 if (BatchCommandLine
== NULL
)
2879 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2884 wcscpy(BatchCommandLine
, CMD_STRING
);
2885 if (CmdLineIsAppName
|| FoundQuotes
)
2887 wcscat(BatchCommandLine
, L
"\"");
2889 wcscat(BatchCommandLine
, lpCommandLine
);
2890 if (CmdLineIsAppName
|| FoundQuotes
)
2892 wcscat(BatchCommandLine
, L
"\"");
2895 /* Create it as a Unicode String */
2896 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
2898 /* Set the command line to this */
2899 lpCommandLine
= CommandLineString
.Buffer
;
2900 lpApplicationName
= NULL
;
2903 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2904 ApplicationName
.Buffer
= NULL
;
2908 case STATUS_INVALID_IMAGE_WIN_16
:
2910 /* It's a Win16 Image, use VDM */
2911 DPRINT1("Launching VDM...\n");
2912 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2913 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2914 return CreateProcessW(L
"ntvdm.exe",
2915 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2916 lpProcessAttributes
,
2923 lpProcessInformation
);
2925 case STATUS_OBJECT_NAME_NOT_FOUND
:
2926 case STATUS_OBJECT_PATH_NOT_FOUND
:
2927 BaseSetLastNTError(Status
);
2931 /* Invalid Image Type */
2932 SetLastError(ERROR_BAD_EXE_FORMAT
);
2937 /* Use our desktop if we didn't get any */
2938 if (!StartupInfo
.lpDesktop
)
2940 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
2943 /* FIXME: Check if Application is allowed to run */
2945 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2947 /* Get some information about the executable */
2948 Status
= NtQuerySection(hSection
,
2949 SectionImageInformation
,
2951 sizeof(SectionImageInfo
),
2953 if(!NT_SUCCESS(Status
))
2955 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
2956 BaseSetLastNTError(Status
);
2960 /* Don't execute DLLs */
2961 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
2963 DPRINT1("Can't execute a DLL\n");
2964 SetLastError(ERROR_BAD_EXE_FORMAT
);
2968 /* FIXME: Check for Debugger */
2970 /* FIXME: Check if Machine Type and SubSys Version Match */
2972 /* We don't support POSIX or anything else for now */
2973 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= SectionImageInfo
.SubSystemType
&&
2974 IMAGE_SUBSYSTEM_WINDOWS_CUI
!= SectionImageInfo
.SubSystemType
)
2976 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
2978 * Despite the name of the error code suggests, it corresponds to the
2979 * well-known "The %1 application cannot be run in Win32 mode" message.
2981 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
2985 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
2987 /* Do not create a console for GUI applications */
2988 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
2989 dwCreationFlags
|= DETACHED_PROCESS
;
2992 /* Initialize the process object attributes */
2993 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
2994 lpProcessAttributes
,
2997 /* Check if we're going to be debugged */
2998 if (dwCreationFlags
& DEBUG_PROCESS
)
3000 /* FIXME: Set process flag */
3003 /* Check if we're going to be debugged */
3004 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3006 /* Connect to DbgUi */
3007 Status
= DbgUiConnectToDbg();
3008 if (!NT_SUCCESS(Status
))
3010 DPRINT1("Failed to connect to DbgUI!\n");
3011 BaseSetLastNTError(Status
);
3015 /* Get the debug object */
3016 hDebug
= DbgUiGetThreadDebugObject();
3018 /* Check if only this process will be debugged */
3019 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3021 /* Set process flag */
3022 hDebug
= (HANDLE
)((ULONG_PTR
)hDebug
| 0x1);
3026 /* Create the Process */
3027 Status
= NtCreateProcess(&hProcess
,
3031 (BOOLEAN
)bInheritHandles
,
3035 if (!NT_SUCCESS(Status
))
3037 DPRINT1("Unable to create process, status 0x%x\n", Status
);
3038 BaseSetLastNTError(Status
);
3042 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
3045 Status
= NtSetInformationProcess(hProcess
,
3046 ProcessPriorityClass
,
3048 sizeof(PROCESS_PRIORITY_CLASS
));
3049 if(!NT_SUCCESS(Status
))
3051 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
3052 BaseSetLastNTError(Status
);
3057 /* Set Error Mode */
3058 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3060 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
3061 NtSetInformationProcess(hProcess
,
3062 ProcessDefaultHardErrorMode
,
3067 /* Convert the directory to a full path */
3068 if (lpCurrentDirectory
)
3070 /* Allocate a buffer */
3071 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
3073 (MAX_PATH
+ 1) * sizeof(WCHAR
));
3074 if (CurrentDirectory
== NULL
)
3076 DPRINT1("Cannot allocate memory for directory name\n");
3077 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3081 /* Get the length */
3082 if (GetFullPathNameW(lpCurrentDirectory
,
3085 &CurrentDirectoryPart
) > MAX_PATH
)
3087 DPRINT1("Directory name too long\n");
3088 SetLastError(ERROR_DIRECTORY
);
3093 /* Insert quotes if needed */
3094 if (QuotesNeeded
|| CmdLineIsAppName
)
3096 /* Allocate a buffer */
3097 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3099 (wcslen(lpCommandLine
) + 2 + 1) *
3101 if (QuotedCmdLine
== NULL
)
3103 DPRINT1("Cannot allocate memory for quoted command line\n");
3104 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3108 /* Copy the first quote */
3109 wcscpy(QuotedCmdLine
, L
"\"");
3111 /* Save a null char */
3114 SaveChar
= *NullBuffer
;
3115 *NullBuffer
= UNICODE_NULL
;
3118 /* Add the command line and the finishing quote */
3119 wcscat(QuotedCmdLine
, lpCommandLine
);
3120 wcscat(QuotedCmdLine
, L
"\"");
3122 /* Add the null char */
3125 *NullBuffer
= SaveChar
;
3126 wcscat(QuotedCmdLine
, NullBuffer
);
3129 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
3134 if (QuotedCmdLine
== NULL
)
3136 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3138 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
3139 if (QuotedCmdLine
== NULL
)
3141 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3144 wcscpy(QuotedCmdLine
, lpCommandLine
);
3147 ScanString
= QuotedCmdLine
;
3148 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
3151 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
3153 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
3158 /* Get the Process Information */
3159 Status
= NtQueryInformationProcess(hProcess
,
3160 ProcessBasicInformation
,
3162 sizeof(ProcessBasicInfo
),
3165 /* Convert the environment */
3166 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3168 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
3169 if (!lpEnvironment
) goto Cleanup
;
3172 /* Create Process Environment */
3173 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
3174 Ret
= BasePushProcessParameters(0,
3177 (LPWSTR
)lpApplicationName
,
3179 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
3180 QuotedCmdLine
: lpCommandLine
,
3188 if (!Ret
) goto Cleanup
;
3190 /* Cleanup Environment */
3191 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3193 RtlDestroyEnvironment(lpEnvironment
);
3196 /* Close the section */
3200 /* Duplicate the handles if needed */
3201 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
3202 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
3204 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
3206 /* Get the remote parameters */
3207 Status
= NtReadVirtualMemory(hProcess
,
3208 &RemotePeb
->ProcessParameters
,
3212 if (!NT_SUCCESS(Status
))
3214 DPRINT1("Failed to read memory\n");
3218 /* Duplicate and write the handles */
3219 BasepDuplicateAndWriteHandle(hProcess
,
3220 OurPeb
->ProcessParameters
->StandardInput
,
3221 &RemoteParameters
->StandardInput
);
3222 BasepDuplicateAndWriteHandle(hProcess
,
3223 OurPeb
->ProcessParameters
->StandardOutput
,
3224 &RemoteParameters
->StandardOutput
);
3225 BasepDuplicateAndWriteHandle(hProcess
,
3226 OurPeb
->ProcessParameters
->StandardError
,
3227 &RemoteParameters
->StandardError
);
3230 /* Create the first thread */
3231 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
3232 SectionImageInfo
.TransferAddress
);
3233 hThread
= BasepCreateFirstThread(hProcess
,
3240 if (hThread
== NULL
)
3242 DPRINT1("Could not create Initial Thread\n");
3243 /* FIXME - set last error code */
3247 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
3249 NtResumeThread(hThread
, &Dummy
);
3253 lpProcessInformation
->dwProcessId
= (DWORD
)ClientId
.UniqueProcess
;
3254 lpProcessInformation
->dwThreadId
= (DWORD
)ClientId
.UniqueThread
;
3255 lpProcessInformation
->hProcess
= hProcess
;
3256 lpProcessInformation
->hThread
= hThread
;
3257 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread
,
3258 ClientId
.UniqueThread
, ClientId
.UniqueProcess
, hProcess
);
3259 hProcess
= hThread
= NULL
;
3263 /* De-allocate heap strings */
3264 if (NameBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3265 if (ApplicationName
.Buffer
)
3266 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
3267 if (CurrentDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
3268 if (QuotedCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
3270 /* Kill any handles still alive */
3271 if (hSection
) NtClose(hSection
);
3274 /* We don't know any more details than this */
3275 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
3278 if (hProcess
) NtClose(hProcess
);
3280 /* Return Success */
3289 CreateProcessW(LPCWSTR lpApplicationName
,
3290 LPWSTR lpCommandLine
,
3291 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3292 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3293 BOOL bInheritHandles
,
3294 DWORD dwCreationFlags
,
3295 LPVOID lpEnvironment
,
3296 LPCWSTR lpCurrentDirectory
,
3297 LPSTARTUPINFOW lpStartupInfo
,
3298 LPPROCESS_INFORMATION lpProcessInformation
)
3300 /* Call the internal (but exported) version */
3301 return CreateProcessInternalW(0,
3304 lpProcessAttributes
,
3311 lpProcessInformation
,
3320 CreateProcessInternalA(HANDLE hToken
,
3321 LPCSTR lpApplicationName
,
3322 LPSTR lpCommandLine
,
3323 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3324 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3325 BOOL bInheritHandles
,
3326 DWORD dwCreationFlags
,
3327 LPVOID lpEnvironment
,
3328 LPCSTR lpCurrentDirectory
,
3329 LPSTARTUPINFOA lpStartupInfo
,
3330 LPPROCESS_INFORMATION lpProcessInformation
,
3333 PUNICODE_STRING CommandLine
= NULL
;
3334 UNICODE_STRING DummyString
;
3335 UNICODE_STRING LiveCommandLine
;
3336 UNICODE_STRING ApplicationName
;
3337 UNICODE_STRING CurrentDirectory
;
3339 STARTUPINFOW StartupInfo
;
3341 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
3342 "lpStartupInfo %x, lpProcessInformation %x\n",
3343 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
3344 lpStartupInfo
, lpProcessInformation
);
3346 /* Copy Startup Info */
3347 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
3349 /* Initialize all strings to nothing */
3350 LiveCommandLine
.Buffer
= NULL
;
3351 DummyString
.Buffer
= NULL
;
3352 ApplicationName
.Buffer
= NULL
;
3353 CurrentDirectory
.Buffer
= NULL
;
3354 StartupInfo
.lpDesktop
= NULL
;
3355 StartupInfo
.lpReserved
= NULL
;
3356 StartupInfo
.lpTitle
= NULL
;
3358 /* Convert the Command line */
3361 /* If it's too long, then we'll have a problem */
3362 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
3363 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
3365 /* Cache it in the TEB */
3366 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
3370 /* Use a dynamic version */
3371 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
3377 /* The logic below will use CommandLine, so we must make it valid */
3378 CommandLine
= &DummyString
;
3381 /* Convert the Name and Directory */
3382 if (lpApplicationName
)
3384 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
3387 if (lpCurrentDirectory
)
3389 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
3390 lpCurrentDirectory
);
3393 /* Now convert Startup Strings */
3394 if (lpStartupInfo
->lpReserved
)
3396 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
3397 &StartupInfo
.lpReserved
);
3399 if (lpStartupInfo
->lpDesktop
)
3401 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
3402 &StartupInfo
.lpDesktop
);
3404 if (lpStartupInfo
->lpTitle
)
3406 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
3407 &StartupInfo
.lpTitle
);
3410 /* Call the Unicode function */
3411 bRetVal
= CreateProcessInternalW(hToken
,
3412 ApplicationName
.Buffer
,
3413 LiveCommandLine
.Buffer
?
3414 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
3415 lpProcessAttributes
,
3420 CurrentDirectory
.Buffer
,
3422 lpProcessInformation
,
3426 RtlFreeUnicodeString(&ApplicationName
);
3427 RtlFreeUnicodeString(&LiveCommandLine
);
3428 RtlFreeUnicodeString(&CurrentDirectory
);
3429 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
3430 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
3431 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
3433 /* Return what Unicode did */
3438 * FUNCTION: The CreateProcess function creates a new process and its
3439 * primary thread. The new process executes the specified executable file
3442 * lpApplicationName = Pointer to name of executable module
3443 * lpCommandLine = Pointer to command line string
3444 * lpProcessAttributes = Process security attributes
3445 * lpThreadAttributes = Thread security attributes
3446 * bInheritHandles = Handle inheritance flag
3447 * dwCreationFlags = Creation flags
3448 * lpEnvironment = Pointer to new environment block
3449 * lpCurrentDirectory = Pointer to current directory name
3450 * lpStartupInfo = Pointer to startup info
3451 * lpProcessInformation = Pointer to process information
3457 CreateProcessA(LPCSTR lpApplicationName
,
3458 LPSTR lpCommandLine
,
3459 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3460 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3461 BOOL bInheritHandles
,
3462 DWORD dwCreationFlags
,
3463 LPVOID lpEnvironment
,
3464 LPCSTR lpCurrentDirectory
,
3465 LPSTARTUPINFOA lpStartupInfo
,
3466 LPPROCESS_INFORMATION lpProcessInformation
)
3468 /* Call the internal (but exported) version */
3469 return CreateProcessInternalA(0,
3472 lpProcessAttributes
,
3479 lpProcessInformation
,
3488 WinExec(LPCSTR lpCmdLine
,
3491 STARTUPINFOA StartupInfo
;
3492 PROCESS_INFORMATION ProcessInformation
;
3495 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
3496 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
3497 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
3498 StartupInfo
.dwFlags
= 0;
3500 if (!CreateProcessA(NULL
,
3509 &ProcessInformation
))
3511 dosErr
= GetLastError();
3512 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
3515 if (NULL
!= UserWaitForInputIdleRoutine
)
3517 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
3521 NtClose(ProcessInformation
.hProcess
);
3522 NtClose(ProcessInformation
.hThread
);
3524 return 33; /* Something bigger than 31 means success. */