ReactOS  0.4.14-dev-828-g8dc90a4
console.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS Console Driver DLL
4  * FILE: win32ss/user/winsrv/consrv/condrv/console.c
5  * PURPOSE: Console Management Functions
6  * PROGRAMMERS: Gé van Geldorp
7  * Jeffrey Morlan
8  * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9  * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include <consrv.h>
15 #include <coninput.h>
16 #include "../../concfg/font.h"
17 
18 #define NDEBUG
19 #include <debug.h>
20 
21 /* GLOBALS ********************************************************************/
22 
24 
25 /* Linked list of consoles */
28 
29 #define ConDrvLockConsoleListExclusive() \
30  RtlAcquireResourceExclusive(&ListLock, TRUE)
31 
32 #define ConDrvLockConsoleListShared() \
33  RtlAcquireResourceShared(&ListLock, TRUE)
34 
35 #define ConDrvUnlockConsoleList() \
36  RtlReleaseResource(&ListLock)
37 
38 
39 static NTSTATUS
41 {
42  ASSERT(Console);
43 
44  /* All went right, so add the console to the list */
46 
47  DPRINT("Insert in the list\n");
49 
50  // FIXME: Move this code to the caller function!!
51  /* Get a new console ID */
54 
55  /* Unlock the console list and return success */
57  return STATUS_SUCCESS;
58 }
59 
60 static NTSTATUS
62 {
63  // ASSERT(Console);
64  if (!Console) return STATUS_INVALID_PARAMETER;
65 
66  /* Remove the console from the list */
68 
69  RemoveEntryList(&Console->ListEntry);
70 
71  /* Unlock the console list and return success */
73  return STATUS_SUCCESS;
74 }
75 
76 
77 /* PRIVATE FUNCTIONS **********************************************************/
78 
79 VOID NTAPI
81 {
82  /* In case we already have a pause event, just exit... */
83  if (Console->UnpauseEvent) return;
84 
85  /* ... otherwise create it */
86  NtCreateEvent(&Console->UnpauseEvent, EVENT_ALL_ACCESS,
88 }
89 
90 VOID NTAPI
92 {
93  /* In case we already freed the event, just exit... */
94  if (!Console->UnpauseEvent) return;
95 
96  /* ... otherwise set and free it */
97  NtSetEvent(Console->UnpauseEvent, NULL);
98  NtClose(Console->UnpauseEvent);
99  Console->UnpauseEvent = NULL;
100 }
101 
102 
103 /*
104  * Console accessibility check helpers
105  */
106 
109  IN CONSOLE_STATE ExpectedState)
110 {
111  // if (!Console) return FALSE;
112 
113  /* The console must be locked */
114  // ASSERT(Console_locked);
115 
116  return (Console->State == ExpectedState);
117 }
118 
121  IN CONSOLE_STATE ExpectedState,
122  IN BOOLEAN LockConsole)
123 {
124  if (!Console) return FALSE;
125 
126  /*
127  * Lock the console to forbid possible console's state changes
128  * (which must be done when the console is already locked).
129  * If we don't want to lock it, it's because the lock is already
130  * held. So there must be no problems.
131  */
132  if (LockConsole) EnterCriticalSection(&Console->Lock);
133 
134  // ASSERT(Console_locked);
135 
136  /* Check whether the console's state is what we expect */
137  if (!ConDrvValidateConsoleState(Console, ExpectedState))
138  {
139  if (LockConsole) LeaveCriticalSection(&Console->Lock);
140  return FALSE;
141  }
142 
143  return TRUE;
144 }
145 
146 
147 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
148 
149 VOID NTAPI
151 {
152  DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
153 
154  /* Initialize the console list and its lock */
157 }
158 
159 /* For resetting the terminal - defined in dummyterm.c */
161 
165 {
167  // CONSOLE_INFO CapturedConsoleInfo;
170  PCONSOLE_SCREEN_BUFFER NewBuffer;
171 
172  if (NewConsole == NULL || ConsoleInfo == NULL)
174 
175  *NewConsole = NULL;
176 
177  /*
178  * Allocate a new console
179  */
181  if (NULL == Console)
182  {
183  DPRINT1("Not enough memory for console creation.\n");
184  return STATUS_NO_MEMORY;
185  }
186 
187  /*
188  * Fix the screen buffer size if needed. The rule is:
189  * ScreenBufferSize >= ConsoleSize
190  */
191  if (ConsoleInfo->ScreenBufferSize.X < ConsoleInfo->ConsoleSize.X)
192  ConsoleInfo->ScreenBufferSize.X = ConsoleInfo->ConsoleSize.X;
193  if (ConsoleInfo->ScreenBufferSize.Y < ConsoleInfo->ConsoleSize.Y)
194  ConsoleInfo->ScreenBufferSize.Y = ConsoleInfo->ConsoleSize.Y;
195 
196  /*
197  * Initialize the console
198  */
199  Console->State = CONSOLE_INITIALIZING;
200  Console->ReferenceCount = 0;
202 
203  /* Initialize the terminal interface */
205 
206  Console->ConsoleSize = ConsoleInfo->ConsoleSize;
207  Console->FixedSize = FALSE; // Value by default; is reseted by the terminals if needed.
208 
209  /* Initialize the input buffer */
210  Status = ConDrvInitInputBuffer(Console, 0 /* ConsoleInfo->InputBufferSize */);
211  if (!NT_SUCCESS(Status))
212  {
213  DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status);
216  return Status;
217  }
218 
219  /* Set-up the code page */
220  if (IsValidCodePage(ConsoleInfo->CodePage))
221  Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
222 
223  Console->IsCJK = IsCJKCodePage(Console->OutputCodePage);
224 
225  /* Initialize a new text-mode screen buffer with default settings */
226  ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
227  ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib;
228  ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib;
229  ScreenBufferInfo.IsCursorVisible = TRUE;
230  ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize;
231 
232  InitializeListHead(&Console->BufferList);
233  Status = ConDrvCreateScreenBuffer(&NewBuffer,
234  Console,
235  NULL,
238  if (!NT_SUCCESS(Status))
239  {
240  DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
244  return Status;
245  }
246  /* Make the new screen buffer active */
247  Console->ActiveBuffer = NewBuffer;
248  Console->UnpauseEvent = NULL;
249 
250  DPRINT("Console initialized\n");
251 
252  /* All went right, so add the console to the list */
254  if (!NT_SUCCESS(Status))
255  {
256  /* Fail */
258  return Status;
259  }
260 
261  /* The initialization is finished */
262  DPRINT("Change state\n");
263  Console->State = CONSOLE_RUNNING;
264 
265  /* Return the newly created console to the caller and a success code too */
266  *NewConsole = Console;
267  return STATUS_SUCCESS;
268 }
269 
272  IN PTERMINAL Terminal)
273 {
275 
276  if (Console == NULL || Terminal == NULL)
278 
279  /* FIXME: Lock the console before ?? */
280 
281  /*
282  * Attach the terminal to the console. Use now the TermIFace of the console,
283  * and not the user-defined temporary Terminal pointer.
284  */
285  Console->TermIFace = *Terminal;
286  Console->TermIFace.Console = Console;
287 
288  /* Initialize the terminal AFTER having attached it to the console */
289  DPRINT("Finish initialization of terminal\n");
290  Status = Console->TermIFace.Vtbl->InitTerminal(&Console->TermIFace, Console);
291  if (!NT_SUCCESS(Status))
292  {
293  DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status);
294 
295  /* We failed, detach the terminal from the console */
296  Terminal->Console = NULL; // For the caller
298  return Status;
299  }
300 
301  /* Copy buffer contents to screen */
302  // Terminal.Draw();
303 
304  DPRINT("Terminal initialization done\n");
305  return STATUS_SUCCESS;
306 }
307 
310 {
311  if (Console == NULL) return STATUS_INVALID_PARAMETER;
312 
313  /* FIXME: Lock the console before ?? */
314 
315  /* Deinitialize the terminal BEFORE detaching it from the console */
316  Console->TermIFace.Vtbl->DeinitTerminal(&Console->TermIFace/*, Console*/);
317 
318  /*
319  * Detach the terminal from the console:
320  * reinitialize the terminal interface.
321  */
323 
324  DPRINT("Terminal unregistered\n");
325  return STATUS_SUCCESS;
326 }
327 
328 VOID NTAPI
330 {
331  DPRINT("ConDrvDeleteConsole(0x%p)\n", Console);
332 
333  /*
334  * Forbid validation of any console by other threads
335  * during the deletion of this console.
336  */
338 
339  /*
340  * If the console is already being destroyed, i.e. not running
341  * or finishing to be initialized, just return.
342  */
345  {
346  /* Unlock the console list and return */
348  return;
349  }
350 
351  /*
352  * We are about to be destroyed. Signal it to other people
353  * so that they can terminate what they are doing, and that
354  * they cannot longer validate the console.
355  */
356  Console->State = CONSOLE_TERMINATING;
357 
358  /*
359  * Allow other threads to finish their job: basically, unlock
360  * all other calls to EnterCriticalSection(&Console->Lock); by
361  * ConDrvValidateConsoleUnsafe functions so that they just see
362  * that we are not in CONSOLE_RUNNING state anymore, or unlock
363  * other concurrent calls to ConDrvDeleteConsole so that they
364  * can see that we are in fact already deleting the console.
365  */
368 
369  /* Deregister the terminal */
370  DPRINT("Deregister terminal\n");
372  DPRINT("Terminal deregistered\n");
373 
374  /***
375  * Check that the console is in terminating state before continuing
376  * (the cleanup code must not change the state of the console...
377  * ...unless to cancel console deletion ?).
378  ***/
379 
381 
383  {
385  return;
386  }
387 
388  /* We are now in destruction */
390 
391  /* We really delete the console. Reset the count to be sure. */
392  Console->ReferenceCount = 0;
393 
394  /* Remove the console from the list */
396 
397  /* Delete the last screen buffer */
398  ConDrvDeleteScreenBuffer(Console->ActiveBuffer);
399  Console->ActiveBuffer = NULL;
400  if (!IsListEmpty(&Console->BufferList))
401  {
402  /***ConDrvUnlockConsoleList();***/
403  ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE);
404  }
405 
406  /* Deinitialize the input buffer */
408 
409  if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
410 
411  DPRINT("ConDrvDeleteConsole - Unlocking\n");
413  DPRINT("ConDrvDeleteConsole - Destroying lock\n");
415  DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
416 
418  DPRINT("ConDrvDeleteConsole - Console destroyed\n");
419 
420  /* Unlock the console list and return */
422 }
423 
424 
425 /* PUBLIC DRIVER APIS *********************************************************/
426 
430  OUT PULONG ConsoleMode)
431 {
433 
434  if (Console == NULL || Object == NULL || ConsoleMode == NULL)
436 
437  /* Validity check */
438  ASSERT(Console == Object->Console);
439 
440  /*** FIXME: */ *ConsoleMode = 0; /***/
441 
442  if (INPUT_BUFFER == Object->Type)
443  {
445  *ConsoleMode = InputBuffer->Mode;
446  }
447  else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
448  {
450  *ConsoleMode = Buffer->Mode;
451  }
452  else
453  {
455  }
456 
457  return Status;
458 }
459 
463  IN ULONG ConsoleMode)
464 {
465 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
466  ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
467  ENABLE_MOUSE_INPUT )
468 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
469 
471 
472  if (Console == NULL || Object == NULL)
474 
475  /* Validity check */
476  ASSERT(Console == Object->Console);
477 
478  if (INPUT_BUFFER == Object->Type)
479  {
481 
482  /* Only the presence of valid mode flags is allowed */
483  if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES)
484  {
486  }
487  else
488  {
489  InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
490  }
491  }
492  else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
493  {
495 
496  /* Only the presence of valid mode flags is allowed */
497  if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
498  {
500  }
501  else
502  {
503  Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
504  }
505  }
506  else
507  {
509  }
510 
511  return Status;
512 }
513 
516  OUT PUINT CodePage,
517  IN BOOLEAN OutputCP)
518 {
519  if (Console == NULL || CodePage == NULL)
521 
522  *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage);
523 
524  return STATUS_SUCCESS;
525 }
526 
529  IN UINT CodePage,
530  IN BOOLEAN OutputCP)
531 {
532  if (Console == NULL || !IsValidCodePage(CodePage))
534 
535  if (OutputCP)
536  {
537  Console->OutputCodePage = CodePage;
538  Console->IsCJK = IsCJKCodePage(CodePage);
539  }
540  else
541  {
542  Console->InputCodePage = CodePage;
543  }
544 
545  return STATUS_SUCCESS;
546 }
547 
548 /* EOF */
#define ConDrvUnlockConsoleList()
Definition: console.c:35
BOOLEAN NTAPI ConDrvValidateConsoleState(IN PCONSOLE Console, IN CONSOLE_STATE ExpectedState)
Definition: console.c:108
#define IN
Definition: typedefs.h:38
static RTL_RESOURCE ListLock
Definition: console.c:27
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
#define ConDrvLockConsoleListExclusive()
Definition: console.c:29
VOID NTAPI ConDrvDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
Definition: conoutput.c:123
NTSTATUS NTAPI ConDrvDetachTerminal(IN PCONSOLE Console)
Definition: console.c:309
CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo
Definition: notevil.c:38
VOID NTAPI ConDrvInitConsoleSupport(VOID)
Definition: console.c:150
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
long __cdecl _InterlockedExchange(_Interlocked_operand_ long volatile *_Target, long _Value)
LONG NTSTATUS
Definition: precomp.h:26
#define ConsoleAllocHeap(Flags, Size)
Definition: heap.h:14
NTSTATUS NTAPI NtCreateEvent(OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState)
Definition: event.c:100
VOID NTAPI ConDrvPause(PCONSOLE Console)
Definition: console.c:80
NTSTATUS ConDrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER *Buffer, IN PCONSOLE Console, IN HANDLE ProcessHandle OPTIONAL, IN ULONG BufferType, IN PVOID ScreenBufferInfo)
Definition: conoutput.c:79
#define TEXTMODE_BUFFER
Definition: pccons.c:21
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define InsertTailList(ListHead, Entry)
NTSTATUS NTAPI ConDrvGetConsoleMode(IN PCONSOLE Console, IN PCONSOLE_IO_OBJECT Object, OUT PULONG ConsoleMode)
Definition: console.c:428
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
CHAR InputBuffer[80]
Definition: conmgr.c:33
VOID NTAPI ConDrvUnpause(PCONSOLE Console)
Definition: console.c:91
NTSTATUS NTAPI ConDrvSetConsoleMode(IN PCONSOLE Console, IN PCONSOLE_IO_OBJECT Object, IN ULONG ConsoleMode)
Definition: console.c:461
#define IsCJKCodePage(CodePage)
Definition: font.h:23
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
VOID NTAPI ConDrvDeleteConsole(IN PCONSOLE Console)
Definition: console.c:329
struct _CONSOLE_INPUT_BUFFER * PCONSOLE_INPUT_BUFFER
long __cdecl _InterlockedIncrement(_Interlocked_operand_ long volatile *_Addend)
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
VOID NTAPI ConDrvDeinitInputBuffer(IN PCONSOLE Console)
Definition: coninput.c:217
struct _CONSOLE_SCREEN_BUFFER * PCONSOLE_SCREEN_BUFFER
Definition: conio.h:70
unsigned char BOOLEAN
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
#define CONSOLE_VALID_INPUT_MODES
static NTSTATUS ConDrvInsertConsole(IN PCONSOLE Console)
Definition: console.c:40
NTSYSAPI VOID NTAPI RtlInitializeResource(_In_ PRTL_RESOURCE Resource)
NTSTATUS NTAPI NtSetEvent(IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL)
Definition: event.c:458
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static LIST_ENTRY ConDrvConsoleList
Definition: console.c:26
static IUnknown Object
Definition: main.c:512
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
NTSTATUS NTAPI ConDrvAttachTerminal(IN PCONSOLE Console, IN PTERMINAL Terminal)
Definition: console.c:271
VOID ResetTerminal(IN PCONSOLE Console)
Definition: dummyterm.c:156
Definition: typedefs.h:117
Status
Definition: gdiplustypes.h:24
static ULONG CurrentConsoleID
Definition: console.c:23
NTSTATUS NTAPI ConDrvSetConsoleCP(IN PCONSOLE Console, IN UINT CodePage, IN BOOLEAN OutputCP)
Definition: console.c:528
BOOL WINAPI IsValidCodePage(UINT CodePage)
Definition: nls.c:1479
NTSTATUS NTAPI ConDrvInitInputBuffer(IN PCONSOLE Console, IN ULONG InputBufferSize)
Definition: coninput.c:189
#define CONSOLE_TEXTMODE_BUFFER
Definition: wincon.h:59
BOOLEAN NTAPI ConDrvValidateConsoleUnsafe(IN PCONSOLE Console, IN CONSOLE_STATE ExpectedState, IN BOOLEAN LockConsole)
Definition: console.c:120
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
Definition: video.c:47
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI ConDrvGetConsoleCP(IN PCONSOLE Console, OUT PUINT CodePage, IN BOOLEAN OutputCP)
Definition: console.c:515
unsigned int UINT
Definition: ndis.h:50
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
CConsole Console
#define DPRINT1
Definition: precomp.h:8
#define ConsoleFreeHeap(HeapBase)
Definition: heap.h:15
static NTSTATUS RemoveConsole(IN PCONSOLE Console)
Definition: console.c:61
NTSTATUS NTAPI ConDrvInitConsole(OUT PCONSOLE *NewConsole, IN PCONSOLE_INFO ConsoleInfo)
Definition: console.c:163
#define OUT
Definition: typedefs.h:39
#define CONSOLE_VALID_OUTPUT_MODES
unsigned int ULONG
Definition: retypes.h:1
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
return STATUS_SUCCESS
Definition: btrfs.c:2938
signed int * PLONG
Definition: retypes.h:5
unsigned int * PUINT
Definition: ndis.h:50