4f60730212b55b48ceeb77e0a89340b0ef9b53b0
[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 Console->InsertMode = ConsoleInfo->InsertMode;
261 Console->LineBuffer = NULL;
262 Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
263 Console->LineComplete = Console->LineUpPressed = FALSE;
264 Console->LineInsertToggle = Console->InsertMode;
265 // LineWakeupMask
266
267 /* Set-up the code page */
268 Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
269
270 /* Initialize a new text-mode screen buffer with default settings */
271 ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
272 ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib;
273 ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib;
274 ScreenBufferInfo.IsCursorVisible = TRUE;
275 ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize;
276
277 InitializeListHead(&Console->BufferList);
278 Status = ConDrvCreateScreenBuffer(&NewBuffer,
279 Console,
280 CONSOLE_TEXTMODE_BUFFER,
281 &ScreenBufferInfo);
282 if (!NT_SUCCESS(Status))
283 {
284 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
285 CloseHandle(Console->InputBuffer.ActiveEvent);
286 DeleteCriticalSection(&Console->Lock);
287 ConsoleFreeHeap(Console);
288 return Status;
289 }
290 /* Make the new screen buffer active */
291 Console->ActiveBuffer = NewBuffer;
292 Console->UnpauseEvent = NULL;
293
294 /* Initialize the console title */
295 ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle);
296 #if 0
297 if (ConsoleInfo.ConsoleTitle[0] == L'\0')
298 {
299 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0])))
300 {
301 ConsoleCreateUnicodeString(&Console->Title, DefaultTitle);
302 }
303 else
304 {
305 ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console");
306 }
307 }
308 else
309 {
310 #endif
311 ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle);
312 #if 0
313 }
314 #endif
315
316 DPRINT("Console initialized\n");
317
318 /* All went right, so add the console to the list */
319 Status = InsertConsole(Console);
320 if (!NT_SUCCESS(Status))
321 {
322 /* Fail */
323 ConDrvDeleteConsole(Console);
324 return Status;
325 }
326
327 /* The initialization is finished */
328 DPRINT("Change state\n");
329 Console->State = CONSOLE_RUNNING;
330
331 /* Return the newly created console to the caller and a success code too */
332 *NewConsole = Console;
333 return STATUS_SUCCESS;
334 }
335
336 NTSTATUS NTAPI
337 ConDrvRegisterTerminal(IN PCONSOLE Console,
338 IN PTERMINAL Terminal)
339 {
340 NTSTATUS Status;
341
342 if (Console == NULL || Terminal == NULL)
343 return STATUS_INVALID_PARAMETER;
344
345 /* FIXME: Lock the console before ?? */
346
347 /*
348 * Attach the terminal to the console. Use now the TermIFace of the console,
349 * and not the user-defined temporary Terminal pointer.
350 */
351 Console->TermIFace = *Terminal;
352 Console->TermIFace.Console = Console;
353
354 /* Initialize the terminal AFTER having attached it to the console */
355 DPRINT("Finish initialization of terminal\n");
356 Status = Console->TermIFace.Vtbl->InitTerminal(&Console->TermIFace, Console);
357 if (!NT_SUCCESS(Status))
358 {
359 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status);
360
361 /* We failed, detach the terminal from the console */
362 Terminal->Console = NULL; // For the caller
363 ResetTerminal(Console);
364
365 return Status;
366 }
367
368 /* Copy buffer contents to screen */
369 // Terminal.Draw();
370 // ConioDrawConsole(Console);
371 DPRINT("Console drawn\n");
372
373 DPRINT("Terminal initialization done\n");
374 return STATUS_SUCCESS;
375 }
376
377 NTSTATUS NTAPI
378 ConDrvDeregisterTerminal(IN PCONSOLE Console)
379 {
380 if (Console == NULL) return STATUS_INVALID_PARAMETER;
381
382 /* FIXME: Lock the console before ?? */
383
384 /* Deinitialize the terminal BEFORE detaching it from the console */
385 Console->TermIFace.Vtbl->DeinitTerminal(&Console->TermIFace/*, Console*/);
386
387 /*
388 * Detach the terminal from the console:
389 * reinitialize the terminal interface.
390 */
391 ResetTerminal(Console);
392
393 DPRINT("Terminal unregistered\n");
394 return STATUS_SUCCESS;
395 }
396
397 VOID NTAPI
398 ConDrvDeleteConsole(IN PCONSOLE Console)
399 {
400 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console);
401
402 /*
403 * Forbid validation of any console by other threads
404 * during the deletion of this console.
405 */
406 ConDrvLockConsoleListExclusive();
407
408 /*
409 * If the console is already being destroyed, i.e. not running
410 * or finishing to be initialized, just return.
411 */
412 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE) &&
413 !ConDrvValidateConsoleUnsafe(Console, CONSOLE_INITIALIZING, TRUE))
414 {
415 /* Unlock the console list and return */
416 ConDrvUnlockConsoleList();
417 return;
418 }
419
420 /*
421 * We are about to be destroyed. Signal it to other people
422 * so that they can terminate what they are doing, and that
423 * they cannot longer validate the console.
424 */
425 Console->State = CONSOLE_TERMINATING;
426
427 /*
428 * Allow other threads to finish their job: basically, unlock
429 * all other calls to EnterCriticalSection(&Console->Lock); by
430 * ConDrvValidateConsoleUnsafe functions so that they just see
431 * that we are not in CONSOLE_RUNNING state anymore, or unlock
432 * other concurrent calls to ConDrvDeleteConsole so that they
433 * can see that we are in fact already deleting the console.
434 */
435 LeaveCriticalSection(&Console->Lock);
436 ConDrvUnlockConsoleList();
437
438 /* FIXME: Send a terminate message to all the processes owning this console */
439
440 /* Cleanup the UI-oriented part */
441 DPRINT("Deregister console\n");
442 ConDrvDeregisterTerminal(Console);
443 DPRINT("Console deregistered\n");
444
445 /***
446 * Check that the console is in terminating state before continuing
447 * (the cleanup code must not change the state of the console...
448 * ...unless to cancel console deletion ?).
449 ***/
450
451 ConDrvLockConsoleListExclusive();
452
453 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
454 {
455 ConDrvUnlockConsoleList();
456 return;
457 }
458
459 /* We are now in destruction */
460 Console->State = CONSOLE_IN_DESTRUCTION;
461
462 /* We really delete the console. Reset the count to be sure. */
463 Console->ReferenceCount = 0;
464
465 /* Remove the console from the list */
466 RemoveConsole(Console);
467
468 /* Discard all entries in the input event queue */
469 PurgeInputBuffer(Console);
470 if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer);
471
472 /* Delete the last screen buffer */
473 ConioDeleteScreenBuffer(Console->ActiveBuffer);
474 Console->ActiveBuffer = NULL;
475 if (!IsListEmpty(&Console->BufferList))
476 {
477 DPRINT1("BUG: screen buffer list not empty\n");
478 ASSERT(FALSE);
479 }
480
481 /**/ CloseHandle(Console->InputBuffer.ActiveEvent); /**/
482 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
483
484 ConsoleFreeUnicodeString(&Console->OriginalTitle);
485 ConsoleFreeUnicodeString(&Console->Title);
486
487 DPRINT("ConDrvDeleteConsole - Unlocking\n");
488 LeaveCriticalSection(&Console->Lock);
489 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
490 DeleteCriticalSection(&Console->Lock);
491 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
492
493 ConsoleFreeHeap(Console);
494 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
495
496 /* Unlock the console list and return */
497 ConDrvUnlockConsoleList();
498 }
499
500
501 /* PUBLIC DRIVER APIS *********************************************************/
502
503 NTSTATUS NTAPI
504 ConDrvGetConsoleMode(IN PCONSOLE Console,
505 IN PCONSOLE_IO_OBJECT Object,
506 OUT PULONG ConsoleMode)
507 {
508 NTSTATUS Status = STATUS_SUCCESS;
509
510 if (Console == NULL || Object == NULL || ConsoleMode == NULL)
511 return STATUS_INVALID_PARAMETER;
512
513 /* Validity check */
514 ASSERT(Console == Object->Console);
515
516 /*** FIXME: */ *ConsoleMode = 0; /***/
517
518 if (INPUT_BUFFER == Object->Type)
519 {
520 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
521
522 *ConsoleMode = InputBuffer->Mode;
523
524 if (Console->QuickEdit || Console->InsertMode)
525 {
526 // Windows does this, even if it's not documented on MSDN
527 *ConsoleMode |= ENABLE_EXTENDED_FLAGS;
528
529 if (Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
530 if (Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
531 }
532 }
533 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
534 {
535 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
536 *ConsoleMode = Buffer->Mode;
537 }
538 else
539 {
540 Status = STATUS_INVALID_HANDLE;
541 }
542
543 return Status;
544 }
545
546 NTSTATUS NTAPI
547 ConDrvSetConsoleMode(IN PCONSOLE Console,
548 IN PCONSOLE_IO_OBJECT Object,
549 IN ULONG ConsoleMode)
550 {
551 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
552 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
553 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
554 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
555 ENABLE_MOUSE_INPUT )
556 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
557
558 NTSTATUS Status = STATUS_SUCCESS;
559
560 if (Console == NULL || Object == NULL)
561 return STATUS_INVALID_PARAMETER;
562
563 /* Validity check */
564 ASSERT(Console == Object->Console);
565
566 if (INPUT_BUFFER == Object->Type)
567 {
568 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
569
570 DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode);
571
572 /*
573 * 1. Only the presence of valid mode flags is allowed.
574 */
575 if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES))
576 {
577 Status = STATUS_INVALID_PARAMETER;
578 goto Quit;
579 }
580
581 /*
582 * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
583 * then consider the flags invalid.
584 *
585 if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
586 (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
587 {
588 Status = STATUS_INVALID_PARAMETER;
589 goto Quit;
590 }
591 */
592
593 /*
594 * 3. Now we can continue.
595 */
596 if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
597 {
598 Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
599 Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
600 }
601 InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
602 }
603 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
604 {
605 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
606
607 DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode);
608
609 if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
610 {
611 Status = STATUS_INVALID_PARAMETER;
612 }
613 else
614 {
615 Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
616 }
617 }
618 else
619 {
620 Status = STATUS_INVALID_HANDLE;
621 }
622
623 Quit:
624 return Status;
625 }
626
627 NTSTATUS NTAPI
628 ConDrvGetConsoleTitle(IN PCONSOLE Console,
629 IN BOOLEAN Unicode,
630 IN OUT PVOID TitleBuffer,
631 IN OUT PULONG BufLength)
632 {
633 ULONG Length;
634
635 if (Console == NULL || TitleBuffer == NULL || BufLength == NULL)
636 return STATUS_INVALID_PARAMETER;
637
638 /* Copy title of the console to the user title buffer */
639 if (Unicode)
640 {
641 if (*BufLength >= sizeof(WCHAR))
642 {
643 Length = min(*BufLength - sizeof(WCHAR), Console->Title.Length);
644 RtlCopyMemory(TitleBuffer, Console->Title.Buffer, Length);
645 ((PWCHAR)TitleBuffer)[Length / sizeof(WCHAR)] = L'\0';
646 *BufLength = Length;
647 }
648 else
649 {
650 *BufLength = Console->Title.Length;
651 }
652 }
653 else
654 {
655 if (*BufLength >= sizeof(CHAR))
656 {
657 Length = min(*BufLength - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
658 Length = WideCharToMultiByte(Console->InputCodePage, 0,
659 Console->Title.Buffer, Length,
660 TitleBuffer, Length,
661 NULL, NULL);
662 ((PCHAR)TitleBuffer)[Length] = '\0';
663 *BufLength = Length;
664 }
665 else
666 {
667 *BufLength = Console->Title.Length / sizeof(WCHAR);
668 }
669 }
670
671 return STATUS_SUCCESS;
672 }
673
674 NTSTATUS NTAPI
675 ConDrvSetConsoleTitle(IN PCONSOLE Console,
676 IN BOOLEAN Unicode,
677 IN PVOID TitleBuffer,
678 IN ULONG BufLength)
679 {
680 PWCHAR Buffer;
681 ULONG Length;
682
683 if (Console == NULL || TitleBuffer == NULL)
684 return STATUS_INVALID_PARAMETER;
685
686 if (Unicode)
687 {
688 /* Length is in bytes */
689 Length = BufLength;
690 }
691 else
692 {
693 /* Use the console input CP for the conversion */
694 Length = MultiByteToWideChar(Console->InputCodePage, 0,
695 TitleBuffer, BufLength,
696 NULL, 0);
697 /* The returned Length was in number of wchars, convert it in bytes */
698 Length *= sizeof(WCHAR);
699 }
700
701 /* Allocate a new buffer to hold the new title (NULL-terminated) */
702 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
703 if (!Buffer) return STATUS_NO_MEMORY;
704
705 /* Free the old title */
706 ConsoleFreeUnicodeString(&Console->Title);
707
708 /* Copy title to console */
709 Console->Title.Buffer = Buffer;
710 Console->Title.Length = Length;
711 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
712
713 if (Unicode)
714 {
715 RtlCopyMemory(Console->Title.Buffer, TitleBuffer, Console->Title.Length);
716 }
717 else
718 {
719 MultiByteToWideChar(Console->InputCodePage, 0,
720 TitleBuffer, BufLength,
721 Console->Title.Buffer,
722 Console->Title.Length / sizeof(WCHAR));
723 }
724
725 /* NULL-terminate */
726 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
727
728 // TermChangeTitle(Console);
729 return STATUS_SUCCESS;
730 }
731
732 NTSTATUS NTAPI
733 ConDrvGetConsoleCP(IN PCONSOLE Console,
734 OUT PUINT CodePage,
735 IN BOOLEAN OutputCP)
736 {
737 if (Console == NULL || CodePage == NULL)
738 return STATUS_INVALID_PARAMETER;
739
740 *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage);
741
742 return STATUS_SUCCESS;
743 }
744
745 NTSTATUS NTAPI
746 ConDrvSetConsoleCP(IN PCONSOLE Console,
747 IN UINT CodePage,
748 IN BOOLEAN OutputCP)
749 {
750 if (Console == NULL || !IsValidCodePage(CodePage))
751 return STATUS_INVALID_PARAMETER;
752
753 if (OutputCP)
754 Console->OutputCodePage = CodePage;
755 else
756 Console->InputCodePage = CodePage;
757
758 return STATUS_SUCCESS;
759 }
760
761 /* EOF */