2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/handle.c
5 * PURPOSE: Console I/O Handles functions
6 * PROGRAMMERS: David Welch
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
15 #include <win/console.h>
20 /* GLOBALS ********************************************************************/
23 typedef struct _CONSOLE_IO_HANDLE
25 PCONSOLE_IO_OBJECT Object
; /* The object on which the handle points to */
29 } CONSOLE_IO_HANDLE
, *PCONSOLE_IO_HANDLE
;
32 /* PRIVATE FUNCTIONS **********************************************************/
35 AdjustHandleCounts(IN PCONSOLE_IO_HANDLE Handle
,
38 PCONSOLE_IO_OBJECT Object
= Handle
->Object
;
40 DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n",
41 Handle
, Change
, Object
);
42 DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->ReferenceCount = %d, Object->Type = %lu\n",
43 Handle
, Change
, Object
, Object
->ReferenceCount
, Object
->Type
);
45 if (Handle
->Access
& GENERIC_READ
) Object
->AccessRead
+= Change
;
46 if (Handle
->Access
& GENERIC_WRITE
) Object
->AccessWrite
+= Change
;
47 if (!(Handle
->ShareMode
& FILE_SHARE_READ
)) Object
->ExclusiveRead
+= Change
;
48 if (!(Handle
->ShareMode
& FILE_SHARE_WRITE
)) Object
->ExclusiveWrite
+= Change
;
50 Object
->ReferenceCount
+= Change
;
52 return Object
->ReferenceCount
;
56 ConSrvCloseHandle(IN PCONSOLE_IO_HANDLE Handle
)
58 PCONSOLE_IO_OBJECT Object
= Handle
->Object
;
62 * If this is a input handle, notify and dereference
63 * all the waits related to this handle.
65 if (Object
->Type
== INPUT_BUFFER
)
67 // PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
68 PCONSOLE Console
= Object
->Console
;
71 * Wake up all the writing waiters related to this handle for this
72 * input buffer, if any, then dereference them and purge them all
74 * To select them amongst all the waiters for this input buffer,
75 * pass the handle pointer to the waiters, then they will check
76 * whether or not they are related to this handle and if so, they
79 CsrNotifyWait(&Console
->ReadWaitQueue
,
83 if (!IsListEmpty(&Console
->ReadWaitQueue
))
85 CsrDereferenceWait(&Console
->ReadWaitQueue
);
89 /* If the last handle to a screen buffer is closed, delete it... */
90 if (AdjustHandleCounts(Handle
, -1) == 0)
92 if (Object
->Type
== TEXTMODE_BUFFER
|| Object
->Type
== GRAPHICS_BUFFER
)
94 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
95 /* ...unless it's the only buffer left. Windows allows deletion
96 * even of the last buffer, but having to deal with a lack of
97 * any active buffer might be error-prone. */
98 if (Buffer
->ListEntry
.Flink
!= Buffer
->ListEntry
.Blink
)
99 ConDrvDeleteScreenBuffer(Buffer
);
101 else if (Object
->Type
== INPUT_BUFFER
)
103 DPRINT("Closing the input buffer\n");
107 DPRINT1("Invalid object type %d\n", Object
->Type
);
111 /* Invalidate (zero-out) this handle entry */
112 // Handle->Object = NULL;
113 // RtlZeroMemory(Handle, sizeof(*Handle));
115 RtlZeroMemory(Handle
, sizeof(*Handle
)); // Be sure the whole entry is invalidated.
123 /* Forward declaration, used in ConSrvInitHandlesTable */
124 static VOID
ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData
);
127 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData
,
129 OUT PHANDLE pInputHandle
,
130 OUT PHANDLE pOutputHandle
,
131 OUT PHANDLE pErrorHandle
)
134 HANDLE InputHandle
= INVALID_HANDLE_VALUE
,
135 OutputHandle
= INVALID_HANDLE_VALUE
,
136 ErrorHandle
= INVALID_HANDLE_VALUE
;
139 * Initialize the handles table. Use temporary variables to store
140 * the handles values in such a way that, if we fail, we don't
141 * return to the caller invalid handle values.
143 * Insert the IO handles.
146 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
148 /* Insert the Input handle */
149 Status
= ConSrvInsertObject(ProcessData
,
151 &Console
->InputBuffer
.Header
,
152 GENERIC_READ
| GENERIC_WRITE
,
154 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
155 if (!NT_SUCCESS(Status
))
157 DPRINT1("Failed to insert the input handle\n");
158 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
159 ConSrvFreeHandlesTable(ProcessData
);
163 /* Insert the Output handle */
164 Status
= ConSrvInsertObject(ProcessData
,
166 &Console
->ActiveBuffer
->Header
,
167 GENERIC_READ
| GENERIC_WRITE
,
169 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
170 if (!NT_SUCCESS(Status
))
172 DPRINT1("Failed to insert the output handle\n");
173 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
174 ConSrvFreeHandlesTable(ProcessData
);
178 /* Insert the Error handle */
179 Status
= ConSrvInsertObject(ProcessData
,
181 &Console
->ActiveBuffer
->Header
,
182 GENERIC_READ
| GENERIC_WRITE
,
184 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
185 if (!NT_SUCCESS(Status
))
187 DPRINT1("Failed to insert the error handle\n");
188 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
189 ConSrvFreeHandlesTable(ProcessData
);
193 /* Return the newly created handles */
194 *pInputHandle
= InputHandle
;
195 *pOutputHandle
= OutputHandle
;
196 *pErrorHandle
= ErrorHandle
;
198 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
199 return STATUS_SUCCESS
;
203 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData
,
204 IN PCONSOLE_PROCESS_DATA TargetProcessData
)
206 NTSTATUS Status
= STATUS_SUCCESS
;
209 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
211 /* Inherit a handles table only if there is no already */
212 if (TargetProcessData
->HandleTable
!= NULL
/* || TargetProcessData->HandleTableSize != 0 */)
214 Status
= STATUS_UNSUCCESSFUL
;
218 /* Allocate a new handle table for the child process */
219 TargetProcessData
->HandleTable
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
220 SourceProcessData
->HandleTableSize
221 * sizeof(CONSOLE_IO_HANDLE
));
222 if (TargetProcessData
->HandleTable
== NULL
)
224 Status
= STATUS_NO_MEMORY
;
228 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
231 * Parse the parent process' handles table and, for each handle,
232 * do a copy of it and reference it, if the handle is inheritable.
234 for (i
= 0, j
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
236 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
237 SourceProcessData
->HandleTable
[i
].Inheritable
)
240 * Copy the handle data and increment the reference count of the
241 * pointed object (via the call to ConSrvCreateHandleEntry == AdjustHandleCounts).
243 TargetProcessData
->HandleTable
[j
] = SourceProcessData
->HandleTable
[i
];
244 AdjustHandleCounts(&TargetProcessData
->HandleTable
[j
], +1);
250 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
255 ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData
)
257 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
259 if (ProcessData
->HandleTable
!= NULL
)
264 * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
265 * ConSrvFreeHandlesTable is called in ConSrvConnect during the
266 * allocation of a new console.
268 // ASSERT(ProcessData->ConsoleHandle);
269 if (ProcessData
->ConsoleHandle
!= NULL
)
271 /* Close all the console handles */
272 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
274 ConSrvCloseHandle(&ProcessData
->HandleTable
[i
]);
277 /* Free the handles table memory */
278 ConsoleFreeHeap(ProcessData
->HandleTable
);
279 ProcessData
->HandleTable
= NULL
;
282 ProcessData
->HandleTableSize
= 0;
284 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
292 // ConSrvCreateObject
294 ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object
,
295 IN CONSOLE_IO_OBJECT_TYPE Type
,
299 // if (!Object) return;
302 Object
->Console
= Console
;
303 Object
->ReferenceCount
= 0;
305 Object
->AccessRead
= Object
->AccessWrite
= 0;
306 Object
->ExclusiveRead
= Object
->ExclusiveWrite
= 0;
310 ConSrvInsertObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
312 IN PCONSOLE_IO_OBJECT Object
,
314 IN BOOLEAN Inheritable
,
317 #define IO_HANDLES_INCREMENT 2 * 3
320 PCONSOLE_IO_HANDLE Block
;
322 // NOTE: Commented out because calling code always lock HandleTableLock before.
323 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
325 ASSERT( (ProcessData
->HandleTable
== NULL
&& ProcessData
->HandleTableSize
== 0) ||
326 (ProcessData
->HandleTable
!= NULL
&& ProcessData
->HandleTableSize
!= 0) );
328 if (ProcessData
->HandleTable
)
330 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
332 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
337 if (i
>= ProcessData
->HandleTableSize
)
339 /* Allocate a new handles table */
340 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
341 (ProcessData
->HandleTableSize
+
342 IO_HANDLES_INCREMENT
) * sizeof(CONSOLE_IO_HANDLE
));
345 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
346 return STATUS_UNSUCCESSFUL
;
349 /* If we previously had a handles table, free it and use the new one */
350 if (ProcessData
->HandleTable
)
352 /* Copy the handles from the old table to the new one */
354 ProcessData
->HandleTable
,
355 ProcessData
->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE
));
356 ConsoleFreeHeap(ProcessData
->HandleTable
);
358 ProcessData
->HandleTable
= Block
;
359 ProcessData
->HandleTableSize
+= IO_HANDLES_INCREMENT
;
362 ProcessData
->HandleTable
[i
].Object
= Object
;
363 ProcessData
->HandleTable
[i
].Access
= Access
;
364 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
365 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
366 AdjustHandleCounts(&ProcessData
->HandleTable
[i
], +1);
367 *Handle
= ULongToHandle((i
<< 2) | 0x3);
369 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
371 return STATUS_SUCCESS
;
375 ConSrvRemoveObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
378 ULONG Index
= HandleToULong(Handle
) >> 2;
380 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
382 ASSERT(ProcessData
->HandleTable
);
383 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
384 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
386 if (Index
>= ProcessData
->HandleTableSize
||
387 ProcessData
->HandleTable
[Index
].Object
== NULL
)
389 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
390 return STATUS_INVALID_HANDLE
;
393 ASSERT(ProcessData
->ConsoleHandle
);
394 ConSrvCloseHandle(&ProcessData
->HandleTable
[Index
]);
396 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
397 return STATUS_SUCCESS
;
401 ConSrvGetObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
403 OUT PCONSOLE_IO_OBJECT
* Object
,
404 OUT PVOID
* Entry OPTIONAL
,
406 IN BOOLEAN LockConsole
,
407 IN CONSOLE_IO_OBJECT_TYPE Type
)
410 ULONG Index
= HandleToULong(Handle
) >> 2;
411 PCONSOLE_IO_HANDLE HandleEntry
= NULL
;
412 PCONSOLE_IO_OBJECT ObjectEntry
= NULL
;
413 // PCONSOLE ObjectConsole;
416 if (Entry
) *Entry
= NULL
;
418 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object
, Handle
);
420 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
422 if ( IsConsoleHandle(Handle
) &&
423 Index
< ProcessData
->HandleTableSize
)
425 HandleEntry
= &ProcessData
->HandleTable
[Index
];
426 ObjectEntry
= HandleEntry
->Object
;
429 if ( HandleEntry
== NULL
||
430 ObjectEntry
== NULL
||
431 (HandleEntry
->Access
& Access
) == 0 ||
432 /*(Type != 0 && ObjectEntry->Type != Type)*/
433 (Type
!= 0 && (ObjectEntry
->Type
& Type
) == 0) )
435 DPRINT("ConSrvGetObject -- Invalid handle 0x%x of type %lu with access %lu ; retrieved object 0x%x (handle 0x%x) of type %lu with access %lu\n",
436 Handle
, Type
, Access
, ObjectEntry
, HandleEntry
, (ObjectEntry
? ObjectEntry
->Type
: 0), (HandleEntry
? HandleEntry
->Access
: 0));
438 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
439 return STATUS_INVALID_HANDLE
;
442 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
444 // Status = ConSrvGetConsole(ProcessData, &ObjectConsole, LockConsole);
445 // if (NT_SUCCESS(Status))
446 if (ConDrvValidateConsoleUnsafe(ObjectEntry
->Console
, CONSOLE_RUNNING
, LockConsole
))
448 _InterlockedIncrement(&ObjectEntry
->Console
->ReferenceCount
);
450 /* Return the objects to the caller */
451 *Object
= ObjectEntry
;
452 if (Entry
) *Entry
= HandleEntry
;
454 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
455 return STATUS_SUCCESS
;
459 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
460 return STATUS_INVALID_HANDLE
;
465 ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object
,
466 IN BOOLEAN IsConsoleLocked
)
468 ConSrvReleaseConsole(Object
->Console
, IsConsoleLocked
);
474 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData
,
475 PHANDLE pInputHandle
,
476 PHANDLE pOutputHandle
,
477 PHANDLE pErrorHandle
,
478 PCONSOLE_INIT_INFO ConsoleInitInfo
)
480 NTSTATUS Status
= STATUS_SUCCESS
;
481 HANDLE ConsoleHandle
;
482 PCONSRV_CONSOLE Console
;
485 * We are about to create a new console. However when ConSrvNewProcess
486 * was called, we didn't know that we wanted to create a new console and
487 * therefore, we by default inherited the handles table from our parent
488 * process. It's only now that we notice that in fact we do not need
489 * them, because we've created a new console and thus we must use it.
491 * Therefore, free the handles table so that we can recreate
492 * a new one later on.
494 ConSrvFreeHandlesTable(ProcessData
);
496 /* Initialize a new Console owned by this process */
497 DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n",
498 ConsoleInitInfo
->ConsoleTitle
? ConsoleInitInfo
->ConsoleTitle
: L
"n/a",
499 ConsoleInitInfo
->AppName
? ConsoleInitInfo
->AppName
: L
"n/a",
500 ConsoleInitInfo
->Desktop
? ConsoleInitInfo
->Desktop
: L
"n/a");
501 Status
= ConSrvInitConsole(&ConsoleHandle
,
504 ProcessData
->Process
);
505 if (!NT_SUCCESS(Status
))
507 DPRINT1("Console initialization failed\n");
511 /* Assign the new console handle */
512 ProcessData
->ConsoleHandle
= ConsoleHandle
;
514 /* Initialize the handles table */
515 Status
= ConSrvInitHandlesTable(ProcessData
,
520 if (!NT_SUCCESS(Status
))
522 DPRINT1("Failed to initialize the handles table\n");
523 ConSrvDeleteConsole(Console
);
524 ProcessData
->ConsoleHandle
= NULL
;
528 /* Duplicate the Initialization Events */
529 Status
= NtDuplicateObject(NtCurrentProcess(),
530 Console
->InitEvents
[INIT_SUCCESS
],
531 ProcessData
->Process
->ProcessHandle
,
532 &ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
533 EVENT_ALL_ACCESS
, 0, 0);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
537 ConSrvFreeHandlesTable(ProcessData
);
538 ConSrvDeleteConsole(Console
);
539 ProcessData
->ConsoleHandle
= NULL
;
543 Status
= NtDuplicateObject(NtCurrentProcess(),
544 Console
->InitEvents
[INIT_FAILURE
],
545 ProcessData
->Process
->ProcessHandle
,
546 &ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
547 EVENT_ALL_ACCESS
, 0, 0);
548 if (!NT_SUCCESS(Status
))
550 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
551 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
552 ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
553 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
554 ConSrvFreeHandlesTable(ProcessData
);
555 ConSrvDeleteConsole(Console
);
556 ProcessData
->ConsoleHandle
= NULL
;
560 /* Duplicate the Input Event */
561 Status
= NtDuplicateObject(NtCurrentProcess(),
562 Console
->InputBuffer
.ActiveEvent
,
563 ProcessData
->Process
->ProcessHandle
,
564 &ConsoleInitInfo
->ConsoleStartInfo
->InputWaitHandle
,
565 EVENT_ALL_ACCESS
, 0, 0);
566 if (!NT_SUCCESS(Status
))
568 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status
);
569 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
570 ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
571 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
572 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
573 ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
574 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
575 ConSrvFreeHandlesTable(ProcessData
);
576 ConSrvDeleteConsole(Console
);
577 ProcessData
->ConsoleHandle
= NULL
;
581 /* Mark the process as having a console */
582 ProcessData
->ConsoleApp
= TRUE
;
583 ProcessData
->Process
->Flags
|= CsrProcessIsConsoleApp
;
585 /* Return the console handle to the caller */
586 ConsoleInitInfo
->ConsoleStartInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
589 * Insert the process into the processes list of the console,
590 * and set its foreground priority.
592 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
593 ConSrvSetProcessFocus(ProcessData
->Process
, Console
->HasFocus
);
595 /* Add a reference count because the process is tied to the console */
596 _InterlockedIncrement(&Console
->ReferenceCount
);
598 /* Update the internal info of the terminal */
599 TermRefreshInternalInfo(Console
);
601 return STATUS_SUCCESS
;
605 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData
,
606 HANDLE ConsoleHandle
,
607 BOOLEAN CreateNewHandlesTable
,
608 PHANDLE pInputHandle
,
609 PHANDLE pOutputHandle
,
610 PHANDLE pErrorHandle
,
611 PCONSOLE_START_INFO ConsoleStartInfo
)
613 NTSTATUS Status
= STATUS_SUCCESS
;
616 /* Validate and lock the console */
617 if (!ConSrvValidateConsole(&Console
,
619 CONSOLE_RUNNING
, TRUE
))
621 // FIXME: Find another status code
622 return STATUS_UNSUCCESSFUL
;
625 /* Inherit the console */
626 ProcessData
->ConsoleHandle
= ConsoleHandle
;
628 if (CreateNewHandlesTable
)
631 * We are about to create a new console. However when ConSrvNewProcess
632 * was called, we didn't know that we wanted to create a new console and
633 * therefore, we by default inherited the handles table from our parent
634 * process. It's only now that we notice that in fact we do not need
635 * them, because we've created a new console and thus we must use it.
637 * Therefore, free the handles table so that we can recreate
638 * a new one later on.
640 ConSrvFreeHandlesTable(ProcessData
);
642 /* Initialize the handles table */
643 Status
= ConSrvInitHandlesTable(ProcessData
,
648 if (!NT_SUCCESS(Status
))
650 DPRINT1("Failed to initialize the handles table\n");
651 ProcessData
->ConsoleHandle
= NULL
;
656 /* Duplicate the Initialization Events */
657 Status
= NtDuplicateObject(NtCurrentProcess(),
658 Console
->InitEvents
[INIT_SUCCESS
],
659 ProcessData
->Process
->ProcessHandle
,
660 &ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
661 EVENT_ALL_ACCESS
, 0, 0);
662 if (!NT_SUCCESS(Status
))
664 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
665 ConSrvFreeHandlesTable(ProcessData
);
666 ProcessData
->ConsoleHandle
= NULL
;
670 Status
= NtDuplicateObject(NtCurrentProcess(),
671 Console
->InitEvents
[INIT_FAILURE
],
672 ProcessData
->Process
->ProcessHandle
,
673 &ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
674 EVENT_ALL_ACCESS
, 0, 0);
675 if (!NT_SUCCESS(Status
))
677 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
678 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
679 ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
680 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
681 ConSrvFreeHandlesTable(ProcessData
);
682 ProcessData
->ConsoleHandle
= NULL
;
686 /* Duplicate the Input Event */
687 Status
= NtDuplicateObject(NtCurrentProcess(),
688 Console
->InputBuffer
.ActiveEvent
,
689 ProcessData
->Process
->ProcessHandle
,
690 &ConsoleStartInfo
->InputWaitHandle
,
691 EVENT_ALL_ACCESS
, 0, 0);
692 if (!NT_SUCCESS(Status
))
694 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status
);
695 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
696 ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
697 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
698 NtDuplicateObject(ProcessData
->Process
->ProcessHandle
,
699 ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
700 NULL
, NULL
, 0, 0, DUPLICATE_CLOSE_SOURCE
);
701 ConSrvFreeHandlesTable(ProcessData
); // NOTE: Always free the handles table.
702 ProcessData
->ConsoleHandle
= NULL
;
706 /* Mark the process as having a console */
707 ProcessData
->ConsoleApp
= TRUE
;
708 ProcessData
->Process
->Flags
|= CsrProcessIsConsoleApp
;
710 /* Return the console handle to the caller */
711 ConsoleStartInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
714 * Insert the process into the processes list of the console,
715 * and set its foreground priority.
717 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
718 ConSrvSetProcessFocus(ProcessData
->Process
, Console
->HasFocus
);
720 /* Add a reference count because the process is tied to the console */
721 _InterlockedIncrement(&Console
->ReferenceCount
);
723 /* Update the internal info of the terminal */
724 TermRefreshInternalInfo(Console
);
726 Status
= STATUS_SUCCESS
;
729 /* Unlock the console and return */
730 LeaveCriticalSection(&Console
->Lock
);
735 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData
)
738 PCONSOLE_PROCESS_DATA ConsoleLeaderProcess
;
740 DPRINT("ConSrvRemoveConsole\n");
742 /* Mark the process as not having a console anymore */
743 ProcessData
->ConsoleApp
= FALSE
;
744 ProcessData
->Process
->Flags
&= ~CsrProcessIsConsoleApp
;
746 /* Validate and lock the console */
747 if (!ConSrvValidateConsole(&Console
,
748 ProcessData
->ConsoleHandle
,
749 CONSOLE_RUNNING
, TRUE
))
751 // FIXME: Find another status code
752 return STATUS_UNSUCCESSFUL
;
755 DPRINT("ConSrvRemoveConsole - Locking OK\n");
757 /* Retrieve the console leader process */
758 ConsoleLeaderProcess
= ConSrvGetConsoleLeaderProcess(Console
);
760 /* Close all console handles and free the handles table */
761 ConSrvFreeHandlesTable(ProcessData
);
763 /* Detach the process from the console */
764 ProcessData
->ConsoleHandle
= NULL
;
766 /* Remove the process from the console's list of processes */
767 RemoveEntryList(&ProcessData
->ConsoleLink
);
769 /* Check whether the console should send a last close notification */
770 if (Console
->NotifyLastClose
)
772 /* If we are removing the process which wants the last close notification... */
773 if (ProcessData
== Console
->NotifiedLastCloseProcess
)
775 /* ... just reset the flag and the pointer... */
776 Console
->NotifyLastClose
= FALSE
;
777 Console
->NotifiedLastCloseProcess
= NULL
;
780 * ... otherwise, if we are removing the console leader process
781 * (that cannot be the process wanting the notification, because
782 * the previous case already dealt with it)...
784 else if (ProcessData
== ConsoleLeaderProcess
)
787 * ... reset the flag first (so that we avoid multiple notifications)
788 * and then send the last close notification.
790 Console
->NotifyLastClose
= FALSE
;
791 ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT
, Console
->NotifiedLastCloseProcess
);
793 /* Only now, reset the pointer */
794 Console
->NotifiedLastCloseProcess
= NULL
;
798 /* Update the internal info of the terminal */
799 TermRefreshInternalInfo(Console
);
801 /* Release the console */
802 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console
->ReferenceCount
);
803 ConSrvReleaseConsole(Console
, TRUE
);
805 return STATUS_SUCCESS
;
809 /* PUBLIC SERVER APIS *********************************************************/
811 CSR_API(SrvOpenConsole
)
814 * This API opens a handle to either the input buffer or to
815 * a screen-buffer of the console of the current process.
819 PCONSOLE_OPENCONSOLE OpenConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.OpenConsoleRequest
;
820 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
823 DWORD DesiredAccess
= OpenConsoleRequest
->DesiredAccess
;
824 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
825 PCONSOLE_IO_OBJECT Object
;
827 OpenConsoleRequest
->Handle
= INVALID_HANDLE_VALUE
;
829 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
830 if (!NT_SUCCESS(Status
))
832 DPRINT1("Can't get console, status %lx\n", Status
);
836 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
839 * Open a handle to either the active screen buffer or the input buffer.
841 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
843 Object
= &Console
->ActiveBuffer
->Header
;
847 Object
= &Console
->InputBuffer
.Header
;
850 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
851 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
852 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
853 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
855 DPRINT1("Sharing violation\n");
856 Status
= STATUS_SHARING_VIOLATION
;
860 Status
= ConSrvInsertObject(ProcessData
,
861 &OpenConsoleRequest
->Handle
,
864 OpenConsoleRequest
->InheritHandle
,
868 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
870 ConSrvReleaseConsole(Console
, TRUE
);
874 CSR_API(SrvDuplicateHandle
)
877 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.DuplicateHandleRequest
;
878 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
881 HANDLE SourceHandle
= DuplicateHandleRequest
->SourceHandle
;
882 ULONG Index
= HandleToULong(SourceHandle
) >> 2;
883 PCONSOLE_IO_HANDLE Entry
;
886 DuplicateHandleRequest
->TargetHandle
= INVALID_HANDLE_VALUE
;
888 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
889 if (!NT_SUCCESS(Status
))
891 DPRINT1("Can't get console, status %lx\n", Status
);
895 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
897 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
898 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
900 if ( /** !IsConsoleHandle(SourceHandle) || **/
901 Index
>= ProcessData
->HandleTableSize
||
902 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
904 DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle
);
905 Status
= STATUS_INVALID_HANDLE
;
909 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
911 DesiredAccess
= Entry
->Access
;
915 DesiredAccess
= DuplicateHandleRequest
->DesiredAccess
;
916 /* Make sure the source handle has all the desired flags */
917 if ((Entry
->Access
& DesiredAccess
) == 0)
919 DPRINT1("Handle 0x%p only has access %X; requested %X\n",
920 SourceHandle
, Entry
->Access
, DesiredAccess
);
921 Status
= STATUS_INVALID_PARAMETER
;
926 /* Insert the new handle inside the process handles table */
927 Status
= ConSrvInsertObject(ProcessData
,
928 &DuplicateHandleRequest
->TargetHandle
,
931 DuplicateHandleRequest
->InheritHandle
,
933 if (NT_SUCCESS(Status
) &&
934 (DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
))
936 /* Close the original handle if needed */
937 ConSrvCloseHandle(Entry
);
941 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
943 ConSrvReleaseConsole(Console
, TRUE
);
947 CSR_API(SrvGetHandleInformation
)
950 PCONSOLE_GETHANDLEINFO GetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetHandleInfoRequest
;
951 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
954 HANDLE Handle
= GetHandleInfoRequest
->Handle
;
955 ULONG Index
= HandleToULong(Handle
) >> 2;
956 PCONSOLE_IO_HANDLE Entry
;
958 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
959 if (!NT_SUCCESS(Status
))
961 DPRINT1("Can't get console, status %lx\n", Status
);
965 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
967 ASSERT(ProcessData
->HandleTable
);
968 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
969 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
971 if (!IsConsoleHandle(Handle
) ||
972 Index
>= ProcessData
->HandleTableSize
||
973 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
975 Status
= STATUS_INVALID_HANDLE
;
980 * Retrieve the handle information flags. The console server
981 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
983 GetHandleInfoRequest
->Flags
= 0;
984 if (Entry
->Inheritable
) GetHandleInfoRequest
->Flags
|= HANDLE_FLAG_INHERIT
;
986 Status
= STATUS_SUCCESS
;
989 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
991 ConSrvReleaseConsole(Console
, TRUE
);
995 CSR_API(SrvSetHandleInformation
)
998 PCONSOLE_SETHANDLEINFO SetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHandleInfoRequest
;
999 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1002 HANDLE Handle
= SetHandleInfoRequest
->Handle
;
1003 ULONG Index
= HandleToULong(Handle
) >> 2;
1004 PCONSOLE_IO_HANDLE Entry
;
1006 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1007 if (!NT_SUCCESS(Status
))
1009 DPRINT1("Can't get console, status %lx\n", Status
);
1013 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1015 ASSERT(ProcessData
->HandleTable
);
1016 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
1017 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
1019 if (!IsConsoleHandle(Handle
) ||
1020 Index
>= ProcessData
->HandleTableSize
||
1021 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
1023 Status
= STATUS_INVALID_HANDLE
;
1028 * Modify the handle information flags. The console server
1029 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
1031 if (SetHandleInfoRequest
->Mask
& HANDLE_FLAG_INHERIT
)
1033 Entry
->Inheritable
= ((SetHandleInfoRequest
->Flags
& HANDLE_FLAG_INHERIT
) != 0);
1036 Status
= STATUS_SUCCESS
;
1039 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1041 ConSrvReleaseConsole(Console
, TRUE
);
1045 CSR_API(SrvCloseHandle
)
1048 PCONSOLE_CLOSEHANDLE CloseHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CloseHandleRequest
;
1049 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1052 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1053 if (!NT_SUCCESS(Status
))
1055 DPRINT1("Can't get console, status %lx\n", Status
);
1059 Status
= ConSrvRemoveObject(ProcessData
, CloseHandleRequest
->Handle
);
1061 ConSrvReleaseConsole(Console
, TRUE
);
1065 CSR_API(SrvVerifyConsoleIoHandle
)
1068 PCONSOLE_VERIFYHANDLE VerifyHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.VerifyHandleRequest
;
1069 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1072 HANDLE IoHandle
= VerifyHandleRequest
->Handle
;
1073 ULONG Index
= HandleToULong(IoHandle
) >> 2;
1075 VerifyHandleRequest
->IsValid
= FALSE
;
1077 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1078 if (!NT_SUCCESS(Status
))
1080 DPRINT1("Can't get console, status %lx\n", Status
);
1084 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1086 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
1087 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
1089 if (!IsConsoleHandle(IoHandle
) ||
1090 Index
>= ProcessData
->HandleTableSize
||
1091 ProcessData
->HandleTable
[Index
].Object
== NULL
)
1093 DPRINT("SrvVerifyConsoleIoHandle failed\n");
1097 VerifyHandleRequest
->IsValid
= TRUE
;
1100 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1102 ConSrvReleaseConsole(Console
, TRUE
);
1103 return STATUS_SUCCESS
;