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