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 ****************************************************************/
20 typedef INT (WINAPI
*MessageBoxW_Proc
) (HWND
, LPCWSTR
, LPCWSTR
, UINT
);
22 /* GLOBALS *******************************************************************/
24 static UNICODE_STRING CommandLineStringW
;
25 static ANSI_STRING CommandLineStringA
;
27 static BOOL bCommandLineInitialized
= FALSE
;
29 WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle
;
31 LPSTARTUPINFOA lpLocalStartupInfo
= NULL
;
34 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
36 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
37 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
39 #define CMD_STRING L"cmd /c "
41 extern __declspec(noreturn
)
44 ConsoleControlDispatcher(DWORD CodeAndFlag
);
46 /* FUNCTIONS ****************************************************************/
49 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
51 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
53 if (GlobalTopLevelExceptionFilter
!= NULL
)
57 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
59 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
64 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
65 GlobalTopLevelExceptionFilter
!= UnhandledExceptionFilter
)
67 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
70 return ExceptionDisposition
;
75 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
79 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
83 /* Set our Start Address */
84 NtSetInformationThread(NtCurrentThread(),
85 ThreadQuerySetWin32StartAddress
,
87 sizeof(PPROCESS_START_ROUTINE
));
89 /* Call the Start Routine */
90 uExitCode
= (lpStartAddress
)();
92 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
94 /* Get the SEH Error */
95 uExitCode
= _SEH2_GetExceptionCode();
99 /* Exit the Process with our error */
100 ExitProcess(uExitCode
);
104 * Tells CSR that a new process was created
108 BasepNotifyCsrOfCreation(ULONG dwCreationFlags
,
110 IN BOOL InheritHandles
)
112 ULONG Request
= CREATE_PROCESS
;
113 CSR_API_MESSAGE CsrRequest
;
116 DPRINT("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
117 ProcessId
, dwCreationFlags
);
119 /* Fill out the request */
120 CsrRequest
.Data
.CreateProcessRequest
.NewProcessId
= ProcessId
;
121 CsrRequest
.Data
.CreateProcessRequest
.Flags
= dwCreationFlags
;
122 CsrRequest
.Data
.CreateProcessRequest
.bInheritHandles
= InheritHandles
;
125 Status
= CsrClientCallServer(&CsrRequest
,
127 MAKE_CSR_API(Request
, CSR_NATIVE
),
128 sizeof(CSR_API_MESSAGE
));
129 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
131 DPRINT1("Failed to tell csrss about new process\n");
132 return CsrRequest
.Status
;
136 return STATUS_SUCCESS
;
141 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
142 IN PCLIENT_ID ClientId
)
144 ULONG Request
= CREATE_THREAD
;
145 CSR_API_MESSAGE CsrRequest
;
148 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
149 ClientId
->UniqueThread
, ThreadHandle
);
151 /* Fill out the request */
152 CsrRequest
.Data
.CreateThreadRequest
.ClientId
= *ClientId
;
153 CsrRequest
.Data
.CreateThreadRequest
.ThreadHandle
= ThreadHandle
;
156 Status
= CsrClientCallServer(&CsrRequest
,
158 MAKE_CSR_API(Request
, CSR_NATIVE
),
159 sizeof(CSR_API_MESSAGE
));
160 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
162 DPRINT1("Failed to tell csrss about new thread\n");
163 return CsrRequest
.Status
;
167 return STATUS_SUCCESS
;
171 * Creates the first Thread in a Proces
175 BasepCreateFirstThread(HANDLE ProcessHandle
,
176 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
177 PSECTION_IMAGE_INFORMATION SectionImageInfo
,
180 OBJECT_ATTRIBUTES LocalObjectAttributes
;
181 POBJECT_ATTRIBUTES ObjectAttributes
;
183 INITIAL_TEB InitialTeb
;
187 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle
);
189 /* Create the Thread's Stack */
190 BasepCreateStack(ProcessHandle
,
191 SectionImageInfo
->MaximumStackSize
,
192 SectionImageInfo
->CommittedStackSize
,
195 /* Create the Thread's Context */
196 BasepInitializeContext(&Context
,
198 SectionImageInfo
->TransferAddress
,
199 InitialTeb
.StackBase
,
202 /* Convert the thread attributes */
203 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
207 /* Create the Kernel Thread Object */
208 Status
= NtCreateThread(&hThread
,
216 if (!NT_SUCCESS(Status
))
221 Status
= BasepNotifyCsrOfThread(hThread
, ClientId
);
222 if (!NT_SUCCESS(Status
))
232 * Converts ANSI to Unicode Environment
236 BasepConvertUnicodeEnvironment(OUT SIZE_T
* EnvSize
,
237 IN PVOID lpEnvironment
)
241 UNICODE_STRING UnicodeEnv
;
244 DPRINT("BasepConvertUnicodeEnvironment\n");
246 /* Scan the environment to calculate its Unicode size */
247 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
250 pcScan
+= strlen(pcScan
) + 1;
253 /* Create our ANSI String */
254 if (pcScan
== (PCHAR
)lpEnvironment
)
256 AnsiEnv
.Length
= 2 * sizeof(CHAR
);
261 AnsiEnv
.Length
= (USHORT
)((ULONG_PTR
)pcScan
- (ULONG_PTR
)lpEnvironment
+ sizeof(CHAR
));
263 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ 1;
265 /* Allocate memory for the Unicode Environment */
266 UnicodeEnv
.Buffer
= NULL
;
267 *EnvSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
268 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
269 (PVOID
)&UnicodeEnv
.Buffer
,
275 if (!NT_SUCCESS(Status
))
277 SetLastError(Status
);
282 /* Use the allocated size */
283 UnicodeEnv
.MaximumLength
= (USHORT
)*EnvSize
;
286 RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
287 return UnicodeEnv
.Buffer
;
291 * Converts a Win32 Priority Class to NT
295 BasepConvertPriorityClass(IN ULONG dwCreationFlags
)
299 if(dwCreationFlags
& IDLE_PRIORITY_CLASS
)
301 ReturnClass
= PROCESS_PRIORITY_CLASS_IDLE
;
303 else if(dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
305 ReturnClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
307 else if(dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
309 ReturnClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
311 else if(dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
313 ReturnClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
315 else if(dwCreationFlags
& HIGH_PRIORITY_CLASS
)
317 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
319 else if(dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
321 /* Check for Privilege First */
322 if (BasepCheckRealTimePrivilege())
324 ReturnClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
328 ReturnClass
= PROCESS_PRIORITY_CLASS_HIGH
;
333 ReturnClass
= PROCESS_PRIORITY_CLASS_INVALID
;
340 * Duplicates a standard handle and writes it where requested.
344 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle
,
345 IN HANDLE StandardHandle
,
349 HANDLE DuplicatedHandle
;
352 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
353 "Address: %p\n", ProcessHandle
, StandardHandle
, Address
);
355 /* Don't touch Console Handles */
356 if (IsConsoleHandle(StandardHandle
)) return;
358 /* Duplicate the handle */
359 Status
= NtDuplicateObject(NtCurrentProcess(),
363 DUPLICATE_SAME_ACCESS
| DUPLICATE_SAME_ATTRIBUTES
,
366 if (NT_SUCCESS(Status
))
369 NtWriteVirtualMemory(ProcessHandle
,
379 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry
,
381 OUT BOOLEAN
*StopEnumeration
)
383 /* Make sure we get Entry, Context and valid StopEnumeration pointer */
386 ASSERT(StopEnumeration
);
388 /* If entry is already found - signal to stop */
389 if (BasepExeLdrEntry
)
391 /* Signal to stop enumeration and return */
392 *StopEnumeration
= TRUE
;
396 /* We don't have a exe ldr entry, so try to see if this one is ours
397 by matching base address */
398 if (Entry
->DllBase
== Context
)
400 /* It matches, so remember the ldr entry */
401 BasepExeLdrEntry
= Entry
;
403 /* And stop enumeration */
404 *StopEnumeration
= TRUE
;
410 BasepGetProcessPath(DWORD Reserved
,
415 LPWSTR AllocatedPath
= NULL
, ch
;
416 ULONG DefaultLength
= BaseDefaultPath
.Length
;
418 UNICODE_STRING EnvPath
;
421 BOOLEAN SecondAttempt
= FALSE
;
422 PPEB Peb
= NtCurrentPeb();
424 if (!Environment
) RtlAcquirePebLock();
426 /* Query PATH env var into append path */
427 Status
= RtlQueryEnvironmentVariable_U(Environment
,
428 &BasePathVariableName
,
429 &BaseDefaultPathAppend
);
430 if (NT_SUCCESS(Status
))
432 /* Add up PATH environment length */
433 DefaultLength
+= BaseDefaultPathAppend
.Length
;
435 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
437 /* We have to allocate path dynamically */
438 AllocatedPath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDefaultPathAppend
.Length
+ sizeof(UNICODE_NULL
));
443 EnvPath
.Buffer
= AllocatedPath
;
444 EnvPath
.Length
= BaseDefaultPathAppend
.Length
+ sizeof(UNICODE_NULL
);
445 EnvPath
.MaximumLength
= EnvPath
.Length
;
447 /* Query PATH env var into newly allocated path */
448 Status
= RtlQueryEnvironmentVariable_U(Environment
,
449 &BasePathVariableName
,
452 if (NT_SUCCESS(Status
))
454 DefaultLength
+= EnvPath
.Length
;
458 /* Free newly allocated path, it didn't work */
459 RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath
);
460 AllocatedPath
= NULL
;
461 Status
= STATUS_NO_MEMORY
;
469 /* Initialize BasepExeLdrEntry if necessary */
470 if (!BasepExeLdrEntry
)
471 LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry
, Peb
->ImageBaseAddress
);
473 DPRINT("Found BasepExeLdrEntry %wZ\n", &BasepExeLdrEntry
->FullDllName
);
475 /* Set name pointer to the full dll path */
476 NamePtr
= BasepExeLdrEntry
->FullDllName
.Buffer
;
480 /* Set name pointer to the provided path */
484 /* Determine application path length */
490 /* Check if there is a slash */
493 /* Update app length */
494 AppLength
= (ULONG_PTR
)ch
- (ULONG_PTR
)NamePtr
+ sizeof(WCHAR
);
501 /* Now check, if we found a valid path in the provided full path */
502 if (!AppLength
&& FullPath
&& !SecondAttempt
)
504 /* We were provided with a bad full path, retry again using just this app's path */
506 SecondAttempt
= TRUE
;
510 /* Allocate the path buffer */
511 PathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, DefaultLength
+ AppLength
+ 2*sizeof(WCHAR
));
515 if (!Environment
) RtlReleasePebLock();
516 if (AllocatedPath
) RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath
);
520 /* Copy contents there */
523 /* Remove trailing slashes if it's not root dir */
524 if (AppLength
!= 3*sizeof(WCHAR
))
525 AppLength
-= sizeof(WCHAR
);
528 RtlMoveMemory(PathBuffer
, NamePtr
, AppLength
);
531 /* Release the lock */
532 if (!Environment
) RtlReleasePebLock();
534 /* Finish preparing the path string */
535 NamePtr
= &PathBuffer
[AppLength
/ sizeof(WCHAR
)];
537 /* Put a separating ";" if something was added */
546 /* Dynamically allocated env path, copy from the static buffer,
547 concatenate with dynamic buffer and free it */
548 RtlMoveMemory(NamePtr
, BaseDefaultPath
.Buffer
, BaseDefaultPath
.Length
);
549 RtlMoveMemory(&NamePtr
[BaseDefaultPath
.Length
/ sizeof(WCHAR
)], AllocatedPath
, EnvPath
.Length
);
552 RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath
);
556 /* Static env path string, copy directly from BaseDefaultPath */
557 RtlMoveMemory(NamePtr
, BaseDefaultPath
.Buffer
, DefaultLength
);
560 /* Null terminate the string */
561 NamePtr
[DefaultLength
/ sizeof(WCHAR
)] = 0;
568 BasepGetDllPath(LPWSTR FullPath
,
572 LPWSTR DllPath
= NULL
;
574 /* Acquire DLL directory lock */
575 RtlEnterCriticalSection(&BaseDllDirectoryLock
);
577 /* Check if we have a base dll directory */
578 if (BaseDllDirectory
.Buffer
)
580 /* Then get process path */
581 DllPath
= BasepGetProcessPath(0, FullPath
, Environment
);
583 /* Release DLL directory lock */
584 RtlLeaveCriticalSection(&BaseDllDirectoryLock
);
586 /* Return dll path */
590 /* Release DLL directory lock */
591 RtlLeaveCriticalSection(&BaseDllDirectoryLock
);
593 /* There is no base DLL directory */
596 /* Return dll path */
599 return BasepGetProcessPath(0, FullPath
, Environment
);
605 BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params
,
606 IN PRTL_USER_PROCESS_PARAMETERS PebParams
,
607 IN BOOL InheritHandles
)
609 DPRINT("BasepCopyHandles %p %p, %d\n", Params
, PebParams
, InheritHandles
);
611 /* Copy the handle if we are inheriting or if it's a console handle */
612 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardInput
))
614 Params
->StandardInput
= PebParams
->StandardInput
;
616 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardOutput
))
618 Params
->StandardOutput
= PebParams
->StandardOutput
;
620 if (InheritHandles
|| IsConsoleHandle(PebParams
->StandardError
))
622 Params
->StandardError
= PebParams
->StandardError
;
628 BasepInitializeEnvironment(HANDLE ProcessHandle
,
630 LPWSTR ApplicationPathName
,
631 LPWSTR lpCurrentDirectory
,
632 LPWSTR lpCommandLine
,
633 LPVOID lpEnvironment
,
635 LPSTARTUPINFOW StartupInfo
,
639 WCHAR FullPath
[MAX_PATH
];
641 LPWSTR DllPathString
;
642 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
643 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
= NULL
;
644 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
649 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
650 PPEB OurPeb
= NtCurrentPeb();
651 LPVOID Environment
= lpEnvironment
;
653 DPRINT("BasepInitializeEnvironment\n");
655 /* Get the full path name */
656 GetFullPathNameW(ApplicationPathName
,
660 DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName
,
663 /* Get the DLL Path */
664 DllPathString
= BasepGetDllPath(FullPath
, Environment
);
666 /* Initialize Strings */
667 RtlInitUnicodeString(&DllPath
, DllPathString
);
668 RtlInitUnicodeString(&ImageName
, FullPath
);
669 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
670 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
672 /* Initialize more Strings from the Startup Info */
673 if (StartupInfo
->lpDesktop
)
675 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
679 RtlInitUnicodeString(&Desktop
, L
"");
681 if (StartupInfo
->lpReserved
)
683 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
687 RtlInitUnicodeString(&Shell
, L
"");
689 if (StartupInfo
->lpTitle
)
691 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
695 RtlInitUnicodeString(&Title
, L
"");
698 /* This one is special because the length can differ */
699 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
700 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
702 /* Create the Parameter Block */
703 DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
704 &ImageName
, &DllPath
, &CommandLine
, &Desktop
, &Title
, &Shell
,
706 Status
= RtlCreateProcessParameters(&ProcessParameters
,
710 &CurrentDirectory
: NULL
,
718 if (!NT_SUCCESS(Status
))
720 DPRINT1("Failed to create process parameters!\n");
724 /* Check if we got an environment. If not, use ours */
727 /* Save pointer and start lookup */
728 Environment
= ScanChar
= ProcessParameters
->Environment
;
732 /* Save pointer and start lookup */
733 Environment
= ScanChar
= OurPeb
->ProcessParameters
->Environment
;
736 /* Find the environment size */
739 if (EnvSize
&& Environment
== lpEnvironment
)
741 /* its a converted ansi environment, bypass the length calculation */
742 EnviroSize
= EnvSize
;
748 ScanChar
+= wcslen(ScanChar
) + 1;
751 /* Calculate the size of the block */
752 if (ScanChar
== Environment
)
754 EnviroSize
= 2 * sizeof(WCHAR
);
758 EnviroSize
= (ULONG
)((ULONG_PTR
)ScanChar
- (ULONG_PTR
)Environment
+ sizeof(WCHAR
));
761 DPRINT("EnvironmentSize %ld\n", EnviroSize
);
763 /* Allocate and Initialize new Environment Block */
765 ProcessParameters
->Environment
= NULL
;
766 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
767 (PVOID
*)&ProcessParameters
->Environment
,
772 if (!NT_SUCCESS(Status
))
774 DPRINT1("Failed to allocate Environment Block\n");
778 /* Write the Environment Block */
779 ZwWriteVirtualMemory(ProcessHandle
,
780 ProcessParameters
->Environment
,
786 /* Write new parameters */
787 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
788 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
789 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
790 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
791 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
792 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
793 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
794 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
795 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
797 /* Write the handles only if we have to */
798 if (StartupInfo
->dwFlags
& STARTF_USESTDHANDLES
)
800 DPRINT("Using Standard Handles\n");
801 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
802 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
803 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
806 /* Use Special Flags for ConDllInitialize in Kernel32 */
807 if (CreationFlags
& DETACHED_PROCESS
)
809 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
811 else if (CreationFlags
& CREATE_NO_WINDOW
)
813 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
815 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
817 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
821 /* Inherit our Console Handle */
822 ProcessParameters
->ConsoleHandle
= OurPeb
->ProcessParameters
->ConsoleHandle
;
824 /* Is the shell trampling on our Handles? */
825 if (!(StartupInfo
->dwFlags
&
826 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
828 /* Use handles from PEB, if inheriting or they are console */
829 DPRINT("Copying handles from parent\n");
830 BasepCopyHandles(ProcessParameters
,
831 OurPeb
->ProcessParameters
,
836 /* Also set the Console Flag */
837 if (CreationFlags
& CREATE_NEW_PROCESS_GROUP
)
839 ProcessParameters
->ConsoleFlags
= 1;
842 /* Allocate memory for the parameter block */
843 Size
= ProcessParameters
->Length
;
844 Status
= NtAllocateVirtualMemory(ProcessHandle
,
845 (PVOID
*)&RemoteParameters
,
850 if (!NT_SUCCESS(Status
))
852 DPRINT1("Failed to allocate Parameters Block\n");
856 /* Set the allocated size */
857 ProcessParameters
->MaximumLength
= Size
;
859 /* Handle some Parameter Flags */
860 ProcessParameters
->ConsoleFlags
= (CreationFlags
& CREATE_NEW_PROCESS_GROUP
);
861 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
862 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
863 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
864 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
865 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
866 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
867 ProcessParameters
->Flags
|= (NtCurrentPeb()->ProcessParameters
->Flags
&
868 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
870 /* Write the Parameter Block */
871 Status
= NtWriteVirtualMemory(ProcessHandle
,
874 ProcessParameters
->Length
,
877 /* Write the PEB Pointer */
878 Status
= NtWriteVirtualMemory(ProcessHandle
,
879 &Peb
->ProcessParameters
,
885 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
886 RtlDestroyProcessParameters(ProcessParameters
);
888 DPRINT("Completed\n");
889 return STATUS_SUCCESS
;
894 InitCommandLines(VOID
)
896 PRTL_USER_PROCESS_PARAMETERS Params
;
898 /* get command line */
899 Params
= NtCurrentPeb()->ProcessParameters
;
900 RtlNormalizeProcessParams (Params
);
902 /* initialize command line buffers */
903 CommandLineStringW
.Length
= Params
->CommandLine
.Length
;
904 CommandLineStringW
.MaximumLength
= CommandLineStringW
.Length
+ sizeof(WCHAR
);
905 CommandLineStringW
.Buffer
= RtlAllocateHeap(GetProcessHeap(),
906 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
907 CommandLineStringW
.MaximumLength
);
908 if (CommandLineStringW
.Buffer
== NULL
)
913 RtlInitAnsiString(&CommandLineStringA
, NULL
);
915 /* Copy command line */
916 RtlCopyUnicodeString(&CommandLineStringW
,
917 &(Params
->CommandLine
));
918 CommandLineStringW
.Buffer
[CommandLineStringW
.Length
/ sizeof(WCHAR
)] = 0;
920 /* convert unicode string to ansi (or oem) */
922 RtlUnicodeStringToAnsiString(&CommandLineStringA
,
926 RtlUnicodeStringToOemString(&CommandLineStringA
,
930 CommandLineStringA
.Buffer
[CommandLineStringA
.Length
] = 0;
932 bCommandLineInitialized
= TRUE
;
940 GetProcessAffinityMask(HANDLE hProcess
,
941 PDWORD_PTR lpProcessAffinityMask
,
942 PDWORD_PTR lpSystemAffinityMask
)
944 PROCESS_BASIC_INFORMATION ProcessInfo
;
945 SYSTEM_BASIC_INFORMATION SystemInfo
;
948 Status
= NtQuerySystemInformation(SystemBasicInformation
,
952 if (!NT_SUCCESS(Status
))
954 BaseSetLastNTError(Status
);
958 Status
= NtQueryInformationProcess(hProcess
,
959 ProcessBasicInformation
,
961 sizeof(PROCESS_BASIC_INFORMATION
),
963 if (!NT_SUCCESS(Status
))
965 BaseSetLastNTError(Status
);
969 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
970 *lpSystemAffinityMask
= (DWORD
)SystemInfo
.ActiveProcessorsAffinityMask
;
981 SetProcessAffinityMask(HANDLE hProcess
,
982 DWORD_PTR dwProcessAffinityMask
)
986 Status
= NtSetInformationProcess(hProcess
,
988 (PVOID
)&dwProcessAffinityMask
,
990 if (!NT_SUCCESS(Status
))
992 BaseSetLastNTError(Status
);
1005 GetProcessShutdownParameters(LPDWORD lpdwLevel
,
1008 CSR_API_MESSAGE CsrRequest
;
1012 Request
= GET_SHUTDOWN_PARAMETERS
;
1013 Status
= CsrClientCallServer(&CsrRequest
,
1015 MAKE_CSR_API(Request
, CSR_NATIVE
),
1016 sizeof(CSR_API_MESSAGE
));
1017 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1019 BaseSetLastNTError(Status
);
1023 *lpdwLevel
= CsrRequest
.Data
.GetShutdownParametersRequest
.Level
;
1024 *lpdwFlags
= CsrRequest
.Data
.GetShutdownParametersRequest
.Flags
;
1035 SetProcessShutdownParameters(DWORD dwLevel
,
1038 CSR_API_MESSAGE CsrRequest
;
1042 CsrRequest
.Data
.SetShutdownParametersRequest
.Level
= dwLevel
;
1043 CsrRequest
.Data
.SetShutdownParametersRequest
.Flags
= dwFlags
;
1045 Request
= SET_SHUTDOWN_PARAMETERS
;
1046 Status
= CsrClientCallServer(&CsrRequest
,
1048 MAKE_CSR_API(Request
, CSR_NATIVE
),
1049 sizeof(CSR_API_MESSAGE
));
1050 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1052 BaseSetLastNTError(Status
);
1065 GetProcessWorkingSetSize(HANDLE hProcess
,
1066 PSIZE_T lpMinimumWorkingSetSize
,
1067 PSIZE_T lpMaximumWorkingSetSize
)
1069 QUOTA_LIMITS QuotaLimits
;
1072 Status
= NtQueryInformationProcess(hProcess
,
1075 sizeof(QUOTA_LIMITS
),
1077 if (!NT_SUCCESS(Status
))
1079 BaseSetLastNTError(Status
);
1083 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1084 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1095 SetProcessWorkingSetSize(HANDLE hProcess
,
1096 SIZE_T dwMinimumWorkingSetSize
,
1097 SIZE_T dwMaximumWorkingSetSize
)
1099 QUOTA_LIMITS QuotaLimits
;
1102 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1103 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1105 Status
= NtSetInformationProcess(hProcess
,
1108 sizeof(QUOTA_LIMITS
));
1109 if (!NT_SUCCESS(Status
))
1111 BaseSetLastNTError(Status
);
1124 GetProcessTimes(HANDLE hProcess
,
1125 LPFILETIME lpCreationTime
,
1126 LPFILETIME lpExitTime
,
1127 LPFILETIME lpKernelTime
,
1128 LPFILETIME lpUserTime
)
1130 KERNEL_USER_TIMES Kut
;
1133 Status
= NtQueryInformationProcess(hProcess
,
1138 if (!NT_SUCCESS(Status
))
1140 BaseSetLastNTError(Status
);
1144 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1145 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1147 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1148 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1150 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1151 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1153 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1154 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1165 GetCurrentProcess(VOID
)
1167 return (HANDLE
)NtCurrentProcess();
1176 GetCurrentThread(VOID
)
1178 return (HANDLE
)NtCurrentThread();
1187 GetCurrentProcessId(VOID
)
1189 return HandleToUlong(GetTeb()->ClientId
.UniqueProcess
);
1198 GetExitCodeProcess(HANDLE hProcess
,
1201 PROCESS_BASIC_INFORMATION ProcessBasic
;
1204 Status
= NtQueryInformationProcess(hProcess
,
1205 ProcessBasicInformation
,
1207 sizeof(PROCESS_BASIC_INFORMATION
),
1209 if (!NT_SUCCESS(Status
))
1211 BaseSetLastNTError(Status
);
1215 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1226 GetProcessId(HANDLE Process
)
1228 PROCESS_BASIC_INFORMATION ProcessBasic
;
1231 Status
= NtQueryInformationProcess(Process
,
1232 ProcessBasicInformation
,
1234 sizeof(PROCESS_BASIC_INFORMATION
),
1236 if (!NT_SUCCESS(Status
))
1238 BaseSetLastNTError(Status
);
1242 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1251 OpenProcess(DWORD dwDesiredAccess
,
1252 BOOL bInheritHandle
,
1256 HANDLE ProcessHandle
;
1257 OBJECT_ATTRIBUTES ObjectAttributes
;
1260 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1261 ClientId
.UniqueThread
= 0;
1263 InitializeObjectAttributes(&ObjectAttributes
,
1265 (bInheritHandle
? OBJ_INHERIT
: 0),
1269 errCode
= NtOpenProcess(&ProcessHandle
,
1273 if (!NT_SUCCESS(errCode
))
1275 BaseSetLastNTError(errCode
);
1279 return ProcessHandle
;
1288 WinExec(LPCSTR lpCmdLine
,
1291 STARTUPINFOA StartupInfo
;
1292 PROCESS_INFORMATION ProcessInformation
;
1295 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1296 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
1297 StartupInfo
.wShowWindow
= (WORD
)uCmdShow
;
1298 StartupInfo
.dwFlags
= 0;
1300 if (!CreateProcessA(NULL
,
1309 &ProcessInformation
))
1311 dosErr
= GetLastError();
1312 return dosErr
< 32 ? dosErr
: ERROR_BAD_FORMAT
;
1315 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
1317 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
,
1321 NtClose(ProcessInformation
.hProcess
);
1322 NtClose(ProcessInformation
.hThread
);
1324 return 33; /* Something bigger than 31 means success. */
1333 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1335 lpfnGlobalRegisterWaitForInputIdle
= lpfnRegisterWaitForInputIdle
;
1344 GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo
)
1346 PRTL_USER_PROCESS_PARAMETERS Params
;
1348 if (lpStartupInfo
== NULL
)
1350 SetLastError(ERROR_INVALID_PARAMETER
);
1354 Params
= NtCurrentPeb()->ProcessParameters
;
1356 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1357 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1358 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1359 lpStartupInfo
->dwX
= Params
->StartingX
;
1360 lpStartupInfo
->dwY
= Params
->StartingY
;
1361 lpStartupInfo
->dwXSize
= Params
->CountX
;
1362 lpStartupInfo
->dwYSize
= Params
->CountY
;
1363 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1364 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1365 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1366 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1367 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1368 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1369 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1371 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1372 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1373 lpStartupInfo
->hStdError
= Params
->StandardError
;
1382 GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo
)
1384 PRTL_USER_PROCESS_PARAMETERS Params
;
1385 ANSI_STRING AnsiString
;
1387 if (lpStartupInfo
== NULL
)
1389 SetLastError(ERROR_INVALID_PARAMETER
);
1393 Params
= NtCurrentPeb ()->ProcessParameters
;
1395 RtlAcquirePebLock ();
1397 /* FIXME - not thread-safe */
1398 if (lpLocalStartupInfo
== NULL
)
1400 /* create new local startup info (ansi) */
1401 lpLocalStartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1403 sizeof(STARTUPINFOA
));
1404 if (lpLocalStartupInfo
== NULL
)
1406 RtlReleasePebLock();
1407 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1411 lpLocalStartupInfo
->cb
= sizeof(STARTUPINFOA
);
1413 /* copy window title string */
1414 RtlUnicodeStringToAnsiString(&AnsiString
,
1415 &Params
->WindowTitle
,
1417 lpLocalStartupInfo
->lpTitle
= AnsiString
.Buffer
;
1419 /* copy desktop info string */
1420 RtlUnicodeStringToAnsiString(&AnsiString
,
1421 &Params
->DesktopInfo
,
1423 lpLocalStartupInfo
->lpDesktop
= AnsiString
.Buffer
;
1425 /* copy shell info string */
1426 RtlUnicodeStringToAnsiString(&AnsiString
,
1429 lpLocalStartupInfo
->lpReserved
= AnsiString
.Buffer
;
1431 lpLocalStartupInfo
->dwX
= Params
->StartingX
;
1432 lpLocalStartupInfo
->dwY
= Params
->StartingY
;
1433 lpLocalStartupInfo
->dwXSize
= Params
->CountX
;
1434 lpLocalStartupInfo
->dwYSize
= Params
->CountY
;
1435 lpLocalStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1436 lpLocalStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1437 lpLocalStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1438 lpLocalStartupInfo
->dwFlags
= Params
->WindowFlags
;
1439 lpLocalStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1440 lpLocalStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1441 lpLocalStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1443 lpLocalStartupInfo
->hStdInput
= Params
->StandardInput
;
1444 lpLocalStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1445 lpLocalStartupInfo
->hStdError
= Params
->StandardError
;
1448 RtlReleasePebLock();
1450 /* copy local startup info data to external startup info */
1451 memcpy(lpStartupInfo
,
1453 sizeof(STARTUPINFOA
));
1462 FlushInstructionCache(HANDLE hProcess
,
1463 LPCVOID lpBaseAddress
,
1468 Status
= NtFlushInstructionCache(hProcess
,
1469 (PVOID
)lpBaseAddress
,
1471 if (!NT_SUCCESS(Status
))
1473 BaseSetLastNTError(Status
);
1486 ExitProcess(UINT uExitCode
)
1488 CSR_API_MESSAGE CsrRequest
;
1492 /* kill sibling threads ... we want to be alone at this point */
1493 NtTerminateProcess(NULL
, 0);
1495 /* unload all dll's */
1496 LdrShutdownProcess();
1498 /* notify csrss of process termination */
1499 Request
= TERMINATE_PROCESS
;
1500 Status
= CsrClientCallServer(&CsrRequest
,
1502 MAKE_CSR_API(Request
, CSR_NATIVE
),
1503 sizeof(CSR_API_MESSAGE
));
1504 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(CsrRequest
.Status
))
1506 DPRINT("Failed to tell csrss about terminating process\n");
1509 NtTerminateProcess(NtCurrentProcess (),
1512 /* should never get here */
1523 TerminateProcess(HANDLE hProcess
,
1528 if (hProcess
== NULL
)
1533 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1534 if (NT_SUCCESS(Status
))
1539 BaseSetLastNTError(Status
);
1549 FatalAppExitA(UINT uAction
,
1550 LPCSTR lpMessageText
)
1552 UNICODE_STRING MessageTextU
;
1553 ANSI_STRING MessageText
;
1555 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1557 RtlAnsiStringToUnicodeString(&MessageTextU
,
1561 FatalAppExitW(uAction
, MessageTextU
.Buffer
);
1563 RtlFreeUnicodeString(&MessageTextU
);
1572 FatalAppExitW(UINT uAction
,
1573 LPCWSTR lpMessageText
)
1575 static const WCHAR szUser32
[] = L
"user32.dll\0";
1577 HMODULE hModule
= GetModuleHandleW(szUser32
);
1578 MessageBoxW_Proc pMessageBoxW
= NULL
;
1580 DPRINT1("AppExit\n");
1583 pMessageBoxW
= (MessageBoxW_Proc
)GetProcAddress(hModule
, "MessageBoxW");
1586 pMessageBoxW(0, lpMessageText
, NULL
, MB_SYSTEMMODAL
| MB_OK
);
1588 DPRINT1("%s\n", lpMessageText
);
1599 FatalExit(int ExitCode
)
1601 ExitProcess(ExitCode
);
1610 GetPriorityClass(HANDLE hProcess
)
1613 PROCESS_PRIORITY_CLASS PriorityClass
;
1615 Status
= NtQueryInformationProcess(hProcess
,
1616 ProcessPriorityClass
,
1618 sizeof(PROCESS_PRIORITY_CLASS
),
1620 if(NT_SUCCESS(Status
))
1622 switch(PriorityClass
.PriorityClass
)
1624 case PROCESS_PRIORITY_CLASS_IDLE
:
1625 return IDLE_PRIORITY_CLASS
;
1627 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
:
1628 return BELOW_NORMAL_PRIORITY_CLASS
;
1630 case PROCESS_PRIORITY_CLASS_NORMAL
:
1631 return NORMAL_PRIORITY_CLASS
;
1633 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
:
1634 return ABOVE_NORMAL_PRIORITY_CLASS
;
1636 case PROCESS_PRIORITY_CLASS_HIGH
:
1637 return HIGH_PRIORITY_CLASS
;
1639 case PROCESS_PRIORITY_CLASS_REALTIME
:
1640 return REALTIME_PRIORITY_CLASS
;
1643 return NORMAL_PRIORITY_CLASS
;
1647 BaseSetLastNTError(Status
);
1657 SetPriorityClass(HANDLE hProcess
,
1658 DWORD dwPriorityClass
)
1661 PROCESS_PRIORITY_CLASS PriorityClass
;
1663 switch (dwPriorityClass
)
1665 case IDLE_PRIORITY_CLASS
:
1666 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1669 case BELOW_NORMAL_PRIORITY_CLASS
:
1670 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1673 case NORMAL_PRIORITY_CLASS
:
1674 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1677 case ABOVE_NORMAL_PRIORITY_CLASS
:
1678 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1681 case HIGH_PRIORITY_CLASS
:
1682 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1685 case REALTIME_PRIORITY_CLASS
:
1686 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_REALTIME
;
1690 SetLastError(ERROR_INVALID_PARAMETER
);
1694 PriorityClass
.Foreground
= FALSE
;
1696 Status
= NtSetInformationProcess(hProcess
,
1697 ProcessPriorityClass
,
1699 sizeof(PROCESS_PRIORITY_CLASS
));
1700 if (!NT_SUCCESS(Status
))
1702 BaseSetLastNTError(Status
);
1715 GetProcessVersion(DWORD ProcessId
)
1718 PIMAGE_NT_HEADERS NtHeader
= NULL
;
1719 IMAGE_NT_HEADERS NtHeaders
;
1720 IMAGE_DOS_HEADER DosHeader
;
1721 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1722 PVOID BaseAddress
= NULL
;
1723 HANDLE ProcessHandle
= NULL
;
1730 if (0 == ProcessId
|| GetCurrentProcessId() == ProcessId
)
1733 BaseAddress
= (PVOID
) NtCurrentPeb()->ImageBaseAddress
;
1734 NtHeader
= RtlImageNtHeader(BaseAddress
);
1736 Version
= (NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
<< 16) |
1737 (NtHeader
->OptionalHeader
.MinorOperatingSystemVersion
);
1742 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1746 if (!ProcessHandle
) return 0;
1748 Status
= NtQueryInformationProcess(ProcessHandle
,
1749 ProcessBasicInformation
,
1751 sizeof(ProcessBasicInfo
),
1754 if (!NT_SUCCESS(Status
)) goto Error
;
1756 Status
= NtReadVirtualMemory(ProcessHandle
,
1757 ProcessBasicInfo
.PebBaseAddress
,
1762 if (!NT_SUCCESS(Status
) || Count
!= sizeof(Peb
)) goto Error
;
1764 memset(&DosHeader
, 0, sizeof(DosHeader
));
1765 Status
= NtReadVirtualMemory(ProcessHandle
,
1766 Peb
.ImageBaseAddress
,
1771 if (!NT_SUCCESS(Status
) || Count
!= sizeof(DosHeader
)) goto Error
;
1772 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
) goto Error
;
1774 memset(&NtHeaders
, 0, sizeof(NtHeaders
));
1775 Status
= NtReadVirtualMemory(ProcessHandle
,
1776 (char *)Peb
.ImageBaseAddress
+ DosHeader
.e_lfanew
,
1781 if (!NT_SUCCESS(Status
) || Count
!= sizeof(NtHeaders
)) goto Error
;
1782 if (NtHeaders
.Signature
!= IMAGE_NT_SIGNATURE
) goto Error
;
1784 Version
= MAKELONG(NtHeaders
.OptionalHeader
.MinorSubsystemVersion
,
1785 NtHeaders
.OptionalHeader
.MajorSubsystemVersion
);
1788 if (!NT_SUCCESS(Status
))
1790 BaseSetLastNTError(Status
);
1796 if (ProcessHandle
) CloseHandle(ProcessHandle
);
1809 GetProcessIoCounters(HANDLE hProcess
,
1810 PIO_COUNTERS lpIoCounters
)
1814 Status
= NtQueryInformationProcess(hProcess
,
1817 sizeof(IO_COUNTERS
),
1819 if (!NT_SUCCESS(Status
))
1821 BaseSetLastNTError(Status
);
1834 GetProcessPriorityBoost(HANDLE hProcess
,
1835 PBOOL pDisablePriorityBoost
)
1838 ULONG PriorityBoost
;
1840 Status
= NtQueryInformationProcess(hProcess
,
1841 ProcessPriorityBoost
,
1845 if (NT_SUCCESS(Status
))
1847 *pDisablePriorityBoost
= PriorityBoost
;
1851 BaseSetLastNTError(Status
);
1861 SetProcessPriorityBoost(HANDLE hProcess
,
1862 BOOL bDisablePriorityBoost
)
1865 ULONG PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
); /* prevent setting values other than 1 and 0 */
1867 Status
= NtSetInformationProcess(hProcess
,
1868 ProcessPriorityBoost
,
1871 if (!NT_SUCCESS(Status
))
1873 BaseSetLastNTError(Status
);
1886 GetProcessHandleCount(HANDLE hProcess
,
1887 PDWORD pdwHandleCount
)
1892 Status
= NtQueryInformationProcess(hProcess
,
1897 if(NT_SUCCESS(Status
))
1899 *pdwHandleCount
= phc
;
1903 BaseSetLastNTError(Status
);
1913 IsWow64Process(HANDLE hProcess
,
1919 Status
= NtQueryInformationProcess(hProcess
,
1920 ProcessWow64Information
,
1924 if (!NT_SUCCESS(Status
))
1926 SetLastError(RtlNtStatusToDosError(Status
));
1930 *Wow64Process
= (pbi
!= 0);
1940 GetCommandLineA(VOID
)
1942 DPRINT("CommandLine \'%s\'\n", CommandLineStringA
.Buffer
);
1943 return CommandLineStringA
.Buffer
;
1952 GetCommandLineW(VOID
)
1954 DPRINT("CommandLine \'%S\'\n", CommandLineStringW
.Buffer
);
1955 return CommandLineStringW
.Buffer
;
1963 ReadProcessMemory(IN HANDLE hProcess
,
1964 IN LPCVOID lpBaseAddress
,
1967 OUT SIZE_T
* lpNumberOfBytesRead
)
1972 Status
= NtReadVirtualMemory(hProcess
,
1973 (PVOID
)lpBaseAddress
,
1976 lpNumberOfBytesRead
);
1977 if (!NT_SUCCESS(Status
))
1980 BaseSetLastNTError (Status
);
1984 /* Return success */
1993 WriteProcessMemory(IN HANDLE hProcess
,
1994 IN LPVOID lpBaseAddress
,
1995 IN LPCVOID lpBuffer
,
1997 OUT SIZE_T
*lpNumberOfBytesWritten
)
2005 /* Set parameters for protect call */
2007 Base
= lpBaseAddress
;
2009 /* Check the current status */
2010 Status
= NtProtectVirtualMemory(hProcess
,
2013 PAGE_EXECUTE_READWRITE
,
2015 if (NT_SUCCESS(Status
))
2017 /* Check if we are unprotecting */
2018 UnProtect
= OldValue
& (PAGE_READWRITE
|
2020 PAGE_EXECUTE_READWRITE
|
2021 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2024 /* Set the new protection */
2025 Status
= NtProtectVirtualMemory(hProcess
,
2031 /* Write the memory */
2032 Status
= NtWriteVirtualMemory(hProcess
,
2036 lpNumberOfBytesWritten
);
2037 if (!NT_SUCCESS(Status
))
2040 BaseSetLastNTError(Status
);
2044 /* Flush the ITLB */
2045 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2050 /* Check if we were read only */
2051 if ((OldValue
& PAGE_NOACCESS
) || (OldValue
& PAGE_READONLY
))
2053 /* Restore protection and fail */
2054 NtProtectVirtualMemory(hProcess
,
2059 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2063 /* Otherwise, do the write */
2064 Status
= NtWriteVirtualMemory(hProcess
,
2068 lpNumberOfBytesWritten
);
2070 /* And restore the protection */
2071 NtProtectVirtualMemory(hProcess
,
2076 if (!NT_SUCCESS(Status
))
2079 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2083 /* Flush the ITLB */
2084 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2091 BaseSetLastNTError(Status
);
2101 ProcessIdToSessionId(IN DWORD dwProcessId
,
2102 OUT DWORD
*pSessionId
)
2104 PROCESS_SESSION_INFORMATION SessionInformation
;
2105 OBJECT_ATTRIBUTES ObjectAttributes
;
2107 HANDLE ProcessHandle
;
2110 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2112 SetLastError(ERROR_INVALID_PARAMETER
);
2116 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2117 ClientId
.UniqueThread
= 0;
2119 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2121 Status
= NtOpenProcess(&ProcessHandle
,
2122 PROCESS_QUERY_INFORMATION
,
2125 if (NT_SUCCESS(Status
))
2127 Status
= NtQueryInformationProcess(ProcessHandle
,
2128 ProcessSessionInformation
,
2129 &SessionInformation
,
2130 sizeof(SessionInformation
),
2132 NtClose(ProcessHandle
);
2134 if (NT_SUCCESS(Status
))
2136 *pSessionId
= SessionInformation
.SessionId
;
2141 BaseSetLastNTError(Status
);
2147 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
2148 IN SIZE_T dwMinimumWorkingSetSize
,
2149 IN SIZE_T dwMaximumWorkingSetSize
,
2159 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
2160 OUT PSIZE_T lpMinimumWorkingSetSize
,
2161 OUT PSIZE_T lpMaximumWorkingSetSize
,
2173 CreateProcessInternalW(HANDLE hToken
,
2174 LPCWSTR lpApplicationName
,
2175 LPWSTR lpCommandLine
,
2176 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2177 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2178 BOOL bInheritHandles
,
2179 DWORD dwCreationFlags
,
2180 LPVOID lpEnvironment
,
2181 LPCWSTR lpCurrentDirectory
,
2182 LPSTARTUPINFOW lpStartupInfo
,
2183 LPPROCESS_INFORMATION lpProcessInformation
,
2187 PROCESS_PRIORITY_CLASS PriorityClass
;
2188 BOOLEAN FoundQuotes
= FALSE
;
2189 BOOLEAN QuotesNeeded
= FALSE
;
2190 BOOLEAN CmdLineIsAppName
= FALSE
;
2191 UNICODE_STRING ApplicationName
= { 0, 0, NULL
};
2192 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2193 POBJECT_ATTRIBUTES ObjectAttributes
;
2194 HANDLE hSection
= NULL
, hProcess
= NULL
, hThread
= NULL
, hDebug
= NULL
;
2195 SECTION_IMAGE_INFORMATION SectionImageInfo
;
2196 LPWSTR CurrentDirectory
= NULL
;
2197 LPWSTR CurrentDirectoryPart
;
2198 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
2199 STARTUPINFOW StartupInfo
;
2201 LPWSTR BatchCommandLine
;
2202 ULONG CmdLineLength
;
2203 UNICODE_STRING CommandLineString
;
2205 LPWSTR QuotedCmdLine
= NULL
;
2207 LPWSTR NullBuffer
= NULL
;
2208 LPWSTR NameBuffer
= NULL
;
2212 BOOLEAN SearchDone
= FALSE
;
2213 BOOLEAN Escape
= FALSE
;
2215 PPEB OurPeb
= NtCurrentPeb();
2220 /* FIXME should process
2221 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2222 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2225 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2226 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2227 lpApplicationName
, lpCommandLine
, lpEnvironment
, lpCurrentDirectory
,
2230 /* Flags we don't handle yet */
2231 if (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
)
2233 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2235 if (dwCreationFlags
& CREATE_SHARED_WOW_VDM
)
2237 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2239 if (dwCreationFlags
& CREATE_FORCEDOS
)
2241 DPRINT1("CREATE_FORCEDOS not handled\n");
2244 /* Fail on this flag, it's only valid with the WithLogonW function */
2245 if (dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
)
2247 DPRINT1("Invalid flag used\n");
2248 SetLastError(ERROR_INVALID_PARAMETER
);
2252 /* This combination is illegal (see MSDN) */
2253 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2254 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2256 DPRINT1("Invalid flag combo used\n");
2257 SetLastError(ERROR_INVALID_PARAMETER
);
2261 /* Another illegal combo */
2262 if ((dwCreationFlags
& (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
)) ==
2263 (CREATE_SEPARATE_WOW_VDM
| CREATE_SHARED_WOW_VDM
))
2265 DPRINT1("Invalid flag combo used\n");
2266 SetLastError(ERROR_INVALID_PARAMETER
);
2270 if (lpCurrentDirectory
)
2272 if ((GetFileAttributesW(lpCurrentDirectory
) == INVALID_FILE_ATTRIBUTES
) ||
2273 !(GetFileAttributesW(lpCurrentDirectory
) & FILE_ATTRIBUTE_DIRECTORY
))
2275 SetLastError(ERROR_DIRECTORY
);
2281 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2282 * so we'll use our own local copy for that.
2284 StartupInfo
= *lpStartupInfo
;
2286 /* FIXME: Use default Separate/Shared VDM Flag */
2288 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2289 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
2291 if (NtIsProcessInJob(NtCurrentProcess(), NULL
))
2293 /* Remove the shared flag and add the separate flag. */
2294 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2295 CREATE_SEPARATE_WOW_VDM
;
2300 * According to some sites, ShellExecuteEx uses an undocumented flag to
2301 * send private handle data (such as HMONITOR or HICON). See:
2302 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2303 * standard handles anymore since we'd be overwriting this private data
2305 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2306 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2308 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2311 /* Start by zeroing out the fields */
2312 RtlZeroMemory(lpProcessInformation
, sizeof(PROCESS_INFORMATION
));
2314 /* Easy stuff first, convert the process priority class */
2315 PriorityClass
.Foreground
= FALSE
;
2316 PriorityClass
.PriorityClass
= (UCHAR
)BasepConvertPriorityClass(dwCreationFlags
);
2320 /* Search for escape sequences */
2321 ScanString
= lpCommandLine
;
2322 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2325 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\"')
2333 /* Get the application name and do all the proper formating necessary */
2335 /* See if we have an application name (oh please let us have one!) */
2336 if (!lpApplicationName
)
2338 /* The fun begins */
2339 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2341 MAX_PATH
* sizeof(WCHAR
));
2342 if (NameBuffer
== NULL
)
2344 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2348 /* This is all we have to work with :( */
2349 lpApplicationName
= lpCommandLine
;
2351 /* Initialize our friends at the beginning */
2352 NullBuffer
= (LPWSTR
)lpApplicationName
;
2353 ScanString
= (LPWSTR
)lpApplicationName
;
2355 /* We will start by looking for a quote */
2356 if (*ScanString
== L
'\"')
2358 /* That was quick */
2361 /* Advance past quote */
2363 lpApplicationName
= ScanString
;
2365 /* Find the closing quote */
2368 if (*ScanString
== L
'\"' && *(ScanString
- 1) != L
'^')
2371 NullBuffer
= ScanString
;
2378 NullBuffer
= ScanString
;
2383 /* No quotes, so we'll be looking for white space */
2385 /* Reset the pointer */
2386 lpApplicationName
= lpCommandLine
;
2388 /* Find whitespace of Tab */
2391 if (*ScanString
== ' ' || *ScanString
== '\t')
2394 NullBuffer
= ScanString
;
2400 NullBuffer
= ScanString
;
2404 /* Set the Null Buffer */
2405 SaveChar
= *NullBuffer
;
2406 *NullBuffer
= UNICODE_NULL
;
2408 /* Do a search for the file */
2409 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName
);
2410 RetVal
= SearchPathW(NULL
,
2415 NULL
) * sizeof(WCHAR
);
2417 /* Did it find something? */
2420 /* Get file attributes */
2421 ULONG Attributes
= GetFileAttributesW(NameBuffer
);
2422 if (Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2424 /* Give it a length of 0 to fail, this was a directory. */
2430 RetVal
+= sizeof(WCHAR
);
2434 /* Now check if we have a file, and if the path size is OK */
2435 if (!RetVal
|| RetVal
>= (MAX_PATH
* sizeof(WCHAR
)))
2440 /* We failed, try to get the Path Type */
2441 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal
);
2442 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2444 /* If it's not relative, try to get the error */
2445 if (PathType
!= RtlPathTypeRelative
)
2447 /* This should fail, and give us a detailed LastError */
2448 hFile
= CreateFileW(lpApplicationName
,
2450 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2453 FILE_ATTRIBUTE_NORMAL
,
2456 /* Did it actually NOT fail? */
2457 if (hFile
!= INVALID_HANDLE_VALUE
)
2459 /* Fake the error */
2461 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2466 /* Immediately set the error */
2467 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2470 /* Did we already fail once? */
2473 SetLastError(Error
);
2477 /* Not yet, cache it */
2478 Error
= GetLastError();
2481 /* Put back the command line */
2482 *NullBuffer
= SaveChar
;
2483 lpApplicationName
= NameBuffer
;
2486 * If the search isn't done and we still have cmdline
2487 * then start over. Ex: c:\ha ha ha\haha.exe
2489 if (*ScanString
&& !SearchDone
)
2491 /* Move in the buffer */
2493 NullBuffer
= ScanString
;
2495 /* We will have to add a quote, since there is a space*/
2496 QuotesNeeded
= TRUE
;
2498 /* And we will also fake the fact we found one */
2505 /* We totally failed */
2509 /* Put back the command line */
2510 *NullBuffer
= SaveChar
;
2511 lpApplicationName
= NameBuffer
;
2512 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal
, NameBuffer
);
2514 else if (!lpCommandLine
|| *lpCommandLine
== UNICODE_NULL
)
2516 /* We have an app name (good!) but no command line */
2517 CmdLineIsAppName
= TRUE
;
2518 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2521 /* At this point the name has been toyed with enough to be openable */
2522 Status
= BasepMapFile(lpApplicationName
, &hSection
, &ApplicationName
);
2524 /* Check for failure */
2525 if (!NT_SUCCESS(Status
))
2527 /* Could be a non-PE File */
2530 /* Check if the Kernel tells us it's not even valid MZ */
2531 case STATUS_INVALID_IMAGE_NE_FORMAT
:
2532 case STATUS_INVALID_IMAGE_PROTECT
:
2533 case STATUS_INVALID_IMAGE_NOT_MZ
:
2536 /* If it's a DOS app, use VDM */
2537 if ((BasepCheckDosApp(&ApplicationName
)))
2539 DPRINT1("Launching VDM...\n");
2540 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2541 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2542 return CreateProcessW(L
"ntvdm.exe",
2543 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2544 lpProcessAttributes
,
2551 lpProcessInformation
);
2554 /* It's a batch file */
2555 Extension
= &ApplicationName
.Buffer
[ApplicationName
.Length
/
2558 /* Make sure the extensions are correct */
2559 if (_wcsnicmp(Extension
, L
".bat", 4) && _wcsnicmp(Extension
, L
".cmd", 4))
2561 SetLastError(ERROR_BAD_EXE_FORMAT
);
2565 /* Calculate the length of the command line */
2566 CmdLineLength
= wcslen(CMD_STRING
) + wcslen(lpCommandLine
) + 1;
2568 /* If we found quotes, then add them into the length size */
2569 if (CmdLineIsAppName
|| FoundQuotes
) CmdLineLength
+= 2;
2570 CmdLineLength
*= sizeof(WCHAR
);
2572 /* Allocate space for the new command line */
2573 BatchCommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2576 if (BatchCommandLine
== NULL
)
2578 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2583 wcscpy(BatchCommandLine
, CMD_STRING
);
2584 if (CmdLineIsAppName
|| FoundQuotes
)
2586 wcscat(BatchCommandLine
, L
"\"");
2588 wcscat(BatchCommandLine
, lpCommandLine
);
2589 if (CmdLineIsAppName
|| FoundQuotes
)
2591 wcscat(BatchCommandLine
, L
"\"");
2594 /* Create it as a Unicode String */
2595 RtlInitUnicodeString(&CommandLineString
, BatchCommandLine
);
2597 /* Set the command line to this */
2598 lpCommandLine
= CommandLineString
.Buffer
;
2599 lpApplicationName
= NULL
;
2602 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2603 ApplicationName
.Buffer
= NULL
;
2607 case STATUS_INVALID_IMAGE_WIN_16
:
2609 /* It's a Win16 Image, use VDM */
2610 DPRINT1("Launching VDM...\n");
2611 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2612 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2613 return CreateProcessW(L
"ntvdm.exe",
2614 (LPWSTR
)((ULONG_PTR
)lpApplicationName
), /* FIXME: Buffer must be writable!!! */
2615 lpProcessAttributes
,
2622 lpProcessInformation
);
2624 case STATUS_OBJECT_NAME_NOT_FOUND
:
2625 case STATUS_OBJECT_PATH_NOT_FOUND
:
2626 BaseSetLastNTError(Status
);
2630 /* Invalid Image Type */
2631 SetLastError(ERROR_BAD_EXE_FORMAT
);
2636 /* Use our desktop if we didn't get any */
2637 if (!StartupInfo
.lpDesktop
)
2639 StartupInfo
.lpDesktop
= OurPeb
->ProcessParameters
->DesktopInfo
.Buffer
;
2642 /* FIXME: Check if Application is allowed to run */
2644 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2646 /* Get some information about the executable */
2647 Status
= ZwQuerySection(hSection
,
2648 SectionImageInformation
,
2650 sizeof(SectionImageInfo
),
2652 if(!NT_SUCCESS(Status
))
2654 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status
);
2655 BaseSetLastNTError(Status
);
2659 /* Don't execute DLLs */
2660 if (SectionImageInfo
.ImageCharacteristics
& IMAGE_FILE_DLL
)
2662 DPRINT1("Can't execute a DLL\n");
2663 SetLastError(ERROR_BAD_EXE_FORMAT
);
2667 /* FIXME: Check for Debugger */
2669 /* FIXME: Check if Machine Type and SubSys Version Match */
2671 /* We don't support POSIX or anything else for now */
2672 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
!= SectionImageInfo
.SubSystemType
&&
2673 IMAGE_SUBSYSTEM_WINDOWS_CUI
!= SectionImageInfo
.SubSystemType
)
2675 DPRINT1("Invalid subsystem %d\n", SectionImageInfo
.SubSystemType
);
2676 SetLastError(ERROR_BAD_EXE_FORMAT
);
2680 if (IMAGE_SUBSYSTEM_WINDOWS_GUI
== SectionImageInfo
.SubSystemType
)
2682 /* Do not create a console for GUI applications */
2683 dwCreationFlags
&= ~CREATE_NEW_CONSOLE
;
2684 dwCreationFlags
|= DETACHED_PROCESS
;
2687 /* Initialize the process object attributes */
2688 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
2689 lpProcessAttributes
,
2692 /* Check if we're going to be debugged */
2693 if (dwCreationFlags
& DEBUG_PROCESS
)
2695 /* FIXME: Set process flag */
2698 /* Check if we're going to be debugged */
2699 if (dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
))
2701 /* Connect to DbgUi */
2702 Status
= DbgUiConnectToDbg();
2703 if (!NT_SUCCESS(Status
))
2705 DPRINT1("Failed to connect to DbgUI!\n");
2706 BaseSetLastNTError(Status
);
2710 /* Get the debug object */
2711 hDebug
= DbgUiGetThreadDebugObject();
2713 /* Check if only this process will be debugged */
2714 if (dwCreationFlags
& DEBUG_ONLY_THIS_PROCESS
)
2716 /* FIXME: Set process flag */
2720 /* Create the Process */
2721 Status
= NtCreateProcess(&hProcess
,
2725 (BOOLEAN
)bInheritHandles
,
2729 if (!NT_SUCCESS(Status
))
2731 DPRINT1("Unable to create process, status 0x%x\n", Status
);
2732 BaseSetLastNTError(Status
);
2736 if (PriorityClass
.PriorityClass
!= PROCESS_PRIORITY_CLASS_INVALID
)
2739 Status
= NtSetInformationProcess(hProcess
,
2740 ProcessPriorityClass
,
2742 sizeof(PROCESS_PRIORITY_CLASS
));
2743 if(!NT_SUCCESS(Status
))
2745 DPRINT1("Unable to set new process priority, status 0x%x\n", Status
);
2746 BaseSetLastNTError(Status
);
2751 /* Set Error Mode */
2752 if (dwCreationFlags
& CREATE_DEFAULT_ERROR_MODE
)
2754 ULONG ErrorMode
= SEM_FAILCRITICALERRORS
;
2755 NtSetInformationProcess(hProcess
,
2756 ProcessDefaultHardErrorMode
,
2761 /* Convert the directory to a full path */
2762 if (lpCurrentDirectory
)
2764 /* Allocate a buffer */
2765 CurrentDirectory
= RtlAllocateHeap(RtlGetProcessHeap(),
2767 (MAX_PATH
+ 1) * sizeof(WCHAR
));
2768 if (CurrentDirectory
== NULL
)
2770 DPRINT1("Cannot allocate memory for directory name\n");
2771 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2775 /* Get the length */
2776 if (GetFullPathNameW(lpCurrentDirectory
,
2779 &CurrentDirectoryPart
) > MAX_PATH
)
2781 DPRINT1("Directory name too long\n");
2782 SetLastError(ERROR_DIRECTORY
);
2787 /* Insert quotes if needed */
2788 if (QuotesNeeded
|| CmdLineIsAppName
)
2790 /* Allocate a buffer */
2791 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2793 (wcslen(lpCommandLine
) + 2 + 1) *
2795 if (QuotedCmdLine
== NULL
)
2797 DPRINT1("Cannot allocate memory for quoted command line\n");
2798 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2802 /* Copy the first quote */
2803 wcscpy(QuotedCmdLine
, L
"\"");
2805 /* Save a null char */
2808 SaveChar
= *NullBuffer
;
2809 *NullBuffer
= UNICODE_NULL
;
2812 /* Add the command line and the finishing quote */
2813 wcscat(QuotedCmdLine
, lpCommandLine
);
2814 wcscat(QuotedCmdLine
, L
"\"");
2816 /* Add the null char */
2819 *NullBuffer
= SaveChar
;
2820 wcscat(QuotedCmdLine
, NullBuffer
);
2823 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine
);
2828 if (QuotedCmdLine
== NULL
)
2830 QuotedCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
2832 (wcslen(lpCommandLine
) + 1) * sizeof(WCHAR
));
2833 if (QuotedCmdLine
== NULL
)
2835 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2838 wcscpy(QuotedCmdLine
, lpCommandLine
);
2841 ScanString
= QuotedCmdLine
;
2842 while (NULL
!= (ScanString
= wcschr(ScanString
, L
'^')))
2845 if (*ScanString
== L
'\"' || *ScanString
== L
'^' || *ScanString
== L
'\\')
2847 memmove(ScanString
-1, ScanString
, wcslen(ScanString
) * sizeof(WCHAR
) + sizeof(WCHAR
));
2852 /* Get the Process Information */
2853 Status
= NtQueryInformationProcess(hProcess
,
2854 ProcessBasicInformation
,
2856 sizeof(ProcessBasicInfo
),
2859 /* Convert the environment */
2860 if(lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2862 lpEnvironment
= BasepConvertUnicodeEnvironment(&EnvSize
, lpEnvironment
);
2863 if (!lpEnvironment
) goto Cleanup
;
2866 /* Create Process Environment */
2867 RemotePeb
= ProcessBasicInfo
.PebBaseAddress
;
2868 Status
= BasepInitializeEnvironment(hProcess
,
2870 (LPWSTR
)lpApplicationName
,
2872 (QuotesNeeded
|| CmdLineIsAppName
|| Escape
) ?
2873 QuotedCmdLine
: lpCommandLine
,
2880 /* Cleanup Environment */
2881 if (lpEnvironment
&& !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2883 RtlDestroyEnvironment(lpEnvironment
);
2886 if (!NT_SUCCESS(Status
))
2888 DPRINT1("Could not initialize Process Environment\n");
2889 BaseSetLastNTError(Status
);
2893 /* Close the section */
2897 /* Duplicate the handles if needed */
2898 if (!bInheritHandles
&& !(StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2899 SectionImageInfo
.SubSystemType
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
2901 PRTL_USER_PROCESS_PARAMETERS RemoteParameters
;
2903 /* Get the remote parameters */
2904 Status
= NtReadVirtualMemory(hProcess
,
2905 &RemotePeb
->ProcessParameters
,
2909 if (!NT_SUCCESS(Status
))
2911 DPRINT1("Failed to read memory\n");
2915 /* Duplicate and write the handles */
2916 BasepDuplicateAndWriteHandle(hProcess
,
2917 OurPeb
->ProcessParameters
->StandardInput
,
2918 &RemoteParameters
->StandardInput
);
2919 BasepDuplicateAndWriteHandle(hProcess
,
2920 OurPeb
->ProcessParameters
->StandardOutput
,
2921 &RemoteParameters
->StandardOutput
);
2922 BasepDuplicateAndWriteHandle(hProcess
,
2923 OurPeb
->ProcessParameters
->StandardError
,
2924 &RemoteParameters
->StandardError
);
2928 Status
= BasepNotifyCsrOfCreation(dwCreationFlags
,
2929 (HANDLE
)ProcessBasicInfo
.UniqueProcessId
,
2932 if (!NT_SUCCESS(Status
))
2934 DPRINT1("CSR Notification Failed");
2935 BaseSetLastNTError(Status
);
2939 /* Create the first thread */
2940 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
2941 SectionImageInfo
.TransferAddress
);
2942 hThread
= BasepCreateFirstThread(hProcess
,
2947 if (hThread
== NULL
)
2949 DPRINT1("Could not create Initial Thread\n");
2950 /* FIXME - set last error code */
2954 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
2956 NtResumeThread(hThread
, &Dummy
);
2960 lpProcessInformation
->dwProcessId
= (DWORD
)ClientId
.UniqueProcess
;
2961 lpProcessInformation
->dwThreadId
= (DWORD
)ClientId
.UniqueThread
;
2962 lpProcessInformation
->hProcess
= hProcess
;
2963 lpProcessInformation
->hThread
= hThread
;
2964 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread
,
2965 ClientId
.UniqueThread
, ClientId
.UniqueProcess
, hProcess
);
2966 hProcess
= hThread
= NULL
;
2970 /* De-allocate heap strings */
2971 if (NameBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2972 if (ApplicationName
.Buffer
)
2973 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName
.Buffer
);
2974 if (CurrentDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory
);
2975 if (QuotedCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine
);
2977 /* Kill any handles still alive */
2978 if (hSection
) NtClose(hSection
);
2981 /* We don't know any more details then this */
2982 NtTerminateProcess(hProcess
, STATUS_UNSUCCESSFUL
);
2985 if (hProcess
) NtClose(hProcess
);
2987 /* Return Success */
2996 CreateProcessW(LPCWSTR lpApplicationName
,
2997 LPWSTR lpCommandLine
,
2998 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2999 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3000 BOOL bInheritHandles
,
3001 DWORD dwCreationFlags
,
3002 LPVOID lpEnvironment
,
3003 LPCWSTR lpCurrentDirectory
,
3004 LPSTARTUPINFOW lpStartupInfo
,
3005 LPPROCESS_INFORMATION lpProcessInformation
)
3007 /* Call the internal (but exported) version */
3008 return CreateProcessInternalW(0,
3011 lpProcessAttributes
,
3018 lpProcessInformation
,
3027 CreateProcessInternalA(HANDLE hToken
,
3028 LPCSTR lpApplicationName
,
3029 LPSTR lpCommandLine
,
3030 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3031 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3032 BOOL bInheritHandles
,
3033 DWORD dwCreationFlags
,
3034 LPVOID lpEnvironment
,
3035 LPCSTR lpCurrentDirectory
,
3036 LPSTARTUPINFOA lpStartupInfo
,
3037 LPPROCESS_INFORMATION lpProcessInformation
,
3040 PUNICODE_STRING CommandLine
= NULL
;
3041 UNICODE_STRING DummyString
;
3042 UNICODE_STRING LiveCommandLine
;
3043 UNICODE_STRING ApplicationName
;
3044 UNICODE_STRING CurrentDirectory
;
3046 STARTUPINFOW StartupInfo
;
3048 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
3049 "lpStartupInfo %x, lpProcessInformation %x\n",
3050 dwCreationFlags
, lpEnvironment
, lpCurrentDirectory
,
3051 lpStartupInfo
, lpProcessInformation
);
3053 /* Copy Startup Info */
3054 RtlMoveMemory(&StartupInfo
, lpStartupInfo
, sizeof(*lpStartupInfo
));
3056 /* Initialize all strings to nothing */
3057 LiveCommandLine
.Buffer
= NULL
;
3058 DummyString
.Buffer
= NULL
;
3059 ApplicationName
.Buffer
= NULL
;
3060 CurrentDirectory
.Buffer
= NULL
;
3061 StartupInfo
.lpDesktop
= NULL
;
3062 StartupInfo
.lpReserved
= NULL
;
3063 StartupInfo
.lpTitle
= NULL
;
3065 /* Convert the Command line */
3068 /* If it's too long, then we'll have a problem */
3069 if ((strlen(lpCommandLine
) + 1) * sizeof(WCHAR
) <
3070 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
3072 /* Cache it in the TEB */
3073 CommandLine
= Basep8BitStringToStaticUnicodeString(lpCommandLine
);
3077 /* Use a dynamic version */
3078 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine
,
3084 /* The logic below will use CommandLine, so we must make it valid */
3085 CommandLine
= &DummyString
;
3088 /* Convert the Name and Directory */
3089 if (lpApplicationName
)
3091 Basep8BitStringToDynamicUnicodeString(&ApplicationName
,
3094 if (lpCurrentDirectory
)
3096 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory
,
3097 lpCurrentDirectory
);
3100 /* Now convert Startup Strings */
3101 if (lpStartupInfo
->lpReserved
)
3103 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpReserved
,
3104 &StartupInfo
.lpReserved
);
3106 if (lpStartupInfo
->lpDesktop
)
3108 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpDesktop
,
3109 &StartupInfo
.lpDesktop
);
3111 if (lpStartupInfo
->lpTitle
)
3113 BasepAnsiStringToHeapUnicodeString(lpStartupInfo
->lpTitle
,
3114 &StartupInfo
.lpTitle
);
3117 /* Call the Unicode function */
3118 bRetVal
= CreateProcessInternalW(hToken
,
3119 ApplicationName
.Buffer
,
3120 LiveCommandLine
.Buffer
?
3121 LiveCommandLine
.Buffer
: CommandLine
->Buffer
,
3122 lpProcessAttributes
,
3127 CurrentDirectory
.Buffer
,
3129 lpProcessInformation
,
3133 RtlFreeUnicodeString(&ApplicationName
);
3134 RtlFreeUnicodeString(&LiveCommandLine
);
3135 RtlFreeUnicodeString(&CurrentDirectory
);
3136 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpDesktop
);
3137 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpReserved
);
3138 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
.lpTitle
);
3140 /* Return what Unicode did */
3145 * FUNCTION: The CreateProcess function creates a new process and its
3146 * primary thread. The new process executes the specified executable file
3149 * lpApplicationName = Pointer to name of executable module
3150 * lpCommandLine = Pointer to command line string
3151 * lpProcessAttributes = Process security attributes
3152 * lpThreadAttributes = Thread security attributes
3153 * bInheritHandles = Handle inheritance flag
3154 * dwCreationFlags = Creation flags
3155 * lpEnvironment = Pointer to new environment block
3156 * lpCurrentDirectory = Pointer to current directory name
3157 * lpStartupInfo = Pointer to startup info
3158 * lpProcessInformation = Pointer to process information
3164 CreateProcessA(LPCSTR lpApplicationName
,
3165 LPSTR lpCommandLine
,
3166 LPSECURITY_ATTRIBUTES lpProcessAttributes
,
3167 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
3168 BOOL bInheritHandles
,
3169 DWORD dwCreationFlags
,
3170 LPVOID lpEnvironment
,
3171 LPCSTR lpCurrentDirectory
,
3172 LPSTARTUPINFOA lpStartupInfo
,
3173 LPPROCESS_INFORMATION lpProcessInformation
)
3175 /* Call the internal (but exported) version */
3176 return CreateProcessInternalA(0,
3179 lpProcessAttributes
,
3186 lpProcessInformation
,