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
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
21 /* GLOBALS ********************************************************************/
23 static ULONG CurrentConsoleID
= 0;
25 /* Linked list of consoles */
26 static LIST_ENTRY ConsoleList
;
27 static RTL_RESOURCE ListLock
;
29 #define ConDrvLockConsoleListExclusive() \
30 RtlAcquireResourceExclusive(&ListLock, TRUE)
32 #define ConDrvLockConsoleListShared() \
33 RtlAcquireResourceShared(&ListLock, TRUE)
35 #define ConDrvUnlockConsoleList() \
36 RtlReleaseResource(&ListLock)
40 InsertConsole(IN PCONSOLE Console
)
44 /* All went right, so add the console to the list */
45 ConDrvLockConsoleListExclusive();
47 DPRINT1("Insert in the list\n");
48 InsertTailList(&ConsoleList
, &Console
->ListEntry
);
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
);
55 /* Unlock the console list and return success */
56 ConDrvUnlockConsoleList();
57 return STATUS_SUCCESS
;
61 RemoveConsole(IN PCONSOLE Console
)
64 if (!Console
) return STATUS_INVALID_PARAMETER
;
66 /* Remove the console from the list */
67 ConDrvLockConsoleListExclusive();
69 RemoveEntryList(&Console
->ListEntry
);
71 /* Unlock the console list and return success */
72 ConDrvUnlockConsoleList();
73 return STATUS_SUCCESS
;
77 /* PRIVATE FUNCTIONS **********************************************************/
79 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
81 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest
,
84 SIZE_T Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
85 if (Size
> MAXUSHORT
) return FALSE
;
87 UniDest
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
);
88 if (UniDest
->Buffer
== NULL
) return FALSE
;
90 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
91 UniDest
->MaximumLength
= (USHORT
)Size
;
92 UniDest
->Length
= (USHORT
)Size
- sizeof(WCHAR
);
97 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
99 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
101 if (UnicodeString
->Buffer
)
103 ConsoleFreeHeap(UnicodeString
->Buffer
);
104 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
109 ConDrvPause(PCONSOLE Console
)
111 if (!Console
->UnpauseEvent
)
112 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
116 ConDrvUnpause(PCONSOLE Console
)
118 if (Console
->UnpauseEvent
)
120 SetEvent(Console
->UnpauseEvent
);
121 CloseHandle(Console
->UnpauseEvent
);
122 Console
->UnpauseEvent
= NULL
;
128 * Console accessibility check helpers
132 ConDrvValidateConsoleState(IN PCONSOLE Console
,
133 IN CONSOLE_STATE ExpectedState
)
135 // if (!Console) return FALSE;
137 /* The console must be locked */
138 // ASSERT(Console_locked);
140 return (Console
->State
== ExpectedState
);
144 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console
,
145 IN CONSOLE_STATE ExpectedState
,
146 IN BOOLEAN LockConsole
)
148 if (!Console
) return FALSE
;
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.
156 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
158 // ASSERT(Console_locked);
160 /* Check whether the console's state is what we expect */
161 if (!ConDrvValidateConsoleState(Console
, ExpectedState
))
163 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
171 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
174 ConDrvInitConsoleSupport(VOID
)
176 DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
178 /* Initialize the console list and its lock */
179 InitializeListHead(&ConsoleList
);
180 RtlInitializeResource(&ListLock
);
182 /* Should call LoadKeyboardLayout */
185 /* For resetting the terminal - defined in dummyterm.c */
186 VOID
ResetTerminal(IN PCONSOLE Console
);
189 ConDrvInitConsole(OUT PCONSOLE
* NewConsole
,
190 IN PCONSOLE_INFO ConsoleInfo
)
193 SECURITY_ATTRIBUTES SecurityAttributes
;
194 // CONSOLE_INFO CapturedConsoleInfo;
195 TEXTMODE_BUFFER_INFO ScreenBufferInfo
;
197 PCONSOLE_SCREEN_BUFFER NewBuffer
;
199 WCHAR DefaultTitle
[128];
202 if (NewConsole
== NULL
|| ConsoleInfo
== NULL
)
203 return STATUS_INVALID_PARAMETER
;
208 * Allocate a new console
210 Console
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(*Console
));
213 DPRINT1("Not enough memory for console creation.\n");
214 return STATUS_NO_MEMORY
;
218 * Fix the screen buffer size if needed. The rule is:
219 * ScreenBufferSize >= ConsoleSize
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
;
227 * Initialize the console
229 Console
->State
= CONSOLE_INITIALIZING
;
230 Console
->ReferenceCount
= 0;
231 InitializeCriticalSection(&Console
->Lock
);
233 /* Initialize the terminal interface */
234 ResetTerminal(Console
);
236 memcpy(Console
->Colors
, ConsoleInfo
->Colors
, sizeof(ConsoleInfo
->Colors
));
237 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
238 Console
->FixedSize
= FALSE
; // Value by default; is reseted by the terminals if needed.
241 * Initialize the input buffer
243 ConSrvInitObject(&Console
->InputBuffer
.Header
, INPUT_BUFFER
, Console
);
245 SecurityAttributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
246 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
247 SecurityAttributes
.bInheritHandle
= TRUE
;
248 Console
->InputBuffer
.ActiveEvent
= CreateEventW(&SecurityAttributes
, TRUE
, FALSE
, NULL
);
249 if (NULL
== Console
->InputBuffer
.ActiveEvent
)
251 DeleteCriticalSection(&Console
->Lock
);
252 ConsoleFreeHeap(Console
);
253 return STATUS_UNSUCCESSFUL
;
256 Console
->InputBuffer
.InputBufferSize
= 0; // FIXME!
257 InitializeListHead(&Console
->InputBuffer
.InputEvents
);
258 Console
->InputBuffer
.Mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
259 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
261 Console
->InsertMode
= ConsoleInfo
->InsertMode
;
262 Console
->LineBuffer
= NULL
;
263 Console
->LineMaxSize
= Console
->LineSize
= Console
->LinePos
= 0;
264 Console
->LineComplete
= Console
->LineUpPressed
= FALSE
;
265 Console
->LineInsertToggle
= Console
->InsertMode
;
268 /* Set-up the code page */
269 Console
->InputCodePage
= Console
->OutputCodePage
= ConsoleInfo
->CodePage
;
271 /* Initialize a new text-mode screen buffer with default settings */
272 ScreenBufferInfo
.ScreenBufferSize
= ConsoleInfo
->ScreenBufferSize
;
273 ScreenBufferInfo
.ScreenAttrib
= ConsoleInfo
->ScreenAttrib
;
274 ScreenBufferInfo
.PopupAttrib
= ConsoleInfo
->PopupAttrib
;
275 ScreenBufferInfo
.IsCursorVisible
= TRUE
;
276 ScreenBufferInfo
.CursorSize
= ConsoleInfo
->CursorSize
;
278 InitializeListHead(&Console
->BufferList
);
279 Status
= ConDrvCreateScreenBuffer(&NewBuffer
,
281 CONSOLE_TEXTMODE_BUFFER
,
283 if (!NT_SUCCESS(Status
))
285 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
286 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
287 DeleteCriticalSection(&Console
->Lock
);
288 ConsoleFreeHeap(Console
);
291 /* Make the new screen buffer active */
292 Console
->ActiveBuffer
= NewBuffer
;
293 Console
->UnpauseEvent
= NULL
;
295 /* Initialize the console title */
296 ConsoleCreateUnicodeString(&Console
->OriginalTitle
, ConsoleInfo
->ConsoleTitle
);
298 if (ConsoleInfo
.ConsoleTitle
[0] == L
'\0')
300 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, DefaultTitle
, sizeof(DefaultTitle
) / sizeof(DefaultTitle
[0])))
302 ConsoleCreateUnicodeString(&Console
->Title
, DefaultTitle
);
306 ConsoleCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
312 ConsoleCreateUnicodeString(&Console
->Title
, ConsoleInfo
->ConsoleTitle
);
317 DPRINT("Console initialized\n");
319 /* All went right, so add the console to the list */
320 Status
= InsertConsole(Console
);
321 if (!NT_SUCCESS(Status
))
324 ConDrvDeleteConsole(Console
);
328 /* The initialization is finished */
329 DPRINT("Change state\n");
330 Console
->State
= CONSOLE_RUNNING
;
332 /* Return the newly created console to the caller and a success code too */
333 *NewConsole
= Console
;
334 return STATUS_SUCCESS
;
338 ConDrvRegisterTerminal(IN PCONSOLE Console
,
339 IN PTERMINAL Terminal
)
343 if (Console
== NULL
|| Terminal
== NULL
)
344 return STATUS_INVALID_PARAMETER
;
346 /* FIXME: Lock the console before ?? */
349 * Attach the terminal to the console. Use now the TermIFace of the console,
350 * and not the user-defined temporary Terminal pointer.
352 Console
->TermIFace
= *Terminal
;
353 Console
->TermIFace
.Console
= Console
;
355 /* Initialize the terminal AFTER having attached it to the console */
356 DPRINT("Finish initialization of terminal\n");
357 Status
= Console
->TermIFace
.Vtbl
->InitTerminal(&Console
->TermIFace
, Console
);
358 if (!NT_SUCCESS(Status
))
360 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status
);
362 /* We failed, detach the terminal from the console */
363 Terminal
->Console
= NULL
; // For the caller
364 ResetTerminal(Console
);
369 /* Copy buffer contents to screen */
371 // ConioDrawConsole(Console);
372 DPRINT("Console drawn\n");
374 DPRINT("Terminal initialization done\n");
375 return STATUS_SUCCESS
;
379 ConDrvDeregisterTerminal(IN PCONSOLE Console
)
381 if (Console
== NULL
) return STATUS_INVALID_PARAMETER
;
383 /* FIXME: Lock the console before ?? */
385 /* Deinitialize the terminal BEFORE detaching it from the console */
386 Console
->TermIFace
.Vtbl
->DeinitTerminal(&Console
->TermIFace
/*, Console*/);
389 * Detach the terminal from the console:
390 * reinitialize the terminal interface.
392 ResetTerminal(Console
);
394 DPRINT("Terminal unregistered\n");
395 return STATUS_SUCCESS
;
399 ConDrvDeleteConsole(IN PCONSOLE Console
)
401 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console
);
404 * Forbid validation of any console by other threads
405 * during the deletion of this console.
407 ConDrvLockConsoleListExclusive();
410 * If the console is already being destroyed, i.e. not running
411 * or finishing to be initialized, just return.
413 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
) &&
414 !ConDrvValidateConsoleUnsafe(Console
, CONSOLE_INITIALIZING
, TRUE
))
416 /* Unlock the console list and return */
417 ConDrvUnlockConsoleList();
422 * We are about to be destroyed. Signal it to other people
423 * so that they can terminate what they are doing, and that
424 * they cannot longer validate the console.
426 Console
->State
= CONSOLE_TERMINATING
;
429 * Allow other threads to finish their job: basically, unlock
430 * all other calls to EnterCriticalSection(&Console->Lock); by
431 * ConDrvValidateConsoleUnsafe functions so that they just see
432 * that we are not in CONSOLE_RUNNING state anymore, or unlock
433 * other concurrent calls to ConDrvDeleteConsole so that they
434 * can see that we are in fact already deleting the console.
436 LeaveCriticalSection(&Console
->Lock
);
437 ConDrvUnlockConsoleList();
439 /* FIXME: Send a terminate message to all the processes owning this console */
441 /* Cleanup the UI-oriented part */
442 DPRINT("Deregister console\n");
443 ConDrvDeregisterTerminal(Console
);
444 DPRINT("Console deregistered\n");
447 * Check that the console is in terminating state before continuing
448 * (the cleanup code must not change the state of the console...
449 * ...unless to cancel console deletion ?).
452 ConDrvLockConsoleListExclusive();
454 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
456 ConDrvUnlockConsoleList();
460 /* We are now in destruction */
461 Console
->State
= CONSOLE_IN_DESTRUCTION
;
463 /* We really delete the console. Reset the count to be sure. */
464 Console
->ReferenceCount
= 0;
466 /* Remove the console from the list */
467 RemoveConsole(Console
);
469 /* Discard all entries in the input event queue */
470 PurgeInputBuffer(Console
);
471 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
473 /* Delete the last screen buffer */
474 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
475 Console
->ActiveBuffer
= NULL
;
476 if (!IsListEmpty(&Console
->BufferList
))
478 DPRINT1("BUG: screen buffer list not empty\n");
482 /**/ CloseHandle(Console
->InputBuffer
.ActiveEvent
); /**/
483 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
485 ConsoleFreeUnicodeString(&Console
->OriginalTitle
);
486 ConsoleFreeUnicodeString(&Console
->Title
);
488 DPRINT("ConDrvDeleteConsole - Unlocking\n");
489 LeaveCriticalSection(&Console
->Lock
);
490 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
491 DeleteCriticalSection(&Console
->Lock
);
492 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
494 ConsoleFreeHeap(Console
);
495 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
497 /* Unlock the console list and return */
498 ConDrvUnlockConsoleList();
502 /* PUBLIC DRIVER APIS *********************************************************/
505 ConDrvGetConsoleMode(IN PCONSOLE Console
,
506 IN PCONSOLE_IO_OBJECT Object
,
507 OUT PULONG ConsoleMode
)
509 NTSTATUS Status
= STATUS_SUCCESS
;
511 if (Console
== NULL
|| Object
== NULL
|| ConsoleMode
== NULL
)
512 return STATUS_INVALID_PARAMETER
;
515 ASSERT(Console
== Object
->Console
);
517 /*** FIXME: */ *ConsoleMode
= 0; /***/
519 if (INPUT_BUFFER
== Object
->Type
)
521 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
523 *ConsoleMode
= InputBuffer
->Mode
;
525 if (Console
->QuickEdit
|| Console
->InsertMode
)
527 // Windows does this, even if it's not documented on MSDN
528 *ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
530 if (Console
->QuickEdit
) *ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
531 if (Console
->InsertMode
) *ConsoleMode
|= ENABLE_INSERT_MODE
;
534 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
536 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
537 *ConsoleMode
= Buffer
->Mode
;
541 Status
= STATUS_INVALID_HANDLE
;
548 ConDrvSetConsoleMode(IN PCONSOLE Console
,
549 IN PCONSOLE_IO_OBJECT Object
,
550 IN ULONG ConsoleMode
)
552 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
553 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
554 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
555 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
557 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
559 NTSTATUS Status
= STATUS_SUCCESS
;
561 if (Console
== NULL
|| Object
== NULL
)
562 return STATUS_INVALID_PARAMETER
;
565 ASSERT(Console
== Object
->Console
);
567 if (INPUT_BUFFER
== Object
->Type
)
569 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
571 DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode
);
574 * 1. Only the presence of valid mode flags is allowed.
576 if (ConsoleMode
& ~(CONSOLE_VALID_INPUT_MODES
| CONSOLE_VALID_CONTROL_MODES
))
578 Status
= STATUS_INVALID_PARAMETER
;
583 * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
584 * then consider the flags invalid.
586 if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
587 (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
589 Status = STATUS_INVALID_PARAMETER;
595 * 3. Now we can continue.
597 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
599 Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
600 Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
602 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
604 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
606 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
608 DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode
);
610 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
612 Status
= STATUS_INVALID_PARAMETER
;
616 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
621 Status
= STATUS_INVALID_HANDLE
;
629 ConDrvGetConsoleTitle(IN PCONSOLE Console
,
631 IN OUT PVOID TitleBuffer
,
632 IN OUT PULONG BufLength
)
636 if (Console
== NULL
|| TitleBuffer
== NULL
|| BufLength
== NULL
)
637 return STATUS_INVALID_PARAMETER
;
639 /* Copy title of the console to the user title buffer */
642 if (*BufLength
>= sizeof(WCHAR
))
644 Length
= min(*BufLength
- sizeof(WCHAR
), Console
->Title
.Length
);
645 RtlCopyMemory(TitleBuffer
, Console
->Title
.Buffer
, Length
);
646 ((PWCHAR
)TitleBuffer
)[Length
/ sizeof(WCHAR
)] = L
'\0';
651 *BufLength
= Console
->Title
.Length
;
656 if (*BufLength
>= sizeof(CHAR
))
658 Length
= min(*BufLength
- sizeof(CHAR
), Console
->Title
.Length
/ sizeof(WCHAR
));
659 Length
= WideCharToMultiByte(Console
->InputCodePage
, 0,
660 Console
->Title
.Buffer
, Length
,
663 ((PCHAR
)TitleBuffer
)[Length
] = '\0';
668 *BufLength
= Console
->Title
.Length
/ sizeof(WCHAR
);
672 return STATUS_SUCCESS
;
676 ConDrvSetConsoleTitle(IN PCONSOLE Console
,
678 IN PVOID TitleBuffer
,
684 if (Console
== NULL
|| TitleBuffer
== NULL
)
685 return STATUS_INVALID_PARAMETER
;
689 /* Length is in bytes */
694 /* Use the console input CP for the conversion */
695 Length
= MultiByteToWideChar(Console
->InputCodePage
, 0,
696 TitleBuffer
, BufLength
,
698 /* The returned Length was in number of wchars, convert it in bytes */
699 Length
*= sizeof(WCHAR
);
702 /* Allocate a new buffer to hold the new title (NULL-terminated) */
703 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Length
+ sizeof(WCHAR
));
704 if (!Buffer
) return STATUS_NO_MEMORY
;
706 /* Free the old title */
707 ConsoleFreeUnicodeString(&Console
->Title
);
709 /* Copy title to console */
710 Console
->Title
.Buffer
= Buffer
;
711 Console
->Title
.Length
= Length
;
712 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
716 RtlCopyMemory(Console
->Title
.Buffer
, TitleBuffer
, Console
->Title
.Length
);
720 MultiByteToWideChar(Console
->InputCodePage
, 0,
721 TitleBuffer
, BufLength
,
722 Console
->Title
.Buffer
,
723 Console
->Title
.Length
/ sizeof(WCHAR
));
727 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
729 // TermChangeTitle(Console);
730 return STATUS_SUCCESS
;
734 ConDrvGetConsoleCP(IN PCONSOLE Console
,
738 if (Console
== NULL
|| CodePage
== NULL
)
739 return STATUS_INVALID_PARAMETER
;
741 *CodePage
= (OutputCP
? Console
->OutputCodePage
: Console
->InputCodePage
);
743 return STATUS_SUCCESS
;
747 ConDrvSetConsoleCP(IN PCONSOLE Console
,
751 if (Console
== NULL
|| !IsValidCodePage(CodePage
))
752 return STATUS_INVALID_PARAMETER
;
755 Console
->OutputCodePage
= CodePage
;
757 Console
->InputCodePage
= CodePage
;
759 return STATUS_SUCCESS
;