Запуск консольных приложений из своей программы




ТРПО. Лабораторная № 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 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».

Для решения задачи:

  1. Разработать консольное приложение «mult.exe», находящее произведение переданных в качестве параметров чисел и возвращающее результат с помощью кода возврата.
  2. Разработать приложение «mults.exe», которое используя «mult.exe» найдет произведение каждой строки входного файла, запишет результат в выходной файл и по завершении своей работы откроет получившийся файл в Блокноте. Имена входного и выходного файлов передаются приложению в качестве параметров.

Замечание. Для запуска стороннего приложения достаточно использовать функцию WinExec. Для того чтобы открыть текстовый файл в Блокноте, необходимо запустить программу «notepad.exe» и передать ей в качестве параметра имя открываемого файла.

Результат работы приложения показан на скриншотах:

Контрольные вопросы

  1. Что такое потоки ввода-вывода?
  2. Как в консоли Windows организовать перенаправление потока вывода в файл?
  3. Как в консоли Windows организовать поток ввода из файла?
  4. Какая процедура в Delphi позволяет завершить программу и передать указанный код возврата?
  5. Как получить значение кода возврата в консоли Windows?
  6. Какие существуют способы запуска приложений из своей программы?



Работы которые могут быть Вам интерессными terminator-da-pridet-spasitel.html

terminator.html

terminatornaya-organizacionnaya-kultura.html

termin-biokonversiya-znachenie-processa-biokonversii-biotransformacii-v-praktike-polucheniya-steroidnih-soedinenij.html

termin-deq-isklyuchen-iz-inkoterms-2010-incoterms-2010-.html

termin-deq-mozhet-ispolzovatsya-tolko-pri-perevozke-tovara-morskim-ili-rechnim-vnutrennim-vodnim-transportom.html

termin-des-isklyuchen-iz-inkoterms-2010-incoterms-2010-.html

termin-des-mozhet-ispolzovatsya-tolko-pri-perevozke-tovara-morskim-ili-rechnim-vnutrennim-vodnim-transportom.html

termin-ekspluataciya-oznachaet-ispolzovanie-chego-to-dlya-opredelennih-celej.html

termin-fas-mozhet-bit-ispolzovan-tolko-pri-morskoj-perevozke-ili-pri-perevozke-vnutrennim-vodnim-transportom.html

term-information-technology.html

termin-gipoksiya-etimologicheski-i-soderzhatelno-traktuyut-dvoyako.html

termini-9-16-veka.html

termin-i-definiciya.html

termini-dlya-igri-po-kompleksirovaniyu.html

termini-dlya-kontrolnoj-raboti-1.html

termini-dlya-sostavleniya-slovarya-i-dlya-zapominaniya.html

termini-ekvivalenti-i-parallelnie-termini-v-otraslevoj-terminosisteme.html

termini-folat-vitamin-m-i-folievaya-kislota-vitamin-v9-chasto-ispolzuyutsya-kak-vzaimozamenyaemie-i-harakterizuet-odnu-i-tuzhe-v-kompleksnuyu-vitaminnuyu-gruppu-folati.html

termini-grecheskogo-proishozhdeniya.html

termini-ih-proishozhdenie-i-primenenie.html

© domain.tld 2017. Design by Design by toptodoc.ru


Автор:

Дата:

Каталог: Образовательный документ