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)
12 /* INCLUDES ****************************************************************/
17 #include <kernel32/kernel32.h>
19 /* FUNCTIONS ****************************************************************/
21 extern __declspec(noreturn)
22 VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
25 PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine;
27 typedef NTSTATUS STDCALL (K32_MBSTR_TO_WCSTR)
34 NTSTATUS STDCALL K32MbStrToWcStr
36 IN K32_MBSTR_TO_WCSTR * True,
37 UNICODE_STRING * DestStr,
38 ANSI_STRING * SourceStr,
42 if(SourceStr->Buffer == NULL)
44 DestStr->Length = DestStr->MaximumLength = 0;
45 DestStr->Buffer = NULL;
46 return STATUS_SUCCESS;
49 return True(DestStr, SourceStr, Allocate);
52 VOID STDCALL RtlRosR32AttribsToNativeAttribs
54 OUT OBJECT_ATTRIBUTES * NativeAttribs,
55 IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL
58 NativeAttribs->Length = sizeof(*NativeAttribs);
59 NativeAttribs->ObjectName = NULL;
60 NativeAttribs->RootDirectory = NULL;
61 NativeAttribs->Attributes = 0;
62 NativeAttribs->SecurityQualityOfService = NULL;
65 if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
67 NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
69 if(Ros32Attribs->bInheritHandle)
70 NativeAttribs->Attributes |= OBJ_INHERIT;
73 NativeAttribs->SecurityDescriptor = NULL;
76 VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed
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
85 if(!NativeAttribs) return;
87 RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
89 if(Ros32Name != NULL && NativeName != NULL)
91 RtlInitUnicodeString(NativeName, Ros32Name);
93 NativeAttribs->ObjectName = NativeName;
94 NativeAttribs->RootDirectory = Ros32NameRoot;
95 NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
103 BOOL STDCALL CreateProcessA
105 LPCSTR lpApplicationName,
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
117 * FUNCTION: The CreateProcess function creates a new process and its
118 * primary thread. The new process executes the specified executable file
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
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;
147 STARTUPINFOW wsiStartupInfo;
149 NTSTATUS STDCALL (*pTrue)
156 ULONG STDCALL (*pRtlMbStringToUnicodeSize)(ANSI_STRING *);
158 DPRINT("CreateProcessA(%s)\n", lpApplicationName);
162 "dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
163 "lpStartupInfo %x, lpProcessInformation %x\n",
171 /* invalid parameter */
172 if(lpStartupInfo == NULL)
174 SetLastError(ERROR_INVALID_PARAMETER);
178 /* multibyte strings are ANSI */
181 pTrue = RtlAnsiStringToUnicodeString;
182 pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize;
184 /* multibyte strings are OEM */
187 pTrue = RtlOemStringToUnicodeString;
188 pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize;
191 /* convert the environment */
192 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
196 UNICODE_STRING wstrEnvVar;
197 ANSI_STRING strEnvVar;
199 /* scan the environment to calculate its Unicode size */
200 for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
202 /* add the size of the current variable */
203 RtlInitAnsiString(&strEnvVar, pcScan);
204 nEnvLen += pRtlMbStringToUnicodeSize(&strEnvVar) + sizeof(WCHAR);
207 /* add the size of the final NUL character */
208 nEnvLen += sizeof(WCHAR);
210 /* environment too large */
211 if(nEnvLen > ~((USHORT)0))
213 SetLastError(ERROR_OUTOFMEMORY);
217 /* allocate the Unicode environment */
218 pwcEnv = (PWCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, nEnvLen);
223 SetLastError(ERROR_OUTOFMEMORY);
227 wstrEnvVar.Buffer = pwcEnv;
228 wstrEnvVar.Length = 0;
229 wstrEnvVar.MaximumLength = nEnvLen;
231 /* scan the environment to convert it */
232 for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
234 /* convert the current variable */
235 RtlInitAnsiString(&strEnvVar, pcScan);
236 K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, FALSE);
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;
244 /* final NUL character */
245 wstrEnvVar.Buffer[0] = 0;
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);
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);
263 /* convert the startup information */
264 memcpy(&wsiStartupInfo, lpStartupInfo, sizeof(wsiStartupInfo));
266 wsiStartupInfo.lpReserved = wstrReserved.Buffer;
267 wsiStartupInfo.lpDesktop = wstrDesktop.Buffer;
268 wsiStartupInfo.lpTitle = wstrTitle.Buffer;
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);
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);
284 DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA));
285 DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW));
287 /* call the Unicode function */
288 bRetVal = CreateProcessW
290 wstrApplicationName.Buffer,
291 wstrCommandLine.Buffer,
296 dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : pwcEnv,
297 wstrCurrentDirectory.Buffer,
302 RtlFreeUnicodeString(&wstrApplicationName);
303 RtlFreeUnicodeString(&wstrCommandLine);
304 RtlFreeUnicodeString(&wstrCurrentDirectory);
305 RtlFreeUnicodeString(&wstrReserved);
306 RtlFreeUnicodeString(&wstrDesktop);
307 RtlFreeUnicodeString(&wstrTitle);
309 RtlFreeHeap(GetProcessHeap(), 0, pwcEnv);
314 static int _except_recursion_trap = 0;
317 struct __EXCEPTION_RECORD;
320 EXCEPTION_DISPOSITION
323 struct _EXCEPTION_RECORD *ExceptionRecord,
324 void * EstablisherFrame,
325 struct _CONTEXT *ContextRecord,
326 void * DispatcherContext )
328 DPRINT1("Process terminated abnormally due to unhandled exception\n");
330 if (3 < ++_except_recursion_trap)
332 DPRINT1("_except_handler(...) appears to be recursing.\n");
333 DPRINT1("Process HALTED.\n");
339 if (/* FIXME: */ TRUE) /* Not a service */
341 DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
342 /* ExitProcess(0); */
347 DPRINT(" calling ExitThread(0) . . .\n");
351 DPRINT1(" We should not get to here !!!\n");
352 /* We should not get to here */
353 return ExceptionContinueSearch;
357 BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
362 DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
364 __try1(_except_handler)
366 uExitCode = (lpStartAddress)((PVOID)lpParameter);
371 DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
373 ExitThread(uExitCode);
377 HANDLE STDCALL KlCreateFirstThread
379 HANDLE ProcessHandle,
380 LPSECURITY_ATTRIBUTES lpThreadAttributes,
381 PSECTION_IMAGE_INFORMATION Sii,
382 LPTHREAD_START_ROUTINE lpStartAddress,
383 DWORD dwCreationFlags,
387 OBJECT_ATTRIBUTES oaThreadAttribs;
388 CLIENT_ID cidClientId;
389 PVOID pTrueStartAddress;
393 /* convert the thread attributes */
394 RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
397 if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
398 pTrueStartAddress = (PVOID)BaseProcessStart;
401 pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
405 "RtlRosCreateUserThreadVa\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"
416 " ParameterCount %u,\n"
417 " Parameters[0] %p,\n"
418 " Parameters[1] %p\n"
422 dwCreationFlags & CREATE_SUSPENDED,
434 /* create the first thread */
435 nErrCode = RtlRosCreateUserThreadVa
439 dwCreationFlags & CREATE_SUSPENDED,
441 &(Sii->StackReserve),
447 (ULONG_PTR)lpStartAddress,
452 if(!NT_SUCCESS(nErrCode))
454 SetLastErrorByStatus(nErrCode);
463 "ClientId.UniqueThread %p\n",
467 cidClientId.UniqueThread
471 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
475 HANDLE KlMapFile(LPCWSTR lpApplicationName)
478 IO_STATUS_BLOCK IoStatusBlock;
479 UNICODE_STRING ApplicationNameString;
480 OBJECT_ATTRIBUTES ObjectAttributes;
481 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
488 * Find the application name
491 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
492 &ApplicationNameString,
497 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
499 InitializeObjectAttributes(&ObjectAttributes,
500 &ApplicationNameString,
501 OBJ_CASE_INSENSITIVE,
506 * Try to open the executable
509 Status = NtOpenFile(&hFile,
510 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
513 FILE_SHARE_DELETE|FILE_SHARE_READ,
514 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
516 RtlFreeUnicodeString (&ApplicationNameString);
518 if (!NT_SUCCESS(Status))
520 DPRINT("Failed to open file\n");
521 SetLastErrorByStatus (Status);
525 Status = NtCreateSection(&hSection,
534 if (!NT_SUCCESS(Status))
536 DPRINT("Failed to create section\n");
537 SetLastErrorByStatus (Status);
544 static NTSTATUS KlInitPeb
546 HANDLE ProcessHandle,
547 PRTL_USER_PROCESS_PARAMETERS Ppb,
548 PVOID * ImageBaseAddress
556 PVOID ParentEnv = NULL;
559 ULONG EnvSize = 0, EnvSize1 = 0;
561 /* create the Environment */
562 if (Ppb->Environment != NULL)
564 ParentEnv = Ppb->Environment;
571 EnvSize = (PVOID)ptr - ParentEnv;
573 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
575 MEMORY_BASIC_INFORMATION MemInfo;
576 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
578 Status = NtQueryVirtualMemory (NtCurrentProcess (),
580 MemoryBasicInformation,
582 sizeof(MEMORY_BASIC_INFORMATION),
584 if (!NT_SUCCESS(Status))
588 EnvSize = MemInfo.RegionSize;
590 DPRINT("EnvironmentSize %ld\n", EnvSize);
592 /* allocate and initialize new environment block */
596 Status = NtAllocateVirtualMemory(ProcessHandle,
600 MEM_RESERVE | MEM_COMMIT,
602 if (!NT_SUCCESS(Status))
607 NtWriteVirtualMemory(ProcessHandle,
616 PpbSize = Ppb->AllocationSize;
617 Status = NtAllocateVirtualMemory(ProcessHandle,
621 MEM_RESERVE | MEM_COMMIT,
623 if (!NT_SUCCESS(Status))
628 //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
629 NtWriteVirtualMemory(ProcessHandle,
635 /* write pointer to environment */
636 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
637 NtWriteVirtualMemory(ProcessHandle,
638 (PVOID)(PpbBase + Offset),
643 /* write pointer to process parameter block */
644 Offset = FIELD_OFFSET(PEB, ProcessParameters);
645 NtWriteVirtualMemory(ProcessHandle,
646 (PVOID)(PEB_BASE + Offset),
651 /* Read image base address. */
652 Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
653 NtReadVirtualMemory(ProcessHandle,
654 (PVOID)(PEB_BASE + Offset),
659 return(STATUS_SUCCESS);
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
681 HANDLE hSection, hProcess, hThread;
683 WCHAR ImagePathName[256];
684 UNICODE_STRING ImagePathName_U;
685 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
687 PRTL_USER_PROCESS_PARAMETERS Ppb;
688 UNICODE_STRING CommandLine_U;
689 CSRSS_API_REQUEST CsrRequest;
690 CSRSS_API_REPLY CsrReply;
691 CHAR ImageFileName[8];
694 UNICODE_STRING CurrentDirectory_U;
695 SECTION_IMAGE_INFORMATION Sii;
696 WCHAR TempCurrentDirectoryW[256];
697 WCHAR TempApplicationNameW[256];
698 WCHAR TempCommandLineNameW[256];
699 UNICODE_STRING RuntimeInfo_U;
700 PVOID ImageBaseAddress;
702 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
703 lpApplicationName, lpCommandLine);
705 if (lpApplicationName != NULL && lpApplicationName[0] != 0)
707 wcscpy (TempApplicationNameW, lpApplicationName);
708 i = wcslen(TempApplicationNameW);
709 if (TempApplicationNameW[i - 1] == L'.')
711 TempApplicationNameW[i - 1] = 0;
715 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
718 s = TempApplicationNameW;
724 e = wcsrchr(s, L'.');
728 e = wcsrchr(s, L'.');
732 else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
734 if (lpCommandLine[0] == L'"')
736 wcscpy(TempApplicationNameW, lpCommandLine + 1);
737 s = wcschr(TempApplicationNameW, L'"');
746 wcscpy(TempApplicationNameW, lpCommandLine);
747 s = wcschr(TempApplicationNameW, L' ');
753 s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
756 s = TempApplicationNameW;
758 s = wcsrchr(s, L'.');
760 wcscat(TempApplicationNameW, L".exe");
767 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
768 lpApplicationName, lpCommandLine);
770 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
775 e = wcsrchr(s, L'.');
776 if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
778 // the command is a batch file
779 if (lpApplicationName != NULL && lpApplicationName[0])
781 // FIXME: use COMSPEC for the command interpreter
782 wcscpy(TempCommandLineNameW, L"cmd /c ");
783 wcscat(TempCommandLineNameW, lpApplicationName);
784 lpCommandLine = TempCommandLineNameW;
785 wcscpy(TempApplicationNameW, L"cmd.exe");
786 if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
798 * Store the image file name for the process
805 for (i = 0; i < 8; i++)
807 ImageFileName[i] = (CHAR)(s[i]);
815 * Process the application name and command line
817 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
818 RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
820 DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
821 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
823 /* Initialize the current directory string */
824 if (lpCurrentDirectory != NULL)
826 RtlInitUnicodeString(&CurrentDirectory_U,
831 GetCurrentDirectoryW(256, TempCurrentDirectoryW);
832 RtlInitUnicodeString(&CurrentDirectory_U,
833 TempCurrentDirectoryW);
837 * Create a section for the executable
840 hSection = KlMapFile (ImagePathName);
841 if (hSection == NULL)
843 /////////////////////////////////////////
845 * Inspect the image to determine executable flavour
847 IO_STATUS_BLOCK IoStatusBlock;
848 UNICODE_STRING ApplicationNameString;
849 OBJECT_ATTRIBUTES ObjectAttributes;
850 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
851 IMAGE_DOS_HEADER DosHeader;
852 IO_STATUS_BLOCK Iosb;
853 LARGE_INTEGER Offset;
856 DPRINT("Inspecting Image Header for image type id\n");
858 // Find the application name
859 if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
860 &ApplicationNameString, NULL, NULL)) {
863 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
865 InitializeObjectAttributes(&ObjectAttributes,
866 &ApplicationNameString,
867 OBJ_CASE_INSENSITIVE,
871 // Try to open the executable
872 Status = NtOpenFile(&hFile,
873 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
876 FILE_SHARE_DELETE|FILE_SHARE_READ,
877 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
879 RtlFreeUnicodeString(&ApplicationNameString);
881 if (!NT_SUCCESS(Status)) {
882 DPRINT("Failed to open file\n");
883 SetLastErrorByStatus(Status);
887 // Read the dos header
889 Status = ZwReadFile(hFile,
899 if (!NT_SUCCESS(Status)) {
900 DPRINT("Failed to read from file\n");
901 SetLastErrorByStatus(Status);
904 if (Iosb.Information != sizeof(DosHeader)) {
905 DPRINT("Failed to read dos header from file\n");
906 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
910 // Check the DOS signature
911 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
912 DPRINT("Failed dos magic check\n");
913 SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
918 DPRINT("Launching VDM...\n");
919 return CreateProcessW(L"ntvdm.exe",
920 (LPWSTR)lpApplicationName,
928 lpProcessInformation);
930 /////////////////////////////////////////
932 * Create a new process
934 Status = NtCreateProcess(&hProcess,
944 if (lpStartupInfo->lpReserved2)
947 * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
948 * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
949 * If is possible that this function overwrite the last information in runtimeinfo
950 * with the null terminator for the unicode string.
952 RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
953 RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
954 memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
961 RtlCreateProcessParameters(&Ppb,
964 lpCurrentDirectory ? &CurrentDirectory_U : NULL,
970 lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
972 if (lpStartupInfo && lpStartupInfo->lpReserved2)
973 RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
977 * Translate some handles for the new process
979 if (Ppb->CurrentDirectoryHandle)
981 Status = NtDuplicateObject (NtCurrentProcess(),
982 Ppb->CurrentDirectoryHandle,
984 &Ppb->CurrentDirectoryHandle,
987 DUPLICATE_SAME_ACCESS);
992 Status = NtDuplicateObject (NtCurrentProcess(),
998 DUPLICATE_SAME_ACCESS);
1002 * Get some information about the executable
1004 Status = ZwQuerySection(hSection,
1005 SectionImageInformation,
1015 * Get some information about the process
1017 NtQueryInformationProcess(hProcess,
1018 ProcessBasicInformation,
1020 sizeof(ProcessBasicInfo),
1022 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
1023 ProcessBasicInfo.UniqueProcessId);
1024 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
1027 * Tell the csrss server we are creating a new process
1029 CsrRequest.Type = CSRSS_CREATE_PROCESS;
1030 CsrRequest.Data.CreateProcessRequest.NewProcessId =
1031 ProcessBasicInfo.UniqueProcessId;
1032 if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1034 /* Do not create a console for GUI applications */
1035 dwCreationFlags &= ~CREATE_NEW_CONSOLE;
1036 dwCreationFlags |= DETACHED_PROCESS;
1038 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
1039 CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
1040 Status = CsrClientCallServer(&CsrRequest,
1042 sizeof(CSRSS_API_REQUEST),
1043 sizeof(CSRSS_API_REPLY));
1044 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1046 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
1049 // Set the child console handles
1050 Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
1051 Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
1052 Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
1054 if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
1056 if (lpStartupInfo->hStdInput)
1057 Ppb->hStdInput = lpStartupInfo->hStdInput;
1058 if (lpStartupInfo->hStdOutput)
1059 Ppb->hStdOutput = lpStartupInfo->hStdOutput;
1060 if (lpStartupInfo->hStdError)
1061 Ppb->hStdError = lpStartupInfo->hStdError;
1064 if (IsConsoleHandle(Ppb->hStdInput))
1066 Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
1070 DPRINT("Duplicate input handle\n");
1071 Status = NtDuplicateObject (NtCurrentProcess(),
1077 DUPLICATE_SAME_ACCESS);
1078 if(!NT_SUCCESS(Status))
1080 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1084 if (IsConsoleHandle(Ppb->hStdOutput))
1086 Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
1090 DPRINT("Duplicate output handle\n");
1091 Status = NtDuplicateObject (NtCurrentProcess(),
1097 DUPLICATE_SAME_ACCESS);
1098 if(!NT_SUCCESS(Status))
1100 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1103 if (IsConsoleHandle(Ppb->hStdError))
1105 CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
1106 CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
1107 CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
1108 Status = CsrClientCallServer(&CsrRequest,
1110 sizeof(CSRSS_API_REQUEST),
1111 sizeof(CSRSS_API_REPLY));
1112 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
1114 Ppb->hStdError = INVALID_HANDLE_VALUE;
1118 Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
1123 DPRINT("Duplicate error handle\n");
1124 Status = NtDuplicateObject (NtCurrentProcess(),
1130 DUPLICATE_SAME_ACCESS);
1131 if(!NT_SUCCESS(Status))
1133 DPRINT("NtDuplicateObject failed, status %x\n", Status);
1138 * Initialize some other fields in the PPB
1142 Ppb->dwFlags = lpStartupInfo->dwFlags;
1143 if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
1145 Ppb->wShowWindow = lpStartupInfo->wShowWindow;
1149 Ppb->wShowWindow = SW_SHOWDEFAULT;
1151 Ppb->dwX = lpStartupInfo->dwX;
1152 Ppb->dwY = lpStartupInfo->dwY;
1153 Ppb->dwXSize = lpStartupInfo->dwXSize;
1154 Ppb->dwYSize = lpStartupInfo->dwYSize;
1155 Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
1163 * Create Process Environment Block
1165 DPRINT("Creating peb\n");
1167 KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
1169 RtlDestroyProcessParameters (Ppb);
1171 Status = NtSetInformationProcess(hProcess,
1172 ProcessImageFileName,
1176 * Create the thread for the kernel
1178 DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
1179 ImageBaseAddress + (ULONG)Sii.EntryPoint);
1180 hThread = KlCreateFirstThread(hProcess,
1183 ImageBaseAddress + (ULONG)Sii.EntryPoint,
1185 &lpProcessInformation->dwThreadId);
1186 if (hThread == INVALID_HANDLE_VALUE)
1191 lpProcessInformation->hProcess = hProcess;
1192 lpProcessInformation->hThread = hThread;