2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/console.c
5 * PURPOSE: Console I/O functions
9 /* INCLUDES ******************************************************************/
12 #define NONAMELESSUNION
16 #include "guiconsole.h"
19 #include "tuiconsole.h"
29 /* FUNCTIONS *****************************************************************/
32 DtbgIsDesktopVisible(VOID
)
34 return !((BOOL
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
));
38 ConSrvConsoleCtrlEventTimeout(DWORD Event
,
39 PCONSOLE_PROCESS_DATA ProcessData
,
44 DPRINT("ConSrvConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
46 if (ProcessData
->CtrlDispatcher
)
48 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
49 ProcessData
->CtrlDispatcher
,
50 UlongToPtr(Event
), 0, NULL
);
53 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
57 DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
58 WaitForSingleObject(Thread
, Timeout
);
64 ConSrvConsoleCtrlEvent(DWORD Event
, PCONSOLE_PROCESS_DATA ProcessData
)
66 ConSrvConsoleCtrlEventTimeout(Event
, ProcessData
, 0);
70 ConioPause(PCONSOLE Console
, UINT Flags
)
72 Console
->PauseFlags
|= Flags
;
73 if (!Console
->UnpauseEvent
)
74 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
78 ConioUnpause(PCONSOLE Console
, UINT Flags
)
80 Console
->PauseFlags
&= ~Flags
;
82 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
83 if (Console
->PauseFlags
== 0 && Console
->UnpauseEvent
)
85 SetEvent(Console
->UnpauseEvent
);
86 CloseHandle(Console
->UnpauseEvent
);
87 Console
->UnpauseEvent
= NULL
;
89 CsrNotifyWait(&Console
->WriteWaitQueue
,
93 if (!IsListEmpty(&Console
->WriteWaitQueue
))
95 CsrDereferenceWait(&Console
->WriteWaitQueue
);
101 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
102 OUT PCONSOLE_INFO ConsoleInfo
,
104 IN SIZE_T IconPathLength
,
107 #define PATH_SEPARATOR L'\\'
110 LPWSTR LinkName
= NULL
;
113 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
116 if (IconPath
== NULL
|| piIcon
== NULL
)
122 /* 1- Find the last path separator if any */
123 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
124 if (LinkName
== NULL
)
126 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
130 /* Skip the path separator */
134 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
135 Length
= wcslen(LinkName
);
136 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
139 /* 3- It may be a link. Try to retrieve some properties */
140 HRESULT hRes
= CoInitialize(NULL
);
143 /* Get a pointer to the IShellLink interface */
144 IShellLinkW
* pshl
= NULL
;
145 hRes
= CoCreateInstance(&CLSID_ShellLink
,
147 CLSCTX_INPROC_SERVER
,
152 /* Get a pointer to the IPersistFile interface */
153 IPersistFile
* ppf
= NULL
;
154 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
157 /* Load the shortcut */
158 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
162 * Finally we can get the properties !
163 * Update the old ones if needed.
168 /* Get the name of the shortcut */
169 Length
= min(Length
- 4,
170 sizeof(ConsoleStartInfo
->ConsoleTitle
) / sizeof(ConsoleStartInfo
->ConsoleTitle
[0]) - 1);
171 wcsncpy(ConsoleStartInfo
->ConsoleTitle
, LinkName
, Length
);
172 ConsoleStartInfo
->ConsoleTitle
[Length
] = L
'\0';
174 // HACK: Copy also the name of the shortcut
176 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
177 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
178 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
180 /* Get the window showing command */
181 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
182 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->ShowWindow
= (WORD
)ShowCmd
;
185 // hRes = pshl->GetHotkey(&ShowCmd);
186 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
188 /* Get the icon location, if any */
189 hRes
= IShellLinkW_GetIconLocation(pshl
, IconPath
, IconPathLength
, piIcon
);
190 if (!SUCCEEDED(hRes
))
195 // FIXME: Since we still don't load console properties from the shortcut,
196 // return false. When this will be done, we will return true instead.
199 IPersistFile_Release(ppf
);
201 IShellLinkW_Release(pshl
);
210 ConSrvInitConsole(OUT PCONSOLE
* NewConsole
,
212 IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
213 IN PCSR_PROCESS ConsoleLeaderProcess
)
216 SECURITY_ATTRIBUTES SecurityAttributes
;
217 CONSOLE_INFO ConsoleInfo
;
219 DWORD ProcessId
= HandleToUlong(ConsoleLeaderProcess
->ClientId
.UniqueProcess
);
221 PCONSOLE_SCREEN_BUFFER NewBuffer
;
224 WCHAR IconPath
[MAX_PATH
+ 1] = L
"";
227 if (NewConsole
== NULL
) return STATUS_INVALID_PARAMETER
;
231 * Allocate a console structure
233 Console
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, sizeof(CONSOLE
));
236 DPRINT1("Not enough memory for console creation.\n");
237 return STATUS_NO_MEMORY
;
241 * Load the console settings
244 /* 1. Load the default settings */
245 ConSrvGetDefaultSettings(&ConsoleInfo
, ProcessId
);
247 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
248 Length
= min(wcslen(ConsoleStartInfo
->ConsoleTitle
),
249 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
250 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleStartInfo
->ConsoleTitle
, Length
);
251 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0';
254 * 3. Check whether the process creating the
255 * console was launched via a shell-link
256 * (ConsoleInfo.ConsoleTitle may be updated).
258 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
260 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
,
266 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
271 * 4. Load the remaining console settings via the registry.
273 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
276 * Either we weren't created by an app launched via a shell-link,
277 * or we failed to load shell-link console properties.
278 * Therefore, load the console infos for the application from the registry.
280 ConSrvReadUserSettings(&ConsoleInfo
, ProcessId
);
283 * Now, update them with the properties the user might gave to us
284 * via the STARTUPINFO structure before calling CreateProcess
285 * (and which was transmitted via the ConsoleStartInfo structure).
287 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
289 ConsoleInfo
.ScreenAttrib
= ConsoleStartInfo
->FillAttribute
;
291 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
293 ConsoleInfo
.ScreenBufferSize
= ConsoleStartInfo
->ScreenBufferSize
;
295 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
297 ConsoleInfo
.u
.GuiInfo
.ShowWindow
= ConsoleStartInfo
->ShowWindow
;
299 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
301 ConsoleInfo
.u
.GuiInfo
.AutoPosition
= FALSE
;
302 ConsoleInfo
.u
.GuiInfo
.WindowOrigin
= ConsoleStartInfo
->ConsoleWindowOrigin
;
304 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
306 // ConsoleInfo.ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
307 ConsoleInfo
.ConsoleSize
.X
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cx
;
308 ConsoleInfo
.ConsoleSize
.Y
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cy
;
311 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
318 * Initialize the console
320 InitializeCriticalSection(&Console
->Lock
);
321 Console
->ReferenceCount
= 0;
322 InitializeListHead(&Console
->ProcessList
);
323 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
324 Console
->Size
= ConsoleInfo
.ConsoleSize
;
327 * Initialize the input buffer
329 Console
->InputBuffer
.Header
.Type
= CONIO_INPUT_BUFFER_MAGIC
;
330 Console
->InputBuffer
.Header
.Console
= Console
;
332 SecurityAttributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
333 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
334 SecurityAttributes
.bInheritHandle
= TRUE
;
335 Console
->InputBuffer
.ActiveEvent
= CreateEventW(&SecurityAttributes
, TRUE
, FALSE
, NULL
);
336 if (NULL
== Console
->InputBuffer
.ActiveEvent
)
338 DeleteCriticalSection(&Console
->Lock
);
339 RtlFreeHeap(ConSrvHeap
, 0, Console
);
340 return STATUS_UNSUCCESSFUL
;
343 // TODO: Use the values from ConsoleInfo.
344 Console
->InputBuffer
.Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
|
345 ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
346 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
347 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
348 InitializeListHead(&Console
->InputBuffer
.ReadWaitQueue
);
349 InitializeListHead(&Console
->InputBuffer
.InputEvents
);
350 Console
->LineBuffer
= NULL
;
351 Console
->CodePage
= GetOEMCP();
352 Console
->OutputCodePage
= GetOEMCP();
354 /* Initialize a new screen buffer with default settings */
355 InitializeListHead(&Console
->BufferList
);
356 Status
= ConSrvCreateScreenBuffer(Console
,
358 ConsoleInfo
.ScreenBufferSize
,
359 ConsoleInfo
.ScreenAttrib
,
360 ConsoleInfo
.PopupAttrib
,
362 ConsoleInfo
.CursorSize
);
363 if (!NT_SUCCESS(Status
))
365 DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
366 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
367 DeleteCriticalSection(&Console
->Lock
);
368 RtlFreeHeap(ConSrvHeap
, 0, Console
);
371 /* Make the new screen buffer active */
372 Console
->ActiveBuffer
= NewBuffer
;
373 Console
->FullScreen
= ConsoleInfo
.FullScreen
;
374 InitializeListHead(&Console
->WriteWaitQueue
);
377 * Initialize the history buffers
379 InitializeListHead(&Console
->HistoryBuffers
);
380 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
381 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
382 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
384 /* Initialize the console title */
385 RtlCreateUnicodeString(&Console
->OriginalTitle
, ConsoleStartInfo
->ConsoleTitle
);
386 if (ConsoleStartInfo
->ConsoleTitle
[0] == L
'\0')
388 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, Title
, sizeof(Title
) / sizeof(Title
[0])))
390 RtlCreateUnicodeString(&Console
->Title
, Title
);
394 RtlCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
399 RtlCreateUnicodeString(&Console
->Title
, ConsoleStartInfo
->ConsoleTitle
);
403 * If we are not in GUI-mode, start the text-mode terminal emulator.
404 * If we fail, try to start the GUI-mode terminal emulator.
407 GuiMode
= DtbgIsDesktopVisible();
415 DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
416 Status
= TuiInitConsole(Console
, &ConsoleInfo
);
417 if (!NT_SUCCESS(Status
))
419 DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status
);
426 * Try to open the GUI-mode terminal emulator. Two cases are possible:
427 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
428 * failed and we start GUI-mode terminal emulator.
429 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
430 * succeeded BUT we failed at starting text-mode terminal emulator.
431 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
432 * terminal emulator (win32k will automatically switch to graphical mode,
433 * therefore no additional code is needed).
437 DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
438 Status
= GuiInitConsole(Console
,
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status
);
446 RtlFreeUnicodeString(&Console
->Title
);
447 RtlFreeUnicodeString(&Console
->OriginalTitle
);
448 ConioDeleteScreenBuffer(NewBuffer
);
449 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
450 DeleteCriticalSection(&Console
->Lock
);
451 RtlFreeHeap(ConSrvHeap
, 0, Console
);
456 /* Copy buffer contents to screen */
457 ConioDrawConsole(Console
);
459 /* Return the newly created console to the caller and a success code too */
460 *NewConsole
= Console
;
461 return STATUS_SUCCESS
;
465 ConSrvInitConsoleSupport(VOID
)
467 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
469 /* Should call LoadKeyboardLayout */
473 ConSrvDeleteConsole(PCONSOLE Console
)
477 DPRINT("ConSrvDeleteConsole\n");
479 /* Drain input event queue */
480 while (Console
->InputBuffer
.InputEvents
.Flink
!= &Console
->InputBuffer
.InputEvents
)
482 Event
= (ConsoleInput
*) Console
->InputBuffer
.InputEvents
.Flink
;
483 Console
->InputBuffer
.InputEvents
.Flink
= Console
->InputBuffer
.InputEvents
.Flink
->Flink
;
484 Console
->InputBuffer
.InputEvents
.Flink
->Flink
->Blink
= &Console
->InputBuffer
.InputEvents
;
485 RtlFreeHeap(ConSrvHeap
, 0, Event
);
488 ConioCleanupConsole(Console
);
489 if (Console
->LineBuffer
)
490 RtlFreeHeap(ConSrvHeap
, 0, Console
->LineBuffer
);
491 while (!IsListEmpty(&Console
->HistoryBuffers
))
492 HistoryDeleteBuffer((struct _HISTORY_BUFFER
*)Console
->HistoryBuffers
.Flink
);
494 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
495 if (!IsListEmpty(&Console
->BufferList
))
497 DPRINT1("BUG: screen buffer list not empty\n");
500 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
501 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
502 DeleteCriticalSection(&Console
->Lock
);
504 RtlFreeUnicodeString(&Console
->OriginalTitle
);
505 RtlFreeUnicodeString(&Console
->Title
);
506 IntDeleteAllAliases(Console
->Aliases
);
507 RtlFreeHeap(ConSrvHeap
, 0, Console
);
510 CSR_API(SrvOpenConsole
)
512 NTSTATUS Status
= STATUS_SUCCESS
;
513 PCONSOLE_OPENCONSOLE OpenConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.OpenConsoleRequest
;
514 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
516 DPRINT("SrvOpenConsole\n");
518 OpenConsoleRequest
->ConsoleHandle
= INVALID_HANDLE_VALUE
;
520 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
522 DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData
, ProcessData
->Console
);
524 if (ProcessData
->Console
)
526 DWORD DesiredAccess
= OpenConsoleRequest
->Access
;
527 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
529 PCONSOLE Console
= ProcessData
->Console
;
532 DPRINT1("SrvOpenConsole - Checkpoint 1\n");
533 EnterCriticalSection(&Console
->Lock
);
534 DPRINT1("SrvOpenConsole - Checkpoint 2\n");
536 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
538 Object
= &Console
->ActiveBuffer
->Header
;
542 Object
= &Console
->InputBuffer
.Header
;
545 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
546 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
547 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
548 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
550 DPRINT1("Sharing violation\n");
551 Status
= STATUS_SHARING_VIOLATION
;
555 Status
= ConSrvInsertObject(ProcessData
,
556 &OpenConsoleRequest
->ConsoleHandle
,
559 OpenConsoleRequest
->Inheritable
,
563 LeaveCriticalSection(&Console
->Lock
);
566 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
571 CSR_API(SrvAllocConsole
)
573 NTSTATUS Status
= STATUS_SUCCESS
;
574 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
575 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
576 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
578 DPRINT("SrvAllocConsole\n");
580 if (ProcessData
->Console
!= NULL
)
582 DPRINT1("Process already has a console\n");
583 return STATUS_ACCESS_DENIED
;
586 if ( !CsrValidateMessageBuffer(ApiMessage
,
587 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
589 sizeof(CONSOLE_START_INFO
)) ||
590 !CsrValidateMessageBuffer(ApiMessage
,
591 (PVOID
*)&AllocConsoleRequest
->AppPath
,
595 return STATUS_INVALID_PARAMETER
;
599 * We are about to create a new console. However when ConSrvNewProcess
600 * was called, we didn't know that we wanted to create a new console and
601 * therefore, we by default inherited the handles table from our parent
602 * process. It's only now that we notice that in fact we do not need
603 * them, because we've created a new console and thus we must use it.
605 * Therefore, free the console we can have and our handles table,
606 * and recreate a new one later on.
608 ConSrvRemoveConsole(ProcessData
);
609 // ConSrvFreeHandlesTable(ProcessData);
611 /* Initialize a new Console owned by the Console Leader Process */
612 Status
= ConSrvAllocateConsole(ProcessData
,
613 AllocConsoleRequest
->AppPath
,
614 &AllocConsoleRequest
->InputHandle
,
615 &AllocConsoleRequest
->OutputHandle
,
616 &AllocConsoleRequest
->ErrorHandle
,
617 AllocConsoleRequest
->ConsoleStartInfo
);
618 if (!NT_SUCCESS(Status
))
620 DPRINT1("Console allocation failed\n");
624 /* Return it to the caller */
625 AllocConsoleRequest
->Console
= ProcessData
->Console
;
627 /* Input Wait Handle */
628 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
630 /* Set the Property Dialog Handler */
631 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
633 /* Set the Ctrl Dispatcher */
634 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
635 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData
->CtrlDispatcher
);
637 return STATUS_SUCCESS
;
640 CSR_API(SrvAttachConsole
)
642 NTSTATUS Status
= STATUS_SUCCESS
;
643 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
644 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
645 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
646 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
647 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
649 DPRINT("SrvAttachConsole\n");
651 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
653 if (TargetProcessData
->Console
!= NULL
)
655 DPRINT1("Process already has a console\n");
656 return STATUS_ACCESS_DENIED
;
659 /* Check whether we try to attach to the parent's console */
660 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
662 PROCESS_BASIC_INFORMATION ProcessInfo
;
663 ULONG Length
= sizeof(ProcessInfo
);
665 /* Get the real parent's ID */
667 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
668 ProcessBasicInformation
,
671 if (!NT_SUCCESS(Status
))
673 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
677 DPRINT("We, process (ID) %lu;%lu\n", TargetProcess
->ClientId
.UniqueProcess
, TargetProcess
->ClientId
.UniqueThread
);
678 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
679 DPRINT("Parent process ID = %lu\n", ProcessId
);
682 /* Lock the source process via its PID */
683 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
684 DPRINT1("Lock process Id %lu - Status %lu\n", ProcessId
, Status
);
685 if (!NT_SUCCESS(Status
)) return Status
;
687 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
689 DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData
->Console
);
690 if (SourceProcessData
->Console
== NULL
)
692 Status
= STATUS_INVALID_HANDLE
;
697 * We are about to create a new console. However when ConSrvNewProcess
698 * was called, we didn't know that we wanted to create a new console and
699 * therefore, we by default inherited the handles table from our parent
700 * process. It's only now that we notice that in fact we do not need
701 * them, because we've created a new console and thus we must use it.
703 * Therefore, free the console we can have and our handles table,
704 * and recreate a new one later on.
706 ConSrvRemoveConsole(TargetProcessData
);
707 // ConSrvFreeHandlesTable(TargetProcessData);
710 * Inherit the console from the parent,
711 * if any, otherwise return an error.
713 Status
= ConSrvInheritConsole(TargetProcessData
,
714 SourceProcessData
->Console
,
716 &AttachConsoleRequest
->InputHandle
,
717 &AttachConsoleRequest
->OutputHandle
,
718 &AttachConsoleRequest
->ErrorHandle
);
719 if (!NT_SUCCESS(Status
))
721 DPRINT1("Console inheritance failed\n");
725 /* Return it to the caller */
726 AttachConsoleRequest
->Console
= TargetProcessData
->Console
;
728 /* Input Wait Handle */
729 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->ConsoleEvent
;
731 /* Set the Property Dialog Handler */
732 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
734 /* Set the Ctrl Dispatcher */
735 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
736 DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData
->CtrlDispatcher
);
738 Status
= STATUS_SUCCESS
;
741 /* Unlock the "source" process and exit */
742 CsrUnlockProcess(SourceProcess
);
746 CSR_API(SrvFreeConsole
)
748 DPRINT1("SrvFreeConsole\n");
749 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
750 return STATUS_SUCCESS
;
753 CSR_API(SrvSetConsoleMode
)
755 #define CONSOLE_INPUT_MODE_VALID ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
756 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
757 ENABLE_MOUSE_INPUT | \
758 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS )
759 #define CONSOLE_OUTPUT_MODE_VALID ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
762 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
763 Object_t
* Object
= NULL
;
765 DPRINT("SrvSetConsoleMode\n");
767 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
768 ConsoleModeRequest
->ConsoleHandle
,
769 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
770 if (!NT_SUCCESS(Status
)) return Status
;
772 Status
= STATUS_SUCCESS
;
774 if (CONIO_INPUT_BUFFER_MAGIC
== Object
->Type
)
776 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
777 InputBuffer
->Mode
= ConsoleModeRequest
->ConsoleMode
& CONSOLE_INPUT_MODE_VALID
;
779 else if (CONIO_SCREEN_BUFFER_MAGIC
== Object
->Type
)
781 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
782 Buffer
->Mode
= ConsoleModeRequest
->ConsoleMode
& CONSOLE_OUTPUT_MODE_VALID
;
786 Status
= STATUS_INVALID_HANDLE
;
789 ConSrvReleaseObject(Object
, TRUE
);
794 CSR_API(SrvGetConsoleMode
)
797 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
798 Object_t
* Object
= NULL
;
800 DPRINT("SrvGetConsoleMode\n");
802 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
803 ConsoleModeRequest
->ConsoleHandle
,
804 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
805 if (!NT_SUCCESS(Status
)) return Status
;
807 Status
= STATUS_SUCCESS
;
809 if (CONIO_INPUT_BUFFER_MAGIC
== Object
->Type
)
811 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
812 ConsoleModeRequest
->ConsoleMode
= InputBuffer
->Mode
;
814 else if (CONIO_SCREEN_BUFFER_MAGIC
== Object
->Type
)
816 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
817 ConsoleModeRequest
->ConsoleMode
= Buffer
->Mode
;
821 Status
= STATUS_INVALID_HANDLE
;
824 ConSrvReleaseObject(Object
, TRUE
);
829 CSR_API(SrvSetConsoleTitle
)
832 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
833 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
837 DPRINT("SrvSetConsoleTitle\n");
839 if (!CsrValidateMessageBuffer(ApiMessage
,
840 (PVOID
)&TitleRequest
->Title
,
841 TitleRequest
->Length
,
844 return STATUS_INVALID_PARAMETER
;
847 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
848 if (!NT_SUCCESS(Status
))
850 DPRINT1("Can't get console\n");
854 /* Allocate a new buffer to hold the new title (NULL-terminated) */
855 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest
->Length
+ sizeof(WCHAR
));
858 /* Free the old title */
859 RtlFreeUnicodeString(&Console
->Title
);
861 /* Copy title to console */
862 Console
->Title
.Buffer
= Buffer
;
863 Console
->Title
.Length
= TitleRequest
->Length
;
864 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
865 RtlCopyMemory(Console
->Title
.Buffer
,
867 Console
->Title
.Length
);
868 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
870 ConioChangeTitle(Console
);
871 Status
= STATUS_SUCCESS
;
875 Status
= STATUS_NO_MEMORY
;
878 ConSrvReleaseConsole(Console
, TRUE
);
882 CSR_API(SrvGetConsoleTitle
)
885 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
886 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
890 DPRINT("SrvGetConsoleTitle\n");
892 if (!CsrValidateMessageBuffer(ApiMessage
,
893 (PVOID
)&TitleRequest
->Title
,
894 TitleRequest
->Length
,
897 return STATUS_INVALID_PARAMETER
;
900 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
901 if (!NT_SUCCESS(Status
))
903 DPRINT1("Can't get console\n");
907 /* Copy title of the console to the user title buffer */
908 if (TitleRequest
->Length
>= sizeof(WCHAR
))
910 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
911 memcpy(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
912 TitleRequest
->Title
[Length
/ sizeof(WCHAR
)] = L
'\0';
915 TitleRequest
->Length
= Console
->Title
.Length
;
917 ConSrvReleaseConsole(Console
, TRUE
);
918 return STATUS_SUCCESS
;
921 /**********************************************************************
922 * HardwareStateProperty
925 * Set/Get the value of the HardwareState and switch
926 * between direct video buffer ouput and GDI windowed
929 * Client hands us a CONSOLE_GETSETHWSTATE object.
930 * We use the same object to Request.
932 * ConsoleHwState has the correct size to be compatible
933 * with NT's, but values are not.
935 static NTSTATUS FASTCALL
936 SetConsoleHardwareState(PCONSOLE Console
, DWORD ConsoleHwState
)
938 DPRINT1("Console Hardware State: %d\n", ConsoleHwState
);
940 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED
== ConsoleHwState
)
941 ||(CONSOLE_HARDWARE_STATE_DIRECT
== ConsoleHwState
))
943 if (Console
->HardwareState
!= ConsoleHwState
)
945 /* TODO: implement switching from full screen to windowed mode */
946 /* TODO: or back; now simply store the hardware state */
947 Console
->HardwareState
= ConsoleHwState
;
950 return STATUS_SUCCESS
;
953 return STATUS_INVALID_PARAMETER_3
; /* Client: (handle, set_get, [mode]) */
956 CSR_API(SrvGetConsoleHardwareState
)
959 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
960 PCONSOLE_SCREEN_BUFFER Buff
;
963 DPRINT("SrvGetConsoleHardwareState\n");
965 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
966 HardwareStateRequest
->OutputHandle
,
970 if (!NT_SUCCESS(Status
))
972 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
976 Console
= Buff
->Header
.Console
;
977 HardwareStateRequest
->State
= Console
->HardwareState
;
979 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
984 CSR_API(SrvSetConsoleHardwareState
)
987 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
988 PCONSOLE_SCREEN_BUFFER Buff
;
991 DPRINT("SrvSetConsoleHardwareState\n");
993 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
994 HardwareStateRequest
->OutputHandle
,
998 if (!NT_SUCCESS(Status
))
1000 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
1004 DPRINT("Setting console hardware state.\n");
1005 Console
= Buff
->Header
.Console
;
1006 Status
= SetConsoleHardwareState(Console
, HardwareStateRequest
->State
);
1008 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1013 CSR_API(SrvGetConsoleWindow
)
1016 PCONSOLE_GETWINDOW GetWindowRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetWindowRequest
;
1019 DPRINT("SrvGetConsoleWindow\n");
1021 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1022 if (!NT_SUCCESS(Status
)) return Status
;
1024 GetWindowRequest
->WindowHandle
= Console
->TermIFace
.Vtbl
->GetConsoleWindowHandle(Console
);
1025 ConSrvReleaseConsole(Console
, TRUE
);
1027 return STATUS_SUCCESS
;
1030 CSR_API(SrvSetConsoleIcon
)
1033 PCONSOLE_SETICON SetIconRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetIconRequest
;
1036 DPRINT("SrvSetConsoleIcon\n");
1038 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1039 if (!NT_SUCCESS(Status
)) return Status
;
1041 Status
= (ConioChangeIcon(Console
, SetIconRequest
->WindowIcon
)
1043 : STATUS_UNSUCCESSFUL
);
1045 ConSrvReleaseConsole(Console
, TRUE
);
1050 CSR_API(SrvGetConsoleCP
)
1053 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1056 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1057 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1059 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1060 if (!NT_SUCCESS(Status
)) return Status
;
1062 ConsoleCPRequest
->CodePage
= (ConsoleCPRequest
->InputCP
? Console
->CodePage
1063 : Console
->OutputCodePage
);
1064 ConSrvReleaseConsole(Console
, TRUE
);
1065 return STATUS_SUCCESS
;
1068 CSR_API(SrvSetConsoleCP
)
1071 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1074 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1075 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1077 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1078 if (!NT_SUCCESS(Status
)) return Status
;
1080 if (IsValidCodePage(ConsoleCPRequest
->CodePage
))
1082 if (ConsoleCPRequest
->InputCP
)
1083 Console
->CodePage
= ConsoleCPRequest
->CodePage
;
1085 Console
->OutputCodePage
= ConsoleCPRequest
->CodePage
;
1087 ConSrvReleaseConsole(Console
, TRUE
);
1088 return STATUS_SUCCESS
;
1091 ConSrvReleaseConsole(Console
, TRUE
);
1092 return STATUS_INVALID_PARAMETER
;
1095 CSR_API(SrvGetConsoleProcessList
)
1098 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1100 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1102 PCONSOLE_PROCESS_DATA current
;
1103 PLIST_ENTRY current_entry
;
1106 DPRINT("SrvGetConsoleProcessList\n");
1108 if (!CsrValidateMessageBuffer(ApiMessage
,
1109 (PVOID
)&GetProcessListRequest
->pProcessIds
,
1110 GetProcessListRequest
->nMaxIds
,
1113 return STATUS_INVALID_PARAMETER
;
1116 Buffer
= GetProcessListRequest
->pProcessIds
;
1118 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1119 if (!NT_SUCCESS(Status
)) return Status
;
1121 for (current_entry
= Console
->ProcessList
.Flink
;
1122 current_entry
!= &Console
->ProcessList
;
1123 current_entry
= current_entry
->Flink
)
1125 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1126 if (++nItems
<= GetProcessListRequest
->nMaxIds
)
1128 *Buffer
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
1132 ConSrvReleaseConsole(Console
, TRUE
);
1134 GetProcessListRequest
->nProcessIdsTotal
= nItems
;
1135 return STATUS_SUCCESS
;
1138 CSR_API(SrvGenerateConsoleCtrlEvent
)
1141 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1143 PCONSOLE_PROCESS_DATA current
;
1144 PLIST_ENTRY current_entry
;
1147 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1148 if (!NT_SUCCESS(Status
)) return Status
;
1150 Group
= GenerateCtrlEventRequest
->ProcessGroup
;
1151 Status
= STATUS_INVALID_PARAMETER
;
1152 for (current_entry
= Console
->ProcessList
.Flink
;
1153 current_entry
!= &Console
->ProcessList
;
1154 current_entry
= current_entry
->Flink
)
1156 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1157 if (Group
== 0 || current
->Process
->ProcessGroupId
== Group
)
1159 ConSrvConsoleCtrlEvent(GenerateCtrlEventRequest
->Event
, current
);
1160 Status
= STATUS_SUCCESS
;
1164 ConSrvReleaseConsole(Console
, TRUE
);
1169 CSR_API(SrvGetConsoleSelectionInfo
)
1172 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetSelectionInfoRequest
;
1175 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1176 if (NT_SUCCESS(Status
))
1178 memset(&GetSelectionInfoRequest
->Info
, 0, sizeof(CONSOLE_SELECTION_INFO
));
1179 if (Console
->Selection
.dwFlags
!= 0)
1180 GetSelectionInfoRequest
->Info
= Console
->Selection
;
1181 ConSrvReleaseConsole(Console
, TRUE
);