2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/vdm.c
5 * PURPOSE: Virtual DOS Machines (VDM) Support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
10 /* INCLUDES *******************************************************************/
18 /* GLOBALS ********************************************************************/
20 BOOLEAN FirstVDM
= TRUE
;
21 LIST_ENTRY VDMConsoleListHead
;
22 RTL_CRITICAL_SECTION DosCriticalSection
;
23 RTL_CRITICAL_SECTION WowCriticalSection
;
25 /* HELPER FUNCTIONS ***********************************************************/
27 PVDM_CONSOLE_RECORD
BaseSrvCreateConsoleRecord(VOID
)
29 PVDM_CONSOLE_RECORD ConsoleRecord
;
31 ConsoleRecord
= RtlAllocateHeap(BaseSrvHeap
, HEAP_ZERO_MEMORY
,
32 sizeof(VDM_CONSOLE_RECORD
));
33 if (ConsoleRecord
== NULL
)
36 /* Initialize the console record */
37 ConsoleRecord
->ConsoleHandle
= NULL
;
38 ConsoleRecord
->ProcessHandle
= NULL
;
39 ConsoleRecord
->ServerEvent
= ConsoleRecord
->ClientEvent
= NULL
;
40 ConsoleRecord
->ReenterCount
= 0;
41 ConsoleRecord
->CurrentDirs
= NULL
;
42 ConsoleRecord
->CurDirsLength
= 0;
43 ConsoleRecord
->SessionId
= 0;
44 InitializeListHead(&ConsoleRecord
->DosListHead
);
49 NTSTATUS
BaseSrvGetConsoleRecord(HANDLE ConsoleHandle
, PVDM_CONSOLE_RECORD
*Record
)
52 PVDM_CONSOLE_RECORD CurrentRecord
= NULL
;
54 /* NULL is not a valid console handle */
55 if (ConsoleHandle
== NULL
) return STATUS_INVALID_PARAMETER
;
57 /* Search for a record that has the same console handle */
58 for (i
= VDMConsoleListHead
.Flink
; i
!= &VDMConsoleListHead
; i
= i
->Flink
)
60 CurrentRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
61 if (CurrentRecord
->ConsoleHandle
== ConsoleHandle
) break;
64 /* Check if nothing was found */
65 if (i
== &VDMConsoleListHead
) CurrentRecord
= NULL
;
67 *Record
= CurrentRecord
;
68 return CurrentRecord
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
71 VOID
BaseSrvDestroyConsoleRecord(PVDM_CONSOLE_RECORD ConsoleRecord
)
73 if (ConsoleRecord
->CurrentDirs
!= NULL
)
75 /* Free the current directories */
76 RtlFreeHeap(BaseSrvHeap
, 0, ConsoleRecord
->CurrentDirs
);
77 ConsoleRecord
->CurrentDirs
= NULL
;
78 ConsoleRecord
->CurDirsLength
= 0;
81 /* Close the process handle */
82 if (ConsoleRecord
->ProcessHandle
)
83 NtClose(ConsoleRecord
->ProcessHandle
);
85 /* Close the event handle */
86 if (ConsoleRecord
->ServerEvent
)
87 NtClose(ConsoleRecord
->ServerEvent
);
89 /* Remove the console record */
90 // RemoveEntryList(&ConsoleRecord->Entry);
91 RtlFreeHeap(BaseSrvHeap
, 0, ConsoleRecord
);
95 NTSTATUS
GetConsoleRecordBySessionId(ULONG TaskId
, PVDM_CONSOLE_RECORD
*Record
)
98 PVDM_CONSOLE_RECORD CurrentRecord
= NULL
;
100 /* Search for a record that has the same console handle */
101 for (i
= VDMConsoleListHead
.Flink
; i
!= &VDMConsoleListHead
; i
= i
->Flink
)
103 CurrentRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
104 if (CurrentRecord
->SessionId
== TaskId
) break;
107 /* Check if nothing was found */
108 if (i
== &VDMConsoleListHead
) CurrentRecord
= NULL
;
110 *Record
= CurrentRecord
;
111 return CurrentRecord
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
114 ULONG
GetNextDosSesId(VOID
)
118 PVDM_CONSOLE_RECORD CurrentRecord
= NULL
;
121 /* Search for an available session ID */
122 for (SessionId
= 1; SessionId
!= 0; SessionId
++)
126 /* Check if the ID is already in use */
127 for (i
= VDMConsoleListHead
.Flink
; i
!= &VDMConsoleListHead
; i
= i
->Flink
)
129 CurrentRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
130 if (CurrentRecord
->SessionId
== SessionId
) Found
= TRUE
;
133 /* If not, we found one */
137 ASSERT(SessionId
!= 0);
139 /* Return the session ID */
143 BOOLEAN
BaseSrvIsVdmAllowed(VOID
)
146 BOOLEAN VdmAllowed
= TRUE
;
147 HANDLE RootKey
, KeyHandle
;
148 UNICODE_STRING KeyName
, ValueName
, MachineKeyName
;
149 OBJECT_ATTRIBUTES Attributes
;
150 UCHAR ValueBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
151 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
154 /* Initialize the unicode strings */
155 RtlInitUnicodeString(&MachineKeyName
, L
"\\Registry\\Machine");
156 RtlInitUnicodeString(&KeyName
, VDM_POLICY_KEY_NAME
);
157 RtlInitUnicodeString(&ValueName
, VDM_DISALLOWED_VALUE_NAME
);
159 InitializeObjectAttributes(&Attributes
,
161 OBJ_CASE_INSENSITIVE
,
165 /* Open the local machine key */
166 Status
= NtOpenKey(&RootKey
, KEY_READ
, &Attributes
);
167 if (!NT_SUCCESS(Status
)) return FALSE
;
169 InitializeObjectAttributes(&Attributes
,
171 OBJ_CASE_INSENSITIVE
,
175 /* Open the policy key in the local machine hive, if it exists */
176 if (NT_SUCCESS(NtOpenKey(&KeyHandle
, KEY_READ
, &Attributes
)))
178 /* Read the value, if it's set */
179 if (NT_SUCCESS(NtQueryValueKey(KeyHandle
,
181 KeyValuePartialInformation
,
186 if (*((PULONG
)ValueInfo
->Data
))
188 /* The VDM has been disabled in the registry */
196 /* Close the local machine key */
199 /* If it's disabled system-wide, there's no need to check the user key */
200 if (!VdmAllowed
) return FALSE
;
202 /* Open the current user key of the client */
203 if (!CsrImpersonateClient(NULL
)) return VdmAllowed
;
204 Status
= RtlOpenCurrentUser(KEY_READ
, &RootKey
);
207 /* If that fails, return the system-wide setting */
208 if (!NT_SUCCESS(Status
)) return VdmAllowed
;
210 InitializeObjectAttributes(&Attributes
,
212 OBJ_CASE_INSENSITIVE
,
216 /* Open the policy key in the current user hive, if it exists */
217 if (NT_SUCCESS(NtOpenKey(&KeyHandle
, KEY_READ
, &Attributes
)))
219 /* Read the value, if it's set */
220 if (NT_SUCCESS(NtQueryValueKey(KeyHandle
,
222 KeyValuePartialInformation
,
227 if (*((PULONG
)ValueInfo
->Data
))
229 /* The VDM has been disabled in the registry */
240 NTSTATUS
BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent
, PHANDLE ClientEvent
)
244 /* Create the event */
245 Status
= NtCreateEvent(ServerEvent
, EVENT_ALL_ACCESS
, NULL
, NotificationEvent
, FALSE
);
246 if (!NT_SUCCESS(Status
)) return Status
;
248 /* Duplicate the event into the client process */
249 Status
= NtDuplicateObject(NtCurrentProcess(),
251 CsrGetClientThread()->Process
->ProcessHandle
,
255 DUPLICATE_SAME_ATTRIBUTES
| DUPLICATE_SAME_ACCESS
);
257 if (!NT_SUCCESS(Status
)) NtClose(*ServerEvent
);
261 VOID
BaseSrvDestroyPairWaitHandles(HANDLE ServerEvent
, HANDLE ClientEvent
)
263 if (ServerEvent
) NtClose(ServerEvent
);
266 /* Close the remote handle */
267 NtDuplicateObject(CsrGetClientThread()->Process
->ProcessHandle
,
273 DUPLICATE_CLOSE_SOURCE
);
277 /* WOW SUPPORT FUNCTIONS ******************************************************/
279 /* DOS SUPPORT FUNCTIONS ******************************************************/
281 VOID
BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo
)
283 /* Free the allocated structure members */
284 if (CommandInfo
->CmdLine
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->CmdLine
);
285 if (CommandInfo
->AppName
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->AppName
);
286 if (CommandInfo
->PifFile
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->PifFile
);
287 if (CommandInfo
->CurDirectory
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->CurDirectory
);
288 if (CommandInfo
->Env
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->Env
);
289 if (CommandInfo
->Desktop
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->Desktop
);
290 if (CommandInfo
->Title
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->Title
);
291 if (CommandInfo
->Reserved
!= NULL
) RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
->Reserved
);
293 /* Free the structure itself */
294 RtlFreeHeap(BaseSrvHeap
, 0, CommandInfo
);
297 VOID
BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess
)
299 ULONG ProcessId
= HandleToUlong(CsrProcess
->ClientId
.UniqueProcess
);
300 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
301 PVDM_DOS_RECORD DosRecord
;
304 /* Enter the critical section */
305 RtlEnterCriticalSection(&DosCriticalSection
);
307 /* Search for a record that has the same process handle */
308 i
= VDMConsoleListHead
.Flink
;
309 while (i
!= &VDMConsoleListHead
)
311 ConsoleRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
314 if (ConsoleRecord
->ProcessId
== ProcessId
)
316 if (ConsoleRecord
->ServerEvent
)
318 NtClose(ConsoleRecord
->ServerEvent
);
319 ConsoleRecord
->ServerEvent
= NULL
;
322 /* Cleanup the DOS records */
323 while (!IsListEmpty(&ConsoleRecord
->DosListHead
))
325 DosRecord
= CONTAINING_RECORD(ConsoleRecord
->DosListHead
.Flink
,
326 VDM_DOS_RECORD
, Entry
);
328 /* Set the event and close it */
329 if (DosRecord
->ServerEvent
)
331 NtSetEvent(DosRecord
->ServerEvent
, NULL
);
332 NtClose(DosRecord
->ServerEvent
);
333 DosRecord
->ServerEvent
= NULL
;
336 /* Remove the DOS entry */
337 if (DosRecord
->CommandInfo
) BaseSrvFreeVDMInfo(DosRecord
->CommandInfo
);
338 RemoveEntryList(&DosRecord
->Entry
);
339 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
342 /* Remove the console record */
343 RemoveEntryList(&ConsoleRecord
->Entry
);
344 BaseSrvDestroyConsoleRecord(ConsoleRecord
);
348 /* Leave the critical section */
349 RtlLeaveCriticalSection(&DosCriticalSection
);
352 BOOLEAN
BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest
, PVDM_DOS_RECORD DosRecord
)
354 BOOLEAN Success
= FALSE
;
355 PVDM_COMMAND_INFO CommandInfo
= NULL
;
357 /* Allocate the command information structure */
358 CommandInfo
= (PVDM_COMMAND_INFO
)RtlAllocateHeap(BaseSrvHeap
,
360 sizeof(VDM_COMMAND_INFO
));
361 if (CommandInfo
== NULL
) return FALSE
;
363 /* Fill the structure */
364 CommandInfo
->TaskId
= CheckVdmRequest
->iTask
;
365 CommandInfo
->ExitCode
= DosRecord
->ExitCode
;
366 CommandInfo
->CodePage
= CheckVdmRequest
->CodePage
;
367 CommandInfo
->StdIn
= CheckVdmRequest
->StdIn
;
368 CommandInfo
->StdOut
= CheckVdmRequest
->StdOut
;
369 CommandInfo
->StdErr
= CheckVdmRequest
->StdErr
;
371 /* Allocate memory for the command line */
372 CommandInfo
->CmdLine
= RtlAllocateHeap(BaseSrvHeap
,
374 CheckVdmRequest
->CmdLen
);
375 if (CommandInfo
->CmdLine
== NULL
) goto Cleanup
;
377 /* Copy the command line */
378 RtlMoveMemory(CommandInfo
->CmdLine
, CheckVdmRequest
->CmdLine
, CheckVdmRequest
->CmdLen
);
380 /* Allocate memory for the application name */
381 CommandInfo
->AppName
= RtlAllocateHeap(BaseSrvHeap
,
383 CheckVdmRequest
->AppLen
);
384 if (CommandInfo
->AppName
== NULL
) goto Cleanup
;
386 /* Copy the application name */
387 RtlMoveMemory(CommandInfo
->AppName
, CheckVdmRequest
->AppName
, CheckVdmRequest
->AppLen
);
389 /* Allocate memory for the PIF file name */
390 if (CheckVdmRequest
->PifLen
!= 0)
392 CommandInfo
->PifFile
= RtlAllocateHeap(BaseSrvHeap
,
394 CheckVdmRequest
->PifLen
);
395 if (CommandInfo
->PifFile
== NULL
) goto Cleanup
;
397 /* Copy the PIF file name */
398 RtlMoveMemory(CommandInfo
->PifFile
, CheckVdmRequest
->PifFile
, CheckVdmRequest
->PifLen
);
400 else CommandInfo
->PifFile
= NULL
;
402 /* Allocate memory for the current directory */
403 if (CheckVdmRequest
->CurDirectoryLen
!= 0)
405 CommandInfo
->CurDirectory
= RtlAllocateHeap(BaseSrvHeap
,
407 CheckVdmRequest
->CurDirectoryLen
);
408 if (CommandInfo
->CurDirectory
== NULL
) goto Cleanup
;
410 /* Copy the current directory */
411 RtlMoveMemory(CommandInfo
->CurDirectory
,
412 CheckVdmRequest
->CurDirectory
,
413 CheckVdmRequest
->CurDirectoryLen
);
415 else CommandInfo
->CurDirectory
= NULL
;
417 /* Allocate memory for the environment block */
418 CommandInfo
->Env
= RtlAllocateHeap(BaseSrvHeap
,
420 CheckVdmRequest
->EnvLen
);
421 if (CommandInfo
->Env
== NULL
) goto Cleanup
;
423 /* Copy the environment block */
424 RtlMoveMemory(CommandInfo
->Env
, CheckVdmRequest
->Env
, CheckVdmRequest
->EnvLen
);
426 CommandInfo
->EnvLen
= CheckVdmRequest
->EnvLen
;
427 RtlMoveMemory(&CommandInfo
->StartupInfo
,
428 CheckVdmRequest
->StartupInfo
,
429 sizeof(STARTUPINFOA
));
431 /* Allocate memory for the desktop */
432 if (CheckVdmRequest
->DesktopLen
!= 0)
434 CommandInfo
->Desktop
= RtlAllocateHeap(BaseSrvHeap
,
436 CheckVdmRequest
->DesktopLen
);
437 if (CommandInfo
->Desktop
== NULL
) goto Cleanup
;
439 /* Copy the desktop name */
440 RtlMoveMemory(CommandInfo
->Desktop
, CheckVdmRequest
->Desktop
, CheckVdmRequest
->DesktopLen
);
442 else CommandInfo
->Desktop
= NULL
;
444 CommandInfo
->DesktopLen
= CheckVdmRequest
->DesktopLen
;
446 /* Allocate memory for the title */
447 if (CheckVdmRequest
->TitleLen
!= 0)
449 CommandInfo
->Title
= RtlAllocateHeap(BaseSrvHeap
,
451 CheckVdmRequest
->TitleLen
);
452 if (CommandInfo
->Title
== NULL
) goto Cleanup
;
455 RtlMoveMemory(CommandInfo
->Title
, CheckVdmRequest
->Title
, CheckVdmRequest
->TitleLen
);
457 else CommandInfo
->Title
= NULL
;
459 CommandInfo
->TitleLen
= CheckVdmRequest
->TitleLen
;
461 /* Allocate memory for the reserved field */
462 if (CheckVdmRequest
->ReservedLen
!= 0)
464 CommandInfo
->Reserved
= RtlAllocateHeap(BaseSrvHeap
,
466 CheckVdmRequest
->ReservedLen
);
467 if (CommandInfo
->Reserved
== NULL
) goto Cleanup
;
469 /* Copy the reserved field */
470 RtlMoveMemory(CommandInfo
->Reserved
,
471 CheckVdmRequest
->Reserved
,
472 CheckVdmRequest
->ReservedLen
);
474 else CommandInfo
->Reserved
= NULL
;
476 CommandInfo
->ReservedLen
= CheckVdmRequest
->ReservedLen
;
478 CommandInfo
->CmdLen
= CheckVdmRequest
->CmdLen
;
479 CommandInfo
->AppLen
= CheckVdmRequest
->AppLen
;
480 CommandInfo
->PifLen
= CheckVdmRequest
->PifLen
;
481 CommandInfo
->CurDirectoryLen
= CheckVdmRequest
->CurDirectoryLen
;
482 CommandInfo
->VDMState
= DosRecord
->State
;
483 // TODO: Set CommandInfo->CurrentDrive
484 // TODO: Set CommandInfo->ComingFromBat
486 /* Set the DOS record's command structure */
487 DosRecord
->CommandInfo
= CommandInfo
;
489 /* The operation was successful */
493 /* If it wasn't successful, free the memory */
494 if (!Success
) BaseSrvFreeVDMInfo(CommandInfo
);
499 NTSTATUS
BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo
,
500 PBASE_GET_NEXT_VDM_COMMAND Message
)
502 NTSTATUS Status
= STATUS_SUCCESS
;
505 Message
->iTask
= CommandInfo
->TaskId
;
506 Message
->StdIn
= CommandInfo
->StdIn
;
507 Message
->StdOut
= CommandInfo
->StdOut
;
508 Message
->StdErr
= CommandInfo
->StdErr
;
509 Message
->CodePage
= CommandInfo
->CodePage
;
510 Message
->dwCreationFlags
= CommandInfo
->CreationFlags
;
511 Message
->ExitCode
= CommandInfo
->ExitCode
;
512 Message
->CurrentDrive
= CommandInfo
->CurrentDrive
;
513 Message
->VDMState
= CommandInfo
->VDMState
;
514 Message
->fComingFromBat
= CommandInfo
->ComingFromBat
;
516 if (Message
->CmdLen
>= CommandInfo
->CmdLen
)
518 /* Copy the command line */
519 RtlMoveMemory(Message
->CmdLine
, CommandInfo
->CmdLine
, CommandInfo
->CmdLen
);
521 else Status
= STATUS_INVALID_PARAMETER
;
522 Message
->CmdLen
= CommandInfo
->CmdLen
;
524 if (Message
->AppLen
>= CommandInfo
->AppLen
)
526 /* Copy the application name */
527 RtlMoveMemory(Message
->AppName
, CommandInfo
->AppName
, CommandInfo
->AppLen
);
529 else Status
= STATUS_INVALID_PARAMETER
;
530 Message
->AppLen
= CommandInfo
->AppLen
;
532 if (Message
->PifLen
>= CommandInfo
->PifLen
)
534 /* Copy the PIF file name */
535 RtlMoveMemory(Message
->PifFile
, CommandInfo
->PifFile
, CommandInfo
->PifLen
);
537 else Status
= STATUS_INVALID_PARAMETER
;
538 Message
->PifLen
= CommandInfo
->PifLen
;
540 if (Message
->CurDirectoryLen
>= CommandInfo
->CurDirectoryLen
)
542 /* Copy the current directory */
543 RtlMoveMemory(Message
->CurDirectory
, CommandInfo
->CurDirectory
, CommandInfo
->CurDirectoryLen
);
545 else Status
= STATUS_INVALID_PARAMETER
;
546 Message
->CurDirectoryLen
= CommandInfo
->CurDirectoryLen
;
548 if (Message
->EnvLen
>= CommandInfo
->EnvLen
)
550 /* Copy the environment */
551 RtlMoveMemory(Message
->Env
, CommandInfo
->Env
, CommandInfo
->EnvLen
);
553 else Status
= STATUS_INVALID_PARAMETER
;
554 Message
->EnvLen
= CommandInfo
->EnvLen
;
556 /* Copy the startup info */
557 RtlMoveMemory(Message
->StartupInfo
,
558 &CommandInfo
->StartupInfo
,
559 sizeof(STARTUPINFOA
));
561 if (Message
->DesktopLen
>= CommandInfo
->DesktopLen
)
563 /* Copy the desktop name */
564 RtlMoveMemory(Message
->Desktop
, CommandInfo
->Desktop
, CommandInfo
->DesktopLen
);
566 else Status
= STATUS_INVALID_PARAMETER
;
567 Message
->DesktopLen
= CommandInfo
->DesktopLen
;
569 if (Message
->TitleLen
>= CommandInfo
->TitleLen
)
572 RtlMoveMemory(Message
->Title
, CommandInfo
->Title
, CommandInfo
->TitleLen
);
574 else Status
= STATUS_INVALID_PARAMETER
;
575 Message
->TitleLen
= CommandInfo
->TitleLen
;
577 if (Message
->ReservedLen
>= CommandInfo
->ReservedLen
)
579 /* Copy the reserved parameter */
580 RtlMoveMemory(Message
->Reserved
, CommandInfo
->Reserved
, CommandInfo
->ReservedLen
);
582 else Status
= STATUS_INVALID_PARAMETER
;
583 Message
->ReservedLen
= CommandInfo
->ReservedLen
;
588 VOID
BaseInitializeVDM(VOID
)
590 /* Initialize the list head */
591 InitializeListHead(&VDMConsoleListHead
);
593 /* Initialize the critical sections */
594 RtlInitializeCriticalSection(&DosCriticalSection
);
595 RtlInitializeCriticalSection(&WowCriticalSection
);
598 /* PUBLIC SERVER APIS *********************************************************/
600 CSR_API(BaseSrvCheckVDM
)
603 PBASE_CHECK_VDM CheckVdmRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.CheckVDMRequest
;
604 PRTL_CRITICAL_SECTION CriticalSection
= NULL
;
605 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
606 PVDM_DOS_RECORD DosRecord
= NULL
;
607 BOOLEAN NewConsoleRecord
= FALSE
;
608 BOOLEAN NewDosRecord
= FALSE
;
610 /* Don't do anything if the VDM has been disabled in the registry */
611 if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED
;
613 /* Validate the message buffers */
614 if (!CsrValidateMessageBuffer(ApiMessage
,
615 (PVOID
*)&CheckVdmRequest
->CmdLine
,
616 CheckVdmRequest
->CmdLen
,
617 sizeof(*CheckVdmRequest
->CmdLine
))
618 || !CsrValidateMessageBuffer(ApiMessage
,
619 (PVOID
*)&CheckVdmRequest
->AppName
,
620 CheckVdmRequest
->AppLen
,
621 sizeof(*CheckVdmRequest
->AppName
))
622 || !CsrValidateMessageBuffer(ApiMessage
,
623 (PVOID
*)&CheckVdmRequest
->PifFile
,
624 CheckVdmRequest
->PifLen
,
625 sizeof(*CheckVdmRequest
->PifFile
))
626 || !CsrValidateMessageBuffer(ApiMessage
,
627 (PVOID
*)&CheckVdmRequest
->CurDirectory
,
628 CheckVdmRequest
->CurDirectoryLen
,
629 sizeof(*CheckVdmRequest
->CurDirectory
))
630 || !CsrValidateMessageBuffer(ApiMessage
,
631 (PVOID
*)&CheckVdmRequest
->Desktop
,
632 CheckVdmRequest
->DesktopLen
,
633 sizeof(*CheckVdmRequest
->Desktop
))
634 || !CsrValidateMessageBuffer(ApiMessage
,
635 (PVOID
*)&CheckVdmRequest
->Title
,
636 CheckVdmRequest
->TitleLen
,
637 sizeof(*CheckVdmRequest
->Title
))
638 || !CsrValidateMessageBuffer(ApiMessage
,
639 (PVOID
*)&CheckVdmRequest
->Reserved
,
640 CheckVdmRequest
->ReservedLen
,
641 sizeof(*CheckVdmRequest
->Reserved
)))
643 return STATUS_INVALID_PARAMETER
;
646 CriticalSection
= (CheckVdmRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
647 ? &DosCriticalSection
648 : &WowCriticalSection
;
650 /* Enter the critical section */
651 RtlEnterCriticalSection(CriticalSection
);
653 /* Check if this is a DOS or WOW VDM */
654 if (CheckVdmRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
656 /* Get the console record */
657 Status
= BaseSrvGetConsoleRecord(CheckVdmRequest
->ConsoleHandle
,
659 if (!NT_SUCCESS(Status
))
661 /* Allocate a new console record */
662 ConsoleRecord
= BaseSrvCreateConsoleRecord();
663 if (ConsoleRecord
== NULL
)
665 Status
= STATUS_NO_MEMORY
;
669 /* Initialize the console record */
670 ConsoleRecord
->ConsoleHandle
= CheckVdmRequest
->ConsoleHandle
;
671 if (ConsoleRecord
->ConsoleHandle
== NULL
)
673 /* The parent doesn't have a console, get a new session ID */
674 ConsoleRecord
->SessionId
= GetNextDosSesId();
678 /* No session ID is needed */
679 ConsoleRecord
->SessionId
= 0;
682 /* Remember that the console record was allocated here */
683 NewConsoleRecord
= TRUE
;
686 if (!NewConsoleRecord
)
688 /* Get the primary DOS record */
689 DosRecord
= (PVDM_DOS_RECORD
)CONTAINING_RECORD(ConsoleRecord
->DosListHead
.Flink
,
690 VDM_DOS_RECORD
, Entry
);
692 if (DosRecord
->State
!= VDM_READY
) // == VDM_NOT_READY
694 /* Allocate a new DOS record */
695 DosRecord
= (PVDM_DOS_RECORD
)RtlAllocateHeap(BaseSrvHeap
,
697 sizeof(VDM_DOS_RECORD
));
698 if (DosRecord
== NULL
)
700 Status
= STATUS_NO_MEMORY
;
704 /* Remember that the DOS record was allocated here */
710 /* Allocate a new DOS record */
711 DosRecord
= (PVDM_DOS_RECORD
)RtlAllocateHeap(BaseSrvHeap
,
713 sizeof(VDM_DOS_RECORD
));
714 if (DosRecord
== NULL
)
716 Status
= STATUS_NO_MEMORY
;
720 /* Remember that the DOS record was allocated here */
724 /* Initialize the DOS record */
725 DosRecord
->State
= VDM_NOT_READY
;
726 DosRecord
->ExitCode
= 0;
728 /* Translate the input structure into a VDM command structure and set it in the DOS record */
729 if (!BaseSrvCopyCommand(CheckVdmRequest
, DosRecord
))
731 /* The only possibility is that an allocation failure occurred */
732 Status
= STATUS_NO_MEMORY
;
738 /* Add the DOS record */
739 InsertHeadList(&ConsoleRecord
->DosListHead
, &DosRecord
->Entry
);
742 if (!NewConsoleRecord
)
744 Status
= BaseSrvCreatePairWaitHandles(&DosRecord
->ServerEvent
, &DosRecord
->ClientEvent
);
745 if (!NT_SUCCESS(Status
)) goto Cleanup
;
747 /* Return the client event handle */
748 CheckVdmRequest
->WaitObjectForParent
= DosRecord
->ClientEvent
;
751 // FIXME: We may notify ONLY if ConsoleRecord->nReEntrancy is > 0
752 // in case NewConsoleRecord == FALSE AND NewDosRecord == TRUE.
753 if (ConsoleRecord
->ServerEvent
)
755 /* Signal the session event */
756 NtSetEvent(ConsoleRecord
->ServerEvent
, NULL
);
759 if (NewConsoleRecord
)
761 /* Add the console record */
762 InsertTailList(&VDMConsoleListHead
, &ConsoleRecord
->Entry
);
765 CheckVdmRequest
->iTask
= ConsoleRecord
->SessionId
;
766 CheckVdmRequest
->VDMState
= NewConsoleRecord
? VDM_NOT_LOADED
: VDM_READY
;
767 Status
= STATUS_SUCCESS
;
771 // TODO: NOT IMPLEMENTED
773 Status
= STATUS_NOT_IMPLEMENTED
;
777 /* Check if it failed */
778 if (!NT_SUCCESS(Status
))
780 /* Free the DOS record if it was allocated here */
783 ASSERT(DosRecord
!= NULL
);
785 BaseSrvDestroyPairWaitHandles(DosRecord
->ServerEvent
,
786 DosRecord
->ClientEvent
);
788 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
792 /* Free the console record if it was allocated here */
793 if (NewConsoleRecord
)
795 ASSERT(ConsoleRecord
!= NULL
);
797 RtlFreeHeap(BaseSrvHeap
, 0, ConsoleRecord
);
798 ConsoleRecord
= NULL
;
802 /* Leave the critical section */
803 RtlLeaveCriticalSection(CriticalSection
);
808 CSR_API(BaseSrvUpdateVDMEntry
)
811 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.UpdateVDMEntryRequest
;
812 PRTL_CRITICAL_SECTION CriticalSection
= NULL
;
813 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
814 PVDM_DOS_RECORD DosRecord
= NULL
;
816 CriticalSection
= (UpdateVdmEntryRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
817 ? &DosCriticalSection
818 : &WowCriticalSection
;
820 /* Enter the critical section */
821 RtlEnterCriticalSection(CriticalSection
);
823 /* Check if this is a DOS or WOW VDM */
824 if (UpdateVdmEntryRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
826 if (UpdateVdmEntryRequest
->iTask
!= 0)
828 /* Get the console record using the task ID */
829 Status
= GetConsoleRecordBySessionId(UpdateVdmEntryRequest
->iTask
,
834 /* Get the console record using the console handle */
835 Status
= BaseSrvGetConsoleRecord(UpdateVdmEntryRequest
->ConsoleHandle
,
839 if (!NT_SUCCESS(Status
)) goto Cleanup
;
841 /* Get the primary DOS record */
842 DosRecord
= (PVDM_DOS_RECORD
)CONTAINING_RECORD(ConsoleRecord
->DosListHead
.Flink
,
843 VDM_DOS_RECORD
, Entry
);
845 switch (UpdateVdmEntryRequest
->EntryIndex
)
849 /* Close the server event handle, the client will close the client handle */
850 NtClose(DosRecord
->ServerEvent
);
851 DosRecord
->ServerEvent
= DosRecord
->ClientEvent
= NULL
;
853 if (UpdateVdmEntryRequest
->VDMCreationState
& (VDM_UNDO_PARTIAL
| VDM_UNDO_FULL
))
855 /* Remove the DOS record */
856 if (DosRecord
->CommandInfo
) BaseSrvFreeVDMInfo(DosRecord
->CommandInfo
);
857 RemoveEntryList(&DosRecord
->Entry
);
858 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
861 * Since this is an undo, if that was the only DOS record the VDM
862 * won't even start, so the console record should be removed too.
864 if (ConsoleRecord
->DosListHead
.Flink
== &ConsoleRecord
->DosListHead
)
866 RemoveEntryList(&ConsoleRecord
->Entry
);
867 BaseSrvDestroyConsoleRecord(ConsoleRecord
);
871 /* It was successful */
872 Status
= STATUS_SUCCESS
;
877 case VdmEntryUpdateProcess
:
879 /* Duplicate the VDM process handle */
880 Status
= NtDuplicateObject(CsrGetClientThread()->Process
->ProcessHandle
,
881 UpdateVdmEntryRequest
->VDMProcessHandle
,
883 &ConsoleRecord
->ProcessHandle
,
886 DUPLICATE_SAME_ATTRIBUTES
| DUPLICATE_SAME_ACCESS
);
887 if (!NT_SUCCESS(Status
)) goto Cleanup
;
890 // FIXME! Should we always do the following??
893 /* Create a pair of handles to one event object */
894 Status
= BaseSrvCreatePairWaitHandles(&DosRecord
->ServerEvent
,
895 &DosRecord
->ClientEvent
);
896 if (!NT_SUCCESS(Status
)) goto Cleanup
;
898 /* Return the client event handle */
899 UpdateVdmEntryRequest
->WaitObjectForParent
= DosRecord
->ClientEvent
;
904 case VdmEntryUpdateControlCHandler
:
906 // TODO: NOT IMPLEMENTED
907 DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!");
908 Status
= STATUS_NOT_IMPLEMENTED
;
916 Status
= STATUS_INVALID_PARAMETER
;
922 // TODO: NOT IMPLEMENTED
924 Status
= STATUS_NOT_IMPLEMENTED
;
928 /* Leave the critical section */
929 RtlLeaveCriticalSection(CriticalSection
);
934 CSR_API(BaseSrvGetNextVDMCommand
)
937 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest
=
938 &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.GetNextVDMCommandRequest
;
939 PRTL_CRITICAL_SECTION CriticalSection
;
940 PLIST_ENTRY i
= NULL
;
941 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
942 PVDM_DOS_RECORD DosRecord
= NULL
;
944 /* Validate the message buffers */
945 if (!CsrValidateMessageBuffer(ApiMessage
,
946 (PVOID
*)&GetNextVdmCommandRequest
->CmdLine
,
947 GetNextVdmCommandRequest
->CmdLen
,
948 sizeof(*GetNextVdmCommandRequest
->CmdLine
))
949 || !CsrValidateMessageBuffer(ApiMessage
,
950 (PVOID
*)&GetNextVdmCommandRequest
->AppName
,
951 GetNextVdmCommandRequest
->AppLen
,
952 sizeof(*GetNextVdmCommandRequest
->AppName
))
953 || !CsrValidateMessageBuffer(ApiMessage
,
954 (PVOID
*)&GetNextVdmCommandRequest
->PifFile
,
955 GetNextVdmCommandRequest
->PifLen
,
956 sizeof(*GetNextVdmCommandRequest
->PifFile
))
957 || !CsrValidateMessageBuffer(ApiMessage
,
958 (PVOID
*)&GetNextVdmCommandRequest
->CurDirectory
,
959 GetNextVdmCommandRequest
->CurDirectoryLen
,
960 sizeof(*GetNextVdmCommandRequest
->CurDirectory
))
961 || !CsrValidateMessageBuffer(ApiMessage
,
962 (PVOID
*)&GetNextVdmCommandRequest
->Env
,
963 GetNextVdmCommandRequest
->EnvLen
,
964 sizeof(*GetNextVdmCommandRequest
->Env
))
965 || !CsrValidateMessageBuffer(ApiMessage
,
966 (PVOID
*)&GetNextVdmCommandRequest
->Desktop
,
967 GetNextVdmCommandRequest
->DesktopLen
,
968 sizeof(*GetNextVdmCommandRequest
->Desktop
))
969 || !CsrValidateMessageBuffer(ApiMessage
,
970 (PVOID
*)&GetNextVdmCommandRequest
->Title
,
971 GetNextVdmCommandRequest
->TitleLen
,
972 sizeof(*GetNextVdmCommandRequest
->Title
))
973 || !CsrValidateMessageBuffer(ApiMessage
,
974 (PVOID
*)&GetNextVdmCommandRequest
->Reserved
,
975 GetNextVdmCommandRequest
->ReservedLen
,
976 sizeof(*GetNextVdmCommandRequest
->Reserved
))
977 || !CsrValidateMessageBuffer(ApiMessage
,
978 (PVOID
*)&GetNextVdmCommandRequest
->StartupInfo
,
980 sizeof(STARTUPINFOA
)))
982 return STATUS_INVALID_PARAMETER
;
985 CriticalSection
= (GetNextVdmCommandRequest
->VDMState
& VDM_FLAG_WOW
)
986 ? &WowCriticalSection
987 : &DosCriticalSection
;
989 /* Enter the critical section */
990 RtlEnterCriticalSection(CriticalSection
);
992 if (GetNextVdmCommandRequest
->VDMState
& VDM_FLAG_WOW
)
994 // TODO: WOW SUPPORT NOT IMPLEMENTED
996 Status
= STATUS_NOT_IMPLEMENTED
;
999 // else if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
1001 if (GetNextVdmCommandRequest
->iTask
!= 0)
1003 /* Get the console record using the task ID */
1004 Status
= GetConsoleRecordBySessionId(GetNextVdmCommandRequest
->iTask
,
1009 /* Get the console record using the console handle */
1010 Status
= BaseSrvGetConsoleRecord(GetNextVdmCommandRequest
->ConsoleHandle
,
1014 /* Make sure we found the console record */
1015 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1017 /* Return the session ID */
1018 GetNextVdmCommandRequest
->iTask
= ConsoleRecord
->SessionId
;
1019 GetNextVdmCommandRequest
->WaitObjectForVDM
= NULL
;
1021 if (GetNextVdmCommandRequest
->VDMState
& VDM_GET_FIRST_COMMAND
)
1023 /* Check if the DOS record list is empty */
1024 if (ConsoleRecord
->DosListHead
.Flink
== &ConsoleRecord
->DosListHead
)
1026 Status
= STATUS_INVALID_PARAMETER
;
1030 /* Get the first DOS record */
1031 DosRecord
= CONTAINING_RECORD(ConsoleRecord
->DosListHead
.Flink
, VDM_DOS_RECORD
, Entry
);
1033 /* Make sure its command information is still there */
1034 if (DosRecord
->CommandInfo
== NULL
)
1036 Status
= STATUS_INVALID_PARAMETER
;
1040 /* Check if the console handle hasn't been set yet */
1041 if (ConsoleRecord
->ConsoleHandle
== NULL
)
1044 ConsoleRecord
->ConsoleHandle
= GetNextVdmCommandRequest
->ConsoleHandle
;
1047 /* Fill the command information */
1048 Status
= BaseSrvFillCommandInfo(DosRecord
->CommandInfo
, GetNextVdmCommandRequest
);
1052 /* Check if we should set the state of a running DOS record to ready */
1053 if (!(GetNextVdmCommandRequest
->VDMState
1054 & (VDM_FLAG_FIRST_TASK
| VDM_FLAG_RETRY
| VDM_FLAG_NESTED_TASK
)))
1056 /* Search for a DOS record that is currently running */
1057 for (i
= ConsoleRecord
->DosListHead
.Flink
; i
!= &ConsoleRecord
->DosListHead
; i
= i
->Flink
)
1059 DosRecord
= CONTAINING_RECORD(i
, VDM_DOS_RECORD
, Entry
);
1060 if (DosRecord
->State
== VDM_NOT_READY
) break;
1063 /* Check if we found any */
1064 if (i
== &ConsoleRecord
->DosListHead
)
1066 Status
= STATUS_INVALID_PARAMETER
;
1070 /* Set the exit code */
1071 DosRecord
->ExitCode
= GetNextVdmCommandRequest
->ExitCode
;
1073 /* Update the VDM state */
1074 DosRecord
->State
= VDM_READY
;
1076 /* Notify all waiting threads that the task is finished */
1077 NtSetEvent(DosRecord
->ServerEvent
, NULL
);
1078 NtClose(DosRecord
->ServerEvent
);
1079 DosRecord
->ServerEvent
= NULL
;
1082 /* Search for a DOS record that is currently running and has command information */
1083 for (i
= ConsoleRecord
->DosListHead
.Flink
; i
!= &ConsoleRecord
->DosListHead
; i
= i
->Flink
)
1085 DosRecord
= CONTAINING_RECORD(i
, VDM_DOS_RECORD
, Entry
);
1086 if ((DosRecord
->State
== VDM_NOT_READY
) && (DosRecord
->CommandInfo
!= NULL
)) break;
1089 /* Check if we found any */
1090 if (i
!= &ConsoleRecord
->DosListHead
)
1092 ASSERT(DosRecord
->CommandInfo
!= NULL
);
1094 /* Check if the caller only wants environment data */
1095 if (GetNextVdmCommandRequest
->VDMState
& VDM_GET_ENVIRONMENT
)
1097 if (GetNextVdmCommandRequest
->EnvLen
< DosRecord
->CommandInfo
->EnvLen
)
1099 /* Not enough space was reserved */
1100 GetNextVdmCommandRequest
->EnvLen
= DosRecord
->CommandInfo
->EnvLen
;
1101 Status
= STATUS_BUFFER_OVERFLOW
;
1105 /* Copy the environment data */
1106 RtlMoveMemory(GetNextVdmCommandRequest
->Env
,
1107 DosRecord
->CommandInfo
->Env
,
1108 DosRecord
->CommandInfo
->EnvLen
);
1110 /* Return the actual size to the caller */
1111 GetNextVdmCommandRequest
->EnvLen
= DosRecord
->CommandInfo
->EnvLen
;
1115 /* Fill the command information */
1116 Status
= BaseSrvFillCommandInfo(DosRecord
->CommandInfo
, GetNextVdmCommandRequest
);
1117 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1119 /* Free the command information, it's no longer needed */
1120 BaseSrvFreeVDMInfo(DosRecord
->CommandInfo
);
1121 DosRecord
->CommandInfo
= NULL
;
1123 /* Update the VDM state */
1124 DosRecord
->State
= VDM_NOT_READY
;
1127 Status
= STATUS_SUCCESS
;
1132 GetNextVdmCommandRequest
->WaitObjectForVDM
= NULL
;
1135 * There is no command yet. Prepare for waiting if we asked so,
1136 * and if we were not retrying a request.
1138 if (!(GetNextVdmCommandRequest
->VDMState
& VDM_FLAG_DONT_WAIT
) ||
1139 !(GetNextVdmCommandRequest
->VDMState
& VDM_FLAG_RETRY
))
1141 if (ConsoleRecord
->ServerEvent
)
1143 /* Reset the event */
1144 NtResetEvent(ConsoleRecord
->ServerEvent
, NULL
);
1148 /* Create a pair of wait handles */
1149 Status
= BaseSrvCreatePairWaitHandles(&ConsoleRecord
->ServerEvent
,
1150 &ConsoleRecord
->ClientEvent
);
1151 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1154 /* Return the client event handle */
1155 GetNextVdmCommandRequest
->WaitObjectForVDM
= ConsoleRecord
->ClientEvent
;
1159 /* Leave the critical section */
1160 RtlLeaveCriticalSection(CriticalSection
);
1165 CSR_API(BaseSrvExitVDM
)
1168 PBASE_EXIT_VDM ExitVdmRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.ExitVDMRequest
;
1169 PRTL_CRITICAL_SECTION CriticalSection
= NULL
;
1170 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
1171 PVDM_DOS_RECORD DosRecord
;
1173 CriticalSection
= (ExitVdmRequest
->iWowTask
== 0)
1174 ? &DosCriticalSection
1175 : &WowCriticalSection
;
1177 /* Enter the critical section */
1178 RtlEnterCriticalSection(CriticalSection
);
1180 if (ExitVdmRequest
->iWowTask
== 0)
1182 /* Get the console record */
1183 Status
= BaseSrvGetConsoleRecord(ExitVdmRequest
->ConsoleHandle
, &ConsoleRecord
);
1184 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1186 if (ConsoleRecord
->ServerEvent
)
1187 ExitVdmRequest
->WaitObjectForVDM
= ConsoleRecord
->ClientEvent
;
1189 // NOTE: The following is the same as in BaseSrvCleanupVDMResources.
1191 if (ConsoleRecord
->ServerEvent
)
1193 NtClose(ConsoleRecord
->ServerEvent
);
1194 ConsoleRecord
->ServerEvent
= NULL
;
1197 /* Cleanup the DOS records */
1198 while (!IsListEmpty(&ConsoleRecord
->DosListHead
))
1200 DosRecord
= CONTAINING_RECORD(ConsoleRecord
->DosListHead
.Flink
,
1201 VDM_DOS_RECORD
, Entry
);
1203 /* Set the event and close it */
1204 if (DosRecord
->ServerEvent
)
1206 NtSetEvent(DosRecord
->ServerEvent
, NULL
);
1207 NtClose(DosRecord
->ServerEvent
);
1208 DosRecord
->ServerEvent
= NULL
;
1211 /* Remove the DOS entry */
1212 if (DosRecord
->CommandInfo
) BaseSrvFreeVDMInfo(DosRecord
->CommandInfo
);
1213 RemoveEntryList(&DosRecord
->Entry
);
1214 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
1217 /* Remove the console record */
1218 RemoveEntryList(&ConsoleRecord
->Entry
);
1219 BaseSrvDestroyConsoleRecord(ConsoleRecord
);
1223 // TODO: NOT IMPLEMENTED
1225 Status
= STATUS_NOT_IMPLEMENTED
;
1229 /* Leave the critical section */
1230 RtlLeaveCriticalSection(CriticalSection
);
1235 CSR_API(BaseSrvIsFirstVDM
)
1237 PBASE_IS_FIRST_VDM IsFirstVDMRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.IsFirstVDMRequest
;
1239 /* Return the result */
1240 IsFirstVDMRequest
->FirstVDM
= FirstVDM
;
1242 /* Clear the first VDM flag */
1245 return STATUS_SUCCESS
;
1248 CSR_API(BaseSrvGetVDMExitCode
)
1251 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.GetVDMExitCodeRequest
;
1252 PLIST_ENTRY i
= NULL
;
1253 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
1254 PVDM_DOS_RECORD DosRecord
= NULL
;
1256 /* Enter the critical section */
1257 RtlEnterCriticalSection(&DosCriticalSection
);
1259 /* Get the console record */
1260 Status
= BaseSrvGetConsoleRecord(GetVDMExitCodeRequest
->ConsoleHandle
, &ConsoleRecord
);
1261 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1263 /* Search for a DOS record that has the same parent process handle */
1264 for (i
= ConsoleRecord
->DosListHead
.Flink
; i
!= &ConsoleRecord
->DosListHead
; i
= i
->Flink
)
1266 DosRecord
= CONTAINING_RECORD(i
, VDM_DOS_RECORD
, Entry
);
1267 if (DosRecord
->ClientEvent
== GetVDMExitCodeRequest
->hParent
) break;
1270 /* Check if no DOS record was found */
1271 if (i
== &ConsoleRecord
->DosListHead
)
1273 Status
= STATUS_NOT_FOUND
;
1277 /* Check if this task is still running */
1278 if (DosRecord
->State
!= VDM_READY
)
1280 GetVDMExitCodeRequest
->ExitCode
= STATUS_PENDING
;
1284 /* Return the exit code */
1285 GetVDMExitCodeRequest
->ExitCode
= DosRecord
->ExitCode
;
1287 // FIXME: We may just change DosRecord->State to VDM_READY in some cases...
1289 /* Since this is a zombie task record, remove it */
1290 if (DosRecord
->CommandInfo
) BaseSrvFreeVDMInfo(DosRecord
->CommandInfo
);
1291 RemoveEntryList(&DosRecord
->Entry
);
1292 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
1295 /* Leave the critical section */
1296 RtlLeaveCriticalSection(&DosCriticalSection
);
1301 CSR_API(BaseSrvSetReenterCount
)
1303 NTSTATUS Status
= STATUS_SUCCESS
;
1304 PBASE_SET_REENTER_COUNT SetReenterCountRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.SetReenterCountRequest
;
1305 PVDM_CONSOLE_RECORD ConsoleRecord
;
1307 /* Enter the critical section */
1308 RtlEnterCriticalSection(&DosCriticalSection
);
1310 /* Get the console record */
1311 Status
= BaseSrvGetConsoleRecord(SetReenterCountRequest
->ConsoleHandle
, &ConsoleRecord
);
1312 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1314 if (SetReenterCountRequest
->fIncDec
== VDM_INC_REENTER_COUNT
)
1316 ConsoleRecord
->ReenterCount
++;
1318 else if (SetReenterCountRequest
->fIncDec
== VDM_DEC_REENTER_COUNT
)
1320 ConsoleRecord
->ReenterCount
--;
1321 if (ConsoleRecord
->ServerEvent
)
1322 NtSetEvent(ConsoleRecord
->ServerEvent
, NULL
);
1326 Status
= STATUS_INVALID_PARAMETER
;
1330 /* Leave the critical section */
1331 RtlLeaveCriticalSection(&DosCriticalSection
);
1336 CSR_API(BaseSrvSetVDMCurDirs
)
1339 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.VDMCurrentDirsRequest
;
1340 PVDM_CONSOLE_RECORD ConsoleRecord
;
1341 PCHAR Buffer
= NULL
;
1343 /* Validate the input buffer */
1344 if (!CsrValidateMessageBuffer(ApiMessage
,
1345 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
,
1346 VDMCurrentDirsRequest
->cchCurDirs
,
1347 sizeof(*VDMCurrentDirsRequest
->lpszzCurDirs
)))
1349 return STATUS_INVALID_PARAMETER
;
1352 /* Enter the critical section */
1353 RtlEnterCriticalSection(&DosCriticalSection
);
1355 /* Find the console record */
1356 Status
= BaseSrvGetConsoleRecord(VDMCurrentDirsRequest
->ConsoleHandle
, &ConsoleRecord
);
1357 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1359 if (ConsoleRecord
->CurrentDirs
== NULL
)
1361 /* Allocate memory for the current directory information */
1362 Buffer
= RtlAllocateHeap(BaseSrvHeap
,
1364 VDMCurrentDirsRequest
->cchCurDirs
);
1368 /* Resize the amount of allocated memory */
1369 Buffer
= RtlReAllocateHeap(BaseSrvHeap
,
1371 ConsoleRecord
->CurrentDirs
,
1372 VDMCurrentDirsRequest
->cchCurDirs
);
1377 /* Allocation failed */
1378 Status
= STATUS_NO_MEMORY
;
1382 /* Update the console record */
1383 ConsoleRecord
->CurrentDirs
= Buffer
;
1384 ConsoleRecord
->CurDirsLength
= VDMCurrentDirsRequest
->cchCurDirs
;
1387 RtlMoveMemory(ConsoleRecord
->CurrentDirs
,
1388 VDMCurrentDirsRequest
->lpszzCurDirs
,
1389 VDMCurrentDirsRequest
->cchCurDirs
);
1392 /* Leave the critical section */
1393 RtlLeaveCriticalSection(&DosCriticalSection
);
1398 CSR_API(BaseSrvGetVDMCurDirs
)
1401 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.VDMCurrentDirsRequest
;
1402 PVDM_CONSOLE_RECORD ConsoleRecord
;
1404 /* Validate the output buffer */
1405 if (!CsrValidateMessageBuffer(ApiMessage
,
1406 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
,
1407 VDMCurrentDirsRequest
->cchCurDirs
,
1408 sizeof(*VDMCurrentDirsRequest
->lpszzCurDirs
)))
1410 return STATUS_INVALID_PARAMETER
;
1413 /* Enter the critical section */
1414 RtlEnterCriticalSection(&DosCriticalSection
);
1416 /* Find the console record */
1417 Status
= BaseSrvGetConsoleRecord(VDMCurrentDirsRequest
->ConsoleHandle
, &ConsoleRecord
);
1418 if (!NT_SUCCESS(Status
)) goto Cleanup
;
1420 /* Return the actual size of the current directory information */
1421 VDMCurrentDirsRequest
->cchCurDirs
= ConsoleRecord
->CurDirsLength
;
1423 /* Check if the buffer is large enough */
1424 if (VDMCurrentDirsRequest
->cchCurDirs
< ConsoleRecord
->CurDirsLength
)
1426 Status
= STATUS_BUFFER_TOO_SMALL
;
1431 RtlMoveMemory(VDMCurrentDirsRequest
->lpszzCurDirs
,
1432 ConsoleRecord
->CurrentDirs
,
1433 ConsoleRecord
->CurDirsLength
);
1436 /* Leave the critical section */
1437 RtlLeaveCriticalSection(&DosCriticalSection
);
1442 CSR_API(BaseSrvBatNotification
)
1444 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1445 return STATUS_NOT_IMPLEMENTED
;
1448 CSR_API(BaseSrvRegisterWowExec
)
1450 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1451 return STATUS_NOT_IMPLEMENTED
;
1454 CSR_API(BaseSrvRefreshIniFileMapping
)
1456 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1457 return STATUS_NOT_IMPLEMENTED
;