[CONSOLE.DLL]
[reactos.git] / win32ss / user / consrv / handle.c
1 /*
2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/handle.c
5 * PURPOSE: Console I/O Handles functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13
14 //#define NDEBUG
15 #include <debug.h>
16
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 static INT
21 AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
22 {
23 Object_t *Object = Entry->Object;
24
25 DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
26
27 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
28 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
29 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
30 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
31
32 Object->HandleCount += Change;
33
34 return Object->HandleCount;
35 }
36
37 static VOID
38 ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
39 {
40 /// LOCK /// Object_t *Object = Entry->Object;
41 /// LOCK /// EnterCriticalSection(&Object->Console->Lock);
42 AdjustHandleCounts(Entry, +1);
43 /// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
44 }
45
46 static VOID
47 ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
48 {
49 Object_t *Object = Entry->Object;
50 if (Object != NULL)
51 {
52 /// LOCK /// PCONSOLE Console = Object->Console;
53 /// LOCK /// EnterCriticalSection(&Console->Lock);
54
55 /*
56 * If this is a input handle, notify and dereference
57 * all the waits related to this handle.
58 */
59 if (Object->Type == CONIO_INPUT_BUFFER_MAGIC)
60 {
61 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
62
63 /*
64 * Wake up all the writing waiters related to this handle for this
65 * input buffer, if any, then dereference them and purge them all
66 * from the list.
67 * To select them amongst all the waiters for this input buffer,
68 * pass the handle pointer to the waiters, then they will check
69 * whether or not they are related to this handle and if so, they
70 * return.
71 */
72 CsrNotifyWait(&InputBuffer->ReadWaitQueue,
73 WaitAll,
74 NULL,
75 (PVOID)Entry);
76 if (!IsListEmpty(&InputBuffer->ReadWaitQueue))
77 {
78 CsrDereferenceWait(&InputBuffer->ReadWaitQueue);
79 }
80 }
81
82 /* If the last handle to a screen buffer is closed, delete it... */
83 if (AdjustHandleCounts(Entry, -1) == 0)
84 {
85 if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
86 {
87 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
88 /* ...unless it's the only buffer left. Windows allows deletion
89 * even of the last buffer, but having to deal with a lack of
90 * any active buffer might be error-prone. */
91 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
92 ConioDeleteScreenBuffer(Buffer);
93 }
94 else if (Object->Type == CONIO_INPUT_BUFFER_MAGIC)
95 {
96 DPRINT1("Closing the input buffer\n");
97 }
98 }
99
100 /// LOCK /// LeaveCriticalSection(&Console->Lock);
101 Entry->Object = NULL;
102 }
103 }
104
105
106 /* FUNCTIONS *****************************************************************/
107
108 /* static */ NTSTATUS
109 FASTCALL
110 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
111 OUT PHANDLE pInputHandle,
112 OUT PHANDLE pOutputHandle,
113 OUT PHANDLE pErrorHandle)
114 {
115 NTSTATUS Status;
116 HANDLE InputHandle = INVALID_HANDLE_VALUE,
117 OutputHandle = INVALID_HANDLE_VALUE,
118 ErrorHandle = INVALID_HANDLE_VALUE;
119
120 /*
121 * Initialize the handles table. Use temporary variables to store
122 * the handles values in such a way that, if we fail, we don't
123 * return to the caller invalid handle values.
124 *
125 * Insert the IO handles.
126 */
127
128 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
129
130 /* Insert the Input handle */
131 Status = ConSrvInsertObject(ProcessData,
132 &InputHandle,
133 &ProcessData->Console->InputBuffer.Header,
134 GENERIC_READ | GENERIC_WRITE,
135 TRUE,
136 FILE_SHARE_READ | FILE_SHARE_WRITE);
137 if (!NT_SUCCESS(Status))
138 {
139 DPRINT1("Failed to insert the input handle\n");
140 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
141 ConSrvFreeHandlesTable(ProcessData);
142 return Status;
143 }
144
145 /* Insert the Output handle */
146 Status = ConSrvInsertObject(ProcessData,
147 &OutputHandle,
148 &ProcessData->Console->ActiveBuffer->Header,
149 GENERIC_READ | GENERIC_WRITE,
150 TRUE,
151 FILE_SHARE_READ | FILE_SHARE_WRITE);
152 if (!NT_SUCCESS(Status))
153 {
154 DPRINT1("Failed to insert the output handle\n");
155 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
156 ConSrvFreeHandlesTable(ProcessData);
157 return Status;
158 }
159
160 /* Insert the Error handle */
161 Status = ConSrvInsertObject(ProcessData,
162 &ErrorHandle,
163 &ProcessData->Console->ActiveBuffer->Header,
164 GENERIC_READ | GENERIC_WRITE,
165 TRUE,
166 FILE_SHARE_READ | FILE_SHARE_WRITE);
167 if (!NT_SUCCESS(Status))
168 {
169 DPRINT1("Failed to insert the error handle\n");
170 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
171 ConSrvFreeHandlesTable(ProcessData);
172 return Status;
173 }
174
175 /* Return the newly created handles */
176 *pInputHandle = InputHandle;
177 *pOutputHandle = OutputHandle;
178 *pErrorHandle = ErrorHandle;
179
180 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
181 return STATUS_SUCCESS;
182 }
183
184 NTSTATUS
185 FASTCALL
186 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
187 IN PCONSOLE_PROCESS_DATA TargetProcessData)
188 {
189 NTSTATUS Status = STATUS_SUCCESS;
190 ULONG i;
191
192 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
193
194 /* Inherit a handles table only if there is no already */
195 if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
196 {
197 Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
198 goto Quit;
199 }
200
201 /* Allocate a new handle table for the child process */
202 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
203 HEAP_ZERO_MEMORY,
204 SourceProcessData->HandleTableSize
205 * sizeof(CONSOLE_IO_HANDLE));
206 if (TargetProcessData->HandleTable == NULL)
207 {
208 Status = STATUS_NO_MEMORY;
209 goto Quit;
210 }
211
212 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
213
214 /*
215 * Parse the parent process' handles table and, for each handle,
216 * do a copy of it and reference it, if the handle is inheritable.
217 */
218 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
219 {
220 if (SourceProcessData->HandleTable[i].Object != NULL &&
221 SourceProcessData->HandleTable[i].Inheritable)
222 {
223 /*
224 * Copy the handle data and increment the reference count of the
225 * pointed object (via the call to ConSrvCreateHandleEntry).
226 */
227 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
228 ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[i]);
229 }
230 }
231
232 Quit:
233 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
234 return Status;
235 }
236
237 VOID
238 FASTCALL
239 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
240 {
241 DPRINT1("ConSrvFreeHandlesTable\n");
242
243 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
244
245 if (ProcessData->HandleTable != NULL)
246 {
247 ULONG i;
248
249 /* Close all console handles and free the handle table memory */
250 for (i = 0; i < ProcessData->HandleTableSize; i++)
251 {
252 ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
253 }
254 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
255 ProcessData->HandleTable = NULL;
256 }
257
258 ProcessData->HandleTableSize = 0;
259
260 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
261 }
262
263 NTSTATUS
264 FASTCALL
265 ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
266 PHANDLE Handle,
267 Object_t *Object,
268 DWORD Access,
269 BOOL Inheritable,
270 DWORD ShareMode)
271 {
272 #define IO_HANDLES_INCREMENT 2*3
273
274 ULONG i;
275 PCONSOLE_IO_HANDLE Block;
276
277 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
278
279 for (i = 0; i < ProcessData->HandleTableSize; i++)
280 {
281 if (ProcessData->HandleTable[i].Object == NULL)
282 {
283 break;
284 }
285 }
286 if (i >= ProcessData->HandleTableSize)
287 {
288 Block = RtlAllocateHeap(ConSrvHeap,
289 HEAP_ZERO_MEMORY,
290 (ProcessData->HandleTableSize +
291 IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
292 if (Block == NULL)
293 {
294 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
295 return STATUS_UNSUCCESSFUL;
296 }
297 RtlCopyMemory(Block,
298 ProcessData->HandleTable,
299 ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
300 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
301 ProcessData->HandleTable = Block;
302 ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
303 }
304
305 ProcessData->HandleTable[i].Object = Object;
306 ProcessData->HandleTable[i].Access = Access;
307 ProcessData->HandleTable[i].Inheritable = Inheritable;
308 ProcessData->HandleTable[i].ShareMode = ShareMode;
309 ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
310 *Handle = ULongToHandle((i << 2) | 0x3);
311
312 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
313
314 return STATUS_SUCCESS;
315 }
316
317 NTSTATUS
318 FASTCALL
319 ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
320 HANDLE Handle)
321 {
322 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
323 Object_t *Object;
324
325 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
326
327 if (h >= ProcessData->HandleTableSize ||
328 (Object = ProcessData->HandleTable[h].Object) == NULL)
329 {
330 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
331 return STATUS_INVALID_HANDLE;
332 }
333
334 DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
335 ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
336
337 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
338
339 return STATUS_SUCCESS;
340 }
341
342 NTSTATUS
343 FASTCALL
344 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
345 HANDLE Handle,
346 Object_t** Object,
347 PCONSOLE_IO_HANDLE* Entry OPTIONAL,
348 DWORD Access,
349 BOOL LockConsole,
350 ULONG Type)
351 {
352 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
353 PCONSOLE_IO_HANDLE HandleEntry = NULL;
354 Object_t* ObjectEntry = NULL;
355
356 ASSERT(Object);
357 if (Entry) *Entry = NULL;
358
359 // DPRINT("ConSrvGetObject, Object: %x, %x, %x\n",
360 // Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
361
362 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
363
364 if ( IsConsoleHandle(Handle) &&
365 h < ProcessData->HandleTableSize )
366 {
367 HandleEntry = &ProcessData->HandleTable[h];
368 ObjectEntry = HandleEntry->Object;
369 }
370
371 if ( HandleEntry == NULL ||
372 ObjectEntry == NULL ||
373 (HandleEntry->Access & Access) == 0 ||
374 (Type != 0 && ObjectEntry->Type != Type) )
375 {
376 DPRINT1("CsrGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access);
377 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
378 return STATUS_INVALID_HANDLE;
379 }
380
381 _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
382 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
383
384 if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock);
385
386 /* Return the objects to the caller */
387 *Object = ObjectEntry;
388 if (Entry) *Entry = HandleEntry;
389
390 return STATUS_SUCCESS;
391 }
392
393 VOID
394 FASTCALL
395 ConSrvReleaseObject(Object_t *Object,
396 BOOL IsConsoleLocked)
397 {
398 ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
399 }
400
401 NTSTATUS
402 FASTCALL
403 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
404 LPCWSTR AppPath,
405 PHANDLE pInputHandle,
406 PHANDLE pOutputHandle,
407 PHANDLE pErrorHandle,
408 PCONSOLE_START_INFO ConsoleStartInfo)
409 {
410 NTSTATUS Status = STATUS_SUCCESS;
411
412 /* Initialize a new Console owned by this process */
413 Status = ConSrvInitConsole(&ProcessData->Console, AppPath, ConsoleStartInfo, ProcessData->Process);
414 if (!NT_SUCCESS(Status))
415 {
416 DPRINT1("Console initialization failed\n");
417 return Status;
418 }
419
420 /* Initialize the handles table */
421 Status = ConSrvInitHandlesTable(ProcessData,
422 pInputHandle,
423 pOutputHandle,
424 pErrorHandle);
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("Failed to initialize the handles table\n");
428 ConSrvDeleteConsole(ProcessData->Console);
429 ProcessData->Console = NULL;
430 return Status;
431 }
432
433 /* Duplicate the Input Event */
434 Status = NtDuplicateObject(NtCurrentProcess(),
435 ProcessData->Console->InputBuffer.ActiveEvent,
436 ProcessData->Process->ProcessHandle,
437 &ProcessData->ConsoleEvent,
438 EVENT_ALL_ACCESS, 0, 0);
439 if (!NT_SUCCESS(Status))
440 {
441 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
442 ConSrvFreeHandlesTable(ProcessData);
443 ConSrvDeleteConsole(ProcessData->Console);
444 ProcessData->Console = NULL;
445 return Status;
446 }
447
448 /* Insert the process into the processes list of the console */
449 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
450
451 /* Add a reference count because the process is tied to the console */
452 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
453
454 return STATUS_SUCCESS;
455 }
456
457 NTSTATUS
458 FASTCALL
459 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
460 PCONSOLE Console,
461 BOOL CreateNewHandlesTable,
462 PHANDLE pInputHandle,
463 PHANDLE pOutputHandle,
464 PHANDLE pErrorHandle)
465 {
466 NTSTATUS Status = STATUS_SUCCESS;
467
468 /* Inherit the console */
469 ProcessData->Console = Console;
470
471 if (CreateNewHandlesTable)
472 {
473 /* Initialize the handles table */
474 Status = ConSrvInitHandlesTable(ProcessData,
475 pInputHandle,
476 pOutputHandle,
477 pErrorHandle);
478 if (!NT_SUCCESS(Status))
479 {
480 DPRINT1("Failed to initialize the handles table\n");
481 ProcessData->Console = NULL;
482 return Status;
483 }
484 }
485
486 /* Duplicate the Input Event */
487 Status = NtDuplicateObject(NtCurrentProcess(),
488 ProcessData->Console->InputBuffer.ActiveEvent,
489 ProcessData->Process->ProcessHandle,
490 &ProcessData->ConsoleEvent,
491 EVENT_ALL_ACCESS, 0, 0);
492 if (!NT_SUCCESS(Status))
493 {
494 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
495 ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
496 ProcessData->Console = NULL;
497 return Status;
498 }
499
500 /* Insert the process into the processes list of the console */
501 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
502
503 /* Add a reference count because the process is tied to the console */
504 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
505
506 return STATUS_SUCCESS;
507 }
508
509 VOID
510 FASTCALL
511 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
512 {
513 PCONSOLE Console;
514 PCONSOLE_PROCESS_DATA NewProcessData;
515
516 DPRINT1("ConSrvRemoveConsole\n");
517
518 /* Close all console handles and free the handle table memory */
519 ConSrvFreeHandlesTable(ProcessData);
520
521 /* Detach process from console */
522 Console = ProcessData->Console;
523 if (Console != NULL)
524 {
525 DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
526 ProcessData->Console = NULL;
527
528 EnterCriticalSection(&Console->Lock);
529 DPRINT1("ConSrvRemoveConsole - Locking OK\n");
530
531 /* Remove ourselves from the console's list of processes */
532 RemoveEntryList(&ProcessData->ConsoleLink);
533
534 /* Update the console leader process */
535 NewProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
536 CONSOLE_PROCESS_DATA,
537 ConsoleLink);
538 Console->ConsoleLeaderCID = NewProcessData->Process->ClientId;
539 SetConsoleWndConsoleLeaderCID(Console);
540
541 /* Release the console */
542 ConSrvReleaseConsole(Console, TRUE);
543 //CloseHandle(ProcessData->ConsoleEvent);
544 //ProcessData->ConsoleEvent = NULL;
545 }
546 }
547
548 NTSTATUS
549 FASTCALL
550 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
551 PCONSOLE* Console,
552 BOOL LockConsole)
553 {
554 PCONSOLE ProcessConsole;
555
556 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
557 ProcessConsole = ProcessData->Console;
558
559 if (!ProcessConsole)
560 {
561 *Console = NULL;
562 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
563 return STATUS_INVALID_HANDLE;
564 }
565
566 InterlockedIncrement(&ProcessConsole->ReferenceCount);
567 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
568
569 if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
570
571 *Console = ProcessConsole;
572
573 return STATUS_SUCCESS;
574 }
575
576 VOID FASTCALL
577 ConSrvReleaseConsole(PCONSOLE Console,
578 BOOL IsConsoleLocked)
579 {
580 if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
581
582 /* Decrement reference count */
583 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
584 ConSrvDeleteConsole(Console);
585 }
586
587 NTSTATUS
588 NTAPI
589 ConSrvNewProcess(PCSR_PROCESS SourceProcess,
590 PCSR_PROCESS TargetProcess)
591 {
592 /**************************************************************************
593 * This function is called whenever a new process (GUI or CUI) is created.
594 *
595 * Copy the parent's handles table here if both the parent and the child
596 * processes are CUI. If we must actually create our proper console (and
597 * thus do not inherit from the console handles of the parent's), then we
598 * will clean this table in the next ConSrvConnect call. Why we are doing
599 * this? It's because here, we still don't know whether or not we must create
600 * a new console instead of inherit it from the parent, and, because in
601 * ConSrvConnect we don't have any reference to the parent process anymore.
602 **************************************************************************/
603
604 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
605
606 DPRINT1("ConSrvNewProcess\n");
607 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
608
609 /* An empty target process is invalid */
610 if (!TargetProcess)
611 return STATUS_INVALID_PARAMETER;
612
613 DPRINT1("ConSrvNewProcess - OK\n");
614
615 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
616
617 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
618
619 /* Initialize the new (target) process */
620 TargetProcessData->Process = TargetProcess;
621 TargetProcessData->ConsoleEvent = NULL;
622 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
623 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
624
625 // Testing
626 TargetProcessData->HandleTableSize = 0;
627 TargetProcessData->HandleTable = NULL;
628
629 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
630
631 /* Do nothing if the source process is NULL */
632 if (!SourceProcess)
633 return STATUS_SUCCESS;
634
635 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
636
637 /*
638 * If both of the processes (parent and new child) are console applications,
639 * then try to inherit handles from the parent process.
640 */
641 if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
642 TargetProcessData->ConsoleApp )
643 {
644 NTSTATUS Status;
645
646 Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
647 if (!NT_SUCCESS(Status)) return Status;
648
649 /* Temporary save the parent's console */
650 TargetProcessData->ParentConsole = SourceProcessData->Console;
651 }
652 else
653 {
654 DPRINT1("ConSrvNewProcess - We don't inherit a handle table : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
655 }
656
657 return STATUS_SUCCESS;
658 }
659
660 NTSTATUS
661 NTAPI
662 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
663 IN OUT PVOID ConnectionInfo,
664 IN OUT PULONG ConnectionInfoLength)
665 {
666 /**************************************************************************
667 * This function is called whenever a CUI new process is created.
668 **************************************************************************/
669
670 NTSTATUS Status = STATUS_SUCCESS;
671 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
672 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
673
674 DPRINT1("ConSrvConnect\n");
675
676 if ( ConnectionInfo == NULL ||
677 ConnectionInfoLength == NULL ||
678 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
679 {
680 DPRINT1("CONSRV: Connection failed\n");
681 return STATUS_UNSUCCESSFUL;
682 }
683
684 /* If we don't need a console, then get out of here */
685 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
686 {
687 DPRINT("ConSrvConnect - No console needed\n");
688 return STATUS_SUCCESS;
689 }
690
691 /* If we don't have a console, then create a new one... */
692 if (!ConnectInfo->Console ||
693 ConnectInfo->Console != ProcessData->ParentConsole)
694 {
695 DPRINT1("ConSrvConnect - Allocate a new console\n");
696
697 /*
698 * We are about to create a new console. However when ConSrvNewProcess
699 * was called, we didn't know that we wanted to create a new console and
700 * therefore, we by default inherited the handles table from our parent
701 * process. It's only now that we notice that in fact we do not need
702 * them, because we've created a new console and thus we must use it.
703 *
704 * Therefore, free the console we can have and our handles table,
705 * and recreate a new one later on.
706 */
707 ConSrvRemoveConsole(ProcessData);
708
709 /* Initialize a new Console owned by the Console Leader Process */
710 Status = ConSrvAllocateConsole(ProcessData,
711 ConnectInfo->AppPath,
712 &ConnectInfo->InputHandle,
713 &ConnectInfo->OutputHandle,
714 &ConnectInfo->ErrorHandle,
715 &ConnectInfo->ConsoleStartInfo);
716 if (!NT_SUCCESS(Status))
717 {
718 DPRINT1("Console allocation failed\n");
719 return Status;
720 }
721 }
722 else /* We inherit it from the parent */
723 {
724 DPRINT1("ConSrvConnect - Reuse current (parent's) console\n");
725
726 /* Reuse our current console */
727 Status = ConSrvInheritConsole(ProcessData,
728 ConnectInfo->Console,
729 FALSE,
730 NULL, // &ConnectInfo->InputHandle,
731 NULL, // &ConnectInfo->OutputHandle,
732 NULL); // &ConnectInfo->ErrorHandle);
733 if (!NT_SUCCESS(Status))
734 {
735 DPRINT1("Console inheritance failed\n");
736 return Status;
737 }
738 }
739
740 /* Return it to the caller */
741 ConnectInfo->Console = ProcessData->Console;
742
743 /* Input Wait Handle */
744 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
745
746 /* Set the Property Dialog Handler */
747 ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
748
749 /* Set the Ctrl Dispatcher */
750 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
751 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
752
753 return STATUS_SUCCESS;
754 }
755
756 VOID
757 WINAPI
758 ConSrvDisconnect(PCSR_PROCESS Process)
759 {
760 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
761
762 /**************************************************************************
763 * This function is called whenever a new process (GUI or CUI) is destroyed.
764 **************************************************************************/
765
766 DPRINT1("ConSrvDisconnect\n");
767
768 if ( ProcessData->Console != NULL ||
769 ProcessData->HandleTable != NULL )
770 {
771 DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
772 ConSrvRemoveConsole(ProcessData);
773 }
774
775 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
776 }
777
778
779
780 CSR_API(SrvCloseHandle)
781 {
782 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
783
784 return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
785 CloseHandleRequest->ConsoleHandle);
786 }
787
788 CSR_API(SrvVerifyConsoleIoHandle)
789 {
790 NTSTATUS Status = STATUS_SUCCESS;
791 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
792 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
793 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
794 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
795
796 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
797
798 if (!IsConsoleHandle(ConsoleHandle) ||
799 Index >= ProcessData->HandleTableSize ||
800 ProcessData->HandleTable[Index].Object == NULL)
801 {
802 DPRINT("CsrVerifyObject failed\n");
803 Status = STATUS_INVALID_HANDLE;
804 }
805
806 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
807
808 return Status;
809 }
810
811 CSR_API(SrvDuplicateHandle)
812 {
813 PCONSOLE_IO_HANDLE Entry;
814 DWORD DesiredAccess;
815 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
816 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
817 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
818 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
819
820 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
821
822 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
823 Index >= ProcessData->HandleTableSize ||
824 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
825 {
826 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
827 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
828 return STATUS_INVALID_HANDLE;
829 }
830
831 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
832 {
833 DesiredAccess = Entry->Access;
834 }
835 else
836 {
837 DesiredAccess = DuplicateHandleRequest->Access;
838 /* Make sure the source handle has all the desired flags */
839 if ((Entry->Access & DesiredAccess) == 0)
840 {
841 DPRINT1("Handle %p only has access %X; requested %X\n",
842 ConsoleHandle, Entry->Access, DesiredAccess);
843 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
844 return STATUS_INVALID_PARAMETER;
845 }
846 }
847
848 ApiMessage->Status = ConSrvInsertObject(ProcessData,
849 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
850 Entry->Object,
851 DesiredAccess,
852 DuplicateHandleRequest->Inheritable,
853 Entry->ShareMode);
854 if (NT_SUCCESS(ApiMessage->Status) &&
855 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
856 {
857 ConSrvCloseHandleEntry(Entry);
858 }
859
860 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
861 return ApiMessage->Status;
862 }
863
864 /**
865 CSR_API(CsrGetInputWaitHandle)
866 {
867 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
868
869 GetConsoleInputWaitHandle->InputWaitHandle =
870 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
871
872 return STATUS_SUCCESS;
873 }
874 **/
875
876 /* EOF */