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