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