1. Computing
Your first raw API Delphi program
Page 1: Your first Delphi application without the Forms unit.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Page 2: Message Boxes, Binary combine with the "OR" operator, and the PChar type.
• Page 3: More complex example: system info
 Join the Discussion
Post your views and comments to this chapter of the free "raw API programming" Delphi Course
Discuss!
 Related Resources
• A Guide to raw API programming.TOC

Chapter 2: A guide to developing Delphi programs in raw Windows API
Let's make a formless program that gets user input and creates a file, using only Windows API calls.

The article is written by Wes Turner, and brought to you by Zarko Gajic

When you create a new application in Delphi you will see a Form (Form1) and the code for this form is in a unit called Unit1. If you open the project file (Project - View Source) it should look like this:

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

The code for Form1 is in a .pas file (Unit1.pas). If you compile and run this program it will be around 250 Kb (depending on your version of Delphi), even though it does not do anything. To create an API version of the ".dpr only program" you will need to take out the Form1, click the "Remove file from project" button and highlight the Unit1 (Form1) and click OK. Now your application will not have any forms and Project1 will look like:

program Project1;

uses
  Forms,

{$R *.RES}

begin
  Application.Initialize;
  Application.Run;
end.

You should notice that the first word in this file (unit) is "Program" and not "Unit", like it is in the form units you are used to. Now Remove the uses clause completely and take out the Application.Initialize; and the Application.Run; lines, take out the Res file compiler directive {$R *.RES} so that the code looks like:

program Project1;

begin

end.

If you are not familiar with the .dpr program file, it is unlike the Unit1.pas for forms, all functions and procedures in the Form .pas file must be "called" in order for it to execute. In a .dpr, the program execution starts at "begin" and goes down line by line (executes each line of code) until it gets to "end." were code in the System unit will be executed to end the program and exit the process. In a GUI program, a loop stops the progression preventing the "end." from being executed.

Compile and run this (you may get a warning message about application or forms not being in your code, continue anyway). It will compile and run (for a couple of milliseconds), you will not see anything and it does not do anything and the app file size will be ~14 Kb (Delphi 7). You should wonder how it is possible to have an application run WITHOUT ANY CODE at all. Well there is code being executed in the Sysinit and System units, which are always used.
You needn't explicitly use any units in a project, but all programs automatically use the System unit. Code is automatically being used to start your application (diferent code is used for a "Console" mode program) in the Sysinit there are calls to initialize your program with a "Module", "hInstance", and others. In the System unit more startup things are done, like these...

function ParamCount: Integer;
var
  P: PChar;
  S: string;
begin
  P := GetParamStr(GetCommandLine, S);
  Result := 0;
  while True do
  begin
    P := GetParamStr(P, S);
    if S = '' then Break;
    Inc(Result);
  end;
end;

function ParamStr(Index: Integer): string;
var
  P: PChar;
  Buffer: array[0..260] of Char;
begin
  if Index = 0 then
    SetString(Result, 
              Buffer, 
              GetModuleFileName(0, Buffer, SizeOf(Buffer)))
  else
  begin
    P := GetCommandLine;
    while True do
    begin
      P := GetParamStr(P, Result);
      if (Index = 0) or (Result = '') then Break;
      Dec(Index);
    end;
  end;
end;

...and lots more code to start a 32 bit Windows program and have usable info like ParamStr(Index: Integer). You may want to look in your Delphi Help for the methods available in the System unit. In beginning Windows programing (for C code) you would have WinMain() to initialize your program (get an hInstance and command line), Delphi initializes it for you in the Sysinit unit, so you do not have a WinMain() in Delphi. There is also some finalization code executed at the "end.", which will do some clean up and exit the process.

Your first program without the Forms unit
Ok, let's get this program to do something. Before you start doing GUI (graphical user interface) and creating windows, let's see if you can do things with out a GUI. We will be using windows API functions so add the "uses" clause with the basic "Windows" unit. We will create a folder and a text file then write the ParamStr(0) to the text. Look in your Windows Developer "Application Programming Interface" (API) Win32 Help index for "CreateDirectory". You will see

BOOL CreateDirectory(
      LPCTSTR lpPathName, 
      LPSECURITY_ATTRIBUTES lpSecurityAttributes
      );

If you are new to C code as used in the Windows API Win32 Help, the variable type is put before the variable, not after it. Also the function result (Return in C) is put before the function, not after it. So in Delphi it would go as:

CreateDirectory(
    lpPathName: PChar; 
    lpSecurityAttributes: PSecurityAttributes
    ): Boolean;

For some info about reading the C code used in Win32 API Help, read Chapter 1 of this Course.

In this first dpr program you will include the compiler directive {$R *.RES} in the code, so you can use the Delphi Menu for "Project" click the "Options" menu item to set a program icon and place version info in the exe file as you would with a VCL project. In this application, a txt file will be created and written to disk using the Delphi system unit text file procedures AssignFile(), Rewrite() and CloseFile(). The compiler directive {$I-} is used with the Rewrite() procedure to keep the program from throwing an Exception on failure of the procedure.

Copy and paste from, or use this code:

program Project1;

uses
  Windows;

{$R *.RES}

var
File1: TextFile;
{variables are put here}

begin  // main program begin
  if  CreateDirectory('C:\Some Test Folder', nil) then
{securityAttributes are nil}
  begin
  AssignFile(File1, 'C:\Some Test Folder\test note.txt');
{use the delphi text file procedures defined in the System unit}
  {$I-}
  Rewrite(File1);
    {put the $I compiler option so exceptions will 
     not be generated and stop this program}
  {$I+}
{test the IOResult for success}
  if IOResult = 0 then
  Write(File1,'ParamStr 0 is '+ ParamStr(0));
  {$I-}
  CloseFile(File1);
  {$I+}
  end;
end.

If you compile and run this program, then look on your C drive for the folder "Some Folder" there should be a text file in it called "test note.txt". The folder and file were created without any visual display (GUI) to the user. You can do many file functions without showing anything, however there is no opportunityortunity to get user input.

Let's look at the program code above you will not see the "interface" and "implementation" sections that you are used to in the .pas units. Also notice that there are no "type" declarations like

type
  TForm1 = class(TForm)
    Button1: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Using the program file code requires a different approach than the unit .pas files. You see the variable "var" declaration above the "begin" reserved word you may also declare a "type" above the "begin". Below the "var", "const", and type declarations and above the "begin" you can place defintions for procedures and functions you will need to use. You can NOT place definitions for procedures and functions below "begin". You can call procedures you have defined above the main begin, below the begin line.

If you are used to working in the form unit, you know you need to call "Close" or "Application.Terminate" to cause your program to end. And I have seen code examples for a .dpr file that will call "Halt;" or "ExitProcess(hInstance);" just before the last line (end.) of code to terminate the program. You do NOT need to call anything to end your program. The program will stop and exit its process when it gets to the "end." of the code without you doing anything. There is cleanup code executed at the "end.", that should be allowed to happen.

Now, let's see how to get some user feedback ...

Next page > Message Boxes, Binary combine with the "OR" operator, and the PChar type. > Page 1, 2, 3

A guide to developing Delphi programs in raw Windows API: Next Chapter >>
>> Creating an API GUI Windows program with message loop

©2014 About.com. All rights reserved.