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 DPRINT("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 OpenConsoleRequest
->ConsoleHandle
= INVALID_HANDLE_VALUE
;
518 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
520 if (ProcessData
->Console
)
522 DWORD DesiredAccess
= OpenConsoleRequest
->Access
;
523 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
525 PCONSOLE Console
= ProcessData
->Console
;
528 EnterCriticalSection(&Console
->Lock
);
530 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
532 Object
= &Console
->ActiveBuffer
->Header
;
536 Object
= &Console
->InputBuffer
.Header
;
539 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
540 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
541 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
542 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
544 DPRINT1("Sharing violation\n");
545 Status
= STATUS_SHARING_VIOLATION
;
549 Status
= ConSrvInsertObject(ProcessData
,
550 &OpenConsoleRequest
->ConsoleHandle
,
553 OpenConsoleRequest
->Inheritable
,
557 LeaveCriticalSection(&Console
->Lock
);
560 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
565 CSR_API(SrvAllocConsole
)
567 NTSTATUS Status
= STATUS_SUCCESS
;
568 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
569 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
570 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
572 if (ProcessData
->Console
!= NULL
)
574 DPRINT1("Process already has a console\n");
575 return STATUS_ACCESS_DENIED
;
578 if ( !CsrValidateMessageBuffer(ApiMessage
,
579 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
581 sizeof(CONSOLE_START_INFO
)) ||
582 !CsrValidateMessageBuffer(ApiMessage
,
583 (PVOID
*)&AllocConsoleRequest
->AppPath
,
587 return STATUS_INVALID_PARAMETER
;
591 * We are about to create a new console. However when ConSrvNewProcess
592 * was called, we didn't know that we wanted to create a new console and
593 * therefore, we by default inherited the handles table from our parent
594 * process. It's only now that we notice that in fact we do not need
595 * them, because we've created a new console and thus we must use it.
597 * Therefore, free the console we can have and our handles table,
598 * and recreate a new one later on.
600 ConSrvRemoveConsole(ProcessData
);
601 // ConSrvFreeHandlesTable(ProcessData);
603 /* Initialize a new Console owned by the Console Leader Process */
604 Status
= ConSrvAllocateConsole(ProcessData
,
605 AllocConsoleRequest
->AppPath
,
606 &AllocConsoleRequest
->InputHandle
,
607 &AllocConsoleRequest
->OutputHandle
,
608 &AllocConsoleRequest
->ErrorHandle
,
609 AllocConsoleRequest
->ConsoleStartInfo
);
610 if (!NT_SUCCESS(Status
))
612 DPRINT1("Console allocation failed\n");
616 /* Return it to the caller */
617 AllocConsoleRequest
->Console
= ProcessData
->Console
;
619 /* Input Wait Handle */
620 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
622 /* Set the Property Dialog Handler */
623 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
625 /* Set the Ctrl Dispatcher */
626 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
628 return STATUS_SUCCESS
;
631 CSR_API(SrvAttachConsole
)
633 NTSTATUS Status
= STATUS_SUCCESS
;
634 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
635 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
636 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
637 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
638 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
640 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
642 if (TargetProcessData
->Console
!= NULL
)
644 DPRINT1("Process already has a console\n");
645 return STATUS_ACCESS_DENIED
;
648 /* Check whether we try to attach to the parent's console */
649 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
651 PROCESS_BASIC_INFORMATION ProcessInfo
;
652 ULONG Length
= sizeof(ProcessInfo
);
654 /* Get the real parent's ID */
656 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
657 ProcessBasicInformation
,
660 if (!NT_SUCCESS(Status
))
662 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
666 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
669 /* Lock the source process via its PID */
670 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
671 if (!NT_SUCCESS(Status
)) return Status
;
673 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
675 if (SourceProcessData
->Console
== NULL
)
677 Status
= STATUS_INVALID_HANDLE
;
682 * We are about to create a new console. However when ConSrvNewProcess
683 * was called, we didn't know that we wanted to create a new console and
684 * therefore, we by default inherited the handles table from our parent
685 * process. It's only now that we notice that in fact we do not need
686 * them, because we've created a new console and thus we must use it.
688 * Therefore, free the console we can have and our handles table,
689 * and recreate a new one later on.
691 ConSrvRemoveConsole(TargetProcessData
);
692 // ConSrvFreeHandlesTable(TargetProcessData);
695 * Inherit the console from the parent,
696 * if any, otherwise return an error.
698 Status
= ConSrvInheritConsole(TargetProcessData
,
699 SourceProcessData
->Console
,
701 &AttachConsoleRequest
->InputHandle
,
702 &AttachConsoleRequest
->OutputHandle
,
703 &AttachConsoleRequest
->ErrorHandle
);
704 if (!NT_SUCCESS(Status
))
706 DPRINT1("Console inheritance failed\n");
710 /* Return it to the caller */
711 AttachConsoleRequest
->Console
= TargetProcessData
->Console
;
713 /* Input Wait Handle */
714 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->ConsoleEvent
;
716 /* Set the Property Dialog Handler */
717 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
719 /* Set the Ctrl Dispatcher */
720 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
722 Status
= STATUS_SUCCESS
;
725 /* Unlock the "source" process and exit */
726 CsrUnlockProcess(SourceProcess
);
730 CSR_API(SrvFreeConsole
)
732 DPRINT1("SrvFreeConsole\n");
733 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
734 return STATUS_SUCCESS
;
737 CSR_API(SrvSetConsoleMode
)
739 #define CONSOLE_INPUT_MODE_VALID ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
740 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
741 ENABLE_MOUSE_INPUT | \
742 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS )
743 #define CONSOLE_OUTPUT_MODE_VALID ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
746 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
747 Object_t
* Object
= NULL
;
749 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
750 ConsoleModeRequest
->ConsoleHandle
,
751 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
752 if (!NT_SUCCESS(Status
)) return Status
;
754 Status
= STATUS_SUCCESS
;
756 if (CONIO_INPUT_BUFFER_MAGIC
== Object
->Type
)
758 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
759 InputBuffer
->Mode
= ConsoleModeRequest
->ConsoleMode
& CONSOLE_INPUT_MODE_VALID
;
761 else if (CONIO_SCREEN_BUFFER_MAGIC
== Object
->Type
)
763 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
764 Buffer
->Mode
= ConsoleModeRequest
->ConsoleMode
& CONSOLE_OUTPUT_MODE_VALID
;
768 Status
= STATUS_INVALID_HANDLE
;
771 ConSrvReleaseObject(Object
, TRUE
);
776 CSR_API(SrvGetConsoleMode
)
779 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
780 Object_t
* Object
= NULL
;
782 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
783 ConsoleModeRequest
->ConsoleHandle
,
784 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
785 if (!NT_SUCCESS(Status
)) return Status
;
787 Status
= STATUS_SUCCESS
;
789 if (CONIO_INPUT_BUFFER_MAGIC
== Object
->Type
)
791 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
792 ConsoleModeRequest
->ConsoleMode
= InputBuffer
->Mode
;
794 else if (CONIO_SCREEN_BUFFER_MAGIC
== Object
->Type
)
796 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
797 ConsoleModeRequest
->ConsoleMode
= Buffer
->Mode
;
801 Status
= STATUS_INVALID_HANDLE
;
804 ConSrvReleaseObject(Object
, TRUE
);
809 CSR_API(SrvSetConsoleTitle
)
812 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
813 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
817 if (!CsrValidateMessageBuffer(ApiMessage
,
818 (PVOID
)&TitleRequest
->Title
,
819 TitleRequest
->Length
,
822 return STATUS_INVALID_PARAMETER
;
825 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
826 if (!NT_SUCCESS(Status
))
828 DPRINT1("Can't get console\n");
832 /* Allocate a new buffer to hold the new title (NULL-terminated) */
833 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest
->Length
+ sizeof(WCHAR
));
836 /* Free the old title */
837 RtlFreeUnicodeString(&Console
->Title
);
839 /* Copy title to console */
840 Console
->Title
.Buffer
= Buffer
;
841 Console
->Title
.Length
= TitleRequest
->Length
;
842 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
843 RtlCopyMemory(Console
->Title
.Buffer
,
845 Console
->Title
.Length
);
846 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
848 ConioChangeTitle(Console
);
849 Status
= STATUS_SUCCESS
;
853 Status
= STATUS_NO_MEMORY
;
856 ConSrvReleaseConsole(Console
, TRUE
);
860 CSR_API(SrvGetConsoleTitle
)
863 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
864 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
868 if (!CsrValidateMessageBuffer(ApiMessage
,
869 (PVOID
)&TitleRequest
->Title
,
870 TitleRequest
->Length
,
873 return STATUS_INVALID_PARAMETER
;
876 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
877 if (!NT_SUCCESS(Status
))
879 DPRINT1("Can't get console\n");
883 /* Copy title of the console to the user title buffer */
884 if (TitleRequest
->Length
>= sizeof(WCHAR
))
886 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
887 memcpy(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
888 TitleRequest
->Title
[Length
/ sizeof(WCHAR
)] = L
'\0';
891 TitleRequest
->Length
= Console
->Title
.Length
;
893 ConSrvReleaseConsole(Console
, TRUE
);
894 return STATUS_SUCCESS
;
897 /**********************************************************************
898 * HardwareStateProperty
901 * Set/Get the value of the HardwareState and switch
902 * between direct video buffer ouput and GDI windowed
905 * Client hands us a CONSOLE_GETSETHWSTATE object.
906 * We use the same object to Request.
908 * ConsoleHwState has the correct size to be compatible
909 * with NT's, but values are not.
911 static NTSTATUS FASTCALL
912 SetConsoleHardwareState(PCONSOLE Console
, DWORD ConsoleHwState
)
914 DPRINT1("Console Hardware State: %d\n", ConsoleHwState
);
916 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED
== ConsoleHwState
)
917 ||(CONSOLE_HARDWARE_STATE_DIRECT
== ConsoleHwState
))
919 if (Console
->HardwareState
!= ConsoleHwState
)
921 /* TODO: implement switching from full screen to windowed mode */
922 /* TODO: or back; now simply store the hardware state */
923 Console
->HardwareState
= ConsoleHwState
;
926 return STATUS_SUCCESS
;
929 return STATUS_INVALID_PARAMETER_3
; /* Client: (handle, set_get, [mode]) */
932 CSR_API(SrvGetConsoleHardwareState
)
935 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
936 PCONSOLE_SCREEN_BUFFER Buff
;
939 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
940 HardwareStateRequest
->OutputHandle
,
944 if (!NT_SUCCESS(Status
))
946 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
950 Console
= Buff
->Header
.Console
;
951 HardwareStateRequest
->State
= Console
->HardwareState
;
953 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
958 CSR_API(SrvSetConsoleHardwareState
)
961 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
962 PCONSOLE_SCREEN_BUFFER Buff
;
965 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
966 HardwareStateRequest
->OutputHandle
,
970 if (!NT_SUCCESS(Status
))
972 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
976 DPRINT("Setting console hardware state.\n");
977 Console
= Buff
->Header
.Console
;
978 Status
= SetConsoleHardwareState(Console
, HardwareStateRequest
->State
);
980 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
985 CSR_API(SrvGetConsoleWindow
)
988 PCONSOLE_GETWINDOW GetWindowRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetWindowRequest
;
991 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
992 if (!NT_SUCCESS(Status
)) return Status
;
994 GetWindowRequest
->WindowHandle
= Console
->TermIFace
.Vtbl
->GetConsoleWindowHandle(Console
);
995 ConSrvReleaseConsole(Console
, TRUE
);
997 return STATUS_SUCCESS
;
1000 CSR_API(SrvSetConsoleIcon
)
1003 PCONSOLE_SETICON SetIconRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetIconRequest
;
1006 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1007 if (!NT_SUCCESS(Status
)) return Status
;
1009 Status
= (ConioChangeIcon(Console
, SetIconRequest
->WindowIcon
)
1011 : STATUS_UNSUCCESSFUL
);
1013 ConSrvReleaseConsole(Console
, TRUE
);
1018 CSR_API(SrvGetConsoleCP
)
1021 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1024 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1025 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1027 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1028 if (!NT_SUCCESS(Status
)) return Status
;
1030 ConsoleCPRequest
->CodePage
= (ConsoleCPRequest
->InputCP
? Console
->CodePage
1031 : Console
->OutputCodePage
);
1032 ConSrvReleaseConsole(Console
, TRUE
);
1033 return STATUS_SUCCESS
;
1036 CSR_API(SrvSetConsoleCP
)
1039 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1042 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1043 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1045 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1046 if (!NT_SUCCESS(Status
)) return Status
;
1048 if (IsValidCodePage(ConsoleCPRequest
->CodePage
))
1050 if (ConsoleCPRequest
->InputCP
)
1051 Console
->CodePage
= ConsoleCPRequest
->CodePage
;
1053 Console
->OutputCodePage
= ConsoleCPRequest
->CodePage
;
1055 ConSrvReleaseConsole(Console
, TRUE
);
1056 return STATUS_SUCCESS
;
1059 ConSrvReleaseConsole(Console
, TRUE
);
1060 return STATUS_INVALID_PARAMETER
;
1063 CSR_API(SrvGetConsoleProcessList
)
1066 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1068 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1070 PCONSOLE_PROCESS_DATA current
;
1071 PLIST_ENTRY current_entry
;
1074 if (!CsrValidateMessageBuffer(ApiMessage
,
1075 (PVOID
)&GetProcessListRequest
->pProcessIds
,
1076 GetProcessListRequest
->nMaxIds
,
1079 return STATUS_INVALID_PARAMETER
;
1082 Buffer
= GetProcessListRequest
->pProcessIds
;
1084 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1085 if (!NT_SUCCESS(Status
)) return Status
;
1087 for (current_entry
= Console
->ProcessList
.Flink
;
1088 current_entry
!= &Console
->ProcessList
;
1089 current_entry
= current_entry
->Flink
)
1091 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1092 if (++nItems
<= GetProcessListRequest
->nMaxIds
)
1094 *Buffer
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
1098 ConSrvReleaseConsole(Console
, TRUE
);
1100 GetProcessListRequest
->nProcessIdsTotal
= nItems
;
1101 return STATUS_SUCCESS
;
1104 CSR_API(SrvGenerateConsoleCtrlEvent
)
1107 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1109 PCONSOLE_PROCESS_DATA current
;
1110 PLIST_ENTRY current_entry
;
1113 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1114 if (!NT_SUCCESS(Status
)) return Status
;
1116 Group
= GenerateCtrlEventRequest
->ProcessGroup
;
1117 Status
= STATUS_INVALID_PARAMETER
;
1118 for (current_entry
= Console
->ProcessList
.Flink
;
1119 current_entry
!= &Console
->ProcessList
;
1120 current_entry
= current_entry
->Flink
)
1122 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1123 if (Group
== 0 || current
->Process
->ProcessGroupId
== Group
)
1125 ConSrvConsoleCtrlEvent(GenerateCtrlEventRequest
->Event
, current
);
1126 Status
= STATUS_SUCCESS
;
1130 ConSrvReleaseConsole(Console
, TRUE
);
1135 CSR_API(SrvGetConsoleSelectionInfo
)
1138 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetSelectionInfoRequest
;
1141 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1142 if (NT_SUCCESS(Status
))
1144 memset(&GetSelectionInfoRequest
->Info
, 0, sizeof(CONSOLE_SELECTION_INFO
));
1145 if (Console
->Selection
.dwFlags
!= 0)
1146 GetSelectionInfoRequest
->Info
= Console
->Selection
;
1147 ConSrvReleaseConsole(Console
, TRUE
);