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