X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=subsystems%2Fwin%2Fbasesrv%2Fvdm.c;h=415662046935ed661d6a2caffd97002f2f9dca64;hp=63f4425ece0e0e32e6c4c5f29245a97bf599fe0c;hb=c098b6e833418d87120657cf7e67659724be88fe;hpb=d01148ac9b99397dfdffd28407270deb5cbc936d diff --git a/subsystems/win/basesrv/vdm.c b/subsystems/win/basesrv/vdm.c index 63f4425ece0..41566204693 100644 --- a/subsystems/win/basesrv/vdm.c +++ b/subsystems/win/basesrv/vdm.c @@ -29,6 +29,9 @@ NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD PLIST_ENTRY i; PVDM_CONSOLE_RECORD CurrentRecord = NULL; + /* NULL is not a valid console handle */ + if (ConsoleHandle == NULL) return STATUS_INVALID_PARAMETER; + /* Search for a record that has the same console handle */ for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) { @@ -36,6 +39,28 @@ NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD if (CurrentRecord->ConsoleHandle == ConsoleHandle) break; } + /* Check if nothing was found */ + if (i == &VDMConsoleListHead) CurrentRecord = NULL; + + *Record = CurrentRecord; + return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; +} + +NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record) +{ + PLIST_ENTRY i; + PVDM_CONSOLE_RECORD CurrentRecord = NULL; + + /* Search for a record that has the same console handle */ + for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) + { + CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); + if (CurrentRecord->SessionId == TaskId) break; + } + + /* Check if nothing was found */ + if (i == &VDMConsoleListHead) CurrentRecord = NULL; + *Record = CurrentRecord; return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; } @@ -187,6 +212,319 @@ NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientE return Status; } +VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo) +{ + /* Free the allocated structure members */ + if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine); + if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName); + if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile); + if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory); + if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env); + if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop); + if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title); + if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved); + + /* Free the structure itself */ + RtlFreeHeap(BaseSrvHeap, 0, CommandInfo); +} + +VOID NTAPI BaseSrvCleanupVdmRecords(ULONG ProcessId) +{ + PLIST_ENTRY i; + PVDM_CONSOLE_RECORD ConsoleRecord = NULL; + PVDM_DOS_RECORD DosRecord; + + /* Enter the critical section */ + RtlEnterCriticalSection(&DosCriticalSection); + + /* Search for a record that has the same process handle */ + for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) + { + ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); + + if (ConsoleRecord->ProcessId == ProcessId) + { + /* Cleanup the DOS records */ + while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead) + { + DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, + VDM_DOS_RECORD, + Entry); + + /* Set the event and close it */ + NtSetEvent(DosRecord->ServerEvent, NULL); + NtClose(DosRecord->ServerEvent); + + /* Remove the DOS entry */ + if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); + RemoveEntryList(&DosRecord->Entry); + RtlFreeHeap(BaseSrvHeap, 0, DosRecord); + } + + if (ConsoleRecord->CurrentDirs != NULL) + { + /* Free the current directories */ + RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs); + ConsoleRecord->CurrentDirs = NULL; + ConsoleRecord->CurDirsLength = 0; + } + + /* Close the event handle */ + if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent); + + /* Remove the console record */ + i = i->Blink; + RemoveEntryList(&ConsoleRecord->Entry); + RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); + } + } + + /* Leave the critical section */ + RtlLeaveCriticalSection(&DosCriticalSection); +} + +BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord) +{ + BOOLEAN Success = FALSE; + PVDM_COMMAND_INFO CommandInfo = NULL; + + /* Allocate the command information structure */ + CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + sizeof(VDM_COMMAND_INFO)); + if (CommandInfo == NULL) return FALSE; + + /* Fill the structure */ + CommandInfo->TaskId = CheckVdmRequest->iTask; + CommandInfo->ExitCode = DosRecord->ExitCode; + CommandInfo->CodePage = CheckVdmRequest->CodePage; + CommandInfo->StdIn = CheckVdmRequest->StdIn; + CommandInfo->StdOut = CheckVdmRequest->StdOut; + CommandInfo->StdErr = CheckVdmRequest->StdErr; + + /* Allocate memory for the command line */ + CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->CmdLen); + if (CommandInfo->CmdLine == NULL) goto Cleanup; + + /* Copy the command line */ + RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen); + + /* Allocate memory for the application name */ + CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->AppLen); + if (CommandInfo->AppName == NULL) goto Cleanup; + + /* Copy the application name */ + RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen); + + /* Allocate memory for the PIF file name */ + if (CheckVdmRequest->PifLen != 0) + { + CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->PifLen); + if (CommandInfo->PifFile == NULL) goto Cleanup; + + /* Copy the PIF file name */ + RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen); + } + else CommandInfo->PifFile = NULL; + + /* Allocate memory for the current directory */ + if (CheckVdmRequest->CurDirectoryLen != 0) + { + CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->CurDirectoryLen); + if (CommandInfo->CurDirectory == NULL) goto Cleanup; + + /* Copy the current directory */ + RtlMoveMemory(CommandInfo->CurDirectory, + CheckVdmRequest->CurDirectory, + CheckVdmRequest->CurDirectoryLen); + } + else CommandInfo->CurDirectory = NULL; + + /* Allocate memory for the environment block */ + CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->EnvLen); + if (CommandInfo->Env == NULL) goto Cleanup; + + /* Copy the environment block */ + RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen); + + CommandInfo->EnvLen = CheckVdmRequest->EnvLen; + RtlMoveMemory(&CommandInfo->StartupInfo, + CheckVdmRequest->StartupInfo, + sizeof(STARTUPINFOA)); + + /* Allocate memory for the desktop */ + if (CheckVdmRequest->DesktopLen != 0) + { + CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->DesktopLen); + if (CommandInfo->Desktop == NULL) goto Cleanup; + + /* Copy the desktop name */ + RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen); + } + else CommandInfo->Desktop = NULL; + + CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen; + + /* Allocate memory for the title */ + if (CheckVdmRequest->TitleLen != 0) + { + CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->TitleLen); + if (CommandInfo->Title == NULL) goto Cleanup; + + /* Copy the title */ + RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen); + } + else CommandInfo->Title = NULL; + + CommandInfo->TitleLen = CheckVdmRequest->TitleLen; + + /* Allocate memory for the reserved field */ + if (CheckVdmRequest->ReservedLen != 0) + { + CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap, + HEAP_ZERO_MEMORY, + CheckVdmRequest->ReservedLen); + if (CommandInfo->Reserved == NULL) goto Cleanup; + + /* Copy the reserved field */ + RtlMoveMemory(CommandInfo->Reserved, + CheckVdmRequest->Reserved, + CheckVdmRequest->ReservedLen); + } + else CommandInfo->Reserved = NULL; + + CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen; + + CommandInfo->CmdLen = CheckVdmRequest->CmdLen; + CommandInfo->AppLen = CheckVdmRequest->AppLen; + CommandInfo->PifLen = CheckVdmRequest->PifLen; + CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen; + CommandInfo->VDMState = DosRecord->State; + // TODO: Set CommandInfo->CurrentDrive + // TODO: Set CommandInfo->ComingFromBat + + /* Set the DOS record's command structure */ + DosRecord->CommandInfo = CommandInfo; + + /* The operation was successful */ + Success = TRUE; + +Cleanup: + /* If it wasn't successful, free the memory */ + if (!Success) BaseSrvFreeVDMInfo(CommandInfo); + + return Success; +} + +NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo, + PBASE_GET_NEXT_VDM_COMMAND Message) +{ + /* Copy the data */ + Message->iTask = CommandInfo->TaskId; + Message->StdIn = CommandInfo->StdIn; + Message->StdOut = CommandInfo->StdOut; + Message->StdErr = CommandInfo->StdErr; + Message->CodePage = CommandInfo->CodePage; + Message->dwCreationFlags = CommandInfo->CreationFlags; + Message->ExitCode = CommandInfo->ExitCode; + Message->CurrentDrive = CommandInfo->CurrentDrive; + Message->VDMState = CommandInfo->VDMState; + Message->fComingFromBat = CommandInfo->ComingFromBat; + + if (CommandInfo->CmdLen && Message->CmdLen) + { + if (Message->CmdLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the command line */ + RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen); + Message->CmdLen = CommandInfo->CmdLen; + } + + if (CommandInfo->AppLen && Message->AppLen) + { + if (Message->AppLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the application name */ + RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen); + Message->AppLen = CommandInfo->AppLen; + } + + if (CommandInfo->PifLen && Message->PifLen) + { + if (Message->PifLen < CommandInfo->PifLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the PIF file name */ + RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen); + Message->PifLen = CommandInfo->PifLen; + } + + if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen) + { + if (Message->CurDirectoryLen < CommandInfo->CurDirectoryLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the current directory */ + RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen); + Message->CurDirectoryLen = CommandInfo->CurDirectoryLen; + } + + if (CommandInfo->EnvLen && Message->EnvLen) + { + if (Message->EnvLen < CommandInfo->EnvLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the environment */ + RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen); + Message->EnvLen = CommandInfo->EnvLen; + } + + /* Copy the startup info */ + RtlMoveMemory(Message->StartupInfo, + &CommandInfo->StartupInfo, + sizeof(STARTUPINFOA)); + + if (CommandInfo->DesktopLen && Message->DesktopLen) + { + if (Message->DesktopLen < CommandInfo->DesktopLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the desktop name */ + RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen); + Message->DesktopLen = CommandInfo->DesktopLen; + } + + if (CommandInfo->TitleLen && Message->TitleLen) + { + if (Message->TitleLen < CommandInfo->TitleLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the title */ + RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen); + Message->TitleLen = CommandInfo->TitleLen; + } + + if (CommandInfo->ReservedLen && Message->ReservedLen) + { + if (Message->ReservedLen < CommandInfo->ReservedLen) return STATUS_BUFFER_TOO_SMALL; + + /* Copy the reserved parameter */ + RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen); + Message->ReservedLen = CommandInfo->ReservedLen; + } + + return STATUS_SUCCESS; +} + VOID NTAPI BaseInitializeVDM(VOID) { /* Initialize the list head */ @@ -270,16 +608,18 @@ CSR_API(BaseSrvCheckVDM) goto Cleanup; } + /* Remember that the console record was allocated here */ + NewConsoleRecord = TRUE; + /* Initialize the console record */ ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle; + ConsoleRecord->ProcessHandle = CsrGetClientThread()->Process->ProcessHandle; + ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL; + ConsoleRecord->ReenterCount = 0; ConsoleRecord->CurrentDirs = NULL; ConsoleRecord->CurDirsLength = 0; ConsoleRecord->SessionId = GetNextDosSesId(); InitializeListHead(&ConsoleRecord->DosListHead); - // TODO: The console record structure is incomplete - - /* Remember that the console record was allocated here */ - NewConsoleRecord = TRUE; } /* Allocate a new DOS record */ @@ -293,30 +633,53 @@ CSR_API(BaseSrvCheckVDM) } /* Initialize the DOS record */ - DosRecord->State = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY; + DosRecord->State = VDM_NOT_LOADED; DosRecord->ExitCode = 0; - // TODO: The DOS record structure is incomplete Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent); if (!NT_SUCCESS(Status)) goto Cleanup; + /* Return the client event handle */ + CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent; + + /* Translate the input structure into a VDM command structure and set it in the DOS record */ + if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord)) + { + /* The only possibility is that an allocation failure occurred */ + Status = STATUS_NO_MEMORY; + goto Cleanup; + } + /* Add the DOS record */ InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry); + if (ConsoleRecord->ServerEvent) + { + /* Signal the session event */ + NtSetEvent(ConsoleRecord->ServerEvent, NULL); + } + if (NewConsoleRecord) { /* Add the console record */ InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry); } - CheckVdmRequest->VDMState = DosRecord->State; + if (ConsoleRecord->ConsoleHandle == NULL) + { + /* The parent doesn't have a console, so return the session ID */ + CheckVdmRequest->iTask = ConsoleRecord->SessionId; + } + else CheckVdmRequest->iTask = 0; + + CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY; Status = STATUS_SUCCESS; } else { // TODO: NOT IMPLEMENTED UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + Status = STATUS_NOT_IMPLEMENTED; } Cleanup: @@ -326,6 +689,19 @@ Cleanup: /* Free the DOS record */ if (DosRecord != NULL) { + if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent); + if (DosRecord->ClientEvent) + { + /* Close the remote handle */ + NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle, + DosRecord->ClientEvent, + NULL, + NULL, + 0, + 0, + DUPLICATE_CLOSE_SOURCE); + } + RtlFreeHeap(BaseSrvHeap, 0, DosRecord); DosRecord = NULL; } @@ -346,14 +722,343 @@ Cleanup: CSR_API(BaseSrvUpdateVDMEntry) { - DPRINT1("%s not yet implemented\n", __FUNCTION__); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest; + PRTL_CRITICAL_SECTION CriticalSection = NULL; + PVDM_CONSOLE_RECORD ConsoleRecord = NULL; + PVDM_DOS_RECORD DosRecord = NULL; + + CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) + ? &DosCriticalSection + : &WowCriticalSection; + + /* Enter the critical section */ + RtlEnterCriticalSection(CriticalSection); + + /* Check if this is a DOS or WOW VDM */ + if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) + { + if (UpdateVdmEntryRequest->iTask != 0) + { + /* Get the console record using the task ID */ + Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask, + &ConsoleRecord); + } + else + { + /* Get the console record using the console handle */ + Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle, + &ConsoleRecord); + } + + if (!NT_SUCCESS(Status)) goto Cleanup; + + /* Get the primary DOS record */ + DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, + VDM_DOS_RECORD, + Entry); + + switch (UpdateVdmEntryRequest->EntryIndex) + { + case VdmEntryUndo: + { + /* Close the server event handle, the client will close the client handle */ + NtClose(DosRecord->ServerEvent); + DosRecord->ServerEvent = DosRecord->ClientEvent = NULL; + + if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL)) + { + /* Remove the DOS record */ + if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); + RemoveEntryList(&DosRecord->Entry); + RtlFreeHeap(BaseSrvHeap, 0, DosRecord); + + /* + * Since this is an undo, if that was the only DOS record the VDM + * won't even start, so the console record should be removed too. + */ + if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead) + { + if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent); + RemoveEntryList(&ConsoleRecord->Entry); + RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); + } + } + + /* It was successful */ + Status = STATUS_SUCCESS; + + break; + } + + case VdmEntryUpdateProcess: + { + /* Duplicate the VDM process handle */ + Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle, + UpdateVdmEntryRequest->VDMProcessHandle, + NtCurrentProcess(), + &ConsoleRecord->ProcessHandle, + 0, + 0, + DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); + if (!NT_SUCCESS(Status)) goto Cleanup; + + /* Create a pair of handles to one event object */ + Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, + &DosRecord->ClientEvent); + if (!NT_SUCCESS(Status)) goto Cleanup; + + /* Return the client event handle */ + UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent; + + break; + } + + case VdmEntryUpdateControlCHandler: + { + // TODO: NOT IMPLEMENTED + DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!"); + Status = STATUS_NOT_IMPLEMENTED; + + break; + } + + default: + { + /* Invalid */ + Status = STATUS_INVALID_PARAMETER; + } + } + } + else + { + // TODO: NOT IMPLEMENTED + UNIMPLEMENTED; + Status = STATUS_NOT_IMPLEMENTED; + } + +Cleanup: + /* Leave the critical section */ + RtlLeaveCriticalSection(CriticalSection); + + return Status; } CSR_API(BaseSrvGetNextVDMCommand) { - DPRINT1("%s not yet implemented\n", __FUNCTION__); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest = + &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest; + PRTL_CRITICAL_SECTION CriticalSection; + PLIST_ENTRY i = NULL; + PVDM_CONSOLE_RECORD ConsoleRecord = NULL; + PVDM_DOS_RECORD DosRecord = NULL; + + /* Validate the message buffers */ + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->CmdLine, + GetNextVdmCommandRequest->CmdLen, + sizeof(*GetNextVdmCommandRequest->CmdLine)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->AppName, + GetNextVdmCommandRequest->AppLen, + sizeof(*GetNextVdmCommandRequest->AppName)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->PifFile, + GetNextVdmCommandRequest->PifLen, + sizeof(*GetNextVdmCommandRequest->PifFile)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->CurDirectory, + GetNextVdmCommandRequest->CurDirectoryLen, + sizeof(*GetNextVdmCommandRequest->CurDirectory)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->Env, + GetNextVdmCommandRequest->EnvLen, + sizeof(*GetNextVdmCommandRequest->Env)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->Desktop, + GetNextVdmCommandRequest->DesktopLen, + sizeof(*GetNextVdmCommandRequest->Desktop)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->Title, + GetNextVdmCommandRequest->TitleLen, + sizeof(*GetNextVdmCommandRequest->Title)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->Reserved, + GetNextVdmCommandRequest->ReservedLen, + sizeof(*GetNextVdmCommandRequest->Reserved)) + || !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&GetNextVdmCommandRequest->StartupInfo, + 1, + sizeof(STARTUPINFOA))) + { + return STATUS_INVALID_PARAMETER; + } + + CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW) + ? &WowCriticalSection + : &DosCriticalSection; + + /* Enter the critical section */ + RtlEnterCriticalSection(CriticalSection); + + if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)) + { + if (GetNextVdmCommandRequest->iTask != 0) + { + /* Get the console record using the task ID */ + Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask, + &ConsoleRecord); + } + else + { + /* Get the console record using the console handle */ + Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle, + &ConsoleRecord); + } + + /* Make sure we found the console record */ + if (!NT_SUCCESS(Status)) goto Cleanup; + + /* Return the session ID */ + GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId; + GetNextVdmCommandRequest->WaitObjectForVDM = NULL; + + if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND) + { + /* Check if the DOS record list is empty */ + if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + /* Get the first DOS record */ + DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry); + + /* Make sure its command information is still there */ + if (DosRecord->CommandInfo == NULL) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + /* Fill the command information */ + Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest); + goto Cleanup; + } + + /* Check if we should set the state of a running DOS record to ready */ + if (!(GetNextVdmCommandRequest->VDMState + & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK))) + { + /* Search for a DOS record that is currently running */ + for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) + { + DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); + if (DosRecord->State == VDM_NOT_READY) break; + } + + /* Check if we found any */ + if (i == &ConsoleRecord->DosListHead) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + /* Set the exit code */ + DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode; + + /* Update the VDM state */ + DosRecord->State = VDM_READY; + + /* Notify all waiting threads that the task is finished */ + NtSetEvent(DosRecord->ServerEvent, NULL); + NtClose(DosRecord->ServerEvent); + DosRecord->ServerEvent = NULL; + } + + /* Search for a DOS record that isn't loaded yet */ + for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) + { + DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); + if (DosRecord->State == VDM_NOT_LOADED) break; + } + + if (i != &ConsoleRecord->DosListHead) + { + /* DOS tasks which haven't been loaded yet should have a command info structure */ + ASSERT(DosRecord->CommandInfo != NULL); + + /* Check if the caller only wants environment data */ + if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT) + { + if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen) + { + /* Not enough space was reserved */ + GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen; + Status = STATUS_BUFFER_OVERFLOW; + goto Cleanup; + } + + /* Copy the environment data */ + RtlMoveMemory(GetNextVdmCommandRequest->Env, + DosRecord->CommandInfo->Env, + DosRecord->CommandInfo->EnvLen); + + /* Return the actual size to the caller */ + GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen; + } + else + { + /* Fill the command information */ + Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest); + + /* Free the command information, it's no longer needed */ + BaseSrvFreeVDMInfo(DosRecord->CommandInfo); + DosRecord->CommandInfo = NULL; + + /* Update the VDM state */ + GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY; + } + + Status = STATUS_SUCCESS; + goto Cleanup; + } + } + else + { + // TODO: WOW SUPPORT NOT IMPLEMENTED + Status = STATUS_NOT_IMPLEMENTED; + goto Cleanup; + } + + /* There is no command yet */ + if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY)) + != (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY)) + { + if (ConsoleRecord->ServerEvent) + { + /* Reset the event */ + NtResetEvent(ConsoleRecord->ServerEvent, NULL); + } + else + { + /* Create a pair of wait handles */ + Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent, + &ConsoleRecord->ClientEvent); + if (!NT_SUCCESS(Status)) goto Cleanup; + } + + /* Return the client event handle */ + GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent; + } + +Cleanup: + /* Leave the critical section */ + RtlLeaveCriticalSection(CriticalSection); + + return Status; } CSR_API(BaseSrvExitVDM) @@ -384,7 +1089,12 @@ CSR_API(BaseSrvExitVDM) VDM_DOS_RECORD, Entry); + /* Set the event and close it */ + NtSetEvent(DosRecord->ServerEvent, NULL); + NtClose(DosRecord->ServerEvent); + /* Remove the DOS entry */ + if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); RemoveEntryList(&DosRecord->Entry); RtlFreeHeap(BaseSrvHeap, 0, DosRecord); } @@ -397,6 +1107,9 @@ CSR_API(BaseSrvExitVDM) ConsoleRecord->CurDirsLength = 0; } + /* Close the event handle */ + if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent); + /* Remove the console record */ RemoveEntryList(&ConsoleRecord->Entry); RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); @@ -405,7 +1118,7 @@ CSR_API(BaseSrvExitVDM) { // TODO: NOT IMPLEMENTED UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + Status = STATUS_NOT_IMPLEMENTED; } Cleanup: @@ -468,6 +1181,7 @@ CSR_API(BaseSrvGetVDMExitCode) GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode; /* Since this is a zombie task record, remove it */ + if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); RemoveEntryList(&DosRecord->Entry); RtlFreeHeap(BaseSrvHeap, 0, DosRecord); @@ -480,8 +1194,30 @@ Cleanup: CSR_API(BaseSrvSetReenterCount) { - DPRINT1("%s not yet implemented\n", __FUNCTION__); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status = STATUS_SUCCESS; + PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest; + PVDM_CONSOLE_RECORD ConsoleRecord; + + /* Enter the critical section */ + RtlEnterCriticalSection(&DosCriticalSection); + + /* Get the console record */ + Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord); + if (!NT_SUCCESS(Status)) goto Cleanup; + + if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++; + else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT) + { + ConsoleRecord->ReenterCount--; + if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL); + } + else Status = STATUS_INVALID_PARAMETER; + +Cleanup: + /* Leave the critical section */ + RtlLeaveCriticalSection(&DosCriticalSection); + + return Status; } CSR_API(BaseSrvSetVDMCurDirs)