[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / proc.c
1 /* $Id: proc.c 57086 2012-08-16 15:39:40Z akhaldi $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS *******************************************************************/
20
21 WaitForInputIdleType UserWaitForInputIdleRoutine;
22 UNICODE_STRING BaseUnicodeCommandLine;
23 ANSI_STRING BaseAnsiCommandLine;
24 UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
25 LPSTARTUPINFOA BaseAnsiStartupInfo = NULL;
26 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
27 BOOLEAN g_AppCertInitialized;
28 BOOLEAN g_HaveAppCerts;
29 LIST_ENTRY BasepAppCertDllsList;
30 RTL_CRITICAL_SECTION gcsAppCert;
31 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc;
32 NTSTATUS g_AppCertStatus;
33 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[2] =
34 {
35 {
36 BasepConfigureAppCertDlls,
37 1,
38 L"AppCertDlls",
39 &BasepAppCertDllsList,
40 0,
41 NULL,
42 0
43 }
44 };
45
46 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens;
47 HMODULE gSaferHandle = (HMODULE)-1;
48
49 VOID WINAPI
50 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
51
52 #define CMD_STRING L"cmd /c "
53
54 /* FUNCTIONS ****************************************************************/
55
56 VOID
57 WINAPI
58 StuffStdHandle(IN HANDLE ProcessHandle,
59 IN HANDLE StandardHandle,
60 IN PHANDLE Address)
61 {
62 NTSTATUS Status;
63 HANDLE DuplicatedHandle;
64 SIZE_T Dummy;
65
66 /* Duplicate the handle */
67 Status = NtDuplicateObject(NtCurrentProcess(),
68 StandardHandle,
69 ProcessHandle,
70 &DuplicatedHandle,
71 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
72 0,
73 0);
74 if (NT_SUCCESS(Status))
75 {
76 /* Write it */
77 NtWriteVirtualMemory(ProcessHandle,
78 Address,
79 &DuplicatedHandle,
80 sizeof(HANDLE),
81 &Dummy);
82 }
83 }
84
85 BOOLEAN
86 WINAPI
87 BuildSubSysCommandLine(IN LPWSTR SubsystemName,
88 IN LPWSTR ApplicationName,
89 IN LPWSTR CommandLine,
90 OUT PUNICODE_STRING SubsysCommandLine)
91 {
92 UNICODE_STRING CommandLineString, ApplicationNameString;
93 PWCHAR Buffer;
94 ULONG Length;
95
96 /* Convert to unicode strings */
97 RtlInitUnicodeString(&CommandLineString, ApplicationName);
98 RtlInitUnicodeString(&ApplicationNameString, CommandLine);
99
100 /* Allocate buffer for the output string */
101 Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32;
102 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
103 RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, Length);
104 if (!Buffer)
105 {
106 /* Fail, no memory */
107 BaseSetLastNTError(STATUS_NO_MEMORY);
108 return FALSE;
109 }
110
111 /* Build the final subsystem command line */
112 RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName);
113 RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString);
114 RtlAppendUnicodeToString(SubsysCommandLine, L" /C ");
115 RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString);
116 return TRUE;
117 }
118
119 BOOLEAN
120 WINAPI
121 BasepIsImageVersionOk(IN ULONG ImageMajorVersion,
122 IN ULONG ImageMinorVersion)
123 {
124 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
125 return ((ImageMajorVersion >= 3) &&
126 ((ImageMajorVersion != 3) ||
127 (ImageMinorVersion >= 10)) &&
128 (ImageMajorVersion <= SharedUserData->NtMajorVersion) &&
129 ((ImageMajorVersion != SharedUserData->NtMajorVersion) ||
130 (ImageMinorVersion <= SharedUserData->NtMinorVersion)));
131 }
132
133 NTSTATUS
134 WINAPI
135 BasepCheckWebBladeHashes(IN HANDLE FileHandle)
136 {
137 NTSTATUS Status;
138 CHAR Hash[16];
139
140 /* Get all the MD5 hashes */
141 Status = RtlComputeImportTableHash(FileHandle, Hash, 1);
142 if (!NT_SUCCESS(Status)) return Status;
143
144 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
145 if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER)
146 {
147 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
148 }
149 else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER)
150 {
151 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
152 }
153 else if (SharedUserData->SuiteMask & VER_SUITE_BLADE)
154 {
155 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
156 }
157
158 /* Actually, fuck it, don't block anything, we're open source */
159 return STATUS_SUCCESS;
160 }
161
162 NTSTATUS
163 NTAPI
164 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List,
165 IN PWCHAR ComponentName,
166 IN PWCHAR DllName)
167 {
168 /* Pretty much the only thing this key is used for, is malware */
169 UNIMPLEMENTED;
170 return STATUS_NOT_IMPLEMENTED;
171 }
172
173 NTSTATUS
174 NTAPI
175 BasepConfigureAppCertDlls(IN PWSTR ValueName,
176 IN ULONG ValueType,
177 IN PVOID ValueData,
178 IN ULONG ValueLength,
179 IN PVOID Context,
180 IN PVOID EntryContext)
181 {
182 /* Add this to the certification list */
183 return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData);
184 }
185
186 NTSTATUS
187 WINAPI
188 BasepIsProcessAllowed(IN PCHAR ApplicationName)
189 {
190 NTSTATUS Status;
191 PWCHAR Buffer;
192 UINT Length;
193 HMODULE TrustLibrary;
194 PBASEP_APPCERT_ENTRY Entry;
195 ULONG CertFlag;
196 PLIST_ENTRY NextEntry;
197 HANDLE KeyHandle;
198 UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
199 OBJECT_ATTRIBUTES KeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey, OBJ_CASE_INSENSITIVE);
200
201 /* Try to initialize the certification subsystem */
202 while (!g_AppCertInitialized)
203 {
204 /* Defaults */
205 Status = STATUS_SUCCESS;
206 Buffer = NULL;
207
208 /* Acquire the lock while initializing and see if we lost a race */
209 RtlEnterCriticalSection(&gcsAppCert);
210 if (g_AppCertInitialized) break;
211
212 /* On embedded, there is a special DLL */
213 if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT)
214 {
215 /* Allocate a buffer for the name */
216 Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
217 0,
218 MAX_PATH * sizeof(WCHAR) +
219 sizeof(UNICODE_NULL));
220 if (!Buffer)
221 {
222 /* Fail if no memory */
223 Status = STATUS_NO_MEMORY;
224 }
225 else
226 {
227 /* Now get the system32 directory in our buffer, make sure it fits */
228 Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL"));
229 if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL")))
230 {
231 /* Add a slash if needed, and add the embedded cert DLL name */
232 if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\';
233 RtlCopyMemory(&Buffer[Length],
234 L"EmbdTrst.DLL",
235 sizeof(L"EmbdTrst.DLL"));
236
237 /* Try to load it */
238 TrustLibrary = LoadLibraryW(Buffer);
239 if (TrustLibrary)
240 {
241 /* And extract the special function out of it */
242 fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary,
243 "ImageOkToRunOnEmbeddedNT");
244 }
245 }
246
247 /* If we didn't get this far, set a failure code */
248 if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL;
249 }
250 }
251 else
252 {
253 /* Other systems have a registry entry for this */
254 Status = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
255 if (NT_SUCCESS(Status))
256 {
257 /* Close it, we'll query it through Rtl */
258 NtClose(KeyHandle);
259
260 /* Do the query, which will call a special callback */
261 Status = RtlQueryRegistryValues(2,
262 L"Session Manager",
263 BasepAppCertTable,
264 0,
265 0);
266 if (Status == 0xC0000034) Status = STATUS_SUCCESS;
267 }
268 }
269
270 /* Free any buffer if we had one */
271 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
272
273 /* Check for errors, or a missing embedded/custom certification DLL */
274 if (!NT_SUCCESS(Status) ||
275 (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList))))
276 {
277 /* The subsystem is not active on this machine, so give up */
278 g_HaveAppCerts = FALSE;
279 g_AppCertStatus = Status;
280 }
281 else
282 {
283 /* We have certification DLLs active, remember this */
284 g_HaveAppCerts = TRUE;
285 }
286
287 /* We are done the initialization phase, release the lock */
288 g_AppCertInitialized = TRUE;
289 RtlLeaveCriticalSection(&gcsAppCert);
290 }
291
292 /* If there's no certification DLLs present, return the failure code */
293 if (!g_HaveAppCerts) return g_AppCertStatus;
294
295 /* Otherwise, assume success and make sure we have *something* */
296 ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList));
297 Status = STATUS_SUCCESS;
298
299 /* If the something is an embedded certification DLL, call it and return */
300 if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName);
301
302 /* Otherwise we have custom certification DLLs, parse them */
303 NextEntry = BasepAppCertDllsList.Flink;
304 CertFlag = 2;
305 while (NextEntry != &BasepAppCertDllsList)
306 {
307 /* Make sure the entry has a callback */
308 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
309 ASSERT(Entry->fPluginCertFunc != NULL);
310
311 /* Call it and check if it failed */
312 Status = Entry->fPluginCertFunc(ApplicationName, 1);
313 if (!NT_SUCCESS(Status)) CertFlag = 3;
314
315 /* Move on */
316 NextEntry = NextEntry->Flink;
317 }
318
319 /* Now loop them again */
320 NextEntry = BasepAppCertDllsList.Flink;
321 while (NextEntry != &BasepAppCertDllsList)
322 {
323 /* Make sure the entry has a callback */
324 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
325 ASSERT(Entry->fPluginCertFunc != NULL);
326
327 /* Call it, this time with the flag from the loop above */
328 Status = Entry->fPluginCertFunc(ApplicationName, CertFlag);
329 }
330
331 /* All done, return the status */
332 return Status;
333 }
334
335 NTSTATUS
336 WINAPI
337 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle,
338 IN HANDLE ProcessHandle,
339 IN HANDLE ThreadHandle)
340 {
341 NTSTATUS Status;
342 ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
343
344 /* Enter the application certification lock */
345 RtlEnterCriticalSection(&gcsAppCert);
346
347 /* Check if we already know the function */
348 if (g_SaferReplaceProcessThreadTokens)
349 {
350 /* Call it */
351 Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
352 ProcessHandle,
353 ThreadHandle) ?
354 STATUS_SUCCESS :
355 STATUS_UNSUCCESSFUL;
356 }
357 else
358 {
359 /* Check if the app certification DLL isn't loaded */
360 if (!(gSaferHandle) ||
361 (gSaferHandle == (HMODULE)-1) ||
362 (gSaferHandle == (HMODULE)-2))
363 {
364 /* Then we can't call the function */
365 Status = STATUS_ENTRYPOINT_NOT_FOUND;
366 }
367 else
368 {
369 /* We have the DLL, find the address of the Safer function */
370 Status = LdrGetProcedureAddress(gSaferHandle,
371 &SaferiReplaceProcessThreadTokens,
372 0,
373 (PVOID*)&g_SaferReplaceProcessThreadTokens);
374 if (NT_SUCCESS(Status))
375 {
376 /* Found it, now call it */
377 Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
378 ProcessHandle,
379 ThreadHandle) ?
380 STATUS_SUCCESS :
381 STATUS_UNSUCCESSFUL;
382 }
383 else
384 {
385 /* We couldn't find it, so this must be an unsupported DLL */
386 LdrUnloadDll(gSaferHandle);
387 gSaferHandle = NULL;
388 Status = STATUS_ENTRYPOINT_NOT_FOUND;
389 }
390 }
391 }
392
393 /* Release the lock and return the result */
394 RtlLeaveCriticalSection(&gcsAppCert);
395 return Status;
396 }
397
398 VOID
399 WINAPI
400 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles)
401 {
402 NTSTATUS Status;
403
404 /* Sanity checks */
405 ASSERT(Handles != NULL);
406 ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess());
407
408 /* Close the file handle */
409 if (Handles->File)
410 {
411 Status = NtClose(Handles->File);
412 ASSERT(NT_SUCCESS(Status));
413 }
414
415 /* Close the section handle */
416 if (Handles->Section)
417 {
418 Status = NtClose(Handles->Section);
419 ASSERT(NT_SUCCESS(Status));
420 }
421
422 /* Unmap the section view */
423 if (Handles->ViewBase.QuadPart)
424 {
425 Status = NtUnmapViewOfSection(NtCurrentProcess(),
426 (PVOID)Handles->ViewBase.LowPart);
427 ASSERT(NT_SUCCESS(Status));
428 }
429 }
430
431 static
432 LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
433 {
434 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
435 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
436 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
437
438 if (RealFilter != NULL)
439 {
440 _SEH2_TRY
441 {
442 ExceptionDisposition = RealFilter(ExceptionInfo);
443 }
444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
445 {
446 }
447 _SEH2_END;
448 }
449 if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
450 RealFilter != UnhandledExceptionFilter)
451 {
452 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
453 }
454
455 return ExceptionDisposition;
456 }
457
458 VOID
459 WINAPI
460 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
461 {
462 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
463
464 _SEH2_TRY
465 {
466 /* Set our Start Address */
467 NtSetInformationThread(NtCurrentThread(),
468 ThreadQuerySetWin32StartAddress,
469 &lpStartAddress,
470 sizeof(PPROCESS_START_ROUTINE));
471
472 /* Call the Start Routine */
473 ExitThread(lpStartAddress());
474 }
475 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
476 {
477 /* Get the Exit code from the SEH Handler */
478 if (!BaseRunningInServerProcess)
479 {
480 /* Kill the whole process, usually */
481 ExitProcess(_SEH2_GetExceptionCode());
482 }
483 else
484 {
485 /* If running inside CSRSS, kill just this thread */
486 ExitThread(_SEH2_GetExceptionCode());
487 }
488 }
489 _SEH2_END;
490 }
491
492 NTSTATUS
493 WINAPI
494 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
495 IN PCLIENT_ID ClientId)
496 {
497 ULONG Request = CREATE_THREAD;
498 CSR_API_MESSAGE CsrRequest;
499 NTSTATUS Status;
500
501 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
502 ClientId->UniqueThread, ThreadHandle);
503
504 /* Fill out the request */
505 CsrRequest.Data.CreateThreadRequest.ClientId = *ClientId;
506 CsrRequest.Data.CreateThreadRequest.ThreadHandle = ThreadHandle;
507
508 /* Call CSR */
509 Status = CsrClientCallServer(&CsrRequest,
510 NULL,
511 MAKE_CSR_API(Request, CSR_NATIVE),
512 sizeof(CSR_API_MESSAGE));
513 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
514 {
515 DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status, CsrRequest.Status);
516 return CsrRequest.Status;
517 }
518
519 /* Return Success */
520 return STATUS_SUCCESS;
521 }
522
523 /*
524 * Creates the first Thread in a Proces
525 */
526 HANDLE
527 WINAPI
528 BasepCreateFirstThread(HANDLE ProcessHandle,
529 LPSECURITY_ATTRIBUTES lpThreadAttributes,
530 PSECTION_IMAGE_INFORMATION SectionImageInfo,
531 PCLIENT_ID ClientId,
532 BOOLEAN InheritHandles,
533 DWORD dwCreationFlags)
534 {
535 OBJECT_ATTRIBUTES LocalObjectAttributes;
536 POBJECT_ATTRIBUTES ObjectAttributes;
537 CONTEXT Context;
538 INITIAL_TEB InitialTeb;
539 NTSTATUS Status;
540 HANDLE hThread;
541 ULONG Request = CREATE_PROCESS;
542 CSR_API_MESSAGE CsrRequest;
543 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
544
545 /* Create the Thread's Stack */
546 BaseCreateStack(ProcessHandle,
547 SectionImageInfo->MaximumStackSize,
548 SectionImageInfo->CommittedStackSize,
549 &InitialTeb);
550
551 /* Create the Thread's Context */
552 BaseInitializeContext(&Context,
553 NtCurrentPeb(),
554 SectionImageInfo->TransferAddress,
555 InitialTeb.StackBase,
556 0);
557
558 /* Convert the thread attributes */
559 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
560 lpThreadAttributes,
561 NULL);
562
563 /* Create the Kernel Thread Object */
564 Status = NtCreateThread(&hThread,
565 THREAD_ALL_ACCESS,
566 ObjectAttributes,
567 ProcessHandle,
568 ClientId,
569 &Context,
570 &InitialTeb,
571 TRUE);
572 if (!NT_SUCCESS(Status))
573 {
574 return NULL;
575 }
576
577 /* Fill out the request to notify CSRSS */
578 CsrRequest.Data.CreateProcessRequest.ClientId = *ClientId;
579 CsrRequest.Data.CreateProcessRequest.ProcessHandle = ProcessHandle;
580 CsrRequest.Data.CreateProcessRequest.ThreadHandle = hThread;
581 CsrRequest.Data.CreateProcessRequest.CreationFlags = dwCreationFlags;
582 CsrRequest.Data.CreateProcessRequest.bInheritHandles = InheritHandles;
583
584 /* Call CSR */
585 Status = CsrClientCallServer(&CsrRequest,
586 NULL,
587 MAKE_CSR_API(Request, CSR_NATIVE),
588 sizeof(CSR_API_MESSAGE));
589 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
590 {
591 DPRINT1("Failed to tell csrss about new process: %lx %lx\n", Status, CsrRequest.Status);
592 return NULL;
593 }
594
595 /* Success */
596 return hThread;
597 }
598
599 /*
600 * Converts ANSI to Unicode Environment
601 */
602 PVOID
603 WINAPI
604 BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize,
605 IN PVOID lpEnvironment)
606 {
607 PCHAR pcScan;
608 ANSI_STRING AnsiEnv;
609 UNICODE_STRING UnicodeEnv;
610 NTSTATUS Status;
611
612 DPRINT("BasepConvertUnicodeEnvironment\n");
613
614 /* Scan the environment to calculate its Unicode size */
615 AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
616 while (*pcScan)
617 {
618 pcScan += strlen(pcScan) + 1;
619 }
620
621 /* Create our ANSI String */
622 if (pcScan == (PCHAR)lpEnvironment)
623 {
624 AnsiEnv.Length = 2 * sizeof(CHAR);
625 }
626 else
627 {
628
629 AnsiEnv.Length = (USHORT)((ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + sizeof(CHAR));
630 }
631 AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
632
633 /* Allocate memory for the Unicode Environment */
634 UnicodeEnv.Buffer = NULL;
635 *EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
636 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
637 (PVOID)&UnicodeEnv.Buffer,
638 0,
639 EnvSize,
640 MEM_COMMIT,
641 PAGE_READWRITE);
642 /* Failure */
643 if (!NT_SUCCESS(Status))
644 {
645 SetLastError(Status);
646 *EnvSize = 0;
647 return NULL;
648 }
649
650 /* Use the allocated size */
651 UnicodeEnv.MaximumLength = (USHORT)*EnvSize;
652
653 /* Convert */
654 RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
655 return UnicodeEnv.Buffer;
656 }
657
658 /*
659 * Converts a Win32 Priority Class to NT
660 */
661 ULONG
662 WINAPI
663 BasepConvertPriorityClass(IN ULONG dwCreationFlags)
664 {
665 ULONG ReturnClass;
666
667 if(dwCreationFlags & IDLE_PRIORITY_CLASS)
668 {
669 ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
670 }
671 else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
672 {
673 ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
674 }
675 else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
676 {
677 ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
678 }
679 else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
680 {
681 ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
682 }
683 else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
684 {
685 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
686 }
687 else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
688 {
689 /* Check for Privilege First */
690 if (BasepIsRealtimeAllowed(TRUE))
691 {
692 ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
693 }
694 else
695 {
696 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
697 }
698 }
699 else
700 {
701 ReturnClass = PROCESS_PRIORITY_CLASS_INVALID;
702 }
703
704 return ReturnClass;
705 }
706
707 /*
708 * Duplicates a standard handle and writes it where requested.
709 */
710 VOID
711 WINAPI
712 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
713 IN HANDLE StandardHandle,
714 IN PHANDLE Address)
715 {
716 NTSTATUS Status;
717 HANDLE DuplicatedHandle;
718 SIZE_T Dummy;
719
720 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
721 "Address: %p\n", ProcessHandle, StandardHandle, Address);
722
723 /* Don't touch Console Handles */
724 if (IsConsoleHandle(StandardHandle)) return;
725
726 /* Duplicate the handle */
727 Status = NtDuplicateObject(NtCurrentProcess(),
728 StandardHandle,
729 ProcessHandle,
730 &DuplicatedHandle,
731 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
732 0,
733 0);
734 if (NT_SUCCESS(Status))
735 {
736 /* Write it */
737 NtWriteVirtualMemory(ProcessHandle,
738 Address,
739 &DuplicatedHandle,
740 sizeof(HANDLE),
741 &Dummy);
742 }
743 }
744
745 BOOLEAN
746 WINAPI
747 BasePushProcessParameters(IN ULONG ParameterFlags,
748 IN HANDLE ProcessHandle,
749 IN PPEB RemotePeb,
750 IN LPCWSTR ApplicationPathName,
751 IN LPWSTR lpCurrentDirectory,
752 IN LPWSTR lpCommandLine,
753 IN LPVOID lpEnvironment,
754 IN LPSTARTUPINFOW StartupInfo,
755 IN DWORD CreationFlags,
756 IN BOOL InheritHandles,
757 IN ULONG ImageSubsystem,
758 IN PVOID AppCompatData,
759 IN ULONG AppCompatDataSize)
760 {
761 WCHAR FullPath[MAX_PATH + 5];
762 PWCHAR Remaining, DllPathString, ScanChar;
763 PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters;
764 PVOID RemoteAppCompatData;
765 UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
766 UNICODE_STRING Desktop, Shell, Runtime, Title;
767 NTSTATUS Status;
768 ULONG EnviroSize;
769 SIZE_T Size;
770 BOOLEAN HavePebLock = FALSE, Result;
771 PPEB Peb = NtCurrentPeb();
772
773 /* Get the full path name */
774 Size = GetFullPathNameW(ApplicationPathName,
775 MAX_PATH + 4,
776 FullPath,
777 &Remaining);
778 if ((Size) && (Size <= (MAX_PATH + 4)))
779 {
780 /* Get the DLL Path */
781 DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment);
782 if (!DllPathString)
783 {
784 /* Fail */
785 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
786 return FALSE;
787 }
788
789 /* Initialize Strings */
790 RtlInitUnicodeString(&DllPath, DllPathString);
791 RtlInitUnicodeString(&ImageName, FullPath);
792 }
793 else
794 {
795 /* Couldn't get the path name. Just take the original path */
796 DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName,
797 lpEnvironment);
798 if (!DllPathString)
799 {
800 /* Fail */
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
802 return FALSE;
803 }
804
805 /* Initialize Strings */
806 RtlInitUnicodeString(&DllPath, DllPathString);
807 RtlInitUnicodeString(&ImageName, ApplicationPathName);
808 }
809
810 /* Initialize Strings */
811 RtlInitUnicodeString(&CommandLine, lpCommandLine);
812 RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
813
814 /* Initialize more Strings from the Startup Info */
815 if (StartupInfo->lpDesktop)
816 {
817 RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
818 }
819 else
820 {
821 RtlInitUnicodeString(&Desktop, L"");
822 }
823 if (StartupInfo->lpReserved)
824 {
825 RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
826 }
827 else
828 {
829 RtlInitUnicodeString(&Shell, L"");
830 }
831 if (StartupInfo->lpTitle)
832 {
833 RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
834 }
835 else
836 {
837 RtlInitUnicodeString(&Title, ApplicationPathName);
838 }
839
840 /* This one is special because the length can differ */
841 Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
842 Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
843
844 /* Enforce no app compat data if the pointer was NULL */
845 if (!AppCompatData) AppCompatDataSize = 0;
846
847 /* Create the Parameter Block */
848 ProcessParameters = NULL;
849 Status = RtlCreateProcessParameters(&ProcessParameters,
850 &ImageName,
851 &DllPath,
852 lpCurrentDirectory ?
853 &CurrentDirectory : NULL,
854 &CommandLine,
855 lpEnvironment,
856 &Title,
857 &Desktop,
858 &Shell,
859 &Runtime);
860 if (!NT_SUCCESS(Status)) goto FailPath;
861
862 /* Clear the current directory handle if not inheriting */
863 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
864
865 /* Check if the user passed in an environment */
866 if (lpEnvironment)
867 {
868 /* We should've made it part of the parameters block, enforce this */
869 ASSERT(ProcessParameters->Environment == lpEnvironment);
870 lpEnvironment = ProcessParameters->Environment;
871 }
872 else
873 {
874 /* The user did not, so use the one from the current PEB */
875 HavePebLock = TRUE;
876 RtlAcquirePebLock();
877 lpEnvironment = Peb->ProcessParameters->Environment;
878 }
879
880 /* Save pointer and start lookup */
881 ScanChar = lpEnvironment;
882 if (lpEnvironment)
883 {
884 /* Find the environment size */
885 while ((ScanChar[0]) || (ScanChar[1])) ++ScanChar;
886 ScanChar += (2 * sizeof(UNICODE_NULL));
887 EnviroSize = (ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment;
888
889 /* Allocate and Initialize new Environment Block */
890 Size = EnviroSize;
891 ProcessParameters->Environment = NULL;
892 Status = NtAllocateVirtualMemory(ProcessHandle,
893 (PVOID*)&ProcessParameters->Environment,
894 0,
895 &Size,
896 MEM_COMMIT,
897 PAGE_READWRITE);
898 if (!NT_SUCCESS(Status)) goto FailPath;
899
900 /* Write the Environment Block */
901 Status = NtWriteVirtualMemory(ProcessHandle,
902 ProcessParameters->Environment,
903 lpEnvironment,
904 EnviroSize,
905 NULL);
906
907 /* No longer need the PEB lock anymore */
908 if (HavePebLock)
909 {
910 /* Release it */
911 RtlReleasePebLock();
912 HavePebLock = FALSE;
913 }
914
915 /* Check if the write failed */
916 if (!NT_SUCCESS(Status)) goto FailPath;
917 }
918
919 /* Write new parameters */
920 ProcessParameters->StartingX = StartupInfo->dwX;
921 ProcessParameters->StartingY = StartupInfo->dwY;
922 ProcessParameters->CountX = StartupInfo->dwXSize;
923 ProcessParameters->CountY = StartupInfo->dwYSize;
924 ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
925 ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
926 ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
927 ProcessParameters->WindowFlags = StartupInfo->dwFlags;
928 ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
929
930 /* Write the handles only if we have to */
931 if (StartupInfo->dwFlags &
932 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
933 {
934 ProcessParameters->StandardInput = StartupInfo->hStdInput;
935 ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
936 ProcessParameters->StandardError = StartupInfo->hStdError;
937 }
938
939 /* Use Special Flags for ConDllInitialize in Kernel32 */
940 if (CreationFlags & DETACHED_PROCESS)
941 {
942 ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
943 }
944 else if (CreationFlags & CREATE_NO_WINDOW)
945 {
946 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
947 }
948 else if (CreationFlags & CREATE_NEW_CONSOLE)
949 {
950 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
951 }
952 else
953 {
954 /* Inherit our Console Handle */
955 ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle;
956
957 /* Make sure that the shell isn't trampling on our handles first */
958 if (!(StartupInfo->dwFlags &
959 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
960 {
961 /* Copy the handle if we are inheriting or if it's a console handle */
962 if ((InheritHandles) ||
963 (IsConsoleHandle(Peb->ProcessParameters->StandardInput)))
964 {
965 ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput;
966 }
967 if ((InheritHandles) ||
968 (IsConsoleHandle(Peb->ProcessParameters->StandardOutput)))
969 {
970 ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput;
971 }
972 if ((InheritHandles) ||
973 (IsConsoleHandle(Peb->ProcessParameters->StandardError)))
974 {
975 ProcessParameters->StandardError = Peb->ProcessParameters->StandardError;
976 }
977 }
978 }
979
980 /* Also set the Console Flag */
981 if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) &&
982 (!(CreationFlags & CREATE_NEW_CONSOLE)))
983 {
984 ProcessParameters->ConsoleFlags = 1;
985 }
986
987 /* See if the first 1MB should be reserved */
988 if (ParameterFlags & 1)
989 {
990 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
991 }
992
993 /* See if the first 16MB should be reserved */
994 if (ParameterFlags & 2)
995 {
996 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB;
997 }
998
999 /* Allocate memory for the parameter block */
1000 Size = ProcessParameters->Length;
1001 RemoteParameters = NULL;
1002 Status = NtAllocateVirtualMemory(ProcessHandle,
1003 (PVOID*)&RemoteParameters,
1004 0,
1005 &Size,
1006 MEM_COMMIT,
1007 PAGE_READWRITE);
1008 if (!NT_SUCCESS(Status)) goto FailPath;
1009
1010 /* Set the allocated size */
1011 ProcessParameters->MaximumLength = Size;
1012
1013 /* Handle some Parameter Flags */
1014 ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
1015 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0;
1016 ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
1017 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0;
1018 ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
1019 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0;
1020 ProcessParameters->Flags |= (Peb->ProcessParameters->Flags &
1021 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS);
1022
1023 /* Write the Parameter Block */
1024 Status = NtWriteVirtualMemory(ProcessHandle,
1025 RemoteParameters,
1026 ProcessParameters,
1027 ProcessParameters->Length,
1028 NULL);
1029 if (!NT_SUCCESS(Status)) goto FailPath;
1030
1031 /* Write the PEB Pointer */
1032 Status = NtWriteVirtualMemory(ProcessHandle,
1033 &RemotePeb->ProcessParameters,
1034 &RemoteParameters,
1035 sizeof(PVOID),
1036 NULL);
1037 if (!NT_SUCCESS(Status)) goto FailPath;
1038
1039 /* Check if there's any app compat data to write */
1040 RemoteAppCompatData = NULL;
1041 if (AppCompatData)
1042 {
1043 /* Allocate some space for the application compatibility data */
1044 Size = AppCompatDataSize;
1045 Status = NtAllocateVirtualMemory(ProcessHandle,
1046 &RemoteAppCompatData,
1047 0,
1048 &Size,
1049 MEM_COMMIT,
1050 PAGE_READWRITE);
1051 if (!NT_SUCCESS(Status)) goto FailPath;
1052
1053 /* Write the application compatibility data */
1054 Status = NtWriteVirtualMemory(ProcessHandle,
1055 RemoteAppCompatData,
1056 AppCompatData,
1057 AppCompatDataSize,
1058 NULL);
1059 if (!NT_SUCCESS(Status)) goto FailPath;
1060 }
1061
1062 /* Write the PEB Pointer to the app compat data (might be NULL) */
1063 Status = NtWriteVirtualMemory(ProcessHandle,
1064 &RemotePeb->pShimData,
1065 &RemoteAppCompatData,
1066 sizeof(PVOID),
1067 NULL);
1068 if (!NT_SUCCESS(Status)) goto FailPath;
1069
1070 /* Now write Peb->ImageSubSystem */
1071 if (ImageSubsystem)
1072 {
1073 NtWriteVirtualMemory(ProcessHandle,
1074 &RemotePeb->ImageSubsystem,
1075 &ImageSubsystem,
1076 sizeof(ImageSubsystem),
1077 NULL);
1078 }
1079
1080 /* Success path */
1081 Result = TRUE;
1082
1083 Quickie:
1084 /* Cleanup */
1085 if (HavePebLock) RtlReleasePebLock();
1086 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
1087 if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters);
1088 return Result;
1089 FailPath:
1090 DPRINT1("Failure to create proecss parameters: %lx\n", Status);
1091 BaseSetLastNTError(Status);
1092 Result = FALSE;
1093 goto Quickie;
1094 }
1095
1096 VOID
1097 WINAPI
1098 InitCommandLines(VOID)
1099 {
1100 NTSTATUS Status;
1101
1102 /* Read the UNICODE_STRING from the PEB */
1103 BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine;
1104
1105 /* Convert to ANSI_STRING for the *A callers */
1106 Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine,
1107 &BaseUnicodeCommandLine,
1108 TRUE);
1109 if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0);
1110 }
1111
1112 /* PUBLIC FUNCTIONS ***********************************************************/
1113
1114 /*
1115 * @implemented
1116 */
1117 BOOL
1118 WINAPI
1119 GetProcessAffinityMask(IN HANDLE hProcess,
1120 OUT PDWORD_PTR lpProcessAffinityMask,
1121 OUT PDWORD_PTR lpSystemAffinityMask)
1122 {
1123 PROCESS_BASIC_INFORMATION ProcessInfo;
1124 NTSTATUS Status;
1125
1126 /* Query information on the process from the kernel */
1127 Status = NtQueryInformationProcess(hProcess,
1128 ProcessBasicInformation,
1129 (PVOID)&ProcessInfo,
1130 sizeof(PROCESS_BASIC_INFORMATION),
1131 NULL);
1132 if (!NT_SUCCESS(Status))
1133 {
1134 /* Fail */
1135 BaseSetLastNTError(Status);
1136 return FALSE;
1137 }
1138
1139 /* Copy the affinity mask, and get the system one from our shared data */
1140 *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
1141 *lpSystemAffinityMask = (DWORD)BaseStaticServerData->SysInfo.ActiveProcessorsAffinityMask;
1142 return TRUE;
1143 }
1144
1145 /*
1146 * @implemented
1147 */
1148 BOOL
1149 WINAPI
1150 SetProcessAffinityMask(IN HANDLE hProcess,
1151 IN DWORD_PTR dwProcessAffinityMask)
1152 {
1153 NTSTATUS Status;
1154
1155 /* Directly set the affinity mask */
1156 Status = NtSetInformationProcess(hProcess,
1157 ProcessAffinityMask,
1158 (PVOID)&dwProcessAffinityMask,
1159 sizeof(DWORD));
1160 if (!NT_SUCCESS(Status))
1161 {
1162 /* Handle failure */
1163 BaseSetLastNTError(Status);
1164 return FALSE;
1165 }
1166
1167 /* Everything was ok */
1168 return TRUE;
1169 }
1170
1171 /*
1172 * @implemented
1173 */
1174 BOOL
1175 WINAPI
1176 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel,
1177 OUT LPDWORD lpdwFlags)
1178 {
1179 CSR_API_MESSAGE CsrRequest;
1180 NTSTATUS Status;
1181
1182 /* Ask CSRSS for shutdown information */
1183 Status = CsrClientCallServer(&CsrRequest,
1184 NULL,
1185 MAKE_CSR_API(GET_SHUTDOWN_PARAMETERS, CSR_NATIVE),
1186 sizeof(CSR_API_MESSAGE));
1187 if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(CsrRequest.Status)))
1188 {
1189 /* Return the failure from CSRSS */
1190 BaseSetLastNTError(CsrRequest.Status);
1191 return FALSE;
1192 }
1193
1194 /* Get the data out of the LCP reply */
1195 *lpdwLevel = CsrRequest.Data.GetShutdownParametersRequest.Level;
1196 *lpdwFlags = CsrRequest.Data.GetShutdownParametersRequest.Flags;
1197 return TRUE;
1198 }
1199
1200 /*
1201 * @implemented
1202 */
1203 BOOL
1204 WINAPI
1205 SetProcessShutdownParameters(IN DWORD dwLevel,
1206 IN DWORD dwFlags)
1207 {
1208 CSR_API_MESSAGE CsrRequest;
1209 NTSTATUS Status;
1210
1211 /* Write the data into the CSRSS request and send it */
1212 CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel;
1213 CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags;
1214 Status = CsrClientCallServer(&CsrRequest,
1215 NULL,
1216 MAKE_CSR_API(SET_SHUTDOWN_PARAMETERS, CSR_NATIVE),
1217 sizeof(CSR_API_MESSAGE));
1218 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
1219 {
1220 /* Return the failure from CSRSS */
1221 BaseSetLastNTError(CsrRequest.Status);
1222 return FALSE;
1223 }
1224
1225 /* All went well */
1226 return TRUE;
1227 }
1228
1229 /*
1230 * @implemented
1231 */
1232 BOOL
1233 WINAPI
1234 GetProcessWorkingSetSizeEx(IN HANDLE hProcess,
1235 OUT PSIZE_T lpMinimumWorkingSetSize,
1236 OUT PSIZE_T lpMaximumWorkingSetSize,
1237 OUT PDWORD Flags)
1238 {
1239 QUOTA_LIMITS_EX QuotaLimits;
1240 NTSTATUS Status;
1241
1242 /* Query the kernel about this */
1243 Status = NtQueryInformationProcess(hProcess,
1244 ProcessQuotaLimits,
1245 &QuotaLimits,
1246 sizeof(QUOTA_LIMITS_EX),
1247 NULL);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 /* Return error */
1251 BaseSetLastNTError(Status);
1252 return FALSE;
1253 }
1254
1255 /* Copy the quota information out */
1256 *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
1257 *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
1258 *Flags = QuotaLimits.Flags;
1259 return TRUE;
1260 }
1261
1262 /*
1263 * @implemented
1264 */
1265 BOOL
1266 WINAPI
1267 GetProcessWorkingSetSize(IN HANDLE hProcess,
1268 OUT PSIZE_T lpMinimumWorkingSetSize,
1269 OUT PSIZE_T lpMaximumWorkingSetSize)
1270 {
1271 DWORD Dummy;
1272 return GetProcessWorkingSetSizeEx(hProcess,
1273 lpMinimumWorkingSetSize,
1274 lpMaximumWorkingSetSize,
1275 &Dummy);
1276 }
1277
1278 /*
1279 * @implemented
1280 */
1281 BOOL
1282 WINAPI
1283 SetProcessWorkingSetSizeEx(IN HANDLE hProcess,
1284 IN SIZE_T dwMinimumWorkingSetSize,
1285 IN SIZE_T dwMaximumWorkingSetSize,
1286 IN DWORD Flags)
1287 {
1288 QUOTA_LIMITS_EX QuotaLimits;
1289 NTSTATUS Status, ReturnStatus;
1290 BOOL Result;
1291 PVOID State;
1292 ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
1293
1294 /* Zero out the input structure */
1295 RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits));
1296
1297 /* Check if the caller sent any limits */
1298 if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize))
1299 {
1300 /* Write the quota information */
1301 QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
1302 QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
1303 QuotaLimits.Flags = Flags;
1304
1305 /* Acquire the required privilege */
1306 Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
1307
1308 /* Request the new quotas */
1309 ReturnStatus = NtSetInformationProcess(hProcess,
1310 ProcessQuotaLimits,
1311 &QuotaLimits,
1312 sizeof(QuotaLimits));
1313 Result = NT_SUCCESS(ReturnStatus);
1314 if (NT_SUCCESS(Status))
1315 {
1316 /* Release the privilege and set succes code */
1317 ASSERT(State != NULL);
1318 RtlReleasePrivilege(State);
1319 State = NULL;
1320 }
1321 }
1322 else
1323 {
1324 /* No limits, fail the call */
1325 ReturnStatus = STATUS_INVALID_PARAMETER;
1326 Result = FALSE;
1327 }
1328
1329 /* Return result code, set error code if this was a failure */
1330 if (!Result) BaseSetLastNTError(ReturnStatus);
1331 return Result;
1332 }
1333
1334 /*
1335 * @implemented
1336 */
1337 BOOL
1338 WINAPI
1339 SetProcessWorkingSetSize(IN HANDLE hProcess,
1340 IN SIZE_T dwMinimumWorkingSetSize,
1341 IN SIZE_T dwMaximumWorkingSetSize)
1342 {
1343 /* Call the newer API */
1344 return SetProcessWorkingSetSizeEx(hProcess,
1345 dwMinimumWorkingSetSize,
1346 dwMaximumWorkingSetSize,
1347 0);
1348 }
1349
1350 /*
1351 * @implemented
1352 */
1353 BOOL
1354 WINAPI
1355 GetProcessTimes(IN HANDLE hProcess,
1356 IN LPFILETIME lpCreationTime,
1357 IN LPFILETIME lpExitTime,
1358 IN LPFILETIME lpKernelTime,
1359 IN LPFILETIME lpUserTime)
1360 {
1361 KERNEL_USER_TIMES Kut;
1362 NTSTATUS Status;
1363
1364 /* Query the times */
1365 Status = NtQueryInformationProcess(hProcess,
1366 ProcessTimes,
1367 &Kut,
1368 sizeof(Kut),
1369 NULL);
1370 if (!NT_SUCCESS(Status))
1371 {
1372 /* Handle failure */
1373 BaseSetLastNTError(Status);
1374 return FALSE;
1375 }
1376
1377 /* Copy all the times and return success */
1378 lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
1379 lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
1380 lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
1381 lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
1382 lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
1383 lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
1384 lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
1385 lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
1386 return TRUE;
1387 }
1388
1389 /*
1390 * @implemented
1391 */
1392 HANDLE
1393 WINAPI
1394 GetCurrentProcess(VOID)
1395 {
1396 return (HANDLE)NtCurrentProcess();
1397 }
1398
1399 /*
1400 * @implemented
1401 */
1402 HANDLE
1403 WINAPI
1404 GetCurrentThread(VOID)
1405 {
1406 return (HANDLE)NtCurrentThread();
1407 }
1408
1409 /*
1410 * @implemented
1411 */
1412 DWORD
1413 WINAPI
1414 GetCurrentProcessId(VOID)
1415 {
1416 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
1417 }
1418
1419 /*
1420 * @implemented
1421 */
1422 BOOL
1423 WINAPI
1424 GetExitCodeProcess(IN HANDLE hProcess,
1425 IN LPDWORD lpExitCode)
1426 {
1427 PROCESS_BASIC_INFORMATION ProcessBasic;
1428 NTSTATUS Status;
1429
1430 /* Ask the kernel */
1431 Status = NtQueryInformationProcess(hProcess,
1432 ProcessBasicInformation,
1433 &ProcessBasic,
1434 sizeof(PROCESS_BASIC_INFORMATION),
1435 NULL);
1436 if (!NT_SUCCESS(Status))
1437 {
1438 /* We failed, was this because this is a VDM process? */
1439 if (BaseCheckForVDM(hProcess, lpExitCode) == TRUE) return TRUE;
1440
1441 /* Not a VDM process, fail the call */
1442 BaseSetLastNTError(Status);
1443 return FALSE;
1444 }
1445
1446 /* Succes case, return the exit code */
1447 *lpExitCode = (DWORD)ProcessBasic.ExitStatus;
1448 return TRUE;
1449 }
1450
1451 /*
1452 * @implemented
1453 */
1454 DWORD
1455 WINAPI
1456 GetProcessId(IN HANDLE Process)
1457 {
1458 PROCESS_BASIC_INFORMATION ProcessBasic;
1459 NTSTATUS Status;
1460
1461 /* Query the kernel */
1462 Status = NtQueryInformationProcess(Process,
1463 ProcessBasicInformation,
1464 &ProcessBasic,
1465 sizeof(PROCESS_BASIC_INFORMATION),
1466 NULL);
1467 if (!NT_SUCCESS(Status))
1468 {
1469 /* Handle failure */
1470 BaseSetLastNTError(Status);
1471 return 0;
1472 }
1473
1474 /* Return the PID */
1475 return (DWORD)ProcessBasic.UniqueProcessId;
1476 }
1477
1478 /*
1479 * @implemented
1480 */
1481 HANDLE
1482 WINAPI
1483 OpenProcess(IN DWORD dwDesiredAccess,
1484 IN BOOL bInheritHandle,
1485 IN DWORD dwProcessId)
1486 {
1487 NTSTATUS Status;
1488 HANDLE ProcessHandle;
1489 OBJECT_ATTRIBUTES ObjectAttributes;
1490 CLIENT_ID ClientId;
1491
1492 /* Setup the input client ID structure */
1493 ClientId.UniqueProcess = UlongToHandle(dwProcessId);
1494 ClientId.UniqueThread = 0;
1495
1496 /* This is needed just to define the inheritance flags */
1497 InitializeObjectAttributes(&ObjectAttributes,
1498 NULL,
1499 (bInheritHandle ? OBJ_INHERIT : 0),
1500 NULL,
1501 NULL);
1502
1503 /* Now try to open the process */
1504 Status = NtOpenProcess(&ProcessHandle,
1505 dwDesiredAccess,
1506 &ObjectAttributes,
1507 &ClientId);
1508 if (!NT_SUCCESS(Status))
1509 {
1510 /* Handle failure */
1511 BaseSetLastNTError(Status);
1512 return NULL;
1513 }
1514
1515 /* Otherwise return a handle to the process */
1516 return ProcessHandle;
1517 }
1518
1519 /*
1520 * @implemented
1521 */
1522 VOID
1523 WINAPI
1524 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle)
1525 {
1526 /* Write the global function pointer */
1527 UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle;
1528 }
1529
1530 /*
1531 * @implemented
1532 */
1533 VOID
1534 WINAPI
1535 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo)
1536 {
1537 PRTL_USER_PROCESS_PARAMETERS Params;
1538
1539 /* Get the process parameters */
1540 Params = NtCurrentPeb()->ProcessParameters;
1541
1542 /* Copy the data out of there */
1543 lpStartupInfo->cb = sizeof(STARTUPINFOW);
1544 lpStartupInfo->lpReserved = Params->ShellInfo.Buffer;
1545 lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
1546 lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
1547 lpStartupInfo->dwX = Params->StartingX;
1548 lpStartupInfo->dwY = Params->StartingY;
1549 lpStartupInfo->dwXSize = Params->CountX;
1550 lpStartupInfo->dwYSize = Params->CountY;
1551 lpStartupInfo->dwXCountChars = Params->CountCharsX;
1552 lpStartupInfo->dwYCountChars = Params->CountCharsY;
1553 lpStartupInfo->dwFillAttribute = Params->FillAttribute;
1554 lpStartupInfo->dwFlags = Params->WindowFlags;
1555 lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1556 lpStartupInfo->cbReserved2 = Params->RuntimeData.Length;
1557 lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1558
1559 /* Check if the standard handles are being used for other features */
1560 if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES |
1561 STARTF_USEHOTKEY |
1562 STARTF_SHELLPRIVATE))
1563 {
1564 /* These are, so copy the standard handles too */
1565 lpStartupInfo->hStdInput = Params->StandardInput;
1566 lpStartupInfo->hStdOutput = Params->StandardOutput;
1567 lpStartupInfo->hStdError = Params->StandardError;
1568 }
1569 }
1570
1571 /*
1572 * @implemented
1573 */
1574 VOID
1575 WINAPI
1576 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo)
1577 {
1578 PRTL_USER_PROCESS_PARAMETERS Params;
1579 ANSI_STRING TitleString, ShellString, DesktopString;
1580 LPSTARTUPINFOA StartupInfo;
1581 NTSTATUS Status;
1582
1583 /* Get the cached information as well as the PEB parameters */
1584 StartupInfo = BaseAnsiStartupInfo;
1585 Params = NtCurrentPeb()->ProcessParameters;
1586
1587 /* Check if this is the first time we have to get the cached version */
1588 while (!StartupInfo)
1589 {
1590 /* Create new ANSI startup info */
1591 StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1592 0,
1593 sizeof(*StartupInfo));
1594 if (StartupInfo)
1595 {
1596 /* Zero out string pointers in case we fail to create them */
1597 StartupInfo->lpReserved = 0;
1598 StartupInfo->lpDesktop = 0;
1599 StartupInfo->lpTitle = 0;
1600
1601 /* Set the size */
1602 StartupInfo->cb = sizeof(*StartupInfo);
1603
1604 /* Copy what's already stored in the PEB */
1605 StartupInfo->dwX = Params->StartingX;
1606 StartupInfo->dwY = Params->StartingY;
1607 StartupInfo->dwXSize = Params->CountX;
1608 StartupInfo->dwYSize = Params->CountY;
1609 StartupInfo->dwXCountChars = Params->CountCharsX;
1610 StartupInfo->dwYCountChars = Params->CountCharsY;
1611 StartupInfo->dwFillAttribute = Params->FillAttribute;
1612 StartupInfo->dwFlags = Params->WindowFlags;
1613 StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1614 StartupInfo->cbReserved2 = Params->RuntimeData.Length;
1615 StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1616 StartupInfo->hStdInput = Params->StandardInput;
1617 StartupInfo->hStdOutput = Params->StandardOutput;
1618 StartupInfo->hStdError = Params->StandardError;
1619
1620 /* Copy shell info string */
1621 Status = RtlUnicodeStringToAnsiString(&ShellString,
1622 &Params->ShellInfo,
1623 TRUE);
1624 if (NT_SUCCESS(Status))
1625 {
1626 /* Save it */
1627 StartupInfo->lpReserved = ShellString.Buffer;
1628
1629 /* Copy desktop info string */
1630 Status = RtlUnicodeStringToAnsiString(&DesktopString,
1631 &Params->DesktopInfo,
1632 TRUE);
1633 if (NT_SUCCESS(Status))
1634 {
1635 /* Save it */
1636 StartupInfo->lpDesktop = DesktopString.Buffer;
1637
1638 /* Copy window title string */
1639 Status = RtlUnicodeStringToAnsiString(&TitleString,
1640 &Params->WindowTitle,
1641 TRUE);
1642 if (NT_SUCCESS(Status))
1643 {
1644 /* Save it */
1645 StartupInfo->lpTitle = TitleString.Buffer;
1646
1647 /* We finished with the ANSI version, try to cache it */
1648 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo,
1649 StartupInfo,
1650 NULL))
1651 {
1652 /* We were the first thread through, use the data */
1653 break;
1654 }
1655
1656 /* Someone beat us to it, use their data instead */
1657 StartupInfo = BaseAnsiStartupInfo;
1658 Status = STATUS_SUCCESS;
1659
1660 /* We're going to free our own stuff, but not raise */
1661 RtlFreeAnsiString(&TitleString);
1662 }
1663 RtlFreeAnsiString(&DesktopString);
1664 }
1665 RtlFreeAnsiString(&ShellString);
1666 }
1667 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo);
1668 }
1669 else
1670 {
1671 /* No memory, fail */
1672 Status = STATUS_NO_MEMORY;
1673 }
1674
1675 /* Raise an error unless we got here due to the race condition */
1676 if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
1677 }
1678
1679 /* Now copy from the cached ANSI version */
1680 lpStartupInfo->cb = StartupInfo->cb;
1681 lpStartupInfo->lpReserved = StartupInfo->lpReserved;
1682 lpStartupInfo->lpDesktop = StartupInfo->lpDesktop;
1683 lpStartupInfo->lpTitle = StartupInfo->lpTitle;
1684 lpStartupInfo->dwX = StartupInfo->dwX;
1685 lpStartupInfo->dwY = StartupInfo->dwY;
1686 lpStartupInfo->dwXSize = StartupInfo->dwXSize;
1687 lpStartupInfo->dwYSize = StartupInfo->dwYSize;
1688 lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars;
1689 lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars;
1690 lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute;
1691 lpStartupInfo->dwFlags = StartupInfo->dwFlags;
1692 lpStartupInfo->wShowWindow = StartupInfo->wShowWindow;
1693 lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2;
1694 lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2;
1695
1696 /* Check if the shell is hijacking the handles for other features */
1697 if (lpStartupInfo->dwFlags &
1698 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
1699 {
1700 /* It isn't, so we can return the raw values */
1701 lpStartupInfo->hStdInput = StartupInfo->hStdInput;
1702 lpStartupInfo->hStdOutput = StartupInfo->hStdOutput;
1703 lpStartupInfo->hStdError = StartupInfo->hStdError;
1704 }
1705 else
1706 {
1707 /* It is, so make sure nobody uses these as console handles */
1708 lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
1709 lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
1710 lpStartupInfo->hStdError = INVALID_HANDLE_VALUE;
1711 }
1712 }
1713
1714 /*
1715 * @implemented
1716 */
1717 BOOL
1718 WINAPI
1719 FlushInstructionCache(IN HANDLE hProcess,
1720 IN LPCVOID lpBaseAddress,
1721 IN SIZE_T dwSize)
1722 {
1723 NTSTATUS Status;
1724
1725 /* Call the native function */
1726 Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, dwSize);
1727 if (!NT_SUCCESS(Status))
1728 {
1729 /* Handle failure case */
1730 BaseSetLastNTError(Status);
1731 return FALSE;
1732 }
1733
1734 /* All good */
1735 return TRUE;
1736 }
1737
1738 /*
1739 * @implemented
1740 */
1741 VOID
1742 WINAPI
1743 ExitProcess(IN UINT uExitCode)
1744 {
1745 CSR_API_MESSAGE CsrRequest;
1746 ASSERT(!BaseRunningInServerProcess);
1747
1748 _SEH2_TRY
1749 {
1750 /* Acquire the PEB lock */
1751 RtlAcquirePebLock();
1752
1753 /* Kill all the threads */
1754 NtTerminateProcess(NULL, 0);
1755
1756 /* Unload all DLLs */
1757 LdrShutdownProcess();
1758
1759 /* Notify Base Server of process termination */
1760 CsrRequest.Data.TerminateProcessRequest.uExitCode = uExitCode;
1761 CsrClientCallServer(&CsrRequest,
1762 NULL,
1763 MAKE_CSR_API(TERMINATE_PROCESS, CSR_NATIVE),
1764 sizeof(CSR_API_MESSAGE));
1765
1766 /* Now do it again */
1767 NtTerminateProcess(NtCurrentProcess(), uExitCode);
1768 }
1769 _SEH2_FINALLY
1770 {
1771 /* Release the PEB lock */
1772 RtlReleasePebLock();
1773 }
1774 _SEH2_END;
1775
1776 /* should never get here */
1777 ASSERT(0);
1778 while(1);
1779 }
1780
1781 /*
1782 * @implemented
1783 */
1784 BOOL
1785 WINAPI
1786 TerminateProcess(IN HANDLE hProcess,
1787 IN UINT uExitCode)
1788 {
1789 NTSTATUS Status;
1790
1791 /* Check if no handle was passed in */
1792 if (!hProcess)
1793 {
1794 /* Set error code */
1795 SetLastError(ERROR_INVALID_HANDLE);
1796 }
1797 else
1798 {
1799 /* Otherwise, try to terminate the process */
1800 Status = NtTerminateProcess(hProcess, uExitCode);
1801 if (NT_SUCCESS(Status)) return TRUE;
1802
1803 /* It failed, convert error code */
1804 BaseSetLastNTError(Status);
1805 }
1806
1807 /* This is the failure path */
1808 return FALSE;
1809 }
1810
1811 /*
1812 * @implemented
1813 */
1814 VOID
1815 WINAPI
1816 FatalAppExitA(UINT uAction,
1817 LPCSTR lpMessageText)
1818 {
1819 PUNICODE_STRING MessageTextU;
1820 ANSI_STRING MessageText;
1821 NTSTATUS Status;
1822
1823 /* Initialize the string using the static TEB pointer */
1824 MessageTextU = &NtCurrentTeb()->StaticUnicodeString;
1825 RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText);
1826
1827 /* Convert to unicode and just exit normally if this failed */
1828 Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE);
1829 if (!NT_SUCCESS(Status)) ExitProcess(0);
1830
1831 /* Call the Wide function */
1832 FatalAppExitW(uAction, MessageTextU->Buffer);
1833 }
1834
1835 /*
1836 * @implemented
1837 */
1838 VOID
1839 WINAPI
1840 FatalAppExitW(IN UINT uAction,
1841 IN LPCWSTR lpMessageText)
1842 {
1843 UNICODE_STRING UnicodeString;
1844 ULONG Response;
1845 NTSTATUS Status;
1846
1847 /* Setup the stirng to print out */
1848 RtlInitUnicodeString(&UnicodeString, lpMessageText);
1849
1850 /* Display the hard error no matter what */
1851 Status = NtRaiseHardError(STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE,
1852 1,
1853 1,
1854 (PULONG_PTR)&UnicodeString,
1855 OptionOkCancel,
1856 &Response);
1857
1858 /* Give the user a chance to abort */
1859 if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) return;
1860
1861 /* Otherwise kill the process */
1862 ExitProcess(0);
1863 }
1864
1865 /*
1866 * @implemented
1867 */
1868 VOID
1869 WINAPI
1870 FatalExit(IN int ExitCode)
1871 {
1872 #if DBG
1873 /* On Checked builds, Windows gives you a nice little debugger UI */
1874 CHAR ch[2];
1875 DbgPrint("FatalExit...\n");
1876 DbgPrint("\n");
1877
1878 while (TRUE)
1879 {
1880 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch, sizeof(ch));
1881 switch (ch[0])
1882 {
1883 case 'B': case 'b':
1884 DbgBreakPoint();
1885 break;
1886
1887 case 'A': case 'a':
1888 ExitProcess(ExitCode);
1889
1890 case 'I': case 'i':
1891 return;
1892 }
1893 }
1894 #endif
1895 /* On other builds, just kill the process */
1896 ExitProcess(ExitCode);
1897 }
1898
1899 /*
1900 * @implemented
1901 */
1902 DWORD
1903 WINAPI
1904 GetPriorityClass(IN HANDLE hProcess)
1905 {
1906 NTSTATUS Status;
1907 PROCESS_PRIORITY_CLASS PriorityClass;
1908
1909 /* Query the kernel */
1910 Status = NtQueryInformationProcess(hProcess,
1911 ProcessPriorityClass,
1912 &PriorityClass,
1913 sizeof(PROCESS_PRIORITY_CLASS),
1914 NULL);
1915 if (NT_SUCCESS(Status))
1916 {
1917 /* Handle the conversion from NT to Win32 classes */
1918 switch (PriorityClass.PriorityClass)
1919 {
1920 case PROCESS_PRIORITY_CLASS_IDLE: return IDLE_PRIORITY_CLASS;
1921 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
1922 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
1923 case PROCESS_PRIORITY_CLASS_HIGH: return HIGH_PRIORITY_CLASS;
1924 case PROCESS_PRIORITY_CLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
1925 case PROCESS_PRIORITY_CLASS_NORMAL: default: return NORMAL_PRIORITY_CLASS;
1926 }
1927 }
1928
1929 /* Failure path */
1930 BaseSetLastNTError(Status);
1931 return FALSE;
1932 }
1933
1934 /*
1935 * @implemented
1936 */
1937 BOOL
1938 WINAPI
1939 SetPriorityClass(IN HANDLE hProcess,
1940 IN DWORD dwPriorityClass)
1941 {
1942 NTSTATUS Status;
1943 PVOID State = NULL;
1944 PROCESS_PRIORITY_CLASS PriorityClass;
1945
1946 /* Handle conversion from Win32 to NT priority classes */
1947 switch (dwPriorityClass)
1948 {
1949 case IDLE_PRIORITY_CLASS:
1950 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
1951 break;
1952
1953 case BELOW_NORMAL_PRIORITY_CLASS:
1954 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
1955 break;
1956
1957 case NORMAL_PRIORITY_CLASS:
1958 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
1959 break;
1960
1961 case ABOVE_NORMAL_PRIORITY_CLASS:
1962 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
1963 break;
1964
1965 case HIGH_PRIORITY_CLASS:
1966 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
1967 break;
1968
1969 case REALTIME_PRIORITY_CLASS:
1970 /* Try to acquire the privilege. If it fails, just use HIGH */
1971 State = BasepIsRealtimeAllowed(TRUE);
1972 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
1973 PriorityClass.PriorityClass += (State != NULL);
1974 break;
1975
1976 default:
1977 /* Unrecognized priority classes don't make it to the kernel */
1978 SetLastError(ERROR_INVALID_PARAMETER);
1979 return FALSE;
1980 }
1981
1982 /* Send the request to the kernel, and don't touch the foreground flag */
1983 PriorityClass.Foreground = FALSE;
1984 Status = NtSetInformationProcess(hProcess,
1985 ProcessPriorityClass,
1986 &PriorityClass,
1987 sizeof(PROCESS_PRIORITY_CLASS));
1988
1989 /* Release the privilege if we had it */
1990 if (State) RtlReleasePrivilege(State);
1991 if (!NT_SUCCESS(Status))
1992 {
1993 /* Handle error path */
1994 BaseSetLastNTError(Status);
1995 return FALSE;
1996 }
1997
1998 /* All done */
1999 return TRUE;
2000 }
2001
2002 /*
2003 * @implemented
2004 */
2005 DWORD
2006 WINAPI
2007 GetProcessVersion(IN DWORD ProcessId)
2008 {
2009 DWORD Version = 0;
2010 PIMAGE_NT_HEADERS NtHeader;
2011 PIMAGE_DOS_HEADER DosHeader;
2012 PPEB Peb;
2013 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
2014 PVOID BaseAddress;
2015 ULONG e_lfanew;
2016 HANDLE ProcessHandle = NULL;
2017 NTSTATUS Status;
2018 USHORT VersionData[2];
2019 BOOLEAN Result;
2020
2021 /* We'll be accessing stuff that can fault, so protect everything with SEH */
2022 _SEH2_TRY
2023 {
2024 /* It this an in-process or out-of-process request? */
2025 if (!(ProcessId) || (GetCurrentProcessId() == ProcessId))
2026 {
2027 /* It's in-process, so just read our own header */
2028 NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
2029 if (!NtHeader)
2030 {
2031 /* Unable to read the NT header, something is wrong here... */
2032 Status = STATUS_INVALID_IMAGE_FORMAT;
2033 goto Error;
2034 }
2035
2036 /* Get the version straight out of the NT header */
2037 Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion,
2038 NtHeader->OptionalHeader.MajorSubsystemVersion);
2039 }
2040 else
2041 {
2042 /* Out-of-process, so open it */
2043 ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
2044 FALSE,
2045 ProcessId);
2046 if (!ProcessHandle) return 0;
2047
2048 /* Try to find out where its PEB lives */
2049 Status = NtQueryInformationProcess(ProcessHandle,
2050 ProcessBasicInformation,
2051 &ProcessBasicInfo,
2052 sizeof(ProcessBasicInfo),
2053 NULL);
2054
2055 if (!NT_SUCCESS(Status)) goto Error;
2056 Peb = ProcessBasicInfo.PebBaseAddress;
2057
2058 /* Now that we have the PEB, read the image base address out of it */
2059 Result = ReadProcessMemory(ProcessHandle,
2060 &Peb->ImageBaseAddress,
2061 &BaseAddress,
2062 sizeof(BaseAddress),
2063 NULL);
2064 if (!Result) goto Error;
2065
2066 /* Now read the e_lfanew (offset to NT header) from the base */
2067 DosHeader = BaseAddress;
2068 Result = ReadProcessMemory(ProcessHandle,
2069 &DosHeader->e_lfanew,
2070 &e_lfanew,
2071 sizeof(e_lfanew),
2072 NULL);
2073 if (!Result) goto Error;
2074
2075 /* And finally, read the NT header itself by adding the offset */
2076 NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew);
2077 Result = ReadProcessMemory(ProcessHandle,
2078 &NtHeader->OptionalHeader.MajorSubsystemVersion,
2079 &VersionData,
2080 sizeof(VersionData),
2081 NULL);
2082 if (!Result) goto Error;
2083
2084 /* Get the version straight out of the NT header */
2085 Version = MAKELONG(VersionData[0], VersionData[1]);
2086
2087 Error:
2088 /* If there was an error anywhere, set the last error */
2089 if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
2090 }
2091 }
2092 _SEH2_FINALLY
2093 {
2094 /* Close the process handle */
2095 if (ProcessHandle) CloseHandle(ProcessHandle);
2096 }
2097 _SEH2_END;
2098
2099 /* And return the version data */
2100 return Version;
2101 }
2102
2103 /*
2104 * @implemented
2105 */
2106 BOOL
2107 WINAPI
2108 GetProcessIoCounters(IN HANDLE hProcess,
2109 OUT PIO_COUNTERS lpIoCounters)
2110 {
2111 NTSTATUS Status;
2112
2113 /* Query the kernel. Structures are identical, so let it do the copy too. */
2114 Status = NtQueryInformationProcess(hProcess,
2115 ProcessIoCounters,
2116 lpIoCounters,
2117 sizeof(IO_COUNTERS),
2118 NULL);
2119 if (!NT_SUCCESS(Status))
2120 {
2121 /* Handle error path */
2122 BaseSetLastNTError(Status);
2123 return FALSE;
2124 }
2125
2126 /* All done */
2127 return TRUE;
2128 }
2129
2130 /*
2131 * @implemented
2132 */
2133 BOOL
2134 WINAPI
2135 GetProcessPriorityBoost(IN HANDLE hProcess,
2136 OUT PBOOL pDisablePriorityBoost)
2137 {
2138 NTSTATUS Status;
2139 ULONG PriorityBoost;
2140
2141 /* Query the kernel */
2142 Status = NtQueryInformationProcess(hProcess,
2143 ProcessPriorityBoost,
2144 &PriorityBoost,
2145 sizeof(ULONG),
2146 NULL);
2147 if (NT_SUCCESS(Status))
2148 {
2149 /* Convert from ULONG to a BOOL */
2150 *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE;
2151 return TRUE;
2152 }
2153
2154 /* Handle error path */
2155 BaseSetLastNTError(Status);
2156 return FALSE;
2157 }
2158
2159 /*
2160 * @implemented
2161 */
2162 BOOL
2163 WINAPI
2164 SetProcessPriorityBoost(IN HANDLE hProcess,
2165 IN BOOL bDisablePriorityBoost)
2166 {
2167 NTSTATUS Status;
2168 ULONG PriorityBoost;
2169
2170 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
2171 PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE);
2172 Status = NtSetInformationProcess(hProcess,
2173 ProcessPriorityBoost,
2174 &PriorityBoost,
2175 sizeof(ULONG));
2176 if (!NT_SUCCESS(Status))
2177 {
2178 /* Handle error path */
2179 BaseSetLastNTError(Status);
2180 return FALSE;
2181 }
2182
2183 /* All done */
2184 return TRUE;
2185 }
2186
2187 /*
2188 * @implemented
2189 */
2190 BOOL
2191 WINAPI
2192 GetProcessHandleCount(IN HANDLE hProcess,
2193 OUT PDWORD pdwHandleCount)
2194 {
2195 ULONG phc;
2196 NTSTATUS Status;
2197
2198 /* Query the kernel */
2199 Status = NtQueryInformationProcess(hProcess,
2200 ProcessHandleCount,
2201 &phc,
2202 sizeof(ULONG),
2203 NULL);
2204 if (NT_SUCCESS(Status))
2205 {
2206 /* Copy the count and return sucecss */
2207 *pdwHandleCount = phc;
2208 return TRUE;
2209 }
2210
2211 /* Handle error path */
2212 BaseSetLastNTError(Status);
2213 return FALSE;
2214 }
2215
2216 /*
2217 * @implemented
2218 */
2219 BOOL
2220 WINAPI
2221 IsWow64Process(IN HANDLE hProcess,
2222 OUT PBOOL Wow64Process)
2223 {
2224 ULONG_PTR pbi;
2225 NTSTATUS Status;
2226
2227 /* Query the kernel */
2228 Status = NtQueryInformationProcess(hProcess,
2229 ProcessWow64Information,
2230 &pbi,
2231 sizeof(pbi),
2232 NULL);
2233 if (!NT_SUCCESS(Status))
2234 {
2235 /* Handle error path */
2236 BaseSetLastNTError(Status);
2237 return FALSE;
2238 }
2239
2240 /* Enforce this is a BOOL, and return success */
2241 *Wow64Process = (pbi != 0);
2242 return TRUE;
2243 }
2244
2245 /*
2246 * @implemented
2247 */
2248 LPSTR
2249 WINAPI
2250 GetCommandLineA(VOID)
2251 {
2252 return BaseAnsiCommandLine.Buffer;
2253 }
2254
2255 /*
2256 * @implemented
2257 */
2258 LPWSTR
2259 WINAPI
2260 GetCommandLineW(VOID)
2261 {
2262 return BaseUnicodeCommandLine.Buffer;
2263 }
2264
2265 /*
2266 * @implemented
2267 */
2268 BOOL
2269 NTAPI
2270 ReadProcessMemory(IN HANDLE hProcess,
2271 IN LPCVOID lpBaseAddress,
2272 IN LPVOID lpBuffer,
2273 IN SIZE_T nSize,
2274 OUT SIZE_T* lpNumberOfBytesRead)
2275 {
2276 NTSTATUS Status;
2277
2278 /* Do the read */
2279 Status = NtReadVirtualMemory(hProcess,
2280 (PVOID)lpBaseAddress,
2281 lpBuffer,
2282 nSize,
2283 &nSize);
2284
2285 /* In user-mode, this parameter is optional */
2286 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
2287 if (!NT_SUCCESS(Status))
2288 {
2289 /* We failed */
2290 BaseSetLastNTError(Status);
2291 return FALSE;
2292 }
2293
2294 /* Return success */
2295 return TRUE;
2296 }
2297
2298 /*
2299 * @implemented
2300 */
2301 BOOL
2302 NTAPI
2303 WriteProcessMemory(IN HANDLE hProcess,
2304 IN LPVOID lpBaseAddress,
2305 IN LPCVOID lpBuffer,
2306 IN SIZE_T nSize,
2307 OUT SIZE_T *lpNumberOfBytesWritten)
2308 {
2309 NTSTATUS Status;
2310 ULONG OldValue;
2311 SIZE_T RegionSize;
2312 PVOID Base;
2313 BOOLEAN UnProtect;
2314
2315 /* Set parameters for protect call */
2316 RegionSize = nSize;
2317 Base = lpBaseAddress;
2318
2319 /* Check the current status */
2320 Status = NtProtectVirtualMemory(hProcess,
2321 &Base,
2322 &RegionSize,
2323 PAGE_EXECUTE_READWRITE,
2324 &OldValue);
2325 if (NT_SUCCESS(Status))
2326 {
2327 /* Check if we are unprotecting */
2328 UnProtect = OldValue & (PAGE_READWRITE |
2329 PAGE_WRITECOPY |
2330 PAGE_EXECUTE_READWRITE |
2331 PAGE_EXECUTE_WRITECOPY) ? FALSE : TRUE;
2332 if (!UnProtect)
2333 {
2334 /* Set the new protection */
2335 Status = NtProtectVirtualMemory(hProcess,
2336 &Base,
2337 &RegionSize,
2338 OldValue,
2339 &OldValue);
2340
2341 /* Write the memory */
2342 Status = NtWriteVirtualMemory(hProcess,
2343 lpBaseAddress,
2344 (LPVOID)lpBuffer,
2345 nSize,
2346 &nSize);
2347
2348 /* In Win32, the parameter is optional, so handle this case */
2349 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
2350
2351 if (!NT_SUCCESS(Status))
2352 {
2353 /* We failed */
2354 BaseSetLastNTError(Status);
2355 return FALSE;
2356 }
2357
2358 /* Flush the ITLB */
2359 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
2360 return TRUE;
2361 }
2362 else
2363 {
2364 /* Check if we were read only */
2365 if (OldValue & (PAGE_NOACCESS | PAGE_READONLY))
2366 {
2367 /* Restore protection and fail */
2368 NtProtectVirtualMemory(hProcess,
2369 &Base,
2370 &RegionSize,
2371 OldValue,
2372 &OldValue);
2373 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
2374
2375 /* Note: This is what Windows returns and code depends on it */
2376 return STATUS_ACCESS_VIOLATION;
2377 }
2378
2379 /* Otherwise, do the write */
2380 Status = NtWriteVirtualMemory(hProcess,
2381 lpBaseAddress,
2382 (LPVOID)lpBuffer,
2383 nSize,
2384 &nSize);
2385
2386 /* In Win32, the parameter is optional, so handle this case */
2387 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
2388
2389 /* And restore the protection */
2390 NtProtectVirtualMemory(hProcess,
2391 &Base,
2392 &RegionSize,
2393 OldValue,
2394 &OldValue);
2395 if (!NT_SUCCESS(Status))
2396 {
2397 /* We failed */
2398 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
2399
2400 /* Note: This is what Windows returns and code depends on it */
2401 return STATUS_ACCESS_VIOLATION;
2402 }
2403
2404 /* Flush the ITLB */
2405 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
2406 return TRUE;
2407 }
2408 }
2409 else
2410 {
2411 /* We failed */
2412 BaseSetLastNTError(Status);
2413 return FALSE;
2414 }
2415 }
2416
2417 /*
2418 * @implemented
2419 */
2420 BOOL
2421 WINAPI
2422 ProcessIdToSessionId(IN DWORD dwProcessId,
2423 OUT PDWORD pSessionId)
2424 {
2425 PROCESS_SESSION_INFORMATION SessionInformation;
2426 OBJECT_ATTRIBUTES ObjectAttributes;
2427 CLIENT_ID ClientId;
2428 HANDLE ProcessHandle;
2429 NTSTATUS Status;
2430
2431 /* Do a quick check if the pointer is not writable */
2432 if (IsBadWritePtr(pSessionId, sizeof(DWORD)))
2433 {
2434 /* Fail fast */
2435 SetLastError(ERROR_INVALID_PARAMETER);
2436 return FALSE;
2437 }
2438
2439 /* Open the process passed in by ID */
2440 ClientId.UniqueProcess = UlongToHandle(dwProcessId);
2441 ClientId.UniqueThread = 0;
2442 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2443 Status = NtOpenProcess(&ProcessHandle,
2444 PROCESS_QUERY_INFORMATION,
2445 &ObjectAttributes,
2446 &ClientId);
2447 if (NT_SUCCESS(Status))
2448 {
2449 /* Query the session ID from the kernel */
2450 Status = NtQueryInformationProcess(ProcessHandle,
2451 ProcessSessionInformation,
2452 &SessionInformation,
2453 sizeof(SessionInformation),
2454 NULL);
2455
2456 /* Close the handle and check if we suceeded */
2457 NtClose(ProcessHandle);
2458 if (NT_SUCCESS(Status))
2459 {
2460 /* Return the session ID */
2461 *pSessionId = SessionInformation.SessionId;
2462 return TRUE;
2463 }
2464 }
2465
2466 /* Set error code and fail */
2467 BaseSetLastNTError(Status);
2468 return FALSE;
2469 }
2470
2471 /*
2472 * @implemented
2473 */
2474 BOOL
2475 WINAPI
2476 CreateProcessInternalW(HANDLE hToken,
2477 LPCWSTR lpApplicationName,
2478 LPWSTR lpCommandLine,
2479 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2480 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2481 BOOL bInheritHandles,
2482 DWORD dwCreationFlags,
2483 LPVOID lpEnvironment,
2484 LPCWSTR lpCurrentDirectory,
2485 LPSTARTUPINFOW lpStartupInfo,
2486 LPPROCESS_INFORMATION lpProcessInformation,
2487 PHANDLE hNewToken)
2488 {
2489 NTSTATUS Status;
2490 PROCESS_PRIORITY_CLASS PriorityClass;
2491 BOOLEAN FoundQuotes = FALSE;
2492 BOOLEAN QuotesNeeded = FALSE;
2493 BOOLEAN CmdLineIsAppName = FALSE;
2494 UNICODE_STRING ApplicationName = { 0, 0, NULL };
2495 OBJECT_ATTRIBUTES LocalObjectAttributes;
2496 POBJECT_ATTRIBUTES ObjectAttributes;
2497 HANDLE hSection = NULL, hProcess = NULL, hThread = NULL, hDebug = NULL;
2498 SECTION_IMAGE_INFORMATION SectionImageInfo;
2499 LPWSTR CurrentDirectory = NULL;
2500 LPWSTR CurrentDirectoryPart;
2501 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
2502 STARTUPINFOW StartupInfo;
2503 ULONG Dummy;
2504 LPWSTR BatchCommandLine;
2505 ULONG CmdLineLength;
2506 UNICODE_STRING CommandLineString;
2507 PWCHAR Extension;
2508 LPWSTR QuotedCmdLine = NULL;
2509 LPWSTR ScanString;
2510 LPWSTR NullBuffer = NULL;
2511 LPWSTR NameBuffer = NULL;
2512 WCHAR SaveChar = 0;
2513 ULONG RetVal;
2514 UINT Error = 0;
2515 BOOLEAN SearchDone = FALSE;
2516 BOOLEAN Escape = FALSE;
2517 CLIENT_ID ClientId;
2518 PPEB OurPeb = NtCurrentPeb();
2519 PPEB RemotePeb;
2520 SIZE_T EnvSize = 0;
2521 BOOL Ret = FALSE;
2522
2523 /* FIXME should process
2524 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2525 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2526 */
2527
2528 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2529 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2530 lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
2531 dwCreationFlags);
2532
2533 /* Flags we don't handle yet */
2534 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
2535 {
2536 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2537 }
2538 if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
2539 {
2540 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2541 }
2542 if (dwCreationFlags & CREATE_FORCEDOS)
2543 {
2544 DPRINT1("CREATE_FORCEDOS not handled\n");
2545 }
2546
2547 /* Fail on this flag, it's only valid with the WithLogonW function */
2548 if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
2549 {
2550 DPRINT1("Invalid flag used\n");
2551 SetLastError(ERROR_INVALID_PARAMETER);
2552 return FALSE;
2553 }
2554
2555 /* This combination is illegal (see MSDN) */
2556 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
2557 (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
2558 {
2559 DPRINT1("Invalid flag combo used\n");
2560 SetLastError(ERROR_INVALID_PARAMETER);
2561 return FALSE;
2562 }
2563
2564 /* Another illegal combo */
2565 if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
2566 (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
2567 {
2568 DPRINT1("Invalid flag combo used\n");
2569 SetLastError(ERROR_INVALID_PARAMETER);
2570 return FALSE;
2571 }
2572
2573 if (lpCurrentDirectory)
2574 {
2575 if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) ||
2576 !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY))
2577 {
2578 SetLastError(ERROR_DIRECTORY);
2579 return FALSE;
2580 }
2581 }
2582
2583 /*
2584 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2585 * so we'll use our own local copy for that.
2586 */
2587 StartupInfo = *lpStartupInfo;
2588
2589 /* FIXME: Use default Separate/Shared VDM Flag */
2590
2591 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2592 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
2593 {
2594 if (NtIsProcessInJob(NtCurrentProcess(), NULL))
2595 {
2596 /* Remove the shared flag and add the separate flag. */
2597 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
2598 CREATE_SEPARATE_WOW_VDM;
2599 }
2600 }
2601
2602 /*
2603 * According to some sites, ShellExecuteEx uses an undocumented flag to
2604 * send private handle data (such as HMONITOR or HICON). See:
2605 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2606 * standard handles anymore since we'd be overwriting this private data
2607 */
2608 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
2609 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
2610 {
2611 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
2612 }
2613
2614 /* Start by zeroing out the fields */
2615 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
2616
2617 /* Easy stuff first, convert the process priority class */
2618 PriorityClass.Foreground = FALSE;
2619 PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags);
2620
2621 if (lpCommandLine)
2622 {
2623 /* Search for escape sequences */
2624 ScanString = lpCommandLine;
2625 while (NULL != (ScanString = wcschr(ScanString, L'^')))
2626 {
2627 ScanString++;
2628 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
2629 {
2630 Escape = TRUE;
2631 break;
2632 }
2633 }
2634 }
2635
2636 /* Get the application name and do all the proper formating necessary */
2637 GetAppName:
2638 /* See if we have an application name (oh please let us have one!) */
2639 if (!lpApplicationName)
2640 {
2641 /* The fun begins */
2642 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2643 0,
2644 MAX_PATH * sizeof(WCHAR));
2645 if (NameBuffer == NULL)
2646 {
2647 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2648 goto Cleanup;
2649 }
2650
2651 /* This is all we have to work with :( */
2652 lpApplicationName = lpCommandLine;
2653
2654 /* Initialize our friends at the beginning */
2655 NullBuffer = (LPWSTR)lpApplicationName;
2656 ScanString = (LPWSTR)lpApplicationName;
2657
2658 /* We will start by looking for a quote */
2659 if (*ScanString == L'\"')
2660 {
2661 /* That was quick */
2662 SearchDone = TRUE;
2663
2664 /* Advance past quote */
2665 ScanString++;
2666 lpApplicationName = ScanString;
2667
2668 /* Find the closing quote */
2669 while (*ScanString)
2670 {
2671 if (*ScanString == L'\"' && *(ScanString - 1) != L'^')
2672 {
2673 /* Found it */
2674 NullBuffer = ScanString;
2675 FoundQuotes = TRUE;
2676 break;
2677 }
2678
2679 /* Keep looking */
2680 ScanString++;
2681 NullBuffer = ScanString;
2682 }
2683 }
2684 else
2685 {
2686 /* No quotes, so we'll be looking for white space */
2687 WhiteScan:
2688 /* Reset the pointer */
2689 lpApplicationName = lpCommandLine;
2690
2691 /* Find whitespace of Tab */
2692 while (*ScanString)
2693 {
2694 if (*ScanString == ' ' || *ScanString == '\t')
2695 {
2696 /* Found it */
2697 NullBuffer = ScanString;
2698 break;
2699 }
2700
2701 /* Keep looking */
2702 ScanString++;
2703 NullBuffer = ScanString;
2704 }
2705 }
2706
2707 /* Set the Null Buffer */
2708 SaveChar = *NullBuffer;
2709 *NullBuffer = UNICODE_NULL;
2710
2711 /* Do a search for the file */
2712 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
2713 RetVal = SearchPathW(NULL,
2714 lpApplicationName,
2715 L".exe",
2716 MAX_PATH,
2717 NameBuffer,
2718 NULL) * sizeof(WCHAR);
2719
2720 /* Did it find something? */
2721 if (RetVal)
2722 {
2723 /* Get file attributes */
2724 ULONG Attributes = GetFileAttributesW(NameBuffer);
2725 if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
2726 {
2727 /* Give it a length of 0 to fail, this was a directory. */
2728 RetVal = 0;
2729 }
2730 else
2731 {
2732 /* It's a file! */
2733 RetVal += sizeof(WCHAR);
2734 }
2735 }
2736
2737 /* Now check if we have a file, and if the path size is OK */
2738 if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR)))
2739 {
2740 ULONG PathType;
2741 HANDLE hFile;
2742
2743 /* We failed, try to get the Path Type */
2744 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
2745 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2746
2747 /* If it's not relative, try to get the error */
2748 if (PathType != RtlPathTypeRelative)
2749 {
2750 /* This should fail, and give us a detailed LastError */
2751 hFile = CreateFileW(lpApplicationName,
2752 GENERIC_READ,
2753 FILE_SHARE_READ | FILE_SHARE_WRITE,
2754 NULL,
2755 OPEN_EXISTING,
2756 FILE_ATTRIBUTE_NORMAL,
2757 NULL);
2758
2759 /* Did it actually NOT fail? */
2760 if (hFile != INVALID_HANDLE_VALUE)
2761 {
2762 /* Fake the error */
2763 CloseHandle(hFile);
2764 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
2765 }
2766 }
2767 else
2768 {
2769 /* Immediately set the error */
2770 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
2771 }
2772
2773 /* Did we already fail once? */
2774 if (Error)
2775 {
2776 SetLastError(Error);
2777 }
2778 else
2779 {
2780 /* Not yet, cache it */
2781 Error = GetLastError();
2782 }
2783
2784 /* Put back the command line */
2785 *NullBuffer = SaveChar;
2786 lpApplicationName = NameBuffer;
2787
2788 /*
2789 * If the search isn't done and we still have cmdline
2790 * then start over. Ex: c:\ha ha ha\haha.exe
2791 */
2792 if (*ScanString && !SearchDone)
2793 {
2794 /* Move in the buffer */
2795 ScanString++;
2796 NullBuffer = ScanString;
2797
2798 /* We will have to add a quote, since there is a space*/
2799 QuotesNeeded = TRUE;
2800
2801 /* And we will also fake the fact we found one */
2802 FoundQuotes = TRUE;
2803
2804 /* Start over */
2805 goto WhiteScan;
2806 }
2807
2808 /* We totally failed */
2809 goto Cleanup;
2810 }
2811
2812 /* Put back the command line */
2813 *NullBuffer = SaveChar;
2814 lpApplicationName = NameBuffer;
2815 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
2816 }
2817 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
2818 {
2819 /* We have an app name (good!) but no command line */
2820 CmdLineIsAppName = TRUE;
2821 lpCommandLine = (LPWSTR)lpApplicationName;
2822 }
2823
2824 /* At this point the name has been toyed with enough to be openable */
2825 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
2826
2827 /* Check for failure */
2828 if (!NT_SUCCESS(Status))
2829 {
2830 /* Could be a non-PE File */
2831 switch (Status)
2832 {
2833 /* Check if the Kernel tells us it's not even valid MZ */
2834 case STATUS_INVALID_IMAGE_NE_FORMAT:
2835 case STATUS_INVALID_IMAGE_PROTECT:
2836 case STATUS_INVALID_IMAGE_NOT_MZ:
2837
2838 #if 0
2839 /* If it's a DOS app, use VDM */
2840 if ((BasepCheckDosApp(&ApplicationName)))
2841 {
2842 DPRINT1("Launching VDM...\n");
2843 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2844 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2845 return CreateProcessW(L"ntvdm.exe",
2846 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
2847 lpProcessAttributes,
2848 lpThreadAttributes,
2849 bInheritHandles,
2850 dwCreationFlags,
2851 lpEnvironment,
2852 lpCurrentDirectory,
2853 &StartupInfo,
2854 lpProcessInformation);
2855 }
2856 #endif
2857 /* It's a batch file */
2858 Extension = &ApplicationName.Buffer[ApplicationName.Length /
2859 sizeof(WCHAR) - 4];
2860
2861 /* Make sure the extensions are correct */
2862 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
2863 {
2864 SetLastError(ERROR_BAD_EXE_FORMAT);
2865 return FALSE;
2866 }
2867
2868 /* Calculate the length of the command line */
2869 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
2870
2871 /* If we found quotes, then add them into the length size */
2872 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
2873 CmdLineLength *= sizeof(WCHAR);
2874
2875 /* Allocate space for the new command line */
2876 BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
2877 0,
2878 CmdLineLength);
2879 if (BatchCommandLine == NULL)
2880 {
2881 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2882 goto Cleanup;
2883 }
2884
2885 /* Build it */
2886 wcscpy(BatchCommandLine, CMD_STRING);
2887 if (CmdLineIsAppName || FoundQuotes)
2888 {
2889 wcscat(BatchCommandLine, L"\"");
2890 }
2891 wcscat(BatchCommandLine, lpCommandLine);
2892 if (CmdLineIsAppName || FoundQuotes)
2893 {
2894 wcscat(BatchCommandLine, L"\"");
2895 }
2896
2897 /* Create it as a Unicode String */
2898 RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
2899
2900 /* Set the command line to this */
2901 lpCommandLine = CommandLineString.Buffer;
2902 lpApplicationName = NULL;
2903
2904 /* Free memory */
2905 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2906 ApplicationName.Buffer = NULL;
2907 goto GetAppName;
2908 break;
2909
2910 case STATUS_INVALID_IMAGE_WIN_16:
2911
2912 /* It's a Win16 Image, use VDM */
2913 DPRINT1("Launching VDM...\n");
2914 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2915 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2916 return CreateProcessW(L"ntvdm.exe",
2917 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
2918 lpProcessAttributes,
2919 lpThreadAttributes,
2920 bInheritHandles,
2921 dwCreationFlags,
2922 lpEnvironment,
2923 lpCurrentDirectory,
2924 &StartupInfo,
2925 lpProcessInformation);
2926
2927 case STATUS_OBJECT_NAME_NOT_FOUND:
2928 case STATUS_OBJECT_PATH_NOT_FOUND:
2929 BaseSetLastNTError(Status);
2930 goto Cleanup;
2931
2932 default:
2933 /* Invalid Image Type */
2934 SetLastError(ERROR_BAD_EXE_FORMAT);
2935 goto Cleanup;
2936 }
2937 }
2938
2939 /* Use our desktop if we didn't get any */
2940 if (!StartupInfo.lpDesktop)
2941 {
2942 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
2943 }
2944
2945 /* FIXME: Check if Application is allowed to run */
2946
2947 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2948
2949 /* Get some information about the executable */
2950 Status = NtQuerySection(hSection,
2951 SectionImageInformation,
2952 &SectionImageInfo,
2953 sizeof(SectionImageInfo),
2954 NULL);
2955 if(!NT_SUCCESS(Status))
2956 {
2957 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
2958 BaseSetLastNTError(Status);
2959 goto Cleanup;
2960 }
2961
2962 /* Don't execute DLLs */
2963 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
2964 {
2965 DPRINT1("Can't execute a DLL\n");
2966 SetLastError(ERROR_BAD_EXE_FORMAT);
2967 goto Cleanup;
2968 }
2969
2970 /* FIXME: Check for Debugger */
2971
2972 /* FIXME: Check if Machine Type and SubSys Version Match */
2973
2974 /* We don't support POSIX or anything else for now */
2975 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType &&
2976 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType)
2977 {
2978 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType);
2979 /*
2980 * Despite the name of the error code suggests, it corresponds to the
2981 * well-known "The %1 application cannot be run in Win32 mode" message.
2982 */
2983 SetLastError(ERROR_CHILD_NOT_COMPLETE);
2984 goto Cleanup;
2985 }
2986
2987 if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType)
2988 {
2989 /* Do not create a console for GUI applications */
2990 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
2991 dwCreationFlags |= DETACHED_PROCESS;
2992 }
2993
2994 /* Initialize the process object attributes */
2995 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
2996 lpProcessAttributes,
2997 NULL);
2998
2999 /* Check if we're going to be debugged */
3000 if (dwCreationFlags & DEBUG_PROCESS)
3001 {
3002 /* FIXME: Set process flag */
3003 }
3004
3005 /* Check if we're going to be debugged */
3006 if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
3007 {
3008 /* Connect to DbgUi */
3009 Status = DbgUiConnectToDbg();
3010 if (!NT_SUCCESS(Status))
3011 {
3012 DPRINT1("Failed to connect to DbgUI!\n");
3013 BaseSetLastNTError(Status);
3014 goto Cleanup;
3015 }
3016
3017 /* Get the debug object */
3018 hDebug = DbgUiGetThreadDebugObject();
3019
3020 /* Check if only this process will be debugged */
3021 if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
3022 {
3023 /* Set process flag */
3024 hDebug = (HANDLE)((ULONG_PTR)hDebug | 0x1);
3025 }
3026 }
3027
3028 /* Create the Process */
3029 Status = NtCreateProcess(&hProcess,
3030 PROCESS_ALL_ACCESS,
3031 ObjectAttributes,
3032 NtCurrentProcess(),
3033 (BOOLEAN)bInheritHandles,
3034 hSection,
3035 hDebug,
3036 NULL);
3037 if (!NT_SUCCESS(Status))
3038 {
3039 DPRINT1("Unable to create process, status 0x%x\n", Status);
3040 BaseSetLastNTError(Status);
3041 goto Cleanup;
3042 }
3043
3044 if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID)
3045 {
3046 /* Set new class */
3047 Status = NtSetInformationProcess(hProcess,
3048 ProcessPriorityClass,
3049 &PriorityClass,
3050 sizeof(PROCESS_PRIORITY_CLASS));
3051 if(!NT_SUCCESS(Status))
3052 {
3053 DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
3054 BaseSetLastNTError(Status);
3055 goto Cleanup;
3056 }
3057 }
3058
3059 /* Set Error Mode */
3060 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
3061 {
3062 ULONG ErrorMode = SEM_FAILCRITICALERRORS;
3063 NtSetInformationProcess(hProcess,
3064 ProcessDefaultHardErrorMode,
3065 &ErrorMode,
3066 sizeof(ULONG));
3067 }
3068
3069 /* Convert the directory to a full path */
3070 if (lpCurrentDirectory)
3071 {
3072 /* Allocate a buffer */
3073 CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
3074 0,
3075 (MAX_PATH + 1) * sizeof(WCHAR));
3076 if (CurrentDirectory == NULL)
3077 {
3078 DPRINT1("Cannot allocate memory for directory name\n");
3079 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3080 goto Cleanup;
3081 }
3082
3083 /* Get the length */
3084 if (GetFullPathNameW(lpCurrentDirectory,
3085 MAX_PATH,
3086 CurrentDirectory,
3087 &CurrentDirectoryPart) > MAX_PATH)
3088 {
3089 DPRINT1("Directory name too long\n");
3090 SetLastError(ERROR_DIRECTORY);
3091 goto Cleanup;
3092 }
3093 }
3094
3095 /* Insert quotes if needed */
3096 if (QuotesNeeded || CmdLineIsAppName)
3097 {
3098 /* Allocate a buffer */
3099 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
3100 0,
3101 (wcslen(lpCommandLine) + 2 + 1) *
3102 sizeof(WCHAR));
3103 if (QuotedCmdLine == NULL)
3104 {
3105 DPRINT1("Cannot allocate memory for quoted command line\n");
3106 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3107 goto Cleanup;
3108 }
3109
3110 /* Copy the first quote */
3111 wcscpy(QuotedCmdLine, L"\"");
3112
3113 /* Save a null char */
3114 if (QuotesNeeded)
3115 {
3116 SaveChar = *NullBuffer;
3117 *NullBuffer = UNICODE_NULL;
3118 }
3119
3120 /* Add the command line and the finishing quote */
3121 wcscat(QuotedCmdLine, lpCommandLine);
3122 wcscat(QuotedCmdLine, L"\"");
3123
3124 /* Add the null char */
3125 if (QuotesNeeded)
3126 {
3127 *NullBuffer = SaveChar;
3128 wcscat(QuotedCmdLine, NullBuffer);
3129 }
3130
3131 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
3132 }
3133
3134 if (Escape)
3135 {
3136 if (QuotedCmdLine == NULL)
3137 {
3138 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
3139 0,
3140 (wcslen(lpCommandLine) + 1) * sizeof(WCHAR));
3141 if (QuotedCmdLine == NULL)
3142 {
3143 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3144 goto Cleanup;
3145 }
3146 wcscpy(QuotedCmdLine, lpCommandLine);
3147 }
3148
3149 ScanString = QuotedCmdLine;
3150 while (NULL != (ScanString = wcschr(ScanString, L'^')))
3151 {
3152 ScanString++;
3153 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
3154 {
3155 memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR));
3156 }
3157 }
3158 }
3159
3160 /* Get the Process Information */
3161 Status = NtQueryInformationProcess(hProcess,
3162 ProcessBasicInformation,
3163 &ProcessBasicInfo,
3164 sizeof(ProcessBasicInfo),
3165 NULL);
3166
3167 /* Convert the environment */
3168 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3169 {
3170 lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
3171 if (!lpEnvironment) goto Cleanup;
3172 }
3173
3174 /* Create Process Environment */
3175 RemotePeb = ProcessBasicInfo.PebBaseAddress;
3176 Ret = BasePushProcessParameters(0,
3177 hProcess,
3178 RemotePeb,
3179 (LPWSTR)lpApplicationName,
3180 CurrentDirectory,
3181 (QuotesNeeded || CmdLineIsAppName || Escape) ?
3182 QuotedCmdLine : lpCommandLine,
3183 lpEnvironment,
3184 &StartupInfo,
3185 dwCreationFlags,
3186 bInheritHandles,
3187 0,
3188 NULL,
3189 0);
3190 if (!Ret) goto Cleanup;
3191
3192 /* Cleanup Environment */
3193 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3194 {
3195 RtlDestroyEnvironment(lpEnvironment);
3196 }
3197
3198 /* Close the section */
3199 NtClose(hSection);
3200 hSection = NULL;
3201
3202 /* Duplicate the handles if needed */
3203 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
3204 SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
3205 {
3206 PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
3207
3208 /* Get the remote parameters */
3209 Status = NtReadVirtualMemory(hProcess,
3210 &RemotePeb->ProcessParameters,
3211 &RemoteParameters,
3212 sizeof(PVOID),
3213 NULL);
3214 if (!NT_SUCCESS(Status))
3215 {
3216 DPRINT1("Failed to read memory\n");
3217 goto Cleanup;
3218 }
3219
3220 /* Duplicate and write the handles */
3221 BasepDuplicateAndWriteHandle(hProcess,
3222 OurPeb->ProcessParameters->StandardInput,
3223 &RemoteParameters->StandardInput);
3224 BasepDuplicateAndWriteHandle(hProcess,
3225 OurPeb->ProcessParameters->StandardOutput,
3226 &RemoteParameters->StandardOutput);
3227 BasepDuplicateAndWriteHandle(hProcess,
3228 OurPeb->ProcessParameters->StandardError,
3229 &RemoteParameters->StandardError);
3230 }
3231
3232 /* Create the first thread */
3233 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
3234 SectionImageInfo.TransferAddress);
3235 hThread = BasepCreateFirstThread(hProcess,
3236 lpThreadAttributes,
3237 &SectionImageInfo,
3238 &ClientId,
3239 bInheritHandles,
3240 dwCreationFlags);
3241
3242 if (hThread == NULL)
3243 {
3244 DPRINT1("Could not create Initial Thread\n");
3245 /* FIXME - set last error code */
3246 goto Cleanup;
3247 }
3248
3249 if (!(dwCreationFlags & CREATE_SUSPENDED))
3250 {
3251 NtResumeThread(hThread, &Dummy);
3252 }
3253
3254 /* Return Data */
3255 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
3256 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
3257 lpProcessInformation->hProcess = hProcess;
3258 lpProcessInformation->hThread = hThread;
3259 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread,
3260 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
3261 hProcess = hThread = NULL;
3262 Ret = TRUE;
3263
3264 Cleanup:
3265 /* De-allocate heap strings */
3266 if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
3267 if (ApplicationName.Buffer)
3268 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
3269 if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
3270 if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
3271
3272 /* Kill any handles still alive */
3273 if (hSection) NtClose(hSection);
3274 if (hThread)
3275 {
3276 /* We don't know any more details than this */
3277 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
3278 NtClose(hThread);
3279 }
3280 if (hProcess) NtClose(hProcess);
3281
3282 /* Return Success */
3283 return Ret;
3284 }
3285
3286 /*
3287 * @implemented
3288 */
3289 BOOL
3290 WINAPI
3291 CreateProcessW(LPCWSTR lpApplicationName,
3292 LPWSTR lpCommandLine,
3293 LPSECURITY_ATTRIBUTES lpProcessAttributes,
3294 LPSECURITY_ATTRIBUTES lpThreadAttributes,
3295 BOOL bInheritHandles,
3296 DWORD dwCreationFlags,
3297 LPVOID lpEnvironment,
3298 LPCWSTR lpCurrentDirectory,
3299 LPSTARTUPINFOW lpStartupInfo,
3300 LPPROCESS_INFORMATION lpProcessInformation)
3301 {
3302 /* Call the internal (but exported) version */
3303 return CreateProcessInternalW(0,
3304 lpApplicationName,
3305 lpCommandLine,
3306 lpProcessAttributes,
3307 lpThreadAttributes,
3308 bInheritHandles,
3309 dwCreationFlags,
3310 lpEnvironment,
3311 lpCurrentDirectory,
3312 lpStartupInfo,
3313 lpProcessInformation,
3314 NULL);
3315 }
3316
3317 /*
3318 * @implemented
3319 */
3320 BOOL
3321 WINAPI
3322 CreateProcessInternalA(HANDLE hToken,
3323 LPCSTR lpApplicationName,
3324 LPSTR lpCommandLine,
3325 LPSECURITY_ATTRIBUTES lpProcessAttributes,
3326 LPSECURITY_ATTRIBUTES lpThreadAttributes,
3327 BOOL bInheritHandles,
3328 DWORD dwCreationFlags,
3329 LPVOID lpEnvironme