static PHISTORY_BUFFER HistoryCurrentBuffer(PCONSOLE Console) { /* TODO: use actual EXE name sent from process that called ReadConsole */ UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" }; PLIST_ENTRY Entry = Console->HistoryBuffers.Flink; PHISTORY_BUFFER Hist; for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink) { Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry); if (RtlEqualUnicodeString(&ExeName, &Hist->ExeName, FALSE)) return Hist; } /* Couldn't find the buffer, create a new one */ Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName.Length); if (!Hist) return NULL; Hist->MaxEntries = Console->HistoryBufferSize; Hist->NumEntries = 0; Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING)); if (!Hist->Entries) { ConsoleFreeHeap(Hist); return NULL; } Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length; Hist->ExeName.Buffer = (PWCHAR)(Hist + 1); memcpy(Hist->ExeName.Buffer, ExeName.Buffer, ExeName.Length); InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry); return Hist; }
BOOLEAN ConvertInputAnsiToUnicode(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, // BOOLEAN IsUnicode, PWCHAR* Target, PUSHORT TargetLength) { ASSERT(Source && Target && TargetLength); /* Use the console input CP for the conversion */ *TargetLength = MultiByteToWideChar(Console->InputCodePage, 0, Source, SourceLength, NULL, 0); *Target = ConsoleAllocHeap(0, *TargetLength * sizeof(WCHAR)); if (*Target == NULL) return FALSE; MultiByteToWideChar(Console->InputCodePage, 0, Source, SourceLength, *Target, *TargetLength); /* The returned Length was in number of WCHARs, convert it in bytes */ *TargetLength *= sizeof(WCHAR); return TRUE; }
NTSTATUS TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, IN PCONSOLE Console, IN HANDLE ProcessHandle, IN PTEXTMODE_BUFFER_INFO TextModeInfo) { NTSTATUS Status = STATUS_SUCCESS; PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL; UNREFERENCED_PARAMETER(ProcessHandle); if (Console == NULL || Buffer == NULL || TextModeInfo == NULL) return STATUS_INVALID_PARAMETER; *Buffer = NULL; Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer, Console, &TextVtbl, sizeof(TEXTMODE_SCREEN_BUFFER)); if (!NT_SUCCESS(Status)) return Status; NewBuffer->Header.Type = TEXTMODE_BUFFER; NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, TextModeInfo->ScreenBufferSize.X * TextModeInfo->ScreenBufferSize.Y * sizeof(CHAR_INFO)); if (NewBuffer->Buffer == NULL) { CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); return STATUS_INSUFFICIENT_RESOURCES; } NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize = TextModeInfo->ScreenBufferSize; NewBuffer->ViewSize = NewBuffer->OldViewSize = Console->ConsoleSize; NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0; NewBuffer->VirtualY = 0; NewBuffer->CursorBlinkOn = NewBuffer->ForceCursorOff = FALSE; NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0)); NewBuffer->CursorInfo.dwSize = min(max(TextModeInfo->CursorSize, 0), 100); NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib; NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib; /* Initialize buffer to be empty with default attributes */ for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++) { ClearLineBuffer(NewBuffer); } NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0; NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer; return STATUS_SUCCESS; }
static NTSTATUS WaitBeforeReading(IN PGET_INPUT_INFO InputInfo, IN PCSR_API_MESSAGE ApiMessage, IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL, IN BOOL CreateWaitBlock OPTIONAL) { if (CreateWaitBlock) { PGET_INPUT_INFO CapturedInputInfo; CapturedInputInfo = ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO)); if (!CapturedInputInfo) return STATUS_NO_MEMORY; RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO)); if (!CsrCreateWait(&InputInfo->InputBuffer->ReadWaitQueue, WaitFunction, InputInfo->CallingThread, ApiMessage, CapturedInputInfo, NULL)) { ConsoleFreeHeap(CapturedInputInfo); return STATUS_NO_MEMORY; } } /* Wait for input */ return STATUS_PENDING; }
NTSTATUS NTAPI ConSrvInitTerminal(IN OUT PTERMINAL Terminal, IN OUT PCONSOLE_INFO ConsoleInfo, IN OUT PVOID ExtraConsoleInfo, IN ULONG ProcessId) { NTSTATUS Status; PFRONTEND FrontEnd; /* Load a suitable frontend for the ConSrv terminal */ FrontEnd = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*FrontEnd)); if (!FrontEnd) return STATUS_NO_MEMORY; Status = ConSrvLoadFrontEnd(FrontEnd, ConsoleInfo, ExtraConsoleInfo, ProcessId); if (!NT_SUCCESS(Status)) { DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status); ConsoleFreeHeap(FrontEnd); return Status; } DPRINT("CONSRV: Frontend initialized\n"); /* Initialize the ConSrv terminal */ Terminal->Vtbl = &ConSrvTermVtbl; // Terminal->Console will be initialized by ConDrvRegisterTerminal Terminal->Context = FrontEnd; /* We store the frontend pointer in the terminal private context */ return STATUS_SUCCESS; }
NTSTATUS FASTCALL ConioProcessInputEvent(PCONSOLE Console, PINPUT_RECORD InputEvent) { ConsoleInput *ConInRec; /* Check for pause or unpause */ if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown) { WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode; if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD)) { DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState; if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT && (vk == VK_PAUSE || (vk == 'S' && (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))))) { ConioPause(Console, PAUSED_FROM_KEYBOARD); return STATUS_SUCCESS; } } else { if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN && vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL) { ConioUnpause(Console, PAUSED_FROM_KEYBOARD); return STATUS_SUCCESS; } } } /* Add event to the queue */ ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput)); if (ConInRec == NULL) return STATUS_INSUFFICIENT_RESOURCES; ConInRec->InputEvent = *InputEvent; InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry); SetEvent(Console->InputBuffer.ActiveEvent); CsrNotifyWait(&Console->InputBuffer.ReadWaitQueue, WaitAny, NULL, NULL); if (!IsListEmpty(&Console->InputBuffer.ReadWaitQueue)) { CsrDereferenceWait(&Console->InputBuffer.ReadWaitQueue); } return STATUS_SUCCESS; }
NTSTATUS ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, IN PCONSOLE_PROCESS_DATA TargetProcessData) { NTSTATUS Status = STATUS_SUCCESS; ULONG i, j; RtlEnterCriticalSection(&SourceProcessData->HandleTableLock); /* Inherit a handles table only if there is no already */ if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */) { Status = STATUS_UNSUCCESSFUL; goto Quit; } /* Allocate a new handle table for the child process */ TargetProcessData->HandleTable = ConsoleAllocHeap(HEAP_ZERO_MEMORY, SourceProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE)); if (TargetProcessData->HandleTable == NULL) { Status = STATUS_NO_MEMORY; goto Quit; } TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; /* * Parse the parent process' handles table and, for each handle, * do a copy of it and reference it, if the handle is inheritable. */ for (i = 0, j = 0; i < SourceProcessData->HandleTableSize; i++) { if (SourceProcessData->HandleTable[i].Object != NULL && SourceProcessData->HandleTable[i].Inheritable) { /* * Copy the handle data and increment the reference count of the * pointed object (via the call to ConSrvCreateHandleEntry == AdjustHandleCounts). */ TargetProcessData->HandleTable[j] = SourceProcessData->HandleTable[i]; AdjustHandleCounts(&TargetProcessData->HandleTable[j], +1); ++j; } } Quit: RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); return Status; }
/* Code taken and adapted from base/system/services/driver.c */ static DWORD ScmLoadDriver(LPCWSTR lpServiceName) { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN WasPrivilegeEnabled = FALSE; PWSTR pszDriverPath; UNICODE_STRING DriverPath; /* Build the driver path */ /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY, (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR)); if (pszDriverPath == NULL) return ERROR_NOT_ENOUGH_MEMORY; wcscpy(pszDriverPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); wcscat(pszDriverPath, lpServiceName); RtlInitUnicodeString(&DriverPath, pszDriverPath); DPRINT(" Path: %wZ\n", &DriverPath); /* Acquire driver-loading privilege */ Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE, FALSE, &WasPrivilegeEnabled); if (!NT_SUCCESS(Status)) { /* We encountered a failure, exit properly */ DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status); goto done; } Status = NtLoadDriver(&DriverPath); /* Release driver-loading privilege */ RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, WasPrivilegeEnabled, FALSE, &WasPrivilegeEnabled); done: ConsoleFreeHeap(pszDriverPath); return RtlNtStatusToDosError(Status); }
PALIAS_HEADER IntCreateAliasHeader(LPCWSTR lpExeName) { PALIAS_HEADER Entry; UINT dwLength = wcslen(lpExeName) + 1; Entry = ConsoleAllocHeap(0, sizeof(ALIAS_HEADER) + sizeof(WCHAR) * dwLength); if (!Entry) return Entry; Entry->lpExeName = (LPCWSTR)(Entry + 1); wcscpy((PWCHAR)Entry->lpExeName, lpExeName); Entry->Data = NULL; Entry->Next = NULL; return Entry; }
NTSTATUS CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, IN OUT PCONSOLE Console, IN SIZE_T Size) { if (Buffer == NULL || Console == NULL) return STATUS_INVALID_PARAMETER; *Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, max(sizeof(CONSOLE_SCREEN_BUFFER), Size)); if (*Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES; /* Initialize the header with the default type */ ConSrvInitObject(&(*Buffer)->Header, SCREEN_BUFFER, Console); (*Buffer)->Vtbl = NULL; return STATUS_SUCCESS; }
static PALIAS_HEADER IntCreateAliasHeader(PCONSRV_CONSOLE Console, PVOID ExeName, USHORT ExeLength, BOOLEAN UnicodeExe) { UNICODE_STRING ExeNameU; PALIAS_HEADER Entry; if (ExeName == NULL) return NULL; if (UnicodeExe) { ExeNameU.Buffer = ExeName; /* Length is in bytes */ ExeNameU.MaximumLength = ExeLength; } else { if (!ConvertInputAnsiToUnicode(Console, ExeName, ExeLength, &ExeNameU.Buffer, &ExeNameU.MaximumLength)) { return NULL; } } ExeNameU.Length = ExeNameU.MaximumLength; Entry = ConsoleAllocHeap(0, sizeof(ALIAS_HEADER) + ExeNameU.Length); if (!Entry) { if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer); return Entry; } Entry->ExeName.Buffer = (PWSTR)(Entry + 1); Entry->ExeName.Length = 0; Entry->ExeName.MaximumLength = ExeNameU.Length; RtlCopyUnicodeString(&Entry->ExeName, &ExeNameU); Entry->Data = NULL; Entry->Next = NULL; if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer); return Entry; }
PALIAS_ENTRY IntCreateAliasEntry(LPCWSTR lpSource, LPCWSTR lpTarget) { UINT dwSource; UINT dwTarget; PALIAS_ENTRY Entry; dwSource = wcslen(lpSource) + 1; dwTarget = wcslen(lpTarget) + 1; Entry = ConsoleAllocHeap(0, sizeof(ALIAS_ENTRY) + sizeof(WCHAR) * (dwSource + dwTarget)); if (!Entry) return Entry; Entry->lpSource = (LPCWSTR)(Entry + 1); wcscpy((LPWSTR)Entry->lpSource, lpSource); Entry->lpTarget = Entry->lpSource + dwSource; wcscpy((LPWSTR)Entry->lpTarget, lpTarget); Entry->Next = NULL; return Entry; }
static VOID WINAPI TuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region) { DWORD BytesReturned; PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; PCONSOLE_DRAW ConsoleDraw; UINT ConsoleDrawSize; if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return; ConsoleDrawSize = sizeof(CONSOLE_DRAW) + (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize); if (NULL == ConsoleDraw) { DPRINT1("ConsoleAllocHeap failed\n"); return; } ConsoleDraw->X = Region->Left; ConsoleDraw->Y = Region->Top; ConsoleDraw->SizeX = ConioRectWidth(Region); ConsoleDraw->SizeY = ConioRectHeight(Region); ConsoleDraw->CursorX = Buff->CursorPosition.X; ConsoleDraw->CursorY = Buff->CursorPosition.Y; TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) { DPRINT1("Failed to draw console\n"); ConsoleFreeHeap(ConsoleDraw); return; } ConsoleFreeHeap(ConsoleDraw); }
NTSTATUS NTAPI TuiInitFrontEnd(IN OUT PFRONTEND This, IN PCONSOLE Console) { PTUI_CONSOLE_DATA TuiData; HANDLE ThreadHandle; if (This == NULL || Console == NULL) return STATUS_INVALID_PARAMETER; // if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) // return STATUS_INVALID_PARAMETER; // /* Initialize the console */ // Console->TermIFace.Vtbl = &TuiVtbl; TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); if (!TuiData) { DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); return STATUS_UNSUCCESSFUL; } // Console->TermIFace.Data = (PVOID)TuiData; TuiData->Console = Console; TuiData->hWindow = NULL; InitializeCriticalSection(&TuiData->Lock); /* * HACK: Resize the console since we don't support for now changing * the console size when we display it with the hardware. */ // Console->ConsoleSize = PhysicalConsoleSize; // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); // /* The console cannot be resized anymore */ // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! // // ConioResizeTerminal(Console); /* * Contrary to what we do in the GUI front-end, here we create * an input thread for each console. It will dispatch all the * input messages to the proper console (on the GUI it is done * via the default GUI dispatch thread). */ ThreadHandle = CreateThread(NULL, 0, TuiConsoleThread, (PVOID)TuiData, 0, NULL); if (NULL == ThreadHandle) { DPRINT1("CONSRV: Unable to create console thread\n"); // TuiDeinitFrontEnd(Console); TuiDeinitFrontEnd(This); return STATUS_UNSUCCESSFUL; } CloseHandle(ThreadHandle); /* * Insert the newly created console in the list of virtual consoles * and activate it (give it the focus). */ EnterCriticalSection(&ActiveVirtConsLock); InsertTailList(&VirtConsList, &TuiData->Entry); ActiveConsole = TuiData; LeaveCriticalSection(&ActiveVirtConsLock); /* Finally, initialize the frontend structure */ This->Data = TuiData; This->OldData = NULL; return STATUS_SUCCESS; }
static BOOL FASTCALL TuiSwapConsole(INT Next) { static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */ DWORD BytesReturned; ANSI_STRING Title; PVOID Buffer; PCOORD pos; if (0 != Next) { /* * Alt-Tab, swap consoles. * move SwapConsole to next console, and print its title. */ EnterCriticalSection(&ActiveVirtConsLock); if (!SwapConsole) SwapConsole = ActiveConsole; SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole)); Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title); Title.Length = 0; Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength); pos = (PCOORD)Buffer; Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD)); RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE); pos->X = (PhysicalConsoleSize.X - Title.Length) / 2; pos->Y = PhysicalConsoleSize.Y / 2; /* Redraw the console to clear off old title */ ConioDrawConsole(ActiveConsole->Console); if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, NULL, 0, Buffer, sizeof(COORD) + Title.Length, &BytesReturned, NULL)) { DPRINT1( "Error writing to console\n" ); } ConsoleFreeHeap(Buffer); LeaveCriticalSection(&ActiveVirtConsLock); return TRUE; } else if (NULL != SwapConsole) { EnterCriticalSection(&ActiveVirtConsLock); if (SwapConsole != ActiveConsole) { /* First remove swapconsole from the list */ SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink; SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink; /* Now insert before activeconsole */ SwapConsole->Entry.Flink = &ActiveConsole->Entry; SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink; ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry; ActiveConsole->Entry.Blink = &SwapConsole->Entry; } ActiveConsole = SwapConsole; SwapConsole = NULL; ConioDrawConsole(ActiveConsole->Console); LeaveCriticalSection(&ActiveVirtConsLock); return TRUE; } else { return FALSE; } }
NTSTATUS ConioResizeBuffer(PCONSOLE Console, PTEXTMODE_SCREEN_BUFFER ScreenBuffer, COORD Size) { PCHAR_INFO Buffer; DWORD Offset = 0; PCHAR_INFO ptr; WORD CurrentAttribute; USHORT CurrentY; PCHAR_INFO OldBuffer; DWORD i; DWORD diff; /* Buffer size is not allowed to be smaller than the view size */ if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y) return STATUS_INVALID_PARAMETER; if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y) { // FIXME: Trigger a buffer resize event ?? return STATUS_SUCCESS; } if (Console->FixedSize) { /* * The console is in fixed-size mode, so we cannot resize anything * at the moment. However, keep those settings somewhere so that * we can try to set them up when we will be allowed to do so. */ ScreenBuffer->OldScreenBufferSize = Size; return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS } Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO)); if (!Buffer) return STATUS_NO_MEMORY; DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y); OldBuffer = ScreenBuffer->Buffer; for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++) { ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY); if (Size.X <= ScreenBuffer->ScreenBufferSize.X) { /* Reduce size */ RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO)); Offset += Size.X; } else { /* Enlarge size */ RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO)); Offset += ScreenBuffer->ScreenBufferSize.X; /* The attribute to be used is the one of the last cell of the current line */ CurrentAttribute = ConioCoordToPointer(ScreenBuffer, ScreenBuffer->ScreenBufferSize.X - 1, CurrentY)->Attributes; diff = Size.X - ScreenBuffer->ScreenBufferSize.X; /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = CurrentAttribute; ++Offset; } } } if (Size.Y > ScreenBuffer->ScreenBufferSize.Y) { diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y); /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib; ++Offset; } } (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer); ConsoleFreeHeap(OldBuffer); ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size; ScreenBuffer->VirtualY = 0; /* Ensure cursor and window are within buffer */ if (ScreenBuffer->CursorPosition.X >= Size.X) ScreenBuffer->CursorPosition.X = Size.X - 1; if (ScreenBuffer->CursorPosition.Y >= Size.Y) ScreenBuffer->CursorPosition.Y = Size.Y - 1; if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X) ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X; if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y) ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y; /* * Trigger a buffer resize event */ if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT) { ULONG NumEventsWritten; INPUT_RECORD er; er.EventType = WINDOW_BUFFER_SIZE_EVENT; er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize; // ConioProcessInputEvent(Console, &er); ConDrvWriteConsoleInput(Console, &Console->InputBuffer, TRUE, &er, 1, &NumEventsWritten); } return STATUS_SUCCESS; }
NTSTATUS ConSrvInsertObject(IN PCONSOLE_PROCESS_DATA ProcessData, OUT PHANDLE Handle, IN PCONSOLE_IO_OBJECT Object, IN ULONG Access, IN BOOLEAN Inheritable, IN ULONG ShareMode) { #define IO_HANDLES_INCREMENT 2 * 3 ULONG i = 0; PCONSOLE_IO_HANDLE Block; // NOTE: Commented out because calling code always lock HandleTableLock before. // RtlEnterCriticalSection(&ProcessData->HandleTableLock); ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); if (ProcessData->HandleTable) { for (i = 0; i < ProcessData->HandleTableSize; i++) { if (ProcessData->HandleTable[i].Object == NULL) break; } } if (i >= ProcessData->HandleTableSize) { /* Allocate a new handles table */ Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY, (ProcessData->HandleTableSize + IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE)); if (Block == NULL) { // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_UNSUCCESSFUL; } /* If we previously had a handles table, free it and use the new one */ if (ProcessData->HandleTable) { /* Copy the handles from the old table to the new one */ RtlCopyMemory(Block, ProcessData->HandleTable, ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE)); ConsoleFreeHeap(ProcessData->HandleTable); } ProcessData->HandleTable = Block; ProcessData->HandleTableSize += IO_HANDLES_INCREMENT; } ProcessData->HandleTable[i].Object = Object; ProcessData->HandleTable[i].Access = Access; ProcessData->HandleTable[i].Inheritable = Inheritable; ProcessData->HandleTable[i].ShareMode = ShareMode; AdjustHandleCounts(&ProcessData->HandleTable[i], +1); *Handle = ULongToHandle((i << 2) | 0x3); // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; }
NTSTATUS ConDrvAddInputEvents(PCONSOLE Console, PINPUT_RECORD InputRecords, // InputEvent ULONG NumEventsToWrite, PULONG NumEventsWritten, BOOLEAN AppendToEnd) { NTSTATUS Status = STATUS_SUCCESS; ULONG i = 0; BOOLEAN SetWaitEvent = FALSE; if (NumEventsWritten) *NumEventsWritten = 0; /* * When adding many single events, in the case of repeated mouse move or * key down events, we try to coalesce them so that we do not saturate * too quickly the input buffer. */ if (NumEventsToWrite == 1 && !IsListEmpty(&Console->InputBuffer.InputEvents)) { PINPUT_RECORD InputRecord = InputRecords; // Only one element PINPUT_RECORD LastInputRecord; ConsoleInput* ConInRec; // Input /* Get the "next" event of the input buffer */ if (AppendToEnd) { /* Get the tail element */ ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Blink, ConsoleInput, ListEntry); } else { /* Get the head element */ ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Flink, ConsoleInput, ListEntry); } LastInputRecord = &ConInRec->InputEvent; if (InputRecord->EventType == MOUSE_EVENT && InputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED) { if (LastInputRecord->EventType == MOUSE_EVENT && LastInputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED) { /* Update the mouse position */ LastInputRecord->Event.MouseEvent.dwMousePosition.X = InputRecord->Event.MouseEvent.dwMousePosition.X; LastInputRecord->Event.MouseEvent.dwMousePosition.Y = InputRecord->Event.MouseEvent.dwMousePosition.Y; i = 1; // return STATUS_SUCCESS; Status = STATUS_SUCCESS; } } else if (InputRecord->EventType == KEY_EVENT && InputRecord->Event.KeyEvent.bKeyDown) { if (LastInputRecord->EventType == KEY_EVENT && LastInputRecord->Event.KeyEvent.bKeyDown && (LastInputRecord->Event.KeyEvent.wVirtualScanCode == // Same scancode InputRecord->Event.KeyEvent.wVirtualScanCode) && (LastInputRecord->Event.KeyEvent.uChar.UnicodeChar == // Same character InputRecord->Event.KeyEvent.uChar.UnicodeChar) && (LastInputRecord->Event.KeyEvent.dwControlKeyState == // Same Ctrl/Alt/Shift state InputRecord->Event.KeyEvent.dwControlKeyState) ) { /* Update the repeat count */ LastInputRecord->Event.KeyEvent.wRepeatCount += InputRecord->Event.KeyEvent.wRepeatCount; i = 1; // return STATUS_SUCCESS; Status = STATUS_SUCCESS; } } } /* If we coalesced the only one element, we can quit */ if (i == 1 && Status == STATUS_SUCCESS /* && NumEventsToWrite == 1 */) goto Done; /* * No event coalesced, add them in the usual way. */ if (AppendToEnd) { /* Go to the beginning of the list */ // InputRecords = InputRecords; } else { /* Go to the end of the list */ InputRecords = &InputRecords[NumEventsToWrite - 1]; } /* Set the event if the list is going to be non-empty */ if (IsListEmpty(&Console->InputBuffer.InputEvents)) SetWaitEvent = TRUE; for (i = 0; i < NumEventsToWrite && NT_SUCCESS(Status); ++i) { PINPUT_RECORD InputRecord; ConsoleInput* ConInRec; if (AppendToEnd) { /* Select the event and go to the next one */ InputRecord = InputRecords++; } else { /* Select the event and go to the previous one */ InputRecord = InputRecords--; } /* Add event to the queue */ ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput)); if (ConInRec == NULL) { // return STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES; continue; } ConInRec->InputEvent = *InputRecord; if (AppendToEnd) { /* Append the event to the end of the queue */ InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry); } else { /* Append the event to the beginning of the queue */ InsertHeadList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry); } // return STATUS_SUCCESS; Status = STATUS_SUCCESS; } if (SetWaitEvent) SetEvent(Console->InputBuffer.ActiveEvent); Done: if (NumEventsWritten) *NumEventsWritten = i; return Status; }
NTSTATUS NTAPI ConDrvReadConsole(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN Unicode, OUT PVOID Buffer, IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, IN ULONG NumCharsToRead, OUT PULONG NumCharsRead OPTIONAL) { // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait. NTSTATUS Status = STATUS_PENDING; PLIST_ENTRY CurrentEntry; ConsoleInput *Input; ULONG i = ReadControl->nInitialChars; if (Console == NULL || InputBuffer == NULL || /* Buffer == NULL || */ ReadControl == NULL || ReadControl->nLength != sizeof(CONSOLE_READCONSOLE_CONTROL)) { return STATUS_INVALID_PARAMETER; } /* Validity checks */ ASSERT(Console == InputBuffer->Header.Console); ASSERT( (Buffer != NULL && NumCharsToRead >= 0) || (Buffer == NULL && NumCharsToRead == 0) ); /* We haven't read anything (yet) */ if (InputBuffer->Mode & ENABLE_LINE_INPUT) { if (Console->LineBuffer == NULL) { /* Starting a new line */ Console->LineMaxSize = (WORD)max(256, NumCharsToRead); Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR)); if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY; Console->LineComplete = FALSE; Console->LineUpPressed = FALSE; Console->LineInsertToggle = 0; Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask; Console->LineSize = ReadControl->nInitialChars; Console->LinePos = Console->LineSize; /* * Pre-filling the buffer is only allowed in the Unicode API, * so we don't need to worry about ANSI <-> Unicode conversion. */ memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR)); if (Console->LineSize == Console->LineMaxSize) { Console->LineComplete = TRUE; Console->LinePos = 0; } } /* If we don't have a complete line yet, process the pending input */ while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents)) { /* Remove input event from queue */ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); if (IsListEmpty(&InputBuffer->InputEvents)) { ResetEvent(InputBuffer->ActiveEvent); } Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); /* Only pay attention to key down */ if (Input->InputEvent.EventType == KEY_EVENT && Input->InputEvent.Event.KeyEvent.bKeyDown) { LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent); ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState; } ConsoleFreeHeap(Input); } /* Check if we have a complete line to read from */ if (Console->LineComplete) { while (i < NumCharsToRead && Console->LinePos != Console->LineSize) { WCHAR Char = Console->LineBuffer[Console->LinePos++]; if (Unicode) { ((PWCHAR)Buffer)[i] = Char; } else { ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); } ++i; } if (Console->LinePos == Console->LineSize) { /* Entire line has been read */ ConsoleFreeHeap(Console->LineBuffer); Console->LineBuffer = NULL; } Status = STATUS_SUCCESS; } } else { /* Character input */ while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents)) { /* Remove input event from queue */ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); if (IsListEmpty(&InputBuffer->InputEvents)) { ResetEvent(InputBuffer->ActiveEvent); } Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); /* Only pay attention to valid ASCII chars, on key down */ if (Input->InputEvent.EventType == KEY_EVENT && Input->InputEvent.Event.KeyEvent.bKeyDown && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0') { WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar; if (Unicode) { ((PWCHAR)Buffer)[i] = Char; } else { ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); } ++i; /* Did read something */ Status = STATUS_SUCCESS; } ConsoleFreeHeap(Input); } } if (NumCharsRead) *NumCharsRead = i; return Status; }
static NTSTATUS NTAPI ConSrvTermReadStream(IN OUT PTERMINAL This, IN BOOLEAN Unicode, /**PWCHAR Buffer,**/ OUT PVOID Buffer, IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, IN PVOID Parameter OPTIONAL, IN ULONG NumCharsToRead, OUT PULONG NumCharsRead OPTIONAL) { PFRONTEND FrontEnd = This->Context; PCONSRV_CONSOLE Console = FrontEnd->Console; PCONSOLE_INPUT_BUFFER InputBuffer = &Console->InputBuffer; PUNICODE_STRING ExeName = Parameter; // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait. NTSTATUS Status = STATUS_PENDING; PLIST_ENTRY CurrentEntry; ConsoleInput *Input; ULONG i; /* Validity checks */ // ASSERT(Console == InputBuffer->Header.Console); ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0)); /* We haven't read anything (yet) */ i = ReadControl->nInitialChars; if (InputBuffer->Mode & ENABLE_LINE_INPUT) { /* COOKED mode, call the line discipline */ if (Console->LineBuffer == NULL) { /* Starting a new line */ Console->LineMaxSize = max(256, NumCharsToRead); Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR)); if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY; Console->LinePos = Console->LineSize = ReadControl->nInitialChars; Console->LineComplete = Console->LineUpPressed = FALSE; Console->LineInsertToggle = Console->InsertMode; Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask; /* * Pre-filling the buffer is only allowed in the Unicode API, * so we don't need to worry about ANSI <-> Unicode conversion. */ memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR)); if (Console->LineSize == Console->LineMaxSize) { Console->LineComplete = TRUE; Console->LinePos = 0; } } /* If we don't have a complete line yet, process the pending input */ while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents)) { /* Remove input event from queue */ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); if (IsListEmpty(&InputBuffer->InputEvents)) { ResetEvent(InputBuffer->ActiveEvent); } Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); /* Only pay attention to key down */ if (Input->InputEvent.EventType == KEY_EVENT && Input->InputEvent.Event.KeyEvent.bKeyDown) { LineInputKeyDown(Console, ExeName, &Input->InputEvent.Event.KeyEvent); ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState; } ConsoleFreeHeap(Input); } /* Check if we have a complete line to read from */ if (Console->LineComplete) { while (i < NumCharsToRead && Console->LinePos != Console->LineSize) { WCHAR Char = Console->LineBuffer[Console->LinePos++]; if (Unicode) { ((PWCHAR)Buffer)[i] = Char; } else { ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); } ++i; } if (Console->LinePos == Console->LineSize) { /* Entire line has been read */ ConsoleFreeHeap(Console->LineBuffer); Console->LineBuffer = NULL; } Status = STATUS_SUCCESS; } } else { /* RAW mode */ /* Character input */ while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents)) { /* Remove input event from queue */ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); if (IsListEmpty(&InputBuffer->InputEvents)) { ResetEvent(InputBuffer->ActiveEvent); } Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); /* Only pay attention to valid characters, on key down */ if (Input->InputEvent.EventType == KEY_EVENT && Input->InputEvent.Event.KeyEvent.bKeyDown && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0') { WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar; if (Unicode) { ((PWCHAR)Buffer)[i] = Char; } else { ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); } ++i; /* Did read something */ Status = STATUS_SUCCESS; } ConsoleFreeHeap(Input); } } // FIXME: Only set if Status == STATUS_SUCCESS ??? if (NumCharsRead) *NumCharsRead = i; return Status; }
NTSTATUS GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, IN OUT PCONSOLE Console, IN PGRAPHICS_BUFFER_INFO GraphicsInfo) { NTSTATUS Status = STATUS_SUCCESS; PGRAPHICS_SCREEN_BUFFER NewBuffer = NULL; LARGE_INTEGER SectionSize; ULONG ViewSize = 0; HANDLE ProcessHandle; if (Buffer == NULL || Console == NULL || GraphicsInfo == NULL) return STATUS_INVALID_PARAMETER; *Buffer = NULL; Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer, Console, sizeof(GRAPHICS_SCREEN_BUFFER)); if (!NT_SUCCESS(Status)) return Status; NewBuffer->Header.Type = GRAPHICS_BUFFER; NewBuffer->Vtbl = &GraphicsVtbl; /* * Remember the handle to the process so that we can close or unmap * correctly the allocated resources when the client releases the * screen buffer. */ ProcessHandle = CsrGetClientThread()->Process->ProcessHandle; NewBuffer->ClientProcess = ProcessHandle; /* Get infos from the graphics buffer information structure */ NewBuffer->BitMapInfoLength = GraphicsInfo->Info.dwBitMapInfoLength; NewBuffer->BitMapInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, NewBuffer->BitMapInfoLength); if (NewBuffer->BitMapInfo == NULL) { CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); return STATUS_INSUFFICIENT_RESOURCES; } /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */ if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight > 0) GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight = -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight; /* We do not use anything else than uncompressed bitmaps */ if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression != BI_RGB) { DPRINT1("biCompression == %d != BI_RGB, correct that!\n", GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression); GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression = BI_RGB; } RtlCopyMemory(NewBuffer->BitMapInfo, GraphicsInfo->Info.lpBitMapInfo, GraphicsInfo->Info.dwBitMapInfoLength); NewBuffer->BitMapUsage = GraphicsInfo->Info.dwUsage; /* Set the screen buffer size. Fight against overflows. */ if ( GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth <= 0xFFFF && -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight <= 0xFFFF ) { /* Be careful about the sign of biHeight */ NewBuffer->ScreenBufferSize.X = (SHORT)GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth ; NewBuffer->ScreenBufferSize.Y = (SHORT)-GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight; NewBuffer->OldViewSize = NewBuffer->ViewSize = NewBuffer->OldScreenBufferSize = NewBuffer->ScreenBufferSize; } else { Status = STATUS_INSUFFICIENT_RESOURCES; ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } /* * Create a mutex to synchronize bitmap memory access * between ourselves and the client. */ Status = NtCreateMutant(&NewBuffer->Mutex, MUTANT_ALL_ACCESS, NULL, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateMutant() failed: %lu\n", Status); ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } /* * Duplicate the Mutex for the client. We must keep a trace of it * so that we can close it when the client releases the screen buffer. */ Status = NtDuplicateObject(NtCurrentProcess(), NewBuffer->Mutex, ProcessHandle, &NewBuffer->ClientMutex, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { DPRINT1("NtDuplicateObject() failed: %lu\n", Status); NtClose(NewBuffer->Mutex); ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } /* * Create a memory section for the bitmap area, to share with the client. */ SectionSize.QuadPart = NewBuffer->BitMapInfo->bmiHeader.biSizeImage; Status = NtCreateSection(&NewBuffer->hSection, SECTION_ALL_ACCESS, NULL, &SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status); NtClose(NewBuffer->ClientMutex); NtClose(NewBuffer->Mutex); ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } /* * Create a view for our needs. */ ViewSize = 0; NewBuffer->BitMap = NULL; Status = NtMapViewOfSection(NewBuffer->hSection, NtCurrentProcess(), (PVOID*)&NewBuffer->BitMap, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status); NtClose(NewBuffer->hSection); NtClose(NewBuffer->ClientMutex); NtClose(NewBuffer->Mutex); ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } /* * Create a view for the client. We must keep a trace of it so that * we can unmap it when the client releases the screen buffer. */ ViewSize = 0; NewBuffer->ClientBitMap = NULL; Status = NtMapViewOfSection(NewBuffer->hSection, ProcessHandle, (PVOID*)&NewBuffer->ClientBitMap, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status); NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer->BitMap); NtClose(NewBuffer->hSection); NtClose(NewBuffer->ClientMutex); NtClose(NewBuffer->Mutex); ConsoleFreeHeap(NewBuffer->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); goto Quit; } NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0; NewBuffer->VirtualY = 0; NewBuffer->CursorBlinkOn = FALSE; NewBuffer->ForceCursorOff = TRUE; NewBuffer->CursorInfo.bVisible = FALSE; NewBuffer->CursorInfo.dwSize = 0; NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0; NewBuffer->Mode = 0; *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer; Status = STATUS_SUCCESS; Quit: return Status; }
static NTSTATUS NTAPI GuiInitFrontEnd(IN OUT PFRONTEND This, IN PCONSRV_CONSOLE Console) { PGUI_INIT_INFO GuiInitInfo; PGUI_CONSOLE_DATA GuiData; if (This == NULL || Console == NULL || This->Context2 == NULL) return STATUS_INVALID_PARAMETER; ASSERT(This->Console == Console); GuiInitInfo = This->Context2; /* Terminal data allocation */ GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData)); if (!GuiData) { DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n"); return STATUS_UNSUCCESSFUL; } /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */ GuiData->Console = Console; GuiData->ActiveBuffer = Console->ActiveBuffer; GuiData->hWindow = NULL; GuiData->IsWindowVisible = GuiInitInfo->IsWindowVisible; /* The console can be resized */ Console->FixedSize = FALSE; InitializeCriticalSection(&GuiData->Lock); /* * Set up GUI data */ RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo)); /* Initialize the icon handles */ if (GuiInitInfo->hIcon != NULL) GuiData->hIcon = GuiInitInfo->hIcon; else GuiData->hIcon = ghDefaultIcon; if (GuiInitInfo->hIconSm != NULL) GuiData->hIconSm = GuiInitInfo->hIconSm; else GuiData->hIconSm = ghDefaultIconSm; ASSERT(GuiData->hIcon && GuiData->hIconSm); /* Mouse is shown by default with its default cursor shape */ GuiData->hCursor = ghDefaultCursor; GuiData->MouseCursorRefCount = 0; /* A priori don't ignore mouse signals */ GuiData->IgnoreNextMouseSignal = FALSE; /* Initialize HACK FOR CORE-8394. See conwnd.c!OnMouse for more details. */ GuiData->HackCORE8394IgnoreNextMove = FALSE; /* Close button and the corresponding system menu item are enabled by default */ GuiData->IsCloseButtonEnabled = TRUE; /* There is no user-reserved menu id range by default */ GuiData->CmdIdLow = GuiData->CmdIdHigh = 0; /* Initialize the selection */ RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection)); GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION; RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor)); GuiData->LineSelection = FALSE; // Default to block selection // TODO: Retrieve the selection mode via the registry. GuiData->InputThreadId = GuiInitInfo->InputThreadId; GuiData->WinSta = GuiInitInfo->WinSta; GuiData->Desktop = GuiInitInfo->Desktop; /* Finally, finish to initialize the frontend structure */ This->Context = GuiData; ConsoleFreeHeap(This->Context2); This->Context2 = NULL; /* * We need to wait until the GUI has been fully initialized * to retrieve custom settings i.e. WindowSize etc... * Ideally we could use SendNotifyMessage for this but its not * yet implemented. */ NtCreateEvent(&GuiData->hGuiInitEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); NtCreateEvent(&GuiData->hGuiTermEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); DPRINT("GUI - Checkpoint\n"); /* Create the terminal window */ PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData); /* Wait until initialization has finished */ NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL); DPRINT("OK we created the console window\n"); NtClose(GuiData->hGuiInitEvent); GuiData->hGuiInitEvent = NULL; /* Check whether we really succeeded in initializing the terminal window */ if (GuiData->hWindow == NULL) { DPRINT("GuiInitConsole - We failed at creating a new terminal window\n"); GuiDeinitFrontEnd(This); return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; }
static PALIAS_ENTRY IntCreateAliasEntry(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, PVOID Target, USHORT TargetLength, BOOLEAN Unicode) { UNICODE_STRING SourceU; UNICODE_STRING TargetU; PALIAS_ENTRY Entry; if (Unicode) { SourceU.Buffer = Source; TargetU.Buffer = Target; /* Length is in bytes */ SourceU.MaximumLength = SourceLength; TargetU.MaximumLength = TargetLength; } else { if (!ConvertInputAnsiToUnicode(Console, Source, SourceLength, &SourceU.Buffer, &SourceU.MaximumLength)) { return NULL; } if (!ConvertInputAnsiToUnicode(Console, Target, TargetLength, &TargetU.Buffer, &TargetU.MaximumLength)) { ConsoleFreeHeap(SourceU.Buffer); return NULL; } } SourceU.Length = SourceU.MaximumLength; TargetU.Length = TargetU.MaximumLength; Entry = ConsoleAllocHeap(0, sizeof(ALIAS_ENTRY) + SourceU.Length + TargetU.Length); if (!Entry) { if (!Unicode) { ConsoleFreeHeap(TargetU.Buffer); ConsoleFreeHeap(SourceU.Buffer); } return Entry; } Entry->Source.Buffer = (PWSTR)(Entry + 1); Entry->Source.Length = 0; Entry->Source.MaximumLength = SourceU.Length; RtlCopyUnicodeString(&Entry->Source, &SourceU); Entry->Target.Buffer = (PWSTR)((ULONG_PTR)Entry->Source.Buffer + Entry->Source.MaximumLength); Entry->Target.Length = 0; Entry->Target.MaximumLength = TargetU.Length; RtlCopyUnicodeString(&Entry->Target, &TargetU); Entry->Next = NULL; if (!Unicode) { ConsoleFreeHeap(TargetU.Buffer); ConsoleFreeHeap(SourceU.Buffer); } return Entry; }
NTSTATUS NTAPI ConDrvInitConsole(OUT PCONSOLE* NewConsole, IN PCONSOLE_INFO ConsoleInfo) { NTSTATUS Status; // CONSOLE_INFO CapturedConsoleInfo; TEXTMODE_BUFFER_INFO ScreenBufferInfo; PCONSOLE Console; PCONSOLE_SCREEN_BUFFER NewBuffer; if (NewConsole == NULL || ConsoleInfo == NULL) return STATUS_INVALID_PARAMETER; *NewConsole = NULL; /* * Allocate a new console */ Console = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*Console)); if (NULL == Console) { DPRINT1("Not enough memory for console creation.\n"); return STATUS_NO_MEMORY; } /* * Fix the screen buffer size if needed. The rule is: * ScreenBufferSize >= ConsoleSize */ if (ConsoleInfo->ScreenBufferSize.X < ConsoleInfo->ConsoleSize.X) ConsoleInfo->ScreenBufferSize.X = ConsoleInfo->ConsoleSize.X; if (ConsoleInfo->ScreenBufferSize.Y < ConsoleInfo->ConsoleSize.Y) ConsoleInfo->ScreenBufferSize.Y = ConsoleInfo->ConsoleSize.Y; /* * Initialize the console */ Console->State = CONSOLE_INITIALIZING; Console->ReferenceCount = 0; InitializeCriticalSection(&Console->Lock); /* Initialize the terminal interface */ ResetTerminal(Console); Console->ConsoleSize = ConsoleInfo->ConsoleSize; Console->FixedSize = FALSE; // Value by default; is reseted by the terminals if needed. /* Initialize the input buffer */ Status = ConDrvInitInputBuffer(Console, 0 /* ConsoleInfo->InputBufferSize */); if (!NT_SUCCESS(Status)) { DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status); DeleteCriticalSection(&Console->Lock); ConsoleFreeHeap(Console); return Status; } /* Set-up the code page */ Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage; /* Initialize a new text-mode screen buffer with default settings */ ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize; ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib; ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib; ScreenBufferInfo.IsCursorVisible = TRUE; ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize; InitializeListHead(&Console->BufferList); Status = ConDrvCreateScreenBuffer(&NewBuffer, Console, NULL, CONSOLE_TEXTMODE_BUFFER, &ScreenBufferInfo); if (!NT_SUCCESS(Status)) { DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status); ConDrvDeinitInputBuffer(Console); DeleteCriticalSection(&Console->Lock); ConsoleFreeHeap(Console); return Status; } /* Make the new screen buffer active */ Console->ActiveBuffer = NewBuffer; Console->UnpauseEvent = NULL; DPRINT("Console initialized\n"); /* All went right, so add the console to the list */ Status = InsertConsole(Console); if (!NT_SUCCESS(Status)) { /* Fail */ ConDrvDeleteConsole(Console); return Status; } /* The initialization is finished */ DPRINT("Change state\n"); Console->State = CONSOLE_RUNNING; /* Return the newly created console to the caller and a success code too */ *NewConsole = Console; return STATUS_SUCCESS; }
NTSTATUS NTAPI ConSrvConnect(IN PCSR_PROCESS CsrProcess, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength) { /************************************************************************** * This function is called whenever a CUI new process is created. **************************************************************************/ NTSTATUS Status = STATUS_SUCCESS; PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); if ( ConnectionInfo == NULL || ConnectionInfoLength == NULL || *ConnectionInfoLength != sizeof(*ConnectInfo) ) { DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), expected %lu\n", ConnectionInfo, ConnectionInfoLength, ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1, sizeof(*ConnectInfo)); return STATUS_UNSUCCESSFUL; } /* If we don't need a console, then get out of here */ DPRINT("ConnectInfo->IsConsoleApp = %s\n", ConnectInfo->IsConsoleApp ? "True" : "False"); if (!ConnectInfo->IsConsoleApp) return STATUS_SUCCESS; /* If we don't inherit from an existing console, then create a new one... */ if (ConnectInfo->ConsoleStartInfo.ConsoleHandle == NULL) { CONSOLE_INIT_INFO ConsoleInitInfo; DPRINT("ConSrvConnect - Allocate a new console\n"); /* Initialize the console initialization info structure */ ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo; ConsoleInitInfo.IsWindowVisible = ConnectInfo->IsWindowVisible; ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength; ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle; ConsoleInitInfo.DesktopLength = 0; ConsoleInitInfo.Desktop = NULL; ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength; ConsoleInitInfo.AppName = ConnectInfo->AppName; ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength; ConsoleInitInfo.CurDir = ConnectInfo->CurDir; /* * Contrary to the case of SrvAllocConsole, the desktop string is * allocated in the process' heap, so we need to retrieve it by * using NtReadVirtualMemory. */ if (ConnectInfo->DesktopLength) { ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength; ConsoleInitInfo.Desktop = ConsoleAllocHeap(HEAP_ZERO_MEMORY, ConsoleInitInfo.DesktopLength); if (ConsoleInitInfo.Desktop == NULL) return STATUS_NO_MEMORY; Status = NtReadVirtualMemory(ProcessData->Process->ProcessHandle, ConnectInfo->Desktop, ConsoleInitInfo.Desktop, ConsoleInitInfo.DesktopLength, NULL); if (!NT_SUCCESS(Status)) { ConsoleFreeHeap(ConsoleInitInfo.Desktop); return Status; } } /* * We are about to create a new console. However when ConSrvNewProcess * was called, we didn't know that we wanted to create a new console and * therefore, we by default inherited the handles table from our parent * process. It's only now that we notice that in fact we do not need * them, because we've created a new console and thus we must use it. * * ConSrvAllocateConsole will free our old handles table * and recreate a new valid one. */ /* Initialize a new Console owned by the Console Leader Process */ Status = ConSrvAllocateConsole(ProcessData, &ConnectInfo->ConsoleStartInfo.InputHandle, &ConnectInfo->ConsoleStartInfo.OutputHandle, &ConnectInfo->ConsoleStartInfo.ErrorHandle, &ConsoleInitInfo); /* Free our local desktop string if any */ if (ConsoleInitInfo.DesktopLength) ConsoleFreeHeap(ConsoleInitInfo.Desktop); /* Check for success */ if (!NT_SUCCESS(Status)) { DPRINT1("Console allocation failed\n"); return Status; } } else /* We inherit it from the parent */ { DPRINT("ConSrvConnect - Reuse current (parent's) console\n"); /* Reuse our current console */ Status = ConSrvInheritConsole(ProcessData, ConnectInfo->ConsoleStartInfo.ConsoleHandle, FALSE, NULL, // &ConnectInfo->ConsoleStartInfo.InputHandle, NULL, // &ConnectInfo->ConsoleStartInfo.OutputHandle, NULL, // &ConnectInfo->ConsoleStartInfo.ErrorHandle, &ConnectInfo->ConsoleStartInfo); if (!NT_SUCCESS(Status)) { DPRINT1("Console inheritance failed\n"); return Status; } } /* Set the Property-Dialog and Control-Dispatcher handlers */ ProcessData->PropRoutine = ConnectInfo->PropRoutine; ProcessData->CtrlRoutine = ConnectInfo->CtrlRoutine; return STATUS_SUCCESS; }
NTSTATUS NTAPI GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, IN OUT PCONSOLE_STATE_INFO ConsoleInfo, IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle) { PCONSOLE_START_INFO ConsoleStartInfo; PGUI_INIT_INFO GuiInitInfo; if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL) return STATUS_INVALID_PARAMETER; ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo; /* * Initialize a private initialization info structure for later use. * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd. */ GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo)); if (GuiInitInfo == NULL) return STATUS_NO_MEMORY; /* Initialize GUI terminal emulator common functionalities */ if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo)) { ConsoleFreeHeap(GuiInitInfo); return STATUS_UNSUCCESSFUL; } /* * Load terminal settings */ #if 0 /* Impersonate the caller in order to retrieve settings in its context */ // if (!CsrImpersonateClient(NULL)) // return STATUS_UNSUCCESSFUL; CsrImpersonateClient(NULL); /* 1. Load the default settings */ GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo); #endif GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL; if (ConsoleInitInfo->IsWindowVisible) { /* 2. Load the remaining console settings via the registry */ if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) { #if 0 /* Load the terminal infos from the registry */ GuiConsoleReadUserSettings(&GuiInitInfo->TermInfo); #endif /* * Now, update them with the properties the user might gave to us * via the STARTUPINFO structure before calling CreateProcess * (and which was transmitted via the ConsoleStartInfo structure). * We therefore overwrite the values read in the registry. */ if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW) { GuiInitInfo->TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow; } if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION) { ConsoleInfo->AutoPosition = FALSE; ConsoleInfo->WindowPosition.x = ConsoleStartInfo->dwWindowOrigin.X; ConsoleInfo->WindowPosition.y = ConsoleStartInfo->dwWindowOrigin.Y; } if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) { ConsoleInfo->FullScreen = TRUE; } } } #if 0 /* Revert impersonation */ CsrRevertToSelf(); #endif // Font data wcsncpy(GuiInitInfo->TermInfo.FaceName, ConsoleInfo->FaceName, LF_FACESIZE); GuiInitInfo->TermInfo.FaceName[LF_FACESIZE - 1] = UNICODE_NULL; GuiInitInfo->TermInfo.FontFamily = ConsoleInfo->FontFamily; GuiInitInfo->TermInfo.FontSize = ConsoleInfo->FontSize; GuiInitInfo->TermInfo.FontWeight = ConsoleInfo->FontWeight; // Display GuiInitInfo->TermInfo.FullScreen = ConsoleInfo->FullScreen; // GuiInitInfo->TermInfo.ShowWindow; GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition; GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition; /* Initialize the icon handles */ // if (ConsoleStartInfo->hIcon != NULL) GuiInitInfo->hIcon = ConsoleStartInfo->hIcon; // else // GuiInitInfo->hIcon = ghDefaultIcon; // if (ConsoleStartInfo->hIconSm != NULL) GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm; // else // GuiInitInfo->hIconSm = ghDefaultIconSm; // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm); GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible; /* Finally, initialize the frontend structure */ FrontEnd->Vtbl = &GuiVtbl; FrontEnd->Context = NULL; FrontEnd->Context2 = GuiInitInfo; return STATUS_SUCCESS; }