xref: /reactos/dll/win32/kernel32/client/vdm.c (revision 9393fc32)
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