0bb3c69e67a01027d02193a050f6b4120a8025e8
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.69 2003/08/18 10:47:04 hbirr 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
330 if (3 < ++_except_recursion_trap)
331 {
332 DPRINT1("_except_handler(...) appears to be recursing.\n");
333 DPRINT1("Process HALTED.\n");
334 for (;;)
335 {
336 }
337 }
338
339 if (/* FIXME: */ TRUE) /* Not a service */
340 {
341 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
342 /* ExitProcess(0); */
343 ExitThread(0);
344 }
345 else
346 {
347 DPRINT(" calling ExitThread(0) . . .\n");
348 ExitThread(0);
349 }
350
351 DPRINT1(" We should not get to here !!!\n");
352 /* We should not get to here */
353 return ExceptionContinueSearch;
354 }
355
356 VOID STDCALL
357 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
358 DWORD lpParameter)
359 {
360 UINT uExitCode = 0;
361
362 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
363
364 __try1(_except_handler)
365 {
366 uExitCode = (lpStartAddress)((PVOID)lpParameter);
367 } __except1
368 {
369 }
370
371 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
372
373 ExitThread(uExitCode);
374 }
375
376
377 HANDLE STDCALL KlCreateFirstThread
378 (
379 HANDLE ProcessHandle,
380 LPSECURITY_ATTRIBUTES lpThreadAttributes,
381 PSECTION_IMAGE_INFORMATION Sii,
382 LPTHREAD_START_ROUTINE lpStartAddress,
383 DWORD dwCreationFlags,
384 LPDWORD lpThreadId
385 )
386 {
387 OBJECT_ATTRIBUTES oaThreadAttribs;
388 CLIENT_ID cidClientId;
389 PVOID pTrueStartAddress;
390 NTSTATUS nErrCode;
391 HANDLE hThread;
392
393 /* convert the thread attributes */
394 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
395
396 /* native image */
397 if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
398 pTrueStartAddress = (PVOID)BaseProcessStart;
399 /* Win32 image */
400 else
401 pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
402
403 DPRINT
404 (
405 "RtlRosCreateUserThreadVa\n"
406 "(\n"
407 " ProcessHandle %p,\n"
408 " ObjectAttributes %p,\n"
409 " CreateSuspended %d,\n"
410 " StackZeroBits %d,\n"
411 " StackReserve %lu,\n"
412 " StackCommit %lu,\n"
413 " StartAddress %p,\n"
414 " ThreadHandle %p,\n"
415 " ClientId %p,\n"
416 " ParameterCount %u,\n"
417 " Parameters[0] %p,\n"
418 " Parameters[1] %p\n"
419 ")\n",
420 ProcessHandle,
421 &oaThreadAttribs,
422 dwCreationFlags & CREATE_SUSPENDED,
423 0,
424 Sii->StackReserve,
425 Sii->StackCommit,
426 pTrueStartAddress,
427 &hThread,
428 &cidClientId,
429 2,
430 lpStartAddress,
431 PEB_BASE
432 );
433
434 /* create the first thread */
435 nErrCode = RtlRosCreateUserThreadVa
436 (
437 ProcessHandle,
438 &oaThreadAttribs,
439 dwCreationFlags & CREATE_SUSPENDED,
440 0,
441 &(Sii->StackReserve),
442 &(Sii->StackCommit),
443 pTrueStartAddress,
444 &hThread,
445 &cidClientId,
446 2,
447 (ULONG_PTR)lpStartAddress,
448 (ULONG_PTR)PEB_BASE
449 );
450
451 /* failure */
452 if(!NT_SUCCESS(nErrCode))
453 {
454 SetLastErrorByStatus(nErrCode);
455 return NULL;
456 }
457
458 DPRINT
459 (
460 "StackReserve %p\n"
461 "StackCommit %p\n"
462 "ThreadHandle %p\n"
463 "ClientId.UniqueThread %p\n",
464 Sii->StackReserve,
465 Sii->StackCommit,
466 hThread,
467 cidClientId.UniqueThread
468 );
469
470 /* success */
471 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
472 return hThread;
473 }
474
475 HANDLE KlMapFile(LPCWSTR lpApplicationName)
476 {
477 HANDLE hFile;
478 IO_STATUS_BLOCK IoStatusBlock;
479 UNICODE_STRING ApplicationNameString;
480 OBJECT_ATTRIBUTES ObjectAttributes;
481 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
482 NTSTATUS Status;
483 HANDLE hSection;
484
485 hFile = NULL;
486
487 /*
488 * Find the application name
489 */
490
491 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
492 &ApplicationNameString,
493 NULL,
494 NULL))
495 return NULL;
496
497 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
498
499 InitializeObjectAttributes(&ObjectAttributes,
500 &ApplicationNameString,
501 OBJ_CASE_INSENSITIVE,
502 NULL,
503 SecurityDescriptor);
504
505 /*
506 * Try to open the executable
507 */
508
509 Status = NtOpenFile(&hFile,
510 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
511 &ObjectAttributes,
512 &IoStatusBlock,
513 FILE_SHARE_DELETE|FILE_SHARE_READ,
514 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
515
516 RtlFreeUnicodeString (&ApplicationNameString);
517
518 if (!NT_SUCCESS(Status))
519 {
520 DPRINT("Failed to open file\n");
521 SetLastErrorByStatus (Status);
522 return(NULL);
523 }
524
525 Status = NtCreateSection(&hSection,
526 SECTION_ALL_ACCESS,
527 NULL,
528 NULL,
529 PAGE_EXECUTE,
530 SEC_IMAGE,
531 hFile);
532 NtClose(hFile);
533
534 if (!NT_SUCCESS(Status))
535 {
536 DPRINT("Failed to create section\n");
537 SetLastErrorByStatus (Status);
538 return(NULL);
539 }
540
541 return(hSection);
542 }
543
544 static NTSTATUS KlInitPeb
545 (
546 HANDLE ProcessHandle,
547 PRTL_USER_PROCESS_PARAMETERS Ppb,
548 PVOID * ImageBaseAddress
549 )
550 {
551 NTSTATUS Status;
552 PVOID PpbBase;
553 ULONG PpbSize;
554 ULONG BytesWritten;
555 ULONG Offset;
556 PVOID ParentEnv = NULL;
557 PVOID EnvPtr = NULL;
558 PWCHAR ptr;
559 ULONG EnvSize = 0, EnvSize1 = 0;
560
561 /* create the Environment */
562 if (Ppb->Environment != NULL)
563 {
564 ParentEnv = Ppb->Environment;
565 ptr = ParentEnv;
566 while (*ptr)
567 {
568 while(*ptr++);
569 }
570 ptr++;
571 EnvSize = (PVOID)ptr - ParentEnv;
572 }
573 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
574 {
575 MEMORY_BASIC_INFORMATION MemInfo;
576 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
577
578 Status = NtQueryVirtualMemory (NtCurrentProcess (),
579 ParentEnv,
580 MemoryBasicInformation,
581 &MemInfo,
582 sizeof(MEMORY_BASIC_INFORMATION),
583 NULL);
584 if (!NT_SUCCESS(Status))
585 {
586 return Status;
587 }
588 EnvSize = MemInfo.RegionSize;
589 }
590 DPRINT("EnvironmentSize %ld\n", EnvSize);
591
592 /* allocate and initialize new environment block */
593 if (EnvSize != 0)
594 {
595 EnvSize1 = EnvSize;
596 Status = NtAllocateVirtualMemory(ProcessHandle,
597 &EnvPtr,
598 0,
599 &EnvSize1,
600 MEM_RESERVE | MEM_COMMIT,
601 PAGE_READWRITE);
602 if (!NT_SUCCESS(Status))
603 {
604 return(Status);
605 }
606
607 NtWriteVirtualMemory(ProcessHandle,
608 EnvPtr,
609 ParentEnv,
610 EnvSize,
611 &BytesWritten);
612 }
613
614 /* create the PPB */
615 PpbBase = NULL;
616 PpbSize = Ppb->AllocationSize;
617 Status = NtAllocateVirtualMemory(ProcessHandle,
618 &PpbBase,
619 0,
620 &PpbSize,
621 MEM_RESERVE | MEM_COMMIT,
622 PAGE_READWRITE);
623 if (!NT_SUCCESS(Status))
624 {
625 return(Status);
626 }
627
628 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
629 NtWriteVirtualMemory(ProcessHandle,
630 PpbBase,
631 Ppb,
632 Ppb->AllocationSize,
633 &BytesWritten);
634
635 /* write pointer to environment */
636 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
637 NtWriteVirtualMemory(ProcessHandle,
638 (PVOID)(PpbBase + Offset),
639 &EnvPtr,
640 sizeof(EnvPtr),
641 &BytesWritten);
642
643 /* write pointer to process parameter block */
644 Offset = FIELD_OFFSET(PEB, ProcessParameters);
645 NtWriteVirtualMemory(ProcessHandle,
646 (PVOID)(PEB_BASE + Offset),
647 &PpbBase,
648 sizeof(PpbBase),
649 &BytesWritten);
650
651 /* Read image base address. */
652 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
653 NtReadVirtualMemory(ProcessHandle,
654 (PVOID)(PEB_BASE + Offset),
655 ImageBaseAddress,
656 sizeof(PVOID),
657 &BytesWritten);
658
659 return(STATUS_SUCCESS);
660 }
661
662
663 /*
664 * @implemented
665 */
666 WINBOOL STDCALL
667 CreateProcessW
668 (
669 LPCWSTR lpApplicationName,
670 LPWSTR lpCommandLine,
671 LPSECURITY_ATTRIBUTES lpProcessAttributes,
672 LPSECURITY_ATTRIBUTES lpThreadAttributes,
673 WINBOOL bInheritHandles,
674 DWORD dwCreationFlags,
675 LPVOID lpEnvironment,
676 LPCWSTR lpCurrentDirectory,
677 LPSTARTUPINFOW lpStartupInfo,
678 LPPROCESS_INFORMATION lpProcessInformation
679 )
680 {
681 HANDLE hSection, hProcess, hThread;
682 NTSTATUS Status;
683 LPTHREAD_START_ROUTINE lpStartAddress = NULL;
684 WCHAR ImagePathName[256];
685 UNICODE_STRING ImagePathName_U;
686 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
687 ULONG retlen;
688 PRTL_USER_PROCESS_PARAMETERS Ppb;
689 UNICODE_STRING CommandLine_U;
690 CSRSS_API_REQUEST CsrRequest;
691 CSRSS_API_REPLY CsrReply;
692 CHAR ImageFileName[8];
693 PWCHAR s, e;
694 ULONG i, len;
695 ANSI_STRING ProcedureName;
696 UNICODE_STRING CurrentDirectory_U;
697 SECTION_IMAGE_INFORMATION Sii;
698 WCHAR TempCurrentDirectoryW[256];
699 WCHAR TempApplicationNameW[256];
700 WCHAR TempCommandLineNameW[256];
701 UNICODE_STRING RuntimeInfo_U;
702 PVOID ImageBaseAddress;
703
704 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
705 lpApplicationName, lpCommandLine);
706
707 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
708 {
709 wcscpy (TempApplicationNameW, lpApplicationName);
710 i = wcslen(TempApplicationNameW);
711 if (TempApplicationNameW[i - 1] == L'.')
712 {
713 TempApplicationNameW[i - 1] = 0;
714 }
715 else
716 {
717 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
718 if (s == NULL)
719 {
720 s = TempApplicationNameW;
721 }
722 else
723 {
724 s++;
725 }
726 e = wcsrchr(s, L'.');
727 if (e == NULL)
728 {
729 wcscat(s, L".exe");
730 e = wcsrchr(s, L'.');
731 }
732 }
733 }
734 else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
735 {
736 if (lpCommandLine[0] == L'"')
737 {
738 wcscpy(TempApplicationNameW, lpCommandLine + 1);
739 s = wcschr(TempApplicationNameW, L'"');
740 if (s == NULL)
741 {
742 return FALSE;
743 }
744 *s = 0;
745 }
746 else
747 {
748 wcscpy(TempApplicationNameW, lpCommandLine);
749 s = wcschr(TempApplicationNameW, L' ');
750 if (s != NULL)
751 {
752 *s = 0;
753 }
754 }
755 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
756 if (s == NULL)
757 {
758 s = TempApplicationNameW;
759 }
760 s = wcsrchr(s, L'.');
761 if (s == NULL)
762 wcscat(TempApplicationNameW, L".exe");
763 }
764 else
765 {
766 return FALSE;
767 }
768
769 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
770 lpApplicationName, lpCommandLine);
771
772 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
773 {
774 return FALSE;
775 }
776
777 e = wcsrchr(s, L'.');
778 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
779 {
780 // the command is a batch file
781 if (lpApplicationName != NULL && lpApplicationName[0])
782 {
783 // FIXME: use COMSPEC for the command interpreter
784 wcscpy(TempCommandLineNameW, L"cmd /c ");
785 wcscat(TempCommandLineNameW, lpApplicationName);
786 lpCommandLine = TempCommandLineNameW;
787 wcscpy(TempApplicationNameW, L"cmd.exe");
788 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
789 {
790 return FALSE;
791 }
792 }
793 else
794 {
795 return FALSE;
796 }
797 }
798
799 /*
800 * Store the image file name for the process
801 */
802 e = wcschr(s, L'.');
803 if (e != NULL)
804 {
805 *e = 0;
806 }
807 for (i = 0; i < 8; i++)
808 {
809 ImageFileName[i] = (CHAR)(s[i]);
810 }
811 if (e != NULL)
812 {
813 *e = '.';
814 }
815
816 /*
817 * Process the application name and command line
818 */
819 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
820 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
821
822 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
823 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
824
825 /* Initialize the current directory string */
826 if (lpCurrentDirectory != NULL)
827 {
828 RtlInitUnicodeString(&CurrentDirectory_U,
829 lpCurrentDirectory);
830 }
831 else
832 {
833 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
834 RtlInitUnicodeString(&CurrentDirectory_U,
835 TempCurrentDirectoryW);
836 }
837
838 /*
839 * Create a section for the executable
840 */
841
842 hSection = KlMapFile (ImagePathName);
843 if (hSection == NULL)
844 {
845 /////////////////////////////////////////
846 /*
847 * Inspect the image to determine executable flavour
848 */
849 IO_STATUS_BLOCK IoStatusBlock;
850 UNICODE_STRING ApplicationNameString;
851 OBJECT_ATTRIBUTES ObjectAttributes;
852 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
853 IMAGE_DOS_HEADER DosHeader;
854 IO_STATUS_BLOCK Iosb;
855 LARGE_INTEGER Offset;
856 HANDLE hFile = NULL;
857
858 DPRINT("Inspecting Image Header for image type id\n");
859
860 // Find the application name
861 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
862 &ApplicationNameString, NULL, NULL)) {
863 return FALSE;
864 }
865 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
866
867 InitializeObjectAttributes(&ObjectAttributes,
868 &ApplicationNameString,
869 OBJ_CASE_INSENSITIVE,
870 NULL,
871 SecurityDescriptor);
872
873 // Try to open the executable
874 Status = NtOpenFile(&hFile,
875 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
876 &ObjectAttributes,
877 &IoStatusBlock,
878 FILE_SHARE_DELETE|FILE_SHARE_READ,
879 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
880
881 RtlFreeUnicodeString(&ApplicationNameString);
882
883 if (!NT_SUCCESS(Status)) {
884 DPRINT("Failed to open file\n");
885 SetLastErrorByStatus(Status);
886 return FALSE;
887 }
888
889 // Read the dos header
890 Offset.QuadPart = 0;
891 Status = ZwReadFile(hFile,
892 NULL,
893 NULL,
894 NULL,
895 &Iosb,
896 &DosHeader,
897 sizeof(DosHeader),
898 &Offset,
899 0);
900
901 if (!NT_SUCCESS(Status)) {
902 DPRINT("Failed to read from file\n");
903 SetLastErrorByStatus(Status);
904 return FALSE;
905 }
906 if (Iosb.Information != sizeof(DosHeader)) {
907 DPRINT("Failed to read dos header from file\n");
908 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
909 return FALSE;
910 }
911
912 // Check the DOS signature
913 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
914 DPRINT("Failed dos magic check\n");
915 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
916 return FALSE;
917 }
918 NtClose(hFile);
919
920 DPRINT("Launching VDM...\n");
921 return CreateProcessW(L"ntvdm.exe",
922 (LPWSTR)lpApplicationName,
923 lpProcessAttributes,
924 lpThreadAttributes,
925 bInheritHandles,
926 dwCreationFlags,
927 lpEnvironment,
928 lpCurrentDirectory,
929 lpStartupInfo,
930 lpProcessInformation);
931 }
932 /////////////////////////////////////////
933 /*
934 * Create a new process
935 */
936 Status = NtCreateProcess(&hProcess,
937 PROCESS_ALL_ACCESS,
938 NULL,
939 NtCurrentProcess(),
940 bInheritHandles,
941 hSection,
942 NULL,
943 NULL);
944 if (lpStartupInfo)
945 {
946 if (lpStartupInfo->lpReserved2)
947 {
948 ULONG i, Count = *(ULONG*)lpStartupInfo->lpReserved2;
949 HANDLE * hFile;
950 HANDLE hTemp;
951 PRTL_USER_PROCESS_PARAMETERS CurrPpb = NtCurrentPeb()->ProcessParameters;
952
953
954 /* FIXME:
955 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
956 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
957 * If is possible that this function overwrite the last information in runtimeinfo
958 * with the null terminator for the unicode string.
959 */
960 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
961 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
962 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
963 }
964 }
965
966 /*
967 * Create the PPB
968 */
969 RtlCreateProcessParameters(&Ppb,
970 &ImagePathName_U,
971 NULL,
972 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
973 &CommandLine_U,
974 lpEnvironment,
975 NULL,
976 NULL,
977 NULL,
978 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
979
980 if (lpStartupInfo && lpStartupInfo->lpReserved2)
981 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
982
983
984 /*
985 * Translate some handles for the new process
986 */
987 if (Ppb->CurrentDirectoryHandle)
988 {
989 Status = NtDuplicateObject (NtCurrentProcess(),
990 Ppb->CurrentDirectoryHandle,
991 hProcess,
992 &Ppb->CurrentDirectoryHandle,
993 0,
994 TRUE,
995 DUPLICATE_SAME_ACCESS);
996 }
997
998 if (Ppb->hConsole)
999 {
1000 Status = NtDuplicateObject (NtCurrentProcess(),
1001 Ppb->hConsole,
1002 hProcess,
1003 &Ppb->hConsole,
1004 0,
1005 TRUE,
1006 DUPLICATE_SAME_ACCESS);
1007 }
1008
1009 /*
1010 * Get some information about the executable
1011 */
1012 Status = ZwQuerySection(hSection,
1013 SectionImageInformation,
1014 &Sii,
1015 sizeof(Sii),
1016 &i);
1017 /*
1018 * Close the section
1019 */
1020 NtClose(hSection);
1021
1022 /*
1023 * Get some information about the process
1024 */
1025 NtQueryInformationProcess(hProcess,
1026 ProcessBasicInformation,
1027 &ProcessBasicInfo,
1028 sizeof(ProcessBasicInfo),
1029 &retlen);
1030 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1031 ProcessBasicInfo.UniqueProcessId);
1032 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
1033
1034 /*
1035 * Tell the csrss server we are creating a new process
1036 */
1037 CsrRequest.Type = CSRSS_CREATE_PROCESS;
1038 CsrRequest.Data.CreateProcessRequest.NewProcessId =
1039 ProcessBasicInfo.UniqueProcessId;
1040 if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1041 {
1042 /* Do not create a console for GUI applications */
1043 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1044 dwCreationFlags |= DETACHED_PROCESS;
1045 }
1046 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
1047 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
1048 Status = CsrClientCallServer(&CsrRequest,
1049 &CsrReply,
1050 sizeof(CSRSS_API_REQUEST),
1051 sizeof(CSRSS_API_REPLY));
1052 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1053 {
1054 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1055 }
1056
1057 // Set the child console handles
1058 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
1059 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
1060 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
1061
1062 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
1063 {
1064 if (lpStartupInfo->hStdInput)
1065 Ppb->hStdInput = lpStartupInfo->hStdInput;
1066 if (lpStartupInfo->hStdOutput)
1067 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
1068 if (lpStartupInfo->hStdError)
1069 Ppb->hStdError = lpStartupInfo->hStdError;
1070 }
1071
1072 if (IsConsoleHandle(Ppb->hStdInput))
1073 {
1074 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1075 }
1076 else
1077 {
1078 DPRINT("Duplicate input handle\n");
1079 Status = NtDuplicateObject (NtCurrentProcess(),
1080 Ppb->hStdInput,
1081 hProcess,
1082 &Ppb->hStdInput,
1083 0,
1084 TRUE,
1085 DUPLICATE_SAME_ACCESS);
1086 if(!NT_SUCCESS(Status))
1087 {
1088 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1089 }
1090 }
1091
1092 if (IsConsoleHandle(Ppb->hStdOutput))
1093 {
1094 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1095 }
1096 else
1097 {
1098 DPRINT("Duplicate output handle\n");
1099 Status = NtDuplicateObject (NtCurrentProcess(),
1100 Ppb->hStdOutput,
1101 hProcess,
1102 &Ppb->hStdOutput,
1103 0,
1104 TRUE,
1105 DUPLICATE_SAME_ACCESS);
1106 if(!NT_SUCCESS(Status))
1107 {
1108 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1109 }
1110 }
1111 if (IsConsoleHandle(Ppb->hStdError))
1112 {
1113 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1114 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1115 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1116 Status = CsrClientCallServer(&CsrRequest,
1117 &CsrReply,
1118 sizeof(CSRSS_API_REQUEST),
1119 sizeof(CSRSS_API_REPLY));
1120 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1121 {
1122 Ppb->hStdError = INVALID_HANDLE_VALUE;
1123 }
1124 else
1125 {
1126 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1127 }
1128 }
1129 else
1130 {
1131 DPRINT("Duplicate error handle\n");
1132 Status = NtDuplicateObject (NtCurrentProcess(),
1133 Ppb->hStdError,
1134 hProcess,
1135 &Ppb->hStdError,
1136 0,
1137 TRUE,
1138 DUPLICATE_SAME_ACCESS);
1139 if(!NT_SUCCESS(Status))
1140 {
1141 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1142 }
1143 }
1144
1145 /*
1146 * Initialize some other fields in the PPB
1147 */
1148 if (lpStartupInfo)
1149 {
1150 Ppb->dwFlags = lpStartupInfo->dwFlags;
1151 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1152 {
1153 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1154 }
1155 else
1156 {
1157 Ppb->wShowWindow = SW_SHOWDEFAULT;
1158 }
1159 Ppb->dwX = lpStartupInfo->dwX;
1160 Ppb->dwY = lpStartupInfo->dwY;
1161 Ppb->dwXSize = lpStartupInfo->dwXSize;
1162 Ppb->dwYSize = lpStartupInfo->dwYSize;
1163 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1164 }
1165 else
1166 {
1167 Ppb->Flags = 0;
1168 }
1169
1170 /*
1171 * Create Process Environment Block
1172 */
1173 DPRINT("Creating peb\n");
1174
1175 KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
1176
1177 RtlDestroyProcessParameters (Ppb);
1178
1179 Status = NtSetInformationProcess(hProcess,
1180 ProcessImageFileName,
1181 ImageFileName,
1182 8);
1183 /*
1184 * Create the thread for the kernel
1185 */
1186 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1187 ImageBaseAddress + (ULONG)Sii.EntryPoint);
1188 hThread = KlCreateFirstThread(hProcess,
1189 lpThreadAttributes,
1190 &Sii,
1191 ImageBaseAddress + (ULONG)Sii.EntryPoint,
1192 dwCreationFlags,
1193 &lpProcessInformation->dwThreadId);
1194 if (hThread == INVALID_HANDLE_VALUE)
1195 {
1196 return FALSE;
1197 }
1198
1199 lpProcessInformation->hProcess = hProcess;
1200 lpProcessInformation->hThread = hThread;
1201
1202 return TRUE;
1203 }
1204
1205 /* EOF */