[KERNEL32]: Code formatting; use the real size of structure members when computing...
[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 NTSTATUS Status;
1415 BOOL Result = FALSE;
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 if (CommandData != NULL)
1424 {
1425 if ((CommandData->VDMState == VDM_INC_REENTER_COUNT)
1426 || (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
1427 {
1428 /* Setup the input parameters */
1429 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1430 SetReenterCount->fIncDec = CommandData->VDMState;
1431
1432 /* Call CSRSS */
1433 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1434 NULL,
1435 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
1436 sizeof(*SetReenterCount));
1437 BaseSetLastNTError(Status);
1438 Result = NT_SUCCESS(Status);
1439 }
1440 else
1441 {
1442 /* Clear the structure */
1443 ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
1444
1445 /* Setup the input parameters */
1446 GetNextVdmCommand->iTask = CommandData->TaskId;
1447 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1448 GetNextVdmCommand->CmdLen = CommandData->CmdLen;
1449 GetNextVdmCommand->AppLen = CommandData->AppLen;
1450 GetNextVdmCommand->PifLen = CommandData->PifLen;
1451 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
1452 GetNextVdmCommand->EnvLen = CommandData->EnvLen;
1453 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
1454 GetNextVdmCommand->TitleLen = CommandData->TitleLen;
1455 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
1456 GetNextVdmCommand->VDMState = CommandData->VDMState;
1457
1458 /* Count the number of strings */
1459 if (CommandData->CmdLen) NumStrings++;
1460 if (CommandData->AppLen) NumStrings++;
1461 if (CommandData->PifLen) NumStrings++;
1462 if (CommandData->CurDirectoryLen) NumStrings++;
1463 if (CommandData->EnvLen) NumStrings++;
1464 if (CommandData->DesktopLen) NumStrings++;
1465 if (CommandData->TitleLen) NumStrings++;
1466 if (CommandData->ReservedLen) NumStrings++;
1467
1468 /* Allocate the capture buffer */
1469 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
1470 GetNextVdmCommand->CmdLen
1471 + GetNextVdmCommand->AppLen
1472 + GetNextVdmCommand->PifLen
1473 + GetNextVdmCommand->CurDirectoryLen
1474 + GetNextVdmCommand->EnvLen
1475 + GetNextVdmCommand->DesktopLen
1476 + GetNextVdmCommand->TitleLen
1477 + GetNextVdmCommand->ReservedLen
1478 + sizeof(STARTUPINFOA));
1479 if (CaptureBuffer == NULL)
1480 {
1481 BaseSetLastNTError(STATUS_NO_MEMORY);
1482 goto Cleanup;
1483 }
1484
1485 /* Allocate memory for the startup info */
1486 CsrAllocateMessagePointer(CaptureBuffer,
1487 sizeof(STARTUPINFOA),
1488 (PVOID*)&GetNextVdmCommand->StartupInfo);
1489
1490 if (CommandData->CmdLen)
1491 {
1492 /* Allocate memory for the command line */
1493 CsrAllocateMessagePointer(CaptureBuffer,
1494 CommandData->CmdLen,
1495 (PVOID*)&GetNextVdmCommand->CmdLine);
1496 }
1497
1498 if (CommandData->AppLen)
1499 {
1500 /* Allocate memory for the application name */
1501 CsrAllocateMessagePointer(CaptureBuffer,
1502 CommandData->AppLen,
1503 (PVOID*)&GetNextVdmCommand->AppName);
1504 }
1505
1506 if (CommandData->PifLen)
1507 {
1508 /* Allocate memory for the PIF file name */
1509 CsrAllocateMessagePointer(CaptureBuffer,
1510 CommandData->PifLen,
1511 (PVOID*)&GetNextVdmCommand->PifFile);
1512 }
1513
1514 if (CommandData->CurDirectoryLen)
1515 {
1516 /* Allocate memory for the current directory */
1517 CsrAllocateMessagePointer(CaptureBuffer,
1518 CommandData->CurDirectoryLen,
1519 (PVOID*)&GetNextVdmCommand->CurDirectory);
1520 }
1521
1522 if (CommandData->EnvLen)
1523 {
1524 /* Allocate memory for the environment */
1525 CsrAllocateMessagePointer(CaptureBuffer,
1526 CommandData->EnvLen,
1527 (PVOID*)&GetNextVdmCommand->Env);
1528 }
1529
1530 if (CommandData->DesktopLen)
1531 {
1532 /* Allocate memory for the desktop name */
1533 CsrAllocateMessagePointer(CaptureBuffer,
1534 CommandData->DesktopLen,
1535 (PVOID*)&GetNextVdmCommand->Desktop);
1536 }
1537
1538 if (CommandData->TitleLen)
1539 {
1540 /* Allocate memory for the title */
1541 CsrAllocateMessagePointer(CaptureBuffer,
1542 CommandData->TitleLen,
1543 (PVOID*)&GetNextVdmCommand->Title);
1544 }
1545
1546 if (CommandData->ReservedLen)
1547 {
1548 /* Allocate memory for the reserved parameter */
1549 CsrAllocateMessagePointer(CaptureBuffer,
1550 CommandData->ReservedLen,
1551 (PVOID*)&GetNextVdmCommand->Reserved);
1552 }
1553
1554 do
1555 {
1556 /* Call CSRSS */
1557 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1558 CaptureBuffer,
1559 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
1560 sizeof(*GetNextVdmCommand));
1561 if (!NT_SUCCESS(Status))
1562 {
1563 /* Store the correct lengths */
1564 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1565 CommandData->AppLen = GetNextVdmCommand->AppLen;
1566 CommandData->PifLen = GetNextVdmCommand->PifLen;
1567 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1568 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1569 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1570 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1571 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1572
1573 BaseSetLastNTError(Status);
1574 goto Cleanup;
1575 }
1576
1577 /* Did we receive an event handle? */
1578 if (GetNextVdmCommand->WaitObjectForVDM != NULL)
1579 {
1580 /* Wait for the event to become signaled and try again */
1581 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
1582 FALSE,
1583 NULL);
1584 if (!NT_SUCCESS(Status))
1585 {
1586 BaseSetLastNTError(Status);
1587 goto Cleanup;
1588 }
1589
1590 /* Set the retry flag and clear the exit code */
1591 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
1592 GetNextVdmCommand->ExitCode = 0;
1593 }
1594 }
1595 while (GetNextVdmCommand->WaitObjectForVDM != NULL);
1596
1597 /* Write back the standard handles */
1598 CommandData->StdIn = GetNextVdmCommand->StdIn;
1599 CommandData->StdOut = GetNextVdmCommand->StdOut;
1600 CommandData->StdErr = GetNextVdmCommand->StdErr;
1601
1602 /* Write back the startup info */
1603 RtlMoveMemory(&CommandData->StartupInfo,
1604 GetNextVdmCommand->StartupInfo,
1605 sizeof(STARTUPINFOA));
1606
1607 if (CommandData->CmdLen)
1608 {
1609 /* Write back the command line */
1610 RtlMoveMemory(CommandData->CmdLine,
1611 GetNextVdmCommand->CmdLine,
1612 GetNextVdmCommand->CmdLen);
1613
1614 /* Set the actual length */
1615 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1616 }
1617
1618 if (CommandData->AppLen)
1619 {
1620 /* Write back the application name */
1621 RtlMoveMemory(CommandData->AppName,
1622 GetNextVdmCommand->AppName,
1623 GetNextVdmCommand->AppLen);
1624
1625 /* Set the actual length */
1626 CommandData->AppLen = GetNextVdmCommand->AppLen;
1627 }
1628
1629 if (CommandData->PifLen)
1630 {
1631 /* Write back the PIF file name */
1632 RtlMoveMemory(CommandData->PifFile,
1633 GetNextVdmCommand->PifFile,
1634 GetNextVdmCommand->PifLen);
1635
1636 /* Set the actual length */
1637 CommandData->PifLen = GetNextVdmCommand->PifLen;
1638 }
1639
1640 if (CommandData->CurDirectoryLen)
1641 {
1642 /* Write back the current directory */
1643 RtlMoveMemory(CommandData->CurDirectory,
1644 GetNextVdmCommand->CurDirectory,
1645 GetNextVdmCommand->CurDirectoryLen);
1646
1647 /* Set the actual length */
1648 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1649 }
1650
1651 if (CommandData->EnvLen)
1652 {
1653 /* Write back the environment */
1654 RtlMoveMemory(CommandData->Env,
1655 GetNextVdmCommand->Env,
1656 GetNextVdmCommand->EnvLen);
1657
1658 /* Set the actual length */
1659 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1660 }
1661
1662 if (CommandData->DesktopLen)
1663 {
1664 /* Write back the desktop name */
1665 RtlMoveMemory(CommandData->Desktop,
1666 GetNextVdmCommand->Desktop,
1667 GetNextVdmCommand->DesktopLen);
1668
1669 /* Set the actual length */
1670 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1671 }
1672
1673 if (CommandData->TitleLen)
1674 {
1675 /* Write back the title */
1676 RtlMoveMemory(CommandData->Title,
1677 GetNextVdmCommand->Title,
1678 GetNextVdmCommand->TitleLen);
1679
1680 /* Set the actual length */
1681 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1682 }
1683
1684 if (CommandData->ReservedLen)
1685 {
1686 /* Write back the reserved parameter */
1687 RtlMoveMemory(CommandData->Reserved,
1688 GetNextVdmCommand->Reserved,
1689 GetNextVdmCommand->ReservedLen);
1690
1691 /* Set the actual length */
1692 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1693 }
1694
1695 /* Write the remaining output parameters */
1696 CommandData->TaskId = GetNextVdmCommand->iTask;
1697 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
1698 CommandData->CodePage = GetNextVdmCommand->CodePage;
1699 CommandData->ExitCode = GetNextVdmCommand->ExitCode;
1700 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
1701 CommandData->VDMState = GetNextVdmCommand->VDMState;
1702 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
1703
1704 /* It was successful */
1705 Result = TRUE;
1706 }
1707 }
1708 else
1709 {
1710 /* Call CSRSS */
1711 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1712 NULL,
1713 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
1714 sizeof(*IsFirstVdm));
1715 if (!NT_SUCCESS(Status))
1716 {
1717 BaseSetLastNTError(Status);
1718 goto Cleanup;
1719 }
1720
1721 /* Return TRUE if this is the first VDM */
1722 Result = IsFirstVdm->FirstVDM;
1723 }
1724
1725 Cleanup:
1726 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
1727 return Result;
1728 }
1729
1730
1731 /*
1732 * @implemented
1733 */
1734 DWORD
1735 WINAPI
1736 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1737 {
1738 BASE_API_MESSAGE ApiMessage;
1739 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1740 PCSR_CAPTURE_BUFFER CaptureBuffer;
1741
1742 /* Allocate the capture buffer */
1743 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1744 if (CaptureBuffer == NULL)
1745 {
1746 BaseSetLastNTError(STATUS_NO_MEMORY);
1747 return 0;
1748 }
1749
1750 /* Setup the input parameters */
1751 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1752 CsrAllocateMessagePointer(CaptureBuffer,
1753 cchCurDirs,
1754 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1755
1756 /* Call CSRSS */
1757 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1758 CaptureBuffer,
1759 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
1760 sizeof(*VDMCurrentDirsRequest));
1761
1762 /* Set the last error */
1763 BaseSetLastNTError(ApiMessage.Status);
1764
1765 if (NT_SUCCESS(ApiMessage.Status))
1766 {
1767 /* Copy the result */
1768 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
1769 }
1770
1771 /* Free the capture buffer */
1772 CsrFreeCaptureBuffer(CaptureBuffer);
1773
1774 /* Return the size if it was successful, or if the buffer was too small */
1775 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
1776 ? VDMCurrentDirsRequest->cchCurDirs : 0;
1777 }
1778
1779
1780 /*
1781 * @implemented (undocumented)
1782 */
1783 BOOL
1784 WINAPI
1785 RegisterConsoleVDM(IN DWORD dwRegisterFlags,
1786 IN HANDLE hStartHardwareEvent,
1787 IN HANDLE hEndHardwareEvent,
1788 IN HANDLE hErrorHardwareEvent,
1789 IN DWORD dwUnusedVar,
1790 OUT LPDWORD lpVideoStateLength,
1791 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
1792 IN PVOID lpUnusedBuffer,
1793 IN DWORD dwUnusedBufferLength,
1794 IN COORD dwVDMBufferSize,
1795 OUT PVOID* lpVDMBuffer)
1796 {
1797 BOOL Success;
1798 CONSOLE_API_MESSAGE ApiMessage;
1799 PCONSOLE_REGISTERVDM RegisterVDMRequest = &ApiMessage.Data.RegisterVDMRequest;
1800 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1801
1802 /* Set up the data to send to the Console Server */
1803 RegisterVDMRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1804 RegisterVDMRequest->RegisterFlags = dwRegisterFlags;
1805
1806 if (dwRegisterFlags != 0)
1807 {
1808 RegisterVDMRequest->StartHardwareEvent = hStartHardwareEvent;
1809 RegisterVDMRequest->EndHardwareEvent = hEndHardwareEvent;
1810 RegisterVDMRequest->ErrorHardwareEvent = hErrorHardwareEvent;
1811
1812 RegisterVDMRequest->VDMBufferSize = dwVDMBufferSize;
1813
1814 #if 0
1815 RegisterVDMRequest->UnusedBufferLength = dwUnusedBufferLength;
1816
1817 /* Allocate a Capture Buffer */
1818 CaptureBuffer = CsrAllocateCaptureBuffer(1, dwUnusedBufferLength);
1819 if (CaptureBuffer == NULL)
1820 {
1821 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1822 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1823 return FALSE;
1824 }
1825
1826 /* Capture the buffer to write */
1827 CsrCaptureMessageBuffer(CaptureBuffer,
1828 (PVOID)lpUnusedBuffer,
1829 dwUnusedBufferLength,
1830 (PVOID*)&RegisterVDMRequest->UnusedBuffer);
1831 #endif
1832 }
1833 else
1834 {
1835 // CaptureBuffer = NULL;
1836 }
1837
1838 /* Call the server */
1839 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1840 CaptureBuffer,
1841 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepRegisterVDM),
1842 sizeof(*RegisterVDMRequest));
1843
1844 /* Check for success */
1845 Success = NT_SUCCESS(ApiMessage.Status);
1846
1847 /* Release the capture buffer if needed */
1848 if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
1849
1850 /* Retrieve the results */
1851 if (Success)
1852 {
1853 if (dwRegisterFlags != 0)
1854 {
1855 _SEH2_TRY
1856 {
1857 *lpVideoStateLength = RegisterVDMRequest->VideoStateLength;
1858 *lpVideoState = RegisterVDMRequest->VideoState;
1859 *lpVDMBuffer = RegisterVDMRequest->VDMBuffer;
1860 }
1861 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1862 {
1863 SetLastError(ERROR_INVALID_ACCESS);
1864 Success = FALSE;
1865 }
1866 _SEH2_END;
1867 }
1868 }
1869 else
1870 {
1871 BaseSetLastNTError(ApiMessage.Status);
1872 }
1873
1874 /* Return success status */
1875 return Success;
1876 }
1877
1878
1879 /*
1880 * @unimplemented
1881 */
1882 BOOL
1883 WINAPI
1884 RegisterWowBaseHandlers (
1885 DWORD Unknown0
1886 )
1887 {
1888 STUB;
1889 return FALSE;
1890 }
1891
1892
1893 /*
1894 * @unimplemented
1895 */
1896 BOOL
1897 WINAPI
1898 RegisterWowExec (
1899 DWORD Unknown0
1900 )
1901 {
1902 STUB;
1903 return FALSE;
1904 }
1905
1906
1907 /*
1908 * @implemented
1909 */
1910 BOOL
1911 WINAPI
1912 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1913 {
1914 BASE_API_MESSAGE ApiMessage;
1915 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1916 PCSR_CAPTURE_BUFFER CaptureBuffer;
1917
1918 /* Allocate the capture buffer */
1919 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1920 if (CaptureBuffer == NULL)
1921 {
1922 BaseSetLastNTError(STATUS_NO_MEMORY);
1923 return FALSE;
1924 }
1925
1926 /* Setup the input parameters */
1927 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1928 CsrCaptureMessageBuffer(CaptureBuffer,
1929 lpszzCurDirs,
1930 cchCurDirs,
1931 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1932
1933 /* Call CSRSS */
1934 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1935 CaptureBuffer,
1936 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
1937 sizeof(*VDMCurrentDirsRequest));
1938
1939 /* Free the capture buffer */
1940 CsrFreeCaptureBuffer(CaptureBuffer);
1941
1942 /* Set the last error */
1943 BaseSetLastNTError(ApiMessage.Status);
1944
1945 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
1946 }
1947
1948 /*
1949 * @unimplemented
1950 */
1951 DWORD
1952 WINAPI
1953 VDMConsoleOperation (
1954 DWORD Unknown0,
1955 DWORD Unknown1
1956 )
1957 {
1958 STUB;
1959 return 0;
1960 }
1961
1962
1963 /*
1964 * @unimplemented
1965 */
1966 BOOL
1967 WINAPI
1968 VDMOperationStarted(IN ULONG Unknown0)
1969 {
1970 DPRINT1("VDMOperationStarted(%d)\n", Unknown0);
1971
1972 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
1973 NULL,
1974 0,
1975 Unknown0);
1976 }