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