VOID GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) { PGRAPHICS_SCREEN_BUFFER Buff = (PGRAPHICS_SCREEN_BUFFER)Buffer; /* * IMPORTANT !! Reinitialize the type so that we don't enter a recursive * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy. */ Buffer->Header.Type = SCREEN_BUFFER; /* * Uninitialize the graphics screen buffer * in the reverse way we initialized it. */ NtUnmapViewOfSection(Buff->ClientProcess, Buff->ClientBitMap); NtUnmapViewOfSection(NtCurrentProcess(), Buff->BitMap); NtClose(Buff->hSection); NtDuplicateObject(Buff->ClientProcess, Buff->ClientMutex, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); NtClose(Buff->Mutex); ConsoleFreeHeap(Buff->BitMapInfo); CONSOLE_SCREEN_BUFFER_Destroy(Buffer); }
static VOID HistoryDeleteBuffer(PHISTORY_BUFFER Hist) { if (!Hist) return; while (Hist->NumEntries != 0) RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]); ConsoleFreeHeap(Hist->Entries); RemoveEntryList(&Hist->ListEntry); ConsoleFreeHeap(Hist); }
static PALIAS_ENTRY IntGetAliasEntry(PCONSRV_CONSOLE Console, PALIAS_HEADER Header, PVOID Source, USHORT SourceLength, BOOLEAN Unicode) { UNICODE_STRING SourceU; PALIAS_ENTRY Entry; INT Diff; if (Header == NULL || Source == NULL) return NULL; if (Unicode) { SourceU.Buffer = Source; /* Length is in bytes */ SourceU.MaximumLength = SourceLength; } else { if (!ConvertInputAnsiToUnicode(Console, Source, SourceLength, &SourceU.Buffer, &SourceU.MaximumLength)) { return NULL; } } SourceU.Length = SourceU.MaximumLength; Entry = Header->Data; while (Entry) { Diff = RtlCompareUnicodeString(&Entry->Source, &SourceU, TRUE); if (!Diff) { if (!Unicode) ConsoleFreeHeap(SourceU.Buffer); return Entry; } if (Diff > 0) break; Entry = Entry->Next; } if (!Unicode) ConsoleFreeHeap(SourceU.Buffer); return NULL; }
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; }
// Wait function CSR_WAIT_FUNCTION static BOOLEAN ReadInputBufferThread(IN PLIST_ENTRY WaitList, IN PCSR_THREAD WaitThread, IN PCSR_API_MESSAGE WaitApiMessage, IN PVOID WaitContext, IN PVOID WaitArgument1, IN PVOID WaitArgument2, IN ULONG WaitFlags) { NTSTATUS Status; PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)WaitApiMessage)->Data.GetInputRequest; PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext; PVOID InputHandle = WaitArgument2; DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags); /* * If we are notified of the process termination via a call * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or * CsrDestroyThread, just return. */ if (WaitFlags & CsrProcessTerminating) { Status = STATUS_THREAD_IS_TERMINATING; goto Quit; } /* * Somebody is closing a handle to this input buffer, * by calling ConSrvCloseHandleEntry. * See whether we are linked to that handle (ie. we * are a waiter for this handle), and if so, return. * Otherwise, ignore the call and continue waiting. */ if (InputHandle != NULL) { Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED : STATUS_PENDING); goto Quit; } /* * If we go there, that means we are notified for some new input. * The console is therefore already locked. */ Status = ReadInputBuffer(InputInfo, GetInputRequest->bRead, WaitApiMessage, FALSE); Quit: if (Status != STATUS_PENDING) { WaitApiMessage->Status = Status; ConsoleFreeHeap(InputInfo); } return (Status == STATUS_PENDING ? FALSE : TRUE); }
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; }
static VOID ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData) { RtlEnterCriticalSection(&ProcessData->HandleTableLock); if (ProcessData->HandleTable != NULL) { ULONG i; /* * ProcessData->ConsoleHandle is NULL (and the assertion fails) when * ConSrvFreeHandlesTable is called in ConSrvConnect during the * allocation of a new console. */ // ASSERT(ProcessData->ConsoleHandle); if (ProcessData->ConsoleHandle != NULL) { /* Close all the console handles */ for (i = 0; i < ProcessData->HandleTableSize; i++) { ConSrvCloseHandle(&ProcessData->HandleTable[i]); } } /* Free the handles table memory */ ConsoleFreeHeap(ProcessData->HandleTable); ProcessData->HandleTable = NULL; } ProcessData->HandleTableSize = 0; RtlLeaveCriticalSection(&ProcessData->HandleTableLock); }
static VOID NTAPI GuiDeinitFrontEnd(IN OUT PFRONTEND This) { PGUI_CONSOLE_DATA GuiData = This->Context; DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n"); PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData); NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL); DPRINT("hGuiTermEvent set\n"); NtClose(GuiData->hGuiTermEvent); GuiData->hGuiTermEvent = NULL; CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n", GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm); if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon) { DPRINT("Destroy hIcon\n"); DestroyIcon(GuiData->hIcon); } if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm) { DPRINT("Destroy hIconSm\n"); DestroyIcon(GuiData->hIconSm); } This->Context = NULL; DeleteCriticalSection(&GuiData->Lock); ConsoleFreeHeap(GuiData); DPRINT("Quit GuiDeinitFrontEnd\n"); }
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; }
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; }
VOID IntDeleteAllAliases(PCONSRV_CONSOLE Console) { PALIAS_HEADER Header, NextHeader; PALIAS_ENTRY Entry, NextEntry; for (Header = Console->Aliases; Header; Header = NextHeader) { NextHeader = Header->Next; for (Entry = Header->Data; Entry; Entry = NextEntry) { NextEntry = Entry->Next; ConsoleFreeHeap(Entry); } ConsoleFreeHeap(Header); } }
static PALIAS_HEADER IntFindAliasHeader(PCONSRV_CONSOLE Console, PVOID ExeName, USHORT ExeLength, BOOLEAN UnicodeExe) { UNICODE_STRING ExeNameU; PALIAS_HEADER RootHeader = Console->Aliases; INT Diff; 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; while (RootHeader) { Diff = RtlCompareUnicodeString(&RootHeader->ExeName, &ExeNameU, TRUE); if (!Diff) { if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer); return RootHeader; } if (Diff > 0) break; RootHeader = RootHeader->Next; } if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer); return NULL; }
NTSTATUS NTAPI GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) { if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; if (FrontEnd->Context ) GuiDeinitFrontEnd(FrontEnd); if (FrontEnd->Context2) ConsoleFreeHeap(FrontEnd->Context2); return STATUS_SUCCESS; }
VOID CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) { if (Buffer->Header.Type == TEXTMODE_BUFFER) TEXTMODE_BUFFER_Destroy(Buffer); else if (Buffer->Header.Type == GRAPHICS_BUFFER) GRAPHICS_BUFFER_Destroy(Buffer); else if (Buffer->Header.Type == SCREEN_BUFFER) ConsoleFreeHeap(Buffer); // else // do_nothing; }
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); }
/* 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); }
VOID FASTCALL PurgeInputBuffer(PCONSOLE Console) { PLIST_ENTRY CurrentEntry; ConsoleInput* Event; while (!IsListEmpty(&Console->InputBuffer.InputEvents)) { CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents); Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); ConsoleFreeHeap(Event); } CloseHandle(Console->InputBuffer.ActiveEvent); }
VOID TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) { PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer; /* * IMPORTANT !! Reinitialize the type so that we don't enter a recursive * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy. */ Buffer->Header.Type = SCREEN_BUFFER; ConsoleFreeHeap(Buff->Buffer); CONSOLE_SCREEN_BUFFER_Destroy(Buffer); }
VOID IntDeleteAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY Entry) { PALIAS_ENTRY *LastLink = &Header->Data; PALIAS_ENTRY CurEntry; while ((CurEntry = *LastLink) != NULL) { if (CurEntry == Entry) { *LastLink = Entry->Next; ConsoleFreeHeap(Entry); return; } LastLink = &CurEntry->Next; } }
NTSTATUS NTAPI ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal) { NTSTATUS Status = STATUS_SUCCESS; PFRONTEND FrontEnd = Terminal->Context; /* Reset the ConSrv terminal */ Terminal->Context = NULL; Terminal->Vtbl = NULL; /* Unload the frontend */ if (FrontEnd != NULL) { Status = ConSrvUnloadFrontEnd(FrontEnd); ConsoleFreeHeap(FrontEnd); } return Status; }
static VOID WINAPI TuiDeinitFrontEnd(IN OUT PFRONTEND This) { // PCONSOLE Console = This->Console; PTUI_CONSOLE_DATA TuiData = This->Data; // Console->TermIFace.Data; /* Close the notification window */ DestroyWindow(TuiData->hWindow); /* * Set the active console to the next one * and remove the console from the list. */ EnterCriticalSection(&ActiveVirtConsLock); ActiveConsole = GetNextConsole(TuiData); RemoveEntryList(&TuiData->Entry); // /* Switch to next console */ // if (ActiveConsole == TuiData) // if (ActiveConsole->Console == Console) // { // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL); // } // if (GetNextConsole(TuiData) != TuiData) // { // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink; // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink; // } LeaveCriticalSection(&ActiveVirtConsLock); /* Switch to the next console */ if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console); // Console->TermIFace.Data = NULL; This->Data = NULL; DeleteCriticalSection(&TuiData->Lock); ConsoleFreeHeap(TuiData); }
VOID CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) { if (Buffer->Header.Type == TEXTMODE_BUFFER) { TEXTMODE_BUFFER_Destroy(Buffer); } else if (Buffer->Header.Type == GRAPHICS_BUFFER) { GRAPHICS_BUFFER_Destroy(Buffer); } else if (Buffer->Header.Type == SCREEN_BUFFER) { /* Free the palette handle */ if (Buffer->PaletteHandle != NULL) DeleteObject(Buffer->PaletteHandle); /* Free the screen buffer memory */ ConsoleFreeHeap(Buffer); } // else // do_nothing; }
NTSTATUS NTAPI ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer) { PLIST_ENTRY CurrentEntry; ConsoleInput* Event; if (Console == NULL || InputBuffer == NULL) return STATUS_INVALID_PARAMETER; /* Validity check */ ASSERT(Console == InputBuffer->Header.Console); /* Discard all entries in the input event queue */ while (!IsListEmpty(&InputBuffer->InputEvents)) { CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); ConsoleFreeHeap(Event); } ResetEvent(InputBuffer->ActiveEvent); 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; }
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; }
VOID NTAPI ConDrvDeleteConsole(IN PCONSOLE Console) { DPRINT("ConDrvDeleteConsole(0x%p)\n", Console); /* * Forbid validation of any console by other threads * during the deletion of this console. */ ConDrvLockConsoleListExclusive(); /* * If the console is already being destroyed, i.e. not running * or finishing to be initialized, just return. */ if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE) && !ConDrvValidateConsoleUnsafe(Console, CONSOLE_INITIALIZING, TRUE)) { /* Unlock the console list and return */ ConDrvUnlockConsoleList(); return; } /* * We are about to be destroyed. Signal it to other people * so that they can terminate what they are doing, and that * they cannot longer validate the console. */ Console->State = CONSOLE_TERMINATING; /* * Allow other threads to finish their job: basically, unlock * all other calls to EnterCriticalSection(&Console->Lock); by * ConDrvValidateConsoleUnsafe functions so that they just see * that we are not in CONSOLE_RUNNING state anymore, or unlock * other concurrent calls to ConDrvDeleteConsole so that they * can see that we are in fact already deleting the console. */ LeaveCriticalSection(&Console->Lock); ConDrvUnlockConsoleList(); /* Deregister the terminal */ DPRINT("Deregister terminal\n"); ConDrvDetachTerminal(Console); DPRINT("Terminal deregistered\n"); /*** * Check that the console is in terminating state before continuing * (the cleanup code must not change the state of the console... * ...unless to cancel console deletion ?). ***/ ConDrvLockConsoleListExclusive(); if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE)) { ConDrvUnlockConsoleList(); return; } /* We are now in destruction */ Console->State = CONSOLE_IN_DESTRUCTION; /* We really delete the console. Reset the count to be sure. */ Console->ReferenceCount = 0; /* Remove the console from the list */ RemoveConsole(Console); /* Delete the last screen buffer */ ConDrvDeleteScreenBuffer(Console->ActiveBuffer); Console->ActiveBuffer = NULL; if (!IsListEmpty(&Console->BufferList)) { /***ConDrvUnlockConsoleList();***/ ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE); } /* Deinitialize the input buffer */ ConDrvDeinitInputBuffer(Console); if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent); DPRINT("ConDrvDeleteConsole - Unlocking\n"); LeaveCriticalSection(&Console->Lock); DPRINT("ConDrvDeleteConsole - Destroying lock\n"); DeleteCriticalSection(&Console->Lock); DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n"); ConsoleFreeHeap(Console); DPRINT("ConDrvDeleteConsole - Console destroyed\n"); /* Unlock the console list and return */ ConDrvUnlockConsoleList(); }
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; }
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; }