Запуск консольных приложений из своей программы
ТРПО. Лабораторная № 2 Взаимодействие с консольными приложениями Теоретическая часть Перенаправление потоков ввода-вывода
Консольные приложения работают с так называемыми потоками ввода-вывода. В частном случае эти потоки могут соответствовать вводу данных с клавиатуры и выводу в консольное окно. К примеру, когда первокурсники решают задачи в Делфи, то они пользуются именно таким режимом работы, позволяющим вводить данные задачи и выводить на экран результат решения.
На самом деле операционная система позволяет перенаправлять потоки ввода-вывода в файл или в другое приложение. Воспользуемся программой sum.exe, которая была создана в предыдущей лабораторной работе и посмотрим, как можно не переписывая код самой программы организовать вывод результата в файл. Достаточно ввести такую команду:
sum 5 3 20 50 > output.txt
Результат работы команды окажется в файле «output.txt» текущего каталога, в консольном окне он отображен не будет. Такое действие называется перенаправлением потоков ввода-вывода, в данном случае происходит перенаправление потока вывода в файл.
Надо заметить, что файл «output.txt» буде перезаписан, то есть имеющаяся в нем информация теряется. Для дозаписи вывода консольного приложения в конец файла можно воспользоваться следующей командой:
sum 32 22 7 >> output.txt
Команда type консоли Windows выводит содержимое файла.
Если консольное приложение осуществляет чтение из стандартного потока ввода командами Read и ReadLn, то возможно организовать перенаправление потока ввода из файла. Например, откомпилируем следующее консольное приложение в файл «sum2.exe»:
program sum2;
{$APPTYPE CONSOLE}
var C, I, A, Sum: Integer;
begin Sum:= 0; Read(C); for I = 1 to C do begin Read (A); Inc(Sum, A); end; {for} WriteLn(Sum); end.
Программа тоже суммирует числа, но теперь эти числа вводятся с клавиатуры, причем сначала мы указываем количество, а затем сами числа. Для того чтобы исходные данные брались из файла необходимо сделать перенаправление потока ввода, например:
sum2 < input.txt
В одной команде можно организовать перенаправление потоков ввода и вывода одновременно, например:
sum2 < input.txt > output.txt
Код возврата На подобии того, как функции могут возвращать некоторое значение, консольные приложения тоже имеют возможность возвращать результат своей работы в виде целочисленного кода. Код возврата всегда представляет из себя целое число. Принято, что нулевой код возврата соответствует успешному завершению программы, а отличные от нуля сигнализируют о возникновении каких-либо проблем. Однако использовать код возврата можно не только для оповещения о проблемах, но и просто как возврат результата работы программы.
Перепишем программу суммирования чисел следующим образом: program sum3;
{$APPTYPE CONSOLE}
uses SysUtils;
var s, i: Integer;
begin s:= 0; for i = 1 to ParamCount do Inc(s, StrToInt(ParamStr(i))); Halt(s); end.
Процедура Halt прекращает выполнение программы и возвращает переданное ей значение. В приведенном примере в качестве кода возврата выступает сумма чисел.
В командный файлах Windows (.cmd-файлы) код возврата последней выполненной команды может учитываться при выполнении условий IF с параметром ERRORLEVEL. Самостоятельно изучите эту возможность, введя в консоли команду «IF /?». Кроме того, создается специальная переменная %ERRORLEVEL%, которая содержит строковое представление кода возврата выполнения последней консольной команды.
Запустите программу и посмотрите на результат ее работы:
Переменная %ERRORLEVEL% всегда содержит код возврата последней выполненной консольной команды.
При вызове консольного приложения из другой программы код возврата также может быть использован для анализа результатов выполнения приложения. Запуск консольных приложений из своей программы Самый простой способ выполнить любую консольную команду – использовать функцию WinExec из модуля Windows. Функция имеет следующий вид: «WinExec (<команда>, SW_SHOWNORMAL)», где <команда> – строка типа PChar, содержащая команду для выполнения. Например, для запуска приложения «sum.exe» с передачей ей параметров можно воспользоваться следующей программой:
program exec;
{$APPTYPE CONSOLE}
uses Windows;
begin WinExec(PChar('sum 2 3 5'), SW_SHOWNORMAL); WriteLn('OK'); ReadLn; end.
Можно заметить, что «OK» будет выведено раньше, чем результат суммирования «10». Дело в том, что запуск программы через WinExec не приводит к ожиданию запустившей программы, она продолжает выполняться параллельно. Таким образом мы только запускаем другую программу, но не можем контролировать ход ее выполнения, в том числе не можем получить код возврата, потому как не ждем ее завершения.
Гораздо большие возможности предоставляет функция CreateProcess из модуля Windows. Для понимания сути ее работы рассмотрим пример программы, запускающей консольное приложение «sum3.exe» и выводящей на экран полученный код возврата:
program exec;
{$APPTYPE CONSOLE}
uses Windows;
function CmdExec(const Cmd: string): Integer; // Выполнение консольного приложения с ожиданием его завершения и возвратом кода возврата var Rlst: LongBool; StartUpInfo: TStartUpInfo; ProcessInfo: TProcessInformation; ExitCode: Cardinal; begin FillChar(StartUpInfo, SizeOf(TStartUpInfo), 0); // заполнение структуры нулями with StartUpInfo do begin cb:= SizeOf(TStartUpInfo); dwFlags:= STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK; wShowWindow:= SW_SHOWNORMAL; end; {with} Rlst:= CreateProcess( nil, PChar(Cmd), // команда nil, nil, False, // флаг наследования текущего процесса NORMAL_PRIORITY_CLASS, // флаги способов создания процесса nil, nil, // текущий диск и каталог StartUpInfo, // структура STARTUPINFO ProcessInfo // структура PROCESS_INFORMATION ); if Rlst then begin // если запуск прошел успешно with ProcessInfo do begin WaitForInputIdle(hProcess, INFINITE); // ждем завершения инициализации WaitForSingleObject(ProcessInfo.hProcess, INFINITE); // ждем завершения процесса GetExitCodeProcess(ProcessInfo.hProcess, ExitCode); // получаем код завершения
CloseHandle(hThread); // закрываем дескриптор процесса CloseHandle(hProcess); // закрываем дескриптор потока end; {with} end else begin // ошибка выполнения команды WriteLn('Error: ', GetLastError, ' > ', Cmd); ExitCode:= 0; end; {if} Result:= Integer(ExitCode); // возвращаем код возврата с приведением к типу Integer end; {func CmdExec}
var S: Integer;
begin S:= CmdExec('sum3 10 15 4 3'); WriteLn(S); ReadLn; end
Если все верно, то должен получиться ответ: 32.
Для упрощения мы разработали функцию CmdExec, позволяющую запустить консольное приложение с ожиданием завершения ее работы и возвратом кода возврата. Таким образом, запуск консольных приложений становится не сложнее вызова WinExec.
Более подробную информацию по функции CreateProcessможно получить на сайте: http://www.delphirus.com/article32.html. Используя материал сайта, разберите реализацию функции CmdExec.
Практическая часть Дан текстовый файл «input.txt», в каждой строке которого записан набор целых чисел через пробелы. Необходимо получить файл «output.txt», каждая строка которого содержит произведение чисел соответствующей строки файла «input.txt».
Для решения задачи:
Замечание. Для запуска стороннего приложения достаточно использовать функцию WinExec. Для того чтобы открыть текстовый файл в Блокноте, необходимо запустить программу «notepad.exe» и передать ей в качестве параметра имя открываемого файла.
Результат работы приложения показан на скриншотах:
Контрольные вопросы
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|