1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Console Server DLL 4 * FILE: win32ss/user/winsrv/consrv/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 /* This is for COM usage */ 16 #define COBJMACROS 17 #include <shlobj.h> 18 19 20 #include <alias.h> 21 #include <history.h> 22 #include "procinit.h" 23 24 #define NDEBUG 25 #include <debug.h> 26 27 28 /* GLOBALS ********************************************************************/ 29 30 /* The list of the ConSrv consoles */ 31 static ULONG ConsoleListSize; 32 static PCONSRV_CONSOLE* ConsoleList; 33 static RTL_RESOURCE ListLock; 34 35 #define ConSrvLockConsoleListExclusive() \ 36 RtlAcquireResourceExclusive(&ListLock, TRUE) 37 38 #define ConSrvLockConsoleListShared() \ 39 RtlAcquireResourceShared(&ListLock, TRUE) 40 41 #define ConSrvUnlockConsoleList() \ 42 RtlReleaseResource(&ListLock) 43 44 45 static NTSTATUS 46 InsertConsole(OUT PHANDLE Handle, 47 IN PCONSRV_CONSOLE Console) 48 { 49 #define CONSOLE_HANDLES_INCREMENT 2 * 3 50 51 NTSTATUS Status = STATUS_SUCCESS; 52 ULONG i = 0; 53 PCONSRV_CONSOLE* Block; 54 55 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) || 56 (ConsoleList != NULL && ConsoleListSize != 0) ); 57 58 /* All went right, so add the console to the list */ 59 ConSrvLockConsoleListExclusive(); 60 DPRINT("Insert in the list\n"); 61 62 if (ConsoleList) 63 { 64 for (i = 0; i < ConsoleListSize; i++) 65 { 66 if (ConsoleList[i] == NULL) break; 67 } 68 } 69 70 if (i >= ConsoleListSize) 71 { 72 DPRINT("Creation of a new handles table\n"); 73 /* Allocate a new handles table */ 74 Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY, 75 (ConsoleListSize + 76 CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSRV_CONSOLE)); 77 if (Block == NULL) 78 { 79 Status = STATUS_UNSUCCESSFUL; 80 goto Quit; 81 } 82 83 /* If we previously had a handles table, free it and use the new one */ 84 if (ConsoleList) 85 { 86 /* Copy the handles from the old table to the new one */ 87 RtlCopyMemory(Block, 88 ConsoleList, 89 ConsoleListSize * sizeof(PCONSRV_CONSOLE)); 90 ConsoleFreeHeap(ConsoleList); 91 } 92 ConsoleList = Block; 93 ConsoleListSize += CONSOLE_HANDLES_INCREMENT; 94 } 95 96 ConsoleList[i] = Console; 97 *Handle = ULongToHandle((i << 2) | 0x3); 98 99 Quit: 100 /* Unlock the console list and return status */ 101 ConSrvUnlockConsoleList(); 102 return Status; 103 } 104 105 /* Unused */ 106 #if 0 107 static NTSTATUS 108 RemoveConsoleByHandle(IN HANDLE Handle) 109 { 110 NTSTATUS Status = STATUS_SUCCESS; 111 PCONSRV_CONSOLE Console; 112 113 BOOLEAN ValidHandle = ((HandleToULong(Handle) & 0x3) == 0x3); 114 ULONG Index = HandleToULong(Handle) >> 2; 115 116 if (!ValidHandle) return STATUS_INVALID_HANDLE; 117 118 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) || 119 (ConsoleList != NULL && ConsoleListSize != 0) ); 120 121 /* Remove the console from the list */ 122 ConSrvLockConsoleListExclusive(); 123 124 if (Index >= ConsoleListSize || 125 (Console = ConsoleList[Index]) == NULL) 126 { 127 Status = STATUS_INVALID_HANDLE; 128 goto Quit; 129 } 130 131 ConsoleList[Index] = NULL; 132 133 Quit: 134 /* Unlock the console list and return status */ 135 ConSrvUnlockConsoleList(); 136 return Status; 137 } 138 #endif 139 140 static NTSTATUS 141 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console) 142 { 143 ULONG i = 0; 144 145 if (!Console) return STATUS_INVALID_PARAMETER; 146 147 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) || 148 (ConsoleList != NULL && ConsoleListSize != 0) ); 149 150 /* Remove the console from the list */ 151 ConSrvLockConsoleListExclusive(); 152 153 if (ConsoleList) 154 { 155 for (i = 0; i < ConsoleListSize; i++) 156 { 157 if (ConsoleList[i] == Console) ConsoleList[i] = NULL; 158 } 159 } 160 161 /* Unlock the console list and return */ 162 ConSrvUnlockConsoleList(); 163 return STATUS_SUCCESS; 164 } 165 166 BOOLEAN NTAPI 167 ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console, 168 IN HANDLE ConsoleHandle, 169 IN CONSOLE_STATE ExpectedState, 170 IN BOOLEAN LockConsole) 171 { 172 BOOLEAN RetVal = FALSE; 173 PCONSRV_CONSOLE ValidatedConsole; 174 175 BOOLEAN ValidHandle = ((HandleToULong(ConsoleHandle) & 0x3) == 0x3); 176 ULONG Index = HandleToULong(ConsoleHandle) >> 2; 177 178 if (!ValidHandle) return FALSE; 179 180 if (!Console) return FALSE; 181 *Console = NULL; 182 183 /* 184 * Forbid creation or deletion of consoles when 185 * checking for the existence of a console. 186 */ 187 ConSrvLockConsoleListShared(); 188 189 if (Index >= ConsoleListSize || 190 (ValidatedConsole = ConsoleList[Index]) == NULL) 191 { 192 /* Unlock the console list and return */ 193 ConSrvUnlockConsoleList(); 194 return FALSE; 195 } 196 197 ValidatedConsole = ConsoleList[Index]; 198 199 /* Unlock the console list and return */ 200 ConSrvUnlockConsoleList(); 201 202 RetVal = ConDrvValidateConsoleUnsafe((PCONSOLE)ValidatedConsole, 203 ExpectedState, 204 LockConsole); 205 if (RetVal) *Console = ValidatedConsole; 206 207 return RetVal; 208 } 209 210 211 /* PRIVATE FUNCTIONS **********************************************************/ 212 213 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180 214 static BOOLEAN 215 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest, 216 IN PCWSTR Source) 217 { 218 SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR); 219 if (Size > MAXUSHORT) return FALSE; 220 221 UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size); 222 if (UniDest->Buffer == NULL) return FALSE; 223 224 RtlCopyMemory(UniDest->Buffer, Source, Size); 225 UniDest->MaximumLength = (USHORT)Size; 226 UniDest->Length = (USHORT)Size - sizeof(WCHAR); 227 228 return TRUE; 229 } 230 231 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431 232 static VOID 233 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString) 234 { 235 if (UnicodeString->Buffer) 236 { 237 ConsoleFreeHeap(UnicodeString->Buffer); 238 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING)); 239 } 240 } 241 242 VOID 243 ConioPause(PCONSRV_CONSOLE Console, UINT Flags) 244 { 245 Console->PauseFlags |= Flags; 246 ConDrvPause((PCONSOLE)Console); 247 } 248 249 VOID 250 ConioUnpause(PCONSRV_CONSOLE Console, UINT Flags) 251 { 252 Console->PauseFlags &= ~Flags; 253 254 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0) 255 if (Console->PauseFlags == 0) 256 { 257 ConDrvUnpause((PCONSOLE)Console); 258 259 CsrNotifyWait(&Console->WriteWaitQueue, 260 TRUE, 261 NULL, 262 NULL); 263 if (!IsListEmpty(&Console->WriteWaitQueue)) 264 { 265 CsrDereferenceWait(&Console->WriteWaitQueue); 266 } 267 } 268 } 269 270 NTSTATUS 271 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData, 272 OUT PCONSRV_CONSOLE* Console, 273 IN BOOLEAN LockConsole) 274 { 275 NTSTATUS Status = STATUS_INVALID_HANDLE; 276 PCONSRV_CONSOLE GrabConsole; 277 278 // if (Console == NULL) return STATUS_INVALID_PARAMETER; 279 ASSERT(Console); 280 *Console = NULL; 281 282 if (ConSrvValidateConsole(&GrabConsole, 283 ProcessData->ConsoleHandle, 284 CONSOLE_RUNNING, 285 LockConsole)) 286 { 287 InterlockedIncrement(&GrabConsole->ReferenceCount); 288 *Console = GrabConsole; 289 Status = STATUS_SUCCESS; 290 } 291 292 return Status; 293 } 294 295 VOID 296 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console, 297 IN BOOLEAN IsConsoleLocked) 298 { 299 LONG RefCount = 0; 300 301 if (!Console) return; 302 // if (Console->ReferenceCount == 0) return; // This shouldn't happen 303 ASSERT(Console->ReferenceCount > 0); 304 305 /* The console must be locked */ 306 // ASSERT(Console_locked); 307 308 /* 309 * Decrement the reference count. Save the new value too, 310 * because Console->ReferenceCount might be modified after 311 * the console gets unlocked but before we check whether we 312 * can destroy it. 313 */ 314 RefCount = _InterlockedDecrement(&Console->ReferenceCount); 315 316 /* Unlock the console if needed */ 317 if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock); 318 319 /* Delete the console if needed */ 320 if (RefCount <= 0) ConSrvDeleteConsole(Console); 321 } 322 323 324 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/ 325 326 VOID NTAPI 327 ConSrvInitConsoleSupport(VOID) 328 { 329 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n"); 330 331 /* Initialize the console list and its lock */ 332 ConsoleListSize = 0; 333 ConsoleList = NULL; 334 RtlInitializeResource(&ListLock); 335 336 /* Should call LoadKeyboardLayout */ 337 } 338 339 NTSTATUS NTAPI 340 ConSrvInitTerminal(IN OUT PTERMINAL Terminal, 341 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 342 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 343 IN HANDLE ConsoleLeaderProcessHandle); 344 NTSTATUS NTAPI 345 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal); 346 347 348 static BOOL 349 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 350 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo) 351 { 352 #define PATH_SEPARATOR L'\\' 353 354 BOOL RetVal = FALSE; 355 HRESULT hRes = S_OK; 356 SIZE_T Length = 0; 357 LPWSTR LinkName = NULL; 358 LPWSTR IconPath = NULL; 359 WCHAR Buffer[MAX_PATH + 1]; 360 361 ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; 362 363 if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) 364 { 365 // return FALSE; // FIXME!! (for icon loading) 366 RetVal = TRUE; 367 goto Finish; 368 } 369 370 /* 1- Find the last path separator if any */ 371 LinkName = wcsrchr(ConsoleInfo->ConsoleTitle, PATH_SEPARATOR); 372 if (LinkName == NULL) 373 LinkName = ConsoleInfo->ConsoleTitle; 374 else 375 ++LinkName; // Skip the path separator 376 377 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */ 378 Length = wcslen(LinkName); 379 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) ) 380 return FALSE; 381 382 /* 3- It may be a link. Try to retrieve some properties */ 383 hRes = CoInitialize(NULL); 384 if (SUCCEEDED(hRes)) 385 { 386 /* Get a pointer to the IShellLink interface */ 387 IShellLinkW* pshl = NULL; 388 hRes = CoCreateInstance(&CLSID_ShellLink, 389 NULL, 390 CLSCTX_INPROC_SERVER, 391 &IID_IShellLinkW, 392 (LPVOID*)&pshl); 393 if (SUCCEEDED(hRes)) 394 { 395 /* Get a pointer to the IPersistFile interface */ 396 IPersistFile* ppf = NULL; 397 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf); 398 if (SUCCEEDED(hRes)) 399 { 400 /* Load the shortcut */ 401 hRes = IPersistFile_Load(ppf, ConsoleInfo->ConsoleTitle, STGM_READ); 402 if (SUCCEEDED(hRes)) 403 { 404 /* 405 * Finally we can get the properties ! 406 * Update the old ones if needed. 407 */ 408 INT ShowCmd = 0; 409 // WORD HotKey = 0; 410 411 /* Reset the name of the console with the name of the shortcut */ 412 Length = min(/*Length*/ Length - 4, // 4 == len(".lnk") 413 (ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR)); 414 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length); 415 ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL; 416 417 /* Get the window showing command */ 418 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd); 419 if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->wShowWindow = (WORD)ShowCmd; 420 421 /* Get the hotkey */ 422 // hRes = pshl->GetHotkey(&ShowCmd); 423 // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey; 424 425 /* Get the icon location, if any */ 426 hRes = IShellLinkW_GetIconLocation(pshl, 427 Buffer, 428 sizeof(Buffer)/sizeof(Buffer[0]) - 1, // == MAX_PATH 429 &ConsoleInitInfo->ConsoleStartInfo->IconIndex); 430 if (!SUCCEEDED(hRes)) 431 { 432 ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; 433 } 434 else 435 { 436 IconPath = Buffer; 437 } 438 439 // FIXME: Since we still don't load console properties from the shortcut, 440 // return false. When this will be done, we will return true instead. 441 RetVal = TRUE; // FALSE; 442 } 443 IPersistFile_Release(ppf); 444 } 445 IShellLinkW_Release(pshl); 446 } 447 } 448 CoUninitialize(); 449 450 Finish: 451 452 if (RetVal) 453 { 454 /* Get the associated icon, if any */ 455 if (IconPath == NULL) 456 { 457 // Question: How to retrieve the full path name 458 // of the app we are going to run?? 459 Length = RtlDosSearchPath_U(ConsoleInitInfo->CurDir, 460 ConsoleInitInfo->AppName, 461 NULL, 462 sizeof(Buffer), 463 Buffer, 464 NULL); 465 if (Length > 0 && Length < sizeof(Buffer)) 466 IconPath = Buffer; 467 else 468 IconPath = ConsoleInitInfo->AppName; 469 470 // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; 471 } 472 DPRINT("IconPath = '%S' ; IconIndex = %lu\n", 473 IconPath, ConsoleInitInfo->ConsoleStartInfo->IconIndex); 474 if (IconPath && *IconPath) 475 { 476 HICON hIcon = NULL, hIconSm = NULL; 477 /* 478 * FIXME!! Because of a strange bug we have in PrivateExtractIconExW 479 * (see r65683 for more details), we cannot use this API to extract 480 * at the same time the large and small icons from the app. 481 * Instead we just use PrivateExtractIconsW. 482 * 483 PrivateExtractIconExW(IconPath, 484 ConsoleInitInfo->ConsoleStartInfo->IconIndex, 485 &hIcon, 486 &hIconSm, 487 1); 488 */ 489 PrivateExtractIconsW(IconPath, 490 ConsoleInitInfo->ConsoleStartInfo->IconIndex, 491 32, 32, 492 &hIcon, NULL, 1, LR_COPYFROMRESOURCE); 493 PrivateExtractIconsW(IconPath, 494 ConsoleInitInfo->ConsoleStartInfo->IconIndex, 495 16, 16, 496 &hIconSm, NULL, 1, LR_COPYFROMRESOURCE); 497 498 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm); 499 if (hIcon != NULL) ConsoleInitInfo->ConsoleStartInfo->hIcon = hIcon; 500 if (hIconSm != NULL) ConsoleInitInfo->ConsoleStartInfo->hIconSm = hIconSm; 501 } 502 } 503 504 // FIXME: See the previous FIXME above. 505 RetVal = FALSE; 506 507 return RetVal; 508 } 509 510 NTSTATUS NTAPI 511 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, 512 OUT PCONSRV_CONSOLE* NewConsole, 513 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 514 IN PCSR_PROCESS ConsoleLeaderProcess) 515 { 516 NTSTATUS Status; 517 HANDLE ConsoleHandle; 518 PCONSRV_CONSOLE Console; 519 520 BYTE ConsoleInfoBuffer[sizeof(CONSOLE_STATE_INFO) + MAX_PATH * sizeof(WCHAR)]; // CONSRV console information 521 PCONSOLE_STATE_INFO ConsoleInfo = (PCONSOLE_STATE_INFO)&ConsoleInfoBuffer; 522 CONSOLE_INFO DrvConsoleInfo; // Console information for CONDRV 523 524 SIZE_T Length = 0; 525 526 TERMINAL Terminal; /* The ConSrv terminal for this console */ 527 528 if (NewConsole == NULL || ConsoleInitInfo == NULL) 529 return STATUS_INVALID_PARAMETER; 530 531 *NewConsole = NULL; 532 533 /* 534 * Load the console settings 535 */ 536 RtlZeroMemory(ConsoleInfo, sizeof(ConsoleInfoBuffer)); 537 ConsoleInfo->cbSize = sizeof(ConsoleInfoBuffer); 538 539 /* 1. Get the title of the console (initialize ConsoleInfo->ConsoleTitle) */ 540 Length = min(ConsoleInitInfo->TitleLength, 541 (ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR)); 542 wcsncpy(ConsoleInfo->ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length); 543 ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL; // NULL-terminate it. 544 545 /* 2. Impersonate the caller in order to retrieve settings in its context */ 546 if (!CsrImpersonateClient(NULL)) 547 return STATUS_BAD_IMPERSONATION_LEVEL; 548 549 /* 3. Load the default settings */ 550 ConCfgGetDefaultSettings(ConsoleInfo); 551 552 /* 553 * 4. Load per-application terminal settings. 554 * 555 * Check whether the process creating the console was launched via 556 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the 557 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too. 558 */ 559 // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading) 560 { 561 if (!LoadShellLinkConsoleInfo(ConsoleInfo, ConsoleInitInfo)) 562 { 563 ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; 564 } 565 } 566 567 /* 568 * 5. Load the remaining console settings via the registry. 569 */ 570 if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) 571 { 572 /* 573 * Either we weren't created by an app launched via a shell-link, 574 * or we failed to load shell-link console properties. 575 * Therefore, load the console infos for the application from the registry. 576 */ 577 ConCfgReadUserSettings(ConsoleInfo, FALSE); 578 579 /* 580 * Now, update them with the properties the user might gave to us 581 * via the STARTUPINFO structure before calling CreateProcess 582 * (and which was transmitted via the ConsoleStartInfo structure). 583 * We therefore overwrite the values read in the registry. 584 */ 585 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE) 586 { 587 ConsoleInfo->ScreenAttributes = (USHORT)ConsoleInitInfo->ConsoleStartInfo->wFillAttribute; 588 } 589 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS) 590 { 591 ConsoleInfo->ScreenBufferSize = ConsoleInitInfo->ConsoleStartInfo->dwScreenBufferSize; 592 } 593 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE) 594 { 595 ConsoleInfo->WindowSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize; 596 } 597 598 #if 0 599 /* 600 * Now, update them with the properties the user might gave to us 601 * via the STARTUPINFO structure before calling CreateProcess 602 * (and which was transmitted via the ConsoleStartInfo structure). 603 * We therefore overwrite the values read in the registry. 604 */ 605 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION) 606 { 607 ConsoleInfo->AutoPosition = FALSE; 608 ConsoleInfo->WindowPosition.x = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.X; 609 ConsoleInfo->WindowPosition.y = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.Y; 610 } 611 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) 612 { 613 ConsoleInfo->FullScreen = TRUE; 614 } 615 #endif 616 } 617 618 /* 6. Revert impersonation */ 619 CsrRevertToSelf(); 620 621 /* Set-up the code page */ 622 ConsoleInfo->CodePage = GetOEMCP(); 623 624 /* 625 * Initialize the ConSrv terminal and give it a chance to load 626 * its own settings and override the console settings. 627 */ 628 Status = ConSrvInitTerminal(&Terminal, 629 ConsoleInfo, 630 ConsoleInitInfo, 631 ConsoleLeaderProcess->ProcessHandle); 632 if (!NT_SUCCESS(Status)) 633 { 634 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status); 635 return Status; 636 } 637 DPRINT("CONSRV: Terminal initialized\n"); 638 639 /* Initialize a new console via the driver */ 640 // DrvConsoleInfo.InputBufferSize = 0; 641 DrvConsoleInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize; 642 DrvConsoleInfo.ConsoleSize = ConsoleInfo->WindowSize; 643 DrvConsoleInfo.CursorSize = ConsoleInfo->CursorSize; 644 // DrvConsoleInfo.CursorBlinkOn = ConsoleInfo->CursorBlinkOn; 645 DrvConsoleInfo.ScreenAttrib = ConsoleInfo->ScreenAttributes; 646 DrvConsoleInfo.PopupAttrib = ConsoleInfo->PopupAttributes; 647 DrvConsoleInfo.CodePage = ConsoleInfo->CodePage; 648 Status = ConDrvInitConsole(&Console, &DrvConsoleInfo); 649 if (!NT_SUCCESS(Status)) 650 { 651 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status); 652 ConSrvDeinitTerminal(&Terminal); 653 return Status; 654 } 655 656 ASSERT(Console); 657 DPRINT("Console initialized\n"); 658 659 /*** Register ConSrv features ***/ 660 661 /* Initialize the console title */ 662 #if 0 663 WCHAR DefaultTitle[128]; 664 #endif 665 ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle); 666 #if 0 667 if (ConsoleInfo->ConsoleTitle[0] == UNICODE_NULL) 668 { 669 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0]))) 670 { 671 ConsoleCreateUnicodeString(&Console->Title, DefaultTitle); 672 } 673 else 674 { 675 ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console"); 676 } 677 } 678 else 679 { 680 #endif 681 ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle); 682 #if 0 683 } 684 #endif 685 686 /* Initialize process support */ 687 InitializeListHead(&Console->ProcessList); 688 Console->NotifiedLastCloseProcess = NULL; 689 Console->NotifyLastClose = FALSE; 690 Console->HasFocus = FALSE; 691 692 /* Initialize pausing support */ 693 Console->PauseFlags = 0; 694 InitializeListHead(&Console->ReadWaitQueue); 695 InitializeListHead(&Console->WriteWaitQueue); 696 697 /* Initialize the alias and history buffers */ 698 Console->Aliases = NULL; 699 InitializeListHead(&Console->HistoryBuffers); 700 Console->HistoryBufferSize = ConsoleInfo->HistoryBufferSize; 701 Console->NumberOfHistoryBuffers = ConsoleInfo->NumberOfHistoryBuffers; 702 Console->HistoryNoDup = ConsoleInfo->HistoryNoDup; 703 704 /* Initialize the Input Line Discipline */ 705 Console->LineBuffer = NULL; 706 Console->LinePos = Console->LineMaxSize = Console->LineSize = 0; 707 Console->LineComplete = Console->LineUpPressed = FALSE; 708 // LineWakeupMask 709 Console->LineInsertToggle = 710 Console->InsertMode = ConsoleInfo->InsertMode; 711 Console->QuickEdit = ConsoleInfo->QuickEdit; 712 713 /* Popup windows */ 714 InitializeListHead(&Console->PopupWindows); 715 716 /* Colour table */ 717 RtlCopyMemory(Console->Colors, ConsoleInfo->ColorTable, 718 sizeof(ConsoleInfo->ColorTable)); 719 720 /* Create the Initialization Events */ 721 Status = NtCreateEvent(&Console->InitEvents[INIT_SUCCESS], EVENT_ALL_ACCESS, 722 NULL, NotificationEvent, FALSE); 723 if (!NT_SUCCESS(Status)) 724 { 725 DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); 726 ConDrvDeleteConsole(Console); 727 ConSrvDeinitTerminal(&Terminal); 728 return Status; 729 } 730 Status = NtCreateEvent(&Console->InitEvents[INIT_FAILURE], EVENT_ALL_ACCESS, 731 NULL, NotificationEvent, FALSE); 732 if (!NT_SUCCESS(Status)) 733 { 734 DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); 735 NtClose(Console->InitEvents[INIT_SUCCESS]); 736 ConDrvDeleteConsole(Console); 737 ConSrvDeinitTerminal(&Terminal); 738 return Status; 739 } 740 741 /* 742 * Attach the ConSrv terminal to the console. 743 * This call makes a copy of our local Terminal variable. 744 */ 745 Status = ConDrvAttachTerminal(Console, &Terminal); 746 if (!NT_SUCCESS(Status)) 747 { 748 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status); 749 NtClose(Console->InitEvents[INIT_FAILURE]); 750 NtClose(Console->InitEvents[INIT_SUCCESS]); 751 ConDrvDeleteConsole(Console); 752 ConSrvDeinitTerminal(&Terminal); 753 return Status; 754 } 755 DPRINT("Terminal attached\n"); 756 757 /* All went right, so add the console to the list */ 758 Status = InsertConsole(&ConsoleHandle, Console); 759 760 // FIXME! We do not support at all asynchronous console creation! 761 NtSetEvent(Console->InitEvents[INIT_SUCCESS], NULL); 762 // NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL); 763 764 /* Return the newly created console to the caller and a success code too */ 765 *NewConsoleHandle = ConsoleHandle; 766 *NewConsole = Console; 767 return STATUS_SUCCESS; 768 } 769 770 VOID NTAPI 771 ConSrvDeleteConsole(PCONSRV_CONSOLE Console) 772 { 773 DPRINT("ConSrvDeleteConsole\n"); 774 775 // FIXME: Send a terminate message to all the processes owning this console 776 777 /* Remove the console from the list */ 778 RemoveConsoleByPointer(Console); 779 780 /* Destroy the Initialization Events */ 781 NtClose(Console->InitEvents[INIT_FAILURE]); 782 NtClose(Console->InitEvents[INIT_SUCCESS]); 783 784 /* Clean the Input Line Discipline */ 785 if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer); 786 787 /* Clean aliases and history */ 788 IntDeleteAllAliases(Console); 789 HistoryDeleteBuffers(Console); 790 791 /* Free the console title */ 792 ConsoleFreeUnicodeString(&Console->OriginalTitle); 793 ConsoleFreeUnicodeString(&Console->Title); 794 795 /* Now, call the driver. ConDrvDetachTerminal is called on-demand. */ 796 ConDrvDeleteConsole((PCONSOLE)Console); 797 798 /* Deinit the ConSrv terminal */ 799 // FIXME!! 800 // ConSrvDeinitTerminal(&Terminal); 801 } 802 803 804 805 806 807 808 static NTSTATUS 809 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent, 810 IN PCONSOLE_PROCESS_DATA ProcessData, 811 IN ULONG Timeout) 812 { 813 NTSTATUS Status = STATUS_SUCCESS; 814 815 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess); 816 817 /* 818 * Be sure we effectively have a control routine. It resides in kernel32.dll (client). 819 */ 820 if (ProcessData->CtrlRoutine == NULL) return Status; 821 822 _SEH2_TRY 823 { 824 HANDLE Thread = NULL; 825 826 _SEH2_TRY 827 { 828 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, 829 ProcessData->CtrlRoutine, 830 UlongToPtr(CtrlEvent), 0, NULL); 831 if (NULL == Thread) 832 { 833 Status = RtlGetLastNtStatus(); 834 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status); 835 } 836 else 837 { 838 DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", 839 ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); 840 WaitForSingleObject(Thread, Timeout); 841 } 842 } 843 _SEH2_FINALLY 844 { 845 CloseHandle(Thread); 846 } 847 _SEH2_END; 848 } 849 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 850 { 851 Status = _SEH2_GetExceptionCode(); 852 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status); 853 } 854 _SEH2_END; 855 856 return Status; 857 } 858 859 NTSTATUS 860 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent, 861 IN PCONSOLE_PROCESS_DATA ProcessData) 862 { 863 return ConSrvConsoleCtrlEventTimeout(CtrlEvent, ProcessData, 0); 864 } 865 866 PCONSOLE_PROCESS_DATA NTAPI 867 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console) 868 { 869 if (Console == NULL) return NULL; 870 871 return CONTAINING_RECORD(Console->ProcessList.Blink, 872 CONSOLE_PROCESS_DATA, 873 ConsoleLink); 874 } 875 876 NTSTATUS NTAPI 877 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console, 878 IN OUT PULONG ProcessIdsList, 879 IN ULONG MaxIdListItems, 880 OUT PULONG ProcessIdsTotal) 881 { 882 PCONSOLE_PROCESS_DATA current; 883 PLIST_ENTRY current_entry; 884 885 if (Console == NULL || ProcessIdsList == NULL || ProcessIdsTotal == NULL) 886 return STATUS_INVALID_PARAMETER; 887 888 *ProcessIdsTotal = 0; 889 890 for (current_entry = Console->ProcessList.Flink; 891 current_entry != &Console->ProcessList; 892 current_entry = current_entry->Flink) 893 { 894 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); 895 if (++(*ProcessIdsTotal) <= MaxIdListItems) 896 { 897 *ProcessIdsList++ = HandleToUlong(current->Process->ClientId.UniqueProcess); 898 } 899 } 900 901 return STATUS_SUCCESS; 902 } 903 904 // ConSrvGenerateConsoleCtrlEvent 905 NTSTATUS NTAPI 906 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console, 907 IN ULONG ProcessGroupId, 908 IN ULONG CtrlEvent) 909 { 910 NTSTATUS Status = STATUS_SUCCESS; 911 PLIST_ENTRY current_entry; 912 PCONSOLE_PROCESS_DATA current; 913 914 /* If the console is already being destroyed, just return */ 915 if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING)) 916 return STATUS_UNSUCCESSFUL; 917 918 /* 919 * Loop through the process list, from the most recent process 920 * (the active one) to the oldest one (the first created, i.e. 921 * the console leader process), and for each, send an event 922 * (new processes are inserted at the head of the console process list). 923 */ 924 current_entry = Console->ProcessList.Flink; 925 while (current_entry != &Console->ProcessList) 926 { 927 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); 928 current_entry = current_entry->Flink; 929 930 /* 931 * Only processes belonging to the same process group are signaled. 932 * If the process group ID is zero, then all the processes are signaled. 933 */ 934 if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId) 935 { 936 Status = ConSrvConsoleCtrlEvent(CtrlEvent, current); 937 } 938 } 939 940 return Status; 941 } 942 943 VOID 944 ConSrvSetProcessFocus(IN PCSR_PROCESS CsrProcess, 945 IN BOOLEAN SetForeground) 946 { 947 // FIXME: Call NtUserSetInformationProcess (currently unimplemented!) 948 // for setting Win32 foreground/background flags. 949 950 if (SetForeground) 951 CsrSetForegroundPriority(CsrProcess); 952 else 953 CsrSetBackgroundPriority(CsrProcess); 954 } 955 956 NTSTATUS NTAPI 957 ConSrvSetConsoleProcessFocus(IN PCONSRV_CONSOLE Console, 958 IN BOOLEAN SetForeground) 959 { 960 PLIST_ENTRY current_entry; 961 PCONSOLE_PROCESS_DATA current; 962 963 /* If the console is already being destroyed, just return */ 964 if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING)) 965 return STATUS_UNSUCCESSFUL; 966 967 /* 968 * Loop through the process list, from the most recent process 969 * to the oldest one, and for each, set its foreground priority. 970 */ 971 current_entry = Console->ProcessList.Flink; 972 while (current_entry != &Console->ProcessList) 973 { 974 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); 975 current_entry = current_entry->Flink; 976 977 ConSrvSetProcessFocus(current->Process, SetForeground); 978 } 979 980 return STATUS_SUCCESS; 981 } 982 983 984 /* PUBLIC SERVER APIS *********************************************************/ 985 986 CSR_API(SrvAllocConsole) 987 { 988 NTSTATUS Status = STATUS_SUCCESS; 989 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest; 990 PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process; 991 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); 992 CONSOLE_INIT_INFO ConsoleInitInfo; 993 994 if (ProcessData->ConsoleHandle != NULL) 995 { 996 DPRINT1("Process already has a console\n"); 997 return STATUS_ACCESS_DENIED; 998 } 999 1000 if ( !CsrValidateMessageBuffer(ApiMessage, 1001 (PVOID*)&AllocConsoleRequest->ConsoleStartInfo, 1002 1, 1003 sizeof(CONSOLE_START_INFO)) || 1004 !CsrValidateMessageBuffer(ApiMessage, 1005 (PVOID*)&AllocConsoleRequest->ConsoleTitle, 1006 AllocConsoleRequest->TitleLength, 1007 sizeof(BYTE)) || 1008 !CsrValidateMessageBuffer(ApiMessage, 1009 (PVOID*)&AllocConsoleRequest->Desktop, 1010 AllocConsoleRequest->DesktopLength, 1011 sizeof(BYTE)) || 1012 !CsrValidateMessageBuffer(ApiMessage, 1013 (PVOID*)&AllocConsoleRequest->CurDir, 1014 AllocConsoleRequest->CurDirLength, 1015 sizeof(BYTE)) || 1016 !CsrValidateMessageBuffer(ApiMessage, 1017 (PVOID*)&AllocConsoleRequest->AppName, 1018 AllocConsoleRequest->AppNameLength, 1019 sizeof(BYTE)) ) 1020 { 1021 return STATUS_INVALID_PARAMETER; 1022 } 1023 1024 /* Initialize the console initialization info structure */ 1025 ConsoleInitInfo.ConsoleStartInfo = AllocConsoleRequest->ConsoleStartInfo; 1026 ConsoleInitInfo.IsWindowVisible = TRUE; // The console window is always visible. 1027 ConsoleInitInfo.TitleLength = AllocConsoleRequest->TitleLength; 1028 ConsoleInitInfo.ConsoleTitle = AllocConsoleRequest->ConsoleTitle; 1029 ConsoleInitInfo.DesktopLength = AllocConsoleRequest->DesktopLength; 1030 ConsoleInitInfo.Desktop = AllocConsoleRequest->Desktop; 1031 ConsoleInitInfo.AppNameLength = AllocConsoleRequest->AppNameLength; 1032 ConsoleInitInfo.AppName = AllocConsoleRequest->AppName; 1033 ConsoleInitInfo.CurDirLength = AllocConsoleRequest->CurDirLength; 1034 ConsoleInitInfo.CurDir = AllocConsoleRequest->CurDir; 1035 1036 /* Initialize a new Console owned by the Console Leader Process */ 1037 Status = ConSrvAllocateConsole(ProcessData, 1038 &AllocConsoleRequest->ConsoleStartInfo->InputHandle, 1039 &AllocConsoleRequest->ConsoleStartInfo->OutputHandle, 1040 &AllocConsoleRequest->ConsoleStartInfo->ErrorHandle, 1041 &ConsoleInitInfo); 1042 if (!NT_SUCCESS(Status)) 1043 { 1044 DPRINT1("Console allocation failed\n"); 1045 return Status; 1046 } 1047 1048 /* Set the Property-Dialog and Control-Dispatcher handlers */ 1049 ProcessData->PropRoutine = AllocConsoleRequest->PropRoutine; 1050 ProcessData->CtrlRoutine = AllocConsoleRequest->CtrlRoutine; 1051 1052 return STATUS_SUCCESS; 1053 } 1054 1055 CSR_API(SrvAttachConsole) 1056 { 1057 NTSTATUS Status = STATUS_SUCCESS; 1058 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest; 1059 PCSR_PROCESS SourceProcess = NULL; // The parent process. 1060 PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves. 1061 HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId); 1062 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData; 1063 1064 TargetProcessData = ConsoleGetPerProcessData(TargetProcess); 1065 1066 if (TargetProcessData->ConsoleHandle != NULL) 1067 { 1068 DPRINT1("Process already has a console\n"); 1069 return STATUS_ACCESS_DENIED; 1070 } 1071 1072 if (!CsrValidateMessageBuffer(ApiMessage, 1073 (PVOID*)&AttachConsoleRequest->ConsoleStartInfo, 1074 1, 1075 sizeof(CONSOLE_START_INFO))) 1076 { 1077 return STATUS_INVALID_PARAMETER; 1078 } 1079 1080 /* Check whether we try to attach to the parent's console */ 1081 if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS)) 1082 { 1083 PROCESS_BASIC_INFORMATION ProcessInfo; 1084 ULONG Length = sizeof(ProcessInfo); 1085 1086 /* Get the real parent's PID */ 1087 1088 Status = NtQueryInformationProcess(TargetProcess->ProcessHandle, 1089 ProcessBasicInformation, 1090 &ProcessInfo, 1091 Length, &Length); 1092 if (!NT_SUCCESS(Status)) 1093 { 1094 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = 0x%08lx\n", Status); 1095 return Status; 1096 } 1097 1098 ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId); 1099 } 1100 1101 /* Lock the source process via its PID */ 1102 Status = CsrLockProcessByClientId(ProcessId, &SourceProcess); 1103 if (!NT_SUCCESS(Status)) return Status; 1104 1105 SourceProcessData = ConsoleGetPerProcessData(SourceProcess); 1106 1107 if (SourceProcessData->ConsoleHandle == NULL) 1108 { 1109 Status = STATUS_INVALID_HANDLE; 1110 goto Quit; 1111 } 1112 1113 /* 1114 * Inherit the console from the parent, 1115 * if any, otherwise return an error. 1116 */ 1117 Status = ConSrvInheritConsole(TargetProcessData, 1118 SourceProcessData->ConsoleHandle, 1119 TRUE, 1120 &AttachConsoleRequest->ConsoleStartInfo->InputHandle, 1121 &AttachConsoleRequest->ConsoleStartInfo->OutputHandle, 1122 &AttachConsoleRequest->ConsoleStartInfo->ErrorHandle, 1123 AttachConsoleRequest->ConsoleStartInfo); 1124 if (!NT_SUCCESS(Status)) 1125 { 1126 DPRINT1("Console inheritance failed\n"); 1127 goto Quit; 1128 } 1129 1130 /* Set the Property-Dialog and Control-Dispatcher handlers */ 1131 TargetProcessData->PropRoutine = AttachConsoleRequest->PropRoutine; 1132 TargetProcessData->CtrlRoutine = AttachConsoleRequest->CtrlRoutine; 1133 1134 Status = STATUS_SUCCESS; 1135 1136 Quit: 1137 /* Unlock the "source" process and exit */ 1138 CsrUnlockProcess(SourceProcess); 1139 return Status; 1140 } 1141 1142 CSR_API(SrvFreeConsole) 1143 { 1144 return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process)); 1145 } 1146 1147 NTSTATUS NTAPI 1148 ConDrvGetConsoleMode(IN PCONSOLE Console, 1149 IN PCONSOLE_IO_OBJECT Object, 1150 OUT PULONG ConsoleMode); 1151 CSR_API(SrvGetConsoleMode) 1152 { 1153 NTSTATUS Status; 1154 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest; 1155 PCONSOLE_IO_OBJECT Object; 1156 1157 PULONG ConsoleMode = &ConsoleModeRequest->Mode; 1158 1159 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), 1160 ConsoleModeRequest->Handle, 1161 &Object, NULL, GENERIC_READ, TRUE, 0); 1162 if (!NT_SUCCESS(Status)) return Status; 1163 1164 /* Get the standard console modes */ 1165 Status = ConDrvGetConsoleMode(Object->Console, Object, 1166 ConsoleMode); 1167 if (NT_SUCCESS(Status)) 1168 { 1169 /* 1170 * If getting the console modes succeeds, then retrieve 1171 * the extended CONSRV-specific input modes. 1172 */ 1173 if (INPUT_BUFFER == Object->Type) 1174 { 1175 if (Object->Console->InsertMode || Object->Console->QuickEdit) 1176 { 1177 /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */ 1178 *ConsoleMode |= ENABLE_EXTENDED_FLAGS; 1179 1180 if (Object->Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE; 1181 if (Object->Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE; 1182 } 1183 } 1184 } 1185 1186 ConSrvReleaseObject(Object, TRUE); 1187 return Status; 1188 } 1189 1190 NTSTATUS NTAPI 1191 ConDrvSetConsoleMode(IN PCONSOLE Console, 1192 IN PCONSOLE_IO_OBJECT Object, 1193 IN ULONG ConsoleMode); 1194 CSR_API(SrvSetConsoleMode) 1195 { 1196 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \ 1197 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE ) 1198 1199 NTSTATUS Status; 1200 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest; 1201 PCONSOLE_IO_OBJECT Object; 1202 1203 ULONG ConsoleMode = ConsoleModeRequest->Mode; 1204 1205 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), 1206 ConsoleModeRequest->Handle, 1207 &Object, NULL, GENERIC_WRITE, TRUE, 0); 1208 if (!NT_SUCCESS(Status)) return Status; 1209 1210 /* Set the standard console modes (without the CONSRV-specific input modes) */ 1211 ConsoleMode &= ~CONSOLE_VALID_CONTROL_MODES; // Remove CONSRV-specific input modes. 1212 Status = ConDrvSetConsoleMode(Object->Console, Object, 1213 ConsoleMode); 1214 if (NT_SUCCESS(Status)) 1215 { 1216 /* 1217 * If setting the console modes succeeds, then set 1218 * the extended CONSRV-specific input modes. 1219 */ 1220 if (INPUT_BUFFER == Object->Type) 1221 { 1222 ConsoleMode = ConsoleModeRequest->Mode; 1223 1224 if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) 1225 { 1226 /* 1227 * If we use control mode flags without ENABLE_EXTENDED_FLAGS, 1228 * then consider the flags invalid. 1229 */ 1230 if ((ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0) 1231 { 1232 Status = STATUS_INVALID_PARAMETER; 1233 } 1234 else 1235 { 1236 Object->Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE); 1237 Object->Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE); 1238 } 1239 } 1240 } 1241 } 1242 1243 ConSrvReleaseObject(Object, TRUE); 1244 return Status; 1245 } 1246 1247 CSR_API(SrvGetConsoleTitle) 1248 { 1249 NTSTATUS Status; 1250 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; 1251 PCONSRV_CONSOLE Console; 1252 ULONG Length; 1253 1254 if (!CsrValidateMessageBuffer(ApiMessage, 1255 (PVOID)&TitleRequest->Title, 1256 TitleRequest->Length, 1257 sizeof(BYTE))) 1258 { 1259 return STATUS_INVALID_PARAMETER; 1260 } 1261 1262 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1263 if (!NT_SUCCESS(Status)) 1264 { 1265 DPRINT1("Can't get console, status %lx\n", Status); 1266 return Status; 1267 } 1268 1269 /* Copy title of the console to the user title buffer */ 1270 if (TitleRequest->Unicode) 1271 { 1272 if (TitleRequest->Length >= sizeof(WCHAR)) 1273 { 1274 Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length); 1275 RtlCopyMemory(TitleRequest->Title, Console->Title.Buffer, Length); 1276 ((PWCHAR)TitleRequest->Title)[Length / sizeof(WCHAR)] = UNICODE_NULL; 1277 TitleRequest->Length = Length; 1278 } 1279 else 1280 { 1281 TitleRequest->Length = Console->Title.Length; 1282 } 1283 } 1284 else 1285 { 1286 if (TitleRequest->Length >= sizeof(CHAR)) 1287 { 1288 Length = min(TitleRequest->Length - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR)); 1289 Length = WideCharToMultiByte(Console->InputCodePage, 0, 1290 Console->Title.Buffer, Length, 1291 TitleRequest->Title, Length, 1292 NULL, NULL); 1293 ((PCHAR)TitleRequest->Title)[Length] = ANSI_NULL; 1294 TitleRequest->Length = Length; 1295 } 1296 else 1297 { 1298 TitleRequest->Length = Console->Title.Length / sizeof(WCHAR); 1299 } 1300 } 1301 1302 ConSrvReleaseConsole(Console, TRUE); 1303 return Status; 1304 } 1305 1306 CSR_API(SrvSetConsoleTitle) 1307 { 1308 NTSTATUS Status; 1309 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; 1310 PCONSRV_CONSOLE Console; 1311 1312 PWCHAR Buffer; 1313 ULONG Length; 1314 1315 if (!CsrValidateMessageBuffer(ApiMessage, 1316 (PVOID)&TitleRequest->Title, 1317 TitleRequest->Length, 1318 sizeof(BYTE))) 1319 { 1320 return STATUS_INVALID_PARAMETER; 1321 } 1322 1323 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1324 if (!NT_SUCCESS(Status)) 1325 { 1326 DPRINT1("Can't get console, status %lx\n", Status); 1327 return Status; 1328 } 1329 1330 if (TitleRequest->Unicode) 1331 { 1332 /* Length is in bytes */ 1333 Length = TitleRequest->Length; 1334 } 1335 else 1336 { 1337 /* Use the console input CP for the conversion */ 1338 Length = MultiByteToWideChar(Console->InputCodePage, 0, 1339 TitleRequest->Title, TitleRequest->Length, 1340 NULL, 0); 1341 /* The returned Length was in number of wchars, convert it in bytes */ 1342 Length *= sizeof(WCHAR); 1343 } 1344 1345 /* Allocate a new buffer to hold the new title (NULL-terminated) */ 1346 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR)); 1347 if (!Buffer) 1348 { 1349 Status = STATUS_NO_MEMORY; 1350 goto Quit; 1351 } 1352 1353 /* Free the old title */ 1354 ConsoleFreeUnicodeString(&Console->Title); 1355 1356 /* Copy title to console */ 1357 Console->Title.Buffer = Buffer; 1358 Console->Title.Length = Length; 1359 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR); 1360 1361 if (TitleRequest->Unicode) 1362 { 1363 RtlCopyMemory(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length); 1364 } 1365 else 1366 { 1367 MultiByteToWideChar(Console->InputCodePage, 0, 1368 TitleRequest->Title, TitleRequest->Length, 1369 Console->Title.Buffer, 1370 Console->Title.Length / sizeof(WCHAR)); 1371 } 1372 1373 /* NULL-terminate */ 1374 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = UNICODE_NULL; 1375 1376 TermChangeTitle(Console); 1377 Status = STATUS_SUCCESS; 1378 1379 Quit: 1380 ConSrvReleaseConsole(Console, TRUE); 1381 return Status; 1382 } 1383 1384 NTSTATUS NTAPI 1385 ConDrvGetConsoleCP(IN PCONSOLE Console, 1386 OUT PUINT CodePage, 1387 IN BOOLEAN OutputCP); 1388 CSR_API(SrvGetConsoleCP) 1389 { 1390 NTSTATUS Status; 1391 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCPRequest; 1392 PCONSRV_CONSOLE Console; 1393 1394 DPRINT("SrvGetConsoleCP, getting %s Code Page\n", 1395 GetConsoleCPRequest->OutputCP ? "Output" : "Input"); 1396 1397 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1398 if (!NT_SUCCESS(Status)) return Status; 1399 1400 Status = ConDrvGetConsoleCP(Console, 1401 &GetConsoleCPRequest->CodePage, 1402 GetConsoleCPRequest->OutputCP); 1403 1404 ConSrvReleaseConsole(Console, TRUE); 1405 return Status; 1406 } 1407 1408 NTSTATUS NTAPI 1409 ConDrvSetConsoleCP(IN PCONSOLE Console, 1410 IN UINT CodePage, 1411 IN BOOLEAN OutputCP); 1412 CSR_API(SrvSetConsoleCP) 1413 { 1414 NTSTATUS Status = STATUS_INVALID_PARAMETER; 1415 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCPRequest; 1416 PCONSRV_CONSOLE Console; 1417 1418 DPRINT("SrvSetConsoleCP, setting %s Code Page\n", 1419 SetConsoleCPRequest->OutputCP ? "Output" : "Input"); 1420 1421 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1422 if (!NT_SUCCESS(Status)) return Status; 1423 1424 Status = ConDrvSetConsoleCP(Console, 1425 SetConsoleCPRequest->CodePage, 1426 SetConsoleCPRequest->OutputCP); 1427 1428 ConSrvReleaseConsole(Console, TRUE); 1429 return Status; 1430 } 1431 1432 CSR_API(SrvGetConsoleProcessList) 1433 { 1434 NTSTATUS Status; 1435 PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest; 1436 PCONSRV_CONSOLE Console; 1437 1438 if (!CsrValidateMessageBuffer(ApiMessage, 1439 (PVOID)&GetProcessListRequest->ProcessIdsList, 1440 GetProcessListRequest->ProcessCount, 1441 sizeof(DWORD))) 1442 { 1443 return STATUS_INVALID_PARAMETER; 1444 } 1445 1446 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1447 if (!NT_SUCCESS(Status)) return Status; 1448 1449 Status = ConSrvGetConsoleProcessList(Console, 1450 GetProcessListRequest->ProcessIdsList, 1451 GetProcessListRequest->ProcessCount, 1452 &GetProcessListRequest->ProcessCount); 1453 1454 ConSrvReleaseConsole(Console, TRUE); 1455 return Status; 1456 } 1457 1458 CSR_API(SrvGenerateConsoleCtrlEvent) 1459 { 1460 NTSTATUS Status; 1461 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest; 1462 PCONSRV_CONSOLE Console; 1463 1464 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1465 if (!NT_SUCCESS(Status)) return Status; 1466 1467 Status = ConSrvConsoleProcessCtrlEvent(Console, 1468 GenerateCtrlEventRequest->ProcessGroupId, 1469 GenerateCtrlEventRequest->CtrlEvent); 1470 1471 ConSrvReleaseConsole(Console, TRUE); 1472 return Status; 1473 } 1474 1475 CSR_API(SrvConsoleNotifyLastClose) 1476 { 1477 NTSTATUS Status; 1478 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 1479 PCONSRV_CONSOLE Console; 1480 1481 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 1482 if (!NT_SUCCESS(Status)) return Status; 1483 1484 /* Only one process is allowed to be registered for last close notification */ 1485 if (!Console->NotifyLastClose) 1486 { 1487 Console->NotifyLastClose = TRUE; 1488 Console->NotifiedLastCloseProcess = ProcessData; 1489 Status = STATUS_SUCCESS; 1490 } 1491 else 1492 { 1493 Status = STATUS_ACCESS_DENIED; 1494 } 1495 1496 ConSrvReleaseConsole(Console, TRUE); 1497 return Status; 1498 } 1499 1500 1501 1502 CSR_API(SrvGetConsoleMouseInfo) 1503 { 1504 NTSTATUS Status; 1505 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetMouseInfoRequest; 1506 PCONSRV_CONSOLE Console; 1507 1508 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1509 if (!NT_SUCCESS(Status)) return Status; 1510 1511 /* Just retrieve the number of buttons of the mouse attached to this console */ 1512 GetMouseInfoRequest->NumButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); 1513 1514 ConSrvReleaseConsole(Console, TRUE); 1515 return STATUS_SUCCESS; 1516 } 1517 1518 CSR_API(SrvSetConsoleKeyShortcuts) 1519 { 1520 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1521 return STATUS_NOT_IMPLEMENTED; 1522 } 1523 1524 CSR_API(SrvGetConsoleKeyboardLayoutName) 1525 { 1526 NTSTATUS Status; 1527 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetKbdLayoutNameRequest; 1528 PCONSRV_CONSOLE Console; 1529 1530 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); 1531 if (!NT_SUCCESS(Status)) return Status; 1532 1533 /* Retrieve the keyboard layout name of the system */ 1534 if (GetKbdLayoutNameRequest->Ansi) 1535 GetKeyboardLayoutNameA((PCHAR)GetKbdLayoutNameRequest->LayoutBuffer); 1536 else 1537 GetKeyboardLayoutNameW((PWCHAR)GetKbdLayoutNameRequest->LayoutBuffer); 1538 1539 ConSrvReleaseConsole(Console, TRUE); 1540 return STATUS_SUCCESS; 1541 } 1542 1543 CSR_API(SrvGetConsoleCharType) 1544 { 1545 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1546 return STATUS_NOT_IMPLEMENTED; 1547 } 1548 1549 CSR_API(SrvSetConsoleLocalEUDC) 1550 { 1551 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1552 return STATUS_NOT_IMPLEMENTED; 1553 } 1554 1555 CSR_API(SrvSetConsoleCursorMode) 1556 { 1557 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1558 return STATUS_NOT_IMPLEMENTED; 1559 } 1560 1561 CSR_API(SrvGetConsoleCursorMode) 1562 { 1563 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1564 return STATUS_NOT_IMPLEMENTED; 1565 } 1566 1567 CSR_API(SrvGetConsoleNlsMode) 1568 { 1569 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1570 return STATUS_NOT_IMPLEMENTED; 1571 } 1572 1573 CSR_API(SrvSetConsoleNlsMode) 1574 { 1575 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1576 return STATUS_NOT_IMPLEMENTED; 1577 } 1578 1579 CSR_API(SrvGetConsoleLangId) 1580 { 1581 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1582 return STATUS_NOT_IMPLEMENTED; 1583 } 1584 1585 /* EOF */ 1586