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