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