Revert my last changes.
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/process/create.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 #include <pseh/framebased.h>
16
17 #define NDEBUG
18 #include "../include/debug.h"
19
20 /* FUNCTIONS ****************************************************************/
21
22 extern __declspec(noreturn)
23 VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
24
25 __declspec(dllimport)
26 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine;
27
28 typedef NTSTATUS STDCALL (K32_MBSTR_TO_WCSTR)
29 (
30 UNICODE_STRING *,
31 ANSI_STRING *,
32 BOOLEAN
33 );
34
35 NTSTATUS STDCALL K32MbStrToWcStr(IN K32_MBSTR_TO_WCSTR * True,
36 UNICODE_STRING * DestStr,
37 ANSI_STRING * SourceStr,
38 BOOLEAN Allocate)
39 {
40 if(SourceStr->Buffer == NULL)
41 {
42 DestStr->Length = DestStr->MaximumLength = 0;
43 DestStr->Buffer = NULL;
44 return STATUS_SUCCESS;
45 }
46
47 return True(DestStr, SourceStr, Allocate);
48 }
49
50 VOID STDCALL RtlRosR32AttribsToNativeAttribs(OUT OBJECT_ATTRIBUTES * NativeAttribs,
51 IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL)
52 {
53 NativeAttribs->Length = sizeof(*NativeAttribs);
54 NativeAttribs->ObjectName = NULL;
55 NativeAttribs->RootDirectory = NULL;
56 NativeAttribs->Attributes = 0;
57 NativeAttribs->SecurityQualityOfService = NULL;
58
59
60 if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
61 {
62 NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
63
64 if(Ros32Attribs->bInheritHandle)
65 {
66 NativeAttribs->Attributes |= OBJ_INHERIT;
67 }
68 }
69 else
70 {
71 NativeAttribs->SecurityDescriptor = NULL;
72 }
73 }
74
75 VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed(OUT OBJECT_ATTRIBUTES * NativeAttribs,
76 IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL,
77 OUT UNICODE_STRING * NativeName OPTIONAL,
78 IN WCHAR * Ros32Name OPTIONAL,
79 IN HANDLE Ros32NameRoot OPTIONAL)
80 {
81 if(!NativeAttribs) return;
82
83 RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
84
85 if(Ros32Name != NULL && NativeName != NULL)
86 {
87 RtlInitUnicodeString(NativeName, Ros32Name);
88
89 NativeAttribs->ObjectName = NativeName;
90 NativeAttribs->RootDirectory = Ros32NameRoot;
91 NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
92 }
93 }
94
95
96 /*
97 * @implemented
98 */
99 BOOL STDCALL CreateProcessA(LPCSTR lpApplicationName,
100 LPSTR lpCommandLine,
101 LPSECURITY_ATTRIBUTES lpProcessAttributes,
102 LPSECURITY_ATTRIBUTES lpThreadAttributes,
103 BOOL bInheritHandles,
104 DWORD dwCreationFlags,
105 LPVOID lpEnvironment,
106 LPCSTR lpCurrentDirectory,
107 LPSTARTUPINFOA lpStartupInfo,
108 LPPROCESS_INFORMATION lpProcessInformation)
109 /*
110 * FUNCTION: The CreateProcess function creates a new process and its
111 * primary thread. The new process executes the specified executable file
112 * ARGUMENTS:
113 *
114 * lpApplicationName = Pointer to name of executable module
115 * lpCommandLine = Pointer to command line string
116 * lpProcessAttributes = Process security attributes
117 * lpThreadAttributes = Thread security attributes
118 * bInheritHandles = Handle inheritance flag
119 * dwCreationFlags = Creation flags
120 * lpEnvironment = Pointer to new environment block
121 * lpCurrentDirectory = Pointer to current directory name
122 * lpStartupInfo = Pointer to startup info
123 * lpProcessInformation = Pointer to process information
124 */
125 {
126 UNICODE_STRING wstrApplicationName;
127 UNICODE_STRING wstrCurrentDirectory;
128 UNICODE_STRING wstrCommandLine;
129 UNICODE_STRING wstrReserved;
130 UNICODE_STRING wstrDesktop;
131 UNICODE_STRING wstrTitle;
132 UNICODE_STRING wstrEnvVar;
133 ANSI_STRING strApplicationName;
134 ANSI_STRING strCurrentDirectory;
135 ANSI_STRING strCommandLine;
136 ANSI_STRING strReserved;
137 ANSI_STRING strDesktop;
138 ANSI_STRING strTitle;
139 BOOL bRetVal;
140 STARTUPINFOW wsiStartupInfo;
141
142 NTSTATUS STDCALL_FUNC (*pTrue)(UNICODE_STRING *,
143 ANSI_STRING *,
144 BOOLEAN);
145
146 ULONG STDCALL_FUNC (*pRtlMbStringToUnicodeSize)(ANSI_STRING *);
147
148 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
149 "lpStartupInfo %x, lpProcessInformation %x\n",
150 dwCreationFlags, lpEnvironment, lpCurrentDirectory,
151 lpStartupInfo, lpProcessInformation);
152
153 /* multibyte strings are ANSI */
154 if(bIsFileApiAnsi)
155 {
156 pTrue = RtlAnsiStringToUnicodeString;
157 pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize;
158 }
159 /* multibyte strings are OEM */
160 else
161 {
162 pTrue = RtlOemStringToUnicodeString;
163 pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize;
164 }
165
166 /* invalid parameter */
167 if(lpStartupInfo == NULL)
168 {
169 SetLastError(ERROR_INVALID_PARAMETER);
170 return FALSE;
171 }
172
173 /* convert the environment */
174 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
175 {
176 PCHAR pcScan;
177 SIZE_T nEnvLen = 0;
178 ANSI_STRING strEnvVar;
179 NTSTATUS Status;
180
181 /* scan the environment to calculate its Unicode size */
182 pcScan = lpEnvironment;
183 do
184 {
185 pcScan += strlen(pcScan) + 1;
186 }
187 while (*pcScan);
188
189 nEnvLen = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
190
191 /* environment too large */
192 if(nEnvLen > ~((USHORT)0))
193 {
194 SetLastError(ERROR_OUTOFMEMORY);
195 return FALSE;
196 }
197
198 strEnvVar.Buffer = lpEnvironment;
199 strEnvVar.MaximumLength = strEnvVar.Length = nEnvLen;
200
201 Status = K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, TRUE);
202
203 /* failure */
204 if (!NT_SUCCESS(Status))
205 {
206 SetLastError(ERROR_OUTOFMEMORY);
207 return FALSE;
208 }
209 }
210
211
212 /* convert the strings */
213 RtlInitAnsiString(&strCommandLine, lpCommandLine);
214 RtlInitAnsiString(&strApplicationName, (LPSTR)lpApplicationName);
215 RtlInitAnsiString(&strCurrentDirectory, (LPSTR)lpCurrentDirectory);
216 RtlInitAnsiString(&strReserved, (LPSTR)lpStartupInfo->lpReserved);
217 RtlInitAnsiString(&strDesktop, (LPSTR)lpStartupInfo->lpDesktop);
218 RtlInitAnsiString(&strTitle, (LPSTR)lpStartupInfo->lpTitle);
219
220 K32MbStrToWcStr(pTrue, &wstrCommandLine, &strCommandLine, TRUE);
221 K32MbStrToWcStr(pTrue, &wstrApplicationName, &strApplicationName, TRUE);
222 K32MbStrToWcStr(pTrue, &wstrCurrentDirectory, &strCurrentDirectory, TRUE);
223 K32MbStrToWcStr(pTrue, &wstrReserved, &strReserved, TRUE);
224 K32MbStrToWcStr(pTrue, &wstrDesktop, &strDesktop, TRUE);
225 K32MbStrToWcStr(pTrue, &wstrTitle, &strTitle, TRUE);
226
227 /* convert the startup information */
228 memcpy(&wsiStartupInfo, lpStartupInfo, sizeof(wsiStartupInfo));
229
230 wsiStartupInfo.lpReserved = wstrReserved.Buffer;
231 wsiStartupInfo.lpDesktop = wstrDesktop.Buffer;
232 wsiStartupInfo.lpTitle = wstrTitle.Buffer;
233
234 DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName);
235 DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine);
236 DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory);
237 DPRINT("wstrReserved %wZ\n", &wstrReserved);
238 DPRINT("wstrDesktop %wZ\n", &wstrDesktop);
239 DPRINT("wstrTitle %wZ\n", &wstrTitle);
240
241 DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName.Buffer);
242 DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine.Buffer);
243 DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory.Buffer);
244 DPRINT("wstrReserved.Buffer %p\n", wstrReserved.Buffer);
245 DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop.Buffer);
246 DPRINT("wstrTitle.Buffer %p\n", wstrTitle.Buffer);
247
248 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA));
249 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW));
250
251 /* call the Unicode function */
252 bRetVal = CreateProcessW(wstrApplicationName.Buffer,
253 wstrCommandLine.Buffer,
254 lpProcessAttributes,
255 lpThreadAttributes,
256 bInheritHandles,
257 dwCreationFlags,
258 !lpEnvironment || (dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ? lpEnvironment : wstrEnvVar.Buffer,
259 wstrCurrentDirectory.Buffer,
260 &wsiStartupInfo,
261 lpProcessInformation);
262
263 RtlFreeUnicodeString(&wstrApplicationName);
264 RtlFreeUnicodeString(&wstrCommandLine);
265 RtlFreeUnicodeString(&wstrCurrentDirectory);
266 RtlFreeUnicodeString(&wstrReserved);
267 RtlFreeUnicodeString(&wstrDesktop);
268 RtlFreeUnicodeString(&wstrTitle);
269
270 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
271 {
272 RtlFreeUnicodeString(&wstrEnvVar);
273 }
274
275 return bRetVal;
276 }
277
278
279 static EXCEPTION_DISPOSITION __cdecl
280 _except_handler(EXCEPTION_RECORD *ExceptionRecord,
281 void * EstablisherFrame,
282 CONTEXT *ContextRecord,
283 void * DispatcherContext)
284 {
285 EXCEPTION_POINTERS ExceptionInfo;
286 EXCEPTION_DISPOSITION ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
287
288 ExceptionInfo.ExceptionRecord = ExceptionRecord;
289 ExceptionInfo.ContextRecord = ContextRecord;
290
291 if (GlobalTopLevelExceptionFilter != NULL)
292 {
293 _SEH_TRY
294 {
295 ExceptionDisposition = GlobalTopLevelExceptionFilter(&ExceptionInfo);
296 }
297 _SEH_HANDLE
298 {
299 ExceptionDisposition = UnhandledExceptionFilter(&ExceptionInfo);
300 }
301 _SEH_END;
302 }
303
304 if (ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER)
305 ExitProcess(ExceptionRecord->ExceptionCode);
306
307 /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
308 if (ExceptionDisposition == EXCEPTION_CONTINUE_EXECUTION)
309 {
310 return ExceptionContinueExecution;
311 }
312 else if (ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH)
313 {
314 return ExceptionContinueSearch;
315 }
316
317 return -1; /* unknown return from UnhandledExceptionFilter */
318 }
319
320
321 VOID STDCALL
322 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
323 DWORD lpParameter)
324 {
325 UINT uExitCode = 0;
326
327 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
328
329 __try1(_except_handler)
330 {
331 uExitCode = (lpStartAddress)((PVOID)lpParameter);
332 } __except1
333
334 ExitProcess(uExitCode);
335 }
336
337
338 HANDLE STDCALL KlCreateFirstThread(HANDLE ProcessHandle,
339 LPSECURITY_ATTRIBUTES lpThreadAttributes,
340 PSECTION_IMAGE_INFORMATION Sii,
341 LPTHREAD_START_ROUTINE lpStartAddress,
342 DWORD dwCreationFlags,
343 LPDWORD lpThreadId)
344 {
345 OBJECT_ATTRIBUTES oaThreadAttribs;
346 CLIENT_ID cidClientId;
347 PVOID pTrueStartAddress;
348 NTSTATUS nErrCode;
349 HANDLE hThread;
350
351 /* convert the thread attributes */
352 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
353
354 /* native image */
355 if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
356 {
357 pTrueStartAddress = (PVOID)BaseProcessStart;
358 }
359 /* Win32 image */
360 else
361 {
362 pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
363 }
364
365 DPRINT("RtlRosCreateUserThreadVa\n"
366 "(\n"
367 " ProcessHandle %p,\n"
368 " ObjectAttributes %p,\n"
369 " CreateSuspended %d,\n"
370 " StackZeroBits %d,\n"
371 " StackReserve %lu,\n"
372 " StackCommit %lu,\n"
373 " StartAddress %p,\n"
374 " ThreadHandle %p,\n"
375 " ClientId %p,\n"
376 " ParameterCount %u,\n"
377 " Parameters[0] %p,\n"
378 " Parameters[1] %p\n"
379 ")\n",
380 ProcessHandle,
381 &oaThreadAttribs,
382 dwCreationFlags & CREATE_SUSPENDED,
383 0,
384 Sii->StackReserve,
385 Sii->StackCommit,
386 pTrueStartAddress,
387 &hThread,
388 &cidClientId,
389 2,
390 lpStartAddress,
391 PEB_BASE);
392
393 /* create the first thread */
394 nErrCode = RtlRosCreateUserThreadVa(ProcessHandle,
395 &oaThreadAttribs,
396 dwCreationFlags & CREATE_SUSPENDED,
397 0,
398 &(Sii->StackReserve),
399 &(Sii->StackCommit),
400 pTrueStartAddress,
401 &hThread,
402 &cidClientId,
403 2,
404 (ULONG_PTR)lpStartAddress,
405 (ULONG_PTR)PEB_BASE);
406 /* failure */
407 if(!NT_SUCCESS(nErrCode))
408 {
409 SetLastErrorByStatus(nErrCode);
410 return NULL;
411 }
412
413 DPRINT("StackReserve %p\n"
414 "StackCommit %p\n"
415 "ThreadHandle %p\n"
416 "ClientId.UniqueThread %p\n",
417 Sii->StackReserve,
418 Sii->StackCommit,
419 hThread,
420 cidClientId.UniqueThread);
421
422 /* success */
423 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
424 return hThread;
425 }
426
427 HANDLE KlMapFile(LPCWSTR lpApplicationName)
428 {
429 HANDLE hFile;
430 IO_STATUS_BLOCK IoStatusBlock;
431 UNICODE_STRING ApplicationNameString;
432 OBJECT_ATTRIBUTES ObjectAttributes;
433 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
434 NTSTATUS Status;
435 HANDLE hSection;
436
437 hFile = NULL;
438
439 /*
440 * Find the application name
441 */
442
443 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
444 &ApplicationNameString,
445 NULL,
446 NULL))
447 return NULL;
448
449 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
450
451 InitializeObjectAttributes(&ObjectAttributes,
452 &ApplicationNameString,
453 OBJ_CASE_INSENSITIVE,
454 NULL,
455 SecurityDescriptor);
456
457 /*
458 * Try to open the executable
459 */
460
461 Status = NtOpenFile(&hFile,
462 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
463 &ObjectAttributes,
464 &IoStatusBlock,
465 FILE_SHARE_DELETE|FILE_SHARE_READ,
466 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
467
468 RtlFreeUnicodeString (&ApplicationNameString);
469
470 if (!NT_SUCCESS(Status))
471 {
472 DPRINT("Failed to open file\n");
473 SetLastErrorByStatus (Status);
474 return(NULL);
475 }
476
477 Status = NtCreateSection(&hSection,
478 SECTION_ALL_ACCESS,
479 NULL,
480 NULL,
481 PAGE_EXECUTE,
482 SEC_IMAGE,
483 hFile);
484 NtClose(hFile);
485
486 if (!NT_SUCCESS(Status))
487 {
488 DPRINT("Failed to create section\n");
489 SetLastErrorByStatus (Status);
490 return(NULL);
491 }
492
493 return(hSection);
494 }
495
496 static NTSTATUS KlInitPeb(HANDLE ProcessHandle,
497 PRTL_USER_PROCESS_PARAMETERS Ppb,
498 PVOID * ImageBaseAddress,
499 ULONG ImageSubSystem)
500 {
501 NTSTATUS Status;
502 PVOID PpbBase;
503 ULONG PpbSize;
504 ULONG BytesWritten;
505 ULONG Offset;
506 PVOID ParentEnv = NULL;
507 PVOID EnvPtr = NULL;
508 PWCHAR ptr;
509 ULONG EnvSize = 0, EnvSize1 = 0;
510
511 /* create the Environment */
512 if (Ppb->Environment != NULL)
513 {
514 ParentEnv = Ppb->Environment;
515 ptr = ParentEnv;
516 while (*ptr)
517 {
518 while(*ptr++);
519 }
520 ptr++;
521 EnvSize = (PVOID)ptr - ParentEnv;
522 }
523 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
524 {
525 MEMORY_BASIC_INFORMATION MemInfo;
526 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
527
528 Status = NtQueryVirtualMemory (NtCurrentProcess (),
529 ParentEnv,
530 MemoryBasicInformation,
531 &MemInfo,
532 sizeof(MEMORY_BASIC_INFORMATION),
533 NULL);
534 if (!NT_SUCCESS(Status))
535 {
536 return Status;
537 }
538 EnvSize = MemInfo.RegionSize;
539 }
540 DPRINT("EnvironmentSize %ld\n", EnvSize);
541
542 /* allocate and initialize new environment block */
543 if (EnvSize != 0)
544 {
545 EnvSize1 = EnvSize;
546 Status = NtAllocateVirtualMemory(ProcessHandle,
547 &EnvPtr,
548 0,
549 &EnvSize1,
550 MEM_RESERVE | MEM_COMMIT,
551 PAGE_READWRITE);
552 if (!NT_SUCCESS(Status))
553 {
554 return(Status);
555 }
556
557 NtWriteVirtualMemory(ProcessHandle,
558 EnvPtr,
559 ParentEnv,
560 EnvSize,
561 &BytesWritten);
562 }
563
564 /* create the PPB */
565 PpbBase = NULL;
566 PpbSize = Ppb->AllocationSize;
567 Status = NtAllocateVirtualMemory(ProcessHandle,
568 &PpbBase,
569 0,
570 &PpbSize,
571 MEM_RESERVE | MEM_COMMIT,
572 PAGE_READWRITE);
573 if (!NT_SUCCESS(Status))
574 {
575 return(Status);
576 }
577
578 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
579 NtWriteVirtualMemory(ProcessHandle,
580 PpbBase,
581 Ppb,
582 Ppb->AllocationSize,
583 &BytesWritten);
584
585 /* write pointer to environment */
586 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
587 NtWriteVirtualMemory(ProcessHandle,
588 (PVOID)(PpbBase + Offset),
589 &EnvPtr,
590 sizeof(EnvPtr),
591 &BytesWritten);
592
593 /* write pointer to process parameter block */
594 Offset = FIELD_OFFSET(PEB, ProcessParameters);
595 NtWriteVirtualMemory(ProcessHandle,
596 (PVOID)(PEB_BASE + Offset),
597 &PpbBase,
598 sizeof(PpbBase),
599 &BytesWritten);
600
601 /* Write image subsystem */
602 Offset = FIELD_OFFSET(PEB, ImageSubSystem);
603 NtWriteVirtualMemory(ProcessHandle,
604 (PVOID)(PEB_BASE + Offset),
605 &ImageSubSystem,
606 sizeof(ImageSubSystem),
607 &BytesWritten);
608
609 /* Read image base address. */
610 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
611 NtReadVirtualMemory(ProcessHandle,
612 (PVOID)(PEB_BASE + Offset),
613 ImageBaseAddress,
614 sizeof(PVOID),
615 &BytesWritten);
616
617 return(STATUS_SUCCESS);
618 }
619
620
621 /*************************************************************************
622 * GetFileName
623 *
624 * Helper for CreateProcessW: retrieve the file name to load from the
625 * app name and command line. Store the file name in buffer, and
626 * return a possibly modified command line.
627 *
628 * FIXME: use CurDir to search for the executable file in the new working directory
629 */
630 static LPWSTR FASTCALL
631 GetFileName(LPCWSTR CurDir, LPCWSTR AppName, LPWSTR CmdLine, LPWSTR Buffer,
632 unsigned BufLen)
633 {
634 WCHAR *Name, *Pos, *Ret = NULL;
635 const WCHAR *p;
636
637 /* if we have an app name, everything is easy */
638
639 if (NULL != AppName)
640 {
641 /* use the unmodified app name as file name */
642 wcsncpy(Buffer, AppName, BufLen );
643 Ret = CmdLine;
644 if (NULL == Ret || L'\0' == CmdLine[0])
645 {
646 /* no command-line, create one */
647 Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName) + 3) * sizeof(WCHAR));
648 if (NULL != Ret)
649 {
650 Ret[0] = L'"';
651 wcscpy(Ret + 1, AppName);
652 wcscat(Ret, L"\"");
653 }
654 }
655 return Ret;
656 }
657
658 if (NULL == CmdLine)
659 {
660 SetLastError(ERROR_INVALID_PARAMETER);
661 return NULL;
662 }
663
664 /* first check for a quoted file name */
665 if (L'"' == CmdLine[0] && NULL != (p = wcschr(CmdLine + 1, L'"')))
666 {
667 int Len = p - CmdLine - 1;
668 /* extract the quoted portion as file name */
669 Name = RtlAllocateHeap(GetProcessHeap(), 0, (Len + 1) * sizeof(WCHAR));
670 if (NULL == Name)
671 {
672 return NULL;
673 }
674 memcpy(Name, CmdLine + 1, Len * sizeof(WCHAR));
675 Name[Len] = L'\0';
676
677 if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
678 {
679 Ret = CmdLine; /* no change necessary */
680 }
681
682 RtlFreeHeap(GetProcessHeap(), 0, Name);
683 return Ret;
684 }
685
686 /* now try the command-line word by word */
687 Name = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 1) * sizeof(WCHAR));
688 if (NULL == Name)
689 {
690 return NULL;
691 }
692 Pos = Name;
693 p = CmdLine;
694
695 while (L'\0' != *p)
696 {
697 do
698 {
699 *Pos++ = *p++;
700 }
701 while (L'\0' != *p && L' ' != *p);
702 *Pos = 0;
703 if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
704 {
705 Ret = CmdLine;
706 break;
707 }
708 }
709
710 if (NULL == Ret || NULL == wcschr(Name, L' '))
711 {
712 RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
713 return Ret;
714 }
715
716 /* now build a new command-line with quotes */
717 Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 3) * sizeof(WCHAR));
718 if (NULL == Ret)
719 {
720 RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
721 return NULL;
722 }
723 Ret[0] = L'"';
724 wcscpy(Ret + 1, Name);
725 wcscat(Ret, L"\"");
726 wcscat(Ret, p);
727
728 RtlFreeHeap(GetProcessHeap(), 0, Name);
729 return Ret;
730 }
731
732
733 /*
734 * @implemented
735 */
736 BOOL STDCALL
737 CreateProcessW(LPCWSTR lpApplicationName,
738 LPWSTR lpCommandLine,
739 LPSECURITY_ATTRIBUTES lpProcessAttributes,
740 LPSECURITY_ATTRIBUTES lpThreadAttributes,
741 BOOL bInheritHandles,
742 DWORD dwCreationFlags,
743 LPVOID lpEnvironment,
744 LPCWSTR lpCurrentDirectory,
745 LPSTARTUPINFOW lpStartupInfo,
746 LPPROCESS_INFORMATION lpProcessInformation)
747 {
748 HANDLE hSection, hProcess, hThread;
749 NTSTATUS Status;
750 WCHAR ImagePathName[256];
751 UNICODE_STRING ImagePathName_U;
752 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
753 ULONG retlen;
754 PRTL_USER_PROCESS_PARAMETERS Ppb;
755 UNICODE_STRING CommandLine_U;
756 CSRSS_API_REQUEST CsrRequest;
757 CSRSS_API_REPLY CsrReply;
758 PWCHAR s, e;
759 ULONG i;
760 UNICODE_STRING CurrentDirectory_U;
761 SECTION_IMAGE_INFORMATION Sii;
762 WCHAR TempCurrentDirectoryW[256];
763 WCHAR TempApplicationNameW[256];
764 WCHAR TempCommandLineNameW[256];
765 UNICODE_STRING RuntimeInfo_U;
766 PVOID ImageBaseAddress;
767 BOOL InputSet, OutputSet, ErrorSet;
768 BOOL InputDup = FALSE, OutputDup = FALSE, ErrorDup = FALSE;
769 WCHAR Name[MAX_PATH];
770 WCHAR *TidyCmdLine;
771 BOOL IsBatchFile = FALSE;
772 PROCESS_PRIORITY_CLASS PriorityClass;
773 OBJECT_ATTRIBUTES ProcObjectAttributes;
774 ULONG ProcAttributes = 0;
775 PVOID ProcSecurity = NULL;
776
777 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
778 lpApplicationName, lpCommandLine);
779
780 TidyCmdLine = GetFileName(lpCurrentDirectory, lpApplicationName, lpCommandLine, Name,
781 sizeof(Name) / sizeof(WCHAR));
782 if (NULL == TidyCmdLine)
783 {
784 return FALSE;
785 }
786 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine);
787
788 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
789 {
790 wcscpy (TempApplicationNameW, lpApplicationName);
791 i = wcslen(TempApplicationNameW);
792 if (TempApplicationNameW[i - 1] == L'.')
793 {
794 TempApplicationNameW[i - 1] = 0;
795 }
796 else
797 {
798 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
799 if (s == NULL)
800 {
801 s = TempApplicationNameW;
802 }
803 else
804 {
805 s++;
806 }
807 e = wcsrchr(s, L'.');
808 if (e == NULL)
809 {
810 wcscat(s, L".exe");
811 e = wcsrchr(s, L'.');
812 }
813 }
814 }
815 else if (L'"' == TidyCmdLine[0])
816 {
817 wcscpy(TempApplicationNameW, TidyCmdLine + 1);
818 s = wcschr(TempApplicationNameW, L'"');
819 if (NULL == s)
820 {
821 return FALSE;
822 }
823 *s = L'\0';
824 }
825 else
826 {
827 wcscpy(TempApplicationNameW, TidyCmdLine);
828 s = wcschr(TempApplicationNameW, L' ');
829 if (NULL != s)
830 {
831 *s = L'\0';
832 }
833 }
834 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
835 if (NULL == s)
836 {
837 s = TempApplicationNameW;
838 }
839 s = wcsrchr(s, L'.');
840 if (NULL == s)
841 {
842 wcscat(TempApplicationNameW, L".exe");
843 }
844
845 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
846 {
847 return FALSE;
848 }
849
850 e = wcsrchr(s, L'.');
851 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
852 {
853 // the command is a batch file
854 IsBatchFile = TRUE;
855 if (lpApplicationName != NULL && lpApplicationName[0])
856 {
857 // FIXME: use COMSPEC for the command interpreter
858 wcscpy(TempCommandLineNameW, L"cmd /c ");
859 wcscat(TempCommandLineNameW, lpApplicationName);
860 lpCommandLine = TempCommandLineNameW;
861 wcscpy(TempApplicationNameW, L"cmd.exe");
862 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
863 {
864 return FALSE;
865 }
866 }
867 else
868 {
869 return FALSE;
870 }
871 }
872
873 /*
874 * Process the application name and command line
875 */
876 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
877 RtlInitUnicodeString(&CommandLine_U, IsBatchFile ? lpCommandLine : TidyCmdLine);
878
879 DPRINT("ImagePathName_U '%S'\n", ImagePathName_U.Buffer);
880 DPRINT("lpCommandLine '%S'\n", lpCommandLine);
881 DPRINT("TidyCmdLine '%S'\n", TidyCmdLine);
882
883 /* Initialize the current directory string */
884 if (lpCurrentDirectory != NULL)
885 {
886 RtlInitUnicodeString(&CurrentDirectory_U,
887 lpCurrentDirectory);
888 }
889 else
890 {
891 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
892 RtlInitUnicodeString(&CurrentDirectory_U,
893 TempCurrentDirectoryW);
894 }
895
896 /*
897 * Create a section for the executable
898 */
899
900 hSection = KlMapFile (ImagePathName);
901 if (hSection == NULL)
902 {
903 /////////////////////////////////////////
904 /*
905 * Inspect the image to determine executable flavour
906 */
907 IO_STATUS_BLOCK IoStatusBlock;
908 UNICODE_STRING ApplicationNameString;
909 OBJECT_ATTRIBUTES ObjectAttributes;
910 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
911 IMAGE_DOS_HEADER DosHeader;
912 IO_STATUS_BLOCK Iosb;
913 LARGE_INTEGER Offset;
914 HANDLE hFile = NULL;
915 DPRINT("Inspecting Image Header for image type id\n");
916
917 // Find the application name
918 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
919 &ApplicationNameString, NULL, NULL))
920 {
921 return FALSE;
922 }
923 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
924
925 InitializeObjectAttributes(&ObjectAttributes,
926 &ApplicationNameString,
927 OBJ_CASE_INSENSITIVE,
928 NULL,
929 SecurityDescriptor);
930
931 // Try to open the executable
932 Status = NtOpenFile(&hFile,
933 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
934 &ObjectAttributes,
935 &IoStatusBlock,
936 FILE_SHARE_DELETE|FILE_SHARE_READ,
937 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
938
939 RtlFreeUnicodeString(&ApplicationNameString);
940
941 if (!NT_SUCCESS(Status))
942 {
943 DPRINT("Failed to open file\n");
944 SetLastErrorByStatus(Status);
945 return FALSE;
946 }
947
948 // Read the dos header
949 Offset.QuadPart = 0;
950 Status = ZwReadFile(hFile,
951 NULL,
952 NULL,
953 NULL,
954 &Iosb,
955 &DosHeader,
956 sizeof(DosHeader),
957 &Offset,
958 0);
959
960 if (!NT_SUCCESS(Status))
961 {
962 DPRINT("Failed to read from file\n");
963 SetLastErrorByStatus(Status);
964 return FALSE;
965 }
966 if (Iosb.Information != sizeof(DosHeader))
967 {
968 DPRINT("Failed to read dos header from file\n");
969 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
970 return FALSE;
971 }
972
973 // Check the DOS signature
974 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
975 {
976 DPRINT("Failed dos magic check\n");
977 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
978 return FALSE;
979 }
980 NtClose(hFile);
981
982 DPRINT("Launching VDM...\n");
983 return CreateProcessW(L"ntvdm.exe",
984 (LPWSTR)lpApplicationName,
985 lpProcessAttributes,
986 lpThreadAttributes,
987 bInheritHandles,
988 dwCreationFlags,
989 lpEnvironment,
990 lpCurrentDirectory,
991 lpStartupInfo,
992 lpProcessInformation);
993 }
994 /////////////////////////////////////////
995
996 /*
997 * Get some information about the executable
998 */
999 Status = ZwQuerySection(hSection,
1000 SectionImageInformation,
1001 &Sii,
1002 sizeof(Sii),
1003 &i);
1004 if (! NT_SUCCESS(Status))
1005 {
1006 NtClose(hSection);
1007 DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status);
1008 SetLastErrorByStatus(Status);
1009 return FALSE;
1010 }
1011
1012 if (0 != (Sii.Characteristics & IMAGE_FILE_DLL))
1013 {
1014 NtClose(hSection);
1015 DPRINT("Can't execute a DLL\n");
1016 SetLastError(ERROR_BAD_EXE_FORMAT);
1017 return FALSE;
1018 }
1019
1020 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != Sii.Subsystem
1021 && IMAGE_SUBSYSTEM_WINDOWS_CUI != Sii.Subsystem)
1022 {
1023 NtClose(hSection);
1024 DPRINT("Invalid subsystem %d\n", Sii.Subsystem);
1025 SetLastError(ERROR_CHILD_NOT_COMPLETE);
1026 return FALSE;
1027 }
1028
1029 /*
1030 * Initialize the process object attributes
1031 */
1032
1033 if(lpProcessAttributes != NULL)
1034 {
1035 if(lpProcessAttributes->bInheritHandle)
1036 {
1037 ProcAttributes |= OBJ_INHERIT;
1038 }
1039 ProcSecurity = lpProcessAttributes->lpSecurityDescriptor;
1040 }
1041
1042 InitializeObjectAttributes(&ProcObjectAttributes,
1043 NULL,
1044 ProcAttributes,
1045 NULL,
1046 ProcSecurity);
1047 /*
1048 * initialize the process priority class structure
1049 */
1050 PriorityClass.Foreground = FALSE;
1051
1052 if(dwCreationFlags & IDLE_PRIORITY_CLASS)
1053 {
1054 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
1055 }
1056 else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
1057 {
1058 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
1059 }
1060 else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
1061 {
1062 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
1063 }
1064 else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
1065 {
1066 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
1067 }
1068 else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
1069 {
1070 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
1071 }
1072 else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
1073 {
1074 /* FIXME - This is a privileged operation. If we don't have the privilege we should
1075 rather use PROCESS_PRIORITY_CLASS_HIGH. */
1076 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
1077 }
1078 else
1079 {
1080 /* FIXME - what to do in this case? */
1081 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
1082 }
1083
1084 /*
1085 * Create a new process
1086 */
1087 Status = NtCreateProcess(&hProcess,
1088 PROCESS_ALL_ACCESS,
1089 &ProcObjectAttributes,
1090 NtCurrentProcess(),
1091 bInheritHandles,
1092 hSection,
1093 NULL,
1094 NULL);
1095 /* FIXME - handle failure!!!!! */
1096
1097 Status = NtSetInformationProcess(hProcess,
1098 ProcessPriorityClass,
1099 &PriorityClass,
1100 sizeof(PROCESS_PRIORITY_CLASS));
1101 /* FIXME - handle failure!!!!! */
1102
1103 if (lpStartupInfo)
1104 {
1105 if (lpStartupInfo->lpReserved2)
1106 {
1107 /* FIXME:
1108 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1109 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1110 * If is possible that this function overwrite the last information in runtimeinfo
1111 * with the null terminator for the unicode string.
1112 */
1113 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
1114 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
1115 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
1116 }
1117 }
1118
1119 /*
1120 * Create the PPB
1121 */
1122 RtlCreateProcessParameters(&Ppb,
1123 &ImagePathName_U,
1124 NULL,
1125 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
1126 &CommandLine_U,
1127 lpEnvironment,
1128 NULL,
1129 NULL,
1130 NULL,
1131 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
1132
1133 if (lpStartupInfo && lpStartupInfo->lpReserved2)
1134 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
1135
1136
1137 /*
1138 * Translate some handles for the new process
1139 */
1140 if (Ppb->CurrentDirectoryHandle)
1141 {
1142 Status = NtDuplicateObject (NtCurrentProcess(),
1143 Ppb->CurrentDirectoryHandle,
1144 hProcess,
1145 &Ppb->CurrentDirectoryHandle,
1146 0,
1147 TRUE,
1148 DUPLICATE_SAME_ACCESS);
1149 /* FIXME - handle failure!!!!! */
1150 }
1151
1152 /*
1153 * Close the section
1154 */
1155 NtClose(hSection);
1156
1157 /*
1158 * Get some information about the process
1159 */
1160 NtQueryInformationProcess(hProcess,
1161 ProcessBasicInformation,
1162 &ProcessBasicInfo,
1163 sizeof(ProcessBasicInfo),
1164 &retlen);
1165 DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
1166 ProcessBasicInfo.UniqueProcessId);
1167 lpProcessInformation->dwProcessId = (DWORD)ProcessBasicInfo.UniqueProcessId;
1168
1169 /*
1170 * Tell the csrss server we are creating a new process
1171 */
1172 CsrRequest.Type = CSRSS_CREATE_PROCESS;
1173 CsrRequest.Data.CreateProcessRequest.NewProcessId =
1174 ProcessBasicInfo.UniqueProcessId;
1175 if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1176 {
1177 /* Do not create a console for GUI applications */
1178 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1179 dwCreationFlags |= DETACHED_PROCESS;
1180 }
1181 else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1182 {
1183 if (NULL == Ppb->hConsole)
1184 {
1185 dwCreationFlags |= CREATE_NEW_CONSOLE;
1186 }
1187 }
1188 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
1189 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
1190 Status = CsrClientCallServer(&CsrRequest,
1191 &CsrReply,
1192 sizeof(CSRSS_API_REQUEST),
1193 sizeof(CSRSS_API_REPLY));
1194 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1195 {
1196 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1197 }
1198
1199 Ppb->hConsole = CsrReply.Data.CreateProcessReply.Console;
1200
1201 InputSet = FALSE;
1202 OutputSet = FALSE;
1203 ErrorSet = FALSE;
1204
1205 /* Set the child console handles */
1206
1207 /* First check if handles were passed in startup info */
1208 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
1209 {
1210 if (lpStartupInfo->hStdInput)
1211 {
1212 Ppb->hStdInput = lpStartupInfo->hStdInput;
1213 InputSet = TRUE;
1214 InputDup = TRUE;
1215 }
1216 if (lpStartupInfo->hStdOutput)
1217 {
1218 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
1219 OutputSet = TRUE;
1220 OutputDup = TRUE;
1221 }
1222 if (lpStartupInfo->hStdError)
1223 {
1224 Ppb->hStdError = lpStartupInfo->hStdError;
1225 ErrorSet = TRUE;
1226 ErrorDup = TRUE;
1227 }
1228 }
1229
1230 /* Check if new console was created, use it for input and output if
1231 not overridden */
1232 if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE)
1233 && NT_SUCCESS(Status) && NT_SUCCESS(CsrReply.Status))
1234 {
1235 if (! InputSet)
1236 {
1237 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1238 InputSet = TRUE;
1239 InputDup = FALSE;
1240 }
1241 if (! OutputSet)
1242 {
1243 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1244 OutputSet = TRUE;
1245 OutputDup = FALSE;
1246 }
1247 if (! ErrorSet)
1248 {
1249 Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
1250 ErrorSet = TRUE;
1251 ErrorDup = FALSE;
1252 }
1253 }
1254
1255 /* Use existing handles otherwise */
1256 if (! InputSet)
1257 {
1258 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
1259 InputDup = TRUE;
1260 }
1261 if (! OutputSet)
1262 {
1263 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
1264 OutputDup = TRUE;
1265 }
1266 if (! ErrorSet)
1267 {
1268 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
1269 ErrorDup = TRUE;
1270 }
1271
1272 /* Now duplicate handles if required */
1273 if (InputDup && Ppb->hStdInput != NULL)
1274 {
1275 if (IsConsoleHandle(Ppb->hStdInput))
1276 {
1277 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1278 }
1279 else
1280 {
1281 DPRINT("Duplicate input handle\n");
1282 Status = NtDuplicateObject (NtCurrentProcess(),
1283 Ppb->hStdInput,
1284 hProcess,
1285 &Ppb->hStdInput,
1286 0,
1287 TRUE,
1288 DUPLICATE_SAME_ACCESS);
1289 if(!NT_SUCCESS(Status))
1290 {
1291 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1292 }
1293 }
1294 }
1295
1296 if (OutputDup && Ppb->hStdOutput != NULL)
1297 {
1298 if (IsConsoleHandle(Ppb->hStdOutput))
1299 {
1300 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1301 }
1302 else
1303 {
1304 DPRINT("Duplicate output handle\n");
1305 Status = NtDuplicateObject (NtCurrentProcess(),
1306 Ppb->hStdOutput,
1307 hProcess,
1308 &Ppb->hStdOutput,
1309 0,
1310 TRUE,
1311 DUPLICATE_SAME_ACCESS);
1312 if(!NT_SUCCESS(Status))
1313 {
1314 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1315 }
1316 }
1317 }
1318
1319 if (ErrorDup && Ppb->hStdError != NULL)
1320 {
1321 if (IsConsoleHandle(Ppb->hStdError))
1322 {
1323 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1324 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1325 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1326 Status = CsrClientCallServer(&CsrRequest,
1327 &CsrReply,
1328 sizeof(CSRSS_API_REQUEST),
1329 sizeof(CSRSS_API_REPLY));
1330 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1331 {
1332 Ppb->hStdError = INVALID_HANDLE_VALUE;
1333 }
1334 else
1335 {
1336 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1337 }
1338 }
1339 else
1340 {
1341 DPRINT("Duplicate error handle\n");
1342 Status = NtDuplicateObject (NtCurrentProcess(),
1343 Ppb->hStdError,
1344 hProcess,
1345 &Ppb->hStdError,
1346 0,
1347 TRUE,
1348 DUPLICATE_SAME_ACCESS);
1349 if(!NT_SUCCESS(Status))
1350 {
1351 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1352 }
1353 }
1354 }
1355
1356 /*
1357 * Initialize some other fields in the PPB
1358 */
1359 if (lpStartupInfo)
1360 {
1361 Ppb->dwFlags = lpStartupInfo->dwFlags;
1362 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1363 {
1364 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1365 }
1366 else
1367 {
1368 Ppb->wShowWindow = SW_SHOWDEFAULT;
1369 }
1370 Ppb->dwX = lpStartupInfo->dwX;
1371 Ppb->dwY = lpStartupInfo->dwY;
1372 Ppb->dwXSize = lpStartupInfo->dwXSize;
1373 Ppb->dwYSize = lpStartupInfo->dwYSize;
1374 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1375 }
1376 else
1377 {
1378 Ppb->Flags = 0;
1379 }
1380
1381 /*
1382 * Create Process Environment Block
1383 */
1384 DPRINT("Creating peb\n");
1385
1386 KlInitPeb(hProcess, Ppb, &ImageBaseAddress, Sii.Subsystem);
1387
1388 RtlDestroyProcessParameters (Ppb);
1389
1390 /*
1391 * Create the thread for the kernel
1392 */
1393 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1394 (PVOID)((ULONG_PTR)ImageBaseAddress + Sii.EntryPoint));
1395 hThread = KlCreateFirstThread(hProcess,
1396 lpThreadAttributes,
1397 &Sii,
1398 (PVOID)((ULONG_PTR)ImageBaseAddress + Sii.EntryPoint),
1399 dwCreationFlags,
1400 &lpProcessInformation->dwThreadId);
1401 if (hThread == NULL)
1402 {
1403 return FALSE;
1404 }
1405
1406 lpProcessInformation->hProcess = hProcess;
1407 lpProcessInformation->hThread = hThread;
1408
1409 return TRUE;
1410 }
1411
1412 /* EOF */