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