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