Small Applications in Delphi - Tutorial by n0v4

posted 9 Mar 2010 07:14 by Delphi Basics   [ updated 4 Aug 2011 12:53 ]
{
    Coder: n0v4.
    Modified: Jack
    Compiled: Compiler included.
    Website: opensc.ws
    Website: www.delphibasics.co.nr
}

Writing Small Applications in Delphi.

For Windows 7 compatibility, read here:

Screenshot: compiled contents of archive.

VCL - Visual Components Library, is mainly responsible for the large size of delphi applications.  VCL is used because it enables applications to be developed faster at the expense of inefficient code and therefore, bloated size.  VCL will not be used in this example.

With Delphi, create a console application and replace all the code in the project with code below:
Program Hello;
begin
MessageBox(0,'Hello','Hello',0);
end;

Removing VCL approximately results in a 12Kb application.  This method is already known by Delphi programmers who want their application to be small. However, 12 Kb is quite a large size for  an application which shows a MessageBox. To make applications even smaller many coders uses KOL unit replacement http://kolmck.net/. KOL - Key Objects Library is a set of objects to develop powerful (but small) 32 bit Windows GUI applications using Delphi but without VCL. It is distributed free of charge, with source code.

The second item that is responsible for the large size of Delphi applications is RTL - Run Time Library. RTL has specific pascal functions such as: AssignFile, Reset, Rewrite, ReadLn, WriteLn, etc. To minimise RTL, you can use reduced System.pas and SysInit.pas units [attached and below].

Minimum required structure of system and sysinit units:
unit System;

interface

procedure _HandleFinally;

type
TGUID = record
D1: LongWord;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;

PInitContext = ^TInitContext;
TInitCOntext = record

OuterContext: PInitContext;
ExcFrame: Pointer;
InitTable: Pointer;
InitCount: Integer;
Module: Pointer;
DLLSaveEBP: Pointer;
DLLSaveEBX: Pointer;
DLLSaveESI: Pointer;
DLLSaveEDI: Pointer;
ExitProcessTLS: procedure;
DLLInitState: Byte;
end;

implementation

procedure _HandleFinally;
asm
end;

end.

unit SysInit;

interface
procedure _InitExe;
procedure _halt0;
procedure _InitLib(Context: PinitContext);

var
ModulelsLib: Boolean;
TlsIndex: Integer = -1;
TlsLast: Byte;

const
PtrToNil: Pointer = nil;

implementation

procedure _InitLib(Context: PinitContext);
asm
end;

procedure _InitExe;
asm
end;

procedure _halt0;
asm
end;

end.

You can create new System.pas and SysInit.pas by copying this code [attached], put them in the project directory and compile them with Borland Comandline Compiler.
dcc32.exe -Q system.pas sysinit.pas -M -Y -Z -$D- -0
You can view the options and descriptions for dcc32.exe by running it with no parameters.

Since you are no longer using RTL, you need to write out the WinAPI imports for each function. You can find the structure of the imports in the Borland import files.  The WINAPI import for the MessageBox function is:
function MessageBoxA(hWnd: Cardinal; lpText, lpCaption: Pchar; uType: Cardinal): Integer; stdcall; external 'user32.dll' name '_MessageBoxA@16';
You can see '_MessageBoxA@16' string by opening user32.lib (imports from Visual C + +) with a HEX editor and looking for 'MessageBox'. The names of library functions have the form: "_MessageBoxA@16", where after the @ is the size of transmitted parameters. 
After recompiling, the Hello application is 3.5 Kb in size.

To reduce the size of the application further, instead of Borland Linker [which adds six sections of 512 bytes to our file], we can use Microsoft Linker to bind the objects into an executable file. "A linker is a program that takes one or more objects generated by a compiler and combines them into a single executable program." http://en.wikipedia.org/wiki/Linker_%28computing%29.

At the release of Delphi 4, Borland changed their OMF [Object Module Format http://en.wikipedia.org/wiki/Relocatable_Object_Module_Format] from Intel OMF [which can be linked by Microsoft Linker] to Borland OMF [which can only be linked with Borland Linker.  Since you have compiled the objects [Hello.obj] with Delphi 6 [included compiler version], they have a Borland OMF.  To link the objects with Microsoft linker, you can use OMF2D written by EliCZ which converts Borland OMF to Intel OMF.
To convert your object, you can run OMF2D with parameters:
omf2d Hello.obj /U-
OMF2D Options
/U-   Do not undecorate EXT/COM/EXP/PUBDEF names

You can use a HEX editor to retreive the entry point of Hello.obj to pass it as a parameter to Microsoft linker.  In this case, it is Start$qqrv.
Now, you can run Microsoft linker with parameters:
link.exe /ALIGN:32 /FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /ENTRY:Start$qqrv Hello.obj user32.lib /out:Hello.exe
Linker Options: http://msdn.microsoft.com/en-us/library/y0zzbyt4.aspx
The /ALIGN option specifies the alignment of each section within the linear address space of the program. The number argument is in bytes and must be a power of two. The default is 4K (4096). The linker issues a warning if the alignment produces an invalid image.
Use /FORCE:UNRESOLVED to create an output file whether or not LINK finds an undefined symbol.

In summary:
Create a new .pas file in delphi and use this code:
unit Hello;

interface

procedure Start;

implementation

function MessageBoxA(hWnd: Cardinal; lpText, lpCaption: Pchar; uType: Cardinal): Integer; stdcall; external 'user32.dll' name '_MessageBoxA@16';

procedure Start;
begin
MessageBoxA(0,'Hello','by n0v4',0);
end;

end.

Compile it with parameters:
dcc32.exe -JP -$A-,B-,C-,D-,G-,H-,I-,J-,L-,M-,O+,P-,Q-,R-,T-,U-,V-,W+,X+,Y- Hello.pas

Convert OMF by running OMF2D with parameters:
omf2d Hello.obj /U-

Retreive entry point with HEX editor from Hello.obj to pass it as parameter for Microsoft linker. In this case it is Start$qqrv.
Now run Microsoft linker with parameters:
link.exe /ALIGN:32 /FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /ENTRY:Start$qqrv Hello.obj user32.lib /out:Hello.exe

Now you have an application of approximately 1Kb written in Delphi.
Now nobody can say that Delphi applications are big.

The archive contains all the required executable files and delphi source code to follow this tutorial completely and create your own small application in Delphi.
Č
ċ
ď
TinyPEinDelphi.7z
(753k)
Delphi Basics,
25 Mar 2010 12:14
Comments