const bool ConsoleUI::StartProgress(LPCTSTR pszText, HANDLE hevtCancel) { AutoCS autoLock(m_csProgress); // Automatic critical section object DWORD dwThreadId; // Launched progress thread id code if(!LockConsole()) return false; // Attempt to lock the console handles if(!m_hevtStop) { UnlockConsole(); return false; } // Test STOP event object m_hevtCancel = hevtCancel; // Store CANCEL event object // Display the standard PLEASE WAIT separator bar, and the progress message if(Separator(CONSOLE_HEADER_PROGRESS)) BlankLines(); if(WriteText(pszText)) BlankLines(); // Attempt to launch the progress worker thread that actually does all of // the real work for us m_hThread = SVCTL::CreateThread(NULL, 0, ProgressThreadProc, this, 0, &dwThreadId); if(!m_hThread) { UnlockConsole(); return false; } // NOTE : The call to UnlockConsole() happens in the StopProgress() function return true; }
void ConsoleUI::DeActivate(void) { CONSOLE_SCREEN_BUFFER_INFO conInfo; // Console screen buffer information if(!LockConsole(true)) return; // Wait for the console lock if(m_hin == m_hout) { UnlockConsole(); return; } // Console is not active // Revoke the console control handler, and destroy the CTRL+C event object SetConsoleCtrlHandler(ConsoleControlHandler, FALSE); if(s_hevtCtrlC) CloseHandle(s_hevtCtrlC); s_hevtCtrlC = NULL; // Restore the original console window caption if it had been altered if(!m_strSavedTitle.IsNull()) SetConsoleTitle(m_strSavedTitle); m_strSavedTitle.Clear(); // Restore the original console screen buffer width if it had been altered if(m_uSavedWidth) { GetConsoleScreenBufferInfo(m_hout, &conInfo); conInfo.dwSize.X = m_uSavedWidth; SetConsoleScreenBufferSize(m_hout, conInfo.dwSize); m_uSavedWidth = 0; } m_hin = m_hout = INVALID_HANDLE_VALUE; // Reset the STDIN/STDOUT handles UnlockConsole(); // Release the console lock }
DWORD ConsoleUI::Activate(LPCTSTR pszTitle) { CONSOLE_SCREEN_BUFFER_INFO conInfo; // Console screen buffer info Buffer<TCHAR> strConTitle; // Console title string buffer // Attempt to lock the console handles. The only way this can fail is if // the underlying kernel object(s) were not properly created if(!LockConsole(true)) return ERROR_INVALID_HANDLE; // Check to see if the input/output handles have already been initialized if(m_hin != m_hout) { UnlockConsole(); return ERROR_ALREADY_INITIALIZED; } // Retrieve the STDIN/STDOUT handles for this process. If they are both set // to INVALID_HANDLE_VALUE, this process is not attached to a console m_hin = GetStdHandle(STD_INPUT_HANDLE); m_hout = GetStdHandle(STD_OUTPUT_HANDLE); if(m_hin == m_hout) { UnlockConsole(); return ERROR_INVALID_HANDLE; } // There are some assumptions made about the width of the console, // so ensure that the screen buffer is at least CONSOLE_MIN_WIDTH wide if(GetConsoleScreenBufferInfo(m_hout, &conInfo)) { if(conInfo.dwSize.X < CONSOLE_MIN_WIDTH) { m_uSavedWidth = conInfo.dwSize.X; conInfo.dwSize.X = CONSOLE_MIN_WIDTH; SetConsoleScreenBufferSize(m_hout, conInfo.dwSize); } } // Change the console window title to reflect the application name if((pszTitle) && (strConTitle.Allocate(1025))) { if(GetConsoleTitle(strConTitle, 1024) > 0) { m_strSavedTitle = strConTitle; // Save the original title SetConsoleTitle(pszTitle); // Set the new title } } // Attempt to create the CTRL+C handler event object, and register the control // handler function to be used for this process s_hevtCtrlC = CreateEvent(NULL, FALSE, FALSE, NULL); SetConsoleCtrlHandler(ConsoleControlHandler, TRUE); BlankLines(); // Start out with a blank line UnlockConsole(); // Release the console lock return ERROR_SUCCESS; }
VOID FreeCon( IN HANDLE ConsoleHandle ) /*++ Routine Description: This routine frees a console and its associated data - input buffer and screen buffer. Arguments: ConsoleHandle - Handle of console to free. Return Value: Note: The console handle table lock must be held when calling this routine. --*/ { PCONSOLE_INFORMATION Console; NTSTATUS Status; HANDLE hWait; HWND hWnd; LARGE_INTEGER li; Status = DereferenceConsoleHandle(ConsoleHandle, &Console ); ASSERT (NT_SUCCESS(Status)); Console->Flags |= CONSOLE_TERMINATING; NtSetEvent(Console->TerminationEvent,NULL); hWnd = Console->hWnd; UnlockConsole(Console); // // Use an event to synchronize the window destruction with // the termination of the thread // if (hWnd != NULL) { Status = NtCreateEvent(&hWait, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); ASSERT(NT_SUCCESS(Status)); if (GetWindowThreadProcessId(hWnd, NULL) == (DWORD)NtCurrentTeb()->ClientId.UniqueThread) { DestroyWindowsWindow(Console,hWait); } else { PostMessage(hWnd, CM_DESTROY_WINDOW, (DWORD)hWait, 0); li.QuadPart = (LONGLONG)-10000 * 10000; NtWaitForSingleObject(hWait, FALSE, &li); } NtClose(hWait); } }
NTSTATUS ApiPreamble( IN HANDLE ConsoleHandle, OUT PCONSOLE_INFORMATION *Console ) { NTSTATUS Status; #ifdef _X86_ //Do not lock the console if we are in the special case: //(1). we are in the middle of handshaking with ntvdm doing // full-screen to windowed mode transition //(2). the calling process is THE ntvdm process(this implies that the // the console has vdm registered. //(3). the console handle is the same one. // if (1), (2) and (3) are true then the console is already locked // (locked by the windowproc while processing the WM_FULLSCREEN // message) RtlEnterCriticalSection(&ConsoleVDMCriticalSection); if (ConsoleVDMOnSwitching != NULL && ConsoleVDMOnSwitching->ConsoleHandle == ConsoleHandle && ConsoleVDMOnSwitching->VDMProcessId == CONSOLE_CLIENTPROCESSID()) { *Console = ConsoleVDMOnSwitching; return STATUS_SUCCESS; } RtlLeaveCriticalSection(&ConsoleVDMCriticalSection); #endif LockConsoleHandleTable(); Status = DereferenceConsoleHandle(ConsoleHandle, Console ); if (!NT_SUCCESS(Status)) { UnlockConsoleHandleTable(); return((ULONG) Status); } LockConsole(*Console); UnlockConsoleHandleTable(); // // Make sure the console has been initialized and the window is valid // if ((*Console)->hWnd == NULL || ((*Console)->Flags & CONSOLE_TERMINATING)) { KdPrint(("CONSRV: bogus window for console %lx\n", *Console)); UnlockConsole(*Console); return STATUS_INVALID_HANDLE; } return Status; }
const INT_PTR ConsoleUI::Message(UINT uType, LPCTSTR pszText) { INT_PTR nResult; // Result from function call // Attempt to lock the console, and default the response code if we cannot if(!LockConsole()) return DefaultUserResponse(uType, false); // Display the icon header and the message text in the console window if(InsertHeader(uType)) BlankLines(); if(WriteText(pszText)) BlankLines(); nResult = PromptUser(uType); // Prompt the user for their response BlankLines(); // Skip a line for neatness UnlockConsole(); // Release the console handle lock return nResult; // Return the user's response }
ULONG SrvVerifyConsoleIoHandle( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) /*++ Routine Description: This routine verifies that a console io handle is valid. Arguments: ApiMessageData - Points to parameter structure. Return Value: --*/ { PCONSOLE_VERIFYIOHANDLE_MSG a = (PCONSOLE_VERIFYIOHANDLE_MSG)&m->u.ApiMessageData; PCONSOLE_INFORMATION Console; NTSTATUS Status; PHANDLE_DATA HandleData; PCONSOLE_PER_PROCESS_DATA ProcessData; UNREFERENCED_PARAMETER(ReplyStatus); Status = ApiPreamble(a->ConsoleHandle, &Console ); if (NT_SUCCESS(Status)) { ProcessData = CONSOLE_PERPROCESSDATA(); Status = DereferenceIoHandleNoCheck(ProcessData, HANDLE_TO_INDEX(a->Handle), &HandleData ); UnlockConsole(Console); } a->Valid = (NT_SUCCESS(Status)); return STATUS_SUCCESS; }
const INT_PTR ConsoleUI::List(UINT uType, LPCTSTR pszHeader, LPCTSTR *rgszItems, DWORD cItems, LPCTSTR pszFooter) { String strItem; // Item text string object DWORD dwIndex; // Loop index variable INT_PTR nResult; // Result from function call // Attempt to lock the console, and default the response code if we cannot if(!LockConsole()) return DefaultUserResponse(uType, false); // Display the optional faux icon header string, and the list box header text if(InsertHeader(uType)) BlankLines(); if(pszHeader) { if(WriteText(pszHeader)) BlankLines(); } // Loop through the array of list items to display them in the console if(rgszItems) { for(dwIndex = 0; dwIndex < cItems; dwIndex++) { strItem = CONSOLE_BULLET; // Start with the bullet strItem += CONSOLE_SPACE; // Add in a space strItem += rgszItems[dwIndex]; // Finish with the text itself WriteText(strItem, CONSOLE_LIST_LMARGIN); } BlankLines(); // Finish up with a blank line } // Display the optional list box footer text before prompting the user if(pszFooter) { if(WriteText(pszFooter)) BlankLines(); } nResult = PromptUser(uType); // Prompt the user for their response BlankLines(); // Skip a line for neatness UnlockConsole(); // Release the console handle lock return nResult; // Return the user's response }
void ConsoleUI::StopProgress(void) { AutoCS autoLock(m_csProgress); // Automatic critical section // If the progress worker thread was successfully started, it needs to be // shut down, and the progress related variables need to be reset if(m_hThread) { // Signal the STOP event object, and wait for the thread to terminate SetEvent(m_hevtStop); WaitForSingleObject(m_hThread, INFINITE); m_hThread = NULL; // Reset the thread object handle m_hevtCancel = NULL; // Reset the event object handle BlankLines(); // Append a blank line to the output UnlockConsole(); // Unlock the lock acquired in StartProgress() } }
VOID PropertiesDlgShow( IN PCONSOLE_INFORMATION Console ) /*++ Displays the properties dialog and updates the window state, if necessary. --*/ { HANDLE hSection = NULL; HANDLE hClientSection = NULL; HANDLE hThread; ULONG ulViewSize; LARGE_INTEGER li; NTSTATUS Status; PCONSOLE_STATE_INFO pStateInfo; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PSCREEN_INFORMATION ScreenInfo; LPTHREAD_START_ROUTINE MyPropRoutine; /* * Create a shared memory block. */ li.QuadPart = sizeof(CONSOLE_STATE_INFO) + Console->OriginalTitleLength; Status = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &li, PAGE_READWRITE, SEC_COMMIT, NULL); if (!NT_SUCCESS(Status)) { KdPrint(("CONSRV: error %x creating file mapping\n", Status)); return; } /* * Get a pointer to the shared memory block. */ pStateInfo = NULL; ulViewSize = 0; Status = NtMapViewOfSection(hSection, NtCurrentProcess(), &pStateInfo, 0, 0, NULL, &ulViewSize, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { KdPrint(("CONSRV: error %x mapping view of file\n", Status)); NtClose(hSection); return; } /* * Fill in the shared memory block with the current values. */ ScreenInfo = Console->CurrentScreenBuffer; pStateInfo->Length = li.LowPart; pStateInfo->ScreenBufferSize = ScreenInfo->ScreenBufferSize; pStateInfo->WindowSize.X = CONSOLE_WINDOW_SIZE_X(ScreenInfo); pStateInfo->WindowSize.Y = CONSOLE_WINDOW_SIZE_Y(ScreenInfo); pStateInfo->WindowPosX = Console->WindowRect.left; pStateInfo->WindowPosY = Console->WindowRect.top; if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { pStateInfo->FontSize = SCR_FONTSIZE(ScreenInfo); pStateInfo->FontFamily = SCR_FAMILY(ScreenInfo); pStateInfo->FontWeight = SCR_FONTWEIGHT(ScreenInfo); wcscpy(pStateInfo->FaceName, SCR_FACENAME(ScreenInfo)); pStateInfo->CursorSize = ScreenInfo->BufferInfo.TextInfo.CursorSize; } pStateInfo->FullScreen = Console->FullScreenFlags & CONSOLE_FULLSCREEN; pStateInfo->QuickEdit = Console->Flags & CONSOLE_QUICK_EDIT_MODE; pStateInfo->AutoPosition = Console->Flags & CONSOLE_AUTO_POSITION; pStateInfo->InsertMode = Console->InsertMode; pStateInfo->ScreenAttributes = ScreenInfo->Attributes; pStateInfo->PopupAttributes = ScreenInfo->PopupAttributes; pStateInfo->HistoryBufferSize = Console->CommandHistorySize; pStateInfo->NumberOfHistoryBuffers = Console->MaxCommandHistories; pStateInfo->HistoryNoDup = Console->Flags & CONSOLE_HISTORY_NODUP; RtlCopyMemory(pStateInfo->ColorTable, Console->ColorTable, sizeof(Console->ColorTable)); pStateInfo->hWnd = Console->hWnd; wcscpy(pStateInfo->ConsoleTitle, Console->OriginalTitle); NtUnmapViewOfSection(NtCurrentProcess(), pStateInfo); /* * Map the shared memory block handle into the client side process's * address space. */ ProcessHandleRecord = CONTAINING_RECORD(Console->ProcessHandleList.Blink, CONSOLE_PROCESS_HANDLE, ListLink); Status = NtDuplicateObject(NtCurrentProcess(), hSection, ProcessHandleRecord->ProcessHandle, &hClientSection, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { KdPrint(("CONSRV: error %x mapping handle to client\n", Status)); NtClose(hSection); return; } /* * Get a pointer to the client-side properties routine. */ if (ProcessHandleRecord->PropRoutine) { MyPropRoutine = ProcessHandleRecord->PropRoutine; } else { MyPropRoutine = PropRoutine; } /* * Call back into the client process to spawn the properties dialog. */ UnlockConsole(Console); hThread = InternalCreateCallbackThread(ProcessHandleRecord->ProcessHandle, (DWORD)MyPropRoutine, (DWORD)hClientSection); if (!hThread) { KdPrint(("CONSRV: CreateRemoteThread failed %d\n", GetLastError())); } LockConsole(Console); /* * Close any open handles and free allocated memory. */ if (hThread) NtClose(hThread); if (hSection) NtClose(hSection); return; }
NTSTATUS ConsoleAddProcessRoutine( IN PCSR_PROCESS ParentProcess, IN PCSR_PROCESS Process ) { PCONSOLE_PER_PROCESS_DATA ProcessData, ParentProcessData; PCONSOLE_INFORMATION Console; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; NTSTATUS Status = STATUS_SUCCESS; ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process); ProcessData->HandleTablePtr = ProcessData->HandleTable; ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES; CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData,FALSE); if (ParentProcess) { ProcessData->RootProcess = FALSE; ParentProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ParentProcess); // // If both the parent and new processes are console apps, // inherit handles from the parent process. // if (ParentProcessData->ConsoleHandle != NULL && (Process->Flags & CSR_PROCESS_CONSOLEAPP)) { LockConsoleHandleTable(); if (!(NT_SUCCESS(DereferenceConsoleHandle(ParentProcessData->ConsoleHandle, &Console)))) { ProcessData->ConsoleHandle = NULL; UnlockConsoleHandleTable(); return STATUS_PROCESS_IS_TERMINATING; } // // Don't add the process if the console is being shutdown. // LockConsole(Console); if (Console->Flags & CONSOLE_SHUTTING_DOWN) { Status = STATUS_PROCESS_IS_TERMINATING; ProcessHandleRecord = NULL; } else { ProcessHandleRecord = HeapAlloc(pConHeap,MAKE_TAG( HANDLE_TAG ),sizeof(CONSOLE_PROCESS_HANDLE)); if (ProcessHandleRecord == NULL) { Status = STATUS_NO_MEMORY; } else { // // duplicate parent's handle table // ASSERT(ProcessData->Foo == 0xF00); Status = InheritIoHandleTable(ProcessData, ParentProcess); if (NT_SUCCESS(Status)) { ProcessHandleRecord->Process = Process; ProcessHandleRecord->CtrlRoutine = NULL; ProcessHandleRecord->PropRoutine = NULL; AddProcessToList(Console,ProcessHandleRecord,Process->ProcessHandle); // // increment console reference count // Console->RefCount++; } else { HeapFree(pConHeap, 0, ProcessHandleRecord); } } } if (!NT_SUCCESS(Status)) { ProcessData->ConsoleHandle = NULL; } UnlockConsole(Console); UnlockConsoleHandleTable(); } else ProcessData->ConsoleHandle = NULL; } else { ProcessData->ConsoleHandle = NULL; } return Status; }