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