Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
4
Добавлен:
26.02.2022
Размер:
154.4 Кб
Скачать

Вариант 4

Задание

Написать программу для обучения пользователя командной строки вежливости с использованием перенаправления потоков ввода и вывода через анонимные каналы.

1.Создать два анонимных канала функцией CreatePipe().

2.Запустить процесс cmd.exe, соединив один из созданных каналов с потоком ввода, а другой канал — с потоками вывода и ошибок дочернего процесса.

3.Считать из канала, связанного с потоком вывода дочернего процесса, все данные функцией ReadFile() и вывести их на экран.

Указание 1. Считать все данные можно, вызывая ReadFile() раз за разом и проверяя окончание считанных данных (их количество возвращается параметром lpNumberOfBytesRead). В условиях ЛР можно считать, что вывод окончен, если последний символ — '>'.

Указание 2. Функция ReadFile() работает с байтами, а не со строками, и не дописывает завершающий '\0' в конец считанных данных. Поэтому выводить данные нужно функцией fwrite(), cout.write() и т. п., но не printf() или оператором <<.

4.Запросить у пользователя полную строку-команду.

5.Если введенная строка не начинается со слова «please» (до первого пробела), уведомить об этом пользователя и перейти к пункту 4.

6.Если введена строка «thanks», остановить дочерний процесс функцией TerminateProcess(), закрыть анонимные каналы функцией CloseHandle() и завершить работу программы.

7.Записать в канал, связанный с потоком ввода дочернего процесса, оставшуюся

часть команды и символ перевода строки '\n'. 8. Перейти к пункту 3 (цикл).

Указание. Официальный пример перенаправления стандартных потоков дочернего процесса через анонимные каналы может быть полезен, но как основа для решения громоздок:

https://docs.microsoft.com/ru-ru/windows/win32/procthread/creating-a-child-process-with-redirected-input-and- output?redirectedfrom=MSDN

В примерах полужирным начертанием обозначен ввод пользователя.

Пример работы программы:

C:\> date /T

Please ask politely! > please date /T

01.09.2015

C:\> please do something nasty

'do' is not recognized as an internal or external command, operable program or batch file.

C:\> thanks

Примечание. Программа cmd.exe перед выводом каждой команды выводит также саму команду. Корректно было бы не печатать её, как в примере, но для простоты можно оставить.

Выполнение

#include <windows.h> #include <iostream> #include <string>

#define MAX_BUFFER_SIZE 256

int main()

1

{

SECURITY_ATTRIBUTES attr;

attr.nLength = sizeof(SECURITY_ATTRIBUTES); attr.bInheritHandle = TRUE; attr.lpSecurityDescriptor = nullptr;

//Создание канала для чтения дочерним процессом

HANDLE in_read = nullptr; HANDLE in_write = nullptr;

if (!CreatePipe(&in_read, &in_write, &attr, 0))

{

std::cout << "\nError. Error code: " << GetLastError() << '\n'; return EXIT_FAILURE;

}

SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0);

//Создание канала для записи дочерним процессом

HANDLE out_read = nullptr; HANDLE out_write = nullptr;

if (!CreatePipe(&out_read, &out_write, &attr, 0))

{

std::cout << "\nError. Error code: " << GetLastError() << '\n'; return EXIT_FAILURE;

}

SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0);

STARTUPINFO si;

ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdError = out_write;

si.hStdOutput = out_write; si.hStdInput = in_read;

si.dwFlags |= STARTF_USESTDHANDLES;

PROCESS_INFORMATION pi;

ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

//Запуск cmd.exe

char cmd_name[] = "cmd.exe";

auto ok = CreateProcess(nullptr, cmd_name, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi); if (!ok)

{

std::cout << "\nError. Error code: " << GetLastError() << '\n'; return EXIT_FAILURE;

}

const char please[] = "please ";

const size_t please_size = sizeof(please) - 1; const char thanks[] = "thanks";

const size_t thanks_size = sizeof(thanks) - 1;

bool stop = false; std::string cmd; while (!stop)

{

2

//Пропуск вывода самой команды size_t skip_size = cmd.size();

if (skip_size)

skip_size -= please_size;

//Считывание данных из канала, связанного с потоком вывода дочернего процесса

DWORD read;

char buffer[MAX_BUFFER_SIZE];

while (ReadFile(out_read, buffer, sizeof(buffer), &read, nullptr))

{

if (skip_size < read)

{

char* buf_ptr = buffer + skip_size; std::cout.write(buf_ptr, read - skip_size); if (buffer[read - 1] == '>')

break;

}

else

{

skip_size -= read;

}

}

bool polite = false; while (!polite)

{

//Ввод строки-команды пользователя std::getline(std::cin, cmd);

//Остановка дочернего процесса, если введена строка thanks if(strncmp(cmd.c_str(), thanks, thanks_size) == 0)

{

stop = true; TerminateProcess(pi.hProcess, 0); break;

}

//Запрос на вежливый ввод, если строка не начинается с please if (strncmp(cmd.c_str(), please, please_size) != 0)

{

std::cout << "Please ask politely!\n>"; polite = false;

}

else

{

//Запись команды дочернему процессу, если введена вежливая команда

DWORD written; cmd += "\n";

WriteFile(in_write, cmd.c_str() + please_size, cmd.size() - please_size, &written, nullptr); polite = true;

}

}

}

3

//Закрытие открытых дескрипторов

CloseHandle(in_read);

CloseHandle(out_write);

CloseHandle(in_write);

CloseHandle(out_read);

CloseHandle(pi.hThread);

CloseHandle(pi.hProcess); return 0;

}

4

Соседние файлы в папке Windows лаб 1-4