[BASESRV][KERNEL32][NTVDM]
[reactos.git] / subsystems / win / basesrv / vdm.c
1 /*
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>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "basesrv.h"
13 #include "vdm.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 BOOLEAN FirstVDM = TRUE;
21 LIST_ENTRY VDMConsoleListHead;
22 RTL_CRITICAL_SECTION DosCriticalSection;
23 RTL_CRITICAL_SECTION WowCriticalSection;
24
25 /* FUNCTIONS ******************************************************************/
26
27 NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
28 {
29 PLIST_ENTRY i;
30 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
31
32 /* Search for a record that has the same console handle */
33 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
34 {
35 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
36 if (CurrentRecord->ConsoleHandle == ConsoleHandle) break;
37 }
38
39 *Record = CurrentRecord;
40 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
41 }
42
43 NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
44 {
45 PLIST_ENTRY i;
46 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
47
48 /* Search for a record that has the same console handle */
49 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
50 {
51 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
52 if (CurrentRecord->SessionId == TaskId) break;
53 }
54
55 *Record = CurrentRecord;
56 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
57 }
58
59 ULONG NTAPI GetNextDosSesId(VOID)
60 {
61 ULONG SessionId;
62 PLIST_ENTRY i;
63 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
64 BOOLEAN Found;
65
66 /* Search for an available session ID */
67 for (SessionId = 1; SessionId != 0; SessionId++)
68 {
69 Found = FALSE;
70
71 /* Check if the ID is already in use */
72 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
73 {
74 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
75 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
76 }
77
78 /* If not, we found one */
79 if (!Found) break;
80 }
81
82 ASSERT(SessionId != 0);
83
84 /* Return the session ID */
85 return SessionId;
86 }
87
88 BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
89 {
90 NTSTATUS Status;
91 BOOLEAN VdmAllowed = TRUE;
92 HANDLE RootKey, KeyHandle;
93 UNICODE_STRING KeyName, ValueName, MachineKeyName;
94 OBJECT_ATTRIBUTES Attributes;
95 UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
96 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
97 ULONG ActualSize;
98
99 /* Initialize the unicode strings */
100 RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine");
101 RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME);
102 RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME);
103
104 InitializeObjectAttributes(&Attributes,
105 &MachineKeyName,
106 OBJ_CASE_INSENSITIVE,
107 NULL,
108 NULL);
109
110 /* Open the local machine key */
111 Status = NtOpenKey(&RootKey, KEY_READ, &Attributes);
112 if (!NT_SUCCESS(Status)) return FALSE;
113
114 InitializeObjectAttributes(&Attributes,
115 &KeyName,
116 OBJ_CASE_INSENSITIVE,
117 RootKey,
118 NULL);
119
120 /* Open the policy key in the local machine hive, if it exists */
121 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
122 {
123 /* Read the value, if it's set */
124 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
125 &ValueName,
126 KeyValuePartialInformation,
127 ValueInfo,
128 sizeof(ValueBuffer),
129 &ActualSize)))
130 {
131 if (*((PULONG)ValueInfo->Data))
132 {
133 /* The VDM has been disabled in the registry */
134 VdmAllowed = FALSE;
135 }
136 }
137
138 NtClose(KeyHandle);
139 }
140
141 /* Close the local machine key */
142 NtClose(RootKey);
143
144 /* If it's disabled system-wide, there's no need to check the user key */
145 if (!VdmAllowed) return FALSE;
146
147 /* Open the current user key of the client */
148 if (!CsrImpersonateClient(NULL)) return VdmAllowed;
149 Status = RtlOpenCurrentUser(KEY_READ, &RootKey);
150 CsrRevertToSelf();
151
152 /* If that fails, return the system-wide setting */
153 if (!NT_SUCCESS(Status)) return VdmAllowed;
154
155 InitializeObjectAttributes(&Attributes,
156 &KeyName,
157 OBJ_CASE_INSENSITIVE,
158 RootKey,
159 NULL);
160
161 /* Open the policy key in the current user hive, if it exists */
162 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
163 {
164 /* Read the value, if it's set */
165 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
166 &ValueName,
167 KeyValuePartialInformation,
168 ValueInfo,
169 sizeof(ValueBuffer),
170 &ActualSize)))
171 {
172 if (*((PULONG)ValueInfo->Data))
173 {
174 /* The VDM has been disabled in the registry */
175 VdmAllowed = FALSE;
176 }
177 }
178
179 NtClose(KeyHandle);
180 }
181
182 return VdmAllowed;
183 }
184
185 NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
186 {
187 NTSTATUS Status;
188
189 /* Create the event */
190 Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
191 if (!NT_SUCCESS(Status)) return Status;
192
193 /* Duplicate the event into the client process */
194 Status = NtDuplicateObject(NtCurrentProcess(),
195 *ServerEvent,
196 CsrGetClientThread()->Process->ProcessHandle,
197 ClientEvent,
198 0,
199 0,
200 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
201
202 if (!NT_SUCCESS(Status)) NtClose(*ServerEvent);
203 return Status;
204 }
205
206 VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
207 {
208 /* Free the allocated structure members */
209 if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
210 if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName);
211 if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile);
212 if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory);
213 if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env);
214 if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop);
215 if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title);
216 if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved);
217
218 /* Free the structure itself */
219 RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
220 }
221
222 VOID NTAPI BaseSrvCleanupVdmRecords(ULONG ProcessId)
223 {
224 PLIST_ENTRY i;
225 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
226 PVDM_DOS_RECORD DosRecord;
227
228 /* Enter the critical section */
229 RtlEnterCriticalSection(&DosCriticalSection);
230
231 /* Search for a record that has the same process handle */
232 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
233 {
234 ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
235
236 if (ConsoleRecord->ProcessId == ProcessId)
237 {
238 /* Cleanup the DOS records */
239 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
240 {
241 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
242 VDM_DOS_RECORD,
243 Entry);
244
245 /* Set the event and close it */
246 NtSetEvent(DosRecord->ServerEvent, NULL);
247 NtClose(DosRecord->ServerEvent);
248
249 /* Remove the DOS entry */
250 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
251 RemoveEntryList(&DosRecord->Entry);
252 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
253 }
254
255 if (ConsoleRecord->CurrentDirs != NULL)
256 {
257 /* Free the current directories */
258 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
259 ConsoleRecord->CurrentDirs = NULL;
260 ConsoleRecord->CurDirsLength = 0;
261 }
262
263 /* Close the event handle */
264 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
265
266 /* Remove the console record */
267 i = i->Blink;
268 RemoveEntryList(&ConsoleRecord->Entry);
269 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
270 }
271 }
272
273 /* Leave the critical section */
274 RtlLeaveCriticalSection(&DosCriticalSection);
275 }
276
277 BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
278 {
279 BOOLEAN Success = FALSE;
280 PVDM_COMMAND_INFO CommandInfo = NULL;
281
282 /* Allocate the command information structure */
283 CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap,
284 HEAP_ZERO_MEMORY,
285 sizeof(VDM_COMMAND_INFO));
286 if (CommandInfo == NULL) return FALSE;
287
288 /* Fill the structure */
289 CommandInfo->TaskId = CheckVdmRequest->iTask;
290 CommandInfo->ExitCode = DosRecord->ExitCode;
291 CommandInfo->CodePage = CheckVdmRequest->CodePage;
292 CommandInfo->StdIn = CheckVdmRequest->StdIn;
293 CommandInfo->StdOut = CheckVdmRequest->StdOut;
294 CommandInfo->StdErr = CheckVdmRequest->StdErr;
295
296 /* Allocate memory for the command line */
297 CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap,
298 HEAP_ZERO_MEMORY,
299 CheckVdmRequest->CmdLen);
300 if (CommandInfo->CmdLine == NULL) goto Cleanup;
301
302 /* Copy the command line */
303 RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen);
304
305 /* Allocate memory for the application name */
306 CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap,
307 HEAP_ZERO_MEMORY,
308 CheckVdmRequest->AppLen);
309 if (CommandInfo->AppName == NULL) goto Cleanup;
310
311 /* Copy the application name */
312 RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen);
313
314 /* Allocate memory for the PIF file name */
315 if (CheckVdmRequest->PifLen != 0)
316 {
317 CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap,
318 HEAP_ZERO_MEMORY,
319 CheckVdmRequest->PifLen);
320 if (CommandInfo->PifFile == NULL) goto Cleanup;
321
322 /* Copy the PIF file name */
323 RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen);
324 }
325 else CommandInfo->PifFile = NULL;
326
327 /* Allocate memory for the current directory */
328 if (CheckVdmRequest->CurDirectoryLen != 0)
329 {
330 CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap,
331 HEAP_ZERO_MEMORY,
332 CheckVdmRequest->CurDirectoryLen);
333 if (CommandInfo->CurDirectory == NULL) goto Cleanup;
334
335 /* Copy the current directory */
336 RtlMoveMemory(CommandInfo->CurDirectory,
337 CheckVdmRequest->CurDirectory,
338 CheckVdmRequest->CurDirectoryLen);
339 }
340 else CommandInfo->CurDirectory = NULL;
341
342 /* Allocate memory for the environment block */
343 CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap,
344 HEAP_ZERO_MEMORY,
345 CheckVdmRequest->EnvLen);
346 if (CommandInfo->Env == NULL) goto Cleanup;
347
348 /* Copy the environment block */
349 RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen);
350
351 CommandInfo->EnvLen = CheckVdmRequest->EnvLen;
352 RtlMoveMemory(&CommandInfo->StartupInfo,
353 CheckVdmRequest->StartupInfo,
354 sizeof(STARTUPINFOA));
355
356 /* Allocate memory for the desktop */
357 if (CheckVdmRequest->DesktopLen != 0)
358 {
359 CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap,
360 HEAP_ZERO_MEMORY,
361 CheckVdmRequest->DesktopLen);
362 if (CommandInfo->Desktop == NULL) goto Cleanup;
363
364 /* Copy the desktop name */
365 RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen);
366 }
367 else CommandInfo->Desktop = NULL;
368
369 CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen;
370
371 /* Allocate memory for the title */
372 if (CheckVdmRequest->TitleLen != 0)
373 {
374 CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap,
375 HEAP_ZERO_MEMORY,
376 CheckVdmRequest->TitleLen);
377 if (CommandInfo->Title == NULL) goto Cleanup;
378
379 /* Copy the title */
380 RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen);
381 }
382 else CommandInfo->Title = NULL;
383
384 CommandInfo->TitleLen = CheckVdmRequest->TitleLen;
385
386 /* Allocate memory for the reserved field */
387 if (CheckVdmRequest->ReservedLen != 0)
388 {
389 CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap,
390 HEAP_ZERO_MEMORY,
391 CheckVdmRequest->ReservedLen);
392 if (CommandInfo->Reserved == NULL) goto Cleanup;
393
394 /* Copy the reserved field */
395 RtlMoveMemory(CommandInfo->Reserved,
396 CheckVdmRequest->Reserved,
397 CheckVdmRequest->ReservedLen);
398 }
399 else CommandInfo->Reserved = NULL;
400
401 CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen;
402
403 CommandInfo->CmdLen = CheckVdmRequest->CmdLen;
404 CommandInfo->AppLen = CheckVdmRequest->AppLen;
405 CommandInfo->PifLen = CheckVdmRequest->PifLen;
406 CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen;
407 CommandInfo->VDMState = DosRecord->State;
408 // TODO: Set CommandInfo->CurrentDrive
409 // TODO: Set CommandInfo->ComingFromBat
410
411 /* Set the DOS record's command structure */
412 DosRecord->CommandInfo = CommandInfo;
413
414 /* The operation was successful */
415 Success = TRUE;
416
417 Cleanup:
418 /* If it wasn't successful, free the memory */
419 if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
420
421 return Success;
422 }
423
424 NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
425 PBASE_GET_NEXT_VDM_COMMAND Message)
426 {
427 /* Copy the data */
428 Message->iTask = CommandInfo->TaskId;
429 Message->StdIn = CommandInfo->StdIn;
430 Message->StdOut = CommandInfo->StdOut;
431 Message->StdErr = CommandInfo->StdErr;
432 Message->CodePage = CommandInfo->CodePage;
433 Message->dwCreationFlags = CommandInfo->CreationFlags;
434 Message->ExitCode = CommandInfo->ExitCode;
435 Message->CurrentDrive = CommandInfo->CurrentDrive;
436 Message->VDMState = CommandInfo->VDMState;
437 Message->fComingFromBat = CommandInfo->ComingFromBat;
438
439 if (CommandInfo->CmdLen && Message->CmdLen)
440 {
441 if (Message->CmdLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
442
443 /* Copy the command line */
444 RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
445 Message->CmdLen = CommandInfo->CmdLen;
446 }
447
448 if (CommandInfo->AppLen && Message->AppLen)
449 {
450 if (Message->AppLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
451
452 /* Copy the application name */
453 RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
454 Message->AppLen = CommandInfo->AppLen;
455 }
456
457 if (CommandInfo->PifLen && Message->PifLen)
458 {
459 if (Message->PifLen < CommandInfo->PifLen) return STATUS_BUFFER_TOO_SMALL;
460
461 /* Copy the PIF file name */
462 RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
463 Message->PifLen = CommandInfo->PifLen;
464 }
465
466 if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen)
467 {
468 if (Message->CurDirectoryLen < CommandInfo->CurDirectoryLen) return STATUS_BUFFER_TOO_SMALL;
469
470 /* Copy the current directory */
471 RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
472 Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
473 }
474
475 if (CommandInfo->EnvLen && Message->EnvLen)
476 {
477 if (Message->EnvLen < CommandInfo->EnvLen) return STATUS_BUFFER_TOO_SMALL;
478
479 /* Copy the environment */
480 RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
481 Message->EnvLen = CommandInfo->EnvLen;
482 }
483
484 /* Copy the startup info */
485 RtlMoveMemory(Message->StartupInfo,
486 &CommandInfo->StartupInfo,
487 sizeof(STARTUPINFOA));
488
489 if (CommandInfo->DesktopLen && Message->DesktopLen)
490 {
491 if (Message->DesktopLen < CommandInfo->DesktopLen) return STATUS_BUFFER_TOO_SMALL;
492
493 /* Copy the desktop name */
494 RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
495 Message->DesktopLen = CommandInfo->DesktopLen;
496 }
497
498 if (CommandInfo->TitleLen && Message->TitleLen)
499 {
500 if (Message->TitleLen < CommandInfo->TitleLen) return STATUS_BUFFER_TOO_SMALL;
501
502 /* Copy the title */
503 RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
504 Message->TitleLen = CommandInfo->TitleLen;
505 }
506
507 if (CommandInfo->ReservedLen && Message->ReservedLen)
508 {
509 if (Message->ReservedLen < CommandInfo->ReservedLen) return STATUS_BUFFER_TOO_SMALL;
510
511 /* Copy the reserved parameter */
512 RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
513 Message->ReservedLen = CommandInfo->ReservedLen;
514 }
515
516 return STATUS_SUCCESS;
517 }
518
519 VOID NTAPI BaseInitializeVDM(VOID)
520 {
521 /* Initialize the list head */
522 InitializeListHead(&VDMConsoleListHead);
523
524 /* Initialize the critical section */
525 RtlInitializeCriticalSection(&DosCriticalSection);
526 RtlInitializeCriticalSection(&WowCriticalSection);
527 }
528
529 /* PUBLIC SERVER APIS *********************************************************/
530
531 CSR_API(BaseSrvCheckVDM)
532 {
533 NTSTATUS Status;
534 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
535 PRTL_CRITICAL_SECTION CriticalSection = NULL;
536 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
537 PVDM_DOS_RECORD DosRecord = NULL;
538 BOOLEAN NewConsoleRecord = FALSE;
539
540 /* Don't do anything if the VDM has been disabled in the registry */
541 if (!BaseSrvIsVdmAllowed()) return STATUS_ACCESS_DENIED;
542
543 /* Validate the message buffers */
544 if (!CsrValidateMessageBuffer(ApiMessage,
545 (PVOID*)&CheckVdmRequest->CmdLine,
546 CheckVdmRequest->CmdLen,
547 sizeof(*CheckVdmRequest->CmdLine))
548 || !CsrValidateMessageBuffer(ApiMessage,
549 (PVOID*)&CheckVdmRequest->AppName,
550 CheckVdmRequest->AppLen,
551 sizeof(*CheckVdmRequest->AppName))
552 || !CsrValidateMessageBuffer(ApiMessage,
553 (PVOID*)&CheckVdmRequest->PifFile,
554 CheckVdmRequest->PifLen,
555 sizeof(*CheckVdmRequest->PifFile))
556 || !CsrValidateMessageBuffer(ApiMessage,
557 (PVOID*)&CheckVdmRequest->CurDirectory,
558 CheckVdmRequest->CurDirectoryLen,
559 sizeof(*CheckVdmRequest->CurDirectory))
560 || !CsrValidateMessageBuffer(ApiMessage,
561 (PVOID*)&CheckVdmRequest->Desktop,
562 CheckVdmRequest->DesktopLen,
563 sizeof(*CheckVdmRequest->Desktop))
564 || !CsrValidateMessageBuffer(ApiMessage,
565 (PVOID*)&CheckVdmRequest->Title,
566 CheckVdmRequest->TitleLen,
567 sizeof(*CheckVdmRequest->Title))
568 || !CsrValidateMessageBuffer(ApiMessage,
569 (PVOID*)&CheckVdmRequest->Reserved,
570 CheckVdmRequest->ReservedLen,
571 sizeof(*CheckVdmRequest->Reserved)))
572 {
573 return STATUS_INVALID_PARAMETER;
574 }
575
576 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
577 ? &DosCriticalSection
578 : &WowCriticalSection;
579
580 /* Enter the critical section */
581 RtlEnterCriticalSection(CriticalSection);
582
583 /* Check if this is a DOS or WOW VDM */
584 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
585 {
586 /* Get the console record */
587 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
588 &ConsoleRecord);
589
590 if (!NT_SUCCESS(Status))
591 {
592 /* Allocate a new console record */
593 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
594 HEAP_ZERO_MEMORY,
595 sizeof(VDM_CONSOLE_RECORD));
596 if (ConsoleRecord == NULL)
597 {
598 Status = STATUS_NO_MEMORY;
599 goto Cleanup;
600 }
601
602 /* Remember that the console record was allocated here */
603 NewConsoleRecord = TRUE;
604
605 /* Initialize the console record */
606 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
607 ConsoleRecord->ProcessHandle = CsrGetClientThread()->Process->ProcessHandle;
608 ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
609 ConsoleRecord->ReenterCount = 0;
610 ConsoleRecord->CurrentDirs = NULL;
611 ConsoleRecord->CurDirsLength = 0;
612 ConsoleRecord->SessionId = GetNextDosSesId();
613 InitializeListHead(&ConsoleRecord->DosListHead);
614 }
615
616 /* Allocate a new DOS record */
617 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
618 HEAP_ZERO_MEMORY,
619 sizeof(VDM_DOS_RECORD));
620 if (DosRecord == NULL)
621 {
622 Status = STATUS_NO_MEMORY;
623 goto Cleanup;
624 }
625
626 /* Initialize the DOS record */
627 DosRecord->State = VDM_NOT_LOADED;
628 DosRecord->ExitCode = 0;
629
630 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
631 if (!NT_SUCCESS(Status)) goto Cleanup;
632
633 /* Return the client event handle */
634 CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
635
636 /* Translate the input structure into a VDM command structure and set it in the DOS record */
637 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
638 {
639 /* The only possibility is that an allocation failure occurred */
640 Status = STATUS_NO_MEMORY;
641 goto Cleanup;
642 }
643
644 /* Add the DOS record */
645 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
646
647 if (ConsoleRecord->ServerEvent)
648 {
649 /* Signal the session event */
650 NtSetEvent(ConsoleRecord->ServerEvent, NULL);
651 }
652
653 if (NewConsoleRecord)
654 {
655 /* Add the console record */
656 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
657 }
658
659 CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
660 Status = STATUS_SUCCESS;
661 }
662 else
663 {
664 // TODO: NOT IMPLEMENTED
665 UNIMPLEMENTED;
666 Status = STATUS_NOT_IMPLEMENTED;
667 }
668
669 Cleanup:
670 /* Check if it failed */
671 if (!NT_SUCCESS(Status))
672 {
673 /* Free the DOS record */
674 if (DosRecord != NULL)
675 {
676 if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent);
677 if (DosRecord->ClientEvent)
678 {
679 /* Close the remote handle */
680 NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
681 DosRecord->ClientEvent,
682 NULL,
683 NULL,
684 0,
685 0,
686 DUPLICATE_CLOSE_SOURCE);
687 }
688
689 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
690 DosRecord = NULL;
691 }
692
693 /* Free the console record if it was allocated here */
694 if (NewConsoleRecord)
695 {
696 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
697 ConsoleRecord = NULL;
698 }
699 }
700
701 /* Leave the critical section */
702 RtlLeaveCriticalSection(CriticalSection);
703
704 return Status;
705 }
706
707 CSR_API(BaseSrvUpdateVDMEntry)
708 {
709 NTSTATUS Status;
710 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest;
711 PRTL_CRITICAL_SECTION CriticalSection = NULL;
712 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
713 PVDM_DOS_RECORD DosRecord = NULL;
714
715 CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
716 ? &DosCriticalSection
717 : &WowCriticalSection;
718
719 /* Enter the critical section */
720 RtlEnterCriticalSection(CriticalSection);
721
722 /* Check if this is a DOS or WOW VDM */
723 if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
724 {
725 if (UpdateVdmEntryRequest->iTask != 0)
726 {
727 /* Get the console record using the task ID */
728 Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask,
729 &ConsoleRecord);
730 }
731 else
732 {
733 /* Get the console record using the console handle */
734 Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle,
735 &ConsoleRecord);
736 }
737
738 if (!NT_SUCCESS(Status)) goto Cleanup;
739
740 /* Get the primary DOS record */
741 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
742 VDM_DOS_RECORD,
743 Entry);
744
745 switch (UpdateVdmEntryRequest->EntryIndex)
746 {
747 case VdmEntryUndo:
748 {
749 /* Close the server event handle, the client will close the client handle */
750 NtClose(DosRecord->ServerEvent);
751 DosRecord->ServerEvent = DosRecord->ClientEvent = NULL;
752
753 if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL))
754 {
755 /* Remove the DOS record */
756 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
757 RemoveEntryList(&DosRecord->Entry);
758 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
759
760 /*
761 * Since this is an undo, if that was the only DOS record the VDM
762 * won't even start, so the console record should be removed too.
763 */
764 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
765 {
766 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
767 RemoveEntryList(&ConsoleRecord->Entry);
768 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
769 }
770 }
771
772 /* It was successful */
773 Status = STATUS_SUCCESS;
774
775 break;
776 }
777
778 case VdmEntryUpdateProcess:
779 {
780 /* Duplicate the VDM process handle */
781 Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
782 UpdateVdmEntryRequest->VDMProcessHandle,
783 NtCurrentProcess(),
784 &ConsoleRecord->ProcessHandle,
785 0,
786 0,
787 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
788 if (!NT_SUCCESS(Status)) goto Cleanup;
789
790 /* Create a pair of handles to one event object */
791 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
792 &DosRecord->ClientEvent);
793 if (!NT_SUCCESS(Status)) goto Cleanup;
794
795 /* Return the client event handle */
796 UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent;
797
798 break;
799 }
800
801 case VdmEntryUpdateControlCHandler:
802 {
803 // TODO: NOT IMPLEMENTED
804 DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!");
805 Status = STATUS_NOT_IMPLEMENTED;
806
807 break;
808 }
809
810 default:
811 {
812 /* Invalid */
813 Status = STATUS_INVALID_PARAMETER;
814 }
815 }
816 }
817 else
818 {
819 // TODO: NOT IMPLEMENTED
820 UNIMPLEMENTED;
821 Status = STATUS_NOT_IMPLEMENTED;
822 }
823
824 Cleanup:
825 /* Leave the critical section */
826 RtlLeaveCriticalSection(CriticalSection);
827
828 return Status;
829 }
830
831 CSR_API(BaseSrvGetNextVDMCommand)
832 {
833 NTSTATUS Status;
834 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
835 &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
836 PRTL_CRITICAL_SECTION CriticalSection;
837 PLIST_ENTRY i = NULL;
838 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
839 PVDM_DOS_RECORD DosRecord = NULL;
840
841 /* Validate the message buffers */
842 if (!CsrValidateMessageBuffer(ApiMessage,
843 (PVOID*)&GetNextVdmCommandRequest->CmdLine,
844 GetNextVdmCommandRequest->CmdLen,
845 sizeof(*GetNextVdmCommandRequest->CmdLine))
846 || !CsrValidateMessageBuffer(ApiMessage,
847 (PVOID*)&GetNextVdmCommandRequest->AppName,
848 GetNextVdmCommandRequest->AppLen,
849 sizeof(*GetNextVdmCommandRequest->AppName))
850 || !CsrValidateMessageBuffer(ApiMessage,
851 (PVOID*)&GetNextVdmCommandRequest->PifFile,
852 GetNextVdmCommandRequest->PifLen,
853 sizeof(*GetNextVdmCommandRequest->PifFile))
854 || !CsrValidateMessageBuffer(ApiMessage,
855 (PVOID*)&GetNextVdmCommandRequest->CurDirectory,
856 GetNextVdmCommandRequest->CurDirectoryLen,
857 sizeof(*GetNextVdmCommandRequest->CurDirectory))
858 || !CsrValidateMessageBuffer(ApiMessage,
859 (PVOID*)&GetNextVdmCommandRequest->Env,
860 GetNextVdmCommandRequest->EnvLen,
861 sizeof(*GetNextVdmCommandRequest->Env))
862 || !CsrValidateMessageBuffer(ApiMessage,
863 (PVOID*)&GetNextVdmCommandRequest->Desktop,
864 GetNextVdmCommandRequest->DesktopLen,
865 sizeof(*GetNextVdmCommandRequest->Desktop))
866 || !CsrValidateMessageBuffer(ApiMessage,
867 (PVOID*)&GetNextVdmCommandRequest->Title,
868 GetNextVdmCommandRequest->TitleLen,
869 sizeof(*GetNextVdmCommandRequest->Title))
870 || !CsrValidateMessageBuffer(ApiMessage,
871 (PVOID*)&GetNextVdmCommandRequest->Reserved,
872 GetNextVdmCommandRequest->ReservedLen,
873 sizeof(*GetNextVdmCommandRequest->Reserved))
874 || !CsrValidateMessageBuffer(ApiMessage,
875 (PVOID*)&GetNextVdmCommandRequest->StartupInfo,
876 1,
877 sizeof(STARTUPINFOA)))
878 {
879 return STATUS_INVALID_PARAMETER;
880 }
881
882 CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
883 ? &WowCriticalSection
884 : &DosCriticalSection;
885
886 /* Enter the critical section */
887 RtlEnterCriticalSection(CriticalSection);
888
889 if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
890 {
891 if (GetNextVdmCommandRequest->iTask != 0)
892 {
893 /* Get the console record using the task ID */
894 Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask,
895 &ConsoleRecord);
896 }
897 else
898 {
899 /* Get the console record using the console handle */
900 Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle,
901 &ConsoleRecord);
902 }
903
904 /* Return the session ID */
905 GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
906 GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
907
908 if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND)
909 {
910 /* Check if the DOS record list is empty */
911 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
912 {
913 Status = STATUS_INVALID_PARAMETER;
914 goto Cleanup;
915 }
916
917 /* Get the first DOS record */
918 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry);
919
920 /* Make sure its command information is still there */
921 if (DosRecord->CommandInfo == NULL)
922 {
923 Status = STATUS_INVALID_PARAMETER;
924 goto Cleanup;
925 }
926
927 /* Fill the command information */
928 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
929 goto Cleanup;
930 }
931
932 /* Check if we should set the state of a running DOS record to ready */
933 if (!(GetNextVdmCommandRequest->VDMState
934 & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK)))
935 {
936 /* Search for a DOS record that is currently running */
937 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
938 {
939 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
940 if (DosRecord->State == VDM_NOT_READY) break;
941 }
942
943 /* Check if we found any */
944 if (i == &ConsoleRecord->DosListHead)
945 {
946 Status = STATUS_INVALID_PARAMETER;
947 goto Cleanup;
948 }
949
950 /* Set the exit code */
951 DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode;
952
953 /* Update the VDM state */
954 DosRecord->State = VDM_READY;
955
956 /* Notify all waiting threads that the task is finished */
957 NtSetEvent(DosRecord->ServerEvent, NULL);
958 NtClose(DosRecord->ServerEvent);
959 DosRecord->ServerEvent = NULL;
960 }
961
962 /* Search for a DOS record that isn't loaded yet */
963 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
964 {
965 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
966 if (DosRecord->State == VDM_NOT_LOADED) break;
967 }
968
969 if (i != &ConsoleRecord->DosListHead)
970 {
971 /* DOS tasks which haven't been loaded yet should have a command info structure */
972 ASSERT(DosRecord->CommandInfo != NULL);
973
974 /* Check if the caller only wants environment data */
975 if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT)
976 {
977 if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen)
978 {
979 /* Not enough space was reserved */
980 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
981 Status = STATUS_BUFFER_OVERFLOW;
982 goto Cleanup;
983 }
984
985 /* Copy the environment data */
986 RtlMoveMemory(GetNextVdmCommandRequest->Env,
987 DosRecord->CommandInfo->Env,
988 DosRecord->CommandInfo->EnvLen);
989
990 /* Return the actual size to the caller */
991 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
992 }
993 else
994 {
995 /* Fill the command information */
996 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
997
998 /* Free the command information, it's no longer needed */
999 BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1000 DosRecord->CommandInfo = NULL;
1001
1002 /* Update the VDM state */
1003 GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY;
1004 }
1005
1006 Status = STATUS_SUCCESS;
1007 goto Cleanup;
1008 }
1009 }
1010 else
1011 {
1012 // TODO: WOW SUPPORT NOT IMPLEMENTED
1013 Status = STATUS_NOT_IMPLEMENTED;
1014 goto Cleanup;
1015 }
1016
1017 /* There is no command yet */
1018 if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
1019 != (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
1020 {
1021 if (ConsoleRecord->ServerEvent)
1022 {
1023 /* Reset the event */
1024 NtResetEvent(ConsoleRecord->ServerEvent, NULL);
1025 }
1026 else
1027 {
1028 /* Create a pair of wait handles */
1029 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
1030 &ConsoleRecord->ClientEvent);
1031 if (!NT_SUCCESS(Status)) goto Cleanup;
1032 }
1033
1034 /* Return the client event handle */
1035 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
1036 }
1037
1038 Cleanup:
1039 /* Leave the critical section */
1040 RtlLeaveCriticalSection(CriticalSection);
1041
1042 return Status;
1043 }
1044
1045 CSR_API(BaseSrvExitVDM)
1046 {
1047 NTSTATUS Status;
1048 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
1049 PRTL_CRITICAL_SECTION CriticalSection = NULL;
1050 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1051 PVDM_DOS_RECORD DosRecord;
1052
1053 CriticalSection = (ExitVdmRequest->iWowTask == 0)
1054 ? &DosCriticalSection
1055 : &WowCriticalSection;
1056
1057 /* Enter the critical section */
1058 RtlEnterCriticalSection(CriticalSection);
1059
1060 if (ExitVdmRequest->iWowTask == 0)
1061 {
1062 /* Get the console record */
1063 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
1064 if (!NT_SUCCESS(Status)) goto Cleanup;
1065
1066 /* Cleanup the DOS records */
1067 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
1068 {
1069 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
1070 VDM_DOS_RECORD,
1071 Entry);
1072
1073 /* Set the event and close it */
1074 NtSetEvent(DosRecord->ServerEvent, NULL);
1075 NtClose(DosRecord->ServerEvent);
1076
1077 /* Remove the DOS entry */
1078 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1079 RemoveEntryList(&DosRecord->Entry);
1080 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1081 }
1082
1083 if (ConsoleRecord->CurrentDirs != NULL)
1084 {
1085 /* Free the current directories */
1086 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
1087 ConsoleRecord->CurrentDirs = NULL;
1088 ConsoleRecord->CurDirsLength = 0;
1089 }
1090
1091 /* Close the event handle */
1092 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
1093
1094 /* Remove the console record */
1095 RemoveEntryList(&ConsoleRecord->Entry);
1096 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
1097 }
1098 else
1099 {
1100 // TODO: NOT IMPLEMENTED
1101 UNIMPLEMENTED;
1102 Status = STATUS_NOT_IMPLEMENTED;
1103 }
1104
1105 Cleanup:
1106 /* Leave the critical section */
1107 RtlLeaveCriticalSection(CriticalSection);
1108
1109 return Status;
1110 }
1111
1112 CSR_API(BaseSrvIsFirstVDM)
1113 {
1114 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
1115
1116 /* Return the result */
1117 IsFirstVDMRequest->FirstVDM = FirstVDM;
1118
1119 /* Clear the first VDM flag */
1120 FirstVDM = FALSE;
1121
1122 return STATUS_SUCCESS;
1123 }
1124
1125 CSR_API(BaseSrvGetVDMExitCode)
1126 {
1127 NTSTATUS Status;
1128 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
1129 PLIST_ENTRY i = NULL;
1130 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1131 PVDM_DOS_RECORD DosRecord = NULL;
1132
1133 /* Enter the critical section */
1134 RtlEnterCriticalSection(&DosCriticalSection);
1135
1136 /* Get the console record */
1137 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
1138 if (!NT_SUCCESS(Status)) goto Cleanup;
1139
1140 /* Search for a DOS record that has the same parent process handle */
1141 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1142 {
1143 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1144 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
1145 }
1146
1147 /* Check if no DOS record was found */
1148 if (i == &ConsoleRecord->DosListHead)
1149 {
1150 Status = STATUS_NOT_FOUND;
1151 goto Cleanup;
1152 }
1153
1154 /* Check if this task is still running */
1155 if (DosRecord->State == VDM_READY)
1156 {
1157 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
1158 goto Cleanup;
1159 }
1160
1161 /* Return the exit code */
1162 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
1163
1164 /* Since this is a zombie task record, remove it */
1165 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1166 RemoveEntryList(&DosRecord->Entry);
1167 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1168
1169 Cleanup:
1170 /* Leave the critical section */
1171 RtlLeaveCriticalSection(&DosCriticalSection);
1172
1173 return Status;
1174 }
1175
1176 CSR_API(BaseSrvSetReenterCount)
1177 {
1178 NTSTATUS Status = STATUS_SUCCESS;
1179 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
1180 PVDM_CONSOLE_RECORD ConsoleRecord;
1181
1182 /* Enter the critical section */
1183 RtlEnterCriticalSection(&DosCriticalSection);
1184
1185 /* Get the console record */
1186 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
1187 if (!NT_SUCCESS(Status)) goto Cleanup;
1188
1189 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
1190 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
1191 {
1192 ConsoleRecord->ReenterCount--;
1193 if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
1194 }
1195 else Status = STATUS_INVALID_PARAMETER;
1196
1197 Cleanup:
1198 /* Leave the critical section */
1199 RtlLeaveCriticalSection(&DosCriticalSection);
1200
1201 return Status;
1202 }
1203
1204 CSR_API(BaseSrvSetVDMCurDirs)
1205 {
1206 NTSTATUS Status;
1207 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1208 PVDM_CONSOLE_RECORD ConsoleRecord;
1209 PCHAR Buffer = NULL;
1210
1211 /* Validate the input buffer */
1212 if (!CsrValidateMessageBuffer(ApiMessage,
1213 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1214 VDMCurrentDirsRequest->cchCurDirs,
1215 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1216 {
1217 return STATUS_INVALID_PARAMETER;
1218 }
1219
1220 /* Enter the critical section */
1221 RtlEnterCriticalSection(&DosCriticalSection);
1222
1223 /* Find the console record */
1224 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1225 if (!NT_SUCCESS(Status)) goto Cleanup;
1226
1227 if (ConsoleRecord->CurrentDirs == NULL)
1228 {
1229 /* Allocate memory for the current directory information */
1230 Buffer = RtlAllocateHeap(BaseSrvHeap,
1231 HEAP_ZERO_MEMORY,
1232 VDMCurrentDirsRequest->cchCurDirs);
1233 }
1234 else
1235 {
1236 /* Resize the amount of allocated memory */
1237 Buffer = RtlReAllocateHeap(BaseSrvHeap,
1238 HEAP_ZERO_MEMORY,
1239 ConsoleRecord->CurrentDirs,
1240 VDMCurrentDirsRequest->cchCurDirs);
1241 }
1242
1243 if (Buffer == NULL)
1244 {
1245 /* Allocation failed */
1246 Status = STATUS_NO_MEMORY;
1247 goto Cleanup;
1248 }
1249
1250 /* Update the console record */
1251 ConsoleRecord->CurrentDirs = Buffer;
1252 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
1253
1254 /* Copy the data */
1255 RtlMoveMemory(ConsoleRecord->CurrentDirs,
1256 VDMCurrentDirsRequest->lpszzCurDirs,
1257 VDMCurrentDirsRequest->cchCurDirs);
1258
1259 Cleanup:
1260 /* Leave the critical section */
1261 RtlLeaveCriticalSection(&DosCriticalSection);
1262
1263 return Status;
1264 }
1265
1266 CSR_API(BaseSrvGetVDMCurDirs)
1267 {
1268 NTSTATUS Status;
1269 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1270 PVDM_CONSOLE_RECORD ConsoleRecord;
1271
1272 /* Validate the output buffer */
1273 if (!CsrValidateMessageBuffer(ApiMessage,
1274 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1275 VDMCurrentDirsRequest->cchCurDirs,
1276 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1277 {
1278 return STATUS_INVALID_PARAMETER;
1279 }
1280
1281 /* Enter the critical section */
1282 RtlEnterCriticalSection(&DosCriticalSection);
1283
1284 /* Find the console record */
1285 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1286 if (!NT_SUCCESS(Status)) goto Cleanup;
1287
1288 /* Return the actual size of the current directory information */
1289 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
1290
1291 /* Check if the buffer is large enough */
1292 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
1293 {
1294 Status = STATUS_BUFFER_TOO_SMALL;
1295 goto Cleanup;
1296 }
1297
1298 /* Copy the data */
1299 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
1300 ConsoleRecord->CurrentDirs,
1301 ConsoleRecord->CurDirsLength);
1302
1303 Cleanup:
1304 /* Leave the critical section */
1305 RtlLeaveCriticalSection(&DosCriticalSection);
1306
1307 return Status;
1308 }
1309
1310 CSR_API(BaseSrvBatNotification)
1311 {
1312 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1313 return STATUS_NOT_IMPLEMENTED;
1314 }
1315
1316 CSR_API(BaseSrvRegisterWowExec)
1317 {
1318 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1319 return STATUS_NOT_IMPLEMENTED;
1320 }
1321
1322 CSR_API(BaseSrvRefreshIniFileMapping)
1323 {
1324 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1325 return STATUS_NOT_IMPLEMENTED;
1326 }
1327
1328 /* EOF */