- Added stack trace reporting in exception handler.
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.72 2003/10/31 16:27:01 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 (Frame != NULL && Frame != (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 * @implemented
679 */
680 WINBOOL STDCALL
681 CreateProcessW
682 (
683 LPCWSTR lpApplicationName,
684 LPWSTR lpCommandLine,
685 LPSECURITY_ATTRIBUTES lpProcessAttributes,
686 LPSECURITY_ATTRIBUTES lpThreadAttributes,
687 WINBOOL bInheritHandles,
688 DWORD dwCreationFlags,
689 LPVOID lpEnvironment,
690 LPCWSTR lpCurrentDirectory,
691 LPSTARTUPINFOW lpStartupInfo,
692 LPPROCESS_INFORMATION lpProcessInformation
693 )
694 {
695 HANDLE hSection, hProcess, hThread;
696 NTSTATUS Status;
697 WCHAR ImagePathName[256];
698 UNICODE_STRING ImagePathName_U;
699 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
700 ULONG retlen;
701 PRTL_USER_PROCESS_PARAMETERS Ppb;
702 UNICODE_STRING CommandLine_U;
703 CSRSS_API_REQUEST CsrRequest;
704 CSRSS_API_REPLY CsrReply;
705 CHAR ImageFileName[8];
706 PWCHAR s, e;
707 ULONG i;
708 UNICODE_STRING CurrentDirectory_U;
709 SECTION_IMAGE_INFORMATION Sii;
710 WCHAR TempCurrentDirectoryW[256];
711 WCHAR TempApplicationNameW[256];
712 WCHAR TempCommandLineNameW[256];
713 UNICODE_STRING RuntimeInfo_U;
714 PVOID ImageBaseAddress;
715
716 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
717 lpApplicationName, lpCommandLine);
718
719 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
720 {
721 wcscpy (TempApplicationNameW, lpApplicationName);
722 i = wcslen(TempApplicationNameW);
723 if (TempApplicationNameW[i - 1] == L'.')
724 {
725 TempApplicationNameW[i - 1] = 0;
726 }
727 else
728 {
729 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
730 if (s == NULL)
731 {
732 s = TempApplicationNameW;
733 }
734 else
735 {
736 s++;
737 }
738 e = wcsrchr(s, L'.');
739 if (e == NULL)
740 {
741 wcscat(s, L".exe");
742 e = wcsrchr(s, L'.');
743 }
744 }
745 }
746 else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
747 {
748 if (lpCommandLine[0] == L'"')
749 {
750 wcscpy(TempApplicationNameW, lpCommandLine + 1);
751 s = wcschr(TempApplicationNameW, L'"');
752 if (s == NULL)
753 {
754 return FALSE;
755 }
756 *s = 0;
757 }
758 else
759 {
760 wcscpy(TempApplicationNameW, lpCommandLine);
761 s = wcschr(TempApplicationNameW, L' ');
762 if (s != NULL)
763 {
764 *s = 0;
765 }
766 }
767 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
768 if (s == NULL)
769 {
770 s = TempApplicationNameW;
771 }
772 s = wcsrchr(s, L'.');
773 if (s == NULL)
774 wcscat(TempApplicationNameW, L".exe");
775 }
776 else
777 {
778 return FALSE;
779 }
780
781 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
782 lpApplicationName, lpCommandLine);
783
784 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
785 {
786 return FALSE;
787 }
788
789 e = wcsrchr(s, L'.');
790 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
791 {
792 // the command is a batch file
793 if (lpApplicationName != NULL && lpApplicationName[0])
794 {
795 // FIXME: use COMSPEC for the command interpreter
796 wcscpy(TempCommandLineNameW, L"cmd /c ");
797 wcscat(TempCommandLineNameW, lpApplicationName);
798 lpCommandLine = TempCommandLineNameW;
799 wcscpy(TempApplicationNameW, L"cmd.exe");
800 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
801 {
802 return FALSE;
803 }
804 }
805 else
806 {
807 return FALSE;
808 }
809 }
810
811 /*
812 * Store the image file name for the process
813 */
814 e = wcschr(s, L'.');
815 if (e != NULL)
816 {
817 *e = 0;
818 }
819 for (i = 0; i < 8; i++)
820 {
821 ImageFileName[i] = (CHAR)(s[i]);
822 }
823 if (e != NULL)
824 {
825 *e = '.';
826 }
827
828 /*
829 * Process the application name and command line
830 */
831 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
832 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
833
834 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
835 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
836
837 /* Initialize the current directory string */
838 if (lpCurrentDirectory != NULL)
839 {
840 RtlInitUnicodeString(&CurrentDirectory_U,
841 lpCurrentDirectory);
842 }
843 else
844 {
845 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
846 RtlInitUnicodeString(&CurrentDirectory_U,
847 TempCurrentDirectoryW);
848 }
849
850 /*
851 * Create a section for the executable
852 */
853
854 hSection = KlMapFile (ImagePathName);
855 if (hSection == NULL)
856 {
857 /////////////////////////////////////////
858 /*
859 * Inspect the image to determine executable flavour
860 */
861 IO_STATUS_BLOCK IoStatusBlock;
862 UNICODE_STRING ApplicationNameString;
863 OBJECT_ATTRIBUTES ObjectAttributes;
864 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
865 IMAGE_DOS_HEADER DosHeader;
866 IO_STATUS_BLOCK Iosb;
867 LARGE_INTEGER Offset;
868 HANDLE hFile = NULL;
869
870 DPRINT("Inspecting Image Header for image type id\n");
871
872 // Find the application name
873 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
874 &ApplicationNameString, NULL, NULL)) {
875 return FALSE;
876 }
877 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
878
879 InitializeObjectAttributes(&ObjectAttributes,
880 &ApplicationNameString,
881 OBJ_CASE_INSENSITIVE,
882 NULL,
883 SecurityDescriptor);
884
885 // Try to open the executable
886 Status = NtOpenFile(&hFile,
887 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
888 &ObjectAttributes,
889 &IoStatusBlock,
890 FILE_SHARE_DELETE|FILE_SHARE_READ,
891 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
892
893 RtlFreeUnicodeString(&ApplicationNameString);
894
895 if (!NT_SUCCESS(Status)) {
896 DPRINT("Failed to open file\n");
897 SetLastErrorByStatus(Status);
898 return FALSE;
899 }
900
901 // Read the dos header
902 Offset.QuadPart = 0;
903 Status = ZwReadFile(hFile,
904 NULL,
905 NULL,
906 NULL,
907 &Iosb,
908 &DosHeader,
909 sizeof(DosHeader),
910 &Offset,
911 0);
912
913 if (!NT_SUCCESS(Status)) {
914 DPRINT("Failed to read from file\n");
915 SetLastErrorByStatus(Status);
916 return FALSE;
917 }
918 if (Iosb.Information != sizeof(DosHeader)) {
919 DPRINT("Failed to read dos header from file\n");
920 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
921 return FALSE;
922 }
923
924 // Check the DOS signature
925 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
926 DPRINT("Failed dos magic check\n");
927 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
928 return FALSE;
929 }
930 NtClose(hFile);
931
932 DPRINT("Launching VDM...\n");
933 return CreateProcessW(L"ntvdm.exe",
934 (LPWSTR)lpApplicationName,
935 lpProcessAttributes,
936 lpThreadAttributes,
937 bInheritHandles,
938 dwCreationFlags,
939 lpEnvironment,
940 lpCurrentDirectory,
941 lpStartupInfo,
942 lpProcessInformation);
943 }
944 /////////////////////////////////////////
945 /*
946 * Create a new process
947 */
948 Status = NtCreateProcess(&hProcess,
949 PROCESS_ALL_ACCESS,
950 NULL,
951 NtCurrentProcess(),
952 bInheritHandles,
953 hSection,
954 NULL,
955 NULL);
956 if (lpStartupInfo)
957 {
958 if (lpStartupInfo->lpReserved2)
959 {
960 /* FIXME:
961 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
962 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
963 * If is possible that this function overwrite the last information in runtimeinfo
964 * with the null terminator for the unicode string.
965 */
966 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
967 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
968 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
969 }
970 }
971
972 /*
973 * Create the PPB
974 */
975 RtlCreateProcessParameters(&Ppb,
976 &ImagePathName_U,
977 NULL,
978 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
979 &CommandLine_U,
980 lpEnvironment,
981 NULL,
982 NULL,
983 NULL,
984 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
985
986 if (lpStartupInfo && lpStartupInfo->lpReserved2)
987 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
988
989
990 /*
991 * Translate some handles for the new process
992 */
993 if (Ppb->CurrentDirectoryHandle)
994 {
995 Status = NtDuplicateObject (NtCurrentProcess(),
996 Ppb->CurrentDirectoryHandle,
997 hProcess,
998 &Ppb->CurrentDirectoryHandle,
999 0,
1000 TRUE,
1001 DUPLICATE_SAME_ACCESS);
1002 }
1003
1004 if (Ppb->hConsole)
1005 {
1006 Status = NtDuplicateObject (NtCurrentProcess(),
1007 Ppb->hConsole,
1008 hProcess,
1009 &Ppb->hConsole,
1010 0,
1011 TRUE,
1012 DUPLICATE_SAME_ACCESS);
1013 }
1014
1015 /*
1016 * Get some information about the executable
1017 */
1018 Status = ZwQuerySection(hSection,
1019 SectionImageInformation,
1020 &Sii,
1021 sizeof(Sii),
1022 &i);
1023 /*
1024 * Close the section
1025 */
1026 NtClose(hSection);
1027
1028 /*
1029 * Get some information about the process
1030 */
1031 NtQueryInformationProcess(hProcess,
1032 ProcessBasicInformation,
1033 &ProcessBasicInfo,
1034 sizeof(ProcessBasicInfo),
1035 &retlen);
1036 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1037 ProcessBasicInfo.UniqueProcessId);
1038 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
1039
1040 /*
1041 * Tell the csrss server we are creating a new process
1042 */
1043 CsrRequest.Type = CSRSS_CREATE_PROCESS;
1044 CsrRequest.Data.CreateProcessRequest.NewProcessId =
1045 ProcessBasicInfo.UniqueProcessId;
1046 if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1047 {
1048 /* Do not create a console for GUI applications */
1049 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1050 dwCreationFlags |= DETACHED_PROCESS;
1051 }
1052 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
1053 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
1054 Status = CsrClientCallServer(&CsrRequest,
1055 &CsrReply,
1056 sizeof(CSRSS_API_REQUEST),
1057 sizeof(CSRSS_API_REPLY));
1058 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1059 {
1060 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1061 }
1062
1063 // Set the child console handles
1064 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
1065 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
1066 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
1067
1068 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
1069 {
1070 if (lpStartupInfo->hStdInput)
1071 Ppb->hStdInput = lpStartupInfo->hStdInput;
1072 if (lpStartupInfo->hStdOutput)
1073 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
1074 if (lpStartupInfo->hStdError)
1075 Ppb->hStdError = lpStartupInfo->hStdError;
1076 }
1077
1078 if (IsConsoleHandle(Ppb->hStdInput))
1079 {
1080 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1081 }
1082 else
1083 {
1084 DPRINT("Duplicate input handle\n");
1085 Status = NtDuplicateObject (NtCurrentProcess(),
1086 Ppb->hStdInput,
1087 hProcess,
1088 &Ppb->hStdInput,
1089 0,
1090 TRUE,
1091 DUPLICATE_SAME_ACCESS);
1092 if(!NT_SUCCESS(Status))
1093 {
1094 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1095 }
1096 }
1097
1098 if (IsConsoleHandle(Ppb->hStdOutput))
1099 {
1100 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1101 }
1102 else
1103 {
1104 DPRINT("Duplicate output handle\n");
1105 Status = NtDuplicateObject (NtCurrentProcess(),
1106 Ppb->hStdOutput,
1107 hProcess,
1108 &Ppb->hStdOutput,
1109 0,
1110 TRUE,
1111 DUPLICATE_SAME_ACCESS);
1112 if(!NT_SUCCESS(Status))
1113 {
1114 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1115 }
1116 }
1117 if (IsConsoleHandle(Ppb->hStdError))
1118 {
1119 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1120 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1121 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1122 Status = CsrClientCallServer(&CsrRequest,
1123 &CsrReply,
1124 sizeof(CSRSS_API_REQUEST),
1125 sizeof(CSRSS_API_REPLY));
1126 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1127 {
1128 Ppb->hStdError = INVALID_HANDLE_VALUE;
1129 }
1130 else
1131 {
1132 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1133 }
1134 }
1135 else
1136 {
1137 DPRINT("Duplicate error handle\n");
1138 Status = NtDuplicateObject (NtCurrentProcess(),
1139 Ppb->hStdError,
1140 hProcess,
1141 &Ppb->hStdError,
1142 0,
1143 TRUE,
1144 DUPLICATE_SAME_ACCESS);
1145 if(!NT_SUCCESS(Status))
1146 {
1147 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1148 }
1149 }
1150
1151 /*
1152 * Initialize some other fields in the PPB
1153 */
1154 if (lpStartupInfo)
1155 {
1156 Ppb->dwFlags = lpStartupInfo->dwFlags;
1157 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1158 {
1159 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1160 }
1161 else
1162 {
1163 Ppb->wShowWindow = SW_SHOWDEFAULT;
1164 }
1165 Ppb->dwX = lpStartupInfo->dwX;
1166 Ppb->dwY = lpStartupInfo->dwY;
1167 Ppb->dwXSize = lpStartupInfo->dwXSize;
1168 Ppb->dwYSize = lpStartupInfo->dwYSize;
1169 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1170 }
1171 else
1172 {
1173 Ppb->Flags = 0;
1174 }
1175
1176 /*
1177 * Create Process Environment Block
1178 */
1179 DPRINT("Creating peb\n");
1180
1181 KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
1182
1183 RtlDestroyProcessParameters (Ppb);
1184
1185 Status = NtSetInformationProcess(hProcess,
1186 ProcessImageFileName,
1187 ImageFileName,
1188 8);
1189 /*
1190 * Create the thread for the kernel
1191 */
1192 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1193 ImageBaseAddress + (ULONG)Sii.EntryPoint);
1194 hThread = KlCreateFirstThread(hProcess,
1195 lpThreadAttributes,
1196 &Sii,
1197 ImageBaseAddress + (ULONG)Sii.EntryPoint,
1198 dwCreationFlags,
1199 &lpProcessInformation->dwThreadId);
1200 if (hThread == INVALID_HANDLE_VALUE)
1201 {
1202 return FALSE;
1203 }
1204
1205 lpProcessInformation->hProcess = hProcess;
1206 lpProcessInformation->hThread = hThread;
1207
1208 return TRUE;
1209 }
1210
1211 /* EOF */