[CONSRV]: Continuing code refactoring of revisions 63866, 63867, 63868 and 63874.
[reactos.git] / win32ss / user / winsrv / consrv / condrv / console.c
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 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <consrv.h>
14
15 #include <coninput.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* GLOBALS ********************************************************************/
22
23 static ULONG CurrentConsoleID = 0;
24
25 /* Linked list of consoles */
26 static LIST_ENTRY ConsoleList;
27 static RTL_RESOURCE ListLock;
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
40 InsertConsole(IN PCONSOLE Console)
41 {
42 ASSERT(Console);
43
44 /* All went right, so add the console to the list */
45 ConDrvLockConsoleListExclusive();
46
47 DPRINT1("Insert in the list\n");
48 InsertTailList(&ConsoleList, &Console->ListEntry);
49
50 // FIXME: Move this code to the caller function!!
51 /* Get a new console ID */
52 _InterlockedExchange((PLONG)&Console->ConsoleID, CurrentConsoleID);
53 _InterlockedIncrement((PLONG)&CurrentConsoleID);
54
55 /* Unlock the console list and return success */
56 ConDrvUnlockConsoleList();
57 return STATUS_SUCCESS;
58 }
59
60 static NTSTATUS
61 RemoveConsole(IN PCONSOLE Console)
62 {
63 // ASSERT(Console);
64 if (!Console) return STATUS_INVALID_PARAMETER;
65
66 /* Remove the console from the list */
67 ConDrvLockConsoleListExclusive();
68
69 RemoveEntryList(&Console->ListEntry);
70
71 /* Unlock the console list and return success */
72 ConDrvUnlockConsoleList();
73 return STATUS_SUCCESS;
74 }
75
76
77 /* PRIVATE FUNCTIONS **********************************************************/
78
79 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
80 static BOOLEAN
81 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest,
82 IN PCWSTR Source)
83 {
84 SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR);
85 if (Size > MAXUSHORT) return FALSE;
86
87 UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
88 if (UniDest->Buffer == NULL) return FALSE;
89
90 RtlCopyMemory(UniDest->Buffer, Source, Size);
91 UniDest->MaximumLength = (USHORT)Size;
92 UniDest->Length = (USHORT)Size - sizeof(WCHAR);
93
94 return TRUE;
95 }
96
97 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
98 static VOID
99 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
100 {
101 if (UnicodeString->Buffer)
102 {
103 ConsoleFreeHeap(UnicodeString->Buffer);
104 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
105 }
106 }
107
108 VOID NTAPI
109 ConDrvPause(PCONSOLE Console)
110 {
111 if (!Console->UnpauseEvent)
112 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
113 }
114
115 VOID NTAPI
116 ConDrvUnpause(PCONSOLE Console)
117 {
118 if (Console->UnpauseEvent)
119 {
120 SetEvent(Console->UnpauseEvent);
121 CloseHandle(Console->UnpauseEvent);
122 Console->UnpauseEvent = NULL;
123 }
124 }
125
126
127 /*
128 * Console accessibility check helpers
129 */
130
131 BOOLEAN NTAPI
132 ConDrvValidateConsoleState(IN PCONSOLE Console,
133 IN CONSOLE_STATE ExpectedState)
134 {
135 // if (!Console) return FALSE;
136
137 /* The console must be locked */
138 // ASSERT(Console_locked);
139
140 return (Console->State == ExpectedState);
141 }
142
143 BOOLEAN NTAPI
144 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console,
145 IN CONSOLE_STATE ExpectedState,
146 IN BOOLEAN LockConsole)
147 {
148 if (!Console) return FALSE;
149
150 /*
151 * Lock the console to forbid possible console's state changes
152 * (which must be done when the console is already locked).
153 * If we don't want to lock it, it's because the lock is already
154 * held. So there must be no problems.
155 */
156 if (LockConsole) EnterCriticalSection(&Console->Lock);
157
158 // ASSERT(Console_locked);
159
160 /* Check whether the console's state is what we expect */
161 if (!ConDrvValidateConsoleState(Console, ExpectedState))
162 {
163 if (LockConsole) LeaveCriticalSection(&Console->Lock);
164 return FALSE;
165 }
166
167 return TRUE;
168 }
169
170
171 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
172
173 VOID NTAPI
174 ConDrvInitConsoleSupport(VOID)
175 {
176 DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
177
178 /* Initialize the console list and its lock */
179 InitializeListHead(&ConsoleList);
180 RtlInitializeResource(&ListLock);
181
182 /* Should call LoadKeyboardLayout */
183 }
184
185 /* For resetting the terminal - defined in dummyterm.c */
186 VOID ResetTerminal(IN PCONSOLE Console);
187
188 NTSTATUS NTAPI
189 ConDrvInitConsole(OUT PCONSOLE* NewConsole,
190 IN PCONSOLE_INFO ConsoleInfo)
191 {
192 NTSTATUS Status;
193 SECURITY_ATTRIBUTES SecurityAttributes;
194 // CONSOLE_INFO CapturedConsoleInfo;
195 TEXTMODE_BUFFER_INFO ScreenBufferInfo;
196 PCONSOLE Console;
197 PCONSOLE_SCREEN_BUFFER NewBuffer;
198 #if 0
199 WCHAR DefaultTitle[128];
200 #endif
201
202 if (NewConsole == NULL || ConsoleInfo == NULL)
203 return STATUS_INVALID_PARAMETER;
204
205 *NewConsole = NULL;
206
207 /*
208 * Allocate a new console
209 */
210 Console = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*Console));
211 if (NULL == Console)
212 {
213 DPRINT1("Not enough memory for console creation.\n");
214 return STATUS_NO_MEMORY;
215 }
216
217 /*
218 * Fix the screen buffer size if needed. The rule is:
219 * ScreenBufferSize >= ConsoleSize
220 */
221 if (ConsoleInfo->ScreenBufferSize.X < ConsoleInfo->ConsoleSize.X)
222 ConsoleInfo->ScreenBufferSize.X = ConsoleInfo->ConsoleSize.X;
223 if (ConsoleInfo->ScreenBufferSize.Y < ConsoleInfo->ConsoleSize.Y)
224 ConsoleInfo->ScreenBufferSize.Y = ConsoleInfo->ConsoleSize.Y;
225
226 /*
227 * Initialize the console
228 */
229 Console->State = CONSOLE_INITIALIZING;
230 Console->ReferenceCount = 0;
231 InitializeCriticalSection(&Console->Lock);
232
233 /* Initialize the terminal interface */
234 ResetTerminal(Console);
235
236 Console->ConsoleSize = ConsoleInfo->ConsoleSize;
237 Console->FixedSize = FALSE; // Value by default; is reseted by the terminals if needed.
238
239 /*
240 * Initialize the input buffer
241 */
242 ConSrvInitObject(&Console->InputBuffer.Header, INPUT_BUFFER, Console);
243
244 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
245 SecurityAttributes.lpSecurityDescriptor = NULL;
246 SecurityAttributes.bInheritHandle = TRUE;
247 Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
248 if (NULL == Console->InputBuffer.ActiveEvent)
249 {
250 DeleteCriticalSection(&Console->Lock);
251 ConsoleFreeHeap(Console);
252 return STATUS_UNSUCCESSFUL;
253 }
254
255 Console->InputBuffer.InputBufferSize = 0; // FIXME!
256 InitializeListHead(&Console->InputBuffer.InputEvents);
257 Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
258 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
259
260 /* Set-up the code page */
261 Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
262
263 /* Initialize a new text-mode screen buffer with default settings */
264 ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
265 ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib;
266 ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib;
267 ScreenBufferInfo.IsCursorVisible = TRUE;
268 ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize;
269
270 InitializeListHead(&Console->BufferList);
271 Status = ConDrvCreateScreenBuffer(&NewBuffer,
272 Console,
273 CONSOLE_TEXTMODE_BUFFER,
274 &ScreenBufferInfo);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
278 CloseHandle(Console->InputBuffer.ActiveEvent);
279 DeleteCriticalSection(&Console->Lock);
280 ConsoleFreeHeap(Console);
281 return Status;
282 }
283 /* Make the new screen buffer active */
284 Console->ActiveBuffer = NewBuffer;
285 Console->UnpauseEvent = NULL;
286
287 /* Initialize the console title */
288 ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle);
289 #if 0
290 if (ConsoleInfo.ConsoleTitle[0] == L'\0')
291 {
292 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0])))
293 {
294 ConsoleCreateUnicodeString(&Console->Title, DefaultTitle);
295 }
296 else
297 {
298 ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console");
299 }
300 }
301 else
302 {
303 #endif
304 ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle);
305 #if 0
306 }
307 #endif
308
309 DPRINT("Console initialized\n");
310
311 /* All went right, so add the console to the list */
312 Status = InsertConsole(Console);
313 if (!NT_SUCCESS(Status))
314 {
315 /* Fail */
316 ConDrvDeleteConsole(Console);
317 return Status;
318 }
319
320 /* The initialization is finished */
321 DPRINT("Change state\n");
322 Console->State = CONSOLE_RUNNING;
323
324 /* Return the newly created console to the caller and a success code too */
325 *NewConsole = Console;
326 return STATUS_SUCCESS;
327 }
328
329 NTSTATUS NTAPI
330 ConDrvRegisterTerminal(IN PCONSOLE Console,
331 IN PTERMINAL Terminal)
332 {
333 NTSTATUS Status;
334
335 if (Console == NULL || Terminal == NULL)
336 return STATUS_INVALID_PARAMETER;
337
338 /* FIXME: Lock the console before ?? */
339
340 /*
341 * Attach the terminal to the console. Use now the TermIFace of the console,
342 * and not the user-defined temporary Terminal pointer.
343 */
344 Console->TermIFace = *Terminal;
345 Console->TermIFace.Console = Console;
346
347 /* Initialize the terminal AFTER having attached it to the console */
348 DPRINT("Finish initialization of terminal\n");
349 Status = Console->TermIFace.Vtbl->InitTerminal(&Console->TermIFace, Console);
350 if (!NT_SUCCESS(Status))
351 {
352 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status);
353
354 /* We failed, detach the terminal from the console */
355 Terminal->Console = NULL; // For the caller
356 ResetTerminal(Console);
357
358 return Status;
359 }
360
361 /* Copy buffer contents to screen */
362 // Terminal.Draw();
363 // ConioDrawConsole(Console);
364 DPRINT("Console drawn\n");
365
366 DPRINT("Terminal initialization done\n");
367 return STATUS_SUCCESS;
368 }
369
370 NTSTATUS NTAPI
371 ConDrvDeregisterTerminal(IN PCONSOLE Console)
372 {
373 if (Console == NULL) return STATUS_INVALID_PARAMETER;
374
375 /* FIXME: Lock the console before ?? */
376
377 /* Deinitialize the terminal BEFORE detaching it from the console */
378 Console->TermIFace.Vtbl->DeinitTerminal(&Console->TermIFace/*, Console*/);
379
380 /*
381 * Detach the terminal from the console:
382 * reinitialize the terminal interface.
383 */
384 ResetTerminal(Console);
385
386 DPRINT("Terminal unregistered\n");
387 return STATUS_SUCCESS;
388 }
389
390 VOID NTAPI
391 ConDrvDeleteConsole(IN PCONSOLE Console)
392 {
393 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console);
394
395 /*
396 * Forbid validation of any console by other threads
397 * during the deletion of this console.
398 */
399 ConDrvLockConsoleListExclusive();
400
401 /*
402 * If the console is already being destroyed, i.e. not running
403 * or finishing to be initialized, just return.
404 */
405 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE) &&
406 !ConDrvValidateConsoleUnsafe(Console, CONSOLE_INITIALIZING, TRUE))
407 {
408 /* Unlock the console list and return */
409 ConDrvUnlockConsoleList();
410 return;
411 }
412
413 /*
414 * We are about to be destroyed. Signal it to other people
415 * so that they can terminate what they are doing, and that
416 * they cannot longer validate the console.
417 */
418 Console->State = CONSOLE_TERMINATING;
419
420 /*
421 * Allow other threads to finish their job: basically, unlock
422 * all other calls to EnterCriticalSection(&Console->Lock); by
423 * ConDrvValidateConsoleUnsafe functions so that they just see
424 * that we are not in CONSOLE_RUNNING state anymore, or unlock
425 * other concurrent calls to ConDrvDeleteConsole so that they
426 * can see that we are in fact already deleting the console.
427 */
428 LeaveCriticalSection(&Console->Lock);
429 ConDrvUnlockConsoleList();
430
431 /* FIXME: Send a terminate message to all the processes owning this console */
432
433 /* Cleanup the UI-oriented part */
434 DPRINT("Deregister console\n");
435 ConDrvDeregisterTerminal(Console);
436 DPRINT("Console deregistered\n");
437
438 /***
439 * Check that the console is in terminating state before continuing
440 * (the cleanup code must not change the state of the console...
441 * ...unless to cancel console deletion ?).
442 ***/
443
444 ConDrvLockConsoleListExclusive();
445
446 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
447 {
448 ConDrvUnlockConsoleList();
449 return;
450 }
451
452 /* We are now in destruction */
453 Console->State = CONSOLE_IN_DESTRUCTION;
454
455 /* We really delete the console. Reset the count to be sure. */
456 Console->ReferenceCount = 0;
457
458 /* Remove the console from the list */
459 RemoveConsole(Console);
460
461 /* Discard all entries in the input event queue */
462 PurgeInputBuffer(Console);
463
464 /* Delete the last screen buffer */
465 ConioDeleteScreenBuffer(Console->ActiveBuffer);
466 Console->ActiveBuffer = NULL;
467 if (!IsListEmpty(&Console->BufferList))
468 {
469 DPRINT1("BUG: screen buffer list not empty\n");
470 ASSERT(FALSE);
471 }
472
473 /**/ CloseHandle(Console->InputBuffer.ActiveEvent); /**/
474 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
475
476 ConsoleFreeUnicodeString(&Console->OriginalTitle);
477 ConsoleFreeUnicodeString(&Console->Title);
478
479 DPRINT("ConDrvDeleteConsole - Unlocking\n");
480 LeaveCriticalSection(&Console->Lock);
481 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
482 DeleteCriticalSection(&Console->Lock);
483 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
484
485 ConsoleFreeHeap(Console);
486 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
487
488 /* Unlock the console list and return */
489 ConDrvUnlockConsoleList();
490 }
491
492
493 /* PUBLIC DRIVER APIS *********************************************************/
494
495 NTSTATUS NTAPI
496 ConDrvGetConsoleMode(IN PCONSOLE Console,
497 IN PCONSOLE_IO_OBJECT Object,
498 OUT PULONG ConsoleMode)
499 {
500 NTSTATUS Status = STATUS_SUCCESS;
501
502 if (Console == NULL || Object == NULL || ConsoleMode == NULL)
503 return STATUS_INVALID_PARAMETER;
504
505 /* Validity check */
506 ASSERT(Console == Object->Console);
507
508 /*** FIXME: */ *ConsoleMode = 0; /***/
509
510 if (INPUT_BUFFER == Object->Type)
511 {
512 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
513 *ConsoleMode = InputBuffer->Mode;
514 }
515 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
516 {
517 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
518 *ConsoleMode = Buffer->Mode;
519 }
520 else
521 {
522 Status = STATUS_INVALID_HANDLE;
523 }
524
525 return Status;
526 }
527
528 NTSTATUS NTAPI
529 ConDrvSetConsoleMode(IN PCONSOLE Console,
530 IN PCONSOLE_IO_OBJECT Object,
531 IN ULONG ConsoleMode)
532 {
533 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
534 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
535 ENABLE_MOUSE_INPUT )
536 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
537
538 NTSTATUS Status = STATUS_SUCCESS;
539
540 if (Console == NULL || Object == NULL)
541 return STATUS_INVALID_PARAMETER;
542
543 /* Validity check */
544 ASSERT(Console == Object->Console);
545
546 if (INPUT_BUFFER == Object->Type)
547 {
548 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
549
550 /* Only the presence of valid mode flags is allowed */
551 if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES)
552 {
553 Status = STATUS_INVALID_PARAMETER;
554 }
555 else
556 {
557 InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
558 }
559 }
560 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
561 {
562 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
563
564 /* Only the presence of valid mode flags is allowed */
565 if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
566 {
567 Status = STATUS_INVALID_PARAMETER;
568 }
569 else
570 {
571 Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
572 }
573 }
574 else
575 {
576 Status = STATUS_INVALID_HANDLE;
577 }
578
579 return Status;
580 }
581
582 NTSTATUS NTAPI
583 ConDrvGetConsoleTitle(IN PCONSOLE Console,
584 IN BOOLEAN Unicode,
585 IN OUT PVOID TitleBuffer,
586 IN OUT PULONG BufLength)
587 {
588 ULONG Length;
589
590 if (Console == NULL || TitleBuffer == NULL || BufLength == NULL)
591 return STATUS_INVALID_PARAMETER;
592
593 /* Copy title of the console to the user title buffer */
594 if (Unicode)
595 {
596 if (*BufLength >= sizeof(WCHAR))
597 {
598 Length = min(*BufLength - sizeof(WCHAR), Console->Title.Length);
599 RtlCopyMemory(TitleBuffer, Console->Title.Buffer, Length);
600 ((PWCHAR)TitleBuffer)[Length / sizeof(WCHAR)] = L'\0';
601 *BufLength = Length;
602 }
603 else
604 {
605 *BufLength = Console->Title.Length;
606 }
607 }
608 else
609 {
610 if (*BufLength >= sizeof(CHAR))
611 {
612 Length = min(*BufLength - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
613 Length = WideCharToMultiByte(Console->InputCodePage, 0,
614 Console->Title.Buffer, Length,
615 TitleBuffer, Length,
616 NULL, NULL);
617 ((PCHAR)TitleBuffer)[Length] = '\0';
618 *BufLength = Length;
619 }
620 else
621 {
622 *BufLength = Console->Title.Length / sizeof(WCHAR);
623 }
624 }
625
626 return STATUS_SUCCESS;
627 }
628
629 NTSTATUS NTAPI
630 ConDrvSetConsoleTitle(IN PCONSOLE Console,
631 IN BOOLEAN Unicode,
632 IN PVOID TitleBuffer,
633 IN ULONG BufLength)
634 {
635 PWCHAR Buffer;
636 ULONG Length;
637
638 if (Console == NULL || TitleBuffer == NULL)
639 return STATUS_INVALID_PARAMETER;
640
641 if (Unicode)
642 {
643 /* Length is in bytes */
644 Length = BufLength;
645 }
646 else
647 {
648 /* Use the console input CP for the conversion */
649 Length = MultiByteToWideChar(Console->InputCodePage, 0,
650 TitleBuffer, BufLength,
651 NULL, 0);
652 /* The returned Length was in number of wchars, convert it in bytes */
653 Length *= sizeof(WCHAR);
654 }
655
656 /* Allocate a new buffer to hold the new title (NULL-terminated) */
657 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
658 if (!Buffer) return STATUS_NO_MEMORY;
659
660 /* Free the old title */
661 ConsoleFreeUnicodeString(&Console->Title);
662
663 /* Copy title to console */
664 Console->Title.Buffer = Buffer;
665 Console->Title.Length = Length;
666 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
667
668 if (Unicode)
669 {
670 RtlCopyMemory(Console->Title.Buffer, TitleBuffer, Console->Title.Length);
671 }
672 else
673 {
674 MultiByteToWideChar(Console->InputCodePage, 0,
675 TitleBuffer, BufLength,
676 Console->Title.Buffer,
677 Console->Title.Length / sizeof(WCHAR));
678 }
679
680 /* NULL-terminate */
681 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
682
683 // TermChangeTitle(Console);
684 return STATUS_SUCCESS;
685 }
686
687 NTSTATUS NTAPI
688 ConDrvGetConsoleCP(IN PCONSOLE Console,
689 OUT PUINT CodePage,
690 IN BOOLEAN OutputCP)
691 {
692 if (Console == NULL || CodePage == NULL)
693 return STATUS_INVALID_PARAMETER;
694
695 *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage);
696
697 return STATUS_SUCCESS;
698 }
699
700 NTSTATUS NTAPI
701 ConDrvSetConsoleCP(IN PCONSOLE Console,
702 IN UINT CodePage,
703 IN BOOLEAN OutputCP)
704 {
705 if (Console == NULL || !IsValidCodePage(CodePage))
706 return STATUS_INVALID_PARAMETER;
707
708 if (OutputCP)
709 Console->OutputCodePage = CodePage;
710 else
711 Console->InputCodePage = CodePage;
712
713 return STATUS_SUCCESS;
714 }
715
716 /* EOF */