mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[BASESRV][KERNEL32][NTVDM]
Make our BaseSrvGetNextVDMCommand and GetNextVDMCommand a bit more Windows-compatible, and modify NTVDM accordingly. svn path=/branches/ntvdm/; revision=63098
This commit is contained in:
parent
d0fad5273f
commit
47c1283bd2
5 changed files with 138 additions and 34 deletions
|
@ -1281,6 +1281,10 @@ GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
|
|||
BaseSetLastNTError(Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Set the retry flag and clear the exit code */
|
||||
GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
|
||||
GetNextVdmCommand->ExitCode = 0;
|
||||
}
|
||||
}
|
||||
while (GetNextVdmCommand->WaitObjectForVDM != NULL);
|
||||
|
|
|
@ -48,11 +48,22 @@ typedef enum _VDM_ENTRY_CODE
|
|||
#define VDM_READY 0x04
|
||||
|
||||
//
|
||||
// VDM Magic Values
|
||||
// VDM Flags
|
||||
//
|
||||
#define VDM_FLAG_FIRST_TASK 0x01
|
||||
#define VDM_FLAG_WOW 0x02
|
||||
#define VDM_FLAG_DOS 0x04
|
||||
#define VDM_FLAG_RETRY 0x08
|
||||
#define VDM_INC_REENTER_COUNT 0x10
|
||||
#define VDM_DEC_REENTER_COUNT 0x20
|
||||
#define VDM_FLAG_NESTED_TASK 0x40
|
||||
#define VDM_FLAG_DONT_WAIT 0x80
|
||||
#define VDM_GET_FIRST_COMMAND 0x100
|
||||
#define VDM_GET_ENVIRONMENT 0x400
|
||||
#define VDM_FLAG_SEPARATE_WOW 0x800
|
||||
#define VDM_LIST_WOW_PROCESSES 0x1000
|
||||
#define VDM_LIST_WOW_TASKS 0x4000
|
||||
#define VDM_ADD_WOW_TASK 0x8000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -1336,7 +1336,7 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
|||
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
|
||||
|
||||
/* Initialize the structure members */
|
||||
CommandInfo.VDMState = VDM_NOT_READY;
|
||||
CommandInfo.VDMState = VDM_FLAG_NESTED_TASK | VDM_FLAG_DONT_WAIT;
|
||||
CommandInfo.CmdLine = CmdLine;
|
||||
CommandInfo.CmdLen = sizeof(CmdLine);
|
||||
CommandInfo.AppName = AppName;
|
||||
|
@ -1399,6 +1399,7 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
|||
PDOS_MCB CurrentMcb;
|
||||
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
|
||||
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
|
||||
VDM_COMMAND_INFO CommandInfo;
|
||||
|
||||
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
|
||||
Psp,
|
||||
|
@ -1445,6 +1446,22 @@ Done:
|
|||
if (CurrentPsp == SYSTEM_PSP) VdmRunning = FALSE;
|
||||
}
|
||||
|
||||
// FIXME: This is probably not the best way to do it
|
||||
/* Check if this was a nested DOS task */
|
||||
if (VdmRunning)
|
||||
{
|
||||
/* Decrement the re-entry count */
|
||||
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
|
||||
GetNextVDMCommand(&CommandInfo);
|
||||
|
||||
/* Clear the structure */
|
||||
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
|
||||
|
||||
/* Update the VDM state of the task */
|
||||
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
|
||||
GetNextVDMCommand(&CommandInfo);
|
||||
}
|
||||
|
||||
/* Save the return code - Normal termination */
|
||||
DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
|
||||
|
||||
|
|
|
@ -390,6 +390,7 @@ VOID ConsoleCleanup(VOID)
|
|||
|
||||
DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
||||
{
|
||||
BOOLEAN First = TRUE;
|
||||
DWORD Result;
|
||||
VDM_COMMAND_INFO CommandInfo;
|
||||
CHAR CmdLine[MAX_PATH];
|
||||
|
@ -407,7 +408,7 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
|||
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
|
||||
|
||||
/* Initialize the structure members */
|
||||
CommandInfo.VDMState = VDM_NOT_LOADED;
|
||||
CommandInfo.VDMState = VDM_FLAG_DOS;
|
||||
CommandInfo.CmdLine = CmdLine;
|
||||
CommandInfo.CmdLen = sizeof(CmdLine);
|
||||
CommandInfo.AppName = AppName;
|
||||
|
@ -421,6 +422,12 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
|||
CommandInfo.Env = Env;
|
||||
CommandInfo.EnvLen = sizeof(Env);
|
||||
|
||||
if (First)
|
||||
{
|
||||
CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
|
||||
First = FALSE;
|
||||
}
|
||||
|
||||
/* Wait for the next available VDM */
|
||||
if (!GetNextVDMCommand(&CommandInfo)) break;
|
||||
|
||||
|
|
|
@ -905,21 +905,58 @@ CSR_API(BaseSrvGetNextVDMCommand)
|
|||
GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
|
||||
GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
|
||||
|
||||
if (!(GetNextVdmCommandRequest->VDMState & VDM_NOT_READY))
|
||||
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)
|
||||
{
|
||||
/* If NTVDM is asking for a new command, it means these are done */
|
||||
DosRecord->State = VDM_READY;
|
||||
|
||||
NtSetEvent(DosRecord->ServerEvent, NULL);
|
||||
NtClose(DosRecord->ServerEvent);
|
||||
DosRecord->ServerEvent = NULL;
|
||||
}
|
||||
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 */
|
||||
|
@ -931,16 +968,40 @@ CSR_API(BaseSrvGetNextVDMCommand)
|
|||
|
||||
if (i != &ConsoleRecord->DosListHead)
|
||||
{
|
||||
/* Fill the command information */
|
||||
Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
|
||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||
/* DOS tasks which haven't been loaded yet should have a command info structure */
|
||||
ASSERT(DosRecord->CommandInfo != NULL);
|
||||
|
||||
/* Free the command information, it's no longer needed */
|
||||
BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Update the VDM state */
|
||||
DosRecord->State = VDM_NOT_READY;
|
||||
/* 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;
|
||||
|
@ -954,21 +1015,25 @@ CSR_API(BaseSrvGetNextVDMCommand)
|
|||
}
|
||||
|
||||
/* There is no command yet */
|
||||
if (ConsoleRecord->ServerEvent)
|
||||
if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
|
||||
!= (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
/* Return the client event handle */
|
||||
GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
/* Leave the critical section */
|
||||
|
|
Loading…
Reference in a new issue