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