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