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