0164cb4438581afee7ce211c19f7362030391ead
[reactos.git] / reactos / dll / win32 / kernel32 / client / vdm.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/client/vdm.c
5 * PURPOSE: Virtual DOS Machines (VDM) Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* TYPES **********************************************************************/
17
18 #define BINARY_UNKNOWN (0)
19 #define BINARY_PE_EXE32 (1)
20 #define BINARY_PE_DLL32 (2)
21 #define BINARY_PE_EXE64 (3)
22 #define BINARY_PE_DLL64 (4)
23 #define BINARY_WIN16 (5)
24 #define BINARY_OS216 (6)
25 #define BINARY_DOS (7)
26 #define BINARY_UNIX_EXE (8)
27 #define BINARY_UNIX_LIB (9)
28
29
30 typedef enum _ENV_NAME_TYPE
31 {
32 EnvNameNotAPath = 1,
33 EnvNameSinglePath ,
34 EnvNameMultiplePath
35 } ENV_NAME_TYPE;
36
37 typedef struct _ENV_INFO
38 {
39 ENV_NAME_TYPE NameType;
40 ULONG NameLength;
41 PWCHAR Name;
42 } ENV_INFO, *PENV_INFO;
43
44 /* GLOBALS ********************************************************************/
45
46 // NOTE: We cannot use ARRAYSIZE in this macro. GCC would complain otherwise.
47 #define ENV_NAME_ENTRY(type, name) \
48 {(type), (sizeof(name)/sizeof(*((ENV_INFO*)0)->Name)) - 1, (name)}
49
50 static ENV_INFO BasepEnvNameType[] =
51 {
52 ENV_NAME_ENTRY(EnvNameMultiplePath, L"PATH"),
53 ENV_NAME_ENTRY(EnvNameSinglePath , L"WINDIR"),
54 ENV_NAME_ENTRY(EnvNameSinglePath , L"SYSTEMROOT"),
55 ENV_NAME_ENTRY(EnvNameMultiplePath, L"TEMP"),
56 ENV_NAME_ENTRY(EnvNameMultiplePath, L"TMP"),
57 };
58
59 static UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com");
60 static UNICODE_STRING BaseDotPifSuffixName = RTL_CONSTANT_STRING(L".pif");
61 static UNICODE_STRING BaseDotExeSuffixName = RTL_CONSTANT_STRING(L".exe");
62
63 /* FUNCTIONS ******************************************************************/
64
65 ULONG
66 WINAPI
67 BaseIsDosApplication(IN PUNICODE_STRING PathName,
68 IN NTSTATUS Status)
69 {
70 UNICODE_STRING String;
71
72 /* Is it a .com? */
73 String.Length = BaseDotComSuffixName.Length;
74 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
75 if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return BINARY_TYPE_COM;
76
77 /* Is it a .pif? */
78 String.Length = BaseDotPifSuffixName.Length;
79 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
80 if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return BINARY_TYPE_PIF;
81
82 /* Is it an exe? */
83 String.Length = BaseDotExeSuffixName.Length;
84 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
85 if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return BINARY_TYPE_EXE;
86
87 return 0;
88 }
89
90 NTSTATUS
91 WINAPI
92 BaseCheckVDM(IN ULONG BinaryType,
93 IN PCWCH ApplicationName,
94 IN PCWCH CommandLine,
95 IN PCWCH CurrentDirectory,
96 IN PANSI_STRING AnsiEnvironment,
97 IN PBASE_API_MESSAGE ApiMessage,
98 IN OUT PULONG iTask,
99 IN DWORD CreationFlags,
100 IN LPSTARTUPINFOW StartupInfo,
101 IN HANDLE hUserToken OPTIONAL)
102 {
103 NTSTATUS Status;
104 PBASE_CHECK_VDM CheckVdm = &ApiMessage->Data.CheckVDMRequest;
105 PCSR_CAPTURE_BUFFER CaptureBuffer;
106 PWCHAR CurrentDir = NULL;
107 PWCHAR ShortAppName = NULL;
108 PWCHAR ShortCurrentDir = NULL;
109 ULONG Length;
110 PCHAR AnsiCmdLine = NULL;
111 PCHAR AnsiAppName = NULL;
112 PCHAR AnsiCurDirectory = NULL;
113 PCHAR AnsiDesktop = NULL;
114 PCHAR AnsiTitle = NULL;
115 PCHAR AnsiReserved = NULL;
116 STARTUPINFOA AnsiStartupInfo;
117 ULONG NumStrings = 5;
118
119 /* Parameters validation */
120 if (ApplicationName == NULL || CommandLine == NULL)
121 {
122 return STATUS_INVALID_PARAMETER;
123 }
124
125 /* Trim leading whitespace from ApplicationName */
126 while (*ApplicationName == L' ' || *ApplicationName == L'\t')
127 ++ApplicationName;
128
129 /* Calculate the size of the short application name */
130 Length = GetShortPathNameW(ApplicationName, NULL, 0);
131 if (Length == 0)
132 {
133 Status = STATUS_OBJECT_PATH_INVALID;
134 goto Cleanup;
135 }
136
137 /* Allocate memory for the short application name */
138 ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
139 HEAP_ZERO_MEMORY,
140 Length * sizeof(WCHAR));
141 if (!ShortAppName)
142 {
143 Status = STATUS_NO_MEMORY;
144 goto Cleanup;
145 }
146
147 /* Get the short application name */
148 if (GetShortPathNameW(ApplicationName, ShortAppName, Length) == 0)
149 {
150 /* Try to determine which error occurred */
151 switch (GetLastError())
152 {
153 case ERROR_NOT_ENOUGH_MEMORY:
154 {
155 Status = STATUS_NO_MEMORY;
156 break;
157 }
158
159 case ERROR_INVALID_PARAMETER:
160 {
161 Status = STATUS_INVALID_PARAMETER;
162 break;
163 }
164
165 default:
166 {
167 Status = STATUS_OBJECT_PATH_INVALID;
168 }
169 }
170
171 goto Cleanup;
172 }
173
174 /* Trim leading whitespace from CommandLine */
175 while (*CommandLine == L' ' || *CommandLine == L'\t')
176 ++CommandLine;
177
178 /*
179 * CommandLine is usually formatted as: 'ApplicationName param0 ...'.
180 * So we want to strip the first token (ApplicationName) from it.
181 * Two cases are in fact possible:
182 * - either the first token is indeed ApplicationName, so we just skip it;
183 * - or the first token is not exactly ApplicationName, because it happened
184 * that somebody else already preprocessed CommandLine. Therefore we
185 * suppose that the first token corresponds to an application name and
186 * we skip it. Care should be taken when quotes are present in this token.
187 */
188 if (*CommandLine)
189 {
190 /* The first part of CommandLine should be the ApplicationName... */
191 Length = wcslen(ApplicationName);
192 if (Length <= wcslen(CommandLine) &&
193 _wcsnicmp(ApplicationName, CommandLine, Length) == 0)
194 {
195 /* Skip it */
196 CommandLine += Length;
197 }
198 /*
199 * ... but it is not, however we still have a token. We suppose that
200 * it corresponds to some sort of application name, so we skip it too.
201 */
202 else
203 {
204 /* Get rid of the first token. We stop when we see whitespace. */
205 while (*CommandLine && !(*CommandLine == L' ' || *CommandLine == L'\t'))
206 {
207 if (*CommandLine == L'\"')
208 {
209 /* We enter a quoted part, skip it */
210 ++CommandLine;
211 while (*CommandLine && *CommandLine++ != L'\"') ;
212 }
213 else
214 {
215 /* Go to the next character */
216 ++CommandLine;
217 }
218 }
219 }
220 }
221
222 /*
223 * Trim remaining whitespace from CommandLine that may be
224 * present between the application name and the parameters.
225 */
226 while (*CommandLine == L' ' || *CommandLine == L'\t')
227 ++CommandLine;
228
229 /* Get the current directory */
230 if (CurrentDirectory == NULL)
231 {
232 /* Allocate memory for the current directory path */
233 Length = GetCurrentDirectoryW(0, NULL);
234 CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
235 HEAP_ZERO_MEMORY,
236 Length * sizeof(WCHAR));
237 if (CurrentDir == NULL)
238 {
239 Status = STATUS_NO_MEMORY;
240 goto Cleanup;
241 }
242
243 /* Get the current directory */
244 GetCurrentDirectoryW(Length, CurrentDir);
245 CurrentDirectory = CurrentDir;
246 }
247
248 /* Calculate the size of the short current directory path */
249 Length = GetShortPathNameW(CurrentDirectory, NULL, 0);
250
251 /* Allocate memory for the short current directory path */
252 ShortCurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
253 HEAP_ZERO_MEMORY,
254 Length * sizeof(WCHAR));
255 if (!ShortCurrentDir)
256 {
257 Status = STATUS_NO_MEMORY;
258 goto Cleanup;
259 }
260
261 /* Get the short current directory path */
262 if (!GetShortPathNameW(CurrentDirectory, ShortCurrentDir, Length))
263 {
264 /* Try to determine which error occurred */
265 switch (GetLastError())
266 {
267 case ERROR_NOT_ENOUGH_MEMORY:
268 {
269 Status = STATUS_NO_MEMORY;
270 break;
271 }
272
273 case ERROR_INVALID_PARAMETER:
274 {
275 Status = STATUS_INVALID_PARAMETER;
276 break;
277 }
278
279 default:
280 {
281 Status = STATUS_OBJECT_PATH_INVALID;
282 }
283 }
284 goto Cleanup;
285 }
286
287 /* Setup the input parameters */
288 CheckVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
289 CheckVdm->BinaryType = BinaryType;
290 CheckVdm->CodePage = CP_ACP;
291 CheckVdm->dwCreationFlags = CreationFlags;
292 CheckVdm->CurDrive = CurrentDirectory[0] - L'A';
293 CheckVdm->CmdLen = wcslen(CommandLine) + 1;
294 CheckVdm->AppLen = wcslen(ShortAppName) + 1;
295 CheckVdm->PifLen = 0; // TODO: PIF file support!
296 CheckVdm->CurDirectoryLen = wcslen(ShortCurrentDir) + 1;
297 CheckVdm->EnvLen = AnsiEnvironment->Length;
298 CheckVdm->DesktopLen = (StartupInfo->lpDesktop != NULL) ? (wcslen(StartupInfo->lpDesktop) + 1) : 0;
299 CheckVdm->TitleLen = (StartupInfo->lpTitle != NULL) ? (wcslen(StartupInfo->lpTitle) + 1) : 0;
300 CheckVdm->ReservedLen = (StartupInfo->lpReserved != NULL) ? (wcslen(StartupInfo->lpReserved) + 1) : 0;
301
302 if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
303 {
304 /* Set the standard handles */
305 CheckVdm->StdIn = StartupInfo->hStdInput;
306 CheckVdm->StdOut = StartupInfo->hStdOutput;
307 CheckVdm->StdErr = StartupInfo->hStdError;
308 }
309
310 /* Allocate memory for the ANSI strings */
311 // We need to add the newline characters '\r\n' to the command line
312 AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen + 2);
313 AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen);
314 AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen);
315 if (StartupInfo->lpDesktop)
316 AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
317 HEAP_ZERO_MEMORY,
318 CheckVdm->DesktopLen);
319 if (StartupInfo->lpTitle)
320 AnsiTitle = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
321 HEAP_ZERO_MEMORY,
322 CheckVdm->TitleLen);
323 if (StartupInfo->lpReserved)
324 AnsiReserved = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
325 HEAP_ZERO_MEMORY,
326 CheckVdm->ReservedLen);
327
328 if (!AnsiCmdLine
329 || !AnsiAppName
330 || !AnsiCurDirectory
331 || (StartupInfo->lpDesktop && !AnsiDesktop)
332 || (StartupInfo->lpTitle && !AnsiTitle)
333 || (StartupInfo->lpReserved && !AnsiReserved))
334 {
335 Status = STATUS_NO_MEMORY;
336 goto Cleanup;
337 }
338
339 /* Convert the command line into an ANSI string */
340 WideCharToMultiByte(CP_ACP,
341 0,
342 CommandLine,
343 CheckVdm->CmdLen,
344 AnsiCmdLine,
345 CheckVdm->CmdLen,
346 NULL,
347 NULL);
348 /* Add the needed newline and NULL-terminate */
349 CheckVdm->CmdLen--; // Rewind back to the NULL character
350 AnsiCmdLine[CheckVdm->CmdLen++] = '\r';
351 AnsiCmdLine[CheckVdm->CmdLen++] = '\n';
352 AnsiCmdLine[CheckVdm->CmdLen++] = 0;
353
354 /* Convert the short application name into an ANSI string */
355 WideCharToMultiByte(CP_ACP,
356 0,
357 ShortAppName,
358 CheckVdm->AppLen,
359 AnsiAppName,
360 CheckVdm->AppLen,
361 NULL,
362 NULL);
363
364 /* Convert the short current directory path into an ANSI string */
365 WideCharToMultiByte(CP_ACP,
366 0,
367 ShortCurrentDir,
368 CheckVdm->CurDirectoryLen,
369 AnsiCurDirectory,
370 CheckVdm->CurDirectoryLen,
371 NULL,
372 NULL);
373
374 if (StartupInfo->lpDesktop)
375 {
376 /* Convert the desktop name into an ANSI string */
377 WideCharToMultiByte(CP_ACP,
378 0,
379 StartupInfo->lpDesktop,
380 CheckVdm->DesktopLen,
381 AnsiDesktop,
382 CheckVdm->DesktopLen,
383 NULL,
384 NULL);
385 NumStrings++;
386 }
387
388 if (StartupInfo->lpTitle)
389 {
390 /* Convert the title into an ANSI string */
391 WideCharToMultiByte(CP_ACP,
392 0,
393 StartupInfo->lpTitle,
394 CheckVdm->TitleLen,
395 AnsiTitle,
396 CheckVdm->TitleLen,
397 NULL,
398 NULL);
399 NumStrings++;
400 }
401
402 if (StartupInfo->lpReserved)
403 {
404 /* Convert the reserved value into an ANSI string */
405 WideCharToMultiByte(CP_ACP,
406 0,
407 StartupInfo->lpReserved,
408 CheckVdm->ReservedLen,
409 AnsiReserved,
410 CheckVdm->ReservedLen,
411 NULL,
412 NULL);
413 NumStrings++;
414 }
415
416 /* Fill the ANSI startup info structure */
417 RtlCopyMemory(&AnsiStartupInfo, StartupInfo, sizeof(AnsiStartupInfo));
418 AnsiStartupInfo.lpReserved = AnsiReserved;
419 AnsiStartupInfo.lpDesktop = AnsiDesktop;
420 AnsiStartupInfo.lpTitle = AnsiTitle;
421
422 /* Allocate the capture buffer */
423 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings,
424 CheckVdm->CmdLen
425 + CheckVdm->AppLen
426 + CheckVdm->PifLen
427 + CheckVdm->CurDirectoryLen
428 + CheckVdm->DesktopLen
429 + CheckVdm->TitleLen
430 + CheckVdm->ReservedLen
431 + CheckVdm->EnvLen
432 + sizeof(*CheckVdm->StartupInfo));
433 if (CaptureBuffer == NULL)
434 {
435 Status = STATUS_NO_MEMORY;
436 goto Cleanup;
437 }
438
439 /* Capture the command line */
440 CsrCaptureMessageBuffer(CaptureBuffer,
441 AnsiCmdLine,
442 CheckVdm->CmdLen,
443 (PVOID*)&CheckVdm->CmdLine);
444
445 /* Capture the application name */
446 CsrCaptureMessageBuffer(CaptureBuffer,
447 AnsiAppName,
448 CheckVdm->AppLen,
449 (PVOID*)&CheckVdm->AppName);
450
451 CheckVdm->PifFile = NULL; // TODO: PIF file support!
452
453 /* Capture the current directory */
454 CsrCaptureMessageBuffer(CaptureBuffer,
455 AnsiCurDirectory,
456 CheckVdm->CurDirectoryLen,
457 (PVOID*)&CheckVdm->CurDirectory);
458
459 /* Capture the environment */
460 CsrCaptureMessageBuffer(CaptureBuffer,
461 AnsiEnvironment->Buffer,
462 CheckVdm->EnvLen,
463 (PVOID*)&CheckVdm->Env);
464
465 /* Capture the startup info structure */
466 CsrCaptureMessageBuffer(CaptureBuffer,
467 &AnsiStartupInfo,
468 sizeof(*CheckVdm->StartupInfo),
469 (PVOID*)&CheckVdm->StartupInfo);
470
471 if (StartupInfo->lpDesktop)
472 {
473 /* Capture the desktop name */
474 CsrCaptureMessageBuffer(CaptureBuffer,
475 AnsiDesktop,
476 CheckVdm->DesktopLen,
477 (PVOID*)&CheckVdm->Desktop);
478 }
479 else CheckVdm->Desktop = NULL;
480
481 if (StartupInfo->lpTitle)
482 {
483 /* Capture the title */
484 CsrCaptureMessageBuffer(CaptureBuffer,
485 AnsiTitle,
486 CheckVdm->TitleLen,
487 (PVOID*)&CheckVdm->Title);
488 }
489 else CheckVdm->Title = NULL;
490
491 if (StartupInfo->lpReserved)
492 {
493 /* Capture the reserved parameter */
494 CsrCaptureMessageBuffer(CaptureBuffer,
495 AnsiReserved,
496 CheckVdm->ReservedLen,
497 (PVOID*)&CheckVdm->Reserved);
498 }
499 else CheckVdm->Reserved = NULL;
500
501 /* Send the message to CSRSS */
502 Status = CsrClientCallServer((PCSR_API_MESSAGE)ApiMessage,
503 CaptureBuffer,
504 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCheckVDM),
505 sizeof(*CheckVdm));
506
507 /* Write back the task ID */
508 *iTask = CheckVdm->iTask;
509
510 Cleanup:
511
512 /* Free the ANSI strings */
513 if (AnsiCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine);
514 if (AnsiAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName);
515 if (AnsiCurDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory);
516 if (AnsiDesktop) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop);
517 if (AnsiTitle) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle);
518 if (AnsiReserved) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved);
519
520 /* Free the capture buffer */
521 CsrFreeCaptureBuffer(CaptureBuffer);
522
523 /* Free the current directory, if it was allocated here, and its short path */
524 if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir);
525 if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir);
526
527 /* Free the short app name */
528 if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
529
530 return Status;
531 }
532
533 BOOL
534 WINAPI
535 BaseUpdateVDMEntry(IN ULONG UpdateIndex,
536 IN OUT PHANDLE WaitHandle,
537 IN ULONG IndexInfo,
538 IN ULONG BinaryType)
539 {
540 BASE_API_MESSAGE ApiMessage;
541 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
542
543 /* Check what update is being sent */
544 switch (UpdateIndex)
545 {
546 /* VDM is being undone */
547 case VdmEntryUndo:
548 {
549 /* Tell the server how far we had gotten along */
550 UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
551 UpdateVdmEntry->VDMCreationState = IndexInfo;
552 break;
553 }
554
555 /* VDM is ready with a new process handle */
556 case VdmEntryUpdateProcess:
557 {
558 /* Send it the process handle */
559 UpdateVdmEntry->VDMProcessHandle = *WaitHandle;
560 UpdateVdmEntry->iTask = IndexInfo;
561 break;
562 }
563 }
564
565 /* Also check what kind of binary this is for the console handle */
566 if (BinaryType == BINARY_TYPE_WOW)
567 {
568 /* Magic value for 16-bit apps */
569 UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
570 }
571 else if (UpdateVdmEntry->iTask)
572 {
573 /* No handle for true VDM */
574 UpdateVdmEntry->ConsoleHandle = NULL;
575 }
576 else
577 {
578 /* Otherwise, use the regular console handle */
579 UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
580 }
581
582 /* Finally write the index and binary type */
583 UpdateVdmEntry->EntryIndex = UpdateIndex;
584 UpdateVdmEntry->BinaryType = BinaryType;
585
586 /* Send the message to CSRSS */
587 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
588 NULL,
589 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry),
590 sizeof(*UpdateVdmEntry));
591 if (!NT_SUCCESS(ApiMessage.Status))
592 {
593 /* Handle failure */
594 BaseSetLastNTError(ApiMessage.Status);
595 return FALSE;
596 }
597
598 /* If this was an update, CSRSS returns a new wait handle */
599 if (UpdateIndex == VdmEntryUpdateProcess)
600 {
601 /* Return it to the caller */
602 *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
603 }
604
605 /* We made it */
606 return TRUE;
607 }
608
609 BOOL
610 WINAPI
611 BaseCheckForVDM(IN HANDLE ProcessHandle,
612 OUT LPDWORD ExitCode)
613 {
614 NTSTATUS Status;
615 EVENT_BASIC_INFORMATION EventBasicInfo;
616 BASE_API_MESSAGE ApiMessage;
617 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
618
619 /* It's VDM if the process is actually a wait handle (an event) */
620 Status = NtQueryEvent(ProcessHandle,
621 EventBasicInformation,
622 &EventBasicInfo,
623 sizeof(EventBasicInfo),
624 NULL);
625 if (!NT_SUCCESS(Status)) return FALSE;
626
627 /* Setup the input parameters */
628 GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
629 GetVdmExitCode->hParent = ProcessHandle;
630
631 /* Call CSRSS */
632 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
633 NULL,
634 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode),
635 sizeof(*GetVdmExitCode));
636 if (!NT_SUCCESS(Status)) return FALSE;
637
638 /* Get the exit code from the reply */
639 *ExitCode = GetVdmExitCode->ExitCode;
640 return TRUE;
641 }
642
643 BOOL
644 WINAPI
645 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
646 IN ULONG DosSeqId,
647 IN ULONG BinaryType,
648 IN PUNICODE_STRING CmdLineString,
649 OUT PULONG VdmSize)
650 {
651 WCHAR Buffer[MAX_PATH];
652 WCHAR CommandLine[MAX_PATH * 2];
653 ULONG Length;
654
655 /* Clear the buffer in case we fail */
656 CmdLineString->Buffer = 0;
657
658 /* Always return the same size: 16 Mb */
659 *VdmSize = 0x1000000;
660
661 /* Get the system directory */
662 Length = GetSystemDirectoryW(Buffer, MAX_PATH);
663 if (!(Length) || (Length >= MAX_PATH))
664 {
665 /* Eliminate no path or path too big */
666 SetLastError(ERROR_INVALID_NAME);
667 return FALSE;
668 }
669
670 /* Check if this is VDM with a DOS Sequence ID */
671 if (DosSeqId)
672 {
673 /*
674 * Build the VDM string for it:
675 * -i%lx : Gives the DOS Sequence ID;
676 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
677 */
678 _snwprintf(CommandLine,
679 ARRAYSIZE(CommandLine),
680 L"\"%s\\ntvdm.exe\" -i%lx %s%c",
681 Buffer,
682 DosSeqId,
683 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
684 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
685 }
686 else
687 {
688 /*
689 * Build the string for it without the DOS Sequence ID:
690 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
691 */
692 _snwprintf(CommandLine,
693 ARRAYSIZE(CommandLine),
694 L"\"%s\\ntvdm.exe\" %s%c",
695 Buffer,
696 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
697 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
698 }
699
700 /* Create the actual string */
701 return RtlCreateUnicodeString(CmdLineString, CommandLine);
702 }
703
704 ENV_NAME_TYPE
705 WINAPI
706 BaseGetEnvNameType_U(IN PWCHAR Name,
707 IN ULONG NameLength)
708 {
709 PENV_INFO EnvInfo;
710 ENV_NAME_TYPE NameType;
711 ULONG i;
712
713 /* Start by assuming the environment variable doesn't describe paths */
714 NameType = EnvNameNotAPath;
715
716 /* Loop all the environment names */
717 for (i = 0; i < ARRAYSIZE(BasepEnvNameType); i++)
718 {
719 /* Get this entry */
720 EnvInfo = &BasepEnvNameType[i];
721
722 /* Check if it matches the name */
723 if ((EnvInfo->NameLength == NameLength) &&
724 (_wcsnicmp(EnvInfo->Name, Name, NameLength) == 0))
725 {
726 /* It does, return the type */
727 NameType = EnvInfo->NameType;
728 break;
729 }
730 }
731
732 return NameType;
733 }
734
735 BOOL
736 NTAPI
737 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
738 OUT PANSI_STRING AnsiEnv,
739 OUT PUNICODE_STRING UnicodeEnv)
740 {
741 #define IS_ALPHA(x) \
742 ( ((x) >= L'A' && (x) <= L'Z') || ((x) >= L'a' && (x) <= L'z') )
743
744 // From lib/rtl/path.c :
745 // Can be put in some .h ??
746 #define IS_PATH_SEPARATOR(x) ((x) == L'\\' || (x) == L'/')
747
748 BOOL Success = FALSE;
749 NTSTATUS Status;
750 ULONG RegionSize, EnvironmentSize = 0;
751 PWCHAR Environment, NewEnvironment = NULL;
752 ENV_NAME_TYPE NameType;
753 ULONG NameLength, NumChars, Remaining;
754 PWCHAR SourcePtr, DestPtr, StartPtr;
755
756 /* Make sure we have both strings */
757 if (!AnsiEnv || !UnicodeEnv)
758 {
759 /* Fail */
760 SetLastError(ERROR_INVALID_PARAMETER);
761 return FALSE;
762 }
763
764 /* Check if an environment was passed in */
765 if (!lpEnvironment)
766 {
767 /* Nope, create one */
768 Status = RtlCreateEnvironment(TRUE, &Environment);
769 if (!NT_SUCCESS(Status)) goto Cleanup;
770 }
771 else
772 {
773 /* Use the one we got */
774 Environment = lpEnvironment;
775 }
776
777 /* Do we have something now ? */
778 if (!Environment)
779 {
780 /* Still not, bail out */
781 SetLastError(ERROR_BAD_ENVIRONMENT);
782 goto Cleanup;
783 }
784
785 /*
786 * Count how much space the whole environment takes. The environment block is
787 * doubly NULL-terminated (NULL from last string and final NULL terminator).
788 */
789 SourcePtr = Environment;
790 while (!(*SourcePtr++ == UNICODE_NULL && *SourcePtr == UNICODE_NULL))
791 ++EnvironmentSize;
792 EnvironmentSize += 2; // Add the two terminating NULLs
793
794 /*
795 * Allocate a new copy large enough to hold all the environment with paths
796 * in their short form. Since the short form of a path can be a bit longer
797 * than its long form, for example in the case where characters that are
798 * invalid in the 8.3 representation are present in the long path name:
799 * 'C:\\a+b' --> 'C:\\A_B~1', or:
800 * 'C:\\a b' --> 'C:\\AB2761~1' (with checksum inserted),
801 * we suppose that the possible total number of extra characters needed to
802 * convert the long paths into their short form is at most equal to MAX_PATH.
803 */
804 RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR);
805 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
806 (PVOID*)&NewEnvironment,
807 0,
808 &RegionSize,
809 MEM_COMMIT,
810 PAGE_READWRITE);
811 if (!NT_SUCCESS(Status))
812 {
813 /* We failed, bail out */
814 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
815 NewEnvironment = NULL;
816 goto Cleanup;
817 }
818
819 /* Parse the environment block */
820 Remaining = MAX_PATH - 2; // '-2': remove the last two NULLs. FIXME: is it really needed??
821 SourcePtr = Environment;
822 DestPtr = NewEnvironment;
823
824 /* Loop through all the environment strings */
825 while (*SourcePtr != UNICODE_NULL)
826 {
827 /*
828 * 1. Check the type of the environment variable and copy its name.
829 */
830
831 /* Regular environment variable */
832 if (*SourcePtr != L'=')
833 {
834 StartPtr = SourcePtr;
835
836 /* Copy the environment variable name, including the '=' */
837 while (*SourcePtr != UNICODE_NULL)
838 {
839 *DestPtr++ = *SourcePtr;
840 if (*SourcePtr++ == L'=') break;
841 }
842
843 /* Guess the type of the environment variable */
844 NameType = BaseGetEnvNameType_U(StartPtr, SourcePtr - StartPtr - 1);
845 }
846 /* 'Current directory' environment variable (i.e. of '=X:=' form) */
847 else // if (*SourcePtr == L'=')
848 {
849 /* First assume we have a possibly malformed environment variable */
850 NameType = EnvNameNotAPath;
851
852 /* Check for a valid 'Current directory' environment variable */
853 if (IS_ALPHA(SourcePtr[1]) && SourcePtr[2] == L':' && SourcePtr[3] == L'=')
854 {
855 /*
856 * Small optimization: convert the path to short form only if
857 * the current directory is not the root directory (i.e. not
858 * of the '=X:=Y:\' form), otherwise just do a simple copy.
859 */
860 if ( wcslen(SourcePtr) >= ARRAYSIZE("=X:=Y:\\")-1 &&
861 !( IS_ALPHA(SourcePtr[4]) && SourcePtr[5] == L':' &&
862 IS_PATH_SEPARATOR(SourcePtr[6]) && SourcePtr[7] == UNICODE_NULL ) )
863 {
864 NameType = EnvNameSinglePath;
865
866 /* Copy the '=X:=' prefix */
867 *DestPtr++ = SourcePtr[0];
868 *DestPtr++ = SourcePtr[1];
869 *DestPtr++ = SourcePtr[2];
870 *DestPtr++ = SourcePtr[3];
871 SourcePtr += 4;
872 }
873 }
874 else
875 {
876 /*
877 * Invalid stuff starting with '=', i.e.:
878 * =? (with '?' not being a letter)
879 * =X??? (with '?' not being ":=" and not followed by something longer than 3 characters)
880 * =X:=??? (with '?' not being "X:\\")
881 *
882 * 'NameType' is already set to 'EnvNameNotAPath'.
883 */
884 }
885 }
886
887
888 /*
889 * 2. Copy the environment value and perform conversions accordingly.
890 */
891
892 if (NameType == EnvNameNotAPath)
893 {
894 /* Copy everything, including the NULL terminator */
895 do
896 {
897 *DestPtr++ = *SourcePtr;
898 } while (*SourcePtr++ != UNICODE_NULL);
899 }
900 else if (NameType == EnvNameSinglePath)
901 {
902 /* Convert the path to its short form */
903 NameLength = wcslen(SourcePtr);
904 NumChars = GetShortPathNameW(SourcePtr, DestPtr, NameLength + 1 + Remaining);
905 if (NumChars == 0 || NumChars > NameLength + Remaining)
906 {
907 /* If the conversion failed, just copy the original value */
908 RtlCopyMemory(DestPtr, SourcePtr, NameLength * sizeof(WCHAR));
909 NumChars = NameLength;
910 }
911 DestPtr += NumChars;
912 if (NumChars > NameLength)
913 Remaining -= (NumChars - NameLength);
914
915 SourcePtr += NameLength;
916
917 /* Copy the NULL terminator */
918 *DestPtr++ = *SourcePtr++;
919 }
920 else // if (NameType == EnvNameMultiplePath)
921 {
922 WCHAR Delimiter;
923
924 /* Loop through the list of paths (delimited by ';') and convert each path to its short form */
925 do
926 {
927 /* Copy any trailing ';' before going to the next path */
928 while (*SourcePtr == L';')
929 {
930 *DestPtr++ = *SourcePtr++;
931 }
932
933 StartPtr = SourcePtr;
934
935 /* Find the next path list delimiter or the NULL terminator */
936 while (*SourcePtr != UNICODE_NULL && *SourcePtr != L';')
937 {
938 ++SourcePtr;
939 }
940 Delimiter = *SourcePtr;
941
942 NameLength = SourcePtr - StartPtr;
943 if (NameLength)
944 {
945 /*
946 * Temporarily replace the possible path list delimiter by NULL.
947 * 'lpEnvironment' must point to a read+write memory buffer!
948 */
949 *SourcePtr = UNICODE_NULL;
950
951 NumChars = GetShortPathNameW(StartPtr, DestPtr, NameLength + 1 + Remaining);
952 if ( NumChars == 0 ||
953 (Delimiter == L';' ? NumChars > NameLength + Remaining
954 : NumChars > NameLength /* + Remaining ?? */) )
955 {
956 /* If the conversion failed, just copy the original value */
957 RtlCopyMemory(DestPtr, StartPtr, NameLength * sizeof(WCHAR));
958 NumChars = NameLength;
959 }
960 DestPtr += NumChars;
961 if (NumChars > NameLength)
962 Remaining -= (NumChars - NameLength);
963
964 /* If removed, restore the path list delimiter in the source environment value and copy it */
965 if (Delimiter != UNICODE_NULL)
966 {
967 *SourcePtr = Delimiter;
968 *DestPtr++ = *SourcePtr++;
969 }
970 }
971 } while (*SourcePtr != UNICODE_NULL);
972
973 /* Copy the NULL terminator */
974 *DestPtr++ = *SourcePtr++;
975 }
976 }
977
978 /* NULL-terminate the environment block */
979 *DestPtr++ = UNICODE_NULL;
980
981 /* Initialize the Unicode string to hold it */
982 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment,
983 (DestPtr - NewEnvironment) * sizeof(WCHAR));
984 UnicodeEnv->Length = UnicodeEnv->MaximumLength;
985
986 /* Create its ANSI version */
987 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
988 if (!NT_SUCCESS(Status))
989 {
990 /* Set last error if conversion failure */
991 BaseSetLastNTError(Status);
992 }
993 else
994 {
995 /* Everything went okay, so return success */
996 Success = TRUE;
997 NewEnvironment = NULL;
998 }
999
1000 Cleanup:
1001 /* Cleanup path starts here, start by destroying the environment copy */
1002 if (!lpEnvironment && Environment) RtlDestroyEnvironment(Environment);
1003
1004 /* See if we are here due to failure */
1005 if (NewEnvironment)
1006 {
1007 /* Initialize the paths to be empty */
1008 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
1009 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
1010
1011 /* Free the environment copy */
1012 RegionSize = 0;
1013 Status = NtFreeVirtualMemory(NtCurrentProcess(),
1014 (PVOID*)&NewEnvironment,
1015 &RegionSize,
1016 MEM_RELEASE);
1017 ASSERT(NT_SUCCESS(Status));
1018 }
1019
1020 /* Return the result */
1021 return Success;
1022 }
1023
1024 BOOL
1025 NTAPI
1026 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv,
1027 IN PUNICODE_STRING UnicodeEnv)
1028 {
1029 ULONG Dummy = 0;
1030
1031 /* Clear the ANSI buffer since Rtl creates this for us */
1032 if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv);
1033
1034 /* The Unicode buffer is build by hand, though */
1035 if (UnicodeEnv->Buffer)
1036 {
1037 /* So clear it through the API */
1038 NtFreeVirtualMemory(NtCurrentProcess(),
1039 (PVOID*)&UnicodeEnv->Buffer,
1040 &Dummy,
1041 MEM_RELEASE);
1042 }
1043
1044 /* All done */
1045 return TRUE;
1046 }
1047
1048
1049 /* Check whether a file is an OS/2 or a very old Windows executable
1050 * by testing on import of KERNEL.
1051 *
1052 * FIXME: is reading the module imports the only way of discerning
1053 * old Windows binaries from OS/2 ones ? At least it seems so...
1054 */
1055 static DWORD WINAPI
1056 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
1057 {
1058 DWORD CurPos;
1059 LPWORD modtab = NULL;
1060 LPSTR nametab = NULL;
1061 DWORD Read, Ret;
1062 int i;
1063
1064 Ret = BINARY_OS216;
1065 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
1066
1067 /* read modref table */
1068 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
1069 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) ||
1070 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) ||
1071 (Read != (DWORD)ne->ne_cmod * sizeof(WORD)))
1072 {
1073 goto broken;
1074 }
1075
1076 /* read imported names table */
1077 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
1078 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) ||
1079 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) ||
1080 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab))
1081 {
1082 goto broken;
1083 }
1084
1085 for(i = 0; i < ne->ne_cmod; i++)
1086 {
1087 LPSTR module;
1088 module = &nametab[modtab[i]];
1089 if(!strncmp(&module[1], "KERNEL", module[0]))
1090 {
1091 /* very old windows file */
1092 Ret = BINARY_WIN16;
1093 goto done;
1094 }
1095 }
1096
1097 broken:
1098 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
1099
1100 done:
1101 HeapFree(GetProcessHeap(), 0, modtab);
1102 HeapFree(GetProcessHeap(), 0, nametab);
1103 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN);
1104 return Ret;
1105 }
1106
1107 static DWORD WINAPI
1108 InternalGetBinaryType(HANDLE hFile)
1109 {
1110 union
1111 {
1112 struct
1113 {
1114 unsigned char magic[4];
1115 unsigned char ignored[12];
1116 unsigned short type;
1117 } elf;
1118 struct
1119 {
1120 unsigned long magic;
1121 unsigned long cputype;
1122 unsigned long cpusubtype;
1123 unsigned long filetype;
1124 } macho;
1125 IMAGE_DOS_HEADER mz;
1126 } Header;
1127 char magic[4];
1128 DWORD Read;
1129
1130 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
1131 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) ||
1132 (Read != sizeof(Header))))
1133 {
1134 return BINARY_UNKNOWN;
1135 }
1136
1137 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic)))
1138 {
1139 /* FIXME: we don't bother to check byte order, architecture, etc. */
1140 switch(Header.elf.type)
1141 {
1142 case 2:
1143 return BINARY_UNIX_EXE;
1144 case 3:
1145 return BINARY_UNIX_LIB;
1146 }
1147 return BINARY_UNKNOWN;
1148 }
1149
1150 /* Mach-o File with Endian set to Big Endian or Little Endian*/
1151 if(Header.macho.magic == 0xFEEDFACE ||
1152 Header.macho.magic == 0xCEFAEDFE)
1153 {
1154 switch(Header.macho.filetype)
1155 {
1156 case 0x8:
1157 /* MH_BUNDLE */
1158 return BINARY_UNIX_LIB;
1159 }
1160 return BINARY_UNKNOWN;
1161 }
1162
1163 /* Not ELF, try DOS */
1164 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE)
1165 {
1166 /* We do have a DOS image so we will now try to seek into
1167 * the file by the amount indicated by the field
1168 * "Offset to extended header" and read in the
1169 * "magic" field information at that location.
1170 * This will tell us if there is more header information
1171 * to read or not.
1172 */
1173 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
1174 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) ||
1175 (Read != sizeof(magic))))
1176 {
1177 return BINARY_DOS;
1178 }
1179
1180 /* Reading the magic field succeeded so
1181 * we will try to determine what type it is.
1182 */
1183 if(!memcmp(magic, "PE\0\0", sizeof(magic)))
1184 {
1185 IMAGE_FILE_HEADER FileHeader;
1186 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) ||
1187 (Read != sizeof(IMAGE_FILE_HEADER)))
1188 {
1189 return BINARY_DOS;
1190 }
1191
1192 /* FIXME - detect 32/64 bit */
1193
1194 if(FileHeader.Characteristics & IMAGE_FILE_DLL)
1195 return BINARY_PE_DLL32;
1196 return BINARY_PE_EXE32;
1197 }
1198
1199 if(!memcmp(magic, "NE", 2))
1200 {
1201 /* This is a Windows executable (NE) header. This can
1202 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
1203 * DOS program (running under a DOS extender). To decide
1204 * which, we'll have to read the NE header.
1205 */
1206 IMAGE_OS2_HEADER ne;
1207 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) ||
1208 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) ||
1209 (Read != sizeof(IMAGE_OS2_HEADER)))
1210 {
1211 /* Couldn't read header, so abort. */
1212 return BINARY_DOS;
1213 }
1214
1215 switch(ne.ne_exetyp)
1216 {
1217 case 2:
1218 return BINARY_WIN16;
1219 case 5:
1220 return BINARY_DOS;
1221 default:
1222 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne);
1223 }
1224 }
1225 return BINARY_DOS;
1226 }
1227 return BINARY_UNKNOWN;
1228 }
1229
1230 /*
1231 * @implemented
1232 */
1233 BOOL
1234 WINAPI
1235 GetBinaryTypeW (
1236 LPCWSTR lpApplicationName,
1237 LPDWORD lpBinaryType
1238 )
1239 {
1240 HANDLE hFile;
1241 DWORD BinType;
1242
1243 if(!lpApplicationName || !lpBinaryType)
1244 {
1245 SetLastError(ERROR_INVALID_PARAMETER);
1246 return FALSE;
1247 }
1248
1249 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL,
1250 OPEN_EXISTING, 0, 0);
1251 if(hFile == INVALID_HANDLE_VALUE)
1252 {
1253 return FALSE;
1254 }
1255
1256 BinType = InternalGetBinaryType(hFile);
1257 CloseHandle(hFile);
1258
1259 switch(BinType)
1260 {
1261 case BINARY_UNKNOWN:
1262 {
1263 WCHAR *dot;
1264
1265 /*
1266 * guess from filename
1267 */
1268 if(!(dot = wcsrchr(lpApplicationName, L'.')))
1269 {
1270 return FALSE;
1271 }
1272 if(!lstrcmpiW(dot, L".COM"))
1273 {
1274 *lpBinaryType = SCS_DOS_BINARY;
1275 return TRUE;
1276 }
1277 if(!lstrcmpiW(dot, L".PIF"))
1278 {
1279 *lpBinaryType = SCS_PIF_BINARY;
1280 return TRUE;
1281 }
1282 return FALSE;
1283 }
1284 case BINARY_PE_EXE32:
1285 case BINARY_PE_DLL32:
1286 {
1287 *lpBinaryType = SCS_32BIT_BINARY;
1288 return TRUE;
1289 }
1290 case BINARY_PE_EXE64:
1291 case BINARY_PE_DLL64:
1292 {
1293 *lpBinaryType = SCS_64BIT_BINARY;
1294 return TRUE;
1295 }
1296 case BINARY_WIN16:
1297 {
1298 *lpBinaryType = SCS_WOW_BINARY;
1299 return TRUE;
1300 }
1301 case BINARY_OS216:
1302 {
1303 *lpBinaryType = SCS_OS216_BINARY;
1304 return TRUE;
1305 }
1306 case BINARY_DOS:
1307 {
1308 *lpBinaryType = SCS_DOS_BINARY;
1309 return TRUE;
1310 }
1311 case BINARY_UNIX_EXE:
1312 case BINARY_UNIX_LIB:
1313 {
1314 return FALSE;
1315 }
1316 }
1317
1318 DPRINT1("Invalid binary type %lu returned!\n", BinType);
1319 return FALSE;
1320 }
1321
1322 /*
1323 * @implemented
1324 */
1325 BOOL
1326 WINAPI
1327 GetBinaryTypeA(IN LPCSTR lpApplicationName,
1328 OUT LPDWORD lpBinaryType)
1329 {
1330 ANSI_STRING ApplicationNameString;
1331 UNICODE_STRING ApplicationNameW;
1332 BOOL StringAllocated = FALSE, Result;
1333 NTSTATUS Status;
1334
1335 RtlInitAnsiString(&ApplicationNameString, lpApplicationName);
1336
1337 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength)
1338 {
1339 StringAllocated = TRUE;
1340 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE);
1341 }
1342 else
1343 {
1344 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE);
1345 }
1346
1347 if (!NT_SUCCESS(Status))
1348 {
1349 BaseSetLastNTError(Status);
1350 return FALSE;
1351 }
1352
1353 if (StringAllocated)
1354 {
1355 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType);
1356 RtlFreeUnicodeString(&ApplicationNameW);
1357 }
1358 else
1359 {
1360 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
1361 }
1362
1363 return Result;
1364 }
1365
1366 /*
1367 * @unimplemented
1368 */
1369 BOOL
1370 WINAPI
1371 CmdBatNotification (
1372 DWORD Unknown
1373 )
1374 {
1375 STUB;
1376 return FALSE;
1377 }
1378
1379 /*
1380 * @implemented
1381 */
1382 VOID
1383 WINAPI
1384 ExitVDM(BOOL IsWow, ULONG iWowTask)
1385 {
1386 BASE_API_MESSAGE ApiMessage;
1387 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
1388
1389 /* Setup the input parameters */
1390 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1391 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
1392 ExitVdm->WaitObjectForVDM = NULL;
1393
1394 /* Call CSRSS */
1395 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1396 NULL,
1397 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
1398 sizeof(*ExitVdm));
1399
1400 /* Close the returned wait object handle, if any */
1401 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
1402 {
1403 CloseHandle(ExitVdm->WaitObjectForVDM);
1404 }
1405 }
1406
1407 /*
1408 * @implemented
1409 */
1410 BOOL
1411 WINAPI
1412 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
1413 {
1414 BOOL Success = FALSE;
1415 NTSTATUS Status;
1416 BASE_API_MESSAGE ApiMessage;
1417 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
1418 PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
1419 PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest;
1420 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1421 ULONG NumStrings = 0;
1422
1423 /*
1424 * Special case to test whether the VDM is the first one.
1425 */
1426 if (CommandData == NULL)
1427 {
1428 /* Call CSRSS */
1429 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1430 NULL,
1431 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
1432 sizeof(*IsFirstVdm));
1433 if (!NT_SUCCESS(ApiMessage.Status))
1434 {
1435 BaseSetLastNTError(ApiMessage.Status);
1436 return FALSE;
1437 }
1438
1439 /* Return TRUE if this is the first VDM */
1440 return IsFirstVdm->FirstVDM;
1441 }
1442
1443 /* CommandData != NULL */
1444
1445 /*
1446 * Special case to increment or decrement the reentrancy count.
1447 */
1448 if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) ||
1449 (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
1450 {
1451 /* Setup the input parameters */
1452 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1453 SetReenterCount->fIncDec = CommandData->VDMState;
1454
1455 /* Call CSRSS */
1456 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1457 NULL,
1458 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
1459 sizeof(*SetReenterCount));
1460 if (!NT_SUCCESS(ApiMessage.Status))
1461 {
1462 BaseSetLastNTError(ApiMessage.Status);
1463 return FALSE;
1464 }
1465
1466 return TRUE;
1467 }
1468
1469 /*
1470 * TODO!
1471 * Special case to retrieve or set WOW information.
1472 */
1473 // TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK)
1474 // then call BasepGetNextVDMCommand in a simpler way!
1475
1476 /*
1477 * Regular case.
1478 */
1479
1480 /* Clear the structure */
1481 RtlZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
1482
1483 /* Setup the input parameters */
1484 GetNextVdmCommand->iTask = CommandData->TaskId;
1485 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1486 GetNextVdmCommand->CmdLen = CommandData->CmdLen;
1487 GetNextVdmCommand->AppLen = CommandData->AppLen;
1488 GetNextVdmCommand->PifLen = CommandData->PifLen;
1489 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
1490 GetNextVdmCommand->EnvLen = CommandData->EnvLen;
1491 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
1492 GetNextVdmCommand->TitleLen = CommandData->TitleLen;
1493 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
1494 GetNextVdmCommand->VDMState = CommandData->VDMState;
1495
1496 /* Count the number of strings */
1497 if (CommandData->CmdLen) NumStrings++;
1498 if (CommandData->AppLen) NumStrings++;
1499 if (CommandData->PifLen) NumStrings++;
1500 if (CommandData->CurDirectoryLen) NumStrings++;
1501 if (CommandData->EnvLen) NumStrings++;
1502 if (CommandData->DesktopLen) NumStrings++;
1503 if (CommandData->TitleLen) NumStrings++;
1504 if (CommandData->ReservedLen) NumStrings++;
1505
1506 /* Allocate the capture buffer */
1507 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
1508 GetNextVdmCommand->CmdLen
1509 + GetNextVdmCommand->AppLen
1510 + GetNextVdmCommand->PifLen
1511 + GetNextVdmCommand->CurDirectoryLen
1512 + GetNextVdmCommand->EnvLen
1513 + GetNextVdmCommand->DesktopLen
1514 + GetNextVdmCommand->TitleLen
1515 + GetNextVdmCommand->ReservedLen
1516 + sizeof(*GetNextVdmCommand->StartupInfo));
1517 if (CaptureBuffer == NULL)
1518 {
1519 BaseSetLastNTError(STATUS_NO_MEMORY);
1520 goto Cleanup;
1521 }
1522
1523 /* Capture the data */
1524
1525 CsrAllocateMessagePointer(CaptureBuffer,
1526 sizeof(*GetNextVdmCommand->StartupInfo),
1527 (PVOID*)&GetNextVdmCommand->StartupInfo);
1528
1529 if (CommandData->CmdLen)
1530 {
1531 CsrAllocateMessagePointer(CaptureBuffer,
1532 CommandData->CmdLen,
1533 (PVOID*)&GetNextVdmCommand->CmdLine);
1534 }
1535
1536 if (CommandData->AppLen)
1537 {
1538 CsrAllocateMessagePointer(CaptureBuffer,
1539 CommandData->AppLen,
1540 (PVOID*)&GetNextVdmCommand->AppName);
1541 }
1542
1543 if (CommandData->PifLen)
1544 {
1545 CsrAllocateMessagePointer(CaptureBuffer,
1546 CommandData->PifLen,
1547 (PVOID*)&GetNextVdmCommand->PifFile);
1548 }
1549
1550 if (CommandData->CurDirectoryLen)
1551 {
1552 CsrAllocateMessagePointer(CaptureBuffer,
1553 CommandData->CurDirectoryLen,
1554 (PVOID*)&GetNextVdmCommand->CurDirectory);
1555 }
1556
1557 if (CommandData->EnvLen)
1558 {
1559 CsrAllocateMessagePointer(CaptureBuffer,
1560 CommandData->EnvLen,
1561 (PVOID*)&GetNextVdmCommand->Env);
1562 }
1563
1564 if (CommandData->DesktopLen)
1565 {
1566 CsrAllocateMessagePointer(CaptureBuffer,
1567 CommandData->DesktopLen,
1568 (PVOID*)&GetNextVdmCommand->Desktop);
1569 }
1570
1571 if (CommandData->TitleLen)
1572 {
1573 CsrAllocateMessagePointer(CaptureBuffer,
1574 CommandData->TitleLen,
1575 (PVOID*)&GetNextVdmCommand->Title);
1576 }
1577
1578 if (CommandData->ReservedLen)
1579 {
1580 CsrAllocateMessagePointer(CaptureBuffer,
1581 CommandData->ReservedLen,
1582 (PVOID*)&GetNextVdmCommand->Reserved);
1583 }
1584
1585 while (TRUE)
1586 {
1587 /* Call CSRSS */
1588 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1589 CaptureBuffer,
1590 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
1591 sizeof(*GetNextVdmCommand));
1592
1593 /* Exit the waiting loop if we did not receive any event handle */
1594 if (GetNextVdmCommand->WaitObjectForVDM == NULL)
1595 break;
1596
1597 /* Wait for the event to become signaled and try again */
1598 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
1599 FALSE, NULL);
1600 if (Status != STATUS_SUCCESS)
1601 {
1602 /* Fail if we timed out, or if some other error happened */
1603 BaseSetLastNTError(Status);
1604 goto Cleanup;
1605 }
1606
1607 /* Set the retry flag, clear the exit code, and retry a query */
1608 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
1609 GetNextVdmCommand->ExitCode = 0;
1610 }
1611
1612 if (!NT_SUCCESS(Status))
1613 {
1614 if (Status == STATUS_INVALID_PARAMETER)
1615 {
1616 /*
1617 * One of the buffer lengths was less than required. Store the correct ones.
1618 * Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect,
1619 * in order to keep compatibility with Windows 2003 BASESRV.DLL.
1620 */
1621 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1622 CommandData->AppLen = GetNextVdmCommand->AppLen;
1623 CommandData->PifLen = GetNextVdmCommand->PifLen;
1624 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1625 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1626 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1627 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1628 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1629 }
1630 else
1631 {
1632 /* Any other failure */
1633 CommandData->CmdLen = 0;
1634 CommandData->AppLen = 0;
1635 CommandData->PifLen = 0;
1636 CommandData->CurDirectoryLen = 0;
1637 CommandData->EnvLen = 0;
1638 CommandData->DesktopLen = 0;
1639 CommandData->TitleLen = 0;
1640 CommandData->ReservedLen = 0;
1641 }
1642
1643 BaseSetLastNTError(Status);
1644 goto Cleanup;
1645 }
1646
1647 /* Write back the standard handles */
1648 CommandData->StdIn = GetNextVdmCommand->StdIn;
1649 CommandData->StdOut = GetNextVdmCommand->StdOut;
1650 CommandData->StdErr = GetNextVdmCommand->StdErr;
1651
1652 /* Write back the startup info */
1653 RtlMoveMemory(&CommandData->StartupInfo,
1654 GetNextVdmCommand->StartupInfo,
1655 sizeof(*GetNextVdmCommand->StartupInfo));
1656
1657 if (CommandData->CmdLen)
1658 {
1659 /* Write back the command line */
1660 RtlMoveMemory(CommandData->CmdLine,
1661 GetNextVdmCommand->CmdLine,
1662 GetNextVdmCommand->CmdLen);
1663
1664 /* Set the actual length */
1665 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1666 }
1667
1668 if (CommandData->AppLen)
1669 {
1670 /* Write back the application name */
1671 RtlMoveMemory(CommandData->AppName,
1672 GetNextVdmCommand->AppName,
1673 GetNextVdmCommand->AppLen);
1674
1675 /* Set the actual length */
1676 CommandData->AppLen = GetNextVdmCommand->AppLen;
1677 }
1678
1679 if (CommandData->PifLen)
1680 {
1681 /* Write back the PIF file name */
1682 RtlMoveMemory(CommandData->PifFile,
1683 GetNextVdmCommand->PifFile,
1684 GetNextVdmCommand->PifLen);
1685
1686 /* Set the actual length */
1687 CommandData->PifLen = GetNextVdmCommand->PifLen;
1688 }
1689
1690 if (CommandData->CurDirectoryLen)
1691 {
1692 /* Write back the current directory */
1693 RtlMoveMemory(CommandData->CurDirectory,
1694 GetNextVdmCommand->CurDirectory,
1695 GetNextVdmCommand->CurDirectoryLen);
1696
1697 /* Set the actual length */
1698 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1699 }
1700
1701 if (CommandData->EnvLen)
1702 {
1703 /* Write back the environment */
1704 RtlMoveMemory(CommandData->Env,
1705 GetNextVdmCommand->Env,
1706 GetNextVdmCommand->EnvLen);
1707
1708 /* Set the actual length */
1709 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1710 }
1711
1712 if (CommandData->DesktopLen)
1713 {
1714 /* Write back the desktop name */
1715 RtlMoveMemory(CommandData->Desktop,
1716 GetNextVdmCommand->Desktop,
1717 GetNextVdmCommand->DesktopLen);
1718
1719 /* Set the actual length */
1720 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1721 }
1722
1723 if (CommandData->TitleLen)
1724 {
1725 /* Write back the title */
1726 RtlMoveMemory(CommandData->Title,
1727 GetNextVdmCommand->Title,
1728 GetNextVdmCommand->TitleLen);
1729
1730 /* Set the actual length */
1731 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1732 }
1733
1734 if (CommandData->ReservedLen)
1735 {
1736 /* Write back the reserved parameter */
1737 RtlMoveMemory(CommandData->Reserved,
1738 GetNextVdmCommand->Reserved,
1739 GetNextVdmCommand->ReservedLen);
1740
1741 /* Set the actual length */
1742 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1743 }
1744
1745 /* Write the remaining output parameters */
1746 CommandData->TaskId = GetNextVdmCommand->iTask;
1747 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
1748 CommandData->CodePage = GetNextVdmCommand->CodePage;
1749 CommandData->ExitCode = GetNextVdmCommand->ExitCode;
1750 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
1751 CommandData->VDMState = GetNextVdmCommand->VDMState;
1752 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
1753
1754 /* It was successful */
1755 Success = TRUE;
1756
1757 Cleanup:
1758 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
1759 return Success;
1760 }
1761
1762
1763 /*
1764 * @implemented
1765 */
1766 DWORD
1767 WINAPI
1768 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1769 {
1770 BASE_API_MESSAGE ApiMessage;
1771 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1772 PCSR_CAPTURE_BUFFER CaptureBuffer;
1773
1774 /* Allocate the capture buffer */
1775 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1776 if (CaptureBuffer == NULL)
1777 {
1778 BaseSetLastNTError(STATUS_NO_MEMORY);
1779 return 0;
1780 }
1781
1782 /* Setup the input parameters */
1783 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1784 CsrAllocateMessagePointer(CaptureBuffer,
1785 cchCurDirs,
1786 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1787
1788 /* Call CSRSS */
1789 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1790 CaptureBuffer,
1791 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
1792 sizeof(*VDMCurrentDirsRequest));
1793
1794 /* Set the last error */
1795 BaseSetLastNTError(ApiMessage.Status);
1796
1797 if (NT_SUCCESS(ApiMessage.Status))
1798 {
1799 /* Copy the result */
1800 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
1801 }
1802
1803 /* Free the capture buffer */
1804 CsrFreeCaptureBuffer(CaptureBuffer);
1805
1806 /* Return the size if it was successful, or if the buffer was too small */
1807 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
1808 ? VDMCurrentDirsRequest->cchCurDirs : 0;
1809 }
1810
1811
1812 /*
1813 * @implemented (undocumented)
1814 */
1815 BOOL
1816 WINAPI
1817 RegisterConsoleVDM(IN DWORD dwRegisterFlags,
1818 IN HANDLE hStartHardwareEvent,
1819 IN HANDLE hEndHardwareEvent,
1820 IN HANDLE hErrorHardwareEvent,
1821 IN DWORD dwUnusedVar,
1822 OUT LPDWORD lpVideoStateLength,
1823 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
1824 IN PVOID lpUnusedBuffer,
1825 IN DWORD dwUnusedBufferLength,
1826 IN COORD dwVDMBufferSize,
1827 OUT PVOID* lpVDMBuffer)
1828 {
1829 BOOL Success;
1830 CONSOLE_API_MESSAGE ApiMessage;
1831 PCONSOLE_REGISTERVDM RegisterVDMRequest = &ApiMessage.Data.RegisterVDMRequest;
1832 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1833
1834 /* Set up the data to send to the Console Server */
1835 RegisterVDMRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1836 RegisterVDMRequest->RegisterFlags = dwRegisterFlags;
1837
1838 if (dwRegisterFlags != 0)
1839 {
1840 RegisterVDMRequest->StartHardwareEvent = hStartHardwareEvent;
1841 RegisterVDMRequest->EndHardwareEvent = hEndHardwareEvent;
1842 RegisterVDMRequest->ErrorHardwareEvent = hErrorHardwareEvent;
1843
1844 RegisterVDMRequest->VDMBufferSize = dwVDMBufferSize;
1845
1846 #if 0
1847 RegisterVDMRequest->UnusedBufferLength = dwUnusedBufferLength;
1848
1849 /* Allocate a Capture Buffer */
1850 CaptureBuffer = CsrAllocateCaptureBuffer(1, dwUnusedBufferLength);
1851 if (CaptureBuffer == NULL)
1852 {
1853 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1854 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1855 return FALSE;
1856 }
1857
1858 /* Capture the buffer to write */
1859 CsrCaptureMessageBuffer(CaptureBuffer,
1860 (PVOID)lpUnusedBuffer,
1861 dwUnusedBufferLength,
1862 (PVOID*)&RegisterVDMRequest->UnusedBuffer);
1863 #endif
1864 }
1865 else
1866 {
1867 // CaptureBuffer = NULL;
1868 }
1869
1870 /* Call the server */
1871 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1872 CaptureBuffer,
1873 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepRegisterVDM),
1874 sizeof(*RegisterVDMRequest));
1875
1876 /* Check for success */
1877 Success = NT_SUCCESS(ApiMessage.Status);
1878
1879 /* Release the capture buffer if needed */
1880 if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
1881
1882 /* Retrieve the results */
1883 if (Success)
1884 {
1885 if (dwRegisterFlags != 0)
1886 {
1887 _SEH2_TRY
1888 {
1889 *lpVideoStateLength = RegisterVDMRequest->VideoStateLength;
1890 *lpVideoState = RegisterVDMRequest->VideoState;
1891 *lpVDMBuffer = RegisterVDMRequest->VDMBuffer;
1892 }
1893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1894 {
1895 SetLastError(ERROR_INVALID_ACCESS);
1896 Success = FALSE;
1897 }
1898 _SEH2_END;
1899 }
1900 }
1901 else
1902 {
1903 BaseSetLastNTError(ApiMessage.Status);
1904 }
1905
1906 /* Return success status */
1907 return Success;
1908 }
1909
1910
1911 /*
1912 * @unimplemented
1913 */
1914 BOOL
1915 WINAPI
1916 RegisterWowBaseHandlers (
1917 DWORD Unknown0
1918 )
1919 {
1920 STUB;
1921 return FALSE;
1922 }
1923
1924
1925 /*
1926 * @unimplemented
1927 */
1928 BOOL
1929 WINAPI
1930 RegisterWowExec (
1931 DWORD Unknown0
1932 )
1933 {
1934 STUB;
1935 return FALSE;
1936 }
1937
1938
1939 /*
1940 * @implemented
1941 */
1942 BOOL
1943 WINAPI
1944 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1945 {
1946 BASE_API_MESSAGE ApiMessage;
1947 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1948 PCSR_CAPTURE_BUFFER CaptureBuffer;
1949
1950 /* Allocate the capture buffer */
1951 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1952 if (CaptureBuffer == NULL)
1953 {
1954 BaseSetLastNTError(STATUS_NO_MEMORY);
1955 return FALSE;
1956 }
1957
1958 /* Setup the input parameters */
1959 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1960 CsrCaptureMessageBuffer(CaptureBuffer,
1961 lpszzCurDirs,
1962 cchCurDirs,
1963 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1964
1965 /* Call CSRSS */
1966 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1967 CaptureBuffer,
1968 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
1969 sizeof(*VDMCurrentDirsRequest));
1970
1971 /* Free the capture buffer */
1972 CsrFreeCaptureBuffer(CaptureBuffer);
1973
1974 /* Set the last error */
1975 BaseSetLastNTError(ApiMessage.Status);
1976
1977 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
1978 }
1979
1980 /*
1981 * @unimplemented
1982 */
1983 DWORD
1984 WINAPI
1985 VDMConsoleOperation (
1986 DWORD Unknown0,
1987 DWORD Unknown1
1988 )
1989 {
1990 STUB;
1991 return 0;
1992 }
1993
1994
1995 /*
1996 * @unimplemented
1997 */
1998 BOOL
1999 WINAPI
2000 VDMOperationStarted(IN ULONG Unknown0)
2001 {
2002 DPRINT1("VDMOperationStarted(%d)\n", Unknown0);
2003
2004 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
2005 NULL,
2006 0,
2007 Unknown0);
2008 }