Делаем программную оболочку для консольной программы на Делфи


Существует масса отличных консольных программ, написанных программистами для собственных нужд, которые активно пошли в массы.  Зачастую, это технические утилиты,  которым просто не нужны все эти графические менюшки и прочие радости современно пользователя.  Главная особенность консольных программ заключается в том, что программист может зациклить свое внимание лишь на  алгоритме своей программы, не распыляя его на юзабилити-интерфейс. Кроме того, консольная программа в силу того, что ей не нужно тратить процессорные ресурсы на различные окошки, работает быстрее.

Подобных программ масса.  Честно говоря, названия тех, которыми  лично я пользуюсь, займут несколько страниц этого блога. Например, есть такой замечательный упаковщик UPX, представляющий собой консольную программу. Для подбора паролей на запароленные архивы существует замечательный брутфорс Crark, использующий для подбора технологию Cuda, что обеспечивает высокую скорость перебора паролей к архивам.

Однако зачастую даже программистам порой бывает неудобно использовать интерфейс командной строки, ничего не говоря уже о простых пользователях. Поэтому часто имеет смысл написать графическую оболочку для той или иной программы, чем мы и займемся в данной статье.

Оговорюсь сразу – способы запуска чужого потока из своей программы актуальны и для других программ, а не только для консольных. Так что имейте это в виду.

Итак, в качестве эксперимента мы будем использовать консольную утилиту g2mtranscoder.exe из  пакета кодека g2m_codec, предназначенную для декодирования видеофайлов, использующих данный кодек. Для чего нам это нужно, я расскажу в статье «Чем конвертировать  видео G2M4 для просмотра его  на Android-устройствах». Немного отходя от темы, мне пришлось написать оболочку для этой программы, чтобы ее мог использовать посетители портала www.programbeginner.ru

Итак, как сказал Гагарин, поехали.  Программировать мы будем на Delphi, хотя могли использовать абсолютно любой язык. Скажу даже более – платформа .Net имеет в своем составе класс, способный еще лучше справится с этой задачей. Однако программирование на C# данной оболочки я отставлю в сторону, так как там вообще все очень просто. Хотя и этот пример не будет сложным.

Начнем с теории. Для запуска других тредов (потоков) Windows любезно предоставляет нам функции WinExec (), ShellExecute (), ShellExecuteEx() и CreateProcess(). Наиболее популярная у начинающих  программистов является функция WinExec в силу своей простоты.  Однако помните – эта функция уже устарела, хотя порой ее возможностей вполне достаточно. Функция WinExec () имеет два параметра и возвращает какое-то число, нужное нам для проверки (хотя его часто и не используют программисты, а зря).  Данная функция имеет два параметра – саму команду и способ отображения нового окна.  Кроме того, не стоит забывать, что функция WinExec возвращает некое число и ели оно больше 31, то функция выполнится успешно. Давайте рассмотрим запуск таким образом консольной утилиты chkdsk из состава Windows:


WinExec ('chkdsk',SW_MAXIMIZE);

Как видите,  данная команда заставит сработать  утилиту проверки файловой системы. Эту команду мы и передали первым параметром. Со вторым параметром еще проще – это всего лишь константа, которая определяет способ отображения вызываемого окна.  В моем примере этот параметр заставит показывать самый большой размер окна.  Однако вы можете и спрятать программу, используя SW_Hide.  Кстати, это всего лишь мнемонические константы. Никто не запрещает вам ставить их цифровые аналоги.

В принципе, если бы нам нужно было бы просто провернуть какие-то манипуляции с файлом, WinExec хватило бы. Однако моя оболочка должна быть интерактивной.  WinExec здесь не подходит.

Вариантов остается всего три: ShellExecute, ShellExecuteEx и CreateProcess. Последний гораздо предпочтительнее, однако не буду вас пугать кодом. Лучше использовать в данной задаче функцию ShellExecuteEx.

Итак, моя оболочка будет иметь следующий вид:

Делаем программную оболочку для консольной программы на Делфи

Это всего лишь тестовая утилита, лишенная всех лишних красивостей. Увы, я аскет по своей природе и ценю больше функционал, чем красивую упаковку. Моя оболочка должна всего лишь получать имя файла для ковертации, запускать g2mtranscoder.exe и  переносить уже переконвертированный файл в любое место на диске. Что ж, напишем следующий код. Создайте проект VCL Application, накидайте контролов примерно так, как они указаны на моем скриншоте и напишите  следующий код:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ShellAPI, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
Edit1: TEdit;
Button2: TButton;
procedure Button2Click(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure Button1MouseEnter(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
Var
path:string;

procedure TForm1.Button1Click(Sender: TObject);
Var
ShExecInfo:TShellExecuteInfo;
input:string;
begin
input:='g2mtranscoder.exe' + ' source=' + path;
//Заполним структуру
ShExecInfo.cbSize := SizeOf (TShellExecuteInfo);
ShExecInfo.fMask := 0;
ShExecInfo.Wnd := 0;
ShExecInfo.lpVerb :=nil;
ShExecInfo.lpFile := Pchar (input);
ShExecInfo.lpParameters := nil;
ShExecInfo.lpDirectory := nil;
ShExecInfo.nShow := SW_MAXIMIZE;
ShExecInfo.hInstApp := 0;
//Запускаем файл
ShellExecuteEx(@ShExecInfo);

end;

procedure TForm1.Button1MouseEnter(Sender: TObject);
begin
if edit1.Text='' then
Button1.Enabled:=false
else
Button1.Enabled:=true;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
path:=OpenDialog1.FileName;
edit1.Text:=path;
end;
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
if edit1.Text='' then
Button1.Enabled:=false
else
Button1.Enabled:=true;
end;

end.

Ключевым моментом здесь является подключение модуля ShellApi – без него функция ShellApiEx не вызовется.  Сама же функция ShellApiEx принимает только один параметр – адрес структуры типа TShellExecuteInfo. Поля структуры нужно заполнить уже в коде. Дл читателей, делающих только первые шаги в программировании, поясняю – структуры очень широко применяются именно для передачи разнородных параметров в функции. Это гораздо быстрее, нежели передавать их вручную. После того, как я заполнил все поля структуры,  можно вызывать уже функцию ShellExecuteEx.

ShellExecute также просто использовать, однако она устарела. А о функции CreateProcess  я расскажу в другой статье.

Яндекс.Метрика