Перейти к содержимому

Как запускать программы в лазарусе

  • автор:

Урок 13. Запуск других приложений

На этом уроке изучим запуск других приложений. Иногда из программы на Delphi требуется запустить другую программу. Для этого есть два способа и оба используют API -функции. Первый способ использует функцию API -функцию WinExec , а второй — ShellExecute . Посмотрим на применение этих функций в деле.

Сначала используем функцию ShellExecute . Для нее пример достаточно распространенный — мы сделаем гиперссылку на форме. Щелкаешь на ней — и оказываешься на некотором сайте. Часто такую ссылку можно видеть в окошке About . Для использования функции ShellExecute прежде всего добавляем ShellAPI в секцию uses нашего кода (иначе компилятор ругнется на эту функцию).

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, ShellAPI;

Далее помещаем на форме Label , и делаем в нем надпись синей и подчеркнутой (как это и принято для гиперссылки). Делаем двойной щелчок мышью на нашем Label1 для перехода в окно кода.

В обработчике пишем следующий код:

procedure TForm1.Label1Click(Sender: TObject);

ShellExecute(Form1.Handle, ‘open’, ‘http: //www.ya.ru’,

nil, nil, SW_SHOWNORMAL)

Запускаем программу, щелкаем на нашей гиперссылке и оказываем на сайте. Все как и ожидалось.

Рассмотрим параметры нашей функции более подробно.

Первый параметр ( Form1.Handle у нас) — это указатель на окно, из которого запускается другое приложение.

Второй параметр (у нас это open ) — показывает, что мы делаем. Значение open для него — самое распространенное. Еще из распространенных значений этот параметр может принимать print (для печати, естественно) и nil (которое фактически тоже самое, что и open ).

Третий параметр — это что мы, собственно открываем (печатаем и т. д.). Он может быть как именем конкретного exe (например, notepad.exe ), так и именем документа (например, test.doc) . В этом случае запустится приложение, ассоциированное с файлом открываемого типа (для *.doc — Word и т. д.). Третье значение для рассматриваемого параметра — это имя папки (например, D:\Delphi ).

Четвертый параметр (у нас он nil ) — это параметры для запускаемого exe-файла (который должен стоять третьим параметром). Например, сюда можно написать, что за файл мы хотим открыть в Блокноте.

Остальные параметры не столь важны, так что если интересно, то смотрите в help .

Что же до функции WinExec , то она оставлена только для совместимости.

Указанный фрагмент запустит Блокнот.

Всё на этом урок закончен.

Запуск чужой программы из своей

В этой статье рассказывается о том, как из своей собственной программы запускать другие программы и получать от них результат. Рассказано о специфике запуска из своей 32-ух битной программы системных утилит в Windows64.

2. Введение

  • ООП-метод, с помощью класса «TProcess» (для Lazarus — «TProcessUTF8»). Поскольку ООП сегодня считается самым правильным стилем то я его поставил на первое место;
  • С помощью функций, которые прячут ООП внутрь себя, несколько упрощая запуск другой программы.

3. ООП-метод запуска. TProcess

Кардинальное различие между классами «TProcess» для чистого FreePascal и «TProcessUTF8» для Lazarus — возможность в последнем использовать не сильно напрягаясь символы национального алфавита в названии запускаемых программ. Всё остальное полностью одинаково. Для использования класса «TProcess» нужно подключить к своей программе модуль «Process». В Lazarus на форму нужно поместить квазивизуальный компонент «TProcess» или «TProcessUTF8», которые находится на вкладке «System» (см. рис. 1), тогда нужный модуль добавится сам собой.

Рисунок 1. Панель компонентов Lazarus. TProcess и TProcessUTF8

Небольшая ложка дёгтя Если вы пользуетесь компонентом Lazarus, то первым по счёту свойством, куда он вам предложит ввести название запускаемой программы — «ApplicationName». Это свойство уже давно объявлено устаревшим (deprecated). Следующим по счёту идёт «CommandLine», которое тоже объявлено устарешим. Когда-то давно в это свойство вводилось название программы и все запускаемые вместе с ним параметры. Сегодня для входных параметров сделан более удобный и понятный список строк — «Parameters» типа TStrings. Хотя предыдущие два свойства пока ещё остаются рабочим вариантом, но при компиляции вы увидите предупреждение. Название запускаемой программы нужно вводить в свойство «Executable» (см. рис.2) и никуда более, если вы не хотите при очередной смене версии компилятора получить неработающую программу.

Рисунок 2. Свойство для названия запускаемой программы

  • Executable — сюда вносится имя запускаемой программы. Если программа находится в пределах стандартной переменной «PATH», то можно без указания каталога, если нет — то полное имя вместе с каталогом.
  • Parameters — дополнительные входные параметры. Это набор строк типа TStrings, поэтому один параметр в одной строке. Синтаксис всех параметров должен быть точно такой, какой полагается при обычном запуске программы в командной строке.
  • Options — опции запуска. Нужные опции перечисляются в квадратных скобках через запятую. В Lazarus ставится галочка возле соответствующей опции. Наиболее популярные опции, почти для всех ОС:
    • poUsePipes — весь вывод запущеной программы заносится в специальный поток (TProcess.Output), который можно потом загрузить в какой-нибудь более удобный для разглядывания компонент, например в TStringList или в TMemo;
    • poWaitOnExit — если запускающей программе обязательно нужно дождаться окончания работы запускаемой, то этот флаг как раз приостанавливает работу основного потока запускающей программы, пока не отработает та, которая из неё запущена. К примеру, дальнейшая работа будет строится на ответе чужой программы;
    • poStderrToOutPut — этот флаг бывает черезвычайно полезен, когда чужая программа выдаёт свои ошибки, ну или вообще какие-нибудь критически выжные сообщения не на стандартный вывод, которым обычно является экран компьютера. Здесь программу принудительно заставляют выводить вообще всё именно в стандартный вывод (TProcess.Output). Но если вам нужно мухи отдельно, а котлеты отдельно, то флаг не ставится а вывод ошибок тогда идёт в отдельный поток (TProcess.StdErr);
    • poRunSuspended — после запуска чужая программа переводится в режим ожидания, т.е. она ничего не делает, а ждёт от вас какого-нибудь пинка. Так, сходу, для чего это непременно может понадобиться я придумать не могу. Но наверняка и для этого флага найдутся веские причины.
    • Это не все опции, но остальные не особо актуальны.
    • ppNormal — приоритет нормальный, как у всех. Это значение стоит по умолчанию;
    • ppHigh — приоритет чуть выше нормального;
    • ppIdle — процесс будет работать только когда система простаивает без дела;
    • ppRealTime — режим реального времени. Хотя для компьютеров общего назначения это некоторое преувеличение, но по крайней мере процессор этому приложению будет давать максимальную квоту времени на выполнение, что заметно прибавит скорости работы.
      Uses Classes, SysUtils, Process; function Wow64DisableWow64FsRedirection(x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64DisableWow64FsRedirection'; function Wow64RevertWow64FsRedirection (x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64RevertWow64FsRedirection'; Var AProcess: TProcess; AStringList: TStringList; // Здесь будет вывод работы процесса proc: string; pnt: Pointer; Begin WriteLn('Какой процесс ищем?'); ReadLn(proc); AStringList := TStringList.Create; AProcess := TProcess.Create(nil); // Эти опции говорят, что нужно дождаться окончания // работы чужой программы и её вывод положить в // специальный закуток AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes]; AProcess.Executable := 'tasklist /FI "IMAGENAME eq '+proc+'"'; AProcess.Executable := 'ps -C '+proc; // // Wow64DisableWow64FsRedirection(pnt); // AProcess.Execute; // // Wow64RevertWow64FsRedirection(pnt); // // Вытаскиваем вывод работы из закутка процесса // в наш набор строк, так будет проще обработать // вывод AStringList.LoadFromStream(AProcess.Output); // Если строк больше 1, // значит процесс в памяти есть If AStringList.Count>1 Then WriteLn('Процесс '+proc+' в памяти сидит!') Else WriteLn('Процесса '+proc+' в памяти не найден. '); AStringList.Free; AProcess.Free; End.
    1. Для Windows не забудьте к имени искомого процесса приписывать точку и расширение, иначе ничего не будет найдено. Чтобы освежить память, можно открыть в Windows «Диспетчер задач». Там наглядно будет видно, как должны выглядеть имена процессов;
    2. А вот теперь то, что из «Диспетчера задач» копировать ни в коем случае не надо. В 64-ёх битной винде, 32-ух битные процессы будут дополнительно помечены » *32″. Несмотря на то, что эта пометка сидит в колонке «Имя образа», к именам процессов она никакого отношения не имеет;
    3. Как вы заметили, в свойство TProcess.Executable я поместил и название программы и её входные параметры. Действительно, на сегодняшний день это свойство является полным аналогом свойства «CommandLine». Будет ли так и дальше — посмотрим. А пока, если входной параметр коротенький и одинокий, его вполне можно писать вместе с названием программы. Если же жераметров много или они длинные, то для ясности их лучше помещать в свойство «Parameters».
      Uses Classes, SysUtils, Process; function Wow64DisableWow64FsRedirection(x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64DisableWow64FsRedirection'; function Wow64RevertWow64FsRedirection (x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64RevertWow64FsRedirection'; Var AProcess: TProcess; AStringList: TStringList; // Здесь будет вывод работы процесса proc: AnsiString; pnt: Pointer; Begin WriteLn('Какой процесс ищем?'); ReadLn (proc); AStringList := TStringList.Create; AProcess := TProcess.Create(nil); // Эти опции говорят, что нужно дождаться окончания // работы чужой программы и её вывод положить в // специальный закуток AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes]; AProcess.Executable := 'tasklist.exe'; AProcess.Parameters.Add('/FI "IMAGENAME eq '+proc+'"'); AProcess.Executable := 'ps'; AProcess.Parameters.Add('-C '+proc); // На всякий случай. Запуск из нашего 32-ух битного приложения // системной утилиты в Win64. // // Wow64DisableWow64FsRedirection(pnt); // AProcess.Execute; // // Wow64RevertWow64FsRedirection(pnt); // // Вытаскиваем вывод работы из закутка процесса // в наш набор строк, так будет проще обработать // вывод AStringList.LoadFromStream(AProcess.Output); // Если строк больше 1, // значит процесс в памяти есть If AStringList.Count>1 Then WriteLn('Процесс '+proc+' в памяти сидит!') Else WriteLn('Процесс '+proc+' в памяти не найден. '); AStringList.Free; AProcess.Free; End.

    Кстати говоря, если вы из вышепредставленного кода хотите сделать функцию, но не хотите передавать в неё параметры типа TStringList, то есть возможность организации параметров в виде одной строки. Допустим строка эта называется «params». Все входные параметры запускаемой программы нужно разбавлять символом перевода строки (#10), примерно так:

    params := '-a param1'#10'-b param2'#10'-c param3';

    а потом засунуть эту строку в свойство «Parameters» таким образом:

    AProcess.Parameters.Text := params;

    TStringList прекрасно воспринимает символ #10 и строки параметров будут разделены правильно. В модуле Process есть специальная процедура CommandToList(), которая переделывает подобную строку из всех параметров в TSringList. Однако пользоваться ею надо с умом. Разделение в ней происходит по символу пробела или любым символом перевода строки. Чтобы в одну строку были занесены параметры типа «ключ значение», которые разделены между собой пробелом, ключ и значение нужно группировать с помощью двойных кавычек:

     Uses Classes, SysUtils, Process; Var AStringList: TStringList; s: string; i: integer; Begin AStringList:=TStringList.Create; WriteLn('Первый вариант, неправильный:'); WriteLn; s:='-a param1 -b param2 -c param3'; CommandToList(s, AStringList); For i:=0 To AStringList.Count-1 Do WriteLn(AStringList[i]); WriteLn; WriteLn('Второй вариант, правильный:'); WriteLn; s:='"-a param1" "-b param2" "-c param3"'; AStringList.Clear; CommandToList(s, AStringList); For i:=0 To AStringList.Count-1 Do WriteLn(AStringList[i]); AStringList.Free; End.

    Рисунок 3. Процедура CommandToList() и параметры типа «ключ значение»

    4. Простые функции запуска

    1. В модуле «SysUtils»:
    ExecuteProcess(const exename: string; const parameters: string или array of string; flags: TExecuteFlags): integer;
    • exename — имя запускаемой программы. Если программа лежит где-то вне системной переменной PATH, то имя писать вместе с полным путём;
    • parameters — входные параметры (ключи) запускаемой программы. Это может быть одна строка, где ключи разделены пробелами, как это делается при запуске из консоли или скрипта. Так же все ключи можно разметить в array of string, при этом одна ячейка (строка) массива — один ключ;
    • flags — тут можно добавить всего один флаг «ExecInheritsHandles», но только в том случае, если у вас Windows или OS/2. Во всех остальных случаях флаг бесполезен. Этот флаг передаёт файловые дескрипторы запускаемой программе.
    RunCommandIndir(const curdir : string; const exename : string; const parameters : array of string; out outputstring: string; out exitstatus : integer; // Необязательный Options : TProcessOptions = []): integer;
    • curdir — рабочий каталог, где будет выполняться запускаемая программа. Может быть пустой строкой;
    • exename — имя запускаемой программы;
    • parameters — входные параметры для запускаемой программы. Массив строк. Одна строка — один параметр.
    • outputstring — это текстовые результаты работы программы, которые она могла бы выдать в консоль;
    • exitstatus — необязательный параметр. Здесь будет номер ошибки, если такое предусмотрено. Если же нет, эту переменную в функцию можно не вписывать.
    • Options — набор флагов запуска, если нужно.
    • Если вызывается с двумя выходными параметрами, то она возвратит 0 если попытка запуска успешна и -1 в случае какой-то ошибки;
    • Если без параметра exitstatus, то будет типа boolean и True в случае успешности попытки запуска.
    RunCommand(const exename : string; const parameters : array of string; out outputstring: string; Options : TProcessOptions = []): boolean;
      Uses SysUtils; Var prog, params: string; Begin prog := '"c:\Program Files (x86)\Mozilla Firefox\firefox.exe"'; prog := 'firefox'; params := 'www.freepascal.ru'; Try ExecuteProcess(prog, params); Except On E: EOSError Do WriteLn('Вах, какая ужасная ошибка с номером ', E.ErrorCode); End; End.

    Функции из модуля Process будут интересны в плане более гибкого управления запускаемой программы с помощью параметра Options или задания специального каталога для жизнедеятельности этой программы.

      Uses Classes, SysUtils, Process; function Wow64DisableWow64FsRedirection(x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64DisableWow64FsRedirection'; function Wow64RevertWow64FsRedirection (x: Pointer): longbool; stdcall; external 'Kernel32.dll' name 'Wow64RevertWow64FsRedirection'; Var prog, ans, user_: String; params: array of String; outstr: TStringList; pnt: Pointer; Begin WriteLn('Какого пользователя ищем?'); ReadLn(user_); SetLength(params, 1); outstr:=TStringList.Create; prog := 'query.exe'; params[0] := 'USER "'+user_+'"'; prog := 'w'; params[0] := user_; // На всякий случай. Запуск из нашего 32-ух битного приложения // системной утилиты в Win64. Wow64DisableWow64FsRedirection(pnt); // Вариант запуска 1 - отдельно программа, // отдельно входные параметры RunCommand(prog, params, ans, []); outstr.Text:=ans; // Если строк больше 1, // значит пользователь найден If outstr.Count>1 Then WriteLn('Пользователь '+user_+' пришёл на работу.') Else WriteLn('Пользователь '+user_+' дрыхнет дома.'); // Вариант запуска 2 - входные параметры // собираются вместе прямо в функции RunCommand(prog, [params[0]], ans, []); outstr.Text:=ans; // Если строк больше 1, // значит пользователь найден If outstr.Count>1 Then WriteLn('Пользователь '+user_+' пришёл на работу.') Else WriteLn('Пользователь '+user_+' дрыхнет дома.'); // Вариант запуска 3 - и программа и // входные параметры в одной строке RunCommand(prog+' '+params[0], [], ans, []); outstr.Text:=ans; // Если строк больше 1, // значит пользователь найден If outstr.Count>1 Then WriteLn('Пользователь '+user_+' пришёл на работу.') Else WriteLn('Пользователь '+user_+' дрыхнет дома.'); Wow64RevertWow64FsRedirection(pnt); End.

    5. Выводы

    Несмотря на то что, по сравнению с TurboPascal, запуск чужих программ усложнился, он стал более гибким и функционально законченым. Вдобавок, по сравнению с Delphi, не нужно принимать никаких хитрых мер, чтобы заполучить вывод чужой программы в свою. Это позволяет не ломать голову над собственным кодом и не лезть в дебри чужого API, чтобы получить у себя этот же функционал, который уже реализован в чужой программе.

    6. Ссылки

    Запуск программы или файла из программы на Delphi 7

    Доброе утро. Подскажите мне, как запустить программу или файл из программы на Delphi 7?

    22.02.2014, 07:39

    Регистрация: 12.07.2009

    Адрес: Богородское

    Сообщения: 3,025

    Вы сказали Спасибо: 115
    Поблагодарили 691 раз(а) в 676 сообщениях

    Версия Delphi: D7E

    Репутация: 1834

    Вариантов море, напр. вот кусочек из drkb

    uses ShellAPI; … var h: hwnd; begin // Используем ShellExecute if ShellExecute(h, 'open', 'readme.txt', nil, nil, SW_SHOW) < 32 then begin ShowMessage('Немогу выполнить ShellExecute !') end; // Используем WinExec if WinExec('Notepad c:\config.sys', SW_SHOW) < 32 then begin ShowMessage('Немогу выполнить WinExec !') end; end;

    а есть ещё ShellExecuteEx или CreateProcess.

    __________________

    Egorkaru (22.02.2014)

    22.02.2014, 07:53

    Регистрация: 21.01.2014

    Адрес: Белово, Кемеровская обл., Россия

    Сообщения: 10

    Вы сказали Спасибо: 1
    Поблагодарили 0 раз(а) в 0 сообщениях

    Версия Delphi: Delphi 7

    Репутация: 10

    Сообщение от Alegun

    Вариантов море, напр. вот кусочек из drkb

    uses ShellAPI; … var h: hwnd; begin // Используем ShellExecute if ShellExecute(h, 'open', 'readme.txt', nil, nil, SW_SHOW) < 32 then begin ShowMessage('Немогу выполнить ShellExecute !') end; // Используем WinExec if WinExec('Notepad c:\config.sys', SW_SHOW) < 32 then begin ShowMessage('Немогу выполнить WinExec !') end; end;

    а есть ещё ShellExecuteEx или CreateProcess.

    Спасибо. Это был первый вопрос, а второй такой: как запустить программу или файл из папки, где находится исходник программы на Delphi 7?

    Как в Lazarus открыть внешнюю программу? Нужно чтобы по нажатию кнопки программа закрывалась и вмес

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

    uses
    Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
    ExtCtrls, StdCtrls;

    TForm1 = class(TForm)
    background: TImage;
    BotTrackBar: TTrackBar;
    Button: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure BotTrackBarChange(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    private
    < private declarations >
    public
    < public declarations >
    end;

    var
    Form1: TForm1;
    BotNum: integer;
    f: textfile;

    procedure TForm1.BotTrackBarChange(Sender: TObject);
    begin
    Form1.Label2.Caption:=IntToStr(Form1.BotTrackBar.Position);
    BotNum:=Form1.BotTrackBar.Position;
    end;

    procedure TForm1.ButtonClick(Sender: TObject);
    begin
    Rewrite(f);
    Write(f, BotNum);
    CloseFile(f);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    BotNum:=5;
    AssignFile(f, 'botnum.ini');
    end;

    Лучший ответ

    Это просто.
    Открытие файла той программой которая ему сопоставлена, или запуск exe файла- ShellExecute(0,'Open',pchar('C:itog .avi'),nil,nil,1); //Важно: после uses указать модуль - shellapi;

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *