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