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