Display module names with the stack trace on unhandled exception (debug)
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.82 2004/05/01 18:09:53 tamlin 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 "../include/debug.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_FUNC (*pTrue)
150 (
151 UNICODE_STRING *,
152 ANSI_STRING *,
153 BOOLEAN
154 );
155
156 ULONG STDCALL_FUNC (*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
315 /*
316 * Private helper function to lookup the module name from a given address.
317 * The address can point to anywhere within the module.
318 */
319 static const char*
320 _module_name_from_addr(const void* addr, char* psz, size_t nChars)
321 {
322 MEMORY_BASIC_INFORMATION mbi;
323 if (VirtualQuery(addr, &mbi, sizeof(mbi)) != sizeof(mbi) ||
324 !GetModuleFileNameA((HMODULE)mbi.AllocationBase, psz, nChars))
325 {
326 psz[0] = '\0';
327 }
328 return psz;
329 }
330
331 static int _except_recursion_trap = 0;
332
333 struct _CONTEXT;
334 struct __EXCEPTION_RECORD;
335
336 static
337 EXCEPTION_DISPOSITION
338 __cdecl
339 _except_handler(
340 struct _EXCEPTION_RECORD *ExceptionRecord,
341 void * EstablisherFrame,
342 struct _CONTEXT *ContextRecord,
343 void * DispatcherContext )
344 {
345 #ifdef _X86_
346 char szMod[128] = "";
347 #endif
348 DPRINT1("Thread terminated abnormally due to unhandled exception\n");
349 DPRINT1("Address:\n");
350 DPRINT1("%8x %s\n",
351 ExceptionRecord->ExceptionAddress,
352 _module_name_from_addr(ExceptionRecord->ExceptionAddress, szMod, sizeof(szMod)));
353
354 #ifdef _X86_
355 {
356 PULONG Frame;
357 DPRINT1("Frames:\n");
358 Frame = (PULONG)((CONTEXT *)ContextRecord)->Ebp;
359 while ((PVOID)Frame[1] != NULL && (PULONG)Frame[1] != (PULONG)0xdeadbeef)
360 {
361 _module_name_from_addr((const void*)Frame[1], szMod, sizeof(szMod));
362 DPRINT1("%8x %s\n", (PVOID)Frame[1], szMod);
363 Frame = (PULONG)Frame[0];
364 }
365 }
366 #endif
367
368 if (3 < ++_except_recursion_trap)
369 {
370 DPRINT1("_except_handler(...) appears to be recursing.\n");
371 DPRINT1("Process HALTED.\n");
372 for (;;)
373 {
374 }
375 }
376
377 if (/* FIXME: */ TRUE) /* Not a service */
378 {
379 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
380 /* ExitProcess(0); */
381 ExitThread(0);
382 }
383 else
384 {
385 DPRINT(" calling ExitThread(0) . . .\n");
386 ExitThread(0);
387 }
388
389 DPRINT1(" We should not get to here !!!\n");
390 /* We should not get to here */
391 return ExceptionContinueSearch;
392 }
393
394 VOID STDCALL
395 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
396 DWORD lpParameter)
397 {
398 UINT uExitCode = 0;
399
400 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
401
402 __try1(_except_handler)
403 {
404 uExitCode = (lpStartAddress)((PVOID)lpParameter);
405 } __except1
406 {
407 }
408
409 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
410
411 ExitThread(uExitCode);
412 }
413
414
415 HANDLE STDCALL KlCreateFirstThread
416 (
417 HANDLE ProcessHandle,
418 LPSECURITY_ATTRIBUTES lpThreadAttributes,
419 PSECTION_IMAGE_INFORMATION Sii,
420 LPTHREAD_START_ROUTINE lpStartAddress,
421 DWORD dwCreationFlags,
422 LPDWORD lpThreadId
423 )
424 {
425 OBJECT_ATTRIBUTES oaThreadAttribs;
426 CLIENT_ID cidClientId;
427 PVOID pTrueStartAddress;
428 NTSTATUS nErrCode;
429 HANDLE hThread;
430
431 /* convert the thread attributes */
432 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
433
434 /* native image */
435 if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
436 pTrueStartAddress = (PVOID)BaseProcessStart;
437 /* Win32 image */
438 else
439 pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
440
441 DPRINT
442 (
443 "RtlRosCreateUserThreadVa\n"
444 "(\n"
445 " ProcessHandle %p,\n"
446 " ObjectAttributes %p,\n"
447 " CreateSuspended %d,\n"
448 " StackZeroBits %d,\n"
449 " StackReserve %lu,\n"
450 " StackCommit %lu,\n"
451 " StartAddress %p,\n"
452 " ThreadHandle %p,\n"
453 " ClientId %p,\n"
454 " ParameterCount %u,\n"
455 " Parameters[0] %p,\n"
456 " Parameters[1] %p\n"
457 ")\n",
458 ProcessHandle,
459 &oaThreadAttribs,
460 dwCreationFlags & CREATE_SUSPENDED,
461 0,
462 Sii->StackReserve,
463 Sii->StackCommit,
464 pTrueStartAddress,
465 &hThread,
466 &cidClientId,
467 2,
468 lpStartAddress,
469 PEB_BASE
470 );
471
472 /* create the first thread */
473 nErrCode = RtlRosCreateUserThreadVa
474 (
475 ProcessHandle,
476 &oaThreadAttribs,
477 dwCreationFlags & CREATE_SUSPENDED,
478 0,
479 &(Sii->StackReserve),
480 &(Sii->StackCommit),
481 pTrueStartAddress,
482 &hThread,
483 &cidClientId,
484 2,
485 (ULONG_PTR)lpStartAddress,
486 (ULONG_PTR)PEB_BASE
487 );
488
489 /* failure */
490 if(!NT_SUCCESS(nErrCode))
491 {
492 SetLastErrorByStatus(nErrCode);
493 return NULL;
494 }
495
496 DPRINT
497 (
498 "StackReserve %p\n"
499 "StackCommit %p\n"
500 "ThreadHandle %p\n"
501 "ClientId.UniqueThread %p\n",
502 Sii->StackReserve,
503 Sii->StackCommit,
504 hThread,
505 cidClientId.UniqueThread
506 );
507
508 /* success */
509 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
510 return hThread;
511 }
512
513 HANDLE KlMapFile(LPCWSTR lpApplicationName)
514 {
515 HANDLE hFile;
516 IO_STATUS_BLOCK IoStatusBlock;
517 UNICODE_STRING ApplicationNameString;
518 OBJECT_ATTRIBUTES ObjectAttributes;
519 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
520 NTSTATUS Status;
521 HANDLE hSection;
522
523 hFile = NULL;
524
525 /*
526 * Find the application name
527 */
528
529 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
530 &ApplicationNameString,
531 NULL,
532 NULL))
533 return NULL;
534
535 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
536
537 InitializeObjectAttributes(&ObjectAttributes,
538 &ApplicationNameString,
539 OBJ_CASE_INSENSITIVE,
540 NULL,
541 SecurityDescriptor);
542
543 /*
544 * Try to open the executable
545 */
546
547 Status = NtOpenFile(&hFile,
548 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
549 &ObjectAttributes,
550 &IoStatusBlock,
551 FILE_SHARE_DELETE|FILE_SHARE_READ,
552 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
553
554 RtlFreeUnicodeString (&ApplicationNameString);
555
556 if (!NT_SUCCESS(Status))
557 {
558 DPRINT("Failed to open file\n");
559 SetLastErrorByStatus (Status);
560 return(NULL);
561 }
562
563 Status = NtCreateSection(&hSection,
564 SECTION_ALL_ACCESS,
565 NULL,
566 NULL,
567 PAGE_EXECUTE,
568 SEC_IMAGE,
569 hFile);
570 NtClose(hFile);
571
572 if (!NT_SUCCESS(Status))
573 {
574 DPRINT("Failed to create section\n");
575 SetLastErrorByStatus (Status);
576 return(NULL);
577 }
578
579 return(hSection);
580 }
581
582 static NTSTATUS KlInitPeb
583 (
584 HANDLE ProcessHandle,
585 PRTL_USER_PROCESS_PARAMETERS Ppb,
586 PVOID * ImageBaseAddress,
587 ULONG ImageSubSystem
588 )
589 {
590 NTSTATUS Status;
591 PVOID PpbBase;
592 ULONG PpbSize;
593 ULONG BytesWritten;
594 ULONG Offset;
595 PVOID ParentEnv = NULL;
596 PVOID EnvPtr = NULL;
597 PWCHAR ptr;
598 ULONG EnvSize = 0, EnvSize1 = 0;
599
600 /* create the Environment */
601 if (Ppb->Environment != NULL)
602 {
603 ParentEnv = Ppb->Environment;
604 ptr = ParentEnv;
605 while (*ptr)
606 {
607 while(*ptr++);
608 }
609 ptr++;
610 EnvSize = (PVOID)ptr - ParentEnv;
611 }
612 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
613 {
614 MEMORY_BASIC_INFORMATION MemInfo;
615 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
616
617 Status = NtQueryVirtualMemory (NtCurrentProcess (),
618 ParentEnv,
619 MemoryBasicInformation,
620 &MemInfo,
621 sizeof(MEMORY_BASIC_INFORMATION),
622 NULL);
623 if (!NT_SUCCESS(Status))
624 {
625 return Status;
626 }
627 EnvSize = MemInfo.RegionSize;
628 }
629 DPRINT("EnvironmentSize %ld\n", EnvSize);
630
631 /* allocate and initialize new environment block */
632 if (EnvSize != 0)
633 {
634 EnvSize1 = EnvSize;
635 Status = NtAllocateVirtualMemory(ProcessHandle,
636 &EnvPtr,
637 0,
638 &EnvSize1,
639 MEM_RESERVE | MEM_COMMIT,
640 PAGE_READWRITE);
641 if (!NT_SUCCESS(Status))
642 {
643 return(Status);
644 }
645
646 NtWriteVirtualMemory(ProcessHandle,
647 EnvPtr,
648 ParentEnv,
649 EnvSize,
650 &BytesWritten);
651 }
652
653 /* create the PPB */
654 PpbBase = NULL;
655 PpbSize = Ppb->AllocationSize;
656 Status = NtAllocateVirtualMemory(ProcessHandle,
657 &PpbBase,
658 0,
659 &PpbSize,
660 MEM_RESERVE | MEM_COMMIT,
661 PAGE_READWRITE);
662 if (!NT_SUCCESS(Status))
663 {
664 return(Status);
665 }
666
667 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
668 NtWriteVirtualMemory(ProcessHandle,
669 PpbBase,
670 Ppb,
671 Ppb->AllocationSize,
672 &BytesWritten);
673
674 /* write pointer to environment */
675 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
676 NtWriteVirtualMemory(ProcessHandle,
677 (PVOID)(PpbBase + Offset),
678 &EnvPtr,
679 sizeof(EnvPtr),
680 &BytesWritten);
681
682 /* write pointer to process parameter block */
683 Offset = FIELD_OFFSET(PEB, ProcessParameters);
684 NtWriteVirtualMemory(ProcessHandle,
685 (PVOID)(PEB_BASE + Offset),
686 &PpbBase,
687 sizeof(PpbBase),
688 &BytesWritten);
689
690 /* Write image subsystem */
691 Offset = FIELD_OFFSET(PEB, ImageSubSystem);
692 NtWriteVirtualMemory(ProcessHandle,
693 (PVOID)(PEB_BASE + Offset),
694 &ImageSubSystem,
695 sizeof(ImageSubSystem),
696 &BytesWritten);
697
698 /* Read image base address. */
699 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
700 NtReadVirtualMemory(ProcessHandle,
701 (PVOID)(PEB_BASE + Offset),
702 ImageBaseAddress,
703 sizeof(PVOID),
704 &BytesWritten);
705
706 return(STATUS_SUCCESS);
707 }
708
709
710 /*************************************************************************
711 * GetFileName
712 *
713 * Helper for CreateProcessW: retrieve the file name to load from the
714 * app name and command line. Store the file name in buffer, and
715 * return a possibly modified command line.
716 *
717 * FIXME: use CurDir to search for the executable file in the new working directory
718 */
719 static LPWSTR FASTCALL
720 GetFileName(LPCWSTR CurDir, LPCWSTR AppName, LPWSTR CmdLine, LPWSTR Buffer,
721 unsigned BufLen)
722 {
723 WCHAR *Name, *Pos, *Ret = NULL;
724 const WCHAR *p;
725
726 /* if we have an app name, everything is easy */
727
728 if (NULL != AppName)
729 {
730 /* use the unmodified app name as file name */
731 wcsncpy(Buffer, AppName, BufLen );
732 Ret = CmdLine;
733 if (NULL == Ret || L'\0' == CmdLine[0])
734 {
735 /* no command-line, create one */
736 Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName) + 3) * sizeof(WCHAR));
737 if (NULL != Ret)
738 {
739 Ret[0] = L'"';
740 wcscpy(Ret + 1, AppName);
741 wcscat(Ret, L"\"");
742 }
743 }
744 return Ret;
745 }
746
747 if (NULL == CmdLine)
748 {
749 SetLastError(ERROR_INVALID_PARAMETER);
750 return NULL;
751 }
752
753 /* first check for a quoted file name */
754 if (L'"' == CmdLine[0] && NULL != (p = wcschr(CmdLine + 1, L'"')))
755 {
756 int Len = p - CmdLine - 1;
757 /* extract the quoted portion as file name */
758 Name = RtlAllocateHeap(GetProcessHeap(), 0, (Len + 1) * sizeof(WCHAR));
759 if (NULL == Name)
760 {
761 return NULL;
762 }
763 memcpy(Name, CmdLine + 1, Len * sizeof(WCHAR));
764 Name[Len] = L'\0';
765
766 if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
767 {
768 Ret = CmdLine; /* no change necessary */
769 }
770
771 RtlFreeHeap(GetProcessHeap(), 0, Name);
772 return Ret;
773 }
774
775 /* now try the command-line word by word */
776 Name = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 1) * sizeof(WCHAR));
777 if (NULL == Name)
778 {
779 return NULL;
780 }
781 Pos = Name;
782 p = CmdLine;
783
784 while (L'\0' != *p)
785 {
786 do
787 {
788 *Pos++ = *p++;
789 }
790 while (L'\0' != *p && L' ' != *p);
791 *Pos = 0;
792 if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
793 {
794 Ret = CmdLine;
795 break;
796 }
797 }
798
799 if (NULL == Ret || NULL == wcschr(Name, L' '))
800 {
801 RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
802 return Ret;
803 }
804
805 /* now build a new command-line with quotes */
806 Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 3) * sizeof(WCHAR));
807 if (NULL == Ret)
808 {
809 RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
810 return NULL;
811 }
812 Ret[0] = L'"';
813 wcscpy(Ret + 1, Name);
814 wcscat(Ret, L"\"");
815 wcscat(Ret, p);
816
817 RtlFreeHeap(GetProcessHeap(), 0, Name);
818 return Ret;
819 }
820
821
822 /*
823 * @implemented
824 */
825 BOOL STDCALL
826 CreateProcessW
827 (
828 LPCWSTR lpApplicationName,
829 LPWSTR lpCommandLine,
830 LPSECURITY_ATTRIBUTES lpProcessAttributes,
831 LPSECURITY_ATTRIBUTES lpThreadAttributes,
832 BOOL bInheritHandles,
833 DWORD dwCreationFlags,
834 LPVOID lpEnvironment,
835 LPCWSTR lpCurrentDirectory,
836 LPSTARTUPINFOW lpStartupInfo,
837 LPPROCESS_INFORMATION lpProcessInformation
838 )
839 {
840 HANDLE hSection, hProcess, hThread;
841 NTSTATUS Status;
842 WCHAR ImagePathName[256];
843 UNICODE_STRING ImagePathName_U;
844 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
845 ULONG retlen;
846 PRTL_USER_PROCESS_PARAMETERS Ppb;
847 UNICODE_STRING CommandLine_U;
848 CSRSS_API_REQUEST CsrRequest;
849 CSRSS_API_REPLY CsrReply;
850 CHAR ImageFileName[8];
851 PWCHAR s, e;
852 ULONG i;
853 UNICODE_STRING CurrentDirectory_U;
854 SECTION_IMAGE_INFORMATION Sii;
855 WCHAR TempCurrentDirectoryW[256];
856 WCHAR TempApplicationNameW[256];
857 WCHAR TempCommandLineNameW[256];
858 UNICODE_STRING RuntimeInfo_U;
859 PVOID ImageBaseAddress;
860 BOOL InputSet, OutputSet, ErrorSet;
861 BOOL InputDup, OutputDup, ErrorDup;
862 WCHAR Name[MAX_PATH];
863 WCHAR *TidyCmdLine;
864
865 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
866 lpApplicationName, lpCommandLine);
867
868 TidyCmdLine = GetFileName(lpCurrentDirectory, lpApplicationName, lpCommandLine, Name,
869 sizeof(Name) / sizeof(WCHAR));
870 if (NULL == TidyCmdLine)
871 {
872 return FALSE;
873 }
874
875 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
876 {
877 wcscpy (TempApplicationNameW, lpApplicationName);
878 i = wcslen(TempApplicationNameW);
879 if (TempApplicationNameW[i - 1] == L'.')
880 {
881 TempApplicationNameW[i - 1] = 0;
882 }
883 else
884 {
885 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
886 if (s == NULL)
887 {
888 s = TempApplicationNameW;
889 }
890 else
891 {
892 s++;
893 }
894 e = wcsrchr(s, L'.');
895 if (e == NULL)
896 {
897 wcscat(s, L".exe");
898 e = wcsrchr(s, L'.');
899 }
900 }
901 }
902 else if (L'"' == TidyCmdLine[0])
903 {
904 wcscpy(TempApplicationNameW, TidyCmdLine + 1);
905 s = wcschr(TempApplicationNameW, L'"');
906 if (NULL == s)
907 {
908 return FALSE;
909 }
910 *s = L'\0';
911 }
912 else
913 {
914 wcscpy(TempApplicationNameW, TidyCmdLine);
915 s = wcschr(TempApplicationNameW, L' ');
916 if (NULL != s)
917 {
918 *s = L'\0';
919 }
920 }
921 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
922 if (NULL == s)
923 {
924 s = TempApplicationNameW;
925 }
926 s = wcsrchr(s, L'.');
927 if (NULL == s)
928 {
929 wcscat(TempApplicationNameW, L".exe");
930 }
931
932 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
933 {
934 return FALSE;
935 }
936
937 e = wcsrchr(s, L'.');
938 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
939 {
940 // the command is a batch file
941 if (lpApplicationName != NULL && lpApplicationName[0])
942 {
943 // FIXME: use COMSPEC for the command interpreter
944 wcscpy(TempCommandLineNameW, L"cmd /c ");
945 wcscat(TempCommandLineNameW, lpApplicationName);
946 lpCommandLine = TempCommandLineNameW;
947 wcscpy(TempApplicationNameW, L"cmd.exe");
948 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
949 {
950 return FALSE;
951 }
952 }
953 else
954 {
955 return FALSE;
956 }
957 }
958
959 /*
960 * Store the image file name for the process
961 */
962 e = wcschr(s, L'.');
963 if (e != NULL)
964 {
965 *e = 0;
966 }
967 for (i = 0; i < 8; i++)
968 {
969 ImageFileName[i] = (CHAR)(s[i]);
970 }
971 if (e != NULL)
972 {
973 *e = '.';
974 }
975
976 /*
977 * Process the application name and command line
978 */
979 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
980 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
981
982 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
983 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
984
985 /* Initialize the current directory string */
986 if (lpCurrentDirectory != NULL)
987 {
988 RtlInitUnicodeString(&CurrentDirectory_U,
989 lpCurrentDirectory);
990 }
991 else
992 {
993 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
994 RtlInitUnicodeString(&CurrentDirectory_U,
995 TempCurrentDirectoryW);
996 }
997
998 /*
999 * Create a section for the executable
1000 */
1001
1002 hSection = KlMapFile (ImagePathName);
1003 if (hSection == NULL)
1004 {
1005 /////////////////////////////////////////
1006 /*
1007 * Inspect the image to determine executable flavour
1008 */
1009 IO_STATUS_BLOCK IoStatusBlock;
1010 UNICODE_STRING ApplicationNameString;
1011 OBJECT_ATTRIBUTES ObjectAttributes;
1012 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
1013 IMAGE_DOS_HEADER DosHeader;
1014 IO_STATUS_BLOCK Iosb;
1015 LARGE_INTEGER Offset;
1016 HANDLE hFile = NULL;
1017
1018 DPRINT("Inspecting Image Header for image type id\n");
1019
1020 // Find the application name
1021 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
1022 &ApplicationNameString, NULL, NULL)) {
1023 return FALSE;
1024 }
1025 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
1026
1027 InitializeObjectAttributes(&ObjectAttributes,
1028 &ApplicationNameString,
1029 OBJ_CASE_INSENSITIVE,
1030 NULL,
1031 SecurityDescriptor);
1032
1033 // Try to open the executable
1034 Status = NtOpenFile(&hFile,
1035 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
1036 &ObjectAttributes,
1037 &IoStatusBlock,
1038 FILE_SHARE_DELETE|FILE_SHARE_READ,
1039 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
1040
1041 RtlFreeUnicodeString(&ApplicationNameString);
1042
1043 if (!NT_SUCCESS(Status)) {
1044 DPRINT("Failed to open file\n");
1045 SetLastErrorByStatus(Status);
1046 return FALSE;
1047 }
1048
1049 // Read the dos header
1050 Offset.QuadPart = 0;
1051 Status = ZwReadFile(hFile,
1052 NULL,
1053 NULL,
1054 NULL,
1055 &Iosb,
1056 &DosHeader,
1057 sizeof(DosHeader),
1058 &Offset,
1059 0);
1060
1061 if (!NT_SUCCESS(Status)) {
1062 DPRINT("Failed to read from file\n");
1063 SetLastErrorByStatus(Status);
1064 return FALSE;
1065 }
1066 if (Iosb.Information != sizeof(DosHeader)) {
1067 DPRINT("Failed to read dos header from file\n");
1068 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
1069 return FALSE;
1070 }
1071
1072 // Check the DOS signature
1073 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
1074 DPRINT("Failed dos magic check\n");
1075 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
1076 return FALSE;
1077 }
1078 NtClose(hFile);
1079
1080 DPRINT("Launching VDM...\n");
1081 return CreateProcessW(L"ntvdm.exe",
1082 (LPWSTR)lpApplicationName,
1083 lpProcessAttributes,
1084 lpThreadAttributes,
1085 bInheritHandles,
1086 dwCreationFlags,
1087 lpEnvironment,
1088 lpCurrentDirectory,
1089 lpStartupInfo,
1090 lpProcessInformation);
1091 }
1092 /////////////////////////////////////////
1093 /*
1094 * Create a new process
1095 */
1096 Status = NtCreateProcess(&hProcess,
1097 PROCESS_ALL_ACCESS,
1098 NULL,
1099 NtCurrentProcess(),
1100 bInheritHandles,
1101 hSection,
1102 NULL,
1103 NULL);
1104 if (lpStartupInfo)
1105 {
1106 if (lpStartupInfo->lpReserved2)
1107 {
1108 /* FIXME:
1109 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
1110 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
1111 * If is possible that this function overwrite the last information in runtimeinfo
1112 * with the null terminator for the unicode string.
1113 */
1114 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
1115 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
1116 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
1117 }
1118 }
1119
1120 /*
1121 * Create the PPB
1122 */
1123 RtlCreateProcessParameters(&Ppb,
1124 &ImagePathName_U,
1125 NULL,
1126 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
1127 &CommandLine_U,
1128 lpEnvironment,
1129 NULL,
1130 NULL,
1131 NULL,
1132 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
1133
1134 if (lpStartupInfo && lpStartupInfo->lpReserved2)
1135 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
1136
1137
1138 /*
1139 * Translate some handles for the new process
1140 */
1141 if (Ppb->CurrentDirectoryHandle)
1142 {
1143 Status = NtDuplicateObject (NtCurrentProcess(),
1144 Ppb->CurrentDirectoryHandle,
1145 hProcess,
1146 &Ppb->CurrentDirectoryHandle,
1147 0,
1148 TRUE,
1149 DUPLICATE_SAME_ACCESS);
1150 }
1151
1152 /*
1153 * Get some information about the executable
1154 */
1155 Status = ZwQuerySection(hSection,
1156 SectionImageInformation,
1157 &Sii,
1158 sizeof(Sii),
1159 &i);
1160 /*
1161 * Close the section
1162 */
1163 NtClose(hSection);
1164
1165 /*
1166 * Get some information about the process
1167 */
1168 NtQueryInformationProcess(hProcess,
1169 ProcessBasicInformation,
1170 &ProcessBasicInfo,
1171 sizeof(ProcessBasicInfo),
1172 &retlen);
1173 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1174 ProcessBasicInfo.UniqueProcessId);
1175 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
1176
1177 /*
1178 * Tell the csrss server we are creating a new process
1179 */
1180 CsrRequest.Type = CSRSS_CREATE_PROCESS;
1181 CsrRequest.Data.CreateProcessRequest.NewProcessId =
1182 ProcessBasicInfo.UniqueProcessId;
1183 if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1184 {
1185 /* Do not create a console for GUI applications */
1186 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1187 dwCreationFlags |= DETACHED_PROCESS;
1188 }
1189 else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1190 {
1191 if (NULL == Ppb->hConsole)
1192 {
1193 dwCreationFlags |= CREATE_NEW_CONSOLE;
1194 }
1195 }
1196 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
1197 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
1198 Status = CsrClientCallServer(&CsrRequest,
1199 &CsrReply,
1200 sizeof(CSRSS_API_REQUEST),
1201 sizeof(CSRSS_API_REPLY));
1202 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1203 {
1204 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1205 }
1206
1207 Ppb->hConsole = CsrReply.Data.CreateProcessReply.Console;
1208
1209 InputSet = FALSE;
1210 OutputSet = FALSE;
1211 ErrorSet = FALSE;
1212
1213 /* Set the child console handles */
1214
1215 /* First check if handles were passed in startup info */
1216 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
1217 {
1218 if (lpStartupInfo->hStdInput)
1219 {
1220 Ppb->hStdInput = lpStartupInfo->hStdInput;
1221 InputSet = TRUE;
1222 InputDup = TRUE;
1223 }
1224 if (lpStartupInfo->hStdOutput)
1225 {
1226 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
1227 OutputSet = TRUE;
1228 OutputDup = TRUE;
1229 }
1230 if (lpStartupInfo->hStdError)
1231 {
1232 Ppb->hStdError = lpStartupInfo->hStdError;
1233 ErrorSet = TRUE;
1234 ErrorDup = TRUE;
1235 }
1236 }
1237
1238 /* Check if new console was created, use it for input and output if
1239 not overridden */
1240 if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE)
1241 && NT_SUCCESS(Status) && NT_SUCCESS(CsrReply.Status))
1242 {
1243 if (! InputSet)
1244 {
1245 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1246 InputSet = TRUE;
1247 InputDup = FALSE;
1248 }
1249 if (! OutputSet)
1250 {
1251 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1252 OutputSet = TRUE;
1253 OutputDup = FALSE;
1254 }
1255 if (! ErrorSet)
1256 {
1257 Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
1258 ErrorSet = TRUE;
1259 ErrorDup = FALSE;
1260 }
1261 }
1262
1263 /* Use existing handles otherwise */
1264 if (! InputSet)
1265 {
1266 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
1267 InputDup = TRUE;
1268 }
1269 if (! OutputSet)
1270 {
1271 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
1272 OutputDup = TRUE;
1273 }
1274 if (! ErrorSet)
1275 {
1276 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
1277 ErrorDup = TRUE;
1278 }
1279
1280 /* Now duplicate handles if required */
1281 if (InputDup)
1282 {
1283 if (IsConsoleHandle(Ppb->hStdInput))
1284 {
1285 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1286 }
1287 else
1288 {
1289 DPRINT("Duplicate input handle\n");
1290 Status = NtDuplicateObject (NtCurrentProcess(),
1291 Ppb->hStdInput,
1292 hProcess,
1293 &Ppb->hStdInput,
1294 0,
1295 TRUE,
1296 DUPLICATE_SAME_ACCESS);
1297 if(!NT_SUCCESS(Status))
1298 {
1299 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1300 }
1301 }
1302 }
1303
1304 if (OutputDup)
1305 {
1306 if (IsConsoleHandle(Ppb->hStdOutput))
1307 {
1308 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1309 }
1310 else
1311 {
1312 DPRINT("Duplicate output handle\n");
1313 Status = NtDuplicateObject (NtCurrentProcess(),
1314 Ppb->hStdOutput,
1315 hProcess,
1316 &Ppb->hStdOutput,
1317 0,
1318 TRUE,
1319 DUPLICATE_SAME_ACCESS);
1320 if(!NT_SUCCESS(Status))
1321 {
1322 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1323 }
1324 }
1325 }
1326
1327 if (ErrorDup)
1328 {
1329 if (IsConsoleHandle(Ppb->hStdError))
1330 {
1331 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1332 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1333 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1334 Status = CsrClientCallServer(&CsrRequest,
1335 &CsrReply,
1336 sizeof(CSRSS_API_REQUEST),
1337 sizeof(CSRSS_API_REPLY));
1338 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1339 {
1340 Ppb->hStdError = INVALID_HANDLE_VALUE;
1341 }
1342 else
1343 {
1344 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1345 }
1346 }
1347 else
1348 {
1349 DPRINT("Duplicate error handle\n");
1350 Status = NtDuplicateObject (NtCurrentProcess(),
1351 Ppb->hStdError,
1352 hProcess,
1353 &Ppb->hStdError,
1354 0,
1355 TRUE,
1356 DUPLICATE_SAME_ACCESS);
1357 if(!NT_SUCCESS(Status))
1358 {
1359 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1360 }
1361 }
1362 }
1363
1364 /*
1365 * Initialize some other fields in the PPB
1366 */
1367 if (lpStartupInfo)
1368 {
1369 Ppb->dwFlags = lpStartupInfo->dwFlags;
1370 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1371 {
1372 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1373 }
1374 else
1375 {
1376 Ppb->wShowWindow = SW_SHOWDEFAULT;
1377 }
1378 Ppb->dwX = lpStartupInfo->dwX;
1379 Ppb->dwY = lpStartupInfo->dwY;
1380 Ppb->dwXSize = lpStartupInfo->dwXSize;
1381 Ppb->dwYSize = lpStartupInfo->dwYSize;
1382 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1383 }
1384 else
1385 {
1386 Ppb->Flags = 0;
1387 }
1388
1389 /*
1390 * Create Process Environment Block
1391 */
1392 DPRINT("Creating peb\n");
1393
1394 KlInitPeb(hProcess, Ppb, &ImageBaseAddress, Sii.Subsystem);
1395
1396 RtlDestroyProcessParameters (Ppb);
1397
1398 Status = NtSetInformationProcess(hProcess,
1399 ProcessImageFileName,
1400 ImageFileName,
1401 8);
1402 /*
1403 * Create the thread for the kernel
1404 */
1405 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1406 ImageBaseAddress + (ULONG)Sii.EntryPoint);
1407 hThread = KlCreateFirstThread(hProcess,
1408 lpThreadAttributes,
1409 &Sii,
1410 ImageBaseAddress + (ULONG)Sii.EntryPoint,
1411 dwCreationFlags,
1412 &lpProcessInformation->dwThreadId);
1413 if (hThread == INVALID_HANDLE_VALUE)
1414 {
1415 return FALSE;
1416 }
1417
1418 lpProcessInformation->hProcess = hProcess;
1419 lpProcessInformation->hThread = hThread;
1420
1421 return TRUE;
1422 }
1423
1424 /* EOF */