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