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