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