[WLAN-BRINGUP]
[reactos.git] / dll / win32 / kernel32 / client / proc.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/proc/proc.c
6 * PURPOSE: Process functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 typedef INT (WINAPI *MessageBoxW_Proc) (HWND, LPCWSTR, LPCWSTR, UINT);
20
21 /* GLOBALS *******************************************************************/
22
23 static UNICODE_STRING CommandLineStringW;
24 static ANSI_STRING CommandLineStringA;
25 UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
26
27 static BOOL bCommandLineInitialized = FALSE;
28
29 WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle;
30
31 LPSTARTUPINFOA lpLocalStartupInfo = NULL;
32
33 VOID WINAPI
34 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
35
36 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
37
38 #define CMD_STRING L"cmd /c "
39
40 extern __declspec(noreturn)
41 VOID
42 CALLBACK
43 ConsoleControlDispatcher(DWORD CodeAndFlag);
44
45 /* FUNCTIONS ****************************************************************/
46
47 static
48 LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
49 {
50 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
51 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
52 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
53
54 if (RealFilter != NULL)
55 {
56 _SEH2_TRY
57 {
58 ExceptionDisposition = RealFilter(ExceptionInfo);
59 }
60 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
61 {
62 }
63 _SEH2_END;
64 }
65 if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
66 RealFilter != UnhandledExceptionFilter)
67 {
68 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
69 }
70
71 return ExceptionDisposition;
72 }
73
74 VOID
75 WINAPI
76 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
77 {
78 UINT uExitCode = 0;
79
80 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
81
82 _SEH2_TRY
83 {
84 /* Set our Start Address */
85 NtSetInformationThread(NtCurrentThread(),
86 ThreadQuerySetWin32StartAddress,
87 &lpStartAddress,
88 sizeof(PPROCESS_START_ROUTINE));
89
90 /* Call the Start Routine */
91 uExitCode = (lpStartAddress)();
92 }
93 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
94 {
95 /* Get the SEH Error */
96 uExitCode = _SEH2_GetExceptionCode();
97 }
98 _SEH2_END;
99
100 /* Exit the Process with our error */
101 ExitProcess(uExitCode);
102 }
103
104 /*
105 * Tells CSR that a new process was created
106 */
107 NTSTATUS
108 WINAPI
109 BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
110 IN HANDLE ProcessId,
111 IN BOOL InheritHandles)
112 {
113 ULONG Request = CREATE_PROCESS;
114 CSR_API_MESSAGE CsrRequest;
115 NTSTATUS Status;
116
117 DPRINT("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
118 ProcessId, dwCreationFlags);
119
120 /* Fill out the request */
121 CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
122 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
123 CsrRequest.Data.CreateProcessRequest.bInheritHandles = InheritHandles;
124
125 /* Call CSR */
126 Status = CsrClientCallServer(&CsrRequest,
127 NULL,
128 MAKE_CSR_API(Request, CSR_NATIVE),
129 sizeof(CSR_API_MESSAGE));
130 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
131 {
132 DPRINT1("Failed to tell csrss about new process\n");
133 return CsrRequest.Status;
134 }
135
136 /* Return Success */
137 return STATUS_SUCCESS;
138 }
139
140 NTSTATUS
141 WINAPI
142 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
143 IN PCLIENT_ID ClientId)
144 {
145 ULONG Request = CREATE_THREAD;
146 CSR_API_MESSAGE CsrRequest;
147 NTSTATUS Status;
148
149 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
150 ClientId->UniqueThread, ThreadHandle);
151
152 /* Fill out the request */
153 CsrRequest.Data.CreateThreadRequest.ClientId = *ClientId;
154 CsrRequest.Data.CreateThreadRequest.ThreadHandle = ThreadHandle;
155
156 /* Call CSR */
157 Status = CsrClientCallServer(&CsrRequest,
158 NULL,
159 MAKE_CSR_API(Request, CSR_NATIVE),
160 sizeof(CSR_API_MESSAGE));
161 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
162 {
163 DPRINT1("Failed to tell csrss about new thread\n");
164 return CsrRequest.Status;
165 }
166
167 /* Return Success */
168 return STATUS_SUCCESS;
169 }
170
171 /*
172 * Creates the first Thread in a Proces
173 */
174 HANDLE
175 WINAPI
176 BasepCreateFirstThread(HANDLE ProcessHandle,
177 LPSECURITY_ATTRIBUTES lpThreadAttributes,
178 PSECTION_IMAGE_INFORMATION SectionImageInfo,
179 PCLIENT_ID ClientId)
180 {
181 OBJECT_ATTRIBUTES LocalObjectAttributes;
182 POBJECT_ATTRIBUTES ObjectAttributes;
183 CONTEXT Context;
184 INITIAL_TEB InitialTeb;
185 NTSTATUS Status;
186 HANDLE hThread;
187
188 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
189
190 /* Create the Thread's Stack */
191 BaseCreateStack(ProcessHandle,
192 SectionImageInfo->MaximumStackSize,
193 SectionImageInfo->CommittedStackSize,
194 &InitialTeb);
195
196 /* Create the Thread's Context */
197 BaseInitializeContext(&Context,
198 NtCurrentPeb(),
199 SectionImageInfo->TransferAddress,
200 InitialTeb.StackBase,
201 0);
202
203 /* Convert the thread attributes */
204 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
205 lpThreadAttributes,
206 NULL);
207
208 /* Create the Kernel Thread Object */
209 Status = NtCreateThread(&hThread,
210 THREAD_ALL_ACCESS,
211 ObjectAttributes,
212 ProcessHandle,
213 ClientId,
214 &Context,
215 &InitialTeb,
216 TRUE);
217 if (!NT_SUCCESS(Status))
218 {
219 return NULL;
220 }
221
222 Status = BasepNotifyCsrOfThread(hThread, ClientId);
223 if (!NT_SUCCESS(Status))
224 {
225 ASSERT(FALSE);
226 }
227
228 /* Success */
229 return hThread;
230 }
231
232 /*
233 * Converts ANSI to Unicode Environment
234 */
235 PVOID
236 WINAPI
237 BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize,
238 IN PVOID lpEnvironment)
239 {
240 PCHAR pcScan;
241 ANSI_STRING AnsiEnv;
242 UNICODE_STRING UnicodeEnv;
243 NTSTATUS Status;
244
245 DPRINT("BasepConvertUnicodeEnvironment\n");
246
247 /* Scan the environment to calculate its Unicode size */
248 AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
249 while (*pcScan)
250 {
251 pcScan += strlen(pcScan) + 1;
252 }
253
254 /* Create our ANSI String */
255 if (pcScan == (PCHAR)lpEnvironment)
256 {
257 AnsiEnv.Length = 2 * sizeof(CHAR);
258 }
259 else
260 {
261
262 AnsiEnv.Length = (USHORT)((ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + sizeof(CHAR));
263 }
264 AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
265
266 /* Allocate memory for the Unicode Environment */
267 UnicodeEnv.Buffer = NULL;
268 *EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
269 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
270 (PVOID)&UnicodeEnv.Buffer,
271 0,
272 EnvSize,
273 MEM_COMMIT,
274 PAGE_READWRITE);
275 /* Failure */
276 if (!NT_SUCCESS(Status))
277 {
278 SetLastError(Status);
279 *EnvSize = 0;
280 return NULL;
281 }
282
283 /* Use the allocated size */
284 UnicodeEnv.MaximumLength = (USHORT)*EnvSize;
285
286 /* Convert */
287 RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
288 return UnicodeEnv.Buffer;
289 }
290
291 /*
292 * Converts a Win32 Priority Class to NT
293 */
294 ULONG
295 WINAPI
296 BasepConvertPriorityClass(IN ULONG dwCreationFlags)
297 {
298 ULONG ReturnClass;
299
300 if(dwCreationFlags & IDLE_PRIORITY_CLASS)
301 {
302 ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
303 }
304 else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
305 {
306 ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
307 }
308 else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
309 {
310 ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
311 }
312 else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
313 {
314 ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
315 }
316 else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
317 {
318 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
319 }
320 else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
321 {
322 /* Check for Privilege First */
323 if (BasepIsRealtimeAllowed(TRUE))
324 {
325 ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
326 }
327 else
328 {
329 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
330 }
331 }
332 else
333 {
334 ReturnClass = PROCESS_PRIORITY_CLASS_INVALID;
335 }
336
337 return ReturnClass;
338 }
339
340 /*
341 * Duplicates a standard handle and writes it where requested.
342 */
343 VOID
344 WINAPI
345 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
346 IN HANDLE StandardHandle,
347 IN PHANDLE Address)
348 {
349 NTSTATUS Status;
350 HANDLE DuplicatedHandle;
351 SIZE_T Dummy;
352
353 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
354 "Address: %p\n", ProcessHandle, StandardHandle, Address);
355
356 /* Don't touch Console Handles */
357 if (IsConsoleHandle(StandardHandle)) return;
358
359 /* Duplicate the handle */
360 Status = NtDuplicateObject(NtCurrentProcess(),
361 StandardHandle,
362 ProcessHandle,
363 &DuplicatedHandle,
364 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
365 0,
366 0);
367 if (NT_SUCCESS(Status))
368 {
369 /* Write it */
370 NtWriteVirtualMemory(ProcessHandle,
371 Address,
372 &DuplicatedHandle,
373 sizeof(HANDLE),
374 &Dummy);
375 }
376 }
377
378 VOID
379 WINAPI
380 BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
381 IN PRTL_USER_PROCESS_PARAMETERS PebParams,
382 IN BOOL InheritHandles)
383 {
384 DPRINT("BasepCopyHandles %p %p, %d\n", Params, PebParams, InheritHandles);
385
386 /* Copy the handle if we are inheriting or if it's a console handle */
387 if ((InheritHandles) || (IsConsoleHandle(PebParams->StandardInput)))
388 {
389 Params->StandardInput = PebParams->StandardInput;
390 }
391
392 if ((InheritHandles) || (IsConsoleHandle(PebParams->StandardOutput)))
393 {
394 Params->StandardOutput = PebParams->StandardOutput;
395 }
396
397 if ((InheritHandles) || (IsConsoleHandle(PebParams->StandardError)))
398 {
399 Params->StandardError = PebParams->StandardError;
400 }
401 }
402
403 NTSTATUS
404 WINAPI
405 BasePushProcessParameters(IN HANDLE ProcessHandle,
406 IN PPEB Peb,
407 IN LPWSTR ApplicationPathName,
408 IN LPWSTR lpCurrentDirectory,
409 IN LPWSTR lpCommandLine,
410 IN LPVOID lpEnvironment,
411 IN SIZE_T EnvSize,
412 IN LPSTARTUPINFOW StartupInfo,
413 IN DWORD CreationFlags,
414 IN BOOL InheritHandles)
415 {
416 WCHAR FullPath[MAX_PATH + 5];
417 LPWSTR Remaining;
418 LPWSTR DllPathString;
419 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
420 PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
421 UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
422 NTSTATUS Status;
423 PWCHAR ScanChar;
424 ULONG EnviroSize;
425 SIZE_T Size;
426 UNICODE_STRING Desktop, Shell, Runtime, Title;
427 PPEB OurPeb = NtCurrentPeb();
428 LPVOID Environment = lpEnvironment;
429 DPRINT("BasePushProcessParameters\n");
430
431 /* Get the full path name */
432 Size = GetFullPathNameW(ApplicationPathName,
433 MAX_PATH + 4,
434 FullPath,
435 &Remaining);
436 if ((Size) && (Size <= (MAX_PATH + 4)))
437 {
438 /* Get the DLL Path */
439 DllPathString = BaseComputeProcessDllPath(ApplicationPathName,
440 Environment);
441 if (!DllPathString) return STATUS_NO_MEMORY;
442
443 /* Initialize Strings */
444 RtlInitUnicodeString(&DllPath, DllPathString);
445 RtlInitUnicodeString(&ImageName, ApplicationPathName);
446 }
447 else
448 {
449 /* Get the DLL Path */
450 DllPathString = BaseComputeProcessDllPath(FullPath, Environment);
451 if (!DllPathString) return STATUS_NO_MEMORY;
452
453 /* Initialize Strings */
454 RtlInitUnicodeString(&DllPath, DllPathString);
455 RtlInitUnicodeString(&ImageName, FullPath);
456 }
457 DPRINT("DllPath: %wZ, ImageName: %wZ\n", DllPath, ImageName);
458
459 /* Initialize Strings */
460 RtlInitUnicodeString(&CommandLine, lpCommandLine);
461 RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
462
463 /* Initialize more Strings from the Startup Info */
464 if (StartupInfo->lpDesktop)
465 {
466 RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
467 }
468 else
469 {
470 RtlInitUnicodeString(&Desktop, L"");
471 }
472 if (StartupInfo->lpReserved)
473 {
474 RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
475 }
476 else
477 {
478 RtlInitUnicodeString(&Shell, L"");
479 }
480 if (StartupInfo->lpTitle)
481 {
482 RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
483 }
484 else
485 {
486 RtlInitUnicodeString(&Title, ApplicationPathName);
487 }
488
489 /* This one is special because the length can differ */
490 Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
491 Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
492
493 /* Create the Parameter Block */
494 DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
495 &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
496 &Runtime);
497 Status = RtlCreateProcessParameters(&ProcessParameters,
498 &ImageName,
499 &DllPath,
500 lpCurrentDirectory ?
501 &CurrentDirectory : NULL,
502 &CommandLine,
503 Environment,
504 &Title,
505 &Desktop,
506 &Shell,
507 &Runtime);
508 if (!NT_SUCCESS(Status))
509 {
510 DPRINT1("Failed to create process parameters!\n");
511 return Status;
512 }
513
514 /* Clear the current directory handle if not inheriting */
515 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
516
517 /* Save pointer and start lookup */
518 Environment = ScanChar = ProcessParameters->Environment;
519 if (Environment)
520 {
521 /* Find the environment size */
522 while (*ScanChar) ScanChar += wcslen(ScanChar) + 1;
523 EnviroSize = (ULONG_PTR)ScanChar - (ULONG_PTR)Environment;
524 DPRINT("EnvironmentSize %ld\n", EnviroSize);
525
526 /* Allocate and Initialize new Environment Block */
527 Size = EnviroSize;
528 ProcessParameters->Environment = NULL;
529 Status = ZwAllocateVirtualMemory(ProcessHandle,
530 (PVOID*)&ProcessParameters->Environment,
531 0,
532 &Size,
533 MEM_COMMIT,
534 PAGE_READWRITE);
535 if (!NT_SUCCESS(Status))
536 {
537 DPRINT1("Failed to allocate Environment Block\n");
538 return Status;
539 }
540
541 /* Write the Environment Block */
542 Status = ZwWriteVirtualMemory(ProcessHandle,
543 ProcessParameters->Environment,
544 Environment,
545 EnviroSize,
546 NULL);
547 if (!NT_SUCCESS(Status))
548 {
549 DPRINT1("Failed to write Environment Block\n");
550 return Status;
551 }
552 }
553
554 /* Write new parameters */
555 ProcessParameters->StartingX = StartupInfo->dwX;
556 ProcessParameters->StartingY = StartupInfo->dwY;
557 ProcessParameters->CountX = StartupInfo->dwXSize;
558 ProcessParameters->CountY = StartupInfo->dwYSize;
559 ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
560 ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
561 ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
562 ProcessParameters->WindowFlags = StartupInfo->dwFlags;
563 ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
564
565 /* Write the handles only if we have to */
566 if (StartupInfo->dwFlags &
567 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
568 {
569 DPRINT("Using Standard Handles\n");
570 ProcessParameters->StandardInput = StartupInfo->hStdInput;
571 ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
572 ProcessParameters->StandardError = StartupInfo->hStdError;
573 }
574
575 /* Use Special Flags for ConDllInitialize in Kernel32 */
576 if (CreationFlags & DETACHED_PROCESS)
577 {
578 ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
579 }
580 else if (CreationFlags & CREATE_NO_WINDOW)
581 {
582 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
583 }
584 else if (CreationFlags & CREATE_NEW_CONSOLE)
585 {
586 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
587 }
588 else
589 {
590 /* Inherit our Console Handle */
591 ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
592
593 /* Is the shell trampling on our Handles? */
594 if (!(StartupInfo->dwFlags &
595 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
596 {
597 /* Use handles from PEB, if inheriting or they are console */
598 DPRINT("Copying handles from parent\n");
599 BasepCopyHandles(ProcessParameters,
600 OurPeb->ProcessParameters,
601 InheritHandles);
602 }
603 }
604
605 /* Also set the Console Flag */
606 if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) &&
607 (!(CreationFlags & CREATE_NEW_CONSOLE)))
608 {
609 ProcessParameters->ConsoleFlags = 1;
610 }
611
612 /* See if the first 1MB should be reserved */
613 if ((ULONG_PTR)ApplicationPathName & 1)
614 {
615 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
616 }
617
618 /* See if the first 16MB should be reserved */
619 if ((ULONG_PTR)ApplicationPathName & 2)
620 {
621 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB;
622 }
623
624 /* Allocate memory for the parameter block */
625 Size = ProcessParameters->Length;
626 Status = NtAllocateVirtualMemory(ProcessHandle,
627 (PVOID*)&RemoteParameters,
628 0,
629 &Size,
630 MEM_COMMIT,
631 PAGE_READWRITE);
632 if (!NT_SUCCESS(Status))
633 {
634 DPRINT1("Failed to allocate Parameters Block\n");
635 return Status;
636 }
637
638 /* Set the allocated size */
639 ProcessParameters->MaximumLength = Size;
640
641 /* Handle some Parameter Flags */
642 ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
643 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0;
644 ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
645 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0;
646 ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
647 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0;
648 ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
649 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS);
650
651 /* Write the Parameter Block */
652 Status = NtWriteVirtualMemory(ProcessHandle,
653 RemoteParameters,
654 ProcessParameters,
655 ProcessParameters->Length,
656 NULL);
657 if (!NT_SUCCESS(Status))
658 {
659 DPRINT1("Failed to write Parameters Block\n");
660 return Status;
661 }
662
663 /* Write the PEB Pointer */
664 Status = NtWriteVirtualMemory(ProcessHandle,
665 &Peb->ProcessParameters,
666 &RemoteParameters,
667 sizeof(PVOID),
668 NULL);
669 if (!NT_SUCCESS(Status))
670 {
671 DPRINT1("Failed to write Parameters Block\n");
672 return Status;
673 }
674
675 /* FIXME: Write Peb->ImageSubSystem */
676
677
678 /* Cleanup */
679 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
680 RtlDestroyProcessParameters(ProcessParameters);
681
682 DPRINT("Completed\n");
683 return STATUS_SUCCESS;
684 }
685
686 VOID
687 WINAPI
688 InitCommandLines(VOID)
689 {
690 PRTL_USER_PROCESS_PARAMETERS Params;
691
692 /* get command line */
693 Params = NtCurrentPeb()->ProcessParameters;
694 RtlNormalizeProcessParams (Params);
695
696 /* initialize command line buffers */
697 CommandLineStringW.Length = Params->CommandLine.Length;
698 CommandLineStringW.MaximumLength = CommandLineStringW.Length + sizeof(WCHAR);
699 CommandLineStringW.Buffer = RtlAllocateHeap(GetProcessHeap(),
700 HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY,
701 CommandLineStringW.MaximumLength);
702 if (CommandLineStringW.Buffer == NULL)
703 {
704 return;
705 }
706
707 RtlInitAnsiString(&CommandLineStringA, NULL);
708
709 /* Copy command line */
710 RtlCopyUnicodeString(&CommandLineStringW,
711 &(Params->CommandLine));
712 CommandLineStringW.Buffer[CommandLineStringW.Length / sizeof(WCHAR)] = 0;
713
714 /* convert unicode string to ansi (or oem) */
715 if (bIsFileApiAnsi)
716 RtlUnicodeStringToAnsiString(&CommandLineStringA,
717 &CommandLineStringW,
718 TRUE);
719 else
720 RtlUnicodeStringToOemString(&CommandLineStringA,
721 &CommandLineStringW,
722 TRUE);
723
724 CommandLineStringA.Buffer[CommandLineStringA.Length] = 0;
725
726 bCommandLineInitialized = TRUE;
727 }
728
729 /*
730 * @implemented
731 */
732 BOOL
733 WINAPI
734 GetProcessAffinityMask(HANDLE hProcess,
735 PDWORD_PTR lpProcessAffinityMask,
736 PDWORD_PTR lpSystemAffinityMask)
737 {
738 PROCESS_BASIC_INFORMATION ProcessInfo;
739 SYSTEM_BASIC_INFORMATION SystemInfo;
740 NTSTATUS Status;
741
742 Status = NtQuerySystemInformation(SystemBasicInformation,
743 &SystemInfo,
744 sizeof(SystemInfo),
745 NULL);
746 if (!NT_SUCCESS(Status))
747 {
748 BaseSetLastNTError(Status);
749 return FALSE;
750 }
751
752 Status = NtQueryInformationProcess(hProcess,
753 ProcessBasicInformation,
754 (PVOID)&ProcessInfo,
755 sizeof(PROCESS_BASIC_INFORMATION),
756 NULL);
757 if (!NT_SUCCESS(Status))
758 {
759 BaseSetLastNTError(Status);
760 return FALSE;
761 }
762
763 *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
764 *lpSystemAffinityMask = (DWORD)SystemInfo.ActiveProcessorsAffinityMask;
765
766 return TRUE;
767 }
768
769
770 /*
771 * @implemented
772 */
773 BOOL
774 WINAPI
775 SetProcessAffinityMask(HANDLE hProcess,
776 DWORD_PTR dwProcessAffinityMask)
777 {
778 NTSTATUS Status;
779
780 Status = NtSetInformationProcess(hProcess,
781 ProcessAffinityMask,
782 (PVOID)&dwProcessAffinityMask,
783 sizeof(DWORD));
784 if (!NT_SUCCESS(Status))
785 {
786 BaseSetLastNTError(Status);
787 return FALSE;
788 }
789
790 return TRUE;
791 }
792
793
794 /*
795 * @implemented
796 */
797 BOOL
798 WINAPI
799 GetProcessShutdownParameters(LPDWORD lpdwLevel,
800 LPDWORD lpdwFlags)
801 {
802 CSR_API_MESSAGE CsrRequest;
803 ULONG Request;
804 NTSTATUS Status;
805
806 Request = GET_SHUTDOWN_PARAMETERS;
807 Status = CsrClientCallServer(&CsrRequest,
808 NULL,
809 MAKE_CSR_API(Request, CSR_NATIVE),
810 sizeof(CSR_API_MESSAGE));
811 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
812 {
813 BaseSetLastNTError(Status);
814 return FALSE;
815 }
816
817 *lpdwLevel = CsrRequest.Data.GetShutdownParametersRequest.Level;
818 *lpdwFlags = CsrRequest.Data.GetShutdownParametersRequest.Flags;
819
820 return TRUE;
821 }
822
823
824 /*
825 * @implemented
826 */
827 BOOL
828 WINAPI
829 SetProcessShutdownParameters(DWORD dwLevel,
830 DWORD dwFlags)
831 {
832 CSR_API_MESSAGE CsrRequest;
833 ULONG Request;
834 NTSTATUS Status;
835
836 CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel;
837 CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags;
838
839 Request = SET_SHUTDOWN_PARAMETERS;
840 Status = CsrClientCallServer(&CsrRequest,
841 NULL,
842 MAKE_CSR_API(Request, CSR_NATIVE),
843 sizeof(CSR_API_MESSAGE));
844 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
845 {
846 BaseSetLastNTError(Status);
847 return FALSE;
848 }
849
850 return TRUE;
851 }
852
853
854 /*
855 * @implemented
856 */
857 BOOL
858 WINAPI
859 GetProcessWorkingSetSize(HANDLE hProcess,
860 PSIZE_T lpMinimumWorkingSetSize,
861 PSIZE_T lpMaximumWorkingSetSize)
862 {
863 QUOTA_LIMITS QuotaLimits;
864 NTSTATUS Status;
865
866 Status = NtQueryInformationProcess(hProcess,
867 ProcessQuotaLimits,
868 &QuotaLimits,
869 sizeof(QUOTA_LIMITS),
870 NULL);
871 if (!NT_SUCCESS(Status))
872 {
873 BaseSetLastNTError(Status);
874 return FALSE;
875 }
876
877 *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
878 *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
879
880 return TRUE;
881 }
882
883
884 /*
885 * @implemented
886 */
887 BOOL
888 WINAPI
889 SetProcessWorkingSetSize(HANDLE hProcess,
890 SIZE_T dwMinimumWorkingSetSize,
891 SIZE_T dwMaximumWorkingSetSize)
892 {
893 QUOTA_LIMITS QuotaLimits;
894 NTSTATUS Status;
895
896 QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
897 QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
898
899 Status = NtSetInformationProcess(hProcess,
900 ProcessQuotaLimits,
901 &QuotaLimits,
902 sizeof(QUOTA_LIMITS));
903 if (!NT_SUCCESS(Status))
904 {
905 BaseSetLastNTError(Status);
906 return FALSE;
907 }
908
909 return TRUE;
910 }
911
912
913 /*
914 * @implemented
915 */
916 BOOL
917 WINAPI
918 GetProcessTimes(HANDLE hProcess,
919 LPFILETIME lpCreationTime,
920 LPFILETIME lpExitTime,
921 LPFILETIME lpKernelTime,
922 LPFILETIME lpUserTime)
923 {
924 KERNEL_USER_TIMES Kut;
925 NTSTATUS Status;
926
927 Status = NtQueryInformationProcess(hProcess,
928 ProcessTimes,
929 &Kut,
930 sizeof(Kut),
931 NULL);
932 if (!NT_SUCCESS(Status))
933 {
934 BaseSetLastNTError(Status);
935 return FALSE;
936 }
937
938 lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
939 lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
940
941 lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
942 lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
943
944 lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
945 lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
946
947 lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
948 lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
949
950 return TRUE;
951 }
952
953
954 /*
955 * @implemented
956 */
957 HANDLE
958 WINAPI
959 GetCurrentProcess(VOID)
960 {
961 return (HANDLE)NtCurrentProcess();
962 }
963
964
965 /*
966 * @implemented
967 */
968 HANDLE
969 WINAPI
970 GetCurrentThread(VOID)
971 {
972 return (HANDLE)NtCurrentThread();
973 }
974
975
976 /*
977 * @implemented
978 */
979 DWORD
980 WINAPI
981 GetCurrentProcessId(VOID)
982 {
983 return HandleToUlong(GetTeb()->ClientId.UniqueProcess);
984 }
985
986
987 /*
988 * @implemented
989 */
990 BOOL
991 WINAPI
992 GetExitCodeProcess(HANDLE hProcess,
993 LPDWORD lpExitCode)
994 {
995 PROCESS_BASIC_INFORMATION ProcessBasic;
996 NTSTATUS Status;
997
998 Status = NtQueryInformationProcess(hProcess,
999 ProcessBasicInformation,
1000 &ProcessBasic,
1001 sizeof(PROCESS_BASIC_INFORMATION),
1002 NULL);
1003 if (!NT_SUCCESS(Status))
1004 {
1005 BaseSetLastNTError(Status);
1006 return FALSE;
1007 }
1008
1009 *lpExitCode = (DWORD)ProcessBasic.ExitStatus;
1010
1011 return TRUE;
1012 }
1013
1014
1015 /*
1016 * @implemented
1017 */
1018 DWORD
1019 WINAPI
1020 GetProcessId(HANDLE Process)
1021 {
1022 PROCESS_BASIC_INFORMATION ProcessBasic;
1023 NTSTATUS Status;
1024
1025 Status = NtQueryInformationProcess(Process,
1026 ProcessBasicInformation,
1027 &ProcessBasic,
1028 sizeof(PROCESS_BASIC_INFORMATION),
1029 NULL);
1030 if (!NT_SUCCESS(Status))
1031 {
1032 BaseSetLastNTError(Status);
1033 return 0;
1034 }
1035
1036 return (DWORD)ProcessBasic.UniqueProcessId;
1037 }
1038
1039
1040 /*
1041 * @implemented
1042 */
1043 HANDLE
1044 WINAPI
1045 OpenProcess(DWORD dwDesiredAccess,
1046 BOOL bInheritHandle,
1047 DWORD dwProcessId)
1048 {
1049 NTSTATUS errCode;
1050 HANDLE ProcessHandle;
1051 OBJECT_ATTRIBUTES ObjectAttributes;
1052 CLIENT_ID ClientId;
1053
1054 ClientId.UniqueProcess = UlongToHandle(dwProcessId);
1055 ClientId.UniqueThread = 0;
1056
1057 InitializeObjectAttributes(&ObjectAttributes,
1058 NULL,
1059 (bInheritHandle ? OBJ_INHERIT : 0),
1060 NULL,
1061 NULL);
1062
1063 errCode = NtOpenProcess(&ProcessHandle,
1064 dwDesiredAccess,
1065 &ObjectAttributes,
1066 &ClientId);
1067 if (!NT_SUCCESS(errCode))
1068 {
1069 BaseSetLastNTError(errCode);
1070 return NULL;
1071 }
1072
1073 return ProcessHandle;
1074 }
1075
1076
1077 /*
1078 * @implemented
1079 */
1080 UINT
1081 WINAPI
1082 WinExec(LPCSTR lpCmdLine,
1083 UINT uCmdShow)
1084 {
1085 STARTUPINFOA StartupInfo;
1086 PROCESS_INFORMATION ProcessInformation;
1087 DWORD dosErr;
1088
1089 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
1090 StartupInfo.cb = sizeof(STARTUPINFOA);
1091 StartupInfo.wShowWindow = (WORD)uCmdShow;
1092 StartupInfo.dwFlags = 0;
1093
1094 if (!CreateProcessA(NULL,
1095 (PVOID)lpCmdLine,
1096 NULL,
1097 NULL,
1098 FALSE,
1099 0,
1100 NULL,
1101 NULL,
1102 &StartupInfo,
1103 &ProcessInformation))
1104 {
1105 dosErr = GetLastError();
1106 return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
1107 }
1108
1109 if (NULL != lpfnGlobalRegisterWaitForInputIdle)
1110 {
1111 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess,
1112 10000);
1113 }
1114
1115 NtClose(ProcessInformation.hProcess);
1116 NtClose(ProcessInformation.hThread);
1117
1118 return 33; /* Something bigger than 31 means success. */
1119 }
1120
1121
1122 /*
1123 * @implemented
1124 */
1125 VOID
1126 WINAPI
1127 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle)
1128 {
1129 lpfnGlobalRegisterWaitForInputIdle = lpfnRegisterWaitForInputIdle;
1130 return;
1131 }
1132
1133 /*
1134 * @implemented
1135 */
1136 VOID
1137 WINAPI
1138 GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
1139 {
1140 PRTL_USER_PROCESS_PARAMETERS Params;
1141
1142 if (lpStartupInfo == NULL)
1143 {
1144 SetLastError(ERROR_INVALID_PARAMETER);
1145 return;
1146 }
1147
1148 Params = NtCurrentPeb()->ProcessParameters;
1149
1150 lpStartupInfo->cb = sizeof(STARTUPINFOW);
1151 lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
1152 lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
1153 lpStartupInfo->dwX = Params->StartingX;
1154 lpStartupInfo->dwY = Params->StartingY;
1155 lpStartupInfo->dwXSize = Params->CountX;
1156 lpStartupInfo->dwYSize = Params->CountY;
1157 lpStartupInfo->dwXCountChars = Params->CountCharsX;
1158 lpStartupInfo->dwYCountChars = Params->CountCharsY;
1159 lpStartupInfo->dwFillAttribute = Params->FillAttribute;
1160 lpStartupInfo->dwFlags = Params->WindowFlags;
1161 lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1162 lpStartupInfo->cbReserved2 = Params->RuntimeData.Length;
1163 lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1164
1165 lpStartupInfo->hStdInput = Params->StandardInput;
1166 lpStartupInfo->hStdOutput = Params->StandardOutput;
1167 lpStartupInfo->hStdError = Params->StandardError;
1168 }
1169
1170
1171 /*
1172 * @implemented
1173 */
1174 VOID
1175 WINAPI
1176 GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
1177 {
1178 PRTL_USER_PROCESS_PARAMETERS Params;
1179 ANSI_STRING AnsiString;
1180
1181 if (lpStartupInfo == NULL)
1182 {
1183 SetLastError(ERROR_INVALID_PARAMETER);
1184 return;
1185 }
1186
1187 Params = NtCurrentPeb ()->ProcessParameters;
1188
1189 RtlAcquirePebLock ();
1190
1191 /* FIXME - not thread-safe */
1192 if (lpLocalStartupInfo == NULL)
1193 {
1194 /* create new local startup info (ansi) */
1195 lpLocalStartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1196 0,
1197 sizeof(STARTUPINFOA));
1198 if (lpLocalStartupInfo == NULL)
1199 {
1200 RtlReleasePebLock();
1201 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1202 return;
1203 }
1204
1205 lpLocalStartupInfo->cb = sizeof(STARTUPINFOA);
1206
1207 /* copy window title string */
1208 RtlUnicodeStringToAnsiString(&AnsiString,
1209 &Params->WindowTitle,
1210 TRUE);
1211 lpLocalStartupInfo->lpTitle = AnsiString.Buffer;
1212
1213 /* copy desktop info string */
1214 RtlUnicodeStringToAnsiString(&AnsiString,
1215 &Params->DesktopInfo,
1216 TRUE);
1217 lpLocalStartupInfo->lpDesktop = AnsiString.Buffer;
1218
1219 /* copy shell info string */
1220 RtlUnicodeStringToAnsiString(&AnsiString,
1221 &Params->ShellInfo,
1222 TRUE);
1223 lpLocalStartupInfo->lpReserved = AnsiString.Buffer;
1224
1225 lpLocalStartupInfo->dwX = Params->StartingX;
1226 lpLocalStartupInfo->dwY = Params->StartingY;
1227 lpLocalStartupInfo->dwXSize = Params->CountX;
1228 lpLocalStartupInfo->dwYSize = Params->CountY;
1229 lpLocalStartupInfo->dwXCountChars = Params->CountCharsX;
1230 lpLocalStartupInfo->dwYCountChars = Params->CountCharsY;
1231 lpLocalStartupInfo->dwFillAttribute = Params->FillAttribute;
1232 lpLocalStartupInfo->dwFlags = Params->WindowFlags;
1233 lpLocalStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1234 lpLocalStartupInfo->cbReserved2 = Params->RuntimeData.Length;
1235 lpLocalStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1236
1237 lpLocalStartupInfo->hStdInput = Params->StandardInput;
1238 lpLocalStartupInfo->hStdOutput = Params->StandardOutput;
1239 lpLocalStartupInfo->hStdError = Params->StandardError;
1240 }
1241
1242 RtlReleasePebLock();
1243
1244 /* copy local startup info data to external startup info */
1245 memcpy(lpStartupInfo,
1246 lpLocalStartupInfo,
1247 sizeof(STARTUPINFOA));
1248 }
1249
1250
1251 /*
1252 * @implemented
1253 */
1254 BOOL
1255 WINAPI
1256 FlushInstructionCache(HANDLE hProcess,
1257 LPCVOID lpBaseAddress,
1258 SIZE_T dwSize)
1259 {
1260 NTSTATUS Status;
1261
1262 Status = NtFlushInstructionCache(hProcess,
1263 (PVOID)lpBaseAddress,
1264 dwSize);
1265 if (!NT_SUCCESS(Status))
1266 {
1267 BaseSetLastNTError(Status);
1268 return FALSE;
1269 }
1270
1271 return TRUE;
1272 }
1273
1274
1275 /*
1276 * @implemented
1277 */
1278 VOID
1279 WINAPI
1280 ExitProcess(UINT uExitCode)
1281 {
1282 CSR_API_MESSAGE CsrRequest;
1283 ULONG Request;
1284 NTSTATUS Status;
1285
1286 /* kill sibling threads ... we want to be alone at this point */
1287 NtTerminateProcess(NULL, 0);
1288
1289 /* unload all dll's */
1290 LdrShutdownProcess();
1291
1292 /* notify csrss of process termination */
1293 Request = TERMINATE_PROCESS;
1294 Status = CsrClientCallServer(&CsrRequest,
1295 NULL,
1296 MAKE_CSR_API(Request, CSR_NATIVE),
1297 sizeof(CSR_API_MESSAGE));
1298 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
1299 {
1300 DPRINT("Failed to tell csrss about terminating process\n");
1301 }
1302
1303 NtTerminateProcess(NtCurrentProcess (),
1304 uExitCode);
1305
1306 /* should never get here */
1307 ASSERT(0);
1308 while(1);
1309 }
1310
1311
1312 /*
1313 * @implemented
1314 */
1315 BOOL
1316 WINAPI
1317 TerminateProcess(HANDLE hProcess,
1318 UINT uExitCode)
1319 {
1320 NTSTATUS Status;
1321
1322 if (hProcess == NULL)
1323 {
1324 return FALSE;
1325 }
1326
1327 Status = NtTerminateProcess(hProcess, uExitCode);
1328 if (NT_SUCCESS(Status))
1329 {
1330 return TRUE;
1331 }
1332
1333 BaseSetLastNTError(Status);
1334 return FALSE;
1335 }
1336
1337
1338 /*
1339 * @unimplemented
1340 */
1341 VOID
1342 WINAPI
1343 FatalAppExitA(UINT uAction,
1344 LPCSTR lpMessageText)
1345 {
1346 UNICODE_STRING MessageTextU;
1347 ANSI_STRING MessageText;
1348
1349 RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText);
1350
1351 RtlAnsiStringToUnicodeString(&MessageTextU,
1352 &MessageText,
1353 TRUE);
1354
1355 FatalAppExitW(uAction, MessageTextU.Buffer);
1356
1357 RtlFreeUnicodeString(&MessageTextU);
1358 }
1359
1360
1361 /*
1362 * @unimplemented
1363 */
1364 VOID
1365 WINAPI
1366 FatalAppExitW(UINT uAction,
1367 LPCWSTR lpMessageText)
1368 {
1369 static const WCHAR szUser32[] = L"user32.dll\0";
1370
1371 HMODULE hModule = GetModuleHandleW(szUser32);
1372 MessageBoxW_Proc pMessageBoxW = NULL;
1373
1374 DPRINT1("AppExit\n");
1375
1376 if (hModule)
1377 pMessageBoxW = (MessageBoxW_Proc)GetProcAddress(hModule, "MessageBoxW");
1378
1379 if (pMessageBoxW)
1380 pMessageBoxW(0, lpMessageText, NULL, MB_SYSTEMMODAL | MB_OK);
1381 else
1382 DPRINT1("%s\n", lpMessageText);
1383
1384 ExitProcess(0);
1385 }
1386
1387
1388 /*
1389 * @implemented
1390 */
1391 VOID
1392 WINAPI
1393 FatalExit(int ExitCode)
1394 {
1395 ExitProcess(ExitCode);
1396 }
1397
1398
1399 /*
1400 * @implemented
1401 */
1402 DWORD
1403 WINAPI
1404 GetPriorityClass(HANDLE hProcess)
1405 {
1406 NTSTATUS Status;
1407 PROCESS_PRIORITY_CLASS PriorityClass;
1408
1409 Status = NtQueryInformationProcess(hProcess,
1410 ProcessPriorityClass,
1411 &PriorityClass,
1412 sizeof(PROCESS_PRIORITY_CLASS),
1413 NULL);
1414 if(NT_SUCCESS(Status))
1415 {
1416 switch(PriorityClass.PriorityClass)
1417 {
1418 case PROCESS_PRIORITY_CLASS_IDLE:
1419 return IDLE_PRIORITY_CLASS;
1420
1421 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:
1422 return BELOW_NORMAL_PRIORITY_CLASS;
1423
1424 case PROCESS_PRIORITY_CLASS_NORMAL:
1425 return NORMAL_PRIORITY_CLASS;
1426
1427 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:
1428 return ABOVE_NORMAL_PRIORITY_CLASS;
1429
1430 case PROCESS_PRIORITY_CLASS_HIGH:
1431 return HIGH_PRIORITY_CLASS;
1432
1433 case PROCESS_PRIORITY_CLASS_REALTIME:
1434 return REALTIME_PRIORITY_CLASS;
1435
1436 default:
1437 return NORMAL_PRIORITY_CLASS;
1438 }
1439 }
1440
1441 BaseSetLastNTError(Status);
1442 return FALSE;
1443 }
1444
1445
1446 /*
1447 * @implemented
1448 */
1449 BOOL
1450 WINAPI
1451 SetPriorityClass(HANDLE hProcess,
1452 DWORD dwPriorityClass)
1453 {
1454 NTSTATUS Status;
1455 PROCESS_PRIORITY_CLASS PriorityClass;
1456
1457 switch (dwPriorityClass)
1458 {
1459 case IDLE_PRIORITY_CLASS:
1460 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
1461 break;
1462
1463 case BELOW_NORMAL_PRIORITY_CLASS:
1464 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
1465 break;
1466
1467 case NORMAL_PRIORITY_CLASS:
1468 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
1469 break;
1470
1471 case ABOVE_NORMAL_PRIORITY_CLASS:
1472 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
1473 break;
1474
1475 case HIGH_PRIORITY_CLASS:
1476 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
1477 break;
1478
1479 case REALTIME_PRIORITY_CLASS:
1480 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
1481 break;
1482
1483 default:
1484 SetLastError(ERROR_INVALID_PARAMETER);
1485 return FALSE;
1486 }
1487
1488 PriorityClass.Foreground = FALSE;
1489
1490 Status = NtSetInformationProcess(hProcess,
1491 ProcessPriorityClass,
1492 &PriorityClass,
1493 sizeof(PROCESS_PRIORITY_CLASS));
1494 if (!NT_SUCCESS(Status))
1495 {
1496 BaseSetLastNTError(Status);
1497 return FALSE;
1498 }
1499
1500 return TRUE;
1501 }
1502
1503
1504 /*
1505 * @implemented
1506 */
1507 DWORD
1508 WINAPI
1509 GetProcessVersion(DWORD ProcessId)
1510 {
1511 DWORD Version = 0;
1512 PIMAGE_NT_HEADERS NtHeader = NULL;
1513 IMAGE_NT_HEADERS NtHeaders;
1514 IMAGE_DOS_HEADER DosHeader;
1515 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
1516 PVOID BaseAddress = NULL;
1517 HANDLE ProcessHandle = NULL;
1518 NTSTATUS Status;
1519 SIZE_T Count;
1520 PEB Peb;
1521
1522 _SEH2_TRY
1523 {
1524 if (0 == ProcessId || GetCurrentProcessId() == ProcessId)
1525 {
1526 /* Caller's */
1527 BaseAddress = (PVOID) NtCurrentPeb()->ImageBaseAddress;
1528 NtHeader = RtlImageNtHeader(BaseAddress);
1529
1530 Version = (NtHeader->OptionalHeader.MajorOperatingSystemVersion << 16) |
1531 (NtHeader->OptionalHeader.MinorOperatingSystemVersion);
1532 }
1533 else
1534 {
1535 /* Other process */
1536 ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
1537 FALSE,
1538 ProcessId);
1539
1540 if (!ProcessHandle) return 0;
1541
1542 Status = NtQueryInformationProcess(ProcessHandle,
1543 ProcessBasicInformation,
1544 &ProcessBasicInfo,
1545 sizeof(ProcessBasicInfo),
1546 NULL);
1547
1548 if (!NT_SUCCESS(Status)) goto Error;
1549
1550 Status = NtReadVirtualMemory(ProcessHandle,
1551 ProcessBasicInfo.PebBaseAddress,
1552 &Peb,
1553 sizeof(Peb),
1554 &Count);
1555
1556 if (!NT_SUCCESS(Status) || Count != sizeof(Peb)) goto Error;
1557
1558 memset(&DosHeader, 0, sizeof(DosHeader));
1559 Status = NtReadVirtualMemory(ProcessHandle,
1560 Peb.ImageBaseAddress,
1561 &DosHeader,
1562 sizeof(DosHeader),
1563 &Count);
1564
1565 if (!NT_SUCCESS(Status) || Count != sizeof(DosHeader)) goto Error;
1566 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) goto Error;
1567
1568 memset(&NtHeaders, 0, sizeof(NtHeaders));
1569 Status = NtReadVirtualMemory(ProcessHandle,
1570 (char *)Peb.ImageBaseAddress + DosHeader.e_lfanew,
1571 &NtHeaders,
1572 sizeof(NtHeaders),
1573 &Count);
1574
1575 if (!NT_SUCCESS(Status) || Count != sizeof(NtHeaders)) goto Error;
1576 if (NtHeaders.Signature != IMAGE_NT_SIGNATURE) goto Error;
1577
1578 Version = MAKELONG(NtHeaders.OptionalHeader.MinorSubsystemVersion,
1579 NtHeaders.OptionalHeader.MajorSubsystemVersion);
1580
1581 Error:
1582 if (!NT_SUCCESS(Status))
1583 {
1584 BaseSetLastNTError(Status);
1585 }
1586 }
1587 }
1588 _SEH2_FINALLY
1589 {
1590 if (ProcessHandle) CloseHandle(ProcessHandle);
1591 }
1592 _SEH2_END;
1593
1594 return Version;
1595 }
1596
1597
1598 /*
1599 * @implemented
1600 */
1601 BOOL
1602 WINAPI
1603 GetProcessIoCounters(HANDLE hProcess,
1604 PIO_COUNTERS lpIoCounters)
1605 {
1606 NTSTATUS Status;
1607
1608 Status = NtQueryInformationProcess(hProcess,
1609 ProcessIoCounters,
1610 lpIoCounters,
1611 sizeof(IO_COUNTERS),
1612 NULL);
1613 if (!NT_SUCCESS(Status))
1614 {
1615 BaseSetLastNTError(Status);
1616 return FALSE;
1617 }
1618
1619 return TRUE;
1620 }
1621
1622
1623 /*
1624 * @implemented
1625 */
1626 BOOL
1627 WINAPI
1628 GetProcessPriorityBoost(HANDLE hProcess,
1629 PBOOL pDisablePriorityBoost)
1630 {
1631 NTSTATUS Status;
1632 ULONG PriorityBoost;
1633
1634 Status = NtQueryInformationProcess(hProcess,
1635 ProcessPriorityBoost,
1636 &PriorityBoost,
1637 sizeof(ULONG),
1638 NULL);
1639 if (NT_SUCCESS(Status))
1640 {
1641 *pDisablePriorityBoost = PriorityBoost;
1642 return TRUE;
1643 }
1644
1645 BaseSetLastNTError(Status);
1646 return FALSE;
1647 }
1648
1649
1650 /*
1651 * @implemented
1652 */
1653 BOOL
1654 WINAPI
1655 SetProcessPriorityBoost(HANDLE hProcess,
1656 BOOL bDisablePriorityBoost)
1657 {
1658 NTSTATUS Status;
1659 ULONG PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE); /* prevent setting values other than 1 and 0 */
1660
1661 Status = NtSetInformationProcess(hProcess,
1662 ProcessPriorityBoost,
1663 &PriorityBoost,
1664 sizeof(ULONG));
1665 if (!NT_SUCCESS(Status))
1666 {
1667 BaseSetLastNTError(Status);
1668 return FALSE;
1669 }
1670
1671 return TRUE;
1672 }
1673
1674
1675 /*
1676 * @implemented
1677 */
1678 BOOL
1679 WINAPI
1680 GetProcessHandleCount(HANDLE hProcess,
1681 PDWORD pdwHandleCount)
1682 {
1683 ULONG phc;
1684 NTSTATUS Status;
1685
1686 Status = NtQueryInformationProcess(hProcess,
1687 ProcessHandleCount,
1688 &phc,
1689 sizeof(ULONG),
1690 NULL);
1691 if(NT_SUCCESS(Status))
1692 {
1693 *pdwHandleCount = phc;
1694 return TRUE;
1695 }
1696
1697 BaseSetLastNTError(Status);
1698 return FALSE;
1699 }
1700
1701
1702 /*
1703 * @implemented
1704 */
1705 BOOL
1706 WINAPI
1707 IsWow64Process(HANDLE hProcess,
1708 PBOOL Wow64Process)
1709 {
1710 ULONG_PTR pbi;
1711 NTSTATUS Status;
1712
1713 Status = NtQueryInformationProcess(hProcess,
1714 ProcessWow64Information,
1715 &pbi,
1716 sizeof(pbi),
1717 NULL);
1718 if (!NT_SUCCESS(Status))
1719 {
1720 SetLastError(RtlNtStatusToDosError(Status));
1721 return FALSE;
1722 }
1723
1724 *Wow64Process = (pbi != 0);
1725
1726 return TRUE;
1727 }
1728
1729 /*
1730 * @implemented
1731 */
1732 LPSTR
1733 WINAPI
1734 GetCommandLineA(VOID)
1735 {
1736 DPRINT("CommandLine \'%s\'\n", CommandLineStringA.Buffer);
1737 return CommandLineStringA.Buffer;
1738 }
1739
1740
1741 /*
1742 * @implemented
1743 */
1744 LPWSTR
1745 WINAPI
1746 GetCommandLineW(VOID)
1747 {
1748 DPRINT("CommandLine \'%S\'\n", CommandLineStringW.Buffer);
1749 return CommandLineStringW.Buffer;
1750 }
1751
1752 /*
1753 * @implemented
1754 */
1755 BOOL
1756 NTAPI
1757 ReadProcessMemory(IN HANDLE hProcess,
1758 IN LPCVOID lpBaseAddress,
1759 IN LPVOID lpBuffer,
1760 IN SIZE_T nSize,
1761 OUT SIZE_T* lpNumberOfBytesRead)
1762 {
1763 NTSTATUS Status;
1764
1765 /* Do the read */
1766 Status = NtReadVirtualMemory(hProcess,
1767 (PVOID)lpBaseAddress,
1768 lpBuffer,
1769 nSize,
1770 lpNumberOfBytesRead);
1771 if (!NT_SUCCESS(Status))
1772 {
1773 /* We failed */
1774 BaseSetLastNTError (Status);
1775 return FALSE;
1776 }
1777
1778 /* Return success */
1779 return TRUE;
1780 }
1781
1782 /*
1783 * @implemented
1784 */
1785 BOOL
1786 NTAPI
1787 WriteProcessMemory(IN HANDLE hProcess,
1788 IN LPVOID lpBaseAddress,
1789 IN LPCVOID lpBuffer,
1790 IN SIZE_T nSize,
1791 OUT SIZE_T *lpNumberOfBytesWritten)
1792 {
1793 NTSTATUS Status;
1794 ULONG OldValue;
1795 SIZE_T RegionSize;
1796 PVOID Base;
1797 BOOLEAN UnProtect;
1798
1799 /* Set parameters for protect call */
1800 RegionSize = nSize;
1801 Base = lpBaseAddress;
1802
1803 /* Check the current status */
1804 Status = NtProtectVirtualMemory(hProcess,
1805 &Base,
1806 &RegionSize,
1807 PAGE_EXECUTE_READWRITE,
1808 &OldValue);
1809 if (NT_SUCCESS(Status))
1810 {
1811 /* Check if we are unprotecting */
1812 UnProtect = OldValue & (PAGE_READWRITE |
1813 PAGE_WRITECOPY |
1814 PAGE_EXECUTE_READWRITE |
1815 PAGE_EXECUTE_WRITECOPY) ? FALSE : TRUE;
1816 if (!UnProtect)
1817 {
1818 /* Set the new protection */
1819 Status = NtProtectVirtualMemory(hProcess,
1820 &Base,
1821 &RegionSize,
1822 OldValue,
1823 &OldValue);
1824
1825 /* Write the memory */
1826 Status = NtWriteVirtualMemory(hProcess,
1827 lpBaseAddress,
1828 (LPVOID)lpBuffer,
1829 nSize,
1830 lpNumberOfBytesWritten);
1831 if (!NT_SUCCESS(Status))
1832 {
1833 /* We failed */
1834 BaseSetLastNTError(Status);
1835 return FALSE;
1836 }
1837
1838 /* Flush the ITLB */
1839 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
1840 return TRUE;
1841 }
1842 else
1843 {
1844 /* Check if we were read only */
1845 if ((OldValue & PAGE_NOACCESS) || (OldValue & PAGE_READONLY))
1846 {
1847 /* Restore protection and fail */
1848 NtProtectVirtualMemory(hProcess,
1849 &Base,
1850 &RegionSize,
1851 OldValue,
1852 &OldValue);
1853 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
1854 return FALSE;
1855 }
1856
1857 /* Otherwise, do the write */
1858 Status = NtWriteVirtualMemory(hProcess,
1859 lpBaseAddress,
1860 (LPVOID)lpBuffer,
1861 nSize,
1862 lpNumberOfBytesWritten);
1863
1864 /* And restore the protection */
1865 NtProtectVirtualMemory(hProcess,
1866 &Base,
1867 &RegionSize,
1868 OldValue,
1869 &OldValue);
1870 if (!NT_SUCCESS(Status))
1871 {
1872 /* We failed */
1873 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
1874 return FALSE;
1875 }
1876
1877 /* Flush the ITLB */
1878 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
1879 return TRUE;
1880 }
1881 }
1882 else
1883 {
1884 /* We failed */
1885 BaseSetLastNTError(Status);
1886 return FALSE;
1887 }
1888 }
1889
1890 /*
1891 * @implemented
1892 */
1893 BOOL
1894 WINAPI
1895 ProcessIdToSessionId(IN DWORD dwProcessId,
1896 OUT DWORD *pSessionId)
1897 {
1898 PROCESS_SESSION_INFORMATION SessionInformation;
1899 OBJECT_ATTRIBUTES ObjectAttributes;
1900 CLIENT_ID ClientId;
1901 HANDLE ProcessHandle;
1902 NTSTATUS Status;
1903
1904 if (IsBadWritePtr(pSessionId, sizeof(DWORD)))
1905 {
1906 SetLastError(ERROR_INVALID_PARAMETER);
1907 return FALSE;
1908 }
1909
1910 ClientId.UniqueProcess = UlongToHandle(dwProcessId);
1911 ClientId.UniqueThread = 0;
1912
1913 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
1914
1915 Status = NtOpenProcess(&ProcessHandle,
1916 PROCESS_QUERY_INFORMATION,
1917 &ObjectAttributes,
1918 &ClientId);
1919 if (NT_SUCCESS(Status))
1920 {
1921 Status = NtQueryInformationProcess(ProcessHandle,
1922 ProcessSessionInformation,
1923 &SessionInformation,
1924 sizeof(SessionInformation),
1925 NULL);
1926 NtClose(ProcessHandle);
1927
1928 if (NT_SUCCESS(Status))
1929 {
1930 *pSessionId = SessionInformation.SessionId;
1931 return TRUE;
1932 }
1933 }
1934
1935 BaseSetLastNTError(Status);
1936 return FALSE;
1937 }
1938
1939 BOOL
1940 WINAPI
1941 SetProcessWorkingSetSizeEx(IN HANDLE hProcess,
1942 IN SIZE_T dwMinimumWorkingSetSize,
1943 IN SIZE_T dwMaximumWorkingSetSize,
1944 IN DWORD Flags)
1945 {
1946 STUB;
1947 return FALSE;
1948 }
1949
1950
1951 BOOL
1952 WINAPI
1953 GetProcessWorkingSetSizeEx(IN HANDLE hProcess,
1954 OUT PSIZE_T lpMinimumWorkingSetSize,
1955 OUT PSIZE_T lpMaximumWorkingSetSize,
1956 OUT PDWORD Flags)
1957 {
1958 STUB;
1959 return FALSE;
1960 }
1961
1962 /*
1963 * @implemented
1964 */
1965 BOOL
1966 WINAPI
1967 CreateProcessInternalW(HANDLE hToken,
1968 LPCWSTR lpApplicationName,
1969 LPWSTR lpCommandLine,
1970 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1971 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1972 BOOL bInheritHandles,
1973 DWORD dwCreationFlags,
1974 LPVOID lpEnvironment,
1975 LPCWSTR lpCurrentDirectory,
1976 LPSTARTUPINFOW lpStartupInfo,
1977 LPPROCESS_INFORMATION lpProcessInformation,
1978 PHANDLE hNewToken)
1979 {
1980 NTSTATUS Status;
1981 PROCESS_PRIORITY_CLASS PriorityClass;
1982 BOOLEAN FoundQuotes = FALSE;
1983 BOOLEAN QuotesNeeded = FALSE;
1984 BOOLEAN CmdLineIsAppName = FALSE;
1985 UNICODE_STRING ApplicationName = { 0, 0, NULL };
1986 OBJECT_ATTRIBUTES LocalObjectAttributes;
1987 POBJECT_ATTRIBUTES ObjectAttributes;
1988 HANDLE hSection = NULL, hProcess = NULL, hThread = NULL, hDebug = NULL;
1989 SECTION_IMAGE_INFORMATION SectionImageInfo;
1990 LPWSTR CurrentDirectory = NULL;
1991 LPWSTR CurrentDirectoryPart;
1992 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
1993 STARTUPINFOW StartupInfo;
1994 ULONG Dummy;
1995 LPWSTR BatchCommandLine;
1996 ULONG CmdLineLength;
1997 UNICODE_STRING CommandLineString;
1998 PWCHAR Extension;
1999 LPWSTR QuotedCmdLine = NULL;
2000 LPWSTR ScanString;
2001 LPWSTR NullBuffer = NULL;
2002 LPWSTR NameBuffer = NULL;
2003 WCHAR SaveChar = 0;
2004 ULONG RetVal;
2005 UINT Error = 0;
2006 BOOLEAN SearchDone = FALSE;
2007 BOOLEAN Escape = FALSE;
2008 CLIENT_ID ClientId;
2009 PPEB OurPeb = NtCurrentPeb();
2010 PPEB RemotePeb;
2011 SIZE_T EnvSize = 0;
2012 BOOL Ret = FALSE;
2013
2014 /* FIXME should process
2015 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2016 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
2017 */
2018
2019 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
2020 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
2021 lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
2022 dwCreationFlags);
2023
2024 /* Flags we don't handle yet */
2025 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
2026 {
2027 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
2028 }
2029 if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
2030 {
2031 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
2032 }
2033 if (dwCreationFlags & CREATE_FORCEDOS)
2034 {
2035 DPRINT1("CREATE_FORCEDOS not handled\n");
2036 }
2037
2038 /* Fail on this flag, it's only valid with the WithLogonW function */
2039 if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
2040 {
2041 DPRINT1("Invalid flag used\n");
2042 SetLastError(ERROR_INVALID_PARAMETER);
2043 return FALSE;
2044 }
2045
2046 /* This combination is illegal (see MSDN) */
2047 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
2048 (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
2049 {
2050 DPRINT1("Invalid flag combo used\n");
2051 SetLastError(ERROR_INVALID_PARAMETER);
2052 return FALSE;
2053 }
2054
2055 /* Another illegal combo */
2056 if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
2057 (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
2058 {
2059 DPRINT1("Invalid flag combo used\n");
2060 SetLastError(ERROR_INVALID_PARAMETER);
2061 return FALSE;
2062 }
2063
2064 if (lpCurrentDirectory)
2065 {
2066 if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) ||
2067 !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY))
2068 {
2069 SetLastError(ERROR_DIRECTORY);
2070 return FALSE;
2071 }
2072 }
2073
2074 /*
2075 * We're going to modify and mask out flags and stuff in lpStartupInfo,
2076 * so we'll use our own local copy for that.
2077 */
2078 StartupInfo = *lpStartupInfo;
2079
2080 /* FIXME: Use default Separate/Shared VDM Flag */
2081
2082 /* If we are inside a Job, use Separate VDM so it won't escape the Job */
2083 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
2084 {
2085 if (NtIsProcessInJob(NtCurrentProcess(), NULL))
2086 {
2087 /* Remove the shared flag and add the separate flag. */
2088 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
2089 CREATE_SEPARATE_WOW_VDM;
2090 }
2091 }
2092
2093 /*
2094 * According to some sites, ShellExecuteEx uses an undocumented flag to
2095 * send private handle data (such as HMONITOR or HICON). See:
2096 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
2097 * standard handles anymore since we'd be overwriting this private data
2098 */
2099 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
2100 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
2101 {
2102 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
2103 }
2104
2105 /* Start by zeroing out the fields */
2106 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
2107
2108 /* Easy stuff first, convert the process priority class */
2109 PriorityClass.Foreground = FALSE;
2110 PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags);
2111
2112 if (lpCommandLine)
2113 {
2114 /* Search for escape sequences */
2115 ScanString = lpCommandLine;
2116 while (NULL != (ScanString = wcschr(ScanString, L'^')))
2117 {
2118 ScanString++;
2119 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\"')
2120 {
2121 Escape = TRUE;
2122 break;
2123 }
2124 }
2125 }
2126
2127 /* Get the application name and do all the proper formating necessary */
2128 GetAppName:
2129 /* See if we have an application name (oh please let us have one!) */
2130 if (!lpApplicationName)
2131 {
2132 /* The fun begins */
2133 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2134 0,
2135 MAX_PATH * sizeof(WCHAR));
2136 if (NameBuffer == NULL)
2137 {
2138 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2139 goto Cleanup;
2140 }
2141
2142 /* This is all we have to work with :( */
2143 lpApplicationName = lpCommandLine;
2144
2145 /* Initialize our friends at the beginning */
2146 NullBuffer = (LPWSTR)lpApplicationName;
2147 ScanString = (LPWSTR)lpApplicationName;
2148
2149 /* We will start by looking for a quote */
2150 if (*ScanString == L'\"')
2151 {
2152 /* That was quick */
2153 SearchDone = TRUE;
2154
2155 /* Advance past quote */
2156 ScanString++;
2157 lpApplicationName = ScanString;
2158
2159 /* Find the closing quote */
2160 while (*ScanString)
2161 {
2162 if (*ScanString == L'\"' && *(ScanString - 1) != L'^')
2163 {
2164 /* Found it */
2165 NullBuffer = ScanString;
2166 FoundQuotes = TRUE;
2167 break;
2168 }
2169
2170 /* Keep looking */
2171 ScanString++;
2172 NullBuffer = ScanString;
2173 }
2174 }
2175 else
2176 {
2177 /* No quotes, so we'll be looking for white space */
2178 WhiteScan:
2179 /* Reset the pointer */
2180 lpApplicationName = lpCommandLine;
2181
2182 /* Find whitespace of Tab */
2183 while (*ScanString)
2184 {
2185 if (*ScanString == ' ' || *ScanString == '\t')
2186 {
2187 /* Found it */
2188 NullBuffer = ScanString;
2189 break;
2190 }
2191
2192 /* Keep looking */
2193 ScanString++;
2194 NullBuffer = ScanString;
2195 }
2196 }
2197
2198 /* Set the Null Buffer */
2199 SaveChar = *NullBuffer;
2200 *NullBuffer = UNICODE_NULL;
2201
2202 /* Do a search for the file */
2203 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
2204 RetVal = SearchPathW(NULL,
2205 lpApplicationName,
2206 L".exe",
2207 MAX_PATH,
2208 NameBuffer,
2209 NULL) * sizeof(WCHAR);
2210
2211 /* Did it find something? */
2212 if (RetVal)
2213 {
2214 /* Get file attributes */
2215 ULONG Attributes = GetFileAttributesW(NameBuffer);
2216 if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
2217 {
2218 /* Give it a length of 0 to fail, this was a directory. */
2219 RetVal = 0;
2220 }
2221 else
2222 {
2223 /* It's a file! */
2224 RetVal += sizeof(WCHAR);
2225 }
2226 }
2227
2228 /* Now check if we have a file, and if the path size is OK */
2229 if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR)))
2230 {
2231 ULONG PathType;
2232 HANDLE hFile;
2233
2234 /* We failed, try to get the Path Type */
2235 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
2236 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2237
2238 /* If it's not relative, try to get the error */
2239 if (PathType != RtlPathTypeRelative)
2240 {
2241 /* This should fail, and give us a detailed LastError */
2242 hFile = CreateFileW(lpApplicationName,
2243 GENERIC_READ,
2244 FILE_SHARE_READ | FILE_SHARE_WRITE,
2245 NULL,
2246 OPEN_EXISTING,
2247 FILE_ATTRIBUTE_NORMAL,
2248 NULL);
2249
2250 /* Did it actually NOT fail? */
2251 if (hFile != INVALID_HANDLE_VALUE)
2252 {
2253 /* Fake the error */
2254 CloseHandle(hFile);
2255 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
2256 }
2257 }
2258 else
2259 {
2260 /* Immediately set the error */
2261 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
2262 }
2263
2264 /* Did we already fail once? */
2265 if (Error)
2266 {
2267 SetLastError(Error);
2268 }
2269 else
2270 {
2271 /* Not yet, cache it */
2272 Error = GetLastError();
2273 }
2274
2275 /* Put back the command line */
2276 *NullBuffer = SaveChar;
2277 lpApplicationName = NameBuffer;
2278
2279 /*
2280 * If the search isn't done and we still have cmdline
2281 * then start over. Ex: c:\ha ha ha\haha.exe
2282 */
2283 if (*ScanString && !SearchDone)
2284 {
2285 /* Move in the buffer */
2286 ScanString++;
2287 NullBuffer = ScanString;
2288
2289 /* We will have to add a quote, since there is a space*/
2290 QuotesNeeded = TRUE;
2291
2292 /* And we will also fake the fact we found one */
2293 FoundQuotes = TRUE;
2294
2295 /* Start over */
2296 goto WhiteScan;
2297 }
2298
2299 /* We totally failed */
2300 goto Cleanup;
2301 }
2302
2303 /* Put back the command line */
2304 *NullBuffer = SaveChar;
2305 lpApplicationName = NameBuffer;
2306 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
2307 }
2308 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
2309 {
2310 /* We have an app name (good!) but no command line */
2311 CmdLineIsAppName = TRUE;
2312 lpCommandLine = (LPWSTR)lpApplicationName;
2313 }
2314
2315 /* At this point the name has been toyed with enough to be openable */
2316 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
2317
2318 /* Check for failure */
2319 if (!NT_SUCCESS(Status))
2320 {
2321 /* Could be a non-PE File */
2322 switch (Status)
2323 {
2324 /* Check if the Kernel tells us it's not even valid MZ */
2325 case STATUS_INVALID_IMAGE_NE_FORMAT:
2326 case STATUS_INVALID_IMAGE_PROTECT:
2327 case STATUS_INVALID_IMAGE_NOT_MZ:
2328
2329 #if 0
2330 /* If it's a DOS app, use VDM */
2331 if ((BasepCheckDosApp(&ApplicationName)))
2332 {
2333 DPRINT1("Launching VDM...\n");
2334 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2335 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2336 return CreateProcessW(L"ntvdm.exe",
2337 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
2338 lpProcessAttributes,
2339 lpThreadAttributes,
2340 bInheritHandles,
2341 dwCreationFlags,
2342 lpEnvironment,
2343 lpCurrentDirectory,
2344 &StartupInfo,
2345 lpProcessInformation);
2346 }
2347 #endif
2348 /* It's a batch file */
2349 Extension = &ApplicationName.Buffer[ApplicationName.Length /
2350 sizeof(WCHAR) - 4];
2351
2352 /* Make sure the extensions are correct */
2353 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
2354 {
2355 SetLastError(ERROR_BAD_EXE_FORMAT);
2356 return FALSE;
2357 }
2358
2359 /* Calculate the length of the command line */
2360 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
2361
2362 /* If we found quotes, then add them into the length size */
2363 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
2364 CmdLineLength *= sizeof(WCHAR);
2365
2366 /* Allocate space for the new command line */
2367 BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
2368 0,
2369 CmdLineLength);
2370 if (BatchCommandLine == NULL)
2371 {
2372 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2373 goto Cleanup;
2374 }
2375
2376 /* Build it */
2377 wcscpy(BatchCommandLine, CMD_STRING);
2378 if (CmdLineIsAppName || FoundQuotes)
2379 {
2380 wcscat(BatchCommandLine, L"\"");
2381 }
2382 wcscat(BatchCommandLine, lpCommandLine);
2383 if (CmdLineIsAppName || FoundQuotes)
2384 {
2385 wcscat(BatchCommandLine, L"\"");
2386 }
2387
2388 /* Create it as a Unicode String */
2389 RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
2390
2391 /* Set the command line to this */
2392 lpCommandLine = CommandLineString.Buffer;
2393 lpApplicationName = NULL;
2394
2395 /* Free memory */
2396 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2397 ApplicationName.Buffer = NULL;
2398 goto GetAppName;
2399 break;
2400
2401 case STATUS_INVALID_IMAGE_WIN_16:
2402
2403 /* It's a Win16 Image, use VDM */
2404 DPRINT1("Launching VDM...\n");
2405 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2406 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2407 return CreateProcessW(L"ntvdm.exe",
2408 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
2409 lpProcessAttributes,
2410 lpThreadAttributes,
2411 bInheritHandles,
2412 dwCreationFlags,
2413 lpEnvironment,
2414 lpCurrentDirectory,
2415 &StartupInfo,
2416 lpProcessInformation);
2417
2418 case STATUS_OBJECT_NAME_NOT_FOUND:
2419 case STATUS_OBJECT_PATH_NOT_FOUND:
2420 BaseSetLastNTError(Status);
2421 goto Cleanup;
2422
2423 default:
2424 /* Invalid Image Type */
2425 SetLastError(ERROR_BAD_EXE_FORMAT);
2426 goto Cleanup;
2427 }
2428 }
2429
2430 /* Use our desktop if we didn't get any */
2431 if (!StartupInfo.lpDesktop)
2432 {
2433 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
2434 }
2435
2436 /* FIXME: Check if Application is allowed to run */
2437
2438 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
2439
2440 /* Get some information about the executable */
2441 Status = ZwQuerySection(hSection,
2442 SectionImageInformation,
2443 &SectionImageInfo,
2444 sizeof(SectionImageInfo),
2445 NULL);
2446 if(!NT_SUCCESS(Status))
2447 {
2448 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
2449 BaseSetLastNTError(Status);
2450 goto Cleanup;
2451 }
2452
2453 /* Don't execute DLLs */
2454 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
2455 {
2456 DPRINT1("Can't execute a DLL\n");
2457 SetLastError(ERROR_BAD_EXE_FORMAT);
2458 goto Cleanup;
2459 }
2460
2461 /* FIXME: Check for Debugger */
2462
2463 /* FIXME: Check if Machine Type and SubSys Version Match */
2464
2465 /* We don't support POSIX or anything else for now */
2466 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType &&
2467 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType)
2468 {
2469 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType);
2470 SetLastError(ERROR_BAD_EXE_FORMAT);
2471 goto Cleanup;
2472 }
2473
2474 if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType)
2475 {
2476 /* Do not create a console for GUI applications */
2477 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
2478 dwCreationFlags |= DETACHED_PROCESS;
2479 }
2480
2481 /* Initialize the process object attributes */
2482 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
2483 lpProcessAttributes,
2484 NULL);
2485
2486 /* Check if we're going to be debugged */
2487 if (dwCreationFlags & DEBUG_PROCESS)
2488 {
2489 /* FIXME: Set process flag */
2490 }
2491
2492 /* Check if we're going to be debugged */
2493 if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
2494 {
2495 /* Connect to DbgUi */
2496 Status = DbgUiConnectToDbg();
2497 if (!NT_SUCCESS(Status))
2498 {
2499 DPRINT1("Failed to connect to DbgUI!\n");
2500 BaseSetLastNTError(Status);
2501 goto Cleanup;
2502 }
2503
2504 /* Get the debug object */
2505 hDebug = DbgUiGetThreadDebugObject();
2506
2507 /* Check if only this process will be debugged */
2508 if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
2509 {
2510 /* FIXME: Set process flag */
2511 }
2512 }
2513
2514 /* Create the Process */
2515 Status = NtCreateProcess(&hProcess,
2516 PROCESS_ALL_ACCESS,
2517 ObjectAttributes,
2518 NtCurrentProcess(),
2519 (BOOLEAN)bInheritHandles,
2520 hSection,
2521 hDebug,
2522 NULL);
2523 if (!NT_SUCCESS(Status))
2524 {
2525 DPRINT1("Unable to create process, status 0x%x\n", Status);
2526 BaseSetLastNTError(Status);
2527 goto Cleanup;
2528 }
2529
2530 if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID)
2531 {
2532 /* Set new class */
2533 Status = NtSetInformationProcess(hProcess,
2534 ProcessPriorityClass,
2535 &PriorityClass,
2536 sizeof(PROCESS_PRIORITY_CLASS));
2537 if(!NT_SUCCESS(Status))
2538 {
2539 DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
2540 BaseSetLastNTError(Status);
2541 goto Cleanup;
2542 }
2543 }
2544
2545 /* Set Error Mode */
2546 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
2547 {
2548 ULONG ErrorMode = SEM_FAILCRITICALERRORS;
2549 NtSetInformationProcess(hProcess,
2550 ProcessDefaultHardErrorMode,
2551 &ErrorMode,
2552 sizeof(ULONG));
2553 }
2554
2555 /* Convert the directory to a full path */
2556 if (lpCurrentDirectory)
2557 {
2558 /* Allocate a buffer */
2559 CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
2560 0,
2561 (MAX_PATH + 1) * sizeof(WCHAR));
2562 if (CurrentDirectory == NULL)
2563 {
2564 DPRINT1("Cannot allocate memory for directory name\n");
2565 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2566 goto Cleanup;
2567 }
2568
2569 /* Get the length */
2570 if (GetFullPathNameW(lpCurrentDirectory,
2571 MAX_PATH,
2572 CurrentDirectory,
2573 &CurrentDirectoryPart) > MAX_PATH)
2574 {
2575 DPRINT1("Directory name too long\n");
2576 SetLastError(ERROR_DIRECTORY);
2577 goto Cleanup;
2578 }
2579 }
2580
2581 /* Insert quotes if needed */
2582 if (QuotesNeeded || CmdLineIsAppName)
2583 {
2584 /* Allocate a buffer */
2585 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
2586 0,
2587 (wcslen(lpCommandLine) + 2 + 1) *
2588 sizeof(WCHAR));
2589 if (QuotedCmdLine == NULL)
2590 {
2591 DPRINT1("Cannot allocate memory for quoted command line\n");
2592 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2593 goto Cleanup;
2594 }
2595
2596 /* Copy the first quote */
2597 wcscpy(QuotedCmdLine, L"\"");
2598
2599 /* Save a null char */
2600 if (QuotesNeeded)
2601 {
2602 SaveChar = *NullBuffer;
2603 *NullBuffer = UNICODE_NULL;
2604 }
2605
2606 /* Add the command line and the finishing quote */
2607 wcscat(QuotedCmdLine, lpCommandLine);
2608 wcscat(QuotedCmdLine, L"\"");
2609
2610 /* Add the null char */
2611 if (QuotesNeeded)
2612 {
2613 *NullBuffer = SaveChar;
2614 wcscat(QuotedCmdLine, NullBuffer);
2615 }
2616
2617 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
2618 }
2619
2620 if (Escape)
2621 {
2622 if (QuotedCmdLine == NULL)
2623 {
2624 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
2625 0,
2626 (wcslen(lpCommandLine) + 1) * sizeof(WCHAR));
2627 if (QuotedCmdLine == NULL)
2628 {
2629 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2630 goto Cleanup;
2631 }
2632 wcscpy(QuotedCmdLine, lpCommandLine);
2633 }
2634
2635 ScanString = QuotedCmdLine;
2636 while (NULL != (ScanString = wcschr(ScanString, L'^')))
2637 {
2638 ScanString++;
2639 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
2640 {
2641 memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR));
2642 }
2643 }
2644 }
2645
2646 /* Get the Process Information */
2647 Status = NtQueryInformationProcess(hProcess,
2648 ProcessBasicInformation,
2649 &ProcessBasicInfo,
2650 sizeof(ProcessBasicInfo),
2651 NULL);
2652
2653 /* Convert the environment */
2654 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
2655 {
2656 lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
2657 if (!lpEnvironment) goto Cleanup;
2658 }
2659
2660 /* Create Process Environment */
2661 RemotePeb = ProcessBasicInfo.PebBaseAddress;
2662 Status = BasePushProcessParameters(hProcess,
2663 RemotePeb,
2664 (LPWSTR)lpApplicationName,
2665 CurrentDirectory,
2666 (QuotesNeeded || CmdLineIsAppName || Escape) ?
2667 QuotedCmdLine : lpCommandLine,
2668 lpEnvironment,
2669 EnvSize,
2670 &StartupInfo,
2671 dwCreationFlags,
2672 bInheritHandles);
2673
2674 /* Cleanup Environment */
2675 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
2676 {
2677 RtlDestroyEnvironment(lpEnvironment);
2678 }
2679
2680 if (!NT_SUCCESS(Status))
2681 {
2682 DPRINT1("Could not initialize Process Environment\n");
2683 BaseSetLastNTError(Status);
2684 goto Cleanup;
2685 }
2686
2687 /* Close the section */
2688 NtClose(hSection);
2689 hSection = NULL;
2690
2691 /* Duplicate the handles if needed */
2692 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
2693 SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2694 {
2695 PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
2696
2697 /* Get the remote parameters */
2698 Status = NtReadVirtualMemory(hProcess,
2699 &RemotePeb->ProcessParameters,
2700 &RemoteParameters,
2701 sizeof(PVOID),
2702 NULL);
2703 if (!NT_SUCCESS(Status))
2704 {
2705 DPRINT1("Failed to read memory\n");
2706 goto Cleanup;
2707 }
2708
2709 /* Duplicate and write the handles */
2710 BasepDuplicateAndWriteHandle(hProcess,
2711 OurPeb->ProcessParameters->StandardInput,
2712 &RemoteParameters->StandardInput);
2713 BasepDuplicateAndWriteHandle(hProcess,
2714 OurPeb->ProcessParameters->StandardOutput,
2715 &RemoteParameters->StandardOutput);
2716 BasepDuplicateAndWriteHandle(hProcess,
2717 OurPeb->ProcessParameters->StandardError,
2718 &RemoteParameters->StandardError);
2719 }
2720
2721 /* Notify CSRSS */
2722 Status = BasepNotifyCsrOfCreation(dwCreationFlags,
2723 (HANDLE)ProcessBasicInfo.UniqueProcessId,
2724 bInheritHandles);
2725
2726 if (!NT_SUCCESS(Status))
2727 {
2728 DPRINT1("CSR Notification Failed\n");
2729 BaseSetLastNTError(Status);
2730 goto Cleanup;
2731 }
2732
2733 /* Create the first thread */
2734 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
2735 SectionImageInfo.TransferAddress);
2736 hThread = BasepCreateFirstThread(hProcess,
2737 lpThreadAttributes,
2738 &SectionImageInfo,
2739 &ClientId);
2740
2741 if (hThread == NULL)
2742 {
2743 DPRINT1("Could not create Initial Thread\n");
2744 /* FIXME - set last error code */
2745 goto Cleanup;
2746 }
2747
2748 if (!(dwCreationFlags & CREATE_SUSPENDED))
2749 {
2750 NtResumeThread(hThread, &Dummy);
2751 }
2752
2753 /* Return Data */
2754 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
2755 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
2756 lpProcessInformation->hProcess = hProcess;
2757 lpProcessInformation->hThread = hThread;
2758 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread,
2759 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
2760 hProcess = hThread = NULL;
2761 Ret = TRUE;
2762
2763 Cleanup:
2764 /* De-allocate heap strings */
2765 if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2766 if (ApplicationName.Buffer)
2767 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
2768 if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
2769 if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
2770
2771 /* Kill any handles still alive */
2772 if (hSection) NtClose(hSection);
2773 if (hThread)
2774 {
2775 /* We don't know any more details then this */
2776 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
2777 NtClose(hThread);
2778 }
2779 if (hProcess) NtClose(hProcess);
2780
2781 /* Return Success */
2782 return Ret;
2783 }
2784
2785 /*
2786 * @implemented
2787 */
2788 BOOL
2789 WINAPI
2790 CreateProcessW(LPCWSTR lpApplicationName,
2791 LPWSTR lpCommandLine,
2792 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2793 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2794 BOOL bInheritHandles,
2795 DWORD dwCreationFlags,
2796 LPVOID lpEnvironment,
2797 LPCWSTR lpCurrentDirectory,
2798 LPSTARTUPINFOW lpStartupInfo,
2799 LPPROCESS_INFORMATION lpProcessInformation)
2800 {
2801 /* Call the internal (but exported) version */
2802 return CreateProcessInternalW(0,
2803 lpApplicationName,
2804 lpCommandLine,
2805 lpProcessAttributes,
2806 lpThreadAttributes,
2807 bInheritHandles,
2808 dwCreationFlags,
2809 lpEnvironment,
2810 lpCurrentDirectory,
2811 lpStartupInfo,
2812 lpProcessInformation,
2813 NULL);
2814 }
2815
2816 /*
2817 * @implemented
2818 */
2819 BOOL
2820 WINAPI
2821 CreateProcessInternalA(HANDLE hToken,
2822 LPCSTR lpApplicationName,
2823 LPSTR lpCommandLine,
2824 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2825 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2826 BOOL bInheritHandles,
2827 DWORD dwCreationFlags,
2828 LPVOID lpEnvironment,
2829 LPCSTR lpCurrentDirectory,
2830 LPSTARTUPINFOA lpStartupInfo,
2831 LPPROCESS_INFORMATION lpProcessInformation,
2832 PHANDLE hNewToken)
2833 {
2834 PUNICODE_STRING CommandLine = NULL;
2835 UNICODE_STRING DummyString;
2836 UNICODE_STRING LiveCommandLine;
2837 UNICODE_STRING ApplicationName;
2838 UNICODE_STRING CurrentDirectory;
2839 BOOL bRetVal;
2840 STARTUPINFOW StartupInfo;
2841
2842 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
2843 "lpStartupInfo %x, lpProcessInformation %x\n",
2844 dwCreationFlags, lpEnvironment, lpCurrentDirectory,
2845 lpStartupInfo, lpProcessInformation);
2846
2847 /* Copy Startup Info */
2848 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
2849
2850 /* Initialize all strings to nothing */
2851 LiveCommandLine.Buffer = NULL;
2852 DummyString.Buffer = NULL;
2853 ApplicationName.Buffer = NULL;
2854 CurrentDirectory.Buffer = NULL;
2855 StartupInfo.lpDesktop = NULL;
2856 StartupInfo.lpReserved = NULL;
2857 StartupInfo.lpTitle = NULL;
2858
2859 /* Convert the Command line */
2860 if (lpCommandLine)
2861 {
2862 /* If it's too long, then we'll have a problem */
2863 if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
2864 NtCurrentTeb()->StaticUnicodeString.MaximumLength)
2865 {
2866 /* Cache it in the TEB */
2867 CommandLine = Basep8BitStringToStaticUnicodeString(lpCommandLine);
2868 }
2869 else
2870 {
2871 /* Use a dynamic version */
2872 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine,
2873 lpCommandLine);
2874 }
2875 }
2876 else
2877 {
2878 /* The logic below will use CommandLine, so we must make it valid */
2879 CommandLine = &DummyString;
2880 }
2881
2882 /* Convert the Name and Directory */
2883 if (lpApplicationName)
2884 {
2885 Basep8BitStringToDynamicUnicodeString(&ApplicationName,
2886 lpApplicationName);
2887 }
2888 if (lpCurrentDirectory)
2889 {
2890 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory,
2891 lpCurrentDirectory);
2892 }
2893
2894 /* Now convert Startup Strings */
2895 if (lpStartupInfo->lpReserved)
2896 {
2897 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
2898 &StartupInfo.lpReserved);
2899 }
2900 if (lpStartupInfo->lpDesktop)
2901 {
2902 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
2903 &StartupInfo.lpDesktop);
2904 }
2905 if (lpStartupInfo->lpTitle)
2906 {
2907 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
2908 &StartupInfo.lpTitle);
2909 }
2910
2911 /* Call the Unicode function */
2912 bRetVal = CreateProcessInternalW(hToken,
2913 ApplicationName.Buffer,
2914 LiveCommandLine.Buffer ?
2915 LiveCommandLine.Buffer : CommandLine->Buffer,
2916 lpProcessAttributes,
2917 lpThreadAttributes,
2918 bInheritHandles,
2919 dwCreationFlags,
2920 lpEnvironment,
2921 CurrentDirectory.Buffer,
2922 &StartupInfo,
2923 lpProcessInformation,
2924 hNewToken);
2925
2926 /* Clean up */
2927 RtlFreeUnicodeString(&ApplicationName);
2928 RtlFreeUnicodeString(&LiveCommandLine);
2929 RtlFreeUnicodeString(&CurrentDirectory);
2930 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop);
2931 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved);
2932 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle);
2933
2934 /* Return what Unicode did */
2935 return bRetVal;
2936 }
2937
2938 /*
2939 * FUNCTION: The CreateProcess function creates a new process and its
2940 * primary thread. The new process executes the specified executable file
2941 * ARGUMENTS:
2942 *
2943 * lpApplicationName = Pointer to name of executable module
2944 * lpCommandLine = Pointer to command line string
2945 * lpProcessAttributes = Process security attributes
2946 * lpThreadAttributes = Thread security attributes
2947 * bInheritHandles = Handle inheritance flag
2948 * dwCreationFlags = Creation flags
2949 * lpEnvironment = Pointer to new environment block
2950 * lpCurrentDirectory = Pointer to current directory name
2951 * lpStartupInfo = Pointer to startup info
2952 * lpProcessInformation = Pointer to process information
2953 *
2954 * @implemented
2955 */
2956 BOOL
2957 WINAPI
2958 CreateProcessA(LPCSTR lpApplicationName,
2959 LPSTR lpCommandLine,
2960 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2961 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2962 BOOL bInheritHandles,
2963 DWORD dwCreationFlags,
2964 LPVOID lpEnvironment,
2965 LPCSTR lpCurrentDirectory,
2966 LPSTARTUPINFOA lpStartupInfo,
2967 LPPROCESS_INFORMATION lpProcessInformation)
2968 {
2969 /* Call the internal (but exported) version */
2970 return CreateProcessInternalA(0,
2971 lpApplicationName,
2972 lpCommandLine,
2973 lpProcessAttributes,
2974 lpThreadAttributes,
2975 bInheritHandles,
2976 dwCreationFlags,
2977 lpEnvironment,
2978 lpCurrentDirectory,
2979 lpStartupInfo,
2980 lpProcessInformation,
2981 NULL);
2982 }
2983
2984 /* EOF */