[CONSRV]
[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 if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer);
464
465 /* Delete the last screen buffer */
466 ConioDeleteScreenBuffer(Console->ActiveBuffer);
467 Console->ActiveBuffer = NULL;
468 if (!IsListEmpty(&Console->BufferList))
469 {
470 DPRINT1("BUG: screen buffer list not empty\n");
471 ASSERT(FALSE);
472 }
473
474 /**/ CloseHandle(Console->InputBuffer.ActiveEvent); /**/
475 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
476
477 ConsoleFreeUnicodeString(&Console->OriginalTitle);
478 ConsoleFreeUnicodeString(&Console->Title);
479
480 DPRINT("ConDrvDeleteConsole - Unlocking\n");
481 LeaveCriticalSection(&Console->Lock);
482 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
483 DeleteCriticalSection(&Console->Lock);
484 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
485
486 ConsoleFreeHeap(Console);
487 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
488
489 /* Unlock the console list and return */
490 ConDrvUnlockConsoleList();
491 }
492
493
494 /* PUBLIC DRIVER APIS *********************************************************/
495
496 NTSTATUS NTAPI
497 ConDrvGetConsoleMode(IN PCONSOLE Console,
498 IN PCONSOLE_IO_OBJECT Object,
499 OUT PULONG ConsoleMode)
500 {
501 NTSTATUS Status = STATUS_SUCCESS;
502
503 if (Console == NULL || Object == NULL || ConsoleMode == NULL)
504 return STATUS_INVALID_PARAMETER;
505
506 /* Validity check */
507 ASSERT(Console == Object->Console);
508
509 /*** FIXME: */ *ConsoleMode = 0; /***/
510
511 if (INPUT_BUFFER == Object->Type)
512 {
513 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
514 *ConsoleMode = InputBuffer->Mode;
515 }
516 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
517 {
518 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
519 *ConsoleMode = Buffer->Mode;
520 }
521 else
522 {
523 Status = STATUS_INVALID_HANDLE;
524 }
525
526 return Status;
527 }
528
529 NTSTATUS NTAPI
530 ConDrvSetConsoleMode(IN PCONSOLE Console,
531 IN PCONSOLE_IO_OBJECT Object,
532 IN ULONG ConsoleMode)
533 {
534 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
535 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
536 ENABLE_MOUSE_INPUT )
537 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
538
539 NTSTATUS Status = STATUS_SUCCESS;
540
541 if (Console == NULL || Object == NULL)
542 return STATUS_INVALID_PARAMETER;
543
544 /* Validity check */
545 ASSERT(Console == Object->Console);
546
547 if (INPUT_BUFFER == Object->Type)
548 {
549 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
550
551 /* Only the presence of valid mode flags is allowed */
552 if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES)
553 {
554 Status = STATUS_INVALID_PARAMETER;
555 }
556 else
557 {
558 InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
559 }
560 }
561 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
562 {
563 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
564
565 /* Only the presence of valid mode flags is allowed */
566 if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
567 {
568 Status = STATUS_INVALID_PARAMETER;
569 }
570 else
571 {
572 Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
573 }
574 }
575 else
576 {
577 Status = STATUS_INVALID_HANDLE;
578 }
579
580 return Status;
581 }
582
583 NTSTATUS NTAPI
584 ConDrvGetConsoleTitle(IN PCONSOLE Console,
585 IN BOOLEAN Unicode,
586 IN OUT PVOID TitleBuffer,
587 IN OUT PULONG BufLength)
588 {
589 ULONG Length;
590
591 if (Console == NULL || TitleBuffer == NULL || BufLength == NULL)
592 return STATUS_INVALID_PARAMETER;
593
594 /* Copy title of the console to the user title buffer */
595 if (Unicode)
596 {
597 if (*BufLength >= sizeof(WCHAR))
598 {
599 Length = min(*BufLength - sizeof(WCHAR), Console->Title.Length);
600 RtlCopyMemory(TitleBuffer, Console->Title.Buffer, Length);
601 ((PWCHAR)TitleBuffer)[Length / sizeof(WCHAR)] = L'\0';
602 *BufLength = Length;
603 }
604 else
605 {
606 *BufLength = Console->Title.Length;
607 }
608 }
609 else
610 {
611 if (*BufLength >= sizeof(CHAR))
612 {
613 Length = min(*BufLength - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
614 Length = WideCharToMultiByte(Console->InputCodePage, 0,
615 Console->Title.Buffer, Length,
616 TitleBuffer, Length,
617 NULL, NULL);
618 ((PCHAR)TitleBuffer)[Length] = '\0';
619 *BufLength = Length;
620 }
621 else
622 {
623 *BufLength = Console->Title.Length / sizeof(WCHAR);
624 }
625 }
626
627 return STATUS_SUCCESS;
628 }
629
630 NTSTATUS NTAPI
631 ConDrvSetConsoleTitle(IN PCONSOLE Console,
632 IN BOOLEAN Unicode,
633 IN PVOID TitleBuffer,
634 IN ULONG BufLength)
635 {
636 PWCHAR Buffer;
637 ULONG Length;
638
639 if (Console == NULL || TitleBuffer == NULL)
640 return STATUS_INVALID_PARAMETER;
641
642 if (Unicode)
643 {
644 /* Length is in bytes */
645 Length = BufLength;
646 }
647 else
648 {
649 /* Use the console input CP for the conversion */
650 Length = MultiByteToWideChar(Console->InputCodePage, 0,
651 TitleBuffer, BufLength,
652 NULL, 0);
653 /* The returned Length was in number of wchars, convert it in bytes */
654 Length *= sizeof(WCHAR);
655 }
656
657 /* Allocate a new buffer to hold the new title (NULL-terminated) */
658 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
659 if (!Buffer) return STATUS_NO_MEMORY;
660
661 /* Free the old title */
662 ConsoleFreeUnicodeString(&Console->Title);
663
664 /* Copy title to console */
665 Console->Title.Buffer = Buffer;
666 Console->Title.Length = Length;
667 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
668
669 if (Unicode)
670 {
671 RtlCopyMemory(Console->Title.Buffer, TitleBuffer, Console->Title.Length);
672 }
673 else
674 {
675 MultiByteToWideChar(Console->InputCodePage, 0,
676 TitleBuffer, BufLength,
677 Console->Title.Buffer,
678 Console->Title.Length / sizeof(WCHAR));
679 }
680
681 /* NULL-terminate */
682 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
683
684 // TermChangeTitle(Console);
685 return STATUS_SUCCESS;
686 }
687
688 NTSTATUS NTAPI
689 ConDrvGetConsoleCP(IN PCONSOLE Console,
690 OUT PUINT CodePage,
691 IN BOOLEAN OutputCP)
692 {
693 if (Console == NULL || CodePage == NULL)
694 return STATUS_INVALID_PARAMETER;
695
696 *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage);
697
698 return STATUS_SUCCESS;
699 }
700
701 NTSTATUS NTAPI
702 ConDrvSetConsoleCP(IN PCONSOLE Console,
703 IN UINT CodePage,
704 IN BOOLEAN OutputCP)
705 {
706 if (Console == NULL || !IsValidCodePage(CodePage))
707 return STATUS_INVALID_PARAMETER;
708
709 if (OutputCP)
710 Console->OutputCodePage = CodePage;
711 else
712 Console->InputCodePage = CodePage;
713
714 return STATUS_SUCCESS;
715 }
716
717 /* EOF */