3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/proc/proc.c
6 * PURPOSE: Process functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
12 /* INCLUDES ****************************************************************/
19 typedef INT (WINAPI
*MessageBoxW_Proc
) (HWND
, LPCWSTR
, LPCWSTR
, UINT
);
21 /* GLOBALS *******************************************************************/
23 static UNICODE_STRING CommandLineStringW
;
24 static ANSI_STRING CommandLineStringA
;
25 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
27 static BOOL bCommandLineInitialized
= FALSE
;
29 WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle
;
31 LPSTARTUPINFOA lpLocalStartupInfo
= NULL
;
34 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
36 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
38 #define CMD_STRING L"cmd /c "
40 extern __declspec(noreturn
)
43 ConsoleControlDispatcher(DWORD CodeAndFlag
);
45 BOOLEAN g_AppCertInitialized
;
46 BOOLEAN g_HaveAppCerts
;
47 LIST_ENTRY BasepAppCertDllsList
;
48 RTL_CRITICAL_SECTION gcsAppCert
;
49 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
50 NTSTATUS g_AppCertStatus
;
52 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
55 BasepConfigureAppCertDlls
,
58 &BasepAppCertDllsList
,
66 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
67 HMODULE gSaferHandle
= (HMODULE
)-1;
69 /* FUNCTIONS ****************************************************************/
73 StuffStdHandle(IN HANDLE ProcessHandle
,
74 IN HANDLE StandardHandle
,
78 HANDLE DuplicatedHandle
;
81 /* Duplicate the handle */
82 Status
= NtDuplicateObject(NtCurrentProcess(),
86 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
89 if (NT_SUCCESS(Status
))
92 NtWriteVirtualMemory(ProcessHandle
,
102 BuildSubSysCommandLine(IN LPWSTR SubsystemName
,
103 IN LPWSTR ApplicationName
,
104 IN LPWSTR CommandLine
,
105 OUT PUNICODE_STRING SubsysCommandLine
)
107 UNICODE_STRING CommandLineString
, ApplicationNameString
;
111 /* Convert to unicode strings */
112 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
113 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
115 /* Allocate buffer for the output string */
116 Length
= CommandLineString
.MaximumLength
+ ApplicationNameString
.MaximumLength
+ 32;
117 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
118 RtlInitEmptyUnicodeString(SubsysCommandLine
, Buffer
, Length
);
121 /* Fail, no memory */
122 BaseSetLastNTError(STATUS_NO_MEMORY
);
126 /* Build the final subsystem command line */
127 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
128 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
129 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
130 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
136 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
137 IN ULONG ImageMinorVersion
)
139 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
140 return ((ImageMajorVersion
>= 3) &&
141 ((ImageMajorVersion
!= 3) ||
142 (ImageMinorVersion
>= 10)) &&
143 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
144 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
145 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
150 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
155 /* Get all the MD5 hashes */
156 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
157 if (!NT_SUCCESS(Status
)) return Status
;
159 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
160 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
162 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
164 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
166 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
168 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
170 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
173 /* Actually, fuck it, don't block anything, we're open source */
174 return STATUS_SUCCESS
;
179 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
180 IN PWCHAR ComponentName
,
183 /* Pretty much the only thing this key is used for, is malware */
185 return STATUS_NOT_IMPLEMENTED
;
190 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
193 IN ULONG ValueLength
,
195 IN PVOID EntryContext
)
197 /* Add this to the certification list */
198 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
203 BasepIsProcessAllowed(IN PCHAR ApplicationName
)
208 HMODULE TrustLibrary
;
209 PBASEP_APPCERT_ENTRY Entry
;
211 PLIST_ENTRY NextEntry
;
213 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
214 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
216 /* Try to initialize the certification subsystem */
217 while (!g_AppCertInitialized
)
220 Status
= STATUS_SUCCESS
;
223 /* Acquire the lock while initializing and see if we lost a race */
224 RtlEnterCriticalSection(&gcsAppCert
);
225 if (g_AppCertInitialized
) break;
227 /* On embedded, there is a special DLL */
228 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
230 /* Allocate a buffer for the name */
231 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
233 MAX_PATH
* sizeof(WCHAR
) +
234 sizeof(UNICODE_NULL
));
237 /* Fail if no memory */
238 Status
= STATUS_NO_MEMORY
;
242 /* Now get the system32 directory in our buffer, make sure it fits */
243 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
244 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
246 /* Add a slash if needed, and add the embedded cert DLL name */
247 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
248 RtlCopyMemory(&Buffer
[Length
],
250 sizeof(L
"EmbdTrst.DLL"));
253 TrustLibrary
= LoadLibraryW(Buffer
);
256 /* And extract the special function out of it */
257 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
258 "ImageOkToRunOnEmbeddedNT");
262 /* If we didn't get this far, set a failure code */
263 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
268 /* Other systems have a registry entry for this */
269 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
270 if (NT_SUCCESS(Status
))
272 /* Close it, we'll query it through Rtl */
275 /* Do the query, which will call a special callback */
276 Status
= RtlQueryRegistryValues(2,
281 if (Status
== 0xC0000034) Status
= STATUS_SUCCESS
;
285 /* Free any buffer if we had one */
286 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
288 /* Check for errors, or a missing embedded/custom certification DLL */
289 if (!NT_SUCCESS(Status
) ||
290 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
292 /* The subsystem is not active on this machine, so give up */
293 g_HaveAppCerts
= FALSE
;
294 g_AppCertStatus
= Status
;
298 /* We have certification DLLs active, remember this */
299 g_HaveAppCerts
= TRUE
;
302 /* We are done the initialization phase, release the lock */
303 g_AppCertInitialized
= TRUE
;
304 RtlLeaveCriticalSection(&gcsAppCert
);
307 /* If there's no certification DLLs present, return the failure code */
308 if (!g_HaveAppCerts
) return g_AppCertStatus
;
310 /* Otherwise, assume success and make sure we have *something* */
311 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
312 Status
= STATUS_SUCCESS
;
314 /* If the something is an embedded certification DLL, call it and return */
315 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
317 /* Otherwise we have custom certification DLLs, parse them */
318 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 and check if it failed */
327 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
328 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
331 NextEntry
= NextEntry
->Flink
;
334 /* Now loop them again */
335 NextEntry
= BasepAppCertDllsList
.Flink
;
336 while (NextEntry
!= &BasepAppCertDllsList
)
338 /* Make sure the entry has a callback */
339 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
340 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
342 /* Call it, this time with the flag from the loop above */
343 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
346 /* All done, return the status */
352 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
353 IN HANDLE ProcessHandle
,
354 IN HANDLE ThreadHandle
)
357 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
359 /* Enter the application certification lock */
360 RtlEnterCriticalSection(&gcsAppCert
);
362 /* Check if we already know the function */
363 if (g_SaferReplaceProcessThreadTokens
)
366 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
374 /* Check if the app certification DLL isn't loaded */
375 if (!(gSaferHandle
) ||
376 (gSaferHandle
== (HMODULE
)-1) ||
377 (gSaferHandle
== (HMODULE
)-2))
379 /* Then we can't call the function */
380 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
384 /* We have the DLL, find the address of the Safer function */
385 Status
= LdrGetProcedureAddress(gSaferHandle
,
386 &SaferiReplaceProcessThreadTokens
,
388 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
389 if (NT_SUCCESS(Status
))
391 /* Found it, now call it */
392 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
400 /* We couldn't find it, so this must be an unsupported DLL */
401 LdrUnloadDll(gSaferHandle
);
403 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
408 /* Release the lock and return the result */
409 RtlLeaveCriticalSection(&gcsAppCert
);
415 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
420 ASSERT(Handles
!= NULL
);
421 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
423 /* Close the file handle */
426 Status
= NtClose(Handles
->File
);
427 ASSERT(NT_SUCCESS(Status
));
430 /* Close the section handle */
431 if (Handles
->Section
)
433 Status
= NtClose(Handles
->Section
);
434 ASSERT(NT_SUCCESS(Status
));
437 /* Unmap the section view */
438 if (Handles
->ViewBase
.QuadPart
)
440 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
441 (PVOID
)Handles
->ViewBase
.LowPart
);
442 ASSERT(NT_SUCCESS(Status
));
447 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
449 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
450 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
451 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
453 if (RealFilter
!= NULL
)
457 ExceptionDisposition
= RealFilter(ExceptionInfo
);
459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
465 RealFilter
!= UnhandledExceptionFilter
)
467 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
470 return ExceptionDisposition
;
475 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
479 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
483 /* Set our Start Address */
484 NtSetInformationThread(NtCurrentThread(),
485 ThreadQuerySetWin32StartAddress
,
487 sizeof(PPROCESS_START_ROUTINE
));
489 /* Call the Start Routine */
490 uExitCode
= (lpStartAddress
)();
492 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
494 /* Get the SEH Error */
495 uExitCode
= _SEH2_GetExceptionCode();
499 /* Exit the Process with our error */
500 ExitProcess(uExitCode
);
504 * Tells CSR that a new process was created
508 BasepNotifyCsrOfCreation(ULONG dwCreationFlags
,
510 IN BOOL InheritHandles
)
512 ULONG Request
= CREATE_PROCESS
;
513 CSR_API_MESSAGE CsrRequest
;
516 DPRINT("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
517 ProcessId
, dwCreationFlags
);
519 /* Fill out the request */
520 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
= ProcessId
;
521 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
522 CsrRequest
.Data
.CreateProcessRequest
.bInheritHandles
= InheritHandles
;
525 Status
= CsrClientCallServer(&CsrRequest
,
527 MAKE_CSR_API(Request
, CSR_NATIVE
),
528 sizeof(CSR_API_MESSAGE
));
529 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
531 DPRINT1("Failed to tell csrss about new process\n");
532 return CsrRequest
.Status
;
536 return STATUS_SUCCESS
;
541 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
542 IN PCLIENT_ID ClientId
)
544 ULONG Request
= CREATE_THREAD
;
545 CSR_API_MESSAGE CsrRequest
;
548 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
549 ClientId
->UniqueThread
, ThreadHandle
);
551 /* Fill out the request */
552 CsrRequest
.Data
.CreateThreadRequest
.ClientId
= *ClientId
;
553 CsrRequest
.Data
.CreateThreadRequest
.ThreadHandle
= ThreadHandle
;
556 Status
= CsrClientCallServer(&CsrRequest
,
558 MAKE_CSR_API(Request
, CSR_NATIVE
),
559 sizeof(CSR_API_MESSAGE
));
560 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
562 DPRINT1("Failed to tell csrss about new thread\n");
563 return CsrRequest
.Status
;
567 return STATUS_SUCCESS
;
571 * Creates the first Thread in a Proces
575 BasepCreateFirstThread(HANDLE ProcessHandle
,
576 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
577 PSECTION_IMAGE_INFORMATION SectionImageInfo
,
580 OBJECT_ATTRIBUTES LocalObjectAttributes
;
581 POBJECT_ATTRIBUTES ObjectAttributes
;
583 INITIAL_TEB InitialTeb
;
587 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
589 /* Create the Thread's Stack */
590 BaseCreateStack(ProcessHandle
,
591 SectionImageInfo
->MaximumStackSize
,
592 SectionImageInfo
->CommittedStackSize
,
595 /* Create the Thread's Context */
596 BaseInitializeContext(&Context
,
598 SectionImageInfo
->TransferAddress
,
599 InitialTeb
.StackBase
,
602 /* Convert the thread attributes */
603 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
607 /* Create the Kernel Thread Object */
608 Status
= NtCreateThread(&hThread
,
616 if (!NT_SUCCESS(Status
))
621 Status
= BasepNotifyCsrOfThread(hThread
, ClientId
);
622 if (!NT_SUCCESS(Status
))
632 * Converts ANSI to Unicode Environment
636 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
637 IN PVOID lpEnvironment
)
641 UNICODE_STRING UnicodeEnv
;
644 DPRINT("BasepConvertUnicodeEnvironment\n");
646 /* Scan the environment to calculate its Unicode size */
647 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
650 pcScan
+= strlen(pcScan
) + 1;
653 /* Create our ANSI String */
654 if (pcScan
== (PCHAR
)lpEnvironment
)
656 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
661 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
663 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
665 /* Allocate memory for the Unicode Environment */
666 UnicodeEnv
.Buffer
= NULL
;
667 *EnvSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
668 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
669 (PVOID
)&UnicodeEnv
.Buffer
,
675 if (!NT_SUCCESS(Status
))
677 SetLastError(Status
);
682 /* Use the allocated size */
683 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
686 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
687 return UnicodeEnv
.Buffer
;
691 * Converts a Win32 Priority Class to NT
695 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
699 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
701 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
703 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
705 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
707 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
709 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
711 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
713 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
715 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
717 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
719 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
721 /* Check for Privilege First */
722 if (BasepIsRealtimeAllowed(TRUE
))
724 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
728 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
733 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
740 * Duplicates a standard handle and writes it where requested.
744 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
745 IN HANDLE StandardHandle
,
749 HANDLE DuplicatedHandle
;
752 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
753 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
755 /* Don't touch Console Handles */
756 if (IsConsoleHandle(StandardHandle
)) return;
758 /* Duplicate the handle */
759 Status
= NtDuplicateObject(NtCurrentProcess(),
763 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
766 if (NT_SUCCESS(Status
))
769 NtWriteVirtualMemory(ProcessHandle
,
779 BasePushProcessParameters(IN ULONG ParameterFlags
,
780 IN HANDLE ProcessHandle
,
782 IN LPCWSTR ApplicationPathName
,
783 IN LPWSTR lpCurrentDirectory
,
784 IN LPWSTR lpCommandLine
,
785 IN LPVOID lpEnvironment
,
786 IN LPSTARTUPINFOW StartupInfo
,
787 IN DWORD CreationFlags
,
788 IN BOOL InheritHandles
,
789 IN ULONG ImageSubsystem
,
790 IN PVOID AppCompatData
,
791 IN ULONG AppCompatDataSize
)
793 WCHAR FullPath
[MAX_PATH
+ 5];
794 PWCHAR Remaining
, DllPathString
, ScanChar
;
795 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
796 PVOID RemoteAppCompatData
;
797 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
798 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
802 BOOLEAN HavePebLock
= FALSE
, Result
;
803 PPEB Peb
= NtCurrentPeb();
804 DPRINT("BasePushProcessParameters\n");
806 /* Get the full path name */
807 Size
= GetFullPathNameW(ApplicationPathName
,
811 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
813 /* Get the DLL Path */
814 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
819 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
823 /* Initialize Strings */
824 RtlInitUnicodeString(&DllPath
, DllPathString
);
825 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
829 /* Get the DLL Path */
830 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
834 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
838 /* Initialize Strings */
839 RtlInitUnicodeString(&DllPath
, DllPathString
);
840 RtlInitUnicodeString(&ImageName
, FullPath
);
843 /* Initialize Strings */
844 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
845 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
847 /* Initialize more Strings from the Startup Info */
848 if (StartupInfo
->lpDesktop
)
850 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
854 RtlInitUnicodeString(&Desktop
, L
"");
856 if (StartupInfo
->lpReserved
)
858 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
862 RtlInitUnicodeString(&Shell
, L
"");
864 if (StartupInfo
->lpTitle
)
866 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
870 RtlInitUnicodeString(&Title
, ApplicationPathName
);
873 /* This one is special because the length can differ */
874 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
875 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
877 /* Enforce no app compat data if the pointer was NULL */
878 if (!AppCompatData
) AppCompatDataSize
= 0;
880 /* Create the Parameter Block */
881 ProcessParameters
= NULL
;
882 Status
= RtlCreateProcessParameters(&ProcessParameters
,
886 &CurrentDirectory
: NULL
,
893 if (!NT_SUCCESS(Status
)) goto FailPath
;
895 /* Clear the current directory handle if not inheriting */
896 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
898 /* Check if the user passed in an environment */
901 /* We should've made it part of the parameters block, enforce this */
902 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
903 lpEnvironment
= ProcessParameters
->Environment
;
907 /* The user did not, so use the one from the current PEB */
910 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
913 /* Save pointer and start lookup */
914 ScanChar
= lpEnvironment
;
917 /* Find the environment size */
918 while ((ScanChar
[0]) || (ScanChar
[1])) ++ScanChar
;
919 ScanChar
+= (2 * sizeof(UNICODE_NULL
));
920 EnviroSize
= (ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
;
922 /* Allocate and Initialize new Environment Block */
924 ProcessParameters
->Environment
= NULL
;
925 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
926 (PVOID
*)&ProcessParameters
->Environment
,
931 if (!NT_SUCCESS(Status
)) goto FailPath
;
933 /* Write the Environment Block */
934 Status
= ZwWriteVirtualMemory(ProcessHandle
,
935 ProcessParameters
->Environment
,
940 /* No longer need the PEB lock anymore */
948 /* Check if the write failed */
949 if (!NT_SUCCESS(Status
)) goto FailPath
;
952 /* Write new parameters */
953 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
954 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
955 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
956 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
957 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
958 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
959 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
960 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
961 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
963 /* Write the handles only if we have to */
964 if (StartupInfo
->dwFlags
&
965 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
967 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
968 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
969 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
972 /* Use Special Flags for ConDllInitialize in Kernel32 */
973 if (CreationFlags
& DETACHED_PROCESS
)
975 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
977 else if (CreationFlags
& CREATE_NO_WINDOW
)
979 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
981 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
983 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
987 /* Inherit our Console Handle */
988 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
990 /* Make sure that the shell isn't trampling on our handles first */
991 if (!(StartupInfo
->dwFlags
&
992 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
994 /* Copy the handle if we are inheriting or if it's a console handle */
995 if ((InheritHandles
) ||
996 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
998 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
1000 if ((InheritHandles
) ||
1001 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
1003 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
1005 if ((InheritHandles
) ||
1006 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
1008 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
1013 /* Also set the Console Flag */
1014 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
1015 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
1017 ProcessParameters
->ConsoleFlags
= 1;
1020 /* See if the first 1MB should be reserved */
1021 if (ParameterFlags
& 1)
1023 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB
;
1026 /* See if the first 16MB should be reserved */
1027 if (ParameterFlags
& 2)
1029 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB
;
1032 /* Allocate memory for the parameter block */
1033 Size
= ProcessParameters
->Length
;
1034 RemoteParameters
= NULL
;
1035 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1036 (PVOID
*)&RemoteParameters
,
1041 if (!NT_SUCCESS(Status
)) goto FailPath
;
1043 /* Set the allocated size */
1044 ProcessParameters
->MaximumLength
= Size
;
1046 /* Handle some Parameter Flags */
1047 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
1048 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
1049 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
1050 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
1051 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
1052 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
1053 ProcessParameters
->Flags
|= (NtCurrentPeb()->ProcessParameters
->Flags
&
1054 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
1056 /* Write the Parameter Block */
1057 Status
= NtWriteVirtualMemory(ProcessHandle
,
1060 ProcessParameters
->Length
,
1062 if (!NT_SUCCESS(Status
)) goto FailPath
;
1064 /* Write the PEB Pointer */
1065 Status
= NtWriteVirtualMemory(ProcessHandle
,
1066 &RemotePeb
->ProcessParameters
,
1070 if (!NT_SUCCESS(Status
)) goto FailPath
;
1072 /* Check if there's any app compat data to write */
1073 RemoteAppCompatData
= NULL
;
1076 /* Allocate some space for the application compatibility data */
1077 Size
= AppCompatDataSize
;
1078 Status
= NtAllocateVirtualMemory(ProcessHandle
,
1079 &RemoteAppCompatData
,
1084 if (!NT_SUCCESS(Status
)) goto FailPath
;
1086 /* Write the application compatibility data */
1087 Status
= NtWriteVirtualMemory(ProcessHandle
,
1088 RemoteAppCompatData
,
1092 if (!NT_SUCCESS(Status
)) goto FailPath
;
1095 /* Write the PEB Pointer to the app compat data (might be NULL) */
1096 Status
= NtWriteVirtualMemory(ProcessHandle
,
1097 &RemotePeb
->pShimData
,
1098 &RemoteAppCompatData
,
1101 if (!NT_SUCCESS(Status
)) goto FailPath
;
1103 /* Now write Peb->ImageSubSystem */
1106 NtWriteVirtualMemory(ProcessHandle
,
1107 &RemotePeb
->ImageSubsystem
,
1109 sizeof(ImageSubsystem
),
1118 if (HavePebLock
) RtlReleasePebLock();
1119 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
1120 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
1123 DPRINT1("Failure to create proecss parameters: %lx\n", Status
);
1124 BaseSetLastNTError(Status
);
1131 InitCommandLines(VOID
)
1133 PRTL_USER_PROCESS_PARAMETERS Params
;
1135 /* get command line */
1136 Params
= NtCurrentPeb()->ProcessParameters
;
1137 RtlNormalizeProcessParams (Params
);
1139 /* initialize command line buffers */
1140 CommandLineStringW
.Length
= Params
->CommandLine
.Length
;
1141 CommandLineStringW
.MaximumLength
= CommandLineStringW
.Length
+ sizeof(WCHAR
);
1142 CommandLineStringW
.Buffer
= RtlAllocateHeap(GetProcessHeap(),
1143 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
1144 CommandLineStringW
.MaximumLength
);
1145 if (CommandLineStringW
.Buffer
== NULL
)
1150 RtlInitAnsiString(&CommandLineStringA
, NULL
);
1152 /* Copy command line */
1153 RtlCopyUnicodeString(&CommandLineStringW
,
1154 &(Params
->CommandLine
));
1155 CommandLineStringW
.Buffer
[CommandLineStringW
.Length
/ sizeof(WCHAR
)] = 0;
1157 /* convert unicode string to ansi (or oem) */
1159 RtlUnicodeStringToAnsiString(&CommandLineStringA
,
1160 &CommandLineStringW
,
1163 RtlUnicodeStringToOemString(&CommandLineStringA
,
1164 &CommandLineStringW
,
1167 CommandLineStringA
.Buffer
[CommandLineStringA
.Length
] = 0;
1169 bCommandLineInitialized
= TRUE
;
1177 GetProcessAffinityMask(HANDLE hProcess
,
1178 PDWORD_PTR lpProcessAffinityMask
,
1179 PDWORD_PTR lpSystemAffinityMask
)
1181 PROCESS_BASIC_INFORMATION ProcessInfo
;
1182 SYSTEM_BASIC_INFORMATION SystemInfo
;
1185 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1189 if (!NT_SUCCESS(Status
))
1191 BaseSetLastNTError(Status
);
1195 Status
= NtQueryInformationProcess(hProcess
,
1196 ProcessBasicInformation
,
1197 (PVOID
)&ProcessInfo
,
1198 sizeof(PROCESS_BASIC_INFORMATION
),
1200 if (!NT_SUCCESS(Status
))
1202 BaseSetLastNTError(Status
);
1206 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
1207 *lpSystemAffinityMask
= (DWORD
)SystemInfo
.ActiveProcessorsAffinityMask
;
1218 SetProcessAffinityMask(HANDLE hProcess
,
1219 DWORD_PTR dwProcessAffinityMask
)
1223 Status
= NtSetInformationProcess(hProcess
,
1224 ProcessAffinityMask
,
1225 (PVOID
)&dwProcessAffinityMask
,
1227 if (!NT_SUCCESS(Status
))
1229 BaseSetLastNTError(Status
);
1242 GetProcessShutdownParameters(LPDWORD lpdwLevel
,
1245 CSR_API_MESSAGE CsrRequest
;
1249 Request
= GET_SHUTDOWN_PARAMETERS
;
1250 Status
= CsrClientCallServer(&CsrRequest
,
1252 MAKE_CSR_API(Request
, CSR_NATIVE
),
1253 sizeof(CSR_API_MESSAGE
));
1254 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1256 BaseSetLastNTError(Status
);
1260 *lpdwLevel
= CsrRequest
.Data
.GetShutdownParametersRequest
.Level
;
1261 *lpdwFlags
= CsrRequest
.Data
.GetShutdownParametersRequest
.Flags
;
1272 SetProcessShutdownParameters(DWORD dwLevel
,
1275 CSR_API_MESSAGE CsrRequest
;
1279 CsrRequest
.Data
.SetShutdownParametersRequest
.Level
= dwLevel
;
1280 CsrRequest
.Data
.SetShutdownParametersRequest
.Flags
= dwFlags
;
1282 Request
= SET_SHUTDOWN_PARAMETERS
;
1283 Status
= CsrClientCallServer(&CsrRequest
,
1285 MAKE_CSR_API(Request
, CSR_NATIVE
),
1286 sizeof(CSR_API_MESSAGE
));
1287 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1289 BaseSetLastNTError(Status
);
1302 GetProcessWorkingSetSize(HANDLE hProcess
,
1303 PSIZE_T lpMinimumWorkingSetSize
,
1304 PSIZE_T lpMaximumWorkingSetSize
)
1306 QUOTA_LIMITS QuotaLimits
;
1309 Status
= NtQueryInformationProcess(hProcess
,
1312 sizeof(QUOTA_LIMITS
),
1314 if (!NT_SUCCESS(Status
))
1316 BaseSetLastNTError(Status
);
1320 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1321 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1332 SetProcessWorkingSetSize(HANDLE hProcess
,
1333 SIZE_T dwMinimumWorkingSetSize
,
1334 SIZE_T dwMaximumWorkingSetSize
)
1336 QUOTA_LIMITS QuotaLimits
;
1339 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1340 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1342 Status
= NtSetInformationProcess(hProcess
,
1345 sizeof(QUOTA_LIMITS
));
1346 if (!NT_SUCCESS(Status
))
1348 BaseSetLastNTError(Status
);
1361 GetProcessTimes(HANDLE hProcess
,
1362 LPFILETIME lpCreationTime
,
1363 LPFILETIME lpExitTime
,
1364 LPFILETIME lpKernelTime
,
1365 LPFILETIME lpUserTime
)
1367 KERNEL_USER_TIMES Kut
;
1370 Status
= NtQueryInformationProcess(hProcess
,
1375 if (!NT_SUCCESS(Status
))
1377 BaseSetLastNTError(Status
);
1381 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1382 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1384 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1385 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1387 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1388 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1390 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1391 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1402 GetCurrentProcess(VOID
)
1404 return (HANDLE
)NtCurrentProcess();
1413 GetCurrentThread(VOID
)
1415 return (HANDLE
)NtCurrentThread();
1424 GetCurrentProcessId(VOID
)
1426 return HandleToUlong(GetTeb()->ClientId
.UniqueProcess
);
1435 GetExitCodeProcess(HANDLE hProcess
,
1438 PROCESS_BASIC_INFORMATION ProcessBasic
;
1441 Status
= NtQueryInformationProcess(hProcess
,
1442 ProcessBasicInformation
,
1444 sizeof(PROCESS_BASIC_INFORMATION
),
1446 if (!NT_SUCCESS(Status
))
1448 BaseSetLastNTError(Status
);
1452 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1463 GetProcessId(HANDLE Process
)
1465 PROCESS_BASIC_INFORMATION ProcessBasic
;
1468 Status
= NtQueryInformationProcess(Process
,
1469 ProcessBasicInformation
,
1471 sizeof(PROCESS_BASIC_INFORMATION
),
1473 if (!NT_SUCCESS(Status
))
1475 BaseSetLastNTError(Status
);
1479 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1488 OpenProcess(DWORD dwDesiredAccess
,
1489 BOOL bInheritHandle
,
1493 HANDLE ProcessHandle
;
1494 OBJECT_ATTRIBUTES ObjectAttributes
;
1497 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1498 ClientId
.UniqueThread
= 0;
1500 InitializeObjectAttributes(&ObjectAttributes
,
1502 (bInheritHandle
? OBJ_INHERIT
: 0),
1506 errCode
= NtOpenProcess(&ProcessHandle
,
1510 if (!NT_SUCCESS(errCode
))
1512 BaseSetLastNTError(errCode
);
1516 return ProcessHandle
;
1525 WinExec(LPCSTR lpCmdLine
,
1528 STARTUPINFOA StartupInfo
;
1529 PROCESS_INFORMATION ProcessInformation
;
1532 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1533 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
1534 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
1535 StartupInfo
.dwFlags
= 0;
1537 if (!CreateProcessA(NULL
,
1546 &ProcessInformation
))
1548 dosErr
= GetLastError();
1549 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
1552 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
1554 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
,
1558 NtClose(ProcessInformation
.hProcess
);
1559 NtClose(ProcessInformation
.hThread
);
1561 return 33; /* Something bigger than 31 means success. */
1570 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1572 lpfnGlobalRegisterWaitForInputIdle
= lpfnRegisterWaitForInputIdle
;
1581 GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo
)
1583 PRTL_USER_PROCESS_PARAMETERS Params
;
1585 if (lpStartupInfo
== NULL
)
1587 SetLastError(ERROR_INVALID_PARAMETER
);
1591 Params
= NtCurrentPeb()->ProcessParameters
;
1593 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1594 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1595 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1596 lpStartupInfo
->dwX
= Params
->StartingX
;
1597 lpStartupInfo
->dwY
= Params
->StartingY
;
1598 lpStartupInfo
->dwXSize
= Params
->CountX
;
1599 lpStartupInfo
->dwYSize
= Params
->CountY
;
1600 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1601 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1602 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1603 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1604 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1605 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1606 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1608 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1609 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1610 lpStartupInfo
->hStdError
= Params
->StandardError
;
1619 GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo
)
1621 PRTL_USER_PROCESS_PARAMETERS Params
;
1622 ANSI_STRING AnsiString
;
1624 if (lpStartupInfo
== NULL
)
1626 SetLastError(ERROR_INVALID_PARAMETER
);
1630 Params
= NtCurrentPeb ()->ProcessParameters
;
1632 RtlAcquirePebLock ();
1634 /* FIXME - not thread-safe */
1635 if (lpLocalStartupInfo
== NULL
)
1637 /* create new local startup info (ansi) */
1638 lpLocalStartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1640 sizeof(STARTUPINFOA
));
1641 if (lpLocalStartupInfo
== NULL
)
1643 RtlReleasePebLock();
1644 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1648 lpLocalStartupInfo
->cb
= sizeof(STARTUPINFOA
);
1650 /* copy window title string */
1651 RtlUnicodeStringToAnsiString(&AnsiString
,
1652 &Params
->WindowTitle
,
1654 lpLocalStartupInfo
->lpTitle
= AnsiString
.Buffer
;
1656 /* copy desktop info string */
1657 RtlUnicodeStringToAnsiString(&AnsiString
,
1658 &Params
->DesktopInfo
,
1660 lpLocalStartupInfo
->lpDesktop
= AnsiString
.Buffer
;
1662 /* copy shell info string */
1663 RtlUnicodeStringToAnsiString(&AnsiString
,
1666 lpLocalStartupInfo
->lpReserved
= AnsiString
.Buffer
;
1668 lpLocalStartupInfo
->dwX
= Params
->StartingX
;
1669 lpLocalStartupInfo
->dwY
= Params
->StartingY
;
1670 lpLocalStartupInfo
->dwXSize
= Params
->CountX
;
1671 lpLocalStartupInfo
->dwYSize
= Params
->CountY
;
1672 lpLocalStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1673 lpLocalStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1674 lpLocalStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1675 lpLocalStartupInfo
->dwFlags
= Params
->WindowFlags
;
1676 lpLocalStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1677 lpLocalStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1678 lpLocalStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1680 lpLocalStartupInfo
->hStdInput
= Params
->StandardInput
;
1681 lpLocalStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1682 lpLocalStartupInfo
->hStdError
= Params
->StandardError
;
1685 RtlReleasePebLock();
1687 /* copy local startup info data to external startup info */
1688 memcpy(lpStartupInfo
,
1690 sizeof(STARTUPINFOA
));
1699 FlushInstructionCache(HANDLE hProcess
,
1700 LPCVOID lpBaseAddress
,
1705 Status
= NtFlushInstructionCache(hProcess
,
1706 (PVOID
)lpBaseAddress
,
1708 if (!NT_SUCCESS(Status
))
1710 BaseSetLastNTError(Status
);
1723 ExitProcess(UINT uExitCode
)
1725 CSR_API_MESSAGE CsrRequest
;
1729 /* kill sibling threads ... we want to be alone at this point */
1730 NtTerminateProcess(NULL
, 0);
1732 /* unload all dll's */
1733 LdrShutdownProcess();
1735 /* notify csrss of process termination */
1736 Request
= TERMINATE_PROCESS
;
1737 Status
= CsrClientCallServer(&CsrRequest
,
1739 MAKE_CSR_API(Request
, CSR_NATIVE
),
1740 sizeof(CSR_API_MESSAGE
));
1741 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1743 DPRINT("Failed to tell csrss about terminating process\n");
1746 NtTerminateProcess(NtCurrentProcess (),
1749 /* should never get here */
1760 TerminateProcess(HANDLE hProcess
,
1765 if (hProcess
== NULL
)
1770 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1771 if (NT_SUCCESS(Status
))
1776 BaseSetLastNTError(Status
);
1786 FatalAppExitA(UINT uAction
,
1787 LPCSTR lpMessageText
)
1789 UNICODE_STRING MessageTextU
;
1790 ANSI_STRING MessageText
;
1792 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1794 RtlAnsiStringToUnicodeString(&MessageTextU
,
1798 FatalAppExitW(uAction
, MessageTextU
.Buffer
);
1800 RtlFreeUnicodeString(&MessageTextU
);
1809 FatalAppExitW(UINT uAction
,
1810 LPCWSTR lpMessageText
)
1812 static const WCHAR szUser32
[] = L
"user32.dll\0";
1814 HMODULE hModule
= GetModuleHandleW(szUser32
);
1815 MessageBoxW_Proc pMessageBoxW
= NULL
;
1817 DPRINT1("AppExit\n");
1820 pMessageBoxW
= (MessageBoxW_Proc
)GetProcAddress(hModule
, "MessageBoxW");
1823 pMessageBoxW(0, lpMessageText
, NULL
, MB_SYSTEMMODAL
| MB_OK
);
1825 DPRINT1("%s\n", lpMessageText
);
1836 FatalExit(int ExitCode
)
1838 ExitProcess(ExitCode
);
1847 GetPriorityClass(HANDLE hProcess
)
1850 PROCESS_PRIORITY_CLASS PriorityClass
;
1852 Status
= NtQueryInformationProcess(hProcess
,
1853 ProcessPriorityClass
,
1855 sizeof(PROCESS_PRIORITY_CLASS
),
1857 if(NT_SUCCESS(Status
))
1859 switch(PriorityClass
.PriorityClass
)
1861 case PROCESS_PRIORITY_CLASS_IDLE
:
1862 return IDLE_PRIORITY_CLASS
;
1864 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
:
1865 return BELOW_NORMAL_PRIORITY_CLASS
;
1867 case PROCESS_PRIORITY_CLASS_NORMAL
:
1868 return NORMAL_PRIORITY_CLASS
;
1870 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
:
1871 return ABOVE_NORMAL_PRIORITY_CLASS
;
1873 case PROCESS_PRIORITY_CLASS_HIGH
:
1874 return HIGH_PRIORITY_CLASS
;
1876 case PROCESS_PRIORITY_CLASS_REALTIME
:
1877 return REALTIME_PRIORITY_CLASS
;
1880 return NORMAL_PRIORITY_CLASS
;
1884 BaseSetLastNTError(Status
);
1894 SetPriorityClass(HANDLE hProcess
,
1895 DWORD dwPriorityClass
)
1898 PROCESS_PRIORITY_CLASS PriorityClass
;
1900 switch (dwPriorityClass
)
1902 case IDLE_PRIORITY_CLASS
:
1903 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1906 case BELOW_NORMAL_PRIORITY_CLASS
:
1907 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1910 case NORMAL_PRIORITY_CLASS
:
1911 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1914 case ABOVE_NORMAL_PRIORITY_CLASS
:
1915 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1918 case HIGH_PRIORITY_CLASS
:
1919 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1922 case REALTIME_PRIORITY_CLASS
:
1923 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
1927 SetLastError(ERROR_INVALID_PARAMETER
);
1931 PriorityClass
.Foreground
= FALSE
;
1933 Status
= NtSetInformationProcess(hProcess
,
1934 ProcessPriorityClass
,
1936 sizeof(PROCESS_PRIORITY_CLASS
));
1937 if (!NT_SUCCESS(Status
))
1939 BaseSetLastNTError(Status
);
1952 GetProcessVersion(DWORD ProcessId
)
1955 PIMAGE_NT_HEADERS NtHeader
= NULL
;
1956 IMAGE_NT_HEADERS NtHeaders
;
1957 IMAGE_DOS_HEADER DosHeader
;
1958 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1959 PVOID BaseAddress
= NULL
;
1960 HANDLE ProcessHandle
= NULL
;
1967 if (0 == ProcessId
|| GetCurrentProcessId() == ProcessId
)
1970 BaseAddress
= (PVOID
) NtCurrentPeb()->ImageBaseAddress
;
1971 NtHeader
= RtlImageNtHeader(BaseAddress
);
1973 Version
= (NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
<< 16) |
1974 (NtHeader
->OptionalHeader
.MinorOperatingSystemVersion
);
1979 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1983 if (!ProcessHandle
) return 0;
1985 Status
= NtQueryInformationProcess(ProcessHandle
,
1986 ProcessBasicInformation
,
1988 sizeof(ProcessBasicInfo
),
1991 if (!NT_SUCCESS(Status
)) goto Error
;
1993 Status
= NtReadVirtualMemory(ProcessHandle
,
1994 ProcessBasicInfo
.PebBaseAddress
,
1999 if (!NT_SUCCESS(Status
) || Count
!= sizeof(Peb
)) goto Error
;
2001 memset(&DosHeader
, 0, sizeof(DosHeader
));
2002 Status
= NtReadVirtualMemory(ProcessHandle
,
2003 Peb
.ImageBaseAddress
,
2008 if (!NT_SUCCESS(Status
) || Count
!= sizeof(DosHeader
)) goto Error
;
2009 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) goto Error
;
2011 memset(&NtHeaders
, 0, sizeof(NtHeaders
));
2012 Status
= NtReadVirtualMemory(ProcessHandle
,
2013 (char *)Peb
.ImageBaseAddress
+ DosHeader
.e_lfanew
,
2018 if (!NT_SUCCESS(Status
) || Count
!= sizeof(NtHeaders
)) goto Error
;
2019 if (NtHeaders
.Signature
!= IMAGE_NT_SIGNATURE
) goto Error
;
2021 Version
= MAKELONG(NtHeaders
.OptionalHeader
.MinorSubsystemVersion
,
2022 NtHeaders
.OptionalHeader
.MajorSubsystemVersion
);
2025 if (!NT_SUCCESS(Status
))
2027 BaseSetLastNTError(Status
);
2033 if (ProcessHandle
) CloseHandle(ProcessHandle
);
2046 GetProcessIoCounters(HANDLE hProcess
,
2047 PIO_COUNTERS lpIoCounters
)
2051 Status
= NtQueryInformationProcess(hProcess
,
2054 sizeof(IO_COUNTERS
),
2056 if (!NT_SUCCESS(Status
))
2058 BaseSetLastNTError(Status
);
2071 GetProcessPriorityBoost(HANDLE hProcess
,
2072 PBOOL pDisablePriorityBoost
)
2075 ULONG PriorityBoost
;
2077 Status
= NtQueryInformationProcess(hProcess
,
2078 ProcessPriorityBoost
,
2082 if (NT_SUCCESS(Status
))
2084 *pDisablePriorityBoost
= PriorityBoost
;
2088 BaseSetLastNTError(Status
);
2098 SetProcessPriorityBoost(HANDLE hProcess
,
2099 BOOL bDisablePriorityBoost
)
2102 ULONG PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
); /* prevent setting values other than 1 and 0 */
2104 Status
= NtSetInformationProcess(hProcess
,
2105 ProcessPriorityBoost
,
2108 if (!NT_SUCCESS(Status
))
2110 BaseSetLastNTError(Status
);
2123 GetProcessHandleCount(HANDLE hProcess
,
2124 PDWORD pdwHandleCount
)
2129 Status
= NtQueryInformationProcess(hProcess
,
2134 if(NT_SUCCESS(Status
))
2136 *pdwHandleCount
= phc
;
2140 BaseSetLastNTError(Status
);
2150 IsWow64Process(HANDLE hProcess
,
2156 Status
= NtQueryInformationProcess(hProcess
,
2157 ProcessWow64Information
,
2161 if (!NT_SUCCESS(Status
))
2163 SetLastError(RtlNtStatusToDosError(Status
));
2167 *Wow64Process
= (pbi
!= 0);
2177 GetCommandLineA(VOID
)
2179 DPRINT("CommandLine \'%s\'\n", CommandLineStringA
.Buffer
);
2180 return CommandLineStringA
.Buffer
;
2189 GetCommandLineW(VOID
)
2191 DPRINT("CommandLine \'%S\'\n", CommandLineStringW
.Buffer
);
2192 return CommandLineStringW
.Buffer
;
2200 ReadProcessMemory(IN HANDLE hProcess
,
2201 IN LPCVOID lpBaseAddress
,
2204 OUT SIZE_T
* lpNumberOfBytesRead
)
2209 Status
= NtReadVirtualMemory(hProcess
,
2210 (PVOID
)lpBaseAddress
,
2213 lpNumberOfBytesRead
);
2214 if (!NT_SUCCESS(Status
))
2217 BaseSetLastNTError (Status
);
2221 /* Return success */
2230 WriteProcessMemory(IN HANDLE hProcess
,
2231 IN LPVOID lpBaseAddress
,
2232 IN LPCVOID lpBuffer
,
2234 OUT SIZE_T
*lpNumberOfBytesWritten
)
2242 /* Set parameters for protect call */
2244 Base
= lpBaseAddress
;
2246 /* Check the current status */
2247 Status
= NtProtectVirtualMemory(hProcess
,
2250 PAGE_EXECUTE_READWRITE
,
2252 if (NT_SUCCESS(Status
))
2254 /* Check if we are unprotecting */
2255 UnProtect
= OldValue
& (PAGE_READWRITE
|
2257 PAGE_EXECUTE_READWRITE
|
2258 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2261 /* Set the new protection */
2262 Status
= NtProtectVirtualMemory(hProcess
,
2268 /* Write the memory */
2269 Status
= NtWriteVirtualMemory(hProcess
,
2273 lpNumberOfBytesWritten
);
2274 if (!NT_SUCCESS(Status
))
2277 BaseSetLastNTError(Status
);
2281 /* Flush the ITLB */
2282 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2287 /* Check if we were read only */
2288 if ((OldValue
& PAGE_NOACCESS
) || (OldValue
& PAGE_READONLY
))
2290 /* Restore protection and fail */
2291 NtProtectVirtualMemory(hProcess
,
2296 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2300 /* Otherwise, do the write */
2301 Status
= NtWriteVirtualMemory(hProcess
,
2305 lpNumberOfBytesWritten
);
2307 /* And restore the protection */
2308 NtProtectVirtualMemory(hProcess
,
2313 if (!NT_SUCCESS(Status
))
2316 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2320 /* Flush the ITLB */
2321 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2328 BaseSetLastNTError(Status
);
2338 ProcessIdToSessionId(IN DWORD dwProcessId
,
2339 OUT DWORD
*pSessionId
)
2341 PROCESS_SESSION_INFORMATION SessionInformation
;
2342 OBJECT_ATTRIBUTES ObjectAttributes
;
2344 HANDLE ProcessHandle
;
2347 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2349 SetLastError(ERROR_INVALID_PARAMETER
);
2353 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2354 ClientId
.UniqueThread
= 0;
2356 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2358 Status
= NtOpenProcess(&ProcessHandle
,
2359 PROCESS_QUERY_INFORMATION
,
2362 if (NT_SUCCESS(Status
))
2364 Status
= NtQueryInformationProcess(ProcessHandle
,
2365 ProcessSessionInformation
,
2366 &SessionInformation
,
2367 sizeof(SessionInformation
),
2369 NtClose(ProcessHandle
);
2371 if (NT_SUCCESS(Status
))
2373 *pSessionId
= SessionInformation
.SessionId
;
2378 BaseSetLastNTError(Status
);
2384 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
2385 IN SIZE_T dwMinimumWorkingSetSize
,
2386 IN SIZE_T dwMaximumWorkingSetSize
,
2396 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
2397 OUT PSIZE_T lpMinimumWorkingSetSize
,
2398 OUT PSIZE_T lpMaximumWorkingSetSize
,
2410 CreateProcessInternalW(HANDLE hToken
,
2411 LPCWSTR lpApplicationName
,
2412 LPWSTR lpCommandLine
,
2413 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2414 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2415 BOOL bInheritHandles
,
2416 DWORD dwCreationFlags
,
2417 LPVOID lpEnvironment
,
2418 LPCWSTR lpCurrentDirectory
,
2419 LPSTARTUPINFOW lpStartupInfo
,
2420 LPPROCESS_INFORMATION lpProcessInformation
,
2424 PROCESS_PRIORITY_CLASS PriorityClass
;
2425 BOOLEAN FoundQuotes
= FALSE
;
2426 BOOLEAN QuotesNeeded
= FALSE
;
2427 BOOLEAN CmdLineIsAppName
= FALSE
;
2428 UNICODE_STRING ApplicationName
= { 0, 0, NULL
};
2429 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2430 POBJECT_ATTRIBUTES ObjectAttributes
;
2431 HANDLE hSection
= NULL
, hProcess
= NULL
, hThread
= NULL
, hDebug
= NULL
;
2432 SECTION_IMAGE_INFORMATION SectionImageInfo
;
2433 LPWSTR CurrentDirectory
= NULL
;
2434 LPWSTR CurrentDirectoryPart
;
2435 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2436 STARTUPINFOW StartupInfo
;
2438 LPWSTR BatchCommandLine
;
2439 ULONG CmdLineLength
;
2440 UNICODE_STRING CommandLineString
;
2442 LPWSTR QuotedCmdLine
= NULL
;
2444 LPWSTR NullBuffer
= NULL
;
2445 LPWSTR NameBuffer
= NULL
;
2449 BOOLEAN SearchDone
= FALSE
;
2450 BOOLEAN Escape
= FALSE
;
2452 PPEB OurPeb
= NtCurrentPeb();
2457 /* FIXME should process
2458 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2459 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2462 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2463 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2464 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
2467 /* Flags we don't handle yet */
2468 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
2470 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2472 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
2474 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2476 if (dwCreationFlags
& CREATE_FORCEDOS
)
2478 DPRINT1("CREATE_FORCEDOS not handled\n");
2481 /* Fail on this flag, it's only valid with the WithLogonW function */
2482 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
2484 DPRINT1("Invalid flag used\n");
2485 SetLastError(ERROR_INVALID_PARAMETER
);
2489 /* This combination is illegal (see MSDN) */
2490 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2491 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2493 DPRINT1("Invalid flag combo used\n");
2494 SetLastError(ERROR_INVALID_PARAMETER
);
2498 /* Another illegal combo */
2499 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
2500 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
2502 DPRINT1("Invalid flag combo used\n");
2503 SetLastError(ERROR_INVALID_PARAMETER
);
2507 if (lpCurrentDirectory
)
2509 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
2510 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
2512 SetLastError(ERROR_DIRECTORY
);
2518 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2519 * so we'll use our own local copy for that.
2521 StartupInfo
= *lpStartupInfo
;
2523 /* FIXME: Use default Separate/Shared VDM Flag */
2525 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2526 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
2528 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
2530 /* Remove the shared flag and add the separate flag. */
2531 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2532 CREATE_SEPARATE_WOW_VDM
;
2537 * According to some sites, ShellExecuteEx uses an undocumented flag to
2538 * send private handle data (such as HMONITOR or HICON). See:
2539 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2540 * standard handles anymore since we'd be overwriting this private data
2542 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2543 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2545 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2548 /* Start by zeroing out the fields */
2549 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
2551 /* Easy stuff first, convert the process priority class */
2552 PriorityClass
.Foreground
= FALSE
;
2553 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
2557 /* Search for escape sequences */
2558 ScanString
= lpCommandLine
;
2559 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2562 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\"')
2570 /* Get the application name and do all the proper formating necessary */
2572 /* See if we have an application name (oh please let us have one!) */
2573 if (!lpApplicationName
)
2575 /* The fun begins */
2576 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2578 MAX_PATH
* sizeof(WCHAR
));
2579 if (NameBuffer
== NULL
)
2581 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2585 /* This is all we have to work with :( */
2586 lpApplicationName
= lpCommandLine
;
2588 /* Initialize our friends at the beginning */
2589 NullBuffer
= (LPWSTR
)lpApplicationName
;
2590 ScanString
= (LPWSTR
)lpApplicationName
;
2592 /* We will start by looking for a quote */
2593 if (*ScanString
== L
'\"')
2595 /* That was quick */
2598 /* Advance past quote */
2600 lpApplicationName
= ScanString
;
2602 /* Find the closing quote */
2605 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
2608 NullBuffer
= ScanString
;
2615 NullBuffer
= ScanString
;
2620 /* No quotes, so we'll be looking for white space */
2622 /* Reset the pointer */
2623 lpApplicationName
= lpCommandLine
;
2625 /* Find whitespace of Tab */
2628 if (*ScanString
== ' ' || *ScanString
== '\t')
2631 NullBuffer
= ScanString
;
2637 NullBuffer
= ScanString
;
2641 /* Set the Null Buffer */
2642 SaveChar
= *NullBuffer
;
2643 *NullBuffer
= UNICODE_NULL
;
2645 /* Do a search for the file */
2646 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
2647 RetVal
= SearchPathW(NULL
,
2652 NULL
) * sizeof(WCHAR
);
2654 /* Did it find something? */
2657 /* Get file attributes */
2658 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
2659 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2661 /* Give it a length of 0 to fail, this was a directory. */
2667 RetVal
+= sizeof(WCHAR
);
2671 /* Now check if we have a file, and if the path size is OK */
2672 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
2677 /* We failed, try to get the Path Type */
2678 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
2679 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2681 /* If it's not relative, try to get the error */
2682 if (PathType
!= RtlPathTypeRelative
)
2684 /* This should fail, and give us a detailed LastError */
2685 hFile
= CreateFileW(lpApplicationName
,
2687 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2690 FILE_ATTRIBUTE_NORMAL
,
2693 /* Did it actually NOT fail? */
2694 if (hFile
!= INVALID_HANDLE_VALUE
)
2696 /* Fake the error */
2698 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2703 /* Immediately set the error */
2704 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2707 /* Did we already fail once? */
2710 SetLastError(Error
);
2714 /* Not yet, cache it */
2715 Error
= GetLastError();
2718 /* Put back the command line */
2719 *NullBuffer
= SaveChar
;
2720 lpApplicationName
= NameBuffer
;
2723 * If the search isn't done and we still have cmdline
2724 * then start over. Ex: c:\ha ha ha\haha.exe
2726 if (*ScanString
&& !SearchDone
)
2728 /* Move in the buffer */
2730 NullBuffer
= ScanString
;
2732 /* We will have to add a quote, since there is a space*/
2733 QuotesNeeded
= TRUE
;
2735 /* And we will also fake the fact we found one */
2742 /* We totally failed */
2746 /* Put back the command line */
2747 *NullBuffer
= SaveChar
;
2748 lpApplicationName
= NameBuffer
;
2749 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
2751 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
2753 /* We have an app name (good!) but no command line */
2754 CmdLineIsAppName
= TRUE
;
2755 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2758 /* At this point the name has been toyed with enough to be openable */
2759 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
2761 /* Check for failure */
2762 if (!NT_SUCCESS(Status
))
2764 /* Could be a non-PE File */
2767 /* Check if the Kernel tells us it's not even valid MZ */
2768 case STATUS_INVALID_IMAGE_NE_FORMAT
:
2769 case STATUS_INVALID_IMAGE_PROTECT
:
2770 case STATUS_INVALID_IMAGE_NOT_MZ
:
2773 /* If it's a DOS app, use VDM */
2774 if ((BasepCheckDosApp(&ApplicationName
)))
2776 DPRINT1("Launching VDM...\n");
2777 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2778 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2779 return CreateProcessW(L
"ntvdm.exe",
2780 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2781 lpProcessAttributes
,
2788 lpProcessInformation
);
2791 /* It's a batch file */
2792 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
2795 /* Make sure the extensions are correct */
2796 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
2798 SetLastError(ERROR_BAD_EXE_FORMAT
);
2802 /* Calculate the length of the command line */
2803 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
2805 /* If we found quotes, then add them into the length size */
2806 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
2807 CmdLineLength
*= sizeof(WCHAR
);
2809 /* Allocate space for the new command line */
2810 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2813 if (BatchCommandLine
== NULL
)
2815 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2820 wcscpy(BatchCommandLine
, CMD_STRING
);
2821 if (CmdLineIsAppName
|| FoundQuotes
)
2823 wcscat(BatchCommandLine
, L
"\"");
2825 wcscat(BatchCommandLine
, lpCommandLine
);
2826 if (CmdLineIsAppName
|| FoundQuotes
)
2828 wcscat(BatchCommandLine
, L
"\"");
2831 /* Create it as a Unicode String */
2832 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
2834 /* Set the command line to this */
2835 lpCommandLine
= CommandLineString
.Buffer
;
2836 lpApplicationName
= NULL
;
2839 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2840 ApplicationName
.Buffer
= NULL
;
2844 case STATUS_INVALID_IMAGE_WIN_16
:
2846 /* It's a Win16 Image, use VDM */
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
);
2861 case STATUS_OBJECT_NAME_NOT_FOUND
:
2862 case STATUS_OBJECT_PATH_NOT_FOUND
:
2863 BaseSetLastNTError(Status
);
2867 /* Invalid Image Type */
2868 SetLastError(ERROR_BAD_EXE_FORMAT
);
2873 /* Use our desktop if we didn't get any */
2874 if (!StartupInfo
.lpDesktop
)
2876 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
2879 /* FIXME: Check if Application is allowed to run */
2881 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2883 /* Get some information about the executable */
2884 Status
= ZwQuerySection(hSection
,
2885 SectionImageInformation
,
2887 sizeof(SectionImageInfo
),
2889 if(!NT_SUCCESS(Status
))
2891 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
2892 BaseSetLastNTError(Status
);
2896 /* Don't execute DLLs */
2897 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
2899 DPRINT1("Can't execute a DLL\n");
2900 SetLastError(ERROR_BAD_EXE_FORMAT
);
2904 /* FIXME: Check for Debugger */
2906 /* FIXME: Check if Machine Type and SubSys Version Match */
2908 /* We don't support POSIX or anything else for now */
2909 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= SectionImageInfo
.SubSystemType
&&
2910 IMAGE_SUBSYSTEM_WINDOWS_CUI
!= SectionImageInfo
.SubSystemType
)
2912 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
2913 SetLastError(ERROR_BAD_EXE_FORMAT
);
2917 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
2919 /* Do not create a console for GUI applications */
2920 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
2921 dwCreationFlags
|= DETACHED_PROCESS
;
2924 /* Initialize the process object attributes */
2925 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
2926 lpProcessAttributes
,
2929 /* Check if we're going to be debugged */
2930 if (dwCreationFlags
& DEBUG_PROCESS
)
2932 /* FIXME: Set process flag */
2935 /* Check if we're going to be debugged */
2936 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
2938 /* Connect to DbgUi */
2939 Status
= DbgUiConnectToDbg();
2940 if (!NT_SUCCESS(Status
))
2942 DPRINT1("Failed to connect to DbgUI!\n");
2943 BaseSetLastNTError(Status
);
2947 /* Get the debug object */
2948 hDebug
= DbgUiGetThreadDebugObject();
2950 /* Check if only this process will be debugged */
2951 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
2953 /* FIXME: Set process flag */
2957 /* Create the Process */
2958 Status
= NtCreateProcess(&hProcess
,
2962 (BOOLEAN
)bInheritHandles
,
2966 if (!NT_SUCCESS(Status
))
2968 DPRINT1("Unable to create process, status 0x%x\n", Status
);
2969 BaseSetLastNTError(Status
);
2973 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
2976 Status
= NtSetInformationProcess(hProcess
,
2977 ProcessPriorityClass
,
2979 sizeof(PROCESS_PRIORITY_CLASS
));
2980 if(!NT_SUCCESS(Status
))
2982 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
2983 BaseSetLastNTError(Status
);
2988 /* Set Error Mode */
2989 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
2991 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
2992 NtSetInformationProcess(hProcess
,
2993 ProcessDefaultHardErrorMode
,
2998 /* Convert the directory to a full path */
2999 if (lpCurrentDirectory
)
3001 /* Allocate a buffer */
3002 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
3004 (MAX_PATH
+ 1) * sizeof(WCHAR
));
3005 if (CurrentDirectory
== NULL
)
3007 DPRINT1("Cannot allocate memory for directory name\n");
3008 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3012 /* Get the length */
3013 if (GetFullPathNameW(lpCurrentDirectory
,
3016 &CurrentDirectoryPart
) > MAX_PATH
)
3018 DPRINT1("Directory name too long\n");
3019 SetLastError(ERROR_DIRECTORY
);
3024 /* Insert quotes if needed */
3025 if (QuotesNeeded
|| CmdLineIsAppName
)
3027 /* Allocate a buffer */
3028 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3030 (wcslen(lpCommandLine
) + 2 + 1) *
3032 if (QuotedCmdLine
== NULL
)
3034 DPRINT1("Cannot allocate memory for quoted command line\n");
3035 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3039 /* Copy the first quote */
3040 wcscpy(QuotedCmdLine
, L
"\"");
3042 /* Save a null char */
3045 SaveChar
= *NullBuffer
;
3046 *NullBuffer
= UNICODE_NULL
;
3049 /* Add the command line and the finishing quote */
3050 wcscat(QuotedCmdLine
, lpCommandLine
);
3051 wcscat(QuotedCmdLine
, L
"\"");
3053 /* Add the null char */
3056 *NullBuffer
= SaveChar
;
3057 wcscat(QuotedCmdLine
, NullBuffer
);
3060 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
3065 if (QuotedCmdLine
== NULL
)
3067 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3069 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
3070 if (QuotedCmdLine
== NULL
)
3072 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3075 wcscpy(QuotedCmdLine
, lpCommandLine
);
3078 ScanString
= QuotedCmdLine
;
3079 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
3082 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
3084 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
3089 /* Get the Process Information */
3090 Status
= NtQueryInformationProcess(hProcess
,
3091 ProcessBasicInformation
,
3093 sizeof(ProcessBasicInfo
),
3096 /* Convert the environment */
3097 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3099 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
3100 if (!lpEnvironment
) goto Cleanup
;
3103 /* Create Process Environment */
3104 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
3105 Ret
= BasePushProcessParameters(0,
3108 (LPWSTR
)lpApplicationName
,
3110 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
3111 QuotedCmdLine
: lpCommandLine
,
3119 if (!Ret
) goto Cleanup
;
3121 /* Cleanup Environment */
3122 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3124 RtlDestroyEnvironment(lpEnvironment
);
3127 /* Close the section */
3131 /* Duplicate the handles if needed */
3132 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
3133 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
3135 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
3137 /* Get the remote parameters */
3138 Status
= NtReadVirtualMemory(hProcess
,
3139 &RemotePeb
->ProcessParameters
,
3143 if (!NT_SUCCESS(Status
))
3145 DPRINT1("Failed to read memory\n");
3149 /* Duplicate and write the handles */
3150 BasepDuplicateAndWriteHandle(hProcess
,
3151 OurPeb
->ProcessParameters
->StandardInput
,
3152 &RemoteParameters
->StandardInput
);
3153 BasepDuplicateAndWriteHandle(hProcess
,
3154 OurPeb
->ProcessParameters
->StandardOutput
,
3155 &RemoteParameters
->StandardOutput
);
3156 BasepDuplicateAndWriteHandle(hProcess
,
3157 OurPeb
->ProcessParameters
->StandardError
,
3158 &RemoteParameters
->StandardError
);
3162 Status
= BasepNotifyCsrOfCreation(dwCreationFlags
,
3163 (HANDLE
)ProcessBasicInfo
.UniqueProcessId
,
3166 if (!NT_SUCCESS(Status
))
3168 DPRINT1("CSR Notification Failed\n");
3169 BaseSetLastNTError(Status
);
3173 /* Create the first thread */
3174 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
3175 SectionImageInfo
.TransferAddress
);
3176 hThread
= BasepCreateFirstThread(hProcess
,
3181 if (hThread
== NULL
)
3183 DPRINT1("Could not create Initial Thread\n");
3184 /* FIXME - set last error code */
3188 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
3190 NtResumeThread(hThread
, &Dummy
);
3194 lpProcessInformation
->dwProcessId
= (DWORD
)ClientId
.UniqueProcess
;
3195 lpProcessInformation
->dwThreadId
= (DWORD
)ClientId
.UniqueThread
;
3196 lpProcessInformation
->hProcess
= hProcess
;
3197 lpProcessInformation
->hThread
= hThread
;
3198 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread
,
3199 ClientId
.UniqueThread
, ClientId
.UniqueProcess
, hProcess
);
3200 hProcess
= hThread
= NULL
;
3204 /* De-allocate heap strings */
3205 if (NameBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3206 if (ApplicationName
.Buffer
)
3207 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
3208 if (CurrentDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
3209 if (QuotedCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
3211 /* Kill any handles still alive */
3212 if (hSection
) NtClose(hSection
);
3215 /* We don't know any more details then this */
3216 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
3219 if (hProcess
) NtClose(hProcess
);
3221 /* Return Success */
3230 CreateProcessW(LPCWSTR lpApplicationName
,
3231 LPWSTR lpCommandLine
,
3232 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3233 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3234 BOOL bInheritHandles
,
3235 DWORD dwCreationFlags
,
3236 LPVOID lpEnvironment
,
3237 LPCWSTR lpCurrentDirectory
,
3238 LPSTARTUPINFOW lpStartupInfo
,
3239 LPPROCESS_INFORMATION lpProcessInformation
)
3241 /* Call the internal (but exported) version */
3242 return CreateProcessInternalW(0,
3245 lpProcessAttributes
,
3252 lpProcessInformation
,
3261 CreateProcessInternalA(HANDLE hToken
,
3262 LPCSTR lpApplicationName
,
3263 LPSTR lpCommandLine
,
3264 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3265 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3266 BOOL bInheritHandles
,
3267 DWORD dwCreationFlags
,
3268 LPVOID lpEnvironment
,
3269 LPCSTR lpCurrentDirectory
,
3270 LPSTARTUPINFOA lpStartupInfo
,
3271 LPPROCESS_INFORMATION lpProcessInformation
,
3274 PUNICODE_STRING CommandLine
= NULL
;
3275 UNICODE_STRING DummyString
;
3276 UNICODE_STRING LiveCommandLine
;
3277 UNICODE_STRING ApplicationName
;
3278 UNICODE_STRING CurrentDirectory
;
3280 STARTUPINFOW StartupInfo
;
3282 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
3283 "lpStartupInfo %x, lpProcessInformation %x\n",
3284 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
3285 lpStartupInfo
, lpProcessInformation
);
3287 /* Copy Startup Info */
3288 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
3290 /* Initialize all strings to nothing */
3291 LiveCommandLine
.Buffer
= NULL
;
3292 DummyString
.Buffer
= NULL
;
3293 ApplicationName
.Buffer
= NULL
;
3294 CurrentDirectory
.Buffer
= NULL
;
3295 StartupInfo
.lpDesktop
= NULL
;
3296 StartupInfo
.lpReserved
= NULL
;
3297 StartupInfo
.lpTitle
= NULL
;
3299 /* Convert the Command line */
3302 /* If it's too long, then we'll have a problem */
3303 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
3304 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
3306 /* Cache it in the TEB */
3307 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
3311 /* Use a dynamic version */
3312 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
3318 /* The logic below will use CommandLine, so we must make it valid */
3319 CommandLine
= &DummyString
;
3322 /* Convert the Name and Directory */
3323 if (lpApplicationName
)
3325 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
3328 if (lpCurrentDirectory
)
3330 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
3331 lpCurrentDirectory
);
3334 /* Now convert Startup Strings */
3335 if (lpStartupInfo
->lpReserved
)
3337 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
3338 &StartupInfo
.lpReserved
);
3340 if (lpStartupInfo
->lpDesktop
)
3342 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
3343 &StartupInfo
.lpDesktop
);
3345 if (lpStartupInfo
->lpTitle
)
3347 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
3348 &StartupInfo
.lpTitle
);
3351 /* Call the Unicode function */
3352 bRetVal
= CreateProcessInternalW(hToken
,
3353 ApplicationName
.Buffer
,
3354 LiveCommandLine
.Buffer
?
3355 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
3356 lpProcessAttributes
,
3361 CurrentDirectory
.Buffer
,
3363 lpProcessInformation
,
3367 RtlFreeUnicodeString(&ApplicationName
);
3368 RtlFreeUnicodeString(&LiveCommandLine
);
3369 RtlFreeUnicodeString(&CurrentDirectory
);
3370 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
3371 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
3372 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
3374 /* Return what Unicode did */
3379 * FUNCTION: The CreateProcess function creates a new process and its
3380 * primary thread. The new process executes the specified executable file
3383 * lpApplicationName = Pointer to name of executable module
3384 * lpCommandLine = Pointer to command line string
3385 * lpProcessAttributes = Process security attributes
3386 * lpThreadAttributes = Thread security attributes
3387 * bInheritHandles = Handle inheritance flag
3388 * dwCreationFlags = Creation flags
3389 * lpEnvironment = Pointer to new environment block
3390 * lpCurrentDirectory = Pointer to current directory name
3391 * lpStartupInfo = Pointer to startup info
3392 * lpProcessInformation = Pointer to process information
3398 CreateProcessA(LPCSTR lpApplicationName
,
3399 LPSTR lpCommandLine
,
3400 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3401 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3402 BOOL bInheritHandles
,
3403 DWORD dwCreationFlags
,
3404 LPVOID lpEnvironment
,
3405 LPCSTR lpCurrentDirectory
,
3406 LPSTARTUPINFOA lpStartupInfo
,
3407 LPPROCESS_INFORMATION lpProcessInformation
)
3409 /* Call the internal (but exported) version */
3410 return CreateProcessInternalA(0,
3413 lpProcessAttributes
,
3420 lpProcessInformation
,