1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Console Server DLL 4 * FILE: win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c 5 * PURPOSE: TUI Terminal Front-End - Virtual Consoles... 6 * PROGRAMMERS: David Welch 7 * Gé van Geldorp 8 * Jeffrey Morlan 9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 10 */ 11 12 #ifdef TUITERM_COMPILE 13 14 #include <consrv.h> 15 16 // #include "include/conio.h" 17 #include "include/console.h" 18 #include "include/settings.h" 19 #include "tuiterm.h" 20 21 #include <ndk/iofuncs.h> 22 #include <ndk/setypes.h> 23 #include <drivers/blue/ntddblue.h> 24 25 #define NDEBUG 26 #include <debug.h> 27 28 29 /* CAB FILE STRUCTURES ******************************************************/ 30 31 typedef struct _CFHEADER 32 { 33 ULONG Signature; // File signature 'MSCF' (CAB_SIGNATURE) 34 ULONG Reserved1; // Reserved field 35 ULONG CabinetSize; // Cabinet file size 36 ULONG Reserved2; // Reserved field 37 ULONG FileTableOffset; // Offset of first CFFILE 38 ULONG Reserved3; // Reserved field 39 USHORT Version; // Cabinet version (CAB_VERSION) 40 USHORT FolderCount; // Number of folders 41 USHORT FileCount; // Number of files 42 USHORT Flags; // Cabinet flags (CAB_FLAG_*) 43 USHORT SetID; // Cabinet set id 44 USHORT CabinetNumber; // Zero-based cabinet number 45 } CFHEADER, *PCFHEADER; 46 47 typedef struct _CFFILE 48 { 49 ULONG FileSize; // Uncompressed file size in bytes 50 ULONG FileOffset; // Uncompressed offset of file in the folder 51 USHORT FileControlID; // File control ID (CAB_FILE_*) 52 USHORT FileDate; // File date stamp, as used by DOS 53 USHORT FileTime; // File time stamp, as used by DOS 54 USHORT Attributes; // File attributes (CAB_ATTRIB_*) 55 /* After this is the NULL terminated filename */ 56 // CHAR FileName[ANYSIZE_ARRAY]; 57 } CFFILE, *PCFFILE; 58 59 #define CAB_SIGNATURE 0x4643534D // "MSCF" 60 #define CAB_VERSION 0x0103 61 62 63 /* GLOBALS ******************************************************************/ 64 65 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \ 66 do { \ 67 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \ 68 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \ 69 } while (0) 70 71 /* TUI Console Window Class name */ 72 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass" 73 74 typedef struct _TUI_CONSOLE_DATA 75 { 76 CRITICAL_SECTION Lock; 77 LIST_ENTRY Entry; /* Entry in the list of virtual consoles */ 78 // HANDLE hTuiInitEvent; 79 // HANDLE hTuiTermEvent; 80 81 HWND hWindow; /* Handle to the console's window (used for the window's procedure) */ 82 83 PCONSRV_CONSOLE Console; /* Pointer to the owned console */ 84 PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to the active screen buffer (then maybe the previous Console member is redundant?? Or not...) */ 85 // TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */ 86 } TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA; 87 88 #define GetNextConsole(Console) \ 89 CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry) 90 91 #define GetPrevConsole(Console) \ 92 CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry) 93 94 95 /* List of the maintained virtual consoles and its lock */ 96 static LIST_ENTRY VirtConsList; 97 static PTUI_CONSOLE_DATA ActiveConsole; /* The active console on screen */ 98 static CRITICAL_SECTION ActiveVirtConsLock; 99 100 static COORD PhysicalConsoleSize; 101 static HANDLE ConsoleDeviceHandle; 102 103 static BOOL ConsInitialized = FALSE; 104 105 /******************************************************************************\ 106 |** BlueScreen Driver management **| 107 \**/ 108 /* Code taken and adapted from base/system/services/driver.c */ 109 static DWORD 110 ScmLoadDriver(LPCWSTR lpServiceName) 111 { 112 NTSTATUS Status = STATUS_SUCCESS; 113 BOOLEAN WasPrivilegeEnabled = FALSE; 114 PWSTR pszDriverPath; 115 UNICODE_STRING DriverPath; 116 117 /* Build the driver path */ 118 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 119 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY, 120 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR)); 121 if (pszDriverPath == NULL) 122 return ERROR_NOT_ENOUGH_MEMORY; 123 124 wcscpy(pszDriverPath, 125 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 126 wcscat(pszDriverPath, 127 lpServiceName); 128 129 RtlInitUnicodeString(&DriverPath, 130 pszDriverPath); 131 132 DPRINT(" Path: %wZ\n", &DriverPath); 133 134 /* Acquire driver-loading privilege */ 135 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 136 TRUE, 137 FALSE, 138 &WasPrivilegeEnabled); 139 if (!NT_SUCCESS(Status)) 140 { 141 /* We encountered a failure, exit properly */ 142 DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status); 143 goto done; 144 } 145 146 Status = NtLoadDriver(&DriverPath); 147 148 /* Release driver-loading privilege */ 149 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 150 WasPrivilegeEnabled, 151 FALSE, 152 &WasPrivilegeEnabled); 153 154 done: 155 ConsoleFreeHeap(pszDriverPath); 156 return RtlNtStatusToDosError(Status); 157 } 158 159 #ifdef BLUESCREEN_DRIVER_UNLOADING 160 static DWORD 161 ScmUnloadDriver(LPCWSTR lpServiceName) 162 { 163 NTSTATUS Status = STATUS_SUCCESS; 164 BOOLEAN WasPrivilegeEnabled = FALSE; 165 PWSTR pszDriverPath; 166 UNICODE_STRING DriverPath; 167 168 /* Build the driver path */ 169 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 170 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY, 171 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR)); 172 if (pszDriverPath == NULL) 173 return ERROR_NOT_ENOUGH_MEMORY; 174 175 wcscpy(pszDriverPath, 176 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 177 wcscat(pszDriverPath, 178 lpServiceName); 179 180 RtlInitUnicodeString(&DriverPath, 181 pszDriverPath); 182 183 DPRINT(" Path: %wZ\n", &DriverPath); 184 185 /* Acquire driver-unloading privilege */ 186 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 187 TRUE, 188 FALSE, 189 &WasPrivilegeEnabled); 190 if (!NT_SUCCESS(Status)) 191 { 192 /* We encountered a failure, exit properly */ 193 DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status); 194 goto done; 195 } 196 197 Status = NtUnloadDriver(&DriverPath); 198 199 /* Release driver-unloading privilege */ 200 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 201 WasPrivilegeEnabled, 202 FALSE, 203 &WasPrivilegeEnabled); 204 205 done: 206 ConsoleFreeHeap(pszDriverPath); 207 return RtlNtStatusToDosError(Status); 208 } 209 #endif 210 /**\ 211 \******************************************************************************/ 212 213 #if 0 214 static BOOL 215 TuiSwapConsole(INT Next) 216 { 217 static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */ 218 DWORD BytesReturned; 219 ANSI_STRING Title; 220 PVOID Buffer; 221 PCOORD pos; 222 223 if (0 != Next) 224 { 225 /* 226 * Alt-Tab, swap consoles. 227 * move SwapConsole to next console, and print its title. 228 */ 229 EnterCriticalSection(&ActiveVirtConsLock); 230 if (!SwapConsole) SwapConsole = ActiveConsole; 231 232 SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole)); 233 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title); 234 Title.Length = 0; 235 Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength); 236 pos = (PCOORD)Buffer; 237 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD)); 238 239 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE); 240 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2; 241 pos->Y = PhysicalConsoleSize.Y / 2; 242 /* Redraw the console to clear off old title */ 243 ConioDrawConsole(ActiveConsole->Console); 244 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, 245 NULL, 0, Buffer, sizeof(COORD) + Title.Length, 246 &BytesReturned, NULL)) 247 { 248 DPRINT1( "Error writing to console\n" ); 249 } 250 ConsoleFreeHeap(Buffer); 251 LeaveCriticalSection(&ActiveVirtConsLock); 252 253 return TRUE; 254 } 255 else if (NULL != SwapConsole) 256 { 257 EnterCriticalSection(&ActiveVirtConsLock); 258 if (SwapConsole != ActiveConsole) 259 { 260 /* First remove swapconsole from the list */ 261 SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink; 262 SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink; 263 /* Now insert before activeconsole */ 264 SwapConsole->Entry.Flink = &ActiveConsole->Entry; 265 SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink; 266 ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry; 267 ActiveConsole->Entry.Blink = &SwapConsole->Entry; 268 } 269 ActiveConsole = SwapConsole; 270 SwapConsole = NULL; 271 ConioDrawConsole(ActiveConsole->Console); 272 LeaveCriticalSection(&ActiveVirtConsLock); 273 return TRUE; 274 } 275 else 276 { 277 return FALSE; 278 } 279 } 280 #endif 281 282 static VOID 283 TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) 284 { 285 UINT SrcDelta, DestDelta; 286 LONG i; 287 PCHAR_INFO Src, SrcEnd; 288 289 Src = ConioCoordToPointer(Buff, Region->Left, Region->Top); 290 SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 291 SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 292 DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */; 293 for (i = Region->Top; i <= Region->Bottom; i++) 294 { 295 ConsoleOutputUnicodeToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar); 296 *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes; 297 298 Src += SrcDelta; 299 if (SrcEnd <= Src) 300 { 301 Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 302 } 303 Dest += DestDelta; 304 } 305 } 306 307 static LRESULT CALLBACK 308 TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 309 { 310 /* 311 PTUI_CONSOLE_DATA TuiData = NULL; 312 PCONSRV_CONSOLE Console = NULL; 313 314 TuiData = TuiGetGuiData(hWnd); 315 if (TuiData == NULL) return 0; 316 */ 317 318 switch (msg) 319 { 320 case WM_CHAR: 321 case WM_SYSCHAR: 322 case WM_KEYDOWN: 323 case WM_SYSKEYDOWN: 324 case WM_KEYUP: 325 case WM_SYSKEYUP: 326 { 327 #if 0 328 if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_TAB) 329 { 330 // if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) 331 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1); 332 333 break; 334 } 335 else if (wParam == VK_MENU /* && !Down */) 336 { 337 TuiSwapConsole(0); 338 break; 339 } 340 #endif 341 342 if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) 343 { 344 MSG Message; 345 Message.hwnd = hWnd; 346 Message.message = msg; 347 Message.wParam = wParam; 348 Message.lParam = lParam; 349 350 ConioProcessKey(ActiveConsole->Console, &Message); 351 LeaveCriticalSection(&ActiveConsole->Console->Lock); 352 } 353 break; 354 } 355 356 case WM_ACTIVATE: 357 { 358 if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) 359 { 360 if (LOWORD(wParam) != WA_INACTIVE) 361 { 362 SetFocus(hWnd); 363 ConioDrawConsole(ActiveConsole->Console); 364 } 365 LeaveCriticalSection(&ActiveConsole->Console->Lock); 366 } 367 break; 368 } 369 370 default: 371 break; 372 } 373 374 return DefWindowProcW(hWnd, msg, wParam, lParam); 375 } 376 377 static DWORD NTAPI 378 TuiConsoleThread(PVOID Param) 379 { 380 PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Param; 381 PCONSRV_CONSOLE Console = TuiData->Console; 382 HWND NewWindow; 383 MSG msg; 384 385 NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS, 386 Console->Title.Buffer, 387 0, 388 -32000, -32000, 0, 0, 389 NULL, NULL, 390 ConSrvDllInstance, 391 (PVOID)Console); 392 if (NULL == NewWindow) 393 { 394 DPRINT1("CONSRV: Unable to create console window\n"); 395 return 1; 396 } 397 TuiData->hWindow = NewWindow; 398 399 SetForegroundWindow(TuiData->hWindow); 400 NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0); 401 402 while (GetMessageW(&msg, NULL, 0, 0)) 403 { 404 TranslateMessage(&msg); 405 DispatchMessageW(&msg); 406 } 407 408 return 0; 409 } 410 411 static BOOLEAN 412 TuiSetConsoleOutputCP( 413 IN HANDLE hNtConddHandle, 414 IN UINT CodePage) 415 { 416 static UINT LastLoadedCodepage = 0; 417 UNICODE_STRING FontFile = RTL_CONSTANT_STRING(L"\\SystemRoot\\vgafonts.cab"); 418 CHAR FontName[20]; 419 420 NTSTATUS Status; 421 HANDLE FileHandle; 422 OBJECT_ATTRIBUTES ObjectAttributes; 423 IO_STATUS_BLOCK IoStatusBlock; 424 // ULONG ReadCP; 425 PUCHAR FontBitField = NULL; 426 427 /* CAB-specific data */ 428 HANDLE FileSectionHandle; 429 PUCHAR FileBuffer = NULL; 430 SIZE_T FileSize = 0; 431 PCFHEADER CabFileHeader; 432 union 433 { 434 PCFFILE CabFile; 435 PVOID Buffer; 436 } Data; 437 PCFFILE FoundFile = NULL; 438 PSTR FileName; 439 USHORT Index; 440 441 if (CodePage == LastLoadedCodepage) 442 return TRUE; 443 444 /* 445 * Open the *uncompressed* fonts archive file. 446 */ 447 InitializeObjectAttributes(&ObjectAttributes, 448 &FontFile, 449 OBJ_CASE_INSENSITIVE, 450 NULL, 451 NULL); 452 453 Status = NtOpenFile(&FileHandle, 454 GENERIC_READ | SYNCHRONIZE, 455 &ObjectAttributes, 456 &IoStatusBlock, 457 FILE_SHARE_READ, 458 FILE_SYNCHRONOUS_IO_NONALERT); 459 if (!NT_SUCCESS(Status)) 460 { 461 DPRINT1("Error: Cannot open '%wZ' (0x%lx)\n", &FontFile, Status); 462 return FALSE; 463 } 464 465 /* 466 * Load it. 467 */ 468 Status = NtCreateSection(&FileSectionHandle, 469 SECTION_ALL_ACCESS, 470 0, 0, 471 PAGE_READONLY, 472 SEC_COMMIT, 473 FileHandle); 474 if (!NT_SUCCESS(Status)) 475 { 476 DPRINT1("NtCreateSection failed (0x%lx)\n", Status); 477 goto Exit; 478 } 479 480 Status = NtMapViewOfSection(FileSectionHandle, 481 NtCurrentProcess(), 482 (PVOID*)&FileBuffer, 483 0, 0, NULL, 484 &FileSize, 485 ViewUnmap, 486 0, 487 PAGE_READONLY); 488 if (!NT_SUCCESS(Status)) 489 { 490 DPRINT1("NtMapViewOfSection failed (0x%lx)\n", Status); 491 goto Exit; 492 } 493 494 /* Wrap in SEH to protect against ill-formed file */ 495 _SEH2_TRY 496 { 497 DPRINT("Cabinet file '%wZ' opened and mapped to 0x%p\n", 498 &FontFile, FileBuffer); 499 500 CabFileHeader = (PCFHEADER)FileBuffer; 501 502 /* Validate the CAB file */ 503 if (FileSize <= sizeof(CFHEADER) || 504 CabFileHeader->Signature != CAB_SIGNATURE || 505 CabFileHeader->Version != CAB_VERSION || 506 CabFileHeader->FolderCount == 0 || 507 CabFileHeader->FileCount == 0 || 508 CabFileHeader->FileTableOffset < sizeof(CFHEADER)) 509 { 510 DPRINT1("Cabinet file '%wZ' has an invalid header\n", &FontFile); 511 Status = STATUS_UNSUCCESSFUL; 512 _SEH2_YIELD(goto Exit); 513 } 514 515 /* 516 * Find the font file within the archive. 517 */ 518 RtlStringCbPrintfA(FontName, sizeof(FontName), 519 "%u-8x8.bin", CodePage); 520 521 /* Read the file table, find the file of interest and the end of the table */ 522 Data.CabFile = (PCFFILE)(FileBuffer + CabFileHeader->FileTableOffset); 523 for (Index = 0; Index < CabFileHeader->FileCount; ++Index) 524 { 525 FileName = (PSTR)(Data.CabFile + 1); 526 527 if (!FoundFile) 528 { 529 // Status = RtlCharToInteger(FileName, 0, &ReadCP); 530 // if (NT_SUCCESS(Status) && (ReadCP == CodePage)) 531 if (_stricmp(FontName, FileName) == 0) 532 { 533 /* We've got the correct file. Save the offset and 534 * loop through the rest of the file table to find 535 * the position, where the actual data starts. */ 536 FoundFile = Data.CabFile; 537 } 538 } 539 540 /* Move to the next file (go past the filename NULL terminator) */ 541 Data.CabFile = (PCFFILE)(strchr(FileName, 0) + 1); 542 } 543 544 if (!FoundFile) 545 { 546 DPRINT("File '%S' not found in cabinet '%wZ'\n", 547 FontName, &FontFile); 548 Status = STATUS_OBJECT_NAME_NOT_FOUND; 549 _SEH2_YIELD(goto Exit); 550 } 551 552 /* 553 * Extract the font file. 554 */ 555 /* Verify the font file size; we only support a fixed 256-char 8-bit font */ 556 if (FoundFile->FileSize != 256 * 8) 557 { 558 DPRINT1("File of size %lu is not of the expected size %lu\n", 559 FoundFile->FileSize, 256 * 8); 560 Status = STATUS_INVALID_BUFFER_SIZE; 561 _SEH2_YIELD(goto Exit); 562 } 563 564 FontBitField = RtlAllocateHeap(RtlGetProcessHeap(), 0, FoundFile->FileSize); 565 if (!FontBitField) 566 { 567 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", FoundFile->FileSize); 568 Status = STATUS_NO_MEMORY; 569 _SEH2_YIELD(goto Exit); 570 } 571 572 /* 8 = Size of a CFFOLDER structure (see cabman). As we don't need 573 * the values of that structure, just increase the offset here. */ 574 Data.Buffer = (PVOID)((ULONG_PTR)Data.Buffer + 8); // sizeof(CFFOLDER); 575 Data.Buffer = (PVOID)((ULONG_PTR)Data.Buffer + FoundFile->FileOffset); 576 577 /* Data.Buffer now points to the actual data of the RAW font */ 578 RtlCopyMemory(FontBitField, Data.Buffer, FoundFile->FileSize); 579 Status = STATUS_SUCCESS; 580 } 581 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 582 { 583 Status = _SEH2_GetExceptionCode(); 584 DPRINT1("TuiSetConsoleOutputCP - Caught an exception, Status = 0x%08lx\n", Status); 585 } 586 _SEH2_END; 587 588 /* 589 * Load the font. 590 */ 591 if (NT_SUCCESS(Status)) 592 { 593 ASSERT(FoundFile); 594 ASSERT(FontBitField); 595 Status = NtDeviceIoControlFile(hNtConddHandle, 596 NULL, 597 NULL, 598 NULL, 599 &IoStatusBlock, 600 IOCTL_CONSOLE_LOADFONT, 601 FontBitField, 602 FoundFile->FileSize, 603 NULL, 604 0); 605 } 606 607 if (FontBitField) 608 RtlFreeHeap(RtlGetProcessHeap(), 0, FontBitField); 609 610 Exit: 611 if (FileBuffer) 612 NtUnmapViewOfSection(NtCurrentProcess(), FileBuffer); 613 614 if (FileSectionHandle) 615 NtClose(FileSectionHandle); 616 617 NtClose(FileHandle); 618 619 if (NT_SUCCESS(Status)) 620 LastLoadedCodepage = CodePage; 621 622 return NT_SUCCESS(Status); 623 } 624 625 static BOOL 626 TuiInit(IN UINT OemCP) 627 { 628 BOOL Success; 629 CONSOLE_SCREEN_BUFFER_INFO ScrInfo; 630 DWORD BytesReturned; 631 WNDCLASSEXW wc; 632 ATOM ConsoleClassAtom; 633 USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; 634 635 /* Exit if we were already initialized */ 636 if (ConsInitialized) return TRUE; 637 638 /* 639 * Initialize the TUI front-end: 640 * - load the console driver, 641 * - open BlueScreen device and enable it, 642 * - set default screen attributes, 643 * - grab the console size. 644 */ 645 ScmLoadDriver(L"Blue"); 646 647 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", 648 FILE_ALL_ACCESS, 649 0, NULL, 650 OPEN_EXISTING, 651 0, NULL); 652 if (ConsoleDeviceHandle == INVALID_HANDLE_VALUE) 653 { 654 DPRINT1("Failed to open BlueScreen.\n"); 655 return FALSE; 656 } 657 658 Success = TRUE; 659 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_RESET_SCREEN, 660 &Success, sizeof(Success), NULL, 0, 661 &BytesReturned, NULL)) 662 { 663 DPRINT1("Failed to enable the screen.\n"); 664 CloseHandle(ConsoleDeviceHandle); 665 return FALSE; 666 } 667 668 if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle, OemCP)) 669 { 670 DPRINT1("Failed to load the font for codepage %d\n", OemCP); 671 /* Let's suppose the font is good enough to continue */ 672 } 673 674 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE, 675 &TextAttribute, sizeof(TextAttribute), NULL, 0, 676 &BytesReturned, NULL)) 677 { 678 DPRINT1("Failed to set text attribute.\n"); 679 } 680 681 ActiveConsole = NULL; 682 InitializeListHead(&VirtConsList); 683 InitializeCriticalSection(&ActiveVirtConsLock); 684 685 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 686 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL)) 687 { 688 DPRINT1("Failed to get console info.\n"); 689 Success = FALSE; 690 goto Quit; 691 } 692 PhysicalConsoleSize = ScrInfo.dwSize; 693 694 /* Register the TUI notification window class */ 695 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW)); 696 wc.cbSize = sizeof(WNDCLASSEXW); 697 wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS; 698 wc.lpfnWndProc = TuiConsoleWndProc; 699 wc.cbWndExtra = 0; 700 wc.hInstance = ConSrvDllInstance; 701 702 ConsoleClassAtom = RegisterClassExW(&wc); 703 if (ConsoleClassAtom == 0) 704 { 705 DPRINT1("Failed to register TUI console wndproc.\n"); 706 Success = FALSE; 707 } 708 else 709 { 710 Success = TRUE; 711 } 712 713 Quit: 714 if (!Success) 715 { 716 DeleteCriticalSection(&ActiveVirtConsLock); 717 CloseHandle(ConsoleDeviceHandle); 718 } 719 720 ConsInitialized = Success; 721 return Success; 722 } 723 724 725 726 /****************************************************************************** 727 * TUI Console Driver * 728 ******************************************************************************/ 729 730 static VOID NTAPI 731 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*, 732 IN PCONSRV_CONSOLE Console */); 733 734 static NTSTATUS NTAPI 735 TuiInitFrontEnd(IN OUT PFRONTEND This, 736 IN PCONSRV_CONSOLE Console) 737 { 738 PTUI_CONSOLE_DATA TuiData; 739 HANDLE ThreadHandle; 740 741 if (This == NULL || Console == NULL) 742 return STATUS_INVALID_PARAMETER; 743 744 if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) 745 return STATUS_INVALID_PARAMETER; 746 747 TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); 748 if (!TuiData) 749 { 750 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); 751 return STATUS_UNSUCCESSFUL; 752 } 753 // Console->FrontEndIFace.Context = (PVOID)TuiData; 754 TuiData->Console = Console; 755 TuiData->ActiveBuffer = Console->ActiveBuffer; 756 TuiData->hWindow = NULL; 757 758 InitializeCriticalSection(&TuiData->Lock); 759 760 /* 761 * HACK: Resize the console since we don't support for now changing 762 * the console size when we display it with the hardware. 763 */ 764 // Console->ConsoleSize = PhysicalConsoleSize; 765 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); 766 767 // /* The console cannot be resized anymore */ 768 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! 769 // // TermResizeTerminal(Console); 770 771 /* 772 * Contrary to what we do in the GUI front-end, here we create 773 * an input thread for each console. It will dispatch all the 774 * input messages to the proper console (on the GUI it is done 775 * via the default GUI dispatch thread). 776 */ 777 ThreadHandle = CreateThread(NULL, 778 0, 779 TuiConsoleThread, 780 (PVOID)TuiData, 781 0, 782 NULL); 783 if (NULL == ThreadHandle) 784 { 785 DPRINT1("CONSRV: Unable to create console thread\n"); 786 // TuiDeinitFrontEnd(Console); 787 TuiDeinitFrontEnd(This); 788 return STATUS_UNSUCCESSFUL; 789 } 790 CloseHandle(ThreadHandle); 791 792 /* 793 * Insert the newly created console in the list of virtual consoles 794 * and activate it (give it the focus). 795 */ 796 EnterCriticalSection(&ActiveVirtConsLock); 797 InsertTailList(&VirtConsList, &TuiData->Entry); 798 ActiveConsole = TuiData; 799 LeaveCriticalSection(&ActiveVirtConsLock); 800 801 /* Finally, initialize the frontend structure */ 802 This->Context = TuiData; 803 This->Context2 = NULL; 804 805 return STATUS_SUCCESS; 806 } 807 808 static VOID NTAPI 809 TuiDeinitFrontEnd(IN OUT PFRONTEND This) 810 { 811 // PCONSRV_CONSOLE Console = This->Console; 812 PTUI_CONSOLE_DATA TuiData = This->Context; 813 814 /* Close the notification window */ 815 DestroyWindow(TuiData->hWindow); 816 817 /* 818 * Set the active console to the next one 819 * and remove the console from the list. 820 */ 821 EnterCriticalSection(&ActiveVirtConsLock); 822 ActiveConsole = GetNextConsole(TuiData); 823 RemoveEntryList(&TuiData->Entry); 824 825 // /* Switch to next console */ 826 // if (ActiveConsole == TuiData) 827 // if (ActiveConsole->Console == Console) 828 // { 829 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL); 830 // } 831 832 // if (GetNextConsole(TuiData) != TuiData) 833 // { 834 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink; 835 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink; 836 // } 837 838 LeaveCriticalSection(&ActiveVirtConsLock); 839 840 /* Switch to the next console */ 841 if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console); 842 843 This->Context = NULL; 844 DeleteCriticalSection(&TuiData->Lock); 845 ConsoleFreeHeap(TuiData); 846 } 847 848 static VOID NTAPI 849 TuiDrawRegion(IN OUT PFRONTEND This, 850 SMALL_RECT* Region) 851 { 852 PTUI_CONSOLE_DATA TuiData = This->Context; 853 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 854 PCONSOLE_DRAW ConsoleDraw; 855 DWORD BytesReturned; 856 UINT ConsoleDrawSize; 857 858 if (TuiData != ActiveConsole) return; 859 if (GetType(Buff) != TEXTMODE_BUFFER) return; 860 861 ConsoleDrawSize = sizeof(CONSOLE_DRAW) + 862 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; 863 ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize); 864 if (NULL == ConsoleDraw) 865 { 866 DPRINT1("ConsoleAllocHeap failed\n"); 867 return; 868 } 869 ConsoleDraw->X = Region->Left; 870 ConsoleDraw->Y = Region->Top; 871 ConsoleDraw->SizeX = ConioRectWidth(Region); 872 ConsoleDraw->SizeY = ConioRectHeight(Region); 873 ConsoleDraw->CursorX = Buff->CursorPosition.X; 874 ConsoleDraw->CursorY = Buff->CursorPosition.Y; 875 876 TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); 877 878 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, 879 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) 880 { 881 DPRINT1("Failed to draw console\n"); 882 ConsoleFreeHeap(ConsoleDraw); 883 return; 884 } 885 886 ConsoleFreeHeap(ConsoleDraw); 887 } 888 889 static VOID NTAPI 890 TuiWriteStream(IN OUT PFRONTEND This, 891 SMALL_RECT* Region, 892 SHORT CursorStartX, 893 SHORT CursorStartY, 894 UINT ScrolledLines, 895 PWCHAR Buffer, 896 UINT Length) 897 { 898 PTUI_CONSOLE_DATA TuiData = This->Context; 899 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 900 PCHAR NewBuffer; 901 ULONG NewLength; 902 DWORD BytesWritten; 903 904 if (TuiData != ActiveConsole) return; 905 if (GetType(Buff) != TEXTMODE_BUFFER) return; 906 907 NewLength = WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 908 Buffer, Length, 909 NULL, 0, NULL, NULL); 910 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR)); 911 if (!NewBuffer) return; 912 913 WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 914 Buffer, Length, 915 NewBuffer, NewLength, NULL, NULL); 916 917 if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL)) 918 { 919 DPRINT1("Error writing to BlueScreen\n"); 920 } 921 922 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer); 923 } 924 925 static VOID NTAPI 926 TuiRingBell(IN OUT PFRONTEND This) 927 { 928 Beep(800, 200); 929 } 930 931 static BOOL NTAPI 932 TuiSetCursorInfo(IN OUT PFRONTEND This, 933 PCONSOLE_SCREEN_BUFFER Buff) 934 { 935 PTUI_CONSOLE_DATA TuiData = This->Context; 936 CONSOLE_CURSOR_INFO Info; 937 DWORD BytesReturned; 938 939 if (TuiData != ActiveConsole) return TRUE; 940 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 941 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 942 943 Info.dwSize = ConioEffectiveCursorSize(TuiData->Console, 100); 944 Info.bVisible = Buff->CursorInfo.bVisible; 945 946 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO, 947 &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL)) 948 { 949 DPRINT1( "Failed to set cursor info\n" ); 950 return FALSE; 951 } 952 953 return TRUE; 954 } 955 956 static BOOL NTAPI 957 TuiSetScreenInfo(IN OUT PFRONTEND This, 958 PCONSOLE_SCREEN_BUFFER Buff, 959 SHORT OldCursorX, 960 SHORT OldCursorY) 961 { 962 PTUI_CONSOLE_DATA TuiData = This->Context; 963 CONSOLE_SCREEN_BUFFER_INFO Info; 964 DWORD BytesReturned; 965 966 if (TuiData != ActiveConsole) return TRUE; 967 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 968 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 969 970 Info.dwCursorPosition = Buff->CursorPosition; 971 Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib; 972 973 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, 974 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0, 975 &BytesReturned, NULL)) 976 { 977 DPRINT1( "Failed to set cursor position\n" ); 978 return FALSE; 979 } 980 981 return TRUE; 982 } 983 984 static VOID NTAPI 985 TuiResizeTerminal(IN OUT PFRONTEND This) 986 { 987 } 988 989 static VOID NTAPI 990 TuiSetActiveScreenBuffer(IN OUT PFRONTEND This) 991 { 992 // PGUI_CONSOLE_DATA GuiData = This->Context; 993 // PCONSOLE_SCREEN_BUFFER ActiveBuffer; 994 // HPALETTE hPalette; 995 996 // EnterCriticalSection(&GuiData->Lock); 997 // GuiData->WindowSizeLock = TRUE; 998 999 // InterlockedExchangePointer(&GuiData->ActiveBuffer, 1000 // ConDrvGetActiveScreenBuffer(GuiData->Console)); 1001 1002 // GuiData->WindowSizeLock = FALSE; 1003 // LeaveCriticalSection(&GuiData->Lock); 1004 1005 // ActiveBuffer = GuiData->ActiveBuffer; 1006 1007 // /* Change the current palette */ 1008 // if (ActiveBuffer->PaletteHandle == NULL) 1009 // { 1010 // hPalette = GuiData->hSysPalette; 1011 // } 1012 // else 1013 // { 1014 // hPalette = ActiveBuffer->PaletteHandle; 1015 // } 1016 1017 // DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette); 1018 1019 // /* Set the new palette for the framebuffer */ 1020 // SelectPalette(GuiData->hMemDC, hPalette, FALSE); 1021 1022 // /* Specify the use of the system palette for the framebuffer */ 1023 // SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage); 1024 1025 // /* Realize the (logical) palette */ 1026 // RealizePalette(GuiData->hMemDC); 1027 1028 // GuiResizeTerminal(This); 1029 // // ConioDrawConsole(Console); 1030 } 1031 1032 static VOID NTAPI 1033 TuiReleaseScreenBuffer(IN OUT PFRONTEND This, 1034 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer) 1035 { 1036 // PGUI_CONSOLE_DATA GuiData = This->Context; 1037 1038 // /* 1039 // * If we were notified to release a screen buffer that is not actually 1040 // * ours, then just ignore the notification... 1041 // */ 1042 // if (ScreenBuffer != GuiData->ActiveBuffer) return; 1043 1044 // /* 1045 // * ... else, we must release our active buffer. Two cases are present: 1046 // * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console 1047 // * active screen buffer, then we can safely switch to it. 1048 // * - If ScreenBuffer IS the console active screen buffer, we must release 1049 // * it ONLY. 1050 // */ 1051 1052 // /* Release the old active palette and set the default one */ 1053 // if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle) 1054 // { 1055 // /* Set the new palette */ 1056 // SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE); 1057 // } 1058 1059 // /* Set the adequate active screen buffer */ 1060 // if (ScreenBuffer != GuiData->Console->ActiveBuffer) 1061 // { 1062 // GuiSetActiveScreenBuffer(This); 1063 // } 1064 // else 1065 // { 1066 // EnterCriticalSection(&GuiData->Lock); 1067 // GuiData->WindowSizeLock = TRUE; 1068 1069 // InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL); 1070 1071 // GuiData->WindowSizeLock = FALSE; 1072 // LeaveCriticalSection(&GuiData->Lock); 1073 // } 1074 } 1075 1076 static VOID NTAPI 1077 TuiRefreshInternalInfo(IN OUT PFRONTEND This) 1078 { 1079 } 1080 1081 static VOID NTAPI 1082 TuiChangeTitle(IN OUT PFRONTEND This) 1083 { 1084 } 1085 1086 static BOOL NTAPI 1087 TuiChangeIcon(IN OUT PFRONTEND This, 1088 HICON IconHandle) 1089 { 1090 return TRUE; 1091 } 1092 1093 static HDESK NTAPI 1094 TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This) 1095 { 1096 // PTUI_CONSOLE_DATA TuiData = This->Context; 1097 return NULL; 1098 } 1099 1100 static HWND NTAPI 1101 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This) 1102 { 1103 PTUI_CONSOLE_DATA TuiData = This->Context; 1104 return TuiData->hWindow; 1105 } 1106 1107 static VOID NTAPI 1108 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This, 1109 PCOORD pSize) 1110 { 1111 if (!pSize) return; 1112 *pSize = PhysicalConsoleSize; 1113 } 1114 1115 static BOOL NTAPI 1116 TuiGetSelectionInfo(IN OUT PFRONTEND This, 1117 PCONSOLE_SELECTION_INFO pSelectionInfo) 1118 { 1119 return TRUE; 1120 } 1121 1122 static BOOL NTAPI 1123 TuiSetPalette(IN OUT PFRONTEND This, 1124 HPALETTE PaletteHandle, 1125 UINT PaletteUsage) 1126 { 1127 return TRUE; 1128 } 1129 1130 static BOOL NTAPI 1131 TuiSetCodePage(IN OUT PFRONTEND This, 1132 UINT CodePage) 1133 { 1134 // PTUI_CONSOLE_DATA TuiData = This->Context; 1135 1136 // TODO: Verify that the console is the visible one. 1137 // Only then can we change the output code page font. 1138 1139 if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle, CodePage)) 1140 { 1141 DPRINT1("Failed to load the font for codepage %d\n", CodePage); 1142 /* Let's suppose the font is good enough to continue */ 1143 return FALSE; 1144 } 1145 1146 return TRUE; 1147 } 1148 1149 static ULONG NTAPI 1150 TuiGetDisplayMode(IN OUT PFRONTEND This) 1151 { 1152 return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN; 1153 } 1154 1155 static BOOL NTAPI 1156 TuiSetDisplayMode(IN OUT PFRONTEND This, 1157 ULONG NewMode) 1158 { 1159 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) 1160 // return FALSE; 1161 return TRUE; 1162 } 1163 1164 static INT NTAPI 1165 TuiShowMouseCursor(IN OUT PFRONTEND This, 1166 BOOL Show) 1167 { 1168 return 0; 1169 } 1170 1171 static BOOL NTAPI 1172 TuiSetMouseCursor(IN OUT PFRONTEND This, 1173 HCURSOR CursorHandle) 1174 { 1175 return TRUE; 1176 } 1177 1178 static HMENU NTAPI 1179 TuiMenuControl(IN OUT PFRONTEND This, 1180 UINT CmdIdLow, 1181 UINT CmdIdHigh) 1182 { 1183 return NULL; 1184 } 1185 1186 static BOOL NTAPI 1187 TuiSetMenuClose(IN OUT PFRONTEND This, 1188 BOOL Enable) 1189 { 1190 return TRUE; 1191 } 1192 1193 static FRONTEND_VTBL TuiVtbl = 1194 { 1195 TuiInitFrontEnd, 1196 TuiDeinitFrontEnd, 1197 TuiDrawRegion, 1198 TuiWriteStream, 1199 TuiRingBell, 1200 TuiSetCursorInfo, 1201 TuiSetScreenInfo, 1202 TuiResizeTerminal, 1203 TuiSetActiveScreenBuffer, 1204 TuiReleaseScreenBuffer, 1205 TuiRefreshInternalInfo, 1206 TuiChangeTitle, 1207 TuiChangeIcon, 1208 TuiGetThreadConsoleDesktop, 1209 TuiGetConsoleWindowHandle, 1210 TuiGetLargestConsoleWindowSize, 1211 TuiGetSelectionInfo, 1212 TuiSetPalette, 1213 TuiSetCodePage, 1214 TuiGetDisplayMode, 1215 TuiSetDisplayMode, 1216 TuiShowMouseCursor, 1217 TuiSetMouseCursor, 1218 TuiMenuControl, 1219 TuiSetMenuClose, 1220 }; 1221 1222 static BOOLEAN 1223 IsConsoleMode(VOID) 1224 { 1225 return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE); 1226 } 1227 1228 NTSTATUS NTAPI 1229 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 1230 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 1231 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 1232 IN HANDLE ConsoleLeaderProcessHandle) 1233 { 1234 if (FrontEnd == NULL || ConsoleInfo == NULL) 1235 return STATUS_INVALID_PARAMETER; 1236 1237 /* We must be in console mode already */ 1238 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL; 1239 1240 /* Initialize the TUI terminal emulator */ 1241 if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL; 1242 1243 /* Finally, initialize the frontend structure */ 1244 FrontEnd->Vtbl = &TuiVtbl; 1245 FrontEnd->Context = NULL; 1246 FrontEnd->Context2 = NULL; 1247 1248 return STATUS_SUCCESS; 1249 } 1250 1251 NTSTATUS NTAPI 1252 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) 1253 { 1254 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; 1255 if (FrontEnd->Context) TuiDeinitFrontEnd(FrontEnd); 1256 1257 return STATUS_SUCCESS; 1258 } 1259 1260 #endif 1261 1262 /* EOF */ 1263