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 /* FUNCTIONS ******************************************************************/
27 NTSTATUS NTAPI
BaseSrvGetConsoleRecord(HANDLE ConsoleHandle
, PVDM_CONSOLE_RECORD
*Record
)
30 PVDM_CONSOLE_RECORD CurrentRecord
= NULL
;
32 /* Search for a record that has the same console handle */
33 for (i
= VDMConsoleListHead
.Flink
; i
!= &VDMConsoleListHead
; i
= i
->Flink
)
35 CurrentRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
36 if (CurrentRecord
->ConsoleHandle
== ConsoleHandle
) break;
39 *Record
= CurrentRecord
;
40 return CurrentRecord
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
43 ULONG NTAPI
GetNextDosSesId(VOID
)
47 PVDM_CONSOLE_RECORD CurrentRecord
= NULL
;
50 /* Search for an available session ID */
51 for (SessionId
= 1; SessionId
!= 0; SessionId
++)
55 /* Check if the ID is already in use */
56 for (i
= VDMConsoleListHead
.Flink
; i
!= &VDMConsoleListHead
; i
= i
->Flink
)
58 CurrentRecord
= CONTAINING_RECORD(i
, VDM_CONSOLE_RECORD
, Entry
);
59 if (CurrentRecord
->SessionId
== SessionId
) Found
= TRUE
;
62 /* If not, we found one */
66 ASSERT(SessionId
!= 0);
68 /* Return the session ID */
72 VOID NTAPI
BaseInitializeVDM(VOID
)
74 /* Initialize the list head */
75 InitializeListHead(&VDMConsoleListHead
);
77 /* Initialize the critical section */
78 RtlInitializeCriticalSection(&DosCriticalSection
);
79 RtlInitializeCriticalSection(&WowCriticalSection
);
82 /* PUBLIC SERVER APIS *********************************************************/
84 CSR_API(BaseSrvCheckVDM
)
87 PBASE_CHECK_VDM CheckVdmRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.CheckVDMRequest
;
88 PRTL_CRITICAL_SECTION CriticalSection
= NULL
;
89 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
91 /* Validate the message buffers */
92 if (!CsrValidateMessageBuffer(ApiMessage
,
93 (PVOID
*)&CheckVdmRequest
->CmdLine
,
94 CheckVdmRequest
->CmdLen
,
95 sizeof(*CheckVdmRequest
->CmdLine
))
96 || !CsrValidateMessageBuffer(ApiMessage
,
97 (PVOID
*)&CheckVdmRequest
->AppName
,
98 CheckVdmRequest
->AppLen
,
99 sizeof(*CheckVdmRequest
->AppName
))
100 || !CsrValidateMessageBuffer(ApiMessage
,
101 (PVOID
*)&CheckVdmRequest
->PifFile
,
102 CheckVdmRequest
->PifLen
,
103 sizeof(*CheckVdmRequest
->PifFile
))
104 || !CsrValidateMessageBuffer(ApiMessage
,
105 (PVOID
*)&CheckVdmRequest
->CurDirectory
,
106 CheckVdmRequest
->CurDirectoryLen
,
107 sizeof(*CheckVdmRequest
->CurDirectory
))
108 || !CsrValidateMessageBuffer(ApiMessage
,
109 (PVOID
*)&CheckVdmRequest
->Desktop
,
110 CheckVdmRequest
->DesktopLen
,
111 sizeof(*CheckVdmRequest
->Desktop
))
112 || !CsrValidateMessageBuffer(ApiMessage
,
113 (PVOID
*)&CheckVdmRequest
->Title
,
114 CheckVdmRequest
->TitleLen
,
115 sizeof(*CheckVdmRequest
->Title
))
116 || !CsrValidateMessageBuffer(ApiMessage
,
117 (PVOID
*)&CheckVdmRequest
->Reserved
,
118 CheckVdmRequest
->ReservedLen
,
119 sizeof(*CheckVdmRequest
->Reserved
)))
121 return STATUS_INVALID_PARAMETER
;
124 CriticalSection
= (CheckVdmRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
125 ? &DosCriticalSection
126 : &WowCriticalSection
;
128 /* Enter the critical section */
129 RtlEnterCriticalSection(CriticalSection
);
131 /* Check if this is a DOS or WOW VDM */
132 if (CheckVdmRequest
->BinaryType
!= BINARY_TYPE_SEPARATE_WOW
)
134 /* Get the console record */
135 Status
= BaseSrvGetConsoleRecord(CheckVdmRequest
->ConsoleHandle
,
138 if (!NT_SUCCESS(Status
))
140 /* Allocate a new console record */
141 ConsoleRecord
= (PVDM_CONSOLE_RECORD
)RtlAllocateHeap(BaseSrvHeap
,
143 sizeof(VDM_CONSOLE_RECORD
));
144 if (ConsoleRecord
== NULL
)
146 Status
= STATUS_NO_MEMORY
;
150 /* Initialize the console record */
151 ConsoleRecord
->ConsoleHandle
= CheckVdmRequest
->ConsoleHandle
;
152 ConsoleRecord
->CurrentDirs
= NULL
;
153 ConsoleRecord
->CurDirsLength
= 0;
154 ConsoleRecord
->SessionId
= GetNextDosSesId();
155 InitializeListHead(&ConsoleRecord
->DosListHead
);
157 /* Add the console record */
158 InsertTailList(&VDMConsoleListHead
, &ConsoleRecord
->Entry
);
161 // TODO: NOT IMPLEMENTED
163 return STATUS_NOT_IMPLEMENTED
;
167 // TODO: NOT IMPLEMENTED
169 return STATUS_NOT_IMPLEMENTED
;
173 /* Leave the critical section */
174 RtlLeaveCriticalSection(CriticalSection
);
179 CSR_API(BaseSrvUpdateVDMEntry
)
181 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
182 return STATUS_NOT_IMPLEMENTED
;
185 CSR_API(BaseSrvGetNextVDMCommand
)
187 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
188 return STATUS_NOT_IMPLEMENTED
;
191 CSR_API(BaseSrvExitVDM
)
193 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
194 return STATUS_NOT_IMPLEMENTED
;
197 CSR_API(BaseSrvIsFirstVDM
)
199 PBASE_IS_FIRST_VDM IsFirstVDMRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.IsFirstVDMRequest
;
201 /* Return the result */
202 IsFirstVDMRequest
->FirstVDM
= FirstVDM
;
204 /* Clear the first VDM flag */
207 return STATUS_SUCCESS
;
210 CSR_API(BaseSrvGetVDMExitCode
)
213 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.GetVDMExitCodeRequest
;
214 PLIST_ENTRY i
= NULL
;
215 PVDM_CONSOLE_RECORD ConsoleRecord
= NULL
;
216 PVDM_DOS_RECORD DosRecord
= NULL
;
218 /* Enter the critical section */
219 RtlEnterCriticalSection(&DosCriticalSection
);
221 /* Get the console record */
222 Status
= BaseSrvGetConsoleRecord(GetVDMExitCodeRequest
->ConsoleHandle
, &ConsoleRecord
);
223 if (!NT_SUCCESS(Status
)) goto Cleanup
;
225 /* Search for a DOS record that has the same parent process handle */
226 for (i
= ConsoleRecord
->DosListHead
.Flink
; i
!= &ConsoleRecord
->DosListHead
; i
= i
->Flink
)
228 DosRecord
= CONTAINING_RECORD(i
, VDM_DOS_RECORD
, Entry
);
229 if (DosRecord
->ParentProcess
== GetVDMExitCodeRequest
->hParent
) break;
232 /* Check if no DOS record was found */
233 if (i
== &ConsoleRecord
->DosListHead
)
235 Status
= STATUS_NOT_FOUND
;
239 /* Check if this task is still running */
240 if (DosRecord
->State
== VDM_READY
)
242 GetVDMExitCodeRequest
->ExitCode
= STATUS_PENDING
;
246 /* Return the exit code */
247 GetVDMExitCodeRequest
->ExitCode
= DosRecord
->ExitCode
;
249 /* Since this is a zombie task record, remove it */
250 RemoveEntryList(&DosRecord
->Entry
);
251 RtlFreeHeap(BaseSrvHeap
, 0, DosRecord
);
254 /* Leave the critical section */
255 RtlLeaveCriticalSection(&DosCriticalSection
);
260 CSR_API(BaseSrvSetReenterCount
)
262 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
263 return STATUS_NOT_IMPLEMENTED
;
266 CSR_API(BaseSrvSetVDMCurDirs
)
269 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.VDMCurrentDirsRequest
;
270 PVDM_CONSOLE_RECORD ConsoleRecord
;
273 /* Validate the input buffer */
274 if (!CsrValidateMessageBuffer(ApiMessage
,
275 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
,
276 VDMCurrentDirsRequest
->cchCurDirs
,
277 sizeof(*VDMCurrentDirsRequest
->lpszzCurDirs
)))
279 return STATUS_INVALID_PARAMETER
;
282 /* Enter the critical section */
283 RtlEnterCriticalSection(&DosCriticalSection
);
285 /* Find the console record */
286 Status
= BaseSrvGetConsoleRecord(VDMCurrentDirsRequest
->ConsoleHandle
, &ConsoleRecord
);
287 if (!NT_SUCCESS(Status
)) goto Cleanup
;
289 if (ConsoleRecord
->CurrentDirs
== NULL
)
291 /* Allocate memory for the current directory information */
292 Buffer
= RtlAllocateHeap(BaseSrvHeap
,
294 VDMCurrentDirsRequest
->cchCurDirs
);
298 /* Resize the amount of allocated memory */
299 Buffer
= RtlReAllocateHeap(BaseSrvHeap
,
301 ConsoleRecord
->CurrentDirs
,
302 VDMCurrentDirsRequest
->cchCurDirs
);
307 /* Allocation failed */
308 Status
= STATUS_NO_MEMORY
;
312 /* Update the console record */
313 ConsoleRecord
->CurrentDirs
= Buffer
;
314 ConsoleRecord
->CurDirsLength
= VDMCurrentDirsRequest
->cchCurDirs
;
317 RtlMoveMemory(ConsoleRecord
->CurrentDirs
,
318 VDMCurrentDirsRequest
->lpszzCurDirs
,
319 VDMCurrentDirsRequest
->cchCurDirs
);
322 /* Leave the critical section */
323 RtlLeaveCriticalSection(&DosCriticalSection
);
328 CSR_API(BaseSrvGetVDMCurDirs
)
331 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.VDMCurrentDirsRequest
;
332 PVDM_CONSOLE_RECORD ConsoleRecord
;
334 /* Validate the output buffer */
335 if (!CsrValidateMessageBuffer(ApiMessage
,
336 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
,
337 VDMCurrentDirsRequest
->cchCurDirs
,
338 sizeof(*VDMCurrentDirsRequest
->lpszzCurDirs
)))
340 return STATUS_INVALID_PARAMETER
;
343 /* Enter the critical section */
344 RtlEnterCriticalSection(&DosCriticalSection
);
346 /* Find the console record */
347 Status
= BaseSrvGetConsoleRecord(VDMCurrentDirsRequest
->ConsoleHandle
, &ConsoleRecord
);
348 if (!NT_SUCCESS(Status
)) goto Cleanup
;
350 /* Return the actual size of the current directory information */
351 VDMCurrentDirsRequest
->cchCurDirs
= ConsoleRecord
->CurDirsLength
;
353 /* Check if the buffer is large enough */
354 if (VDMCurrentDirsRequest
->cchCurDirs
< ConsoleRecord
->CurDirsLength
)
356 Status
= STATUS_BUFFER_TOO_SMALL
;
361 RtlMoveMemory(VDMCurrentDirsRequest
->lpszzCurDirs
,
362 ConsoleRecord
->CurrentDirs
,
363 ConsoleRecord
->CurDirsLength
);
366 /* Leave the critical section */
367 RtlLeaveCriticalSection(&DosCriticalSection
);
372 CSR_API(BaseSrvBatNotification
)
374 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
375 return STATUS_NOT_IMPLEMENTED
;
378 CSR_API(BaseSrvRegisterWowExec
)
380 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
381 return STATUS_NOT_IMPLEMENTED
;
384 CSR_API(BaseSrvRefreshIniFileMapping
)
386 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
387 return STATUS_NOT_IMPLEMENTED
;