Сверхмалые приложения на Delphi
Многие начинающие программисты и даже некоторые взрослые "солидные" люди, программирующие на C++, Asm'е или других языках упорно считают, что на Delphi можно создавать только программы огромного размера и жрущие много памяти. Более продвинутые и менее упрямые люди знают, что на Delphi, если отказаться от использования VCL можно добиться от минимальной программы размера 8 кб. Ещё более продвинутые знают, что сделав программу используя Runtime Packages можно уменьшить её до 3,5 Кб, но при этом она будет работать только на компьютерах с той же версией Delphi, что и на компьютере создателя. Сегодня нам предстоит сломать стереотипы и рассказать всем о секрете, который знали только избранные.
Сегодня мы создадим на Delphi программу, занимающую всего 2,5 Кб и работающую на любом компьютере. Все знают, что программа с формой на Delphi занимает 300-400 Кб из за VCL, в частности из-за модулей Forms и Classes. Удалив форму и всё из uses, и откомпилировав программу мы получаем приложение размером 8 Кб. В чём же дело? А дело в том, что к каждой программе на Delphi неявно подключены два базовых модуля: System.pas и SysInit.pas. В них содержатся функции для работы со строками (Copy, Pos, Length и т.д.), функции для работы с файлами (AssignFile, WriteLn, Reset и т.д.) и прочее.
Создайте пустую программу и откомпилируйте её. Она будет размером 8 кб. Теперь добавьте переменную var f: file и после begin напишите: AssignFile(f, 'c:\text.txt'). После компиляции программа стала занимать 15 кб. Дело в том, что ф-ция AssignFile оказалась включена в проект. Но так как разработчики Delphi делали ставку не на эффективность кода, а на простоту написания, то в пустую программу по умолчанию добавляется много лишнего. Итак, приступаем к удалению всего лишнего. Предупреждение: после удаления вышеописанные функции (работа со строками, и т.д.) будут недоступны. В вашем арсенале останутся только WinAPI функции, которые самому придётся объявлять и ассемблерные вставки. Вот листинг модуля System.pas нашего нового Delphi:
[code=delphi]
unit System;
interface
procedure _InitExe; //Без комментариев
procedure _HandleFinally;
procedure _halt0;
procedure ExitProcess(Code: LongWord); stdcall; external 'kernel32.dll' name 'ExitProcess';
//Здесь мы описываем процедуру ExitProcess, о предназначении которой говорится ниже
type
TGUID = record
D1: LongWord;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;
//Вообще-то эта запись не нужна, но по какой-то причине компилятор Delphi требует её наличия
implementation
procedure _InitExe;
asm
end;
//Компилятор Delphi требует наличия этой процедуры. Это точка входа программы. Сюда можно
//поместить то, что вы хотите сделать ещё до выполнения основного кода, записанного в dpr
//файле (файле проекта). В нашем минимальном приложении оставим её пустой.
procedure _HandleFinally;
asm
end;
procedure _halt0;
begin
ExitProcess(0);
end;
//Эта процедура вызывается при нормальном завершении работы программы. Обязателен вызов
//ExitProcess, без него возникнет серьёзная ошибка. Весь свой код, который вы хотите
//выполнить при завершении надо писать до ExitProcess.
end.
Теперь содержимое второго важнейшего файла SysInit.pas:
unit SysInit;
interface
implementation
end.
[/code=delphi]
То есть он просто пустой. Итак, сохраним эти исходники с соответствующими именами в какой-нибудь папке. Теперь в той же папке создадим .bat файл, для тех кто в танке - он служит для последовательного исполнения ms-dos команд и запуска консольных приложений. Запишем в него следующую строку:
dcc32 -q system sysinit -m -y -z -$D-
Она скомпилирует модули System.pas и SysInit.pas, которые мы только что создали, и создаст два .dcu файла. Теперь перенесём эти .dcu файлы в папку с нашим проектом, назовём его, например, Project.dpr. Запишем туда код:
[code=delphi]
program Project;
procedure Sleep(milliseconds: Cardinal); stdcall; external 'kernel32.dll' name 'Sleep';
begin
Sleep(10000);
end.
[/code=delphi]
Это означает, что программа запустится, 10 секунд повисит в памяти и завершится. Как я уже говорил, в программах такого вида описывать WinAPI функции надо самим. Теперь создадим в папке с проектом и .dcu файлами ещё один .bat файл, в который напишем:
dcc32 project.dpr
Если вы всё сделали правильно, то после запуска этого файла вы получите программу размером 3,5 кб. Но мы обещали 2,5 кб, и своё обещание сдержим. Программу необходимо сжать архиватором upx, который есть в интернете. Вот в принципе и всё. Заметка: старайтесь использовать WinAPI функции из как можно меньшего числа системных dll файлов. Например, если бы я в dpr файле вместо Sleep вызвал бы MessageBox (user32.dll), то программа занимала бы в памяти 1,5 мб из-за загрузки 2-х dll (kernel32.dll - ExitProcess
и user32.dll - MessageBox), а потому как функция Sleep находится в kernel32.dll, то загружать надо всего лишь одну библиотеку и программа будет в памяти занимать только 500-600 кб.
Заметка: при компиляции будет выдаваться 2-3 ошибки. 2 - обязательно, выглядеть будут вроде такого: Cannot find TIsList, а третья будет выдаваться, если вы будете компилировать программы на компьютере, где нет Delphi. Она будет выглядеть вот так: Cannot load library TLINK32.DLL. Игнорируйте эти ошибки, они процессу создания программы не повредят.
Заметка: при создании таких программ на компьютере, где нет Delphi рекомендуется во избежание ошибок для описывания WinAPI функций использовать MSDN.
Written by: @dmin
e-mail: 5252@mail.ru
- Добавить комментарий
- 7058 просмотров
Комментарии
13 комментария(ев)Дата: ЧТ, 25/08/2011 - 17:12
...а еще был случай с одним рецензентом: как то один из редакторов "Cистемного администратора" (журнал такой), уважаемый человек, уверял меня: что на Delphi нельзя создать сервис (службу)
Дата: ЧТ, 25/08/2011 - 23:35
Раньше вообще была модной тема: "Чего нельзя создать на Delphi". Какие примеры народ только не приводил.
Дата: ПТ, 26/08/2011 - 02:57
Кстати интересно сейчас было бы почитать "что нельзя сделать на делфи"
Дата: ПТ, 26/08/2011 - 07:55
Сейчас тема уже не в топе. Всем интересней читать про смерть Delphi =)
Дата: ПТ, 26/08/2011 - 14:54
Но все же. Ради смеха почитать
Дата: СР, 26/10/2011 - 23:18
ага =) гуф тоже умер xD
Дата: ПТ, 26/08/2011 - 03:50
На мой взгляд писать на Delphi с помощью WinAPI когда есть VCL это словно прокладывать тоннель в метро с помощью коловорота. Если же хочешь написать какую-нибудь незаметную программу - изучай ассемблер
Дата: ПТ, 26/08/2011 - 05:57
Ассемблер это уж слишком, в нем нет необходимости при написании маленьких программ. Минимальную программу легче все получить спомощью специально настроенной visual c++. В итоге программа будет иметь вес ~1.5 кб. И даже upx ничего не сможет дать в этом случае, ибо меньше нельзя впринципе. Убедиться в чистоте программы можно спомощью тойже IDA.
Дата: ПТ, 26/08/2011 - 08:06
Сейчас о размере своего приложения мало кто заботится, но вот раньше все было по другому. Я помню как реально мучился с оптимизацией. Брррр.
Я вот обратил внимание, что сейчас ни у кого нет желания учить старые языки программирования. Взять тот же ассемблер. Сейчас мало кто задумывается о его изучении, однако на этом языке написано куча софта, который нужно поддерживать и дорабатывать. Чувствую, рано или поздно цены на специалистов по "мертвым" языка взлетят.
Дата: ПТ, 26/08/2011 - 14:56
Я тоже не вижу смысла заботиться о размере ЕХЕ файла, причем уже с 2006 года наверно. Размер занимаемый в оперативке это конечно другое, тут все таки надо оптимизировать.