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 "
52 #define NTVDM_STRING L"\\ntvdm.exe"
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
);
189 BasepCheckDosApp(IN PUNICODE_STRING ApplicationName
)
193 /* Get the extension from the file name */
194 Extension
= &ApplicationName
->Buffer
[ApplicationName
->Length
/
197 /* Check if the extension is .COM */
198 if (_wcsnicmp(Extension
, L
".com", 4) == 0) return TRUE
;
204 BasepIsProcessAllowed(IN PCHAR ApplicationName
)
209 HMODULE TrustLibrary
;
210 PBASEP_APPCERT_ENTRY Entry
;
212 PLIST_ENTRY NextEntry
;
214 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
215 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
217 /* Try to initialize the certification subsystem */
218 while (!g_AppCertInitialized
)
221 Status
= STATUS_SUCCESS
;
224 /* Acquire the lock while initializing and see if we lost a race */
225 RtlEnterCriticalSection(&gcsAppCert
);
226 if (g_AppCertInitialized
) break;
228 /* On embedded, there is a special DLL */
229 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
231 /* Allocate a buffer for the name */
232 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
234 MAX_PATH
* sizeof(WCHAR
) +
235 sizeof(UNICODE_NULL
));
238 /* Fail if no memory */
239 Status
= STATUS_NO_MEMORY
;
243 /* Now get the system32 directory in our buffer, make sure it fits */
244 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
245 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
247 /* Add a slash if needed, and add the embedded cert DLL name */
248 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
249 RtlCopyMemory(&Buffer
[Length
],
251 sizeof(L
"EmbdTrst.DLL"));
254 TrustLibrary
= LoadLibraryW(Buffer
);
257 /* And extract the special function out of it */
258 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
259 "ImageOkToRunOnEmbeddedNT");
263 /* If we didn't get this far, set a failure code */
264 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
269 /* Other systems have a registry entry for this */
270 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
271 if (NT_SUCCESS(Status
))
273 /* Close it, we'll query it through Rtl */
276 /* Do the query, which will call a special callback */
277 Status
= RtlQueryRegistryValues(2,
282 if (Status
== 0xC0000034) Status
= STATUS_SUCCESS
;
286 /* Free any buffer if we had one */
287 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
289 /* Check for errors, or a missing embedded/custom certification DLL */
290 if (!NT_SUCCESS(Status
) ||
291 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
293 /* The subsystem is not active on this machine, so give up */
294 g_HaveAppCerts
= FALSE
;
295 g_AppCertStatus
= Status
;
299 /* We have certification DLLs active, remember this */
300 g_HaveAppCerts
= TRUE
;
303 /* We are done the initialization phase, release the lock */
304 g_AppCertInitialized
= TRUE
;
305 RtlLeaveCriticalSection(&gcsAppCert
);
308 /* If there's no certification DLLs present, return the failure code */
309 if (!g_HaveAppCerts
) return g_AppCertStatus
;
311 /* Otherwise, assume success and make sure we have *something* */
312 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
313 Status
= STATUS_SUCCESS
;
315 /* If the something is an embedded certification DLL, call it and return */
316 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
318 /* Otherwise we have custom certification DLLs, parse them */
319 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 and check if it failed */
328 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
329 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
332 NextEntry
= NextEntry
->Flink
;
335 /* Now loop them again */
336 NextEntry
= BasepAppCertDllsList
.Flink
;
337 while (NextEntry
!= &BasepAppCertDllsList
)
339 /* Make sure the entry has a callback */
340 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
341 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
343 /* Call it, this time with the flag from the loop above */
344 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
347 /* All done, return the status */
353 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
354 IN HANDLE ProcessHandle
,
355 IN HANDLE ThreadHandle
)
358 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
360 /* Enter the application certification lock */
361 RtlEnterCriticalSection(&gcsAppCert
);
363 /* Check if we already know the function */
364 if (g_SaferReplaceProcessThreadTokens
)
367 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
375 /* Check if the app certification DLL isn't loaded */
376 if (!(gSaferHandle
) ||
377 (gSaferHandle
== (HMODULE
)-1) ||
378 (gSaferHandle
== (HMODULE
)-2))
380 /* Then we can't call the function */
381 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
385 /* We have the DLL, find the address of the Safer function */
386 Status
= LdrGetProcedureAddress(gSaferHandle
,
387 &SaferiReplaceProcessThreadTokens
,
389 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
390 if (NT_SUCCESS(Status
))
392 /* Found it, now call it */
393 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
401 /* We couldn't find it, so this must be an unsupported DLL */
402 LdrUnloadDll(gSaferHandle
);
404 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
409 /* Release the lock and return the result */
410 RtlLeaveCriticalSection(&gcsAppCert
);
416 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
421 ASSERT(Handles
!= NULL
);
422 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
424 /* Close the file handle */
427 Status
= NtClose(Handles
->File
);
428 ASSERT(NT_SUCCESS(Status
));
431 /* Close the section handle */
432 if (Handles
->Section
)
434 Status
= NtClose(Handles
->Section
);
435 ASSERT(NT_SUCCESS(Status
));
438 /* Unmap the section view */
439 if (Handles
->ViewBase
.QuadPart
)
441 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
442 (PVOID
)Handles
->ViewBase
.LowPart
);
443 ASSERT(NT_SUCCESS(Status
));
448 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
450 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
451 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
452 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
454 if (RealFilter
!= NULL
)
458 ExceptionDisposition
= RealFilter(ExceptionInfo
);
460 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
465 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
466 RealFilter
!= UnhandledExceptionFilter
)
468 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
471 return ExceptionDisposition
;
476 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
478 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
482 /* Set our Start Address */
483 NtSetInformationThread(NtCurrentThread(),
484 ThreadQuerySetWin32StartAddress
,
486 sizeof(PPROCESS_START_ROUTINE
));
488 /* Call the Start Routine */
489 ExitThread(lpStartAddress());
491 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
493 /* Get the Exit code from the SEH Handler */
494 if (!BaseRunningInServerProcess
)
496 /* Kill the whole process, usually */
497 ExitProcess(_SEH2_GetExceptionCode());
501 /* If running inside CSRSS, kill just this thread */
502 ExitThread(_SEH2_GetExceptionCode());
510 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
511 IN PCLIENT_ID ClientId
)
514 BASE_API_MESSAGE ApiMessage
;
515 PBASE_CREATE_THREAD CreateThreadRequest
= &ApiMessage
.Data
.CreateThreadRequest
;
517 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
518 ClientId
->UniqueThread
, ThreadHandle
);
520 /* Fill out the request */
521 CreateThreadRequest
->ClientId
= *ClientId
;
522 CreateThreadRequest
->ThreadHandle
= ThreadHandle
;
525 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
527 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
528 sizeof(BASE_CREATE_THREAD
));
529 if (!NT_SUCCESS(Status
))
531 DPRINT1("Failed to tell CSRSS about new thread: %lx\n", Status
);
536 return STATUS_SUCCESS
;
540 * Creates the first Thread in a Proces
544 BasepCreateFirstThread(HANDLE ProcessHandle
,
545 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
546 PSECTION_IMAGE_INFORMATION SectionImageInfo
,
548 DWORD dwCreationFlags
)
551 OBJECT_ATTRIBUTES LocalObjectAttributes
;
552 POBJECT_ATTRIBUTES ObjectAttributes
;
554 INITIAL_TEB InitialTeb
;
556 BASE_API_MESSAGE ApiMessage
;
557 PBASE_CREATE_PROCESS CreateProcessRequest
= &ApiMessage
.Data
.CreateProcessRequest
;
559 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
561 /* Create the Thread's Stack */
562 BaseCreateStack(ProcessHandle
,
563 SectionImageInfo
->MaximumStackSize
,
564 SectionImageInfo
->CommittedStackSize
,
567 /* Create the Thread's Context */
568 BaseInitializeContext(&Context
,
570 SectionImageInfo
->TransferAddress
,
571 InitialTeb
.StackBase
,
574 /* Convert the thread attributes */
575 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
579 /* Create the Kernel Thread Object */
580 Status
= NtCreateThread(&hThread
,
588 if (!NT_SUCCESS(Status
))
593 /* Fill out the request to notify CSRSS */
594 CreateProcessRequest
->ClientId
= *ClientId
;
595 CreateProcessRequest
->ProcessHandle
= ProcessHandle
;
596 CreateProcessRequest
->ThreadHandle
= hThread
;
597 CreateProcessRequest
->CreationFlags
= dwCreationFlags
;
600 * For GUI applications we turn on the 2nd bit. This also allows
601 * us to know whether or not this is a GUI or a TUI application.
603 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
->SubSystemType
)
605 CreateProcessRequest
->ProcessHandle
= (HANDLE
)
606 ((ULONG_PTR
)CreateProcessRequest
->ProcessHandle
| 2);
610 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
612 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateProcess
),
613 sizeof(BASE_CREATE_PROCESS
));
614 if (!NT_SUCCESS(Status
))
616 DPRINT1("Failed to tell CSRSS about new process: %lx\n", Status
);
625 * Converts ANSI to Unicode Environment
629 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
630 IN PVOID lpEnvironment
)
634 UNICODE_STRING UnicodeEnv
;
637 DPRINT("BasepConvertUnicodeEnvironment\n");
639 /* Scan the environment to calculate its Unicode size */
640 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
643 pcScan
+= strlen(pcScan
) + 1;
646 /* Create our ANSI String */
647 if (pcScan
== (PCHAR
)lpEnvironment
)
649 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
654 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
656 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
658 /* Allocate memory for the Unicode Environment */
659 UnicodeEnv
.Buffer
= NULL
;
660 *EnvSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
661 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
662 (PVOID
)&UnicodeEnv
.Buffer
,
668 if (!NT_SUCCESS(Status
))
670 SetLastError(Status
);
675 /* Use the allocated size */
676 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
679 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
680 return UnicodeEnv
.Buffer
;
684 * Converts a Win32 Priority Class to NT
688 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
692 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
694 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
696 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
698 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
700 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
702 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
704 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
706 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
708 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
710 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
712 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
714 /* Check for Privilege First */
715 if (BasepIsRealtimeAllowed(TRUE
))
717 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
721 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
726 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
733 * Duplicates a standard handle and writes it where requested.
737 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
738 IN HANDLE StandardHandle
,
742 HANDLE DuplicatedHandle
;
745 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
746 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
748 /* Don't touch Console Handles */
749 if (IsConsoleHandle(StandardHandle
)) return;
751 /* Duplicate the handle */
752 Status
= NtDuplicateObject(NtCurrentProcess(),
756 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
759 if (NT_SUCCESS(Status
))
762 NtWriteVirtualMemory(ProcessHandle
,
772 BasePushProcessParameters(IN ULONG ParameterFlags
,
773 IN HANDLE ProcessHandle
,
775 IN LPCWSTR ApplicationPathName
,
776 IN LPWSTR lpCurrentDirectory
,
777 IN LPWSTR lpCommandLine
,
778 IN LPVOID lpEnvironment
,
779 IN LPSTARTUPINFOW StartupInfo
,
780 IN DWORD CreationFlags
,
781 IN BOOL InheritHandles
,
782 IN ULONG ImageSubsystem
,
783 IN PVOID AppCompatData
,
784 IN ULONG AppCompatDataSize
)
786 WCHAR FullPath
[MAX_PATH
+ 5];
787 PWCHAR Remaining
, DllPathString
, ScanChar
;
788 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
789 PVOID RemoteAppCompatData
;
790 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
791 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
795 BOOLEAN HavePebLock
= FALSE
, Result
;
796 PPEB Peb
= NtCurrentPeb();
798 /* Get the full path name */
799 Size
= GetFullPathNameW(ApplicationPathName
,
803 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
805 /* Get the DLL Path */
806 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
810 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
814 /* Initialize Strings */
815 RtlInitUnicodeString(&DllPath
, DllPathString
);
816 RtlInitUnicodeString(&ImageName
, FullPath
);
820 /* Couldn't get the path name. Just take the original path */
821 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
826 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
830 /* Initialize Strings */
831 RtlInitUnicodeString(&DllPath
, DllPathString
);
832 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
835 /* Initialize Strings */
836 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
837 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
839 /* Initialize more Strings from the Startup Info */
840 if (StartupInfo
->lpDesktop
)
842 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
846 RtlInitUnicodeString(&Desktop
, L
"");
848 if (StartupInfo
->lpReserved
)
850 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
854 RtlInitUnicodeString(&Shell
, L
"");
856 if (StartupInfo
->lpTitle
)
858 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
862 RtlInitUnicodeString(&Title
, ApplicationPathName
);
865 /* This one is special because the length can differ */
866 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
867 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
869 /* Enforce no app compat data if the pointer was NULL */
870 if (!AppCompatData
) AppCompatDataSize
= 0;
872 /* Create the Parameter Block */
873 ProcessParameters
= NULL
;
874 Status
= RtlCreateProcessParameters(&ProcessParameters
,
878 &CurrentDirectory
: NULL
,
885 if (!NT_SUCCESS(Status
)) goto FailPath
;
887 /* Clear the current directory handle if not inheriting */
888 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
890 /* Check if the user passed in an environment */
893 /* We should've made it part of the parameters block, enforce this */
894 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
895 lpEnvironment
= ProcessParameters
->Environment
;
899 /* The user did not, so use the one from the current PEB */
902 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
905 /* Save pointer and start lookup */
906 ScanChar
= lpEnvironment
;
909 /* Find the environment size */
910 while ((ScanChar
[0]) || (ScanChar
[1])) ++ScanChar
;
911 ScanChar
+= (2 * sizeof(UNICODE_NULL
));
912 EnviroSize
= (ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
;
914 /* Allocate and Initialize new Environment Block */
916 ProcessParameters
->Environment
= NULL
;
917 Status
= NtAllocateVirtualMemory(ProcessHandle
,
918 (PVOID
*)&ProcessParameters
->Environment
,
923 if (!NT_SUCCESS(Status
)) goto FailPath
;
925 /* Write the Environment Block */
926 Status
= NtWriteVirtualMemory(ProcessHandle
,
927 ProcessParameters
->Environment
,
932 /* No longer need the PEB lock anymore */
940 /* Check if the write failed */
941 if (!NT_SUCCESS(Status
)) goto FailPath
;
944 /* Write new parameters */
945 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
946 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
947 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
948 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
949 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
950 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
951 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
952 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
953 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
955 /* Write the handles only if we have to */
956 if (StartupInfo
->dwFlags
&
957 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
959 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
960 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
961 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
964 /* Use Special Flags for BasepInitConsole in Kernel32 */
965 if (CreationFlags
& DETACHED_PROCESS
)
967 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
969 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
971 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
973 else if (CreationFlags
& CREATE_NO_WINDOW
)
975 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
979 /* Inherit our Console Handle */
980 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
982 /* Make sure that the shell isn't trampling on our handles first */
983 if (!(StartupInfo
->dwFlags
&
984 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
986 /* Copy the handle if we are inheriting or if it's a console handle */
987 if ((InheritHandles
) ||
988 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
990 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
992 if ((InheritHandles
) ||
993 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
995 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
997 if ((InheritHandles
) ||
998 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
1000 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
1005 /* Also set the Console Flag */
1006 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
1007 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
1009 ProcessParameters
->ConsoleFlags
= 1;
1012 /* See if the first 1MB should be reserved */
1013 if (ParameterFlags
& 1)
1015 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB
;
1018 /* See if the first 16MB should be reserved */
1019 if (ParameterFlags
& 2)
1021 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB
;
1024 /* Allocate memory for the parameter block */
1025 Size
= ProcessParameters
->Length
;
1026 RemoteParameters
= NULL
;
1027 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1028 (PVOID
*)&RemoteParameters
,
1033 if (!NT_SUCCESS(Status
)) goto FailPath
;
1035 /* Set the allocated size */
1036 ProcessParameters
->MaximumLength
= Size
;
1038 /* Handle some Parameter Flags */
1039 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
1040 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
1041 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
1042 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
1043 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
1044 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
1045 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
1046 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
1048 /* Write the Parameter Block */
1049 Status
= NtWriteVirtualMemory(ProcessHandle
,
1052 ProcessParameters
->Length
,
1054 if (!NT_SUCCESS(Status
)) goto FailPath
;
1056 /* Write the PEB Pointer */
1057 Status
= NtWriteVirtualMemory(ProcessHandle
,
1058 &RemotePeb
->ProcessParameters
,
1062 if (!NT_SUCCESS(Status
)) goto FailPath
;
1064 /* Check if there's any app compat data to write */
1065 RemoteAppCompatData
= NULL
;
1068 /* Allocate some space for the application compatibility data */
1069 Size
= AppCompatDataSize
;
1070 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1071 &RemoteAppCompatData
,
1076 if (!NT_SUCCESS(Status
)) goto FailPath
;
1078 /* Write the application compatibility data */
1079 Status
= NtWriteVirtualMemory(ProcessHandle
,
1080 RemoteAppCompatData
,
1084 if (!NT_SUCCESS(Status
)) goto FailPath
;
1087 /* Write the PEB Pointer to the app compat data (might be NULL) */
1088 Status
= NtWriteVirtualMemory(ProcessHandle
,
1089 &RemotePeb
->pShimData
,
1090 &RemoteAppCompatData
,
1093 if (!NT_SUCCESS(Status
)) goto FailPath
;
1095 /* Now write Peb->ImageSubSystem */
1098 NtWriteVirtualMemory(ProcessHandle
,
1099 &RemotePeb
->ImageSubsystem
,
1101 sizeof(ImageSubsystem
),
1110 if (HavePebLock
) RtlReleasePebLock();
1111 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
1112 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
1115 DPRINT1("Failure to create proecss parameters: %lx\n", Status
);
1116 BaseSetLastNTError(Status
);
1123 InitCommandLines(VOID
)
1127 /* Read the UNICODE_STRING from the PEB */
1128 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
1130 /* Convert to ANSI_STRING for the *A callers */
1131 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
1132 &BaseUnicodeCommandLine
,
1134 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
1137 /* PUBLIC FUNCTIONS ***********************************************************/
1144 GetProcessAffinityMask(IN HANDLE hProcess
,
1145 OUT PDWORD_PTR lpProcessAffinityMask
,
1146 OUT PDWORD_PTR lpSystemAffinityMask
)
1148 PROCESS_BASIC_INFORMATION ProcessInfo
;
1151 /* Query information on the process from the kernel */
1152 Status
= NtQueryInformationProcess(hProcess
,
1153 ProcessBasicInformation
,
1154 (PVOID
)&ProcessInfo
,
1155 sizeof(PROCESS_BASIC_INFORMATION
),
1157 if (!NT_SUCCESS(Status
))
1160 BaseSetLastNTError(Status
);
1164 /* Copy the affinity mask, and get the system one from our shared data */
1165 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
1166 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
1175 SetProcessAffinityMask(IN HANDLE hProcess
,
1176 IN DWORD_PTR dwProcessAffinityMask
)
1180 /* Directly set the affinity mask */
1181 Status
= NtSetInformationProcess(hProcess
,
1182 ProcessAffinityMask
,
1183 (PVOID
)&dwProcessAffinityMask
,
1185 if (!NT_SUCCESS(Status
))
1187 /* Handle failure */
1188 BaseSetLastNTError(Status
);
1192 /* Everything was ok */
1201 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
1202 OUT LPDWORD lpdwFlags
)
1205 BASE_API_MESSAGE ApiMessage
;
1206 PBASE_GET_PROCESS_SHUTDOWN_PARAMS GetShutdownParametersRequest
= &ApiMessage
.Data
.GetShutdownParametersRequest
;
1208 /* Ask CSRSS for shutdown information */
1209 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1211 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
1212 sizeof(BASE_GET_PROCESS_SHUTDOWN_PARAMS
));
1213 if (!NT_SUCCESS(Status
))
1215 /* Return the failure from CSRSS */
1216 BaseSetLastNTError(Status
);
1220 /* Get the data back */
1221 *lpdwLevel
= GetShutdownParametersRequest
->Level
;
1222 *lpdwFlags
= GetShutdownParametersRequest
->Flags
;
1231 SetProcessShutdownParameters(IN DWORD dwLevel
,
1235 BASE_API_MESSAGE ApiMessage
;
1236 PBASE_SET_PROCESS_SHUTDOWN_PARAMS SetShutdownParametersRequest
= &ApiMessage
.Data
.SetShutdownParametersRequest
;
1238 /* Write the data into the CSRSS request and send it */
1239 SetShutdownParametersRequest
->Level
= dwLevel
;
1240 SetShutdownParametersRequest
->Flags
= dwFlags
;
1241 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1243 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1244 sizeof(BASE_SET_PROCESS_SHUTDOWN_PARAMS
));
1245 if (!NT_SUCCESS(Status
))
1247 /* Return the failure from CSRSS */
1248 BaseSetLastNTError(Status
);
1261 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1262 OUT PSIZE_T lpMinimumWorkingSetSize
,
1263 OUT PSIZE_T lpMaximumWorkingSetSize
,
1266 QUOTA_LIMITS_EX QuotaLimits
;
1269 /* Query the kernel about this */
1270 Status
= NtQueryInformationProcess(hProcess
,
1273 sizeof(QUOTA_LIMITS_EX
),
1275 if (!NT_SUCCESS(Status
))
1278 BaseSetLastNTError(Status
);
1282 /* Copy the quota information out */
1283 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1284 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1285 *Flags
= QuotaLimits
.Flags
;
1294 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1295 OUT PSIZE_T lpMinimumWorkingSetSize
,
1296 OUT PSIZE_T lpMaximumWorkingSetSize
)
1299 return GetProcessWorkingSetSizeEx(hProcess
,
1300 lpMinimumWorkingSetSize
,
1301 lpMaximumWorkingSetSize
,
1310 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1311 IN SIZE_T dwMinimumWorkingSetSize
,
1312 IN SIZE_T dwMaximumWorkingSetSize
,
1315 QUOTA_LIMITS_EX QuotaLimits
;
1316 NTSTATUS Status
, ReturnStatus
;
1319 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1321 /* Zero out the input structure */
1322 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1324 /* Check if the caller sent any limits */
1325 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1327 /* Write the quota information */
1328 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1329 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1330 QuotaLimits
.Flags
= Flags
;
1332 /* Acquire the required privilege */
1333 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1335 /* Request the new quotas */
1336 ReturnStatus
= NtSetInformationProcess(hProcess
,
1339 sizeof(QuotaLimits
));
1340 Result
= NT_SUCCESS(ReturnStatus
);
1341 if (NT_SUCCESS(Status
))
1343 /* Release the privilege and set succes code */
1344 ASSERT(State
!= NULL
);
1345 RtlReleasePrivilege(State
);
1351 /* No limits, fail the call */
1352 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1356 /* Return result code, set error code if this was a failure */
1357 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1366 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1367 IN SIZE_T dwMinimumWorkingSetSize
,
1368 IN SIZE_T dwMaximumWorkingSetSize
)
1370 /* Call the newer API */
1371 return SetProcessWorkingSetSizeEx(hProcess
,
1372 dwMinimumWorkingSetSize
,
1373 dwMaximumWorkingSetSize
,
1382 GetProcessTimes(IN HANDLE hProcess
,
1383 IN LPFILETIME lpCreationTime
,
1384 IN LPFILETIME lpExitTime
,
1385 IN LPFILETIME lpKernelTime
,
1386 IN LPFILETIME lpUserTime
)
1388 KERNEL_USER_TIMES Kut
;
1391 /* Query the times */
1392 Status
= NtQueryInformationProcess(hProcess
,
1397 if (!NT_SUCCESS(Status
))
1399 /* Handle failure */
1400 BaseSetLastNTError(Status
);
1404 /* Copy all the times and return success */
1405 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1406 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1407 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1408 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1409 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1410 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1411 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1412 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1421 GetCurrentProcess(VOID
)
1423 return (HANDLE
)NtCurrentProcess();
1431 GetCurrentThread(VOID
)
1433 return (HANDLE
)NtCurrentThread();
1441 GetCurrentProcessId(VOID
)
1443 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1451 GetExitCodeProcess(IN HANDLE hProcess
,
1452 IN LPDWORD lpExitCode
)
1454 PROCESS_BASIC_INFORMATION ProcessBasic
;
1457 /* Ask the kernel */
1458 Status
= NtQueryInformationProcess(hProcess
,
1459 ProcessBasicInformation
,
1461 sizeof(PROCESS_BASIC_INFORMATION
),
1463 if (!NT_SUCCESS(Status
))
1465 /* We failed, was this because this is a VDM process? */
1466 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1468 /* Not a VDM process, fail the call */
1469 BaseSetLastNTError(Status
);
1473 /* Succes case, return the exit code */
1474 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1483 GetProcessId(IN HANDLE Process
)
1485 PROCESS_BASIC_INFORMATION ProcessBasic
;
1488 /* Query the kernel */
1489 Status
= NtQueryInformationProcess(Process
,
1490 ProcessBasicInformation
,
1492 sizeof(PROCESS_BASIC_INFORMATION
),
1494 if (!NT_SUCCESS(Status
))
1496 /* Handle failure */
1497 BaseSetLastNTError(Status
);
1501 /* Return the PID */
1502 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1510 OpenProcess(IN DWORD dwDesiredAccess
,
1511 IN BOOL bInheritHandle
,
1512 IN DWORD dwProcessId
)
1515 HANDLE ProcessHandle
;
1516 OBJECT_ATTRIBUTES ObjectAttributes
;
1519 /* Setup the input client ID structure */
1520 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1521 ClientId
.UniqueThread
= 0;
1523 /* This is needed just to define the inheritance flags */
1524 InitializeObjectAttributes(&ObjectAttributes
,
1526 (bInheritHandle
? OBJ_INHERIT
: 0),
1530 /* Now try to open the process */
1531 Status
= NtOpenProcess(&ProcessHandle
,
1535 if (!NT_SUCCESS(Status
))
1537 /* Handle failure */
1538 BaseSetLastNTError(Status
);
1542 /* Otherwise return a handle to the process */
1543 return ProcessHandle
;
1551 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1553 /* Write the global function pointer */
1554 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1562 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1564 PRTL_USER_PROCESS_PARAMETERS Params
;
1566 /* Get the process parameters */
1567 Params
= NtCurrentPeb()->ProcessParameters
;
1569 /* Copy the data out of there */
1570 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1571 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1572 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1573 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1574 lpStartupInfo
->dwX
= Params
->StartingX
;
1575 lpStartupInfo
->dwY
= Params
->StartingY
;
1576 lpStartupInfo
->dwXSize
= Params
->CountX
;
1577 lpStartupInfo
->dwYSize
= Params
->CountY
;
1578 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1579 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1580 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1581 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1582 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1583 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1584 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1586 /* Check if the standard handles are being used for other features */
1587 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1589 STARTF_SHELLPRIVATE
))
1591 /* These are, so copy the standard handles too */
1592 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1593 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1594 lpStartupInfo
->hStdError
= Params
->StandardError
;
1603 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1605 PRTL_USER_PROCESS_PARAMETERS Params
;
1606 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1607 LPSTARTUPINFOA StartupInfo
;
1610 /* Get the cached information as well as the PEB parameters */
1611 StartupInfo
= BaseAnsiStartupInfo
;
1612 Params
= NtCurrentPeb()->ProcessParameters
;
1614 /* Check if this is the first time we have to get the cached version */
1615 while (!StartupInfo
)
1617 /* Create new ANSI startup info */
1618 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1620 sizeof(*StartupInfo
));
1623 /* Zero out string pointers in case we fail to create them */
1624 StartupInfo
->lpReserved
= 0;
1625 StartupInfo
->lpDesktop
= 0;
1626 StartupInfo
->lpTitle
= 0;
1629 StartupInfo
->cb
= sizeof(*StartupInfo
);
1631 /* Copy what's already stored in the PEB */
1632 StartupInfo
->dwX
= Params
->StartingX
;
1633 StartupInfo
->dwY
= Params
->StartingY
;
1634 StartupInfo
->dwXSize
= Params
->CountX
;
1635 StartupInfo
->dwYSize
= Params
->CountY
;
1636 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1637 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1638 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1639 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1640 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1641 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1642 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1643 StartupInfo
->hStdInput
= Params
->StandardInput
;
1644 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1645 StartupInfo
->hStdError
= Params
->StandardError
;
1647 /* Copy shell info string */
1648 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1651 if (NT_SUCCESS(Status
))
1654 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1656 /* Copy desktop info string */
1657 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1658 &Params
->DesktopInfo
,
1660 if (NT_SUCCESS(Status
))
1663 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1665 /* Copy window title string */
1666 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1667 &Params
->WindowTitle
,
1669 if (NT_SUCCESS(Status
))
1672 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1674 /* We finished with the ANSI version, try to cache it */
1675 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo
,
1679 /* We were the first thread through, use the data */
1683 /* Someone beat us to it, use their data instead */
1684 StartupInfo
= BaseAnsiStartupInfo
;
1685 Status
= STATUS_SUCCESS
;
1687 /* We're going to free our own stuff, but not raise */
1688 RtlFreeAnsiString(&TitleString
);
1690 RtlFreeAnsiString(&DesktopString
);
1692 RtlFreeAnsiString(&ShellString
);
1694 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1698 /* No memory, fail */
1699 Status
= STATUS_NO_MEMORY
;
1702 /* Raise an error unless we got here due to the race condition */
1703 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1706 /* Now copy from the cached ANSI version */
1707 lpStartupInfo
->cb
= StartupInfo
->cb
;
1708 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1709 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1710 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1711 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1712 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1713 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1714 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1715 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1716 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1717 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1718 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1719 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1720 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1721 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1723 /* Check if the shell is hijacking the handles for other features */
1724 if (lpStartupInfo
->dwFlags
&
1725 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1727 /* It isn't, so we can return the raw values */
1728 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1729 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1730 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1734 /* It is, so make sure nobody uses these as console handles */
1735 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1736 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1737 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1746 FlushInstructionCache(IN HANDLE hProcess
,
1747 IN LPCVOID lpBaseAddress
,
1752 /* Call the native function */
1753 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, dwSize
);
1754 if (!NT_SUCCESS(Status
))
1756 /* Handle failure case */
1757 BaseSetLastNTError(Status
);
1770 ExitProcess(IN UINT uExitCode
)
1772 BASE_API_MESSAGE ApiMessage
;
1773 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1775 ASSERT(!BaseRunningInServerProcess
);
1779 /* Acquire the PEB lock */
1780 RtlAcquirePebLock();
1782 /* Kill all the threads */
1783 NtTerminateProcess(NULL
, 0);
1785 /* Unload all DLLs */
1786 LdrShutdownProcess();
1788 /* Notify Base Server of process termination */
1789 ExitProcessRequest
->uExitCode
= uExitCode
;
1790 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1792 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1793 sizeof(BASE_EXIT_PROCESS
));
1795 /* Now do it again */
1796 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1800 /* Release the PEB lock */
1801 RtlReleasePebLock();
1805 /* should never get here */
1815 TerminateProcess(IN HANDLE hProcess
,
1820 /* Check if no handle was passed in */
1823 /* Set error code */
1824 SetLastError(ERROR_INVALID_HANDLE
);
1828 /* Otherwise, try to terminate the process */
1829 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1830 if (NT_SUCCESS(Status
)) return TRUE
;
1832 /* It failed, convert error code */
1833 BaseSetLastNTError(Status
);
1836 /* This is the failure path */
1845 FatalAppExitA(UINT uAction
,
1846 LPCSTR lpMessageText
)
1848 PUNICODE_STRING MessageTextU
;
1849 ANSI_STRING MessageText
;
1852 /* Initialize the string using the static TEB pointer */
1853 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1854 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1856 /* Convert to unicode and just exit normally if this failed */
1857 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1858 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1860 /* Call the Wide function */
1861 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1869 FatalAppExitW(IN UINT uAction
,
1870 IN LPCWSTR lpMessageText
)
1872 UNICODE_STRING UnicodeString
;
1876 /* Setup the string to print out */
1877 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1879 /* Display the hard error no matter what */
1880 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1883 (PULONG_PTR
)&UnicodeString
,
1887 /* Give the user a chance to abort */
1888 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1890 /* Otherwise kill the process */
1899 FatalExit(IN
int ExitCode
)
1902 /* On Checked builds, Windows gives you a nice little debugger UI */
1904 DbgPrint("FatalExit...\n");
1909 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1917 ExitProcess(ExitCode
);
1924 /* On other builds, just kill the process */
1925 ExitProcess(ExitCode
);
1933 GetPriorityClass(IN HANDLE hProcess
)
1936 PROCESS_PRIORITY_CLASS PriorityClass
;
1938 /* Query the kernel */
1939 Status
= NtQueryInformationProcess(hProcess
,
1940 ProcessPriorityClass
,
1942 sizeof(PROCESS_PRIORITY_CLASS
),
1944 if (NT_SUCCESS(Status
))
1946 /* Handle the conversion from NT to Win32 classes */
1947 switch (PriorityClass
.PriorityClass
)
1949 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1950 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1951 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1952 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1953 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1954 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1959 BaseSetLastNTError(Status
);
1968 SetPriorityClass(IN HANDLE hProcess
,
1969 IN DWORD dwPriorityClass
)
1973 PROCESS_PRIORITY_CLASS PriorityClass
;
1975 /* Handle conversion from Win32 to NT priority classes */
1976 switch (dwPriorityClass
)
1978 case IDLE_PRIORITY_CLASS
:
1979 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1982 case BELOW_NORMAL_PRIORITY_CLASS
:
1983 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1986 case NORMAL_PRIORITY_CLASS
:
1987 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1990 case ABOVE_NORMAL_PRIORITY_CLASS
:
1991 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1994 case HIGH_PRIORITY_CLASS
:
1995 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1998 case REALTIME_PRIORITY_CLASS
:
1999 /* Try to acquire the privilege. If it fails, just use HIGH */
2000 State
= BasepIsRealtimeAllowed(TRUE
);
2001 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2002 PriorityClass
.PriorityClass
+= (State
!= NULL
);
2006 /* Unrecognized priority classes don't make it to the kernel */
2007 SetLastError(ERROR_INVALID_PARAMETER
);
2011 /* Send the request to the kernel, and don't touch the foreground flag */
2012 PriorityClass
.Foreground
= FALSE
;
2013 Status
= NtSetInformationProcess(hProcess
,
2014 ProcessPriorityClass
,
2016 sizeof(PROCESS_PRIORITY_CLASS
));
2018 /* Release the privilege if we had it */
2019 if (State
) RtlReleasePrivilege(State
);
2020 if (!NT_SUCCESS(Status
))
2022 /* Handle error path */
2023 BaseSetLastNTError(Status
);
2036 GetProcessVersion(IN DWORD ProcessId
)
2039 PIMAGE_NT_HEADERS NtHeader
;
2040 PIMAGE_DOS_HEADER DosHeader
;
2042 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2045 HANDLE ProcessHandle
= NULL
;
2047 USHORT VersionData
[2];
2050 /* We'll be accessing stuff that can fault, so protect everything with SEH */
2053 /* It this an in-process or out-of-process request? */
2054 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
2056 /* It's in-process, so just read our own header */
2057 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
2060 /* Unable to read the NT header, something is wrong here... */
2061 Status
= STATUS_INVALID_IMAGE_FORMAT
;
2065 /* Get the version straight out of the NT header */
2066 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
2067 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
2071 /* Out-of-process, so open it */
2072 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
2075 if (!ProcessHandle
) return 0;
2077 /* Try to find out where its PEB lives */
2078 Status
= NtQueryInformationProcess(ProcessHandle
,
2079 ProcessBasicInformation
,
2081 sizeof(ProcessBasicInfo
),
2084 if (!NT_SUCCESS(Status
)) goto Error
;
2085 Peb
= ProcessBasicInfo
.PebBaseAddress
;
2087 /* Now that we have the PEB, read the image base address out of it */
2088 Result
= ReadProcessMemory(ProcessHandle
,
2089 &Peb
->ImageBaseAddress
,
2091 sizeof(BaseAddress
),
2093 if (!Result
) goto Error
;
2095 /* Now read the e_lfanew (offset to NT header) from the base */
2096 DosHeader
= BaseAddress
;
2097 Result
= ReadProcessMemory(ProcessHandle
,
2098 &DosHeader
->e_lfanew
,
2102 if (!Result
) goto Error
;
2104 /* And finally, read the NT header itself by adding the offset */
2105 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
2106 Result
= ReadProcessMemory(ProcessHandle
,
2107 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
2109 sizeof(VersionData
),
2111 if (!Result
) goto Error
;
2113 /* Get the version straight out of the NT header */
2114 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
2117 /* If there was an error anywhere, set the last error */
2118 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
2123 /* Close the process handle */
2124 if (ProcessHandle
) CloseHandle(ProcessHandle
);
2128 /* And return the version data */
2137 GetProcessIoCounters(IN HANDLE hProcess
,
2138 OUT PIO_COUNTERS lpIoCounters
)
2142 /* Query the kernel. Structures are identical, so let it do the copy too. */
2143 Status
= NtQueryInformationProcess(hProcess
,
2146 sizeof(IO_COUNTERS
),
2148 if (!NT_SUCCESS(Status
))
2150 /* Handle error path */
2151 BaseSetLastNTError(Status
);
2164 GetProcessPriorityBoost(IN HANDLE hProcess
,
2165 OUT PBOOL pDisablePriorityBoost
)
2168 ULONG PriorityBoost
;
2170 /* Query the kernel */
2171 Status
= NtQueryInformationProcess(hProcess
,
2172 ProcessPriorityBoost
,
2176 if (NT_SUCCESS(Status
))
2178 /* Convert from ULONG to a BOOL */
2179 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
2183 /* Handle error path */
2184 BaseSetLastNTError(Status
);
2193 SetProcessPriorityBoost(IN HANDLE hProcess
,
2194 IN BOOL bDisablePriorityBoost
)
2197 ULONG PriorityBoost
;
2199 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
2200 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
2201 Status
= NtSetInformationProcess(hProcess
,
2202 ProcessPriorityBoost
,
2205 if (!NT_SUCCESS(Status
))
2207 /* Handle error path */
2208 BaseSetLastNTError(Status
);
2221 GetProcessHandleCount(IN HANDLE hProcess
,
2222 OUT PDWORD pdwHandleCount
)
2227 /* Query the kernel */
2228 Status
= NtQueryInformationProcess(hProcess
,
2233 if (NT_SUCCESS(Status
))
2235 /* Copy the count and return sucecss */
2236 *pdwHandleCount
= phc
;
2240 /* Handle error path */
2241 BaseSetLastNTError(Status
);
2250 IsWow64Process(IN HANDLE hProcess
,
2251 OUT PBOOL Wow64Process
)
2256 /* Query the kernel */
2257 Status
= NtQueryInformationProcess(hProcess
,
2258 ProcessWow64Information
,
2262 if (!NT_SUCCESS(Status
))
2264 /* Handle error path */
2265 BaseSetLastNTError(Status
);
2269 /* Enforce this is a BOOL, and return success */
2270 *Wow64Process
= (pbi
!= 0);
2279 GetCommandLineA(VOID
)
2281 return BaseAnsiCommandLine
.Buffer
;
2289 GetCommandLineW(VOID
)
2291 return BaseUnicodeCommandLine
.Buffer
;
2299 ReadProcessMemory(IN HANDLE hProcess
,
2300 IN LPCVOID lpBaseAddress
,
2303 OUT SIZE_T
* lpNumberOfBytesRead
)
2308 Status
= NtReadVirtualMemory(hProcess
,
2309 (PVOID
)lpBaseAddress
,
2314 /* In user-mode, this parameter is optional */
2315 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2316 if (!NT_SUCCESS(Status
))
2319 BaseSetLastNTError(Status
);
2323 /* Return success */
2332 WriteProcessMemory(IN HANDLE hProcess
,
2333 IN LPVOID lpBaseAddress
,
2334 IN LPCVOID lpBuffer
,
2336 OUT SIZE_T
*lpNumberOfBytesWritten
)
2344 /* Set parameters for protect call */
2346 Base
= lpBaseAddress
;
2348 /* Check the current status */
2349 Status
= NtProtectVirtualMemory(hProcess
,
2352 PAGE_EXECUTE_READWRITE
,
2354 if (NT_SUCCESS(Status
))
2356 /* Check if we are unprotecting */
2357 UnProtect
= OldValue
& (PAGE_READWRITE
|
2359 PAGE_EXECUTE_READWRITE
|
2360 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2363 /* Set the new protection */
2364 Status
= NtProtectVirtualMemory(hProcess
,
2370 /* Write the memory */
2371 Status
= NtWriteVirtualMemory(hProcess
,
2377 /* In Win32, the parameter is optional, so handle this case */
2378 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2380 if (!NT_SUCCESS(Status
))
2383 BaseSetLastNTError(Status
);
2387 /* Flush the ITLB */
2388 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2393 /* Check if we were read only */
2394 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2396 /* Restore protection and fail */
2397 NtProtectVirtualMemory(hProcess
,
2402 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2404 /* Note: This is what Windows returns and code depends on it */
2405 return STATUS_ACCESS_VIOLATION
;
2408 /* Otherwise, do the write */
2409 Status
= NtWriteVirtualMemory(hProcess
,
2415 /* In Win32, the parameter is optional, so handle this case */
2416 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2418 /* And restore the protection */
2419 NtProtectVirtualMemory(hProcess
,
2424 if (!NT_SUCCESS(Status
))
2427 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2429 /* Note: This is what Windows returns and code depends on it */
2430 return STATUS_ACCESS_VIOLATION
;
2433 /* Flush the ITLB */
2434 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2441 BaseSetLastNTError(Status
);
2451 ProcessIdToSessionId(IN DWORD dwProcessId
,
2452 OUT PDWORD pSessionId
)
2454 PROCESS_SESSION_INFORMATION SessionInformation
;
2455 OBJECT_ATTRIBUTES ObjectAttributes
;
2457 HANDLE ProcessHandle
;
2460 /* Do a quick check if the pointer is not writable */
2461 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2464 SetLastError(ERROR_INVALID_PARAMETER
);
2468 /* Open the process passed in by ID */
2469 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2470 ClientId
.UniqueThread
= 0;
2471 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2472 Status
= NtOpenProcess(&ProcessHandle
,
2473 PROCESS_QUERY_INFORMATION
,
2476 if (NT_SUCCESS(Status
))
2478 /* Query the session ID from the kernel */
2479 Status
= NtQueryInformationProcess(ProcessHandle
,
2480 ProcessSessionInformation
,
2481 &SessionInformation
,
2482 sizeof(SessionInformation
),
2485 /* Close the handle and check if we suceeded */
2486 NtClose(ProcessHandle
);
2487 if (NT_SUCCESS(Status
))
2489 /* Return the session ID */
2490 *pSessionId
= SessionInformation
.SessionId
;
2495 /* Set error code and fail */
2496 BaseSetLastNTError(Status
);
2505 CreateProcessInternalW(HANDLE hToken
,
2506 LPCWSTR lpApplicationName
,
2507 LPWSTR lpCommandLine
,
2508 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2509 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2510 BOOL bInheritHandles
,
2511 DWORD dwCreationFlags
,
2512 LPVOID lpEnvironment
,
2513 LPCWSTR lpCurrentDirectory
,
2514 LPSTARTUPINFOW lpStartupInfo
,
2515 LPPROCESS_INFORMATION lpProcessInformation
,
2519 PROCESS_PRIORITY_CLASS PriorityClass
;
2520 BOOLEAN FoundQuotes
= FALSE
;
2521 BOOLEAN QuotesNeeded
= FALSE
;
2522 BOOLEAN CmdLineIsAppName
= FALSE
;
2523 UNICODE_STRING ApplicationName
= { 0, 0, NULL
};
2524 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2525 POBJECT_ATTRIBUTES ObjectAttributes
;
2526 HANDLE hSection
= NULL
, hProcess
= NULL
, hThread
= NULL
, hDebug
= NULL
;
2527 SECTION_IMAGE_INFORMATION SectionImageInfo
;
2528 LPWSTR CurrentDirectory
= NULL
;
2529 LPWSTR CurrentDirectoryPart
;
2530 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2531 STARTUPINFOW StartupInfo
;
2533 LPWSTR BatchCommandLine
;
2534 ULONG CmdLineLength
;
2535 UNICODE_STRING CommandLineString
;
2537 LPWSTR QuotedCmdLine
= NULL
;
2539 LPWSTR NullBuffer
= NULL
;
2540 LPWSTR NameBuffer
= NULL
;
2545 BOOLEAN SearchDone
= FALSE
;
2546 BOOLEAN Escape
= FALSE
;
2548 PPEB OurPeb
= NtCurrentPeb();
2552 WCHAR VdmPath
[MAX_PATH
];
2554 /* FIXME should process
2555 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2556 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2559 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2560 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2561 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
2564 /* Flags we don't handle yet */
2565 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
2567 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2569 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
2571 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2573 if (dwCreationFlags
& CREATE_FORCEDOS
)
2575 DPRINT1("CREATE_FORCEDOS not handled\n");
2578 /* Fail on this flag, it's only valid with the WithLogonW function */
2579 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
2581 DPRINT1("Invalid flag used\n");
2582 SetLastError(ERROR_INVALID_PARAMETER
);
2586 /* This combination is illegal (see MSDN) */
2587 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2588 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2590 DPRINT1("Invalid flag combo used\n");
2591 SetLastError(ERROR_INVALID_PARAMETER
);
2595 /* Another illegal combo */
2596 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
2597 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
2599 DPRINT1("Invalid flag combo used\n");
2600 SetLastError(ERROR_INVALID_PARAMETER
);
2604 if (lpCurrentDirectory
)
2606 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
2607 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
2609 SetLastError(ERROR_DIRECTORY
);
2615 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2616 * so we'll use our own local copy for that.
2618 StartupInfo
= *lpStartupInfo
;
2620 /* FIXME: Use default Separate/Shared VDM Flag */
2622 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2623 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
2625 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
2627 /* Remove the shared flag and add the separate flag. */
2628 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2629 CREATE_SEPARATE_WOW_VDM
;
2633 /* Get the path to the VDM host */
2634 Length
= GetSystemDirectoryW(VdmPath
, MAX_PATH
- wcslen(NTVDM_STRING
));
2635 if ((Length
== 0) || (Length
>= MAX_PATH
- wcslen(NTVDM_STRING
)))
2637 /* System path not found for some reason, fail */
2638 SetLastError(ERROR_INVALID_NAME
);
2641 wcscat(VdmPath
, NTVDM_STRING
);
2644 * According to some sites, ShellExecuteEx uses an undocumented flag to
2645 * send private handle data (such as HMONITOR or HICON). See:
2646 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2647 * standard handles anymore since we'd be overwriting this private data
2649 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2650 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2652 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2655 /* Start by zeroing out the fields */
2656 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
2658 /* Easy stuff first, convert the process priority class */
2659 PriorityClass
.Foreground
= FALSE
;
2660 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
2664 /* Search for escape sequences */
2665 ScanString
= lpCommandLine
;
2666 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2669 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
2677 /* Get the application name and do all the proper formating necessary */
2679 /* See if we have an application name (oh please let us have one!) */
2680 if (!lpApplicationName
)
2682 /* The fun begins */
2683 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2685 MAX_PATH
* sizeof(WCHAR
));
2686 if (NameBuffer
== NULL
)
2688 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2692 /* This is all we have to work with :( */
2693 lpApplicationName
= lpCommandLine
;
2695 /* Initialize our friends at the beginning */
2696 NullBuffer
= (LPWSTR
)lpApplicationName
;
2697 ScanString
= (LPWSTR
)lpApplicationName
;
2699 /* We will start by looking for a quote */
2700 if (*ScanString
== L
'\"')
2702 /* That was quick */
2705 /* Advance past quote */
2707 lpApplicationName
= ScanString
;
2709 /* Find the closing quote */
2712 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
2715 NullBuffer
= ScanString
;
2722 NullBuffer
= ScanString
;
2727 /* No quotes, so we'll be looking for white space */
2729 /* Reset the pointer */
2730 lpApplicationName
= lpCommandLine
;
2732 /* Find whitespace of Tab */
2735 if (*ScanString
== ' ' || *ScanString
== '\t')
2738 NullBuffer
= ScanString
;
2744 NullBuffer
= ScanString
;
2748 /* Set the Null Buffer */
2749 SaveChar
= *NullBuffer
;
2750 *NullBuffer
= UNICODE_NULL
;
2752 /* Do a search for the file */
2753 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
2754 RetVal
= SearchPathW(NULL
,
2759 NULL
) * sizeof(WCHAR
);
2761 /* Did it find something? */
2764 /* Get file attributes */
2765 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
2766 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2768 /* Give it a length of 0 to fail, this was a directory. */
2774 RetVal
+= sizeof(WCHAR
);
2778 /* Now check if we have a file, and if the path size is OK */
2779 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
2784 /* We failed, try to get the Path Type */
2785 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
2786 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2788 /* If it's not relative, try to get the error */
2789 if (PathType
!= RtlPathTypeRelative
)
2791 /* This should fail, and give us a detailed LastError */
2792 hFile
= CreateFileW(lpApplicationName
,
2794 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2797 FILE_ATTRIBUTE_NORMAL
,
2800 /* Did it actually NOT fail? */
2801 if (hFile
!= INVALID_HANDLE_VALUE
)
2803 /* Fake the error */
2805 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2810 /* Immediately set the error */
2811 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2814 /* Did we already fail once? */
2817 SetLastError(Error
);
2821 /* Not yet, cache it */
2822 Error
= GetLastError();
2825 /* Put back the command line */
2826 *NullBuffer
= SaveChar
;
2827 lpApplicationName
= NameBuffer
;
2830 * If the search isn't done and we still have cmdline
2831 * then start over. Ex: c:\ha ha ha\haha.exe
2833 if (*ScanString
&& !SearchDone
)
2835 /* Move in the buffer */
2837 NullBuffer
= ScanString
;
2839 /* We will have to add a quote, since there is a space*/
2840 QuotesNeeded
= TRUE
;
2842 /* And we will also fake the fact we found one */
2849 /* We totally failed */
2853 /* Put back the command line */
2854 *NullBuffer
= SaveChar
;
2855 lpApplicationName
= NameBuffer
;
2856 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
2858 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
2860 /* We have an app name (good!) but no command line */
2861 CmdLineIsAppName
= TRUE
;
2862 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2865 /* At this point the name has been toyed with enough to be openable */
2866 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
2868 /* Check for failure */
2869 if (!NT_SUCCESS(Status
))
2871 /* Could be a non-PE File */
2874 /* Check if the Kernel tells us it's not even valid MZ */
2875 case STATUS_INVALID_IMAGE_NE_FORMAT
:
2876 case STATUS_INVALID_IMAGE_PROTECT
:
2877 case STATUS_INVALID_IMAGE_NOT_MZ
:
2879 /* If it's a DOS app, use VDM */
2880 if ((BasepCheckDosApp(&ApplicationName
)))
2882 DPRINT1("Launching VDM...\n");
2883 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2884 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2885 return CreateProcessW(VdmPath
,
2886 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2887 lpProcessAttributes
,
2894 lpProcessInformation
);
2896 /* It's a batch file */
2897 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
2900 /* Make sure the extensions are correct */
2901 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
2903 SetLastError(ERROR_BAD_EXE_FORMAT
);
2907 /* Calculate the length of the command line */
2908 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
2910 /* If we found quotes, then add them into the length size */
2911 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
2912 CmdLineLength
*= sizeof(WCHAR
);
2914 /* Allocate space for the new command line */
2915 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2918 if (BatchCommandLine
== NULL
)
2920 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2925 wcscpy(BatchCommandLine
, CMD_STRING
);
2926 if (CmdLineIsAppName
|| FoundQuotes
)
2928 wcscat(BatchCommandLine
, L
"\"");
2930 wcscat(BatchCommandLine
, lpCommandLine
);
2931 if (CmdLineIsAppName
|| FoundQuotes
)
2933 wcscat(BatchCommandLine
, L
"\"");
2936 /* Create it as a Unicode String */
2937 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
2939 /* Set the command line to this */
2940 lpCommandLine
= CommandLineString
.Buffer
;
2941 lpApplicationName
= NULL
;
2944 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2945 ApplicationName
.Buffer
= NULL
;
2949 case STATUS_INVALID_IMAGE_WIN_16
:
2951 /* It's a Win16 Image, use VDM */
2952 DPRINT1("Launching VDM...\n");
2953 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2954 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2955 return CreateProcessW(VdmPath
,
2956 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2957 lpProcessAttributes
,
2964 lpProcessInformation
);
2966 case STATUS_OBJECT_NAME_NOT_FOUND
:
2967 case STATUS_OBJECT_PATH_NOT_FOUND
:
2968 BaseSetLastNTError(Status
);
2972 /* Invalid Image Type */
2973 SetLastError(ERROR_BAD_EXE_FORMAT
);
2978 /* Use our desktop if we didn't get any */
2979 if (!StartupInfo
.lpDesktop
)
2981 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
2984 /* FIXME: Check if Application is allowed to run */
2986 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2988 /* Get some information about the executable */
2989 Status
= NtQuerySection(hSection
,
2990 SectionImageInformation
,
2992 sizeof(SectionImageInfo
),
2994 if(!NT_SUCCESS(Status
))
2996 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
2997 BaseSetLastNTError(Status
);
3001 /* Don't execute DLLs */
3002 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3004 DPRINT1("Can't execute a DLL\n");
3005 SetLastError(ERROR_BAD_EXE_FORMAT
);
3009 /* FIXME: Check for Debugger */
3011 /* FIXME: Check if Machine Type and SubSys Version Match */
3013 /* We don't support POSIX or anything else for now */
3014 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= SectionImageInfo
.SubSystemType
&&
3015 IMAGE_SUBSYSTEM_WINDOWS_CUI
!= SectionImageInfo
.SubSystemType
)
3017 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
3019 * Despite the name of the error code suggests, it corresponds to the
3020 * well-known "The %1 application cannot be run in Win32 mode" message.
3022 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
3026 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
3028 /* Do not create a console for GUI applications */
3029 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
3030 dwCreationFlags
|= DETACHED_PROCESS
;
3033 /* Initialize the process object attributes */
3034 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3035 lpProcessAttributes
,
3038 /* Check if we're going to be debugged */
3039 if (dwCreationFlags
& DEBUG_PROCESS
)
3041 /* FIXME: Set process flag */
3044 /* Check if we're going to be debugged */
3045 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
3047 /* Connect to DbgUi */
3048 Status
= DbgUiConnectToDbg();
3049 if (!NT_SUCCESS(Status
))
3051 DPRINT1("Failed to connect to DbgUI!\n");
3052 BaseSetLastNTError(Status
);
3056 /* Get the debug object */
3057 hDebug
= DbgUiGetThreadDebugObject();
3059 /* Check if only this process will be debugged */
3060 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
3062 /* Set process flag */
3063 hDebug
= (HANDLE
)((ULONG_PTR
)hDebug
| 0x1);
3067 /* Create the Process */
3068 Status
= NtCreateProcess(&hProcess
,
3072 (BOOLEAN
)bInheritHandles
,
3076 if (!NT_SUCCESS(Status
))
3078 DPRINT1("Unable to create process, status 0x%x\n", Status
);
3079 BaseSetLastNTError(Status
);
3083 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
3086 Status
= NtSetInformationProcess(hProcess
,
3087 ProcessPriorityClass
,
3089 sizeof(PROCESS_PRIORITY_CLASS
));
3090 if(!NT_SUCCESS(Status
))
3092 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
3093 BaseSetLastNTError(Status
);
3098 /* Set Error Mode */
3099 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
3101 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
3102 NtSetInformationProcess(hProcess
,
3103 ProcessDefaultHardErrorMode
,
3108 /* Convert the directory to a full path */
3109 if (lpCurrentDirectory
)
3111 /* Allocate a buffer */
3112 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
3114 (MAX_PATH
+ 1) * sizeof(WCHAR
));
3115 if (CurrentDirectory
== NULL
)
3117 DPRINT1("Cannot allocate memory for directory name\n");
3118 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3122 /* Get the length */
3123 if (GetFullPathNameW(lpCurrentDirectory
,
3126 &CurrentDirectoryPart
) > MAX_PATH
)
3128 DPRINT1("Directory name too long\n");
3129 SetLastError(ERROR_DIRECTORY
);
3134 /* Insert quotes if needed */
3135 if (QuotesNeeded
|| CmdLineIsAppName
)
3137 /* Allocate a buffer */
3138 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3140 (wcslen(lpCommandLine
) + 2 + 1) *
3142 if (QuotedCmdLine
== NULL
)
3144 DPRINT1("Cannot allocate memory for quoted command line\n");
3145 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3149 /* Copy the first quote */
3150 wcscpy(QuotedCmdLine
, L
"\"");
3152 /* Save a null char */
3155 SaveChar
= *NullBuffer
;
3156 *NullBuffer
= UNICODE_NULL
;
3159 /* Add the command line and the finishing quote */
3160 wcscat(QuotedCmdLine
, lpCommandLine
);
3161 wcscat(QuotedCmdLine
, L
"\"");
3163 /* Add the null char */
3166 *NullBuffer
= SaveChar
;
3167 wcscat(QuotedCmdLine
, NullBuffer
);
3170 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
3175 if (QuotedCmdLine
== NULL
)
3177 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3179 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
3180 if (QuotedCmdLine
== NULL
)
3182 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3185 wcscpy(QuotedCmdLine
, lpCommandLine
);
3188 ScanString
= QuotedCmdLine
;
3189 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
3192 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
3194 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
3199 /* Get the Process Information */
3200 Status
= NtQueryInformationProcess(hProcess
,
3201 ProcessBasicInformation
,
3203 sizeof(ProcessBasicInfo
),
3206 /* Convert the environment */
3207 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3209 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
3210 if (!lpEnvironment
) goto Cleanup
;
3213 /* Create Process Environment */
3214 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
3215 Ret
= BasePushProcessParameters(0,
3218 (LPWSTR
)lpApplicationName
,
3220 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
3221 QuotedCmdLine
: lpCommandLine
,
3229 if (!Ret
) goto Cleanup
;
3231 /* Cleanup Environment */
3232 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3234 RtlDestroyEnvironment(lpEnvironment
);
3237 /* Close the section */
3241 /* Duplicate the handles if needed */
3242 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
3243 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
3245 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
3247 /* Get the remote parameters */
3248 Status
= NtReadVirtualMemory(hProcess
,
3249 &RemotePeb
->ProcessParameters
,
3253 if (!NT_SUCCESS(Status
))
3255 DPRINT1("Failed to read memory\n");
3259 /* Duplicate and write the handles */
3260 BasepDuplicateAndWriteHandle(hProcess
,
3261 OurPeb
->ProcessParameters
->StandardInput
,
3262 &RemoteParameters
->StandardInput
);
3263 BasepDuplicateAndWriteHandle(hProcess
,
3264 OurPeb
->ProcessParameters
->StandardOutput
,
3265 &RemoteParameters
->StandardOutput
);
3266 BasepDuplicateAndWriteHandle(hProcess
,
3267 OurPeb
->ProcessParameters
->StandardError
,
3268 &RemoteParameters
->StandardError
);
3271 /* Create the first thread */
3272 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
3273 SectionImageInfo
.TransferAddress
);
3274 hThread
= BasepCreateFirstThread(hProcess
,
3280 if (hThread
== NULL
)
3282 DPRINT1("Could not create Initial Thread\n");
3283 /* FIXME - set last error code */
3287 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
3289 NtResumeThread(hThread
, &Dummy
);
3293 lpProcessInformation
->dwProcessId
= (DWORD
)ClientId
.UniqueProcess
;
3294 lpProcessInformation
->dwThreadId
= (DWORD
)ClientId
.UniqueThread
;
3295 lpProcessInformation
->hProcess
= hProcess
;
3296 lpProcessInformation
->hThread
= hThread
;
3297 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread
,
3298 ClientId
.UniqueThread
, ClientId
.UniqueProcess
, hProcess
);
3299 hProcess
= hThread
= NULL
;
3303 /* De-allocate heap strings */
3304 if (NameBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3305 if (ApplicationName
.Buffer
)
3306 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
3307 if (CurrentDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
3308 if (QuotedCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
3310 /* Kill any handles still alive */
3311 if (hSection
) NtClose(hSection
);
3314 /* We don't know any more details than this */
3315 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
3318 if (hProcess
) NtClose(hProcess
);
3320 /* Return Success */
3329 CreateProcessW(LPCWSTR lpApplicationName
,
3330 LPWSTR lpCommandLine
,
3331 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3332 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3333 BOOL bInheritHandles
,
3334 DWORD dwCreationFlags
,
3335 LPVOID lpEnvironment
,
3336 LPCWSTR lpCurrentDirectory
,
3337 LPSTARTUPINFOW lpStartupInfo
,
3338 LPPROCESS_INFORMATION lpProcessInformation
)
3340 /* Call the internal (but exported) version */
3341 return CreateProcessInternalW(0,
3344 lpProcessAttributes
,
3351 lpProcessInformation
,
3360 CreateProcessInternalA(HANDLE hToken
,
3361 LPCSTR lpApplicationName
,
3362 LPSTR lpCommandLine
,
3363 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3364 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3365 BOOL bInheritHandles
,
3366 DWORD dwCreationFlags
,
3367 LPVOID lpEnvironment
,
3368 LPCSTR lpCurrentDirectory
,
3369 LPSTARTUPINFOA lpStartupInfo
,
3370 LPPROCESS_INFORMATION lpProcessInformation
,
3373 PUNICODE_STRING CommandLine
= NULL
;
3374 UNICODE_STRING DummyString
;
3375 UNICODE_STRING LiveCommandLine
;
3376 UNICODE_STRING ApplicationName
;
3377 UNICODE_STRING CurrentDirectory
;
3379 STARTUPINFOW StartupInfo
;
3381 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
3382 "lpStartupInfo %x, lpProcessInformation %x\n",
3383 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
3384 lpStartupInfo
, lpProcessInformation
);
3386 /* Copy Startup Info */
3387 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
3389 /* Initialize all strings to nothing */
3390 LiveCommandLine
.Buffer
= NULL
;
3391 DummyString
.Buffer
= NULL
;
3392 ApplicationName
.Buffer
= NULL
;
3393 CurrentDirectory
.Buffer
= NULL
;
3394 StartupInfo
.lpDesktop
= NULL
;
3395 StartupInfo
.lpReserved
= NULL
;
3396 StartupInfo
.lpTitle
= NULL
;
3398 /* Convert the Command line */
3401 /* If it's too long, then we'll have a problem */
3402 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
3403 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
3405 /* Cache it in the TEB */
3406 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
3410 /* Use a dynamic version */
3411 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
3417 /* The logic below will use CommandLine, so we must make it valid */
3418 CommandLine
= &DummyString
;
3421 /* Convert the Name and Directory */
3422 if (lpApplicationName
)
3424 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
3427 if (lpCurrentDirectory
)
3429 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
3430 lpCurrentDirectory
);
3433 /* Now convert Startup Strings */
3434 if (lpStartupInfo
->lpReserved
)
3436 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
3437 &StartupInfo
.lpReserved
);
3439 if (lpStartupInfo
->lpDesktop
)
3441 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
3442 &StartupInfo
.lpDesktop
);
3444 if (lpStartupInfo
->lpTitle
)
3446 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
3447 &StartupInfo
.lpTitle
);
3450 /* Call the Unicode function */
3451 bRetVal
= CreateProcessInternalW(hToken
,
3452 ApplicationName
.Buffer
,
3453 LiveCommandLine
.Buffer
?
3454 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
3455 lpProcessAttributes
,
3460 CurrentDirectory
.Buffer
,
3462 lpProcessInformation
,
3466 RtlFreeUnicodeString(&ApplicationName
);
3467 RtlFreeUnicodeString(&LiveCommandLine
);
3468 RtlFreeUnicodeString(&CurrentDirectory
);
3469 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
3470 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
3471 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
3473 /* Return what Unicode did */
3478 * FUNCTION: The CreateProcess function creates a new process and its
3479 * primary thread. The new process executes the specified executable file
3482 * lpApplicationName = Pointer to name of executable module
3483 * lpCommandLine = Pointer to command line string
3484 * lpProcessAttributes = Process security attributes
3485 * lpThreadAttributes = Thread security attributes
3486 * bInheritHandles = Handle inheritance flag
3487 * dwCreationFlags = Creation flags
3488 * lpEnvironment = Pointer to new environment block
3489 * lpCurrentDirectory = Pointer to current directory name
3490 * lpStartupInfo = Pointer to startup info
3491 * lpProcessInformation = Pointer to process information
3497 CreateProcessA(LPCSTR lpApplicationName
,
3498 LPSTR lpCommandLine
,
3499 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3500 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3501 BOOL bInheritHandles
,
3502 DWORD dwCreationFlags
,
3503 LPVOID lpEnvironment
,
3504 LPCSTR lpCurrentDirectory
,
3505 LPSTARTUPINFOA lpStartupInfo
,
3506 LPPROCESS_INFORMATION lpProcessInformation
)
3508 /* Call the internal (but exported) version */
3509 return CreateProcessInternalA(0,
3512 lpProcessAttributes
,
3519 lpProcessInformation
,
3528 WinExec(LPCSTR lpCmdLine
,
3531 STARTUPINFOA StartupInfo
;
3532 PROCESS_INFORMATION ProcessInformation
;
3535 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
3536 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
3537 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
3538 StartupInfo
.dwFlags
= 0;
3540 if (!CreateProcessA(NULL
,
3549 &ProcessInformation
))
3551 dosErr
= GetLastError();
3552 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
3555 if (NULL
!= UserWaitForInputIdleRoutine
)
3557 UserWaitForInputIdleRoutine(ProcessInformation
.hProcess
,
3561 NtClose(ProcessInformation
.hProcess
);
3562 NtClose(ProcessInformation
.hThread
);
3564 return 33; /* Something bigger than 31 means success. */