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