2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/proc/proc.c
5 * PURPOSE: Process functions
6 * PROGRAMMERS: Ariadne (ariadne@xs4all.nl)
11 /* INCLUDES ****************************************************************/
18 /* GLOBALS *******************************************************************/
20 WaitForInputIdleType UserWaitForInputIdleRoutine
;
21 UNICODE_STRING BaseUnicodeCommandLine
;
22 ANSI_STRING BaseAnsiCommandLine
;
23 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
24 LPSTARTUPINFOA BaseAnsiStartupInfo
= NULL
;
25 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
26 BOOLEAN g_AppCertInitialized
;
27 BOOLEAN g_HaveAppCerts
;
28 LIST_ENTRY BasepAppCertDllsList
;
29 RTL_CRITICAL_SECTION gcsAppCert
;
30 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
31 NTSTATUS g_AppCertStatus
;
32 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
35 BasepConfigureAppCertDlls
,
38 &BasepAppCertDllsList
,
45 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
46 HMODULE gSaferHandle
= (HMODULE
)-1;
49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
51 #define CMD_STRING L"cmd /c "
53 /* FUNCTIONS ****************************************************************/
57 StuffStdHandle(IN HANDLE ProcessHandle
,
58 IN HANDLE StandardHandle
,
62 HANDLE DuplicatedHandle
;
65 /* Duplicate the handle */
66 Status
= NtDuplicateObject(NtCurrentProcess(),
70 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
73 if (NT_SUCCESS(Status
))
76 NtWriteVirtualMemory(ProcessHandle
,
86 BuildSubSysCommandLine(IN LPWSTR SubsystemName
,
87 IN LPWSTR ApplicationName
,
88 IN LPWSTR CommandLine
,
89 OUT PUNICODE_STRING SubsysCommandLine
)
91 UNICODE_STRING CommandLineString
, ApplicationNameString
;
95 /* Convert to unicode strings */
96 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
97 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
99 /* Allocate buffer for the output string */
100 Length
= CommandLineString
.MaximumLength
+ ApplicationNameString
.MaximumLength
+ 32;
101 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
102 RtlInitEmptyUnicodeString(SubsysCommandLine
, Buffer
, Length
);
105 /* Fail, no memory */
106 BaseSetLastNTError(STATUS_NO_MEMORY
);
110 /* Build the final subsystem command line */
111 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
112 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
113 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
114 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
120 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
121 IN ULONG ImageMinorVersion
)
123 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
124 return ((ImageMajorVersion
>= 3) &&
125 ((ImageMajorVersion
!= 3) ||
126 (ImageMinorVersion
>= 10)) &&
127 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
128 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
129 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
134 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
139 /* Get all the MD5 hashes */
140 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
141 if (!NT_SUCCESS(Status
)) return Status
;
143 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
144 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
146 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
148 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
150 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
152 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
154 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
157 /* Actually, fuck it, don't block anything, we're open source */
158 return STATUS_SUCCESS
;
163 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
164 IN PWCHAR ComponentName
,
167 /* Pretty much the only thing this key is used for, is malware */
169 return STATUS_NOT_IMPLEMENTED
;
174 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
177 IN ULONG ValueLength
,
179 IN PVOID EntryContext
)
181 /* Add this to the certification list */
182 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
187 BasepIsProcessAllowed(IN PCHAR ApplicationName
)
192 HMODULE TrustLibrary
;
193 PBASEP_APPCERT_ENTRY Entry
;
195 PLIST_ENTRY NextEntry
;
197 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
198 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
200 /* Try to initialize the certification subsystem */
201 while (!g_AppCertInitialized
)
204 Status
= STATUS_SUCCESS
;
207 /* Acquire the lock while initializing and see if we lost a race */
208 RtlEnterCriticalSection(&gcsAppCert
);
209 if (g_AppCertInitialized
) break;
211 /* On embedded, there is a special DLL */
212 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
214 /* Allocate a buffer for the name */
215 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
217 MAX_PATH
* sizeof(WCHAR
) +
218 sizeof(UNICODE_NULL
));
221 /* Fail if no memory */
222 Status
= STATUS_NO_MEMORY
;
226 /* Now get the system32 directory in our buffer, make sure it fits */
227 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
228 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
230 /* Add a slash if needed, and add the embedded cert DLL name */
231 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
232 RtlCopyMemory(&Buffer
[Length
],
234 sizeof(L
"EmbdTrst.DLL"));
237 TrustLibrary
= LoadLibraryW(Buffer
);
240 /* And extract the special function out of it */
241 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
242 "ImageOkToRunOnEmbeddedNT");
246 /* If we didn't get this far, set a failure code */
247 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
252 /* Other systems have a registry entry for this */
253 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
254 if (NT_SUCCESS(Status
))
256 /* Close it, we'll query it through Rtl */
259 /* Do the query, which will call a special callback */
260 Status
= RtlQueryRegistryValues(2,
265 if (Status
== 0xC0000034) Status
= STATUS_SUCCESS
;
269 /* Free any buffer if we had one */
270 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
272 /* Check for errors, or a missing embedded/custom certification DLL */
273 if (!NT_SUCCESS(Status
) ||
274 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
276 /* The subsystem is not active on this machine, so give up */
277 g_HaveAppCerts
= FALSE
;
278 g_AppCertStatus
= Status
;
282 /* We have certification DLLs active, remember this */
283 g_HaveAppCerts
= TRUE
;
286 /* We are done the initialization phase, release the lock */
287 g_AppCertInitialized
= TRUE
;
288 RtlLeaveCriticalSection(&gcsAppCert
);
291 /* If there's no certification DLLs present, return the failure code */
292 if (!g_HaveAppCerts
) return g_AppCertStatus
;
294 /* Otherwise, assume success and make sure we have *something* */
295 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
296 Status
= STATUS_SUCCESS
;
298 /* If the something is an embedded certification DLL, call it and return */
299 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
301 /* Otherwise we have custom certification DLLs, parse them */
302 NextEntry
= BasepAppCertDllsList
.Flink
;
304 while (NextEntry
!= &BasepAppCertDllsList
)
306 /* Make sure the entry has a callback */
307 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
308 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
310 /* Call it and check if it failed */
311 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
312 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
315 NextEntry
= NextEntry
->Flink
;
318 /* Now loop them again */
319 NextEntry
= BasepAppCertDllsList
.Flink
;
320 while (NextEntry
!= &BasepAppCertDllsList
)
322 /* Make sure the entry has a callback */
323 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
324 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
326 /* Call it, this time with the flag from the loop above */
327 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
330 /* All done, return the status */
336 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
337 IN HANDLE ProcessHandle
,
338 IN HANDLE ThreadHandle
)
341 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
343 /* Enter the application certification lock */
344 RtlEnterCriticalSection(&gcsAppCert
);
346 /* Check if we already know the function */
347 if (g_SaferReplaceProcessThreadTokens
)
350 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
358 /* Check if the app certification DLL isn't loaded */
359 if (!(gSaferHandle
) ||
360 (gSaferHandle
== (HMODULE
)-1) ||
361 (gSaferHandle
== (HMODULE
)-2))
363 /* Then we can't call the function */
364 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
368 /* We have the DLL, find the address of the Safer function */
369 Status
= LdrGetProcedureAddress(gSaferHandle
,
370 &SaferiReplaceProcessThreadTokens
,
372 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
373 if (NT_SUCCESS(Status
))
375 /* Found it, now call it */
376 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
384 /* We couldn't find it, so this must be an unsupported DLL */
385 LdrUnloadDll(gSaferHandle
);
387 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
392 /* Release the lock and return the result */
393 RtlLeaveCriticalSection(&gcsAppCert
);
399 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
404 ASSERT(Handles
!= NULL
);
405 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
407 /* Close the file handle */
410 Status
= NtClose(Handles
->File
);
411 ASSERT(NT_SUCCESS(Status
));
414 /* Close the section handle */
415 if (Handles
->Section
)
417 Status
= NtClose(Handles
->Section
);
418 ASSERT(NT_SUCCESS(Status
));
421 /* Unmap the section view */
422 if (Handles
->ViewBase
.QuadPart
)
424 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
425 (PVOID
)Handles
->ViewBase
.LowPart
);
426 ASSERT(NT_SUCCESS(Status
));
431 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
433 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
434 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
435 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
437 if (RealFilter
!= NULL
)
441 ExceptionDisposition
= RealFilter(ExceptionInfo
);
443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
448 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
449 RealFilter
!= UnhandledExceptionFilter
)
451 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
454 return ExceptionDisposition
;
459 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
461 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
465 /* Set our Start Address */
466 NtSetInformationThread(NtCurrentThread(),
467 ThreadQuerySetWin32StartAddress
,
469 sizeof(PPROCESS_START_ROUTINE
));
471 /* Call the Start Routine */
472 ExitThread(lpStartAddress());
474 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
476 /* Get the Exit code from the SEH Handler */
477 if (!BaseRunningInServerProcess
)
479 /* Kill the whole process, usually */
480 ExitProcess(_SEH2_GetExceptionCode());
484 /* If running inside CSRSS, kill just this thread */
485 ExitThread(_SEH2_GetExceptionCode());
493 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
494 IN PCLIENT_ID ClientId
)
497 BASE_API_MESSAGE ApiMessage
;
498 PBASE_CREATE_THREAD CreateThreadRequest
= &ApiMessage
.Data
.CreateThreadRequest
;
500 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
501 ClientId
->UniqueThread
, ThreadHandle
);
503 /* Fill out the request */
504 CreateThreadRequest
->ClientId
= *ClientId
;
505 CreateThreadRequest
->ThreadHandle
= ThreadHandle
;
508 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
510 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
511 sizeof(BASE_CREATE_THREAD
));
512 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(ApiMessage
.Status
))
514 DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status
, ApiMessage
.Status
);
515 return ApiMessage
.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
)
535 OBJECT_ATTRIBUTES LocalObjectAttributes
;
536 POBJECT_ATTRIBUTES ObjectAttributes
;
538 INITIAL_TEB InitialTeb
;
540 BASE_API_MESSAGE ApiMessage
;
541 PBASE_CREATE_PROCESS CreateProcessRequest
= &ApiMessage
.Data
.CreateProcessRequest
;
543 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
545 /* Create the Thread's Stack */
546 BaseCreateStack(ProcessHandle
,
547 SectionImageInfo
->MaximumStackSize
,
548 SectionImageInfo
->CommittedStackSize
,
551 /* Create the Thread's Context */
552 BaseInitializeContext(&Context
,
554 SectionImageInfo
->TransferAddress
,
555 InitialTeb
.StackBase
,
558 /* Convert the thread attributes */
559 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
563 /* Create the Kernel Thread Object */
564 Status
= NtCreateThread(&hThread
,
572 if (!NT_SUCCESS(Status
))
577 /* Fill out the request to notify CSRSS */
578 CreateProcessRequest
->ClientId
= *ClientId
;
579 CreateProcessRequest
->ProcessHandle
= ProcessHandle
;
580 CreateProcessRequest
->ThreadHandle
= hThread
;
581 CreateProcessRequest
->CreationFlags
= dwCreationFlags
;
582 CreateProcessRequest
->bInheritHandles
= InheritHandles
;
585 DPRINT1("Calling CsrClientCallServer from BasepCreateFirstThread...\n");
586 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
588 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateProcess
),
589 sizeof(BASE_CREATE_PROCESS
));
590 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(ApiMessage
.Status
))
592 DPRINT1("Failed to tell csrss about new process: %lx %lx\n", Status
, ApiMessage
.Status
);
601 * Converts ANSI to Unicode Environment
605 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
606 IN PVOID lpEnvironment
)
610 UNICODE_STRING UnicodeEnv
;
613 DPRINT("BasepConvertUnicodeEnvironment\n");
615 /* Scan the environment to calculate its Unicode size */
616 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
619 pcScan
+= strlen(pcScan
) + 1;
622 /* Create our ANSI String */
623 if (pcScan
== (PCHAR
)lpEnvironment
)
625 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
630 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
632 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
634 /* Allocate memory for the Unicode Environment */
635 UnicodeEnv
.Buffer
= NULL
;
636 *EnvSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
637 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
638 (PVOID
)&UnicodeEnv
.Buffer
,
644 if (!NT_SUCCESS(Status
))
646 SetLastError(Status
);
651 /* Use the allocated size */
652 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
655 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
656 return UnicodeEnv
.Buffer
;
660 * Converts a Win32 Priority Class to NT
664 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
668 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
670 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
672 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
674 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
676 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
678 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
680 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
682 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
684 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
686 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
688 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
690 /* Check for Privilege First */
691 if (BasepIsRealtimeAllowed(TRUE
))
693 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
697 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
702 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
709 * Duplicates a standard handle and writes it where requested.
713 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
714 IN HANDLE StandardHandle
,
718 HANDLE DuplicatedHandle
;
721 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
722 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
724 /* Don't touch Console Handles */
725 if (IsConsoleHandle(StandardHandle
)) return;
727 /* Duplicate the handle */
728 Status
= NtDuplicateObject(NtCurrentProcess(),
732 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
735 if (NT_SUCCESS(Status
))
738 NtWriteVirtualMemory(ProcessHandle
,
748 BasePushProcessParameters(IN ULONG ParameterFlags
,
749 IN HANDLE ProcessHandle
,
751 IN LPCWSTR ApplicationPathName
,
752 IN LPWSTR lpCurrentDirectory
,
753 IN LPWSTR lpCommandLine
,
754 IN LPVOID lpEnvironment
,
755 IN LPSTARTUPINFOW StartupInfo
,
756 IN DWORD CreationFlags
,
757 IN BOOL InheritHandles
,
758 IN ULONG ImageSubsystem
,
759 IN PVOID AppCompatData
,
760 IN ULONG AppCompatDataSize
)
762 WCHAR FullPath
[MAX_PATH
+ 5];
763 PWCHAR Remaining
, DllPathString
, ScanChar
;
764 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
765 PVOID RemoteAppCompatData
;
766 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
767 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
771 BOOLEAN HavePebLock
= FALSE
, Result
;
772 PPEB Peb
= NtCurrentPeb();
774 /* Get the full path name */
775 Size
= GetFullPathNameW(ApplicationPathName
,
779 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
781 /* Get the DLL Path */
782 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
786 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
790 /* Initialize Strings */
791 RtlInitUnicodeString(&DllPath
, DllPathString
);
792 RtlInitUnicodeString(&ImageName
, FullPath
);
796 /* Couldn't get the path name. Just take the original path */
797 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
802 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
806 /* Initialize Strings */
807 RtlInitUnicodeString(&DllPath
, DllPathString
);
808 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
811 /* Initialize Strings */
812 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
813 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
815 /* Initialize more Strings from the Startup Info */
816 if (StartupInfo
->lpDesktop
)
818 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
822 RtlInitUnicodeString(&Desktop
, L
"");
824 if (StartupInfo
->lpReserved
)
826 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
830 RtlInitUnicodeString(&Shell
, L
"");
832 if (StartupInfo
->lpTitle
)
834 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
838 RtlInitUnicodeString(&Title
, ApplicationPathName
);
841 /* This one is special because the length can differ */
842 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
843 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
845 /* Enforce no app compat data if the pointer was NULL */
846 if (!AppCompatData
) AppCompatDataSize
= 0;
848 /* Create the Parameter Block */
849 ProcessParameters
= NULL
;
850 Status
= RtlCreateProcessParameters(&ProcessParameters
,
854 &CurrentDirectory
: NULL
,
861 if (!NT_SUCCESS(Status
)) goto FailPath
;
863 /* Clear the current directory handle if not inheriting */
864 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
866 /* Check if the user passed in an environment */
869 /* We should've made it part of the parameters block, enforce this */
870 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
871 lpEnvironment
= ProcessParameters
->Environment
;
875 /* The user did not, so use the one from the current PEB */
878 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
881 /* Save pointer and start lookup */
882 ScanChar
= lpEnvironment
;
885 /* Find the environment size */
886 while ((ScanChar
[0]) || (ScanChar
[1])) ++ScanChar
;
887 ScanChar
+= (2 * sizeof(UNICODE_NULL
));
888 EnviroSize
= (ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
;
890 /* Allocate and Initialize new Environment Block */
892 ProcessParameters
->Environment
= NULL
;
893 Status
= NtAllocateVirtualMemory(ProcessHandle
,
894 (PVOID
*)&ProcessParameters
->Environment
,
899 if (!NT_SUCCESS(Status
)) goto FailPath
;
901 /* Write the Environment Block */
902 Status
= NtWriteVirtualMemory(ProcessHandle
,
903 ProcessParameters
->Environment
,
908 /* No longer need the PEB lock anymore */
916 /* Check if the write failed */
917 if (!NT_SUCCESS(Status
)) goto FailPath
;
920 /* Write new parameters */
921 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
922 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
923 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
924 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
925 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
926 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
927 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
928 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
929 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
931 /* Write the handles only if we have to */
932 if (StartupInfo
->dwFlags
&
933 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
935 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
936 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
937 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
940 /* Use Special Flags for ConDllInitialize in Kernel32 */
941 if (CreationFlags
& DETACHED_PROCESS
)
943 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
945 else if (CreationFlags
& CREATE_NO_WINDOW
)
947 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
949 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
951 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
955 /* Inherit our Console Handle */
956 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
958 /* Make sure that the shell isn't trampling on our handles first */
959 if (!(StartupInfo
->dwFlags
&
960 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
962 /* Copy the handle if we are inheriting or if it's a console handle */
963 if ((InheritHandles
) ||
964 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
966 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
968 if ((InheritHandles
) ||
969 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
971 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
973 if ((InheritHandles
) ||
974 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
976 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
981 /* Also set the Console Flag */
982 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
983 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
985 ProcessParameters
->ConsoleFlags
= 1;
988 /* See if the first 1MB should be reserved */
989 if (ParameterFlags
& 1)
991 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB
;
994 /* See if the first 16MB should be reserved */
995 if (ParameterFlags
& 2)
997 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB
;
1000 /* Allocate memory for the parameter block */
1001 Size
= ProcessParameters
->Length
;
1002 RemoteParameters
= NULL
;
1003 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1004 (PVOID
*)&RemoteParameters
,
1009 if (!NT_SUCCESS(Status
)) goto FailPath
;
1011 /* Set the allocated size */
1012 ProcessParameters
->MaximumLength
= Size
;
1014 /* Handle some Parameter Flags */
1015 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
1016 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
1017 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
1018 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
1019 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
1020 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
1021 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
1022 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
1024 /* Write the Parameter Block */
1025 Status
= NtWriteVirtualMemory(ProcessHandle
,
1028 ProcessParameters
->Length
,
1030 if (!NT_SUCCESS(Status
)) goto FailPath
;
1032 /* Write the PEB Pointer */
1033 Status
= NtWriteVirtualMemory(ProcessHandle
,
1034 &RemotePeb
->ProcessParameters
,
1038 if (!NT_SUCCESS(Status
)) goto FailPath
;
1040 /* Check if there's any app compat data to write */
1041 RemoteAppCompatData
= NULL
;
1044 /* Allocate some space for the application compatibility data */
1045 Size
= AppCompatDataSize
;
1046 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1047 &RemoteAppCompatData
,
1052 if (!NT_SUCCESS(Status
)) goto FailPath
;
1054 /* Write the application compatibility data */
1055 Status
= NtWriteVirtualMemory(ProcessHandle
,
1056 RemoteAppCompatData
,
1060 if (!NT_SUCCESS(Status
)) goto FailPath
;
1063 /* Write the PEB Pointer to the app compat data (might be NULL) */
1064 Status
= NtWriteVirtualMemory(ProcessHandle
,
1065 &RemotePeb
->pShimData
,
1066 &RemoteAppCompatData
,
1069 if (!NT_SUCCESS(Status
)) goto FailPath
;
1071 /* Now write Peb->ImageSubSystem */
1074 NtWriteVirtualMemory(ProcessHandle
,
1075 &RemotePeb
->ImageSubsystem
,
1077 sizeof(ImageSubsystem
),
1086 if (HavePebLock
) RtlReleasePebLock();
1087 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
1088 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
1091 DPRINT1("Failure to create proecss parameters: %lx\n", Status
);
1092 BaseSetLastNTError(Status
);
1099 InitCommandLines(VOID
)
1103 /* Read the UNICODE_STRING from the PEB */
1104 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
1106 /* Convert to ANSI_STRING for the *A callers */
1107 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
1108 &BaseUnicodeCommandLine
,
1110 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
1113 /* PUBLIC FUNCTIONS ***********************************************************/
1120 GetProcessAffinityMask(IN HANDLE hProcess
,
1121 OUT PDWORD_PTR lpProcessAffinityMask
,
1122 OUT PDWORD_PTR lpSystemAffinityMask
)
1124 PROCESS_BASIC_INFORMATION ProcessInfo
;
1127 /* Query information on the process from the kernel */
1128 Status
= NtQueryInformationProcess(hProcess
,
1129 ProcessBasicInformation
,
1130 (PVOID
)&ProcessInfo
,
1131 sizeof(PROCESS_BASIC_INFORMATION
),
1133 if (!NT_SUCCESS(Status
))
1136 BaseSetLastNTError(Status
);
1140 /* Copy the affinity mask, and get the system one from our shared data */
1141 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
1142 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
1151 SetProcessAffinityMask(IN HANDLE hProcess
,
1152 IN DWORD_PTR dwProcessAffinityMask
)
1156 /* Directly set the affinity mask */
1157 Status
= NtSetInformationProcess(hProcess
,
1158 ProcessAffinityMask
,
1159 (PVOID
)&dwProcessAffinityMask
,
1161 if (!NT_SUCCESS(Status
))
1163 /* Handle failure */
1164 BaseSetLastNTError(Status
);
1168 /* Everything was ok */
1177 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
1178 OUT LPDWORD lpdwFlags
)
1181 BASE_API_MESSAGE ApiMessage
;
1182 PBASE_GET_PROCESS_SHUTDOWN_PARAMS GetShutdownParametersRequest
= &ApiMessage
.Data
.GetShutdownParametersRequest
;
1184 /* Ask CSRSS for shutdown information */
1185 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1187 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
1188 sizeof(BASE_GET_PROCESS_SHUTDOWN_PARAMS
));
1189 if (!(NT_SUCCESS(Status
)) || !(NT_SUCCESS(ApiMessage
.Status
)))
1191 /* Return the failure from CSRSS */
1192 BaseSetLastNTError(ApiMessage
.Status
);
1196 /* Get the data out of the LCP reply */
1197 *lpdwLevel
= GetShutdownParametersRequest
->Level
;
1198 *lpdwFlags
= GetShutdownParametersRequest
->Flags
;
1207 SetProcessShutdownParameters(IN DWORD dwLevel
,
1211 BASE_API_MESSAGE ApiMessage
;
1212 PBASE_SET_PROCESS_SHUTDOWN_PARAMS SetShutdownParametersRequest
= &ApiMessage
.Data
.SetShutdownParametersRequest
;
1214 /* Write the data into the CSRSS request and send it */
1215 SetShutdownParametersRequest
->Level
= dwLevel
;
1216 SetShutdownParametersRequest
->Flags
= dwFlags
;
1217 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1219 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1220 sizeof(BASE_SET_PROCESS_SHUTDOWN_PARAMS
));
1221 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(ApiMessage
.Status
))
1223 /* Return the failure from CSRSS */
1224 BaseSetLastNTError(ApiMessage
.Status
);
1237 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1238 OUT PSIZE_T lpMinimumWorkingSetSize
,
1239 OUT PSIZE_T lpMaximumWorkingSetSize
,
1242 QUOTA_LIMITS_EX QuotaLimits
;
1245 /* Query the kernel about this */
1246 Status
= NtQueryInformationProcess(hProcess
,
1249 sizeof(QUOTA_LIMITS_EX
),
1251 if (!NT_SUCCESS(Status
))
1254 BaseSetLastNTError(Status
);
1258 /* Copy the quota information out */
1259 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1260 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1261 *Flags
= QuotaLimits
.Flags
;
1270 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1271 OUT PSIZE_T lpMinimumWorkingSetSize
,
1272 OUT PSIZE_T lpMaximumWorkingSetSize
)
1275 return GetProcessWorkingSetSizeEx(hProcess
,
1276 lpMinimumWorkingSetSize
,
1277 lpMaximumWorkingSetSize
,
1286 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1287 IN SIZE_T dwMinimumWorkingSetSize
,
1288 IN SIZE_T dwMaximumWorkingSetSize
,
1291 QUOTA_LIMITS_EX QuotaLimits
;
1292 NTSTATUS Status
, ReturnStatus
;
1295 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1297 /* Zero out the input structure */
1298 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1300 /* Check if the caller sent any limits */
1301 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1303 /* Write the quota information */
1304 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1305 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1306 QuotaLimits
.Flags
= Flags
;
1308 /* Acquire the required privilege */
1309 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1311 /* Request the new quotas */
1312 ReturnStatus
= NtSetInformationProcess(hProcess
,
1315 sizeof(QuotaLimits
));
1316 Result
= NT_SUCCESS(ReturnStatus
);
1317 if (NT_SUCCESS(Status
))
1319 /* Release the privilege and set succes code */
1320 ASSERT(State
!= NULL
);
1321 RtlReleasePrivilege(State
);
1327 /* No limits, fail the call */
1328 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1332 /* Return result code, set error code if this was a failure */
1333 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1342 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1343 IN SIZE_T dwMinimumWorkingSetSize
,
1344 IN SIZE_T dwMaximumWorkingSetSize
)
1346 /* Call the newer API */
1347 return SetProcessWorkingSetSizeEx(hProcess
,
1348 dwMinimumWorkingSetSize
,
1349 dwMaximumWorkingSetSize
,
1358 GetProcessTimes(IN HANDLE hProcess
,
1359 IN LPFILETIME lpCreationTime
,
1360 IN LPFILETIME lpExitTime
,
1361 IN LPFILETIME lpKernelTime
,
1362 IN LPFILETIME lpUserTime
)
1364 KERNEL_USER_TIMES Kut
;
1367 /* Query the times */
1368 Status
= NtQueryInformationProcess(hProcess
,
1373 if (!NT_SUCCESS(Status
))
1375 /* Handle failure */
1376 BaseSetLastNTError(Status
);
1380 /* Copy all the times and return success */
1381 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1382 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1383 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1384 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1385 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1386 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1387 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1388 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1397 GetCurrentProcess(VOID
)
1399 return (HANDLE
)NtCurrentProcess();
1407 GetCurrentThread(VOID
)
1409 return (HANDLE
)NtCurrentThread();
1417 GetCurrentProcessId(VOID
)
1419 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1427 GetExitCodeProcess(IN HANDLE hProcess
,
1428 IN LPDWORD lpExitCode
)
1430 PROCESS_BASIC_INFORMATION ProcessBasic
;
1433 /* Ask the kernel */
1434 Status
= NtQueryInformationProcess(hProcess
,
1435 ProcessBasicInformation
,
1437 sizeof(PROCESS_BASIC_INFORMATION
),
1439 if (!NT_SUCCESS(Status
))
1441 /* We failed, was this because this is a VDM process? */
1442 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1444 /* Not a VDM process, fail the call */
1445 BaseSetLastNTError(Status
);
1449 /* Succes case, return the exit code */
1450 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1459 GetProcessId(IN HANDLE Process
)
1461 PROCESS_BASIC_INFORMATION ProcessBasic
;
1464 /* Query the kernel */
1465 Status
= NtQueryInformationProcess(Process
,
1466 ProcessBasicInformation
,
1468 sizeof(PROCESS_BASIC_INFORMATION
),
1470 if (!NT_SUCCESS(Status
))
1472 /* Handle failure */
1473 BaseSetLastNTError(Status
);
1477 /* Return the PID */
1478 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1486 OpenProcess(IN DWORD dwDesiredAccess
,
1487 IN BOOL bInheritHandle
,
1488 IN DWORD dwProcessId
)
1491 HANDLE ProcessHandle
;
1492 OBJECT_ATTRIBUTES ObjectAttributes
;
1495 /* Setup the input client ID structure */
1496 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1497 ClientId
.UniqueThread
= 0;
1499 /* This is needed just to define the inheritance flags */
1500 InitializeObjectAttributes(&ObjectAttributes
,
1502 (bInheritHandle
? OBJ_INHERIT
: 0),
1506 /* Now try to open the process */
1507 Status
= NtOpenProcess(&ProcessHandle
,
1511 if (!NT_SUCCESS(Status
))
1513 /* Handle failure */
1514 BaseSetLastNTError(Status
);
1518 /* Otherwise return a handle to the process */
1519 return ProcessHandle
;
1527 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1529 /* Write the global function pointer */
1530 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1538 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1540 PRTL_USER_PROCESS_PARAMETERS Params
;
1542 /* Get the process parameters */
1543 Params
= NtCurrentPeb()->ProcessParameters
;
1545 /* Copy the data out of there */
1546 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1547 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1548 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1549 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1550 lpStartupInfo
->dwX
= Params
->StartingX
;
1551 lpStartupInfo
->dwY
= Params
->StartingY
;
1552 lpStartupInfo
->dwXSize
= Params
->CountX
;
1553 lpStartupInfo
->dwYSize
= Params
->CountY
;
1554 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1555 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1556 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1557 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1558 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1559 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1560 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1562 /* Check if the standard handles are being used for other features */
1563 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1565 STARTF_SHELLPRIVATE
))
1567 /* These are, so copy the standard handles too */
1568 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1569 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1570 lpStartupInfo
->hStdError
= Params
->StandardError
;
1579 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1581 PRTL_USER_PROCESS_PARAMETERS Params
;
1582 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1583 LPSTARTUPINFOA StartupInfo
;
1586 /* Get the cached information as well as the PEB parameters */
1587 StartupInfo
= BaseAnsiStartupInfo
;
1588 Params
= NtCurrentPeb()->ProcessParameters
;
1590 /* Check if this is the first time we have to get the cached version */
1591 while (!StartupInfo
)
1593 /* Create new ANSI startup info */
1594 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1596 sizeof(*StartupInfo
));
1599 /* Zero out string pointers in case we fail to create them */
1600 StartupInfo
->lpReserved
= 0;
1601 StartupInfo
->lpDesktop
= 0;
1602 StartupInfo
->lpTitle
= 0;
1605 StartupInfo
->cb
= sizeof(*StartupInfo
);
1607 /* Copy what's already stored in the PEB */
1608 StartupInfo
->dwX
= Params
->StartingX
;
1609 StartupInfo
->dwY
= Params
->StartingY
;
1610 StartupInfo
->dwXSize
= Params
->CountX
;
1611 StartupInfo
->dwYSize
= Params
->CountY
;
1612 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1613 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1614 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1615 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1616 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1617 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1618 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1619 StartupInfo
->hStdInput
= Params
->StandardInput
;
1620 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1621 StartupInfo
->hStdError
= Params
->StandardError
;
1623 /* Copy shell info string */
1624 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1627 if (NT_SUCCESS(Status
))
1630 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1632 /* Copy desktop info string */
1633 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1634 &Params
->DesktopInfo
,
1636 if (NT_SUCCESS(Status
))
1639 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1641 /* Copy window title string */
1642 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1643 &Params
->WindowTitle
,
1645 if (NT_SUCCESS(Status
))
1648 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1650 /* We finished with the ANSI version, try to cache it */
1651 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo
,
1655 /* We were the first thread through, use the data */
1659 /* Someone beat us to it, use their data instead */
1660 StartupInfo
= BaseAnsiStartupInfo
;
1661 Status
= STATUS_SUCCESS
;
1663 /* We're going to free our own stuff, but not raise */
1664 RtlFreeAnsiString(&TitleString
);
1666 RtlFreeAnsiString(&DesktopString
);
1668 RtlFreeAnsiString(&ShellString
);
1670 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1674 /* No memory, fail */
1675 Status
= STATUS_NO_MEMORY
;
1678 /* Raise an error unless we got here due to the race condition */
1679 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1682 /* Now copy from the cached ANSI version */
1683 lpStartupInfo
->cb
= StartupInfo
->cb
;
1684 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1685 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1686 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1687 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1688 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1689 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1690 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1691 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1692 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1693 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1694 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1695 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1696 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1697 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1699 /* Check if the shell is hijacking the handles for other features */
1700 if (lpStartupInfo
->dwFlags
&
1701 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1703 /* It isn't, so we can return the raw values */
1704 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1705 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1706 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1710 /* It is, so make sure nobody uses these as console handles */
1711 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1712 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1713 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1722 FlushInstructionCache(IN HANDLE hProcess
,
1723 IN LPCVOID lpBaseAddress
,
1728 /* Call the native function */
1729 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, dwSize
);
1730 if (!NT_SUCCESS(Status
))
1732 /* Handle failure case */
1733 BaseSetLastNTError(Status
);
1746 ExitProcess(IN UINT uExitCode
)
1748 BASE_API_MESSAGE ApiMessage
;
1749 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1751 ASSERT(!BaseRunningInServerProcess
);
1755 /* Acquire the PEB lock */
1756 RtlAcquirePebLock();
1758 /* Kill all the threads */
1759 NtTerminateProcess(NULL
, 0);
1761 /* Unload all DLLs */
1762 LdrShutdownProcess();
1764 /* Notify Base Server of process termination */
1765 ExitProcessRequest
->uExitCode
= uExitCode
;
1766 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1768 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1769 sizeof(BASE_EXIT_PROCESS
));
1771 /* Now do it again */
1772 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1776 /* Release the PEB lock */
1777 RtlReleasePebLock();
1781 /* should never get here */
1791 TerminateProcess(IN HANDLE hProcess
,
1796 /* Check if no handle was passed in */
1799 /* Set error code */
1800 SetLastError(ERROR_INVALID_HANDLE
);
1804 /* Otherwise, try to terminate the process */
1805 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1806 if (NT_SUCCESS(Status
)) return TRUE
;
1808 /* It failed, convert error code */
1809 BaseSetLastNTError(Status
);
1812 /* This is the failure path */
1821 FatalAppExitA(UINT uAction
,
1822 LPCSTR lpMessageText
)
1824 PUNICODE_STRING MessageTextU
;
1825 ANSI_STRING MessageText
;
1828 /* Initialize the string using the static TEB pointer */
1829 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1830 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1832 /* Convert to unicode and just exit normally if this failed */
1833 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1834 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1836 /* Call the Wide function */
1837 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1845 FatalAppExitW(IN UINT uAction
,
1846 IN LPCWSTR lpMessageText
)
1848 UNICODE_STRING UnicodeString
;
1852 /* Setup the stirng to print out */
1853 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1855 /* Display the hard error no matter what */
1856 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1859 (PULONG_PTR
)&UnicodeString
,
1863 /* Give the user a chance to abort */
1864 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1866 /* Otherwise kill the process */
1875 FatalExit(IN
int ExitCode
)
1878 /* On Checked builds, Windows gives you a nice little debugger UI */
1880 DbgPrint("FatalExit...\n");
1885 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1893 ExitProcess(ExitCode
);
1900 /* On other builds, just kill the process */
1901 ExitProcess(ExitCode
);
1909 GetPriorityClass(IN HANDLE hProcess
)
1912 PROCESS_PRIORITY_CLASS PriorityClass
;
1914 /* Query the kernel */
1915 Status
= NtQueryInformationProcess(hProcess
,
1916 ProcessPriorityClass
,
1918 sizeof(PROCESS_PRIORITY_CLASS
),
1920 if (NT_SUCCESS(Status
))
1922 /* Handle the conversion from NT to Win32 classes */
1923 switch (PriorityClass
.PriorityClass
)
1925 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1926 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1927 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1928 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1929 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1930 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1935 BaseSetLastNTError(Status
);
1944 SetPriorityClass(IN HANDLE hProcess
,
1945 IN DWORD dwPriorityClass
)
1949 PROCESS_PRIORITY_CLASS PriorityClass
;
1951 /* Handle conversion from Win32 to NT priority classes */
1952 switch (dwPriorityClass
)
1954 case IDLE_PRIORITY_CLASS
:
1955 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1958 case BELOW_NORMAL_PRIORITY_CLASS
:
1959 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1962 case NORMAL_PRIORITY_CLASS
:
1963 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1966 case ABOVE_NORMAL_PRIORITY_CLASS
:
1967 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1970 case HIGH_PRIORITY_CLASS
:
1971 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1974 case REALTIME_PRIORITY_CLASS
:
1975 /* Try to acquire the privilege. If it fails, just use HIGH */
1976 State
= BasepIsRealtimeAllowed(TRUE
);
1977 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1978 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1982 /* Unrecognized priority classes don't make it to the kernel */
1983 SetLastError(ERROR_INVALID_PARAMETER
);
1987 /* Send the request to the kernel, and don't touch the foreground flag */
1988 PriorityClass
.Foreground
= FALSE
;
1989 Status
= NtSetInformationProcess(hProcess
,
1990 ProcessPriorityClass
,
1992 sizeof(PROCESS_PRIORITY_CLASS
));
1994 /* Release the privilege if we had it */
1995 if (State
) RtlReleasePrivilege(State
);
1996 if (!NT_SUCCESS(Status
))
1998 /* Handle error path */
1999 BaseSetLastNTError(Status
);
2012 GetProcessVersion(IN DWORD ProcessId
)
2015 PIMAGE_NT_HEADERS NtHeader
;
2016 PIMAGE_DOS_HEADER DosHeader
;
2018 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2021 HANDLE ProcessHandle
= NULL
;
2023 USHORT VersionData
[2];
2026 /* We'll be accessing stuff that can fault, so protect everything with SEH */
2029 /* It this an in-process or out-of-process request? */
2030 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
2032 /* It's in-process, so just read our own header */
2033 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
2036 /* Unable to read the NT header, something is wrong here... */
2037 Status
= STATUS_INVALID_IMAGE_FORMAT
;
2041 /* Get the version straight out of the NT header */
2042 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
2043 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
2047 /* Out-of-process, so open it */
2048 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
2051 if (!ProcessHandle
) return 0;
2053 /* Try to find out where its PEB lives */
2054 Status
= NtQueryInformationProcess(ProcessHandle
,
2055 ProcessBasicInformation
,
2057 sizeof(ProcessBasicInfo
),
2060 if (!NT_SUCCESS(Status
)) goto Error
;
2061 Peb
= ProcessBasicInfo
.PebBaseAddress
;
2063 /* Now that we have the PEB, read the image base address out of it */
2064 Result
= ReadProcessMemory(ProcessHandle
,
2065 &Peb
->ImageBaseAddress
,
2067 sizeof(BaseAddress
),
2069 if (!Result
) goto Error
;
2071 /* Now read the e_lfanew (offset to NT header) from the base */
2072 DosHeader
= BaseAddress
;
2073 Result
= ReadProcessMemory(ProcessHandle
,
2074 &DosHeader
->e_lfanew
,
2078 if (!Result
) goto Error
;
2080 /* And finally, read the NT header itself by adding the offset */
2081 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
2082 Result
= ReadProcessMemory(ProcessHandle
,
2083 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
2085 sizeof(VersionData
),
2087 if (!Result
) goto Error
;
2089 /* Get the version straight out of the NT header */
2090 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
2093 /* If there was an error anywhere, set the last error */
2094 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
2099 /* Close the process handle */
2100 if (ProcessHandle
) CloseHandle(ProcessHandle
);
2104 /* And return the version data */
2113 GetProcessIoCounters(IN HANDLE hProcess
,
2114 OUT PIO_COUNTERS lpIoCounters
)
2118 /* Query the kernel. Structures are identical, so let it do the copy too. */
2119 Status
= NtQueryInformationProcess(hProcess
,
2122 sizeof(IO_COUNTERS
),
2124 if (!NT_SUCCESS(Status
))
2126 /* Handle error path */
2127 BaseSetLastNTError(Status
);
2140 GetProcessPriorityBoost(IN HANDLE hProcess
,
2141 OUT PBOOL pDisablePriorityBoost
)
2144 ULONG PriorityBoost
;
2146 /* Query the kernel */
2147 Status
= NtQueryInformationProcess(hProcess
,
2148 ProcessPriorityBoost
,
2152 if (NT_SUCCESS(Status
))
2154 /* Convert from ULONG to a BOOL */
2155 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
2159 /* Handle error path */
2160 BaseSetLastNTError(Status
);
2169 SetProcessPriorityBoost(IN HANDLE hProcess
,
2170 IN BOOL bDisablePriorityBoost
)
2173 ULONG PriorityBoost
;
2175 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
2176 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
2177 Status
= NtSetInformationProcess(hProcess
,
2178 ProcessPriorityBoost
,
2181 if (!NT_SUCCESS(Status
))
2183 /* Handle error path */
2184 BaseSetLastNTError(Status
);
2197 GetProcessHandleCount(IN HANDLE hProcess
,
2198 OUT PDWORD pdwHandleCount
)
2203 /* Query the kernel */
2204 Status
= NtQueryInformationProcess(hProcess
,
2209 if (NT_SUCCESS(Status
))
2211 /* Copy the count and return sucecss */
2212 *pdwHandleCount
= phc
;
2216 /* Handle error path */
2217 BaseSetLastNTError(Status
);
2226 IsWow64Process(IN HANDLE hProcess
,
2227 OUT PBOOL Wow64Process
)
2232 /* Query the kernel */
2233 Status
= NtQueryInformationProcess(hProcess
,
2234 ProcessWow64Information
,
2238 if (!NT_SUCCESS(Status
))
2240 /* Handle error path */
2241 BaseSetLastNTError(Status
);
2245 /* Enforce this is a BOOL, and return success */
2246 *Wow64Process
= (pbi
!= 0);
2255 GetCommandLineA(VOID
)
2257 return BaseAnsiCommandLine
.Buffer
;
2265 GetCommandLineW(VOID
)
2267 return BaseUnicodeCommandLine
.Buffer
;
2275 ReadProcessMemory(IN HANDLE hProcess
,
2276 IN LPCVOID lpBaseAddress
,
2279 OUT SIZE_T
* lpNumberOfBytesRead
)
2284 Status
= NtReadVirtualMemory(hProcess
,
2285 (PVOID
)lpBaseAddress
,
2290 /* In user-mode, this parameter is optional */
2291 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2292 if (!NT_SUCCESS(Status
))
2295 BaseSetLastNTError(Status
);
2299 /* Return success */
2308 WriteProcessMemory(IN HANDLE hProcess
,
2309 IN LPVOID lpBaseAddress
,
2310 IN LPCVOID lpBuffer
,
2312 OUT SIZE_T
*lpNumberOfBytesWritten
)
2320 /* Set parameters for protect call */
2322 Base
= lpBaseAddress
;
2324 /* Check the current status */
2325 Status
= NtProtectVirtualMemory(hProcess
,
2328 PAGE_EXECUTE_READWRITE
,
2330 if (NT_SUCCESS(Status
))
2332 /* Check if we are unprotecting */
2333 UnProtect
= OldValue
& (PAGE_READWRITE
|
2335 PAGE_EXECUTE_READWRITE
|
2336 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2339 /* Set the new protection */
2340 Status
= NtProtectVirtualMemory(hProcess
,
2346 /* Write the memory */
2347 Status
= NtWriteVirtualMemory(hProcess
,
2353 /* In Win32, the parameter is optional, so handle this case */
2354 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2356 if (!NT_SUCCESS(Status
))
2359 BaseSetLastNTError(Status
);
2363 /* Flush the ITLB */
2364 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2369 /* Check if we were read only */
2370 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2372 /* Restore protection and fail */
2373 NtProtectVirtualMemory(hProcess
,
2378 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2380 /* Note: This is what Windows returns and code depends on it */
2381 return STATUS_ACCESS_VIOLATION
;
2384 /* Otherwise, do the write */
2385 Status
= NtWriteVirtualMemory(hProcess
,
2391 /* In Win32, the parameter is optional, so handle this case */
2392 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2394 /* And restore the protection */
2395 NtProtectVirtualMemory(hProcess
,
2400 if (!NT_SUCCESS(Status
))
2403 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2405 /* Note: This is what Windows returns and code depends on it */
2406 return STATUS_ACCESS_VIOLATION
;
2409 /* Flush the ITLB */
2410 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2417 BaseSetLastNTError(Status
);
2427 ProcessIdToSessionId(IN DWORD dwProcessId
,
2428 OUT PDWORD pSessionId
)
2430 PROCESS_SESSION_INFORMATION SessionInformation
;
2431 OBJECT_ATTRIBUTES ObjectAttributes
;
2433 HANDLE ProcessHandle
;
2436 /* Do a quick check if the pointer is not writable */
2437 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2440 SetLastError(ERROR_INVALID_PARAMETER
);
2444 /* Open the process passed in by ID */
2445 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2446 ClientId
.UniqueThread
= 0;
2447 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2448 Status
= NtOpenProcess(&ProcessHandle
,
2449 PROCESS_QUERY_INFORMATION
,
2452 if (NT_SUCCESS(Status
))
2454 /* Query the session ID from the kernel */
2455 Status
= NtQueryInformationProcess(ProcessHandle
,
2456 ProcessSessionInformation
,
2457 &SessionInformation
,
2458 sizeof(SessionInformation
),
2461 /* Close the handle and check if we suceeded */
2462 NtClose(ProcessHandle
);
2463 if (NT_SUCCESS(Status
))
2465 /* Return the session ID */
2466 *pSessionId
= SessionInformation
.SessionId
;
2471 /* Set error code and fail */
2472 BaseSetLastNTError(Status
);
2481 CreateProcessInternalW(HANDLE hToken
,
2482 LPCWSTR lpApplicationName
,
2483 LPWSTR lpCommandLine
,
2484 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2485 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2486 BOOL bInheritHandles
,
2487 DWORD dwCreationFlags
,
2488 LPVOID lpEnvironment
,
2489 LPCWSTR lpCurrentDirectory
,
2490 LPSTARTUPINFOW lpStartupInfo
,
2491 LPPROCESS_INFORMATION lpProcessInformation
,
2495 PROCESS_PRIORITY_CLASS PriorityClass
;
2496 BOOLEAN FoundQuotes
= FALSE
;
2497 BOOLEAN QuotesNeeded
= FALSE
;
2498 BOOLEAN CmdLineIsAppName
= FALSE
;
2499 UNICODE_STRING ApplicationName
= { 0, 0, NULL
};
2500 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2501 POBJECT_ATTRIBUTES ObjectAttributes
;
2502 HANDLE hSection
= NULL
, hProcess
= NULL
, hThread
= NULL
, hDebug
= NULL
;
2503 SECTION_IMAGE_INFORMATION SectionImageInfo
;
2504 LPWSTR CurrentDirectory
= NULL
;
2505 LPWSTR CurrentDirectoryPart
;
2506 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2507 STARTUPINFOW StartupInfo
;
2509 LPWSTR BatchCommandLine
;
2510 ULONG CmdLineLength
;
2511 UNICODE_STRING CommandLineString
;
2513 LPWSTR QuotedCmdLine
= NULL
;
2515 LPWSTR NullBuffer
= NULL
;
2516 LPWSTR NameBuffer
= NULL
;
2520 BOOLEAN SearchDone
= FALSE
;
2521 BOOLEAN Escape
= FALSE
;
2523 PPEB OurPeb
= NtCurrentPeb();
2528 /* FIXME should process
2529 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2530 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2533 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2534 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2535 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
2538 /* Flags we don't handle yet */
2539 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
2541 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2543 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
2545 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2547 if (dwCreationFlags
& CREATE_FORCEDOS
)
2549 DPRINT1("CREATE_FORCEDOS not handled\n");
2552 /* Fail on this flag, it's only valid with the WithLogonW function */
2553 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
2555 DPRINT1("Invalid flag used\n");
2556 SetLastError(ERROR_INVALID_PARAMETER
);
2560 /* This combination is illegal (see MSDN) */
2561 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2562 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2564 DPRINT1("Invalid flag combo used\n");
2565 SetLastError(ERROR_INVALID_PARAMETER
);
2569 /* Another illegal combo */
2570 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
2571 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
2573 DPRINT1("Invalid flag combo used\n");
2574 SetLastError(ERROR_INVALID_PARAMETER
);
2578 if (lpCurrentDirectory
)
2580 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
2581 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
2583 SetLastError(ERROR_DIRECTORY
);
2589 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2590 * so we'll use our own local copy for that.
2592 StartupInfo
= *lpStartupInfo
;
2594 /* FIXME: Use default Separate/Shared VDM Flag */
2596 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2597 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
2599 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
2601 /* Remove the shared flag and add the separate flag. */
2602 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2603 CREATE_SEPARATE_WOW_VDM
;
2608 * According to some sites, ShellExecuteEx uses an undocumented flag to
2609 * send private handle data (such as HMONITOR or HICON). See:
2610 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2611 * standard handles anymore since we'd be overwriting this private data
2613 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2614 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2616 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2619 /* Start by zeroing out the fields */
2620 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
2622 /* Easy stuff first, convert the process priority class */
2623 PriorityClass
.Foreground
= FALSE
;
2624 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
2628 /* Search for escape sequences */
2629 ScanString
= lpCommandLine
;
2630 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2633 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\"')
2641 /* Get the application name and do all the proper formating necessary */
2643 /* See if we have an application name (oh please let us have one!) */
2644 if (!lpApplicationName
)
2646 /* The fun begins */
2647 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2649 MAX_PATH
* sizeof(WCHAR
));
2650 if (NameBuffer
== NULL
)
2652 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2656 /* This is all we have to work with :( */
2657 lpApplicationName
= lpCommandLine
;
2659 /* Initialize our friends at the beginning */
2660 NullBuffer
= (LPWSTR
)lpApplicationName
;
2661 ScanString
= (LPWSTR
)lpApplicationName
;
2663 /* We will start by looking for a quote */
2664 if (*ScanString
== L
'\"')
2666 /* That was quick */
2669 /* Advance past quote */
2671 lpApplicationName
= ScanString
;
2673 /* Find the closing quote */
2676 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
2679 NullBuffer
= ScanString
;
2686 NullBuffer
= ScanString
;
2691 /* No quotes, so we'll be looking for white space */
2693 /* Reset the pointer */
2694 lpApplicationName
= lpCommandLine
;
2696 /* Find whitespace of Tab */
2699 if (*ScanString
== ' ' || *ScanString
== '\t')
2702 NullBuffer
= ScanString
;
2708 NullBuffer
= ScanString
;
2712 /* Set the Null Buffer */
2713 SaveChar
= *NullBuffer
;
2714 *NullBuffer
= UNICODE_NULL
;
2716 /* Do a search for the file */
2717 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
2718 RetVal
= SearchPathW(NULL
,
2723 NULL
) * sizeof(WCHAR
);
2725 /* Did it find something? */
2728 /* Get file attributes */
2729 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
2730 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2732 /* Give it a length of 0 to fail, this was a directory. */
2738 RetVal
+= sizeof(WCHAR
);
2742 /* Now check if we have a file, and if the path size is OK */
2743 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
2748 /* We failed, try to get the Path Type */
2749 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
2750 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2752 /* If it's not relative, try to get the error */
2753 if (PathType
!= RtlPathTypeRelative
)
2755 /* This should fail, and give us a detailed LastError */
2756 hFile
= CreateFileW(lpApplicationName
,
2758 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2761 FILE_ATTRIBUTE_NORMAL
,
2764 /* Did it actually NOT fail? */
2765 if (hFile
!= INVALID_HANDLE_VALUE
)
2767 /* Fake the error */
2769 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2774 /* Immediately set the error */
2775 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2778 /* Did we already fail once? */
2781 SetLastError(Error
);
2785 /* Not yet, cache it */
2786 Error
= GetLastError();
2789 /* Put back the command line */
2790 *NullBuffer
= SaveChar
;
2791 lpApplicationName
= NameBuffer
;
2794 * If the search isn't done and we still have cmdline
2795 * then start over. Ex: c:\ha ha ha\haha.exe
2797 if (*ScanString
&& !SearchDone
)
2799 /* Move in the buffer */
2801 NullBuffer
= ScanString
;
2803 /* We will have to add a quote, since there is a space*/
2804 QuotesNeeded
= TRUE
;
2806 /* And we will also fake the fact we found one */
2813 /* We totally failed */
2817 /* Put back the command line */
2818 *NullBuffer
= SaveChar
;
2819 lpApplicationName
= NameBuffer
;
2820 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
2822 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
2824 /* We have an app name (good!) but no command line */
2825 CmdLineIsAppName
= TRUE
;
2826 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2829 /* At this point the name has been toyed with enough to be openable */
2830 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
2832 /* Check for failure */
2833 if (!NT_SUCCESS(Status
))
2835 /* Could be a non-PE File */
2838 /* Check if the Kernel tells us it's not even valid MZ */
2839 case STATUS_INVALID_IMAGE_NE_FORMAT
:
2840 case STATUS_INVALID_IMAGE_PROTECT
:
2841 case STATUS_INVALID_IMAGE_NOT_MZ
:
2844 /* If it's a DOS app, use VDM */
2845 if ((BasepCheckDosApp(&ApplicationName
)))
2847 DPRINT1("Launching VDM...\n");
2848 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2849 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2850 return CreateProcessW(L
"ntvdm.exe",
2851 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2852 lpProcessAttributes
,
2859 lpProcessInformation
);
2862 /* It's a batch file */
2863 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
2866 /* Make sure the extensions are correct */
2867 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
2869 SetLastError(ERROR_BAD_EXE_FORMAT
);
2873 /* Calculate the length of the command line */
2874 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
2876 /* If we found quotes, then add them into the length size */
2877 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
2878 CmdLineLength
*= sizeof(WCHAR
);
2880 /* Allocate space for the new command line */
2881 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2884 if (BatchCommandLine
== NULL
)
2886 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2891 wcscpy(BatchCommandLine
, CMD_STRING
);
2892 if (CmdLineIsAppName
|| FoundQuotes
)
2894 wcscat(BatchCommandLine
, L
"\"");
2896 wcscat(BatchCommandLine
, lpCommandLine
);
2897 if (CmdLineIsAppName
|| FoundQuotes
)
2899 wcscat(BatchCommandLine
, L
"\"");
2902 /* Create it as a Unicode String */
2903 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
2905 /* Set the command line to this */
2906 lpCommandLine
= CommandLineString
.Buffer
;
2907 lpApplicationName
= NULL
;
2910 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2911 ApplicationName
.Buffer
= NULL
;
2915 case STATUS_INVALID_IMAGE_WIN_16
:
2917 /* It's a Win16 Image, use VDM */
2918 DPRINT1("Launching VDM...\n");
2919 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2920 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2921 return CreateProcessW(L
"ntvdm.exe",
2922 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2923 lpProcessAttributes
,
2930 lpProcessInformation
);
2932 case STATUS_OBJECT_NAME_NOT_FOUND
:
2933 case STATUS_OBJECT_PATH_NOT_FOUND
:
2934 BaseSetLastNTError(Status
);
2938 /* Invalid Image Type */
2939 SetLastError(ERROR_BAD_EXE_FORMAT
);
2944 /* Use our desktop if we didn't get any */
2945 if (!StartupInfo
.lpDesktop
)
2947 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
2950 /* FIXME: Check if Application is allowed to run */
2952 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2954 /* Get some information about the executable */
2955 Status
= NtQuerySection(hSection
,
2956 SectionImageInformation
,
2958 sizeof(SectionImageInfo
),
2960 if(!NT_SUCCESS(Status
))
2962 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
2963 BaseSetLastNTError(Status
);
2967 /* Don't execute DLLs */
2968 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
2970 DPRINT1("Can't execute a DLL\n");
2971 SetLastError(ERROR_BAD_EXE_FORMAT
);
2975 /* FIXME: Check for Debugger */
2977 /* FIXME: Check if Machine Type and SubSys Version Match */
2979 /* We don't support POSIX or anything else for now */
2980 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= SectionImageInfo
.SubSystemType
&&
2981 IMAGE_SUBSYSTEM_WINDOWS_CUI
!= SectionImageInfo
.SubSystemType
)
2983 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
2985 * Despite the name of the error code suggests, it corresponds to the
2986 * well-known "The %1 application cannot be run in Win32 mode" message.
2988 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
2992 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
2994 /* Do not create a console for GUI applications */
2995 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
2996 dwCreationFlags
|= DETACHED_PROCESS
;
2999 /* Initialize the process object attributes */
3000 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3001 lpProcessAttributes
,
3004 /* Check if we're going to be debugged */
3005 if (dwCreationFlags
& DEBUG_PROCESS
)
3007 /* FIXME: Set process flag */
3010 /* Check if we're going to be debugged */
3011 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3013 /* Connect to DbgUi */
3014 Status
= DbgUiConnectToDbg();
3015 if (!NT_SUCCESS(Status
))
3017 DPRINT1("Failed to connect to DbgUI!\n");
3018 BaseSetLastNTError(Status
);
3022 /* Get the debug object */
3023 hDebug
= DbgUiGetThreadDebugObject();
3025 /* Check if only this process will be debugged */
3026 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3028 /* Set process flag */
3029 hDebug
= (HANDLE
)((ULONG_PTR
)hDebug
| 0x1);
3033 /* Create the Process */
3034 Status
= NtCreateProcess(&hProcess
,
3038 (BOOLEAN
)bInheritHandles
,
3042 if (!NT_SUCCESS(Status
))
3044 DPRINT1("Unable to create process, status 0x%x\n", Status
);
3045 BaseSetLastNTError(Status
);
3049 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
3052 Status
= NtSetInformationProcess(hProcess
,
3053 ProcessPriorityClass
,
3055 sizeof(PROCESS_PRIORITY_CLASS
));
3056 if(!NT_SUCCESS(Status
))
3058 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
3059 BaseSetLastNTError(Status
);
3064 /* Set Error Mode */
3065 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3067 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
3068 NtSetInformationProcess(hProcess
,
3069 ProcessDefaultHardErrorMode
,
3074 /* Convert the directory to a full path */
3075 if (lpCurrentDirectory
)
3077 /* Allocate a buffer */
3078 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
3080 (MAX_PATH
+ 1) * sizeof(WCHAR
));
3081 if (CurrentDirectory
== NULL
)
3083 DPRINT1("Cannot allocate memory for directory name\n");
3084 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3088 /* Get the length */
3089 if (GetFullPathNameW(lpCurrentDirectory
,
3092 &CurrentDirectoryPart
) > MAX_PATH
)
3094 DPRINT1("Directory name too long\n");
3095 SetLastError(ERROR_DIRECTORY
);
3100 /* Insert quotes if needed */
3101 if (QuotesNeeded
|| CmdLineIsAppName
)
3103 /* Allocate a buffer */
3104 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3106 (wcslen(lpCommandLine
) + 2 + 1) *
3108 if (QuotedCmdLine
== NULL
)
3110 DPRINT1("Cannot allocate memory for quoted command line\n");
3111 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3115 /* Copy the first quote */
3116 wcscpy(QuotedCmdLine
, L
"\"");
3118 /* Save a null char */
3121 SaveChar
= *NullBuffer
;
3122 *NullBuffer
= UNICODE_NULL
;
3125 /* Add the command line and the finishing quote */
3126 wcscat(QuotedCmdLine
, lpCommandLine
);
3127 wcscat(QuotedCmdLine
, L
"\"");
3129 /* Add the null char */
3132 *NullBuffer
= SaveChar
;
3133 wcscat(QuotedCmdLine
, NullBuffer
);
3136 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
3141 if (QuotedCmdLine
== NULL
)
3143 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3145 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
3146 if (QuotedCmdLine
== NULL
)
3148 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3151 wcscpy(QuotedCmdLine
, lpCommandLine
);
3154 ScanString
= QuotedCmdLine
;
3155 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
3158 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
3160 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
3165 /* Get the Process Information */
3166 Status
= NtQueryInformationProcess(hProcess
,
3167 ProcessBasicInformation
,
3169 sizeof(ProcessBasicInfo
),
3172 /* Convert the environment */
3173 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3175 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
3176 if (!lpEnvironment
) goto Cleanup
;
3179 /* Create Process Environment */
3180 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
3181 Ret
= BasePushProcessParameters(0,
3184 (LPWSTR
)lpApplicationName
,
3186 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
3187 QuotedCmdLine
: lpCommandLine
,
3195 if (!Ret
) goto Cleanup
;
3197 /* Cleanup Environment */
3198 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3200 RtlDestroyEnvironment(lpEnvironment
);
3203 /* Close the section */
3207 /* Duplicate the handles if needed */
3208 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
3209 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
3211 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
3213 /* Get the remote parameters */
3214 Status
= NtReadVirtualMemory(hProcess
,
3215 &RemotePeb
->ProcessParameters
,
3219 if (!NT_SUCCESS(Status
))
3221 DPRINT1("Failed to read memory\n");
3225 /* Duplicate and write the handles */
3226 BasepDuplicateAndWriteHandle(hProcess
,
3227 OurPeb
->ProcessParameters
->StandardInput
,
3228 &RemoteParameters
->StandardInput
);
3229 BasepDuplicateAndWriteHandle(hProcess
,
3230 OurPeb
->ProcessParameters
->StandardOutput
,
3231 &RemoteParameters
->StandardOutput
);
3232 BasepDuplicateAndWriteHandle(hProcess
,
3233 OurPeb
->ProcessParameters
->StandardError
,
3234 &RemoteParameters
->StandardError
);
3237 /* Create the first thread */
3238 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
3239 SectionImageInfo
.TransferAddress
);
3240 hThread
= BasepCreateFirstThread(hProcess
,
3247 if (hThread
== NULL
)
3249 DPRINT1("Could not create Initial Thread\n");
3250 /* FIXME - set last error code */
3254 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
3256 NtResumeThread(hThread
, &Dummy
);
3260 lpProcessInformation
->dwProcessId
= (DWORD
)ClientId
.UniqueProcess
;
3261 lpProcessInformation
->dwThreadId
= (DWORD
)ClientId
.UniqueThread
;
3262 lpProcessInformation
->hProcess
= hProcess
;
3263 lpProcessInformation
->hThread
= hThread
;
3264 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread
,
3265 ClientId
.UniqueThread
, ClientId
.UniqueProcess
, hProcess
);
3266 hProcess
= hThread
= NULL
;
3270 /* De-allocate heap strings */
3271 if (NameBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3272 if (ApplicationName
.Buffer
)
3273 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
3274 if (CurrentDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
3275 if (QuotedCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
3277 /* Kill any handles still alive */
3278 if (hSection
) NtClose(hSection
);
3281 /* We don't know any more details than this */
3282 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
3285 if (hProcess
) NtClose(hProcess
);
3287 /* Return Success */
3296 CreateProcessW(LPCWSTR lpApplicationName
,
3297 LPWSTR lpCommandLine
,
3298 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3299 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3300 BOOL bInheritHandles
,
3301 DWORD dwCreationFlags
,
3302 LPVOID lpEnvironment
,
3303 LPCWSTR lpCurrentDirectory
,
3304 LPSTARTUPINFOW lpStartupInfo
,
3305 LPPROCESS_INFORMATION lpProcessInformation
)
3307 /* Call the internal (but exported) version */
3308 return CreateProcessInternalW(0,
3311 lpProcessAttributes
,
3318 lpProcessInformation
,
3327 CreateProcessInternalA(HANDLE hToken
,
3328 LPCSTR lpApplicationName
,
3329 LPSTR lpCommandLine
,
3330 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3331 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3332 BOOL bInheritHandles
,
3333 DWORD dwCreationFlags
,
3334 LPVOID lpEnvironment
,
3335 LPCSTR lpCurrentDirectory
,
3336 LPSTARTUPINFOA lpStartupInfo
,
3337 LPPROCESS_INFORMATION lpProcessInformation
,
3340 PUNICODE_STRING CommandLine
= NULL
;
3341 UNICODE_STRING DummyString
;
3342 UNICODE_STRING LiveCommandLine
;
3343 UNICODE_STRING ApplicationName
;
3344 UNICODE_STRING CurrentDirectory
;
3346 STARTUPINFOW StartupInfo
;
3348 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
3349 "lpStartupInfo %x, lpProcessInformation %x\n",
3350 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
3351 lpStartupInfo
, lpProcessInformation
);
3353 /* Copy Startup Info */
3354 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
3356 /* Initialize all strings to nothing */
3357 LiveCommandLine
.Buffer
= NULL
;
3358 DummyString
.Buffer
= NULL
;
3359 ApplicationName
.Buffer
= NULL
;
3360 CurrentDirectory
.Buffer
= NULL
;
3361 StartupInfo
.lpDesktop
= NULL
;
3362 StartupInfo
.lpReserved
= NULL
;
3363 StartupInfo
.lpTitle
= NULL
;
3365 /* Convert the Command line */
3368 /* If it's too long, then we'll have a problem */
3369 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
3370 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
3372 /* Cache it in the TEB */
3373 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
3377 /* Use a dynamic version */
3378 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
3384 /* The logic below will use CommandLine, so we must make it valid */
3385 CommandLine
= &DummyString
;
3388 /* Convert the Name and Directory */
3389 if (lpApplicationName
)
3391 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
3394 if (lpCurrentDirectory
)
3396 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
3397 lpCurrentDirectory
);
3400 /* Now convert Startup Strings */
3401 if (lpStartupInfo
->lpReserved
)
3403 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
3404 &StartupInfo
.lpReserved
);
3406 if (lpStartupInfo
->lpDesktop
)
3408 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
3409 &StartupInfo
.lpDesktop
);
3411 if (lpStartupInfo
->lpTitle
)
3413 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
3414 &StartupInfo
.lpTitle
);
3417 /* Call the Unicode function */
3418 bRetVal
= CreateProcessInternalW(hToken
,
3419 ApplicationName
.Buffer
,
3420 LiveCommandLine
.Buffer
?
3421 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
3422 lpProcessAttributes
,
3427 CurrentDirectory
.Buffer
,
3429 lpProcessInformation
,
3433 RtlFreeUnicodeString(&ApplicationName
);
3434 RtlFreeUnicodeString(&LiveCommandLine
);
3435 RtlFreeUnicodeString(&CurrentDirectory
);
3436 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
3437 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
3438 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
3440 /* Return what Unicode did */
3445 * FUNCTION: The CreateProcess function creates a new process and its
3446 * primary thread. The new process executes the specified executable file
3449 * lpApplicationName = Pointer to name of executable module
3450 * lpCommandLine = Pointer to command line string
3451 * lpProcessAttributes = Process security attributes
3452 * lpThreadAttributes = Thread security attributes
3453 * bInheritHandles = Handle inheritance flag
3454 * dwCreationFlags = Creation flags
3455 * lpEnvironment = Pointer to new environment block
3456 * lpCurrentDirectory = Pointer to current directory name
3457 * lpStartupInfo = Pointer to startup info
3458 * lpProcessInformation = Pointer to process information
3464 CreateProcessA(LPCSTR lpApplicationName
,
3465 LPSTR lpCommandLine
,
3466 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3467 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3468 BOOL bInheritHandles
,
3469 DWORD dwCreationFlags
,
3470 LPVOID lpEnvironment
,
3471 LPCSTR lpCurrentDirectory
,
3472 LPSTARTUPINFOA lpStartupInfo
,
3473 LPPROCESS_INFORMATION lpProcessInformation
)
3475 /* Call the internal (but exported) version */
3476 return CreateProcessInternalA(0,
3479 lpProcessAttributes
,
3486 lpProcessInformation
,
3495 WinExec(LPCSTR lpCmdLine
,
3498 STARTUPINFOA StartupInfo
;
3499 PROCESS_INFORMATION ProcessInformation
;
3502 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
3503 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
3504 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
3505 StartupInfo
.dwFlags
= 0;
3507 if (!CreateProcessA(NULL
,
3516 &ProcessInformation
))
3518 dosErr
= GetLastError();
3519 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
3522 if (NULL
!= UserWaitForInputIdleRoutine
)
3524 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
3528 NtClose(ProcessInformation
.hProcess
);
3529 NtClose(ProcessInformation
.hThread
);
3531 return 33; /* Something bigger than 31 means success. */