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 IO Handle functions
9 /* INCLUDES ******************************************************************/
18 /* PRIVATE FUNCTIONS *********************************************************/
21 AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry
, INT Change
)
23 Object_t
*Object
= Entry
->Object
;
25 DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry
, Change
, Object
, Object
->HandleCount
, Object
->Type
);
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
;
32 Object
->HandleCount
+= Change
;
34 return Object
->HandleCount
;
38 Win32CsrCreateHandleEntry(PCONSOLE_IO_HANDLE Entry
)
40 Object_t
*Object
= Entry
->Object
;
41 EnterCriticalSection(&Object
->Console
->Lock
);
42 AdjustHandleCounts(Entry
, +1);
43 LeaveCriticalSection(&Object
->Console
->Lock
);
47 Win32CsrCloseHandleEntry(PCONSOLE_IO_HANDLE Entry
)
49 Object_t
*Object
= Entry
->Object
;
52 PCONSOLE Console
= Object
->Console
;
53 EnterCriticalSection(&Console
->Lock
);
55 /* If the last handle to a screen buffer is closed, delete it... */
56 if (AdjustHandleCounts(Entry
, -1) == 0)
58 if (Object
->Type
== CONIO_SCREEN_BUFFER_MAGIC
)
60 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
61 /* ...unless it's the only buffer left. Windows allows deletion
62 * even of the last buffer, but having to deal with a lack of
63 * any active buffer might be error-prone. */
64 if (Buffer
->ListEntry
.Flink
!= Buffer
->ListEntry
.Blink
)
65 ConioDeleteScreenBuffer(Buffer
);
67 else if (Object
->Type
== CONIO_CONSOLE_MAGIC
)
69 /* TODO: FIXME: Destroy here the console ?? */
70 // ConioDeleteConsole(Console);
74 LeaveCriticalSection(&Console
->Lock
);
80 /* FUNCTIONS *****************************************************************/
84 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData
,
92 PCONSOLE_IO_HANDLE Block
;
94 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
96 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
98 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
103 if (i
>= ProcessData
->HandleTableSize
)
105 Block
= RtlAllocateHeap(ConSrvHeap
,
107 (ProcessData
->HandleTableSize
+ 64) * sizeof(CONSOLE_IO_HANDLE
));
110 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
111 return STATUS_UNSUCCESSFUL
;
114 ProcessData
->HandleTable
,
115 ProcessData
->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE
));
116 RtlFreeHeap(ConSrvHeap
, 0, ProcessData
->HandleTable
);
117 ProcessData
->HandleTable
= Block
;
118 ProcessData
->HandleTableSize
+= 64;
120 ProcessData
->HandleTable
[i
].Object
= Object
;
121 ProcessData
->HandleTable
[i
].Access
= Access
;
122 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
123 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
124 Win32CsrCreateHandleEntry(&ProcessData
->HandleTable
[i
]);
125 *Handle
= UlongToHandle((i
<< 2) | 0x3);
126 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
127 return STATUS_SUCCESS
;
132 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData
,
135 ULONG_PTR h
= (ULONG_PTR
)Handle
>> 2;
138 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
140 if (h
>= ProcessData
->HandleTableSize
||
141 (Object
= ProcessData
->HandleTable
[h
].Object
) == NULL
)
143 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
144 return STATUS_INVALID_HANDLE
;
147 DPRINT1("Win32CsrReleaseObject - Process 0x%p, Release 0x%p\n", ProcessData
->Process
, &ProcessData
->HandleTable
[h
]);
148 Win32CsrCloseHandleEntry(&ProcessData
->HandleTable
[h
]);
150 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
152 return STATUS_SUCCESS
;
157 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData
,
163 ULONG_PTR h
= (ULONG_PTR
)Handle
>> 2;
165 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
166 Object
, Handle
, ProcessData
? ProcessData
->HandleTableSize
: 0);
168 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
170 if ( !IsConsoleHandle(Handle
) ||
171 h
>= ProcessData
->HandleTableSize
||
172 (*Object
= ProcessData
->HandleTable
[h
].Object
) == NULL
||
173 ~ProcessData
->HandleTable
[h
].Access
& Access
||
174 (Type
!= 0 && (*Object
)->Type
!= Type
) )
176 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle
);
177 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
178 return STATUS_INVALID_HANDLE
;
181 _InterlockedIncrement(&(*Object
)->Console
->ReferenceCount
);
182 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
184 EnterCriticalSection(&((*Object
)->Console
->Lock
));
185 return STATUS_SUCCESS
;
189 Win32CsrUnlockConsole(PCONSOLE Console
)
191 LeaveCriticalSection(&Console
->Lock
);
193 /* Decrement reference count */
194 if (_InterlockedDecrement(&Console
->ReferenceCount
) == 0)
195 ConioDeleteConsole(Console
);
200 Win32CsrUnlockObject(Object_t
*Object
)
202 Win32CsrUnlockConsole(Object
->Console
);
207 /** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/
210 ConsoleNewProcess(PCSR_PROCESS SourceProcess
,
211 PCSR_PROCESS TargetProcess
)
213 /**************************************************************************
214 * This function is called whenever a new process (GUI or CUI) is created.
216 * Copy the parent's handles table here if both the parent and the child
217 * processes are CUI. If we must actually create our proper console (and
218 * thus do not inherit from the console handles of the parent's), then we
219 * will clean this table in the next ConsoleConnect call. Why we are doing
220 * this? It's because here, we still don't know whether or not we must create
221 * a new console instead of inherit it from the parent, and, because in
222 * ConsoleConnect we don't have any reference to the parent process anymore.
223 **************************************************************************/
225 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
228 DPRINT1("ConsoleNewProcess inside\n");
229 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess
, TargetProcess
);
231 /* An empty target process is invalid */
233 return STATUS_INVALID_PARAMETER
;
235 DPRINT1("ConsoleNewProcess - OK\n");
237 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
238 DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData
);
240 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData
, sizeof(*TargetProcessData
));
242 /* Initialize the new (target) process */
243 TargetProcessData
->Process
= TargetProcess
;
244 TargetProcessData
->ConsoleEvent
= NULL
;
245 TargetProcessData
->Console
= TargetProcessData
->ParentConsole
= NULL
;
246 // TargetProcessData->bInheritHandles = FALSE;
247 TargetProcessData
->ConsoleApp
= ((TargetProcess
->Flags
& CsrProcessIsConsoleApp
) ? TRUE
: FALSE
);
250 TargetProcessData
->HandleTableSize
= 0;
251 TargetProcessData
->HandleTable
= NULL
;
253 /* HACK */ RtlZeroMemory(&TargetProcessData
->HandleTableLock
, sizeof(RTL_CRITICAL_SECTION
));
254 RtlInitializeCriticalSection(&TargetProcessData
->HandleTableLock
);
256 /* Do nothing if the source process is NULL */
258 return STATUS_SUCCESS
;
260 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
261 DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData
);
264 * If both of the processes (parent and new child) are console applications,
265 * then try to inherit handles from the parent process.
267 if ( SourceProcessData
->Console
!= NULL
&& /* SourceProcessData->ConsoleApp */
268 TargetProcessData
->ConsoleApp
)
271 if (TargetProcessData->HandleTableSize)
273 return STATUS_INVALID_PARAMETER;
277 DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n");
278 /* Temporary "inherit" the console from the parent */
279 TargetProcessData
->ParentConsole
= SourceProcessData
->Console
;
280 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
281 DPRINT1("ConsoleNewProcess - Copy the handle table (2)\n");
283 /* Allocate a new handle table for the child process */
284 TargetProcessData
->HandleTable
= RtlAllocateHeap(ConSrvHeap
,
286 SourceProcessData
->HandleTableSize
287 * sizeof(CONSOLE_IO_HANDLE
));
288 if (TargetProcessData
->HandleTable
== NULL
)
290 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
291 return STATUS_UNSUCCESSFUL
;
294 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
297 * Parse the parent process' handles table and, for each handle,
298 * do a copy of it and reference it, if the handle is inheritable.
300 for (i
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
302 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
303 SourceProcessData
->HandleTable
[i
].Inheritable
)
306 * Copy the handle data and increment the reference count of the
307 * pointed object (via the call to Win32CsrCreateHandleEntry).
309 TargetProcessData
->HandleTable
[i
] = SourceProcessData
->HandleTable
[i
];
310 Win32CsrCreateHandleEntry(&TargetProcessData
->HandleTable
[i
]);
314 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
318 DPRINT1("ConsoleNewProcess - We don't launch a Console process : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData
->Console
, TargetProcess
->Flags
);
321 return STATUS_SUCCESS
;
326 ConsoleConnect(IN PCSR_PROCESS CsrProcess
,
327 IN OUT PVOID ConnectionInfo
,
328 IN OUT PULONG ConnectionInfoLength
)
330 /**************************************************************************
331 * This function is called whenever a CUI new process is created.
332 **************************************************************************/
334 NTSTATUS Status
= STATUS_SUCCESS
;
335 PCONSOLE_CONNECTION_INFO ConnectInfo
= (PCONSOLE_CONNECTION_INFO
)ConnectionInfo
;
336 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
337 BOOLEAN NewConsole
= FALSE
;
338 // PCONSOLE Console = NULL;
340 DPRINT1("ConsoleConnect\n");
342 if ( ConnectionInfo
== NULL
||
343 ConnectionInfoLength
== NULL
||
344 *ConnectionInfoLength
!= sizeof(CONSOLE_CONNECTION_INFO
) )
346 DPRINT1("CONSRV: Connection failed\n");
347 return STATUS_UNSUCCESSFUL
;
350 /* If we don't need a console, then get out of here */
351 if (!ConnectInfo
->ConsoleNeeded
|| !ProcessData
->ConsoleApp
) // In fact, it is for GUI apps.
353 DPRINT("ConsoleConnect - No console needed\n");
354 return STATUS_SUCCESS
;
357 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
359 /* If we don't have a console, then create a new one... */
360 if (!ConnectInfo
->Console
||
361 ConnectInfo
->Console
!= ProcessData
->ParentConsole
)
363 DPRINT1("ConsoleConnect - Allocate a new console\n");
365 /* Initialize a new Console owned by the Console Leader Process */
367 Status
= CsrInitConsole(&ProcessData
->Console
, ConnectInfo
->ShowCmd
, CsrProcess
);
368 if (!NT_SUCCESS(Status
))
370 DPRINT1("Console initialization failed\n");
371 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
375 else /* We inherit it from the parent */
377 DPRINT1("ConsoleConnect - Reuse current (parent's) console\n");
379 /* Reuse our current console */
381 ProcessData
->Console
= ConnectInfo
->Console
;
384 /* Insert the process into the processes list of the console */
385 InsertHeadList(&ProcessData
->Console
->ProcessList
, &ProcessData
->ConsoleLink
);
387 /* Return it to the caller */
388 ConnectInfo
->Console
= ProcessData
->Console
;
390 /* Add a reference count because the process is tied to the console */
391 _InterlockedIncrement(&ProcessData
->Console
->ReferenceCount
);
393 if (NewConsole
/* || !ProcessData->bInheritHandles */)
396 * We've just created a new console. However when ConsoleNewProcess was
397 * called, we didn't know that we wanted to create a new console and
398 * therefore, we by default inherited the handles table from our parent
399 * process. It's only now that we notice that in fact we do not need
400 * them, because we've created a new console and thus we must use it.
402 * Therefore, free our handles table and recreate a new one.
407 /* Close all console handles and free the handle table memory */
408 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
410 Win32CsrCloseHandleEntry(&ProcessData
->HandleTable
[i
]);
412 ProcessData
->HandleTableSize
= 0;
413 RtlFreeHeap(ConSrvHeap
, 0, ProcessData
->HandleTable
);
414 ProcessData
->HandleTable
= NULL
;
417 * Create a new handle table - Insert the IO handles
420 /* Insert the Input handle */
421 Status
= Win32CsrInsertObject(ProcessData
,
422 &ConnectInfo
->InputHandle
,
423 &ProcessData
->Console
->Header
,
424 GENERIC_READ
| GENERIC_WRITE
,
426 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
427 if (!NT_SUCCESS(Status
))
429 DPRINT1("Failed to insert the input handle\n");
430 ConioDeleteConsole(ProcessData
->Console
);
431 ProcessData
->Console
= NULL
;
432 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
436 /* Insert the Output handle */
437 Status
= Win32CsrInsertObject(ProcessData
,
438 &ConnectInfo
->OutputHandle
,
439 &ProcessData
->Console
->ActiveBuffer
->Header
,
440 GENERIC_READ
| GENERIC_WRITE
,
442 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("Failed to insert the output handle\n");
446 ConioDeleteConsole(ProcessData
->Console
);
447 Win32CsrReleaseObject(ProcessData
,
448 ConnectInfo
->InputHandle
);
449 ProcessData
->Console
= NULL
;
450 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
454 /* Insert the Error handle */
455 Status
= Win32CsrInsertObject(ProcessData
,
456 &ConnectInfo
->ErrorHandle
,
457 &ProcessData
->Console
->ActiveBuffer
->Header
,
458 GENERIC_READ
| GENERIC_WRITE
,
460 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
461 if (!NT_SUCCESS(Status
))
463 DPRINT1("Failed to insert the error handle\n");
464 ConioDeleteConsole(ProcessData
->Console
);
465 Win32CsrReleaseObject(ProcessData
,
466 ConnectInfo
->OutputHandle
);
467 Win32CsrReleaseObject(ProcessData
,
468 ConnectInfo
->InputHandle
);
469 ProcessData
->Console
= NULL
;
470 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
475 /* Duplicate the Event */
476 Status
= NtDuplicateObject(NtCurrentProcess(),
477 ProcessData
->Console
->ActiveEvent
,
478 ProcessData
->Process
->ProcessHandle
,
479 &ProcessData
->ConsoleEvent
,
480 EVENT_ALL_ACCESS
, 0, 0);
481 if (!NT_SUCCESS(Status
))
483 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
484 ConioDeleteConsole(ProcessData
->Console
);
485 if (NewConsole
/* || !ProcessData->bInheritHandles */)
487 Win32CsrReleaseObject(ProcessData
,
488 ConnectInfo
->ErrorHandle
);
489 Win32CsrReleaseObject(ProcessData
,
490 ConnectInfo
->OutputHandle
);
491 Win32CsrReleaseObject(ProcessData
,
492 ConnectInfo
->InputHandle
);
494 ProcessData
->Console
= NULL
;
495 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
498 /* Input Wait Handle */
499 ConnectInfo
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
501 /* Set the Ctrl Dispatcher */
502 ProcessData
->CtrlDispatcher
= ConnectInfo
->CtrlDispatcher
;
503 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData
->CtrlDispatcher
);
505 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
506 return STATUS_SUCCESS
;
511 Win32CsrReleaseConsole(PCSR_PROCESS Process
)
513 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(Process
);
517 DPRINT1("Win32CsrReleaseConsole\n");
519 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
521 /* Close all console handles and free the handle table memory */
522 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
524 Win32CsrCloseHandleEntry(&ProcessData
->HandleTable
[i
]);
526 ProcessData
->HandleTableSize
= 0;
527 RtlFreeHeap(ConSrvHeap
, 0, ProcessData
->HandleTable
);
528 ProcessData
->HandleTable
= NULL
;
530 /* Detach process from console */
531 Console
= ProcessData
->Console
;
534 DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console
->ReferenceCount
);
535 ProcessData
->Console
= NULL
;
536 EnterCriticalSection(&Console
->Lock
);
537 RemoveEntryList(&ProcessData
->ConsoleLink
);
538 Win32CsrUnlockConsole(Console
);
539 //CloseHandle(ProcessData->ConsoleEvent);
540 //ProcessData->ConsoleEvent = NULL;
543 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
548 ConsoleDisconnect(PCSR_PROCESS Process
)
550 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(Process
);
552 /**************************************************************************
553 * This function is called whenever a new process (GUI or CUI) is destroyed.
555 * Only do something if the process is a CUI. <-- modify this behaviour if
556 * we deal with a GUI which
557 * quits and acquired a
559 **************************************************************************/
561 DPRINT1("ConsoleDisconnect called\n");
562 // if (ProcessData->Console != NULL)
563 if (ProcessData
->ConsoleApp
)
565 DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n");
566 Win32CsrReleaseConsole(Process
);
569 RtlDeleteCriticalSection(&ProcessData
->HandleTableLock
);
574 CSR_API(SrvCloseHandle
)
576 PCONSOLE_CLOSEHANDLE CloseHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CloseHandleRequest
;
578 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
579 CloseHandleRequest
->ConsoleHandle
);
582 CSR_API(SrvVerifyConsoleIoHandle
)
584 NTSTATUS Status
= STATUS_SUCCESS
;
585 PCONSOLE_VERIFYHANDLE VerifyHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.VerifyHandleRequest
;
586 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
587 HANDLE ConsoleHandle
= VerifyHandleRequest
->ConsoleHandle
;
588 ULONG_PTR Index
= (ULONG_PTR
)ConsoleHandle
>> 2;
590 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
592 if (!IsConsoleHandle(ConsoleHandle
) ||
593 Index
>= ProcessData
->HandleTableSize
||
594 ProcessData
->HandleTable
[Index
].Object
== NULL
)
596 DPRINT("CsrVerifyObject failed\n");
597 Status
= STATUS_INVALID_HANDLE
;
600 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
605 CSR_API(SrvDuplicateHandle
)
607 PCONSOLE_IO_HANDLE Entry
;
609 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.DuplicateHandleRequest
;
610 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
611 HANDLE ConsoleHandle
= DuplicateHandleRequest
->ConsoleHandle
;
612 ULONG_PTR Index
= (ULONG_PTR
)ConsoleHandle
>> 2;
614 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
616 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
617 Index
>= ProcessData
->HandleTableSize
||
618 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
620 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle
);
621 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
622 return STATUS_INVALID_HANDLE
;
625 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
627 DesiredAccess
= Entry
->Access
;
631 DesiredAccess
= DuplicateHandleRequest
->Access
;
632 /* Make sure the source handle has all the desired flags */
633 if (~Entry
->Access
& DesiredAccess
)
635 DPRINT1("Handle %p only has access %X; requested %X\n",
636 ConsoleHandle
, Entry
->Access
, DesiredAccess
);
637 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
638 return STATUS_INVALID_PARAMETER
;
642 ApiMessage
->Status
= Win32CsrInsertObject(ProcessData
,
643 &DuplicateHandleRequest
->ConsoleHandle
, // Use the new handle value!
646 DuplicateHandleRequest
->Inheritable
,
648 if (NT_SUCCESS(ApiMessage
->Status
) &&
649 DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
)
651 Win32CsrCloseHandleEntry(Entry
);
654 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
655 return ApiMessage
->Status
;
659 CSR_API(CsrGetInputWaitHandle)
661 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
663 GetConsoleInputWaitHandle->InputWaitHandle =
664 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
666 return STATUS_SUCCESS;