Thursday, August 21, 2008

Manipulating files in your system

Manipulating files in your system

Several common file operations are built into the runtime library (RTL). The routines for working with files operate at a high level. For most routines, we have to specify the name of the file and the routine makes the necessary calls to the operating system for us. In some cases, we have to use file handles instead.

We have runtime library routines to perform following file manipulation tasks:

  1. Checking a file
  2. Deleting a file
  3. Finding a file
  4. Renaming a file
  5. File date-time routines
  6. Copying a file

File exists ?

To check whether a file exists or not in your system, you can use FileExists command. You have to pass filename with full path information as a parameter. The function returns True if it
finds the file in the system or returns False.

Delete File

Deleting a file erases the file from the disk and removes the entry from the disk's
directory. There is no corresponding operation to restore a deleted file, so applications
should generally allow users to confirm before deleting files. To delete a file, pass the
name of the file to the DeleteFile function:

DeleteFile returns True if it deleted the file and False if it did not (for example, if the
file did not exist or if it was read-only). DeleteFile erases the file named by FileName
from the disk.

Find file

There are three routines used for finding a file: FindFirst, FindNext, and FindClose.
FindFirst searches for the first instance of a filename with a given set of attributes in a
specified directory. FindNext returns the next entry matching the name and attributes
specified in a previous call to FindFirst. FindClose releases memory allocated by FindFirst. You should always use FindClose to terminate a FindFirst/FindNext sequence.
The three file find routines take a TSearchRec as one of the parameters. TSearchRec defines
the file information searched for by FindFirst or FindNext. If a file is found, the fields
of the TSearchRec type parameter are modified to describe the found file.

See the structure of the TsearchRec.


TFileName = string;

TSearchRec = record

Time: Integer; //Time contains the time stamp of the file.

Size: Integer; //Size contains the size of the file in bytes.

Attr: Integer; //Attr represents the file attributes of the file.

Name: TFileName; //Name contains the filename and extension.

ExcludeAttr: Integer;

FindHandle: THandle;

FindData: TWin32FindData; //FindData contains additional information such as


Attr of TSearchRec is one of the commonly used property. You can test Attr against the
following attribute constants to determine if a file has a specific attribute:

Attribute Constant - Description


faReadOnly - Read only files

faHidden - Hidden files

faSysFile - System files

faVolumeID -Volume ID files

faDirectory -Directory files

faArchive -Archive files

faAnyFile -Any file

Eg :
If the found file is a hidden file, the following expression will evaluate to True:
(SearchRec.Attr and faHidden > 0).

To search for read-only and hidden files in addition to normal files, pass the following as
the Attr parameter : (faReadOnly or faHidden).

See the following code to illustrate the use of all the 3 file finding code.

var SearchRec: TSearchRec;
while (True) do


FindFirst('c:\MyFolder\*.*', faAnyFile, SearchRec);

Memo1.Add(SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size');

if FindNext(SearchRec) = 0 then

Memo1.Add(SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size')







Rename File

To change a file name, you can use the RenameFile function. Syntax is
function RenameFile(const OldFileName, NewFileName: string): Boolean;
RenameFile changes a file name, identified by OldFileName, to the name specified by
NewFileName. If the operation succeeds, RenameFile returns True. If it cannot rename the
file (for example, if a file called NewFileName already exists), RenameFile returns False.
For example:
if not RenameFile('OLDNAME.TXT','NEWNAME.TXT') then ErrorMsg('Error renaming file!');
You cannot rename (move) a file across drives using RenameFile. You would need to first copy
the file and then delete the old one.

File date-time routines

The FileAge, FileGetDate, and FileSetDate routines operate on operating system date-time
values. FileAge returns the date-and-time stamp of a file, or -1 if the file does not exist.
FileSetDate sets the date-and-time stamp for a specified file, and returns zero on success
or an error code on failure. FileGetDate returns a date-and-time stamp for the specified
file or -1 if the handle is invalid.
As with most of the file manipulating routines, FileAge uses a string filename. FileGetDate
and FileSetDate, however, use a Handle type as a parameter. To get the file handle either:
1.Use the FileOpen or FileCreate function to create a new file or open an existing file.
Both FileOpen and FileCreate return the file handle.
2.Instantiate TFileStream to create or open a file. Then use its Handle property.

Copy File

The runtime library does not provide any routines for copying a file. However, if you are
writing Windows-only applications, you can directly call the Windows API CopyFile function
to copy a file. Similar to most of the runtime library file routines, CopyFile takes a
filename as a parameter, not a file handle. CopyFile is also useful when moving files across
drives because neither the RenameFile function nor the Windows API MoveFile function can
rename or move files across drives.

Delphi provides a number of different file access mechanisms. The oldest is in support of
consoles, where the Read, ReadLn, Write and WriteLn routines have a syntax that omits the
file name. With no file name, IO (Input and Output) is routed to the console. Additionally, hidden away, Delphi provides a very elegant way of reading and writing complete text files. The TStringList class has methods for loading the list of strings from a text file. And for saving the list likewise.

Accessing files

There are a number of basic operations for handling both text and binary files.


myFile : TextFile;


AssignFile(myFile, 'Test.txt');

Here we are getting a handle to a text file, designated by the TextFile type (binary files
are of type File). We ask Delphi to assign a file handle for a file called 'Test.txt' which
will be assumed to be in the current directory.If the file exists in some other folder , you
can specify the whole path within the quotes. Next, we must open the file using this handle. This operation tells Delphi how we want to treat the file. There are 3 ways of opening the file:

ReWrite - Opens a file as new - discards existing contents if file exists

Reset - Opens a file for read and write access

Append - Opens a file for appending to the end (such as a log file)

When we have finished, we must close the file using the command : CloseFile(myFile);

Reading and writing to text files

You can any of the following commands to read from and write to the file.
Read : Reads the current line . File Pointer won't move to next line

ReadLn : Reads current line and file pointer moves to the next line.

Write : Write string to the file , But file pointer won't move to next line.

WriteLn : Writes data to file and file pointer moves to next line.
Here is a simple example of access to a text file:


myFile : TextFile;

text : string;


AssignFile(myFile, 'Test.txt');


WriteLn(myFile, 'Hello');

WriteLn(myFile, 'World');


Reset(myFile); // Reopen the file for reading

while not Eof(myFile) do


ReadLn(myFile, text);





The ShowMessage routine displays the following :



If we replaced the ReWrite routine with Append, and rerun the code, the existing file would
then contain:





Reading and writing to typed binary files

Typed binary files are files that have a data type as the basic unit of writing and reading.
You write, say, an Integer, or a Record to a file, and read the same unit of data back.
Records are particularly useful, allowing us to store any mix of data types in the one file
unit of data. This is best illustrated with an example:


TCustomer = Record

name : string[20];

age : Integer;

male : Boolean;



myFile : File of TCustomer; // A file of customer records

customer : TCustomer; // A customer record variable


AssignFile(myFile, 'Test.cus');

ReWrite(myFile); := 'Fred Bloggs';

customer.age := 21;

customer.male := true;

Write(myFile, customer); := 'Jane Turner';

customer.age := 45;

customer.male := false;

Write(myFile, customer);


FileMode := fmOpenRead;


while not Eof(myFile) do


Read(myFile, customer);

if customer.male


ShowMessage('Man with name ' ' is '+IntToStr(customer.age))

else ShowMessage('Lady with name ' ' is '+IntToStr(customer.age));




Output : Man with name Fred Bloggs is 21

Lady with name Jane Turner is 45
The code is very similar to that used for text files, except that we define a file of a
certain type (record), and pass/receive record data when writing/reading.

Reading and writing to pure binary files

Pure binary files are a bit peculiar. You must use BlockRead and BlockWrite instead of Read
and Write. These have the added benefit of greater performance than the Read and Write.

Here is an example :


myFile : File;

byteArray : array[1..8] of byte;

oneByte : byte;

i, count : Integer;


AssignFile(myFile, 'Test.byt');

ReWrite(myFile, 4); // Define a single 'record' as 4 bytes

for i := 1 to 8 do

byteArray[i] := i;

BlockWrite(myFile, byteArray, 2); // Write 2 'records' of 4 bytes

// Fill out the data array with different data

for i := 1 to 4 do byteArray[i] := i*i; // Value : 1, 4, 9, 16

BlockWrite(myFile, byteArray, 1); // Write 1 record of 4 bytes


FileMode := fmOpenRead;

Reset(myFile, 1);

ShowMessage('Reading first set of bytes :');

BlockRead(myFile, byteArray, 6, count); // Display the byte values read

for i := 1 to count do


ShowMessage('Reading remaining bytes :');

while not Eof(myFile) do


BlockRead(myFile, oneByte, 1); // Read and display one byte at a time





Getting information about files and directories

There are a number of routines that allow you to do all sorts of things with files and
directories that contain them:

ChDir : Change the working drive plus path for a specified drive

CreateDir : Create a directory

Erase : Erase a file

FileSearch : Search for a file in one or more directories

FileSetDate : Set the last modified date and time of a file

Flush : Flushes buffered text file data to the file

GetCurrentDir : Get the current directory (drive plus directory)

MkDir : Make a directory

RemoveDir : Remove a directory

Rename : Rename a file

RmDir : Remove a directory

SelectDirectory : Display a dialog to allow user selection of a directory

SetCurrentDir : Change the current directory

Truncate : Truncates a file size

Using TStringList to read and write text files

The TStringList class is a very useful utility class that works on a lits of strings, each
indexable like an array. The list can be sorted, and supports name/value pair strings,
allowing selection by name or value. These lists can be furnished from text files. Here we show a TStringList object being created, and loaded from a file:


fileData : TStringList; // Our TStringList variable


fileData := TStringList.Create; // Create the TSTringList object

fileData.LoadFromFile('Testing.txt'); // Load from Testing.txt file ...

We can display the whole file in a Memo box : memoBox.Text := fileData.Text;
Similarly you can use the SaveToFile command to save the whole strings stored inside the
String List to a text file.
Eg: fileData.SaveToFile('Test.txt'); // Save the reverse sequence file

Wednesday, August 6, 2008

How to configure PHP 5 and Apache 2.2

Hi all!

I faced lots of problems while setting up PHP and Apache web server. It took almost 2 days for me to set it up:-(. So I thought I have to write down all the steps I had done to set up so that it can be useful for someone who are intending to setup.

Step 1 - Download PHP 5 zip package and Apache 2.2 installer. Make sure you are downloading only the Zip package for PHP. Never download the PHP installer. Because it does not contain all the support dlls.

Step 2 - First install your Apache 2.2 web server in your local machine. By default it'll install Apache in the folder "C:\Program Files\Apache Software Foundation\Apache2.2"

Step 3 - Click on the "Monitor Apache Services" menu and see all the Apache services are running properly. You'll get an icon on the taksbar .

Step 4 - Create a new folder called PHP under C:\ and unzip the PHP zip package under this folder. Few important files available in that folder are


Step 5 - Rename file "php.ini-recommended" to "php.ini". Plz take a copy of this file before doing that. Because we have to change some configurations in this file.

Step 6 - Copy file php5ts.dll to windows system32 folder and Apache server's Bin folder.

Step 7 - Make following changes to 'php.ini' file. Find out "doc_root" keyword in php.ini and set the Apache HtDocs folder path here as shown below.

doc_root =C:\Program Files\Apache Software Foundation\Apache2.2\htdocs
You can specify the path of HtDocs folder where you installed Apache.

This is the only configuration I have changed. If you want to change , you can do that according to the Install.txt

Step 8 - Copy Php.ini to C:\Program Files\Apache Software Foundation\Apache2.2 folder.

Step 9 - Now we are going to touch another configuration file 'Httpd.conf' under Apache folder. You can find this fle under the "Conf" folder (C:\Program Files\Apache Software Foundation\Apache2.2\Conf). Before making any change, plz take a copy of this file.

Step 10 - Search for "ServerRoot" configuration. You can find the folder where you installed Apache. No need to change this. Just verify whether this is correct.

Step 11 - Now you can see configurations like Listen and Listen 80. If you are configuring Apache in your local machine, instead of these configurations, you can have LISTEN localhost:80.

Step 12 - Next configuration is LoadModule. You have to add the following line under the LoadModules available in the httpd.conf file. You can find so many loadModule statements in the httpd.conf file. Just add the following under the last LoadModule Statement.

LoadModule php5_module "c:/php/php5apache2_2.dll"

If you have installed Apache 2, then you have to add the following line.

LoadModule php5_module "c:/php/php5apache2.dll" . Verify this .dll file is available under the PHP folder. So depends on the version of Apache server, you have to add the respective LoadModule statement.

Step 13 - Add the following lines under LoadModule statement.

SetEnv PHPRC C:/php
Action application/x-httpd-php "c:/php/php-cgi.exe"

Step 14 - If still you have the PHPRC configuration, sometimes it won't work. Better you can add the path in the Windows Environment variable.

Steps to add an environment variable:

1. Select "MyComputer" icon in your desktop.
2. Right click the icon and select the "Properties" menu. System properties dialog box will pop
3. Select "Advanced" tab. In the bottom of the window, you can see a button with caption
"Environment Variables"
4. Click that button and a new dialog box comes up with all available environment variables.
5. In this dialog , you can see 2 lists . One for User variables and one for System variables.
6. Select the Path variable in the "System variables" list.
7. Click on the edit button and you'll get an edit window for this system variable.
8. Go to the end of the "Variable Value" and add following text
9. Click Ok buttons continuously to save the environment variable.

Step 15 - Search for DirectoryIndex configuration. You can find the following line

DirectoryIndex index.html
Replace this line with
DirectoryIndex index.html index.php index.html.var

Step 16 - Search for the module name "mime_module". You have to add following lines under this module .

AddType application/x-httpd-php .html .php
AddType application/x-httpd-php-source phps
AddHandler php5-script php
AddType text/html .php

Step 17 - You have done all the configurations. Now restart your machine and start your Apache web server.

Step 18 - Copy your Index.html to C:\Program Files\Apache Software Foundation\Apache2.2\htdocs

Step 19 - Open your browser and type http://localhost/ and see whether you are getting the output of the index.html you have copied in step 18.

Step 20 - If your site is working fine, you have done the setup :-).

Now you can create your own PHP files and try with Apache server.
Have a good day!

Sunday, August 3, 2008

Threads in Delphi

If we have a time consuming loop in our Delphi program , then till the loop ends , the interface will be stuck. It won't process any messages. You can avoid this problem by adding Application.ProcessMessages inside the loop. So the messages get processed inside the loop also. Application.ProcessMessages is practically useless because the application will only receive messages at the time the call is made. It won't release the interface. Using a thread, on the other hand, frees up the interface because the process is running completely separate from the main thread of the program where the interface resides. So regardless of what you execute within a loop that is running in a separate thread, your interface will never get locked up.
You can have multiple threads to process different independent operations.

To use a thread object in your application, you must create a new descendant of TThread. To create a descendant of TThread, choose FileNewOther from the main menu. In the New Items dialog box, double-click Thread Object and enter a class name, such as TMyThread. To name this new thread, check the Named Thread check box and enter a thread name (VCL applications only). Naming your thread makes it easier to track the thread while debugging. After you click OK, the Code editor creates a new unit file to implement the thread. For more information on naming threads, see Naming a thread.Unlike most dialog boxes in the IDE that require a class name, the New Thread Object dialog box does not automatically prepend a 'T' to the front of the class name you provide.

The automatically generated unit file contains the skeleton code for your new thread class. If you named your thread TMyThread, it would look like the following:
unit Unit1;
uses Classes;
type TMyThread = class(TThread)
private { Private declarations }
protected procedure Execute; override;

implementation{ TMyThread }

procedure TMyThread.Execute;
begin { Place thread code here }


Initializing a thread
If you want to write initialization code for your new thread class, you must override the Create method. Add a new constructor to the declaration of your thread class and write the initialization code as its implementation. This is where you can assign a default priority for your thread and indicate whether it should be freed automatically when it finishes executing.

Default priority
Priority indicates how much preference the thread gets when the operating system schedules CPU time among all the threads in your application. Use a high priority thread to handle time critical tasks, and a low priority thread to perform other tasks. To indicate the priority of your thread object, set the Priority property.

If writing a Windows-only application, Priority values fall along a scale, as described in the following table:
Value : Priority
tpIdle : The thread executes only when the system is idle. Windows
: won't interrupt other threads to execute a thread with tpIdle priority.
tpLowest : The thread's priority is two points below normal.
tpLower : The thread's priority is one point below normal.
tpNormal : The thread has normal priority.
tpHigher : The thread's priority is one point above normal.
tpHighest : The thread's priority is two points above normal.
tpTimeCritical : The thread gets highest priority.

constructor TMyThread.Create(CreateSuspended: Boolean);
inherited Create(CreateSuspended);
Priority := tpIdle;

When threads are freed
Usually, when threads finish their operation, they can simply be freed. In this case, it is easiest to let the thread object free itself. To do this, set the FreeOnTerminate property to True.
There are times, however, when the termination of a thread must be coordinated with other threads. For example, you may be waiting for one thread to return a value before performing an action in another thread. To do this, you do not want to free the first thread until the second has received the return value. You can handle this situation by setting FreeOnTerminate to False and then explicitly freeing the first thread from the second.

Execute method
The Execute method is your thread function. You can think of it as a program that is launched by your application, except that it shares the same process space. Writing the thread function is a little trickier than writing a separate program because you must make sure that you don't overwrite memory that is used by other threads in your application. On the other hand, because the thread shares the same process space with other threads, you can use the shared memory to communicate between threads.

When you use objects from the class hierarchy, their properties and methods are not guaranteed to be thread-safe. That is, accessing properties or executing methods may perform some actions that use memory which is not protected from the actions of other threads. Because of this, a main thread is set aside to access VCL and CLX objects. This is the thread that handles all Windows messages received by components in your application.

If all objects access their properties and execute their methods within this single thread, you need not worry about your objects interfering with each other. To use the main thread, create a separate routine that performs the required actions. Call this separate routine from within your thread's Synchronize method. For example:

procedure TMyThread.ClickButton;

procedure TMyThread.Execute;

Synchronize waits for the main thread to enter the message loop and then executes the passed method.

If you want to use variables that are global to all the routines running in your thread, but not shared with other instances of the same thread class. You can do this by declaring thread-local variables. Make a variable thread-local by declaring it in a threadvar section. For example,

threadvar x : integer;

declares an integer type variable that is private to each thread in the application, but global within each thread.

Exception Handling in Delphi

We know that errors do occur time to time in any application evenif we think we write only perfect code :-) . We cann't avoid the unexpected errors most of the time. If you are a serious coder , you have to think about the error occuring situations and handle these errors. Delphi has a very advanced exception handling to trap these kind of errors and mainly to avoid system crash. Also you can use this to store your data and release memory properly before an exception. If you have an exception handler for a particular piece of code, the control will jump to this handler when any exception occur in that particular code. Following are the keywords available in Delphi for exception handling.

1. Try .. Except .. end

2. Try ... Finally..end

3. Raise

If you have a piece of code in between Try and Except and any exception occur in any of these code , the control will stop executing try .. except block and control will jump to except .. end block. See the following piece of code.

A := B / C;
A := 0;
ShowMessage('Error occured');

If any error occur in the 2 lines between Try and Except block , control will jump to the block between Except and end. If no error occur in the code between Try and Except , control will jump to the statement just below the end statement. It won't execute the error handler code. In Delphi, all exceptions are derived from the base class called Exception. If you need more information from the exception happened , you have to use the exception class along with Except clause as shown below.

A := B / C;
On E : Exception do
A := 0;
ShowMessage('Error Message - ' + E.Message);
ShowMessage('Error class name - ' + E.ClassName);

Instead of Exception base class, you can use specific classes like EAccessViolation , EDatabaseError , EConvertError Etc.

Result := x / y;
on EZeroDivide do
Result := 0,0;
ShowMessage('Divide by zero!');

You have one more kind of exception in Delphi, that's Try..Finally..end . Finally .. end block is a handler which should execute in any case. If you got any exception in the try .. finally block or if you don’t have any exception in try .. finally block also, the finally .. end block will be executed. So this kind of handler can be used to free memory properly so that the memory will be released in any situations.

Frm := TMyClass.Create();
Result := IntToStr(A);

Raise Exceptions

If you want to raise an exception explicitly , you can use the command Raise.

Delphi exceptions

Exception - Base class
EAbort - Abort without dialog
EAbstractError - Abstract method error
AssertionFailed - Assert call failed
EBitsError - Boolean array error
ECommonCalendarError - Calendar calc error
EDateTimeError - DateTime calc error
EMonthCalError - Month calc error
EConversionError - Raised by Convert
EConvertError - Object convert error
EDatabaseError - Database error
EExternal - Hardware/Windows error
EAccessViolation - Access violation
EControlC - User abort occured
EExternalException - Other Internal error
EIntError - Integer calc error
EDivByZero - Integer Divide by zero
EIntOverflow - Integer overflow
ERangeError - Out of value range
EMathError - Floating point error
EInvalidArgument - Bad argument value
EInvalidOp - Inappropriate operation
EOverflow - Value too large
EUnderflow - Value too small
EZeroDivide - Floating Divide by zero
EStackOverflow - Severe Delphi problem
EHeapException - Dynamic memory problem
EInvalidPointer - Bad memory pointer
EOutOfMemory - Cannot allocate memory
EInOutError - IO error
EInvalidCast - Object casting error
EInvalidOperation - Bad component op
EMenuError - Menu item error
EOSError - Operating system error
EParserError - Parsing error
EPrinter - Printer error
EPropertyError - Class property error#
EPropReadOnly - Invalid property access
EPropWriteOnly - Invalid property access
EThread - Thread error
EVariantError - Variant problem

Saturday, August 2, 2008

Message Handling in Delphi

Delphi allows you to define your own messages which'll then be posted on the Windows message queue and then handled by your own custom handler in your application.

Define your own custom message
Each message must have a unique id. The constant WM_USER is defined (in the Messages unit) as the first message number available for application use.


These messages should be defined in the interface section of the unit containing the form that will be handling them. Alternately, to guarantee that all messages are unique within an application consider defining all your messages together in a single unit.
WM_USER is fine for internal application messages.
Use WM_APP for messages between applications.
Use the RegisterMessage API call if you need a message number that is guaranteed to be unique in a system.

Define a handler for the message
To add a message handler to a form, define a procedure that takes an argument of type TMessage and add the directive "message" with the message id that the procedure is to handle.

For example:
type TMyForm = class(TForm) .
procedure OnTestMessage(var Msg: TMessage); message WM_TEST_MESSAGE ;
procedure OnHelloMessage(var Msg: TMessage); message WM_HELLO_MESSAGE ;
Send the message
To send a message use either:
PostMessage (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL;
SendMessage (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL;
both of which are defined in the Windows unit. Both of these will append the message to the end of the application's Windows message queue. The difference between them is that SendMessage will not return until the message has been handled, whereas PostMessage will return straight away.

Pass data via messages
The additional parameters wParam and lParam provide a mechanism to pass some additional information along with the message. Both of these parameters are defined as type Integer. At the recipient end the values can be extracted from the message by simply referencing the WParam and LParam members of TMessage.

Note: The technique described here is suited for sending data from a thread to the main process (or form) of the application. The wParam and lParam members are ideally suited for passing integer data, but can also be used to pass objects, for example:
and at the recipient end:
procedure TMyForm.OnHelloMessage(var Msg: TMessage);
var myObject: TMyClass;
begin myObject := TMyClass(msg.WParam);
You must ensure that the pointer being sent is still valid when it is used by the recipient. A simple approach is to use SendMessage rather than PostMessage. Consider if you use PostMessage and then free the object being sent, the recipient may pick up the
reference to the object after it has been freed - at best this will be a source of difficult to find bugs, at worst it may crash your program.

Friday, August 1, 2008

Useful Delphi sites

Useful Delhi sites








Delphi Groups
1. INDUG - Indian Delphi group

2. ADUG - Australian Delphi group

3. DelphiNet

4. delphi-en

5. advanced_delphi

6. Interbase 2000

7. Delphi-DUnit

8. D-Winsock

9. delphi_programers

10. indug-jobs