PDA

View Full Version : Delphi 6 Tutorial (Chapter 7)


_I_Play_Chess
10-25-2003, 10:40 AM
Sophisticated Delphi Pascal techniques for Beginners
------------------------------------------------------------------

Sophisticated Delphi Pascal techniques for Beginners. Time to extend your Delphi Pascal knowledge to the max. Here are some intermediate Delphi problems and articles for everyday development tasks.
Welcome to the seventh chapter of the FREE online programming course:

Delphi Pascal: a step forward
Here's a list of tutorials, and articles, that will help you learn more of Delphi Pascal. Each tutorial will help you to better understand a particular feature of Delphi Pascal language, with practical and easy to understand workigng code examples.
Some of the articles use Windows API calls, if you are unfamiliar with the term, do not run away, just follow the article code and you'll understand it completely.

Base Conversions, and more: (See chapter 7 page 1)
-------------------------------------------------------------------
Routines for converting Int to Bin, Int to Hex, Int to Roman and vice versa

Disk in drive A: (See chapter 7 page 2)
------------------------------------------------
Some useful routines when playing with floppy disk and Delphi

Start from Delphi: (See chapter 7 page 3)
---------------------------------------------------
Executing and running applications and files from Delphi.

Auto completing Dates: (See chapter 7 page 4)
----------------------------------------------------------
Date manipulation: improve your code, let them type faster

NO GUI Delphi applications: (Already exposed in Chapter 6)
--------------------------------------------------------------------------
Creating a console mode application with Delphi; a text-mode program that runs without a graphical interface. Even more: see how to capture the output of a console application in a GUI Delphi program.

Text Files in Delphi: (See chapter 7 page 5)
------------------------------------------------------
Handling ASCII files from Object Pascal code.

Errors and Exceptions: (See chapter 7 page 6)
----------------------------------------------------------
How to handle errors and exceptions in Delphi.

To the next chapter: A Beginner's Guide to Delphi Programming
This is the end of the seventh chapter, in the next chapter, we'll deal the arto of commenting Delphi Pascal source code.

_I_Play_Chess
10-25-2003, 10:44 AM
Base Conversions, and more
Numbers, numbers...
------------------------------------

A number system defines a set of values used to represent quantity. Computer uses the binary system. Understanding binary and hexadecimal numbers (often used to represent values [numbers and memory addresses] in computer systems) is essential for systems-level programming. Binary numbers are important because the computer "works with" binary numbers -- numbers composed of two digits, 1 and 0. Hexadecimal numbers are convenient because they allow us to handle binary numbers easily.

Delphi provides many useful functions for converting integer (decimal) values to strings (way to represent hexadecimal and binary numbers) and vice versa.

Let's see what functions we can use to convert numbers from one base to another, what functions are missing and how to easily implement them in Object Pascal.

IntToHex, HexToInt

In the SysUtils unit there is an IntToHex function that returns the hex representation of an integer.
----------------------------------------
function IntToHex (Value: Integer; Digits: Integer): string;
----------------------------------------

Ok, we have the ability to convert integer to hexadecimal, but where is the HexToInt function? There is no HexToInt function in Delphi??.
Nevertheless, Delphi allows expressions with hexadecimal notation (using a $ prefix). So, here is a simple HexToInt function:
---------------------------------
function HexToInt(HexNum: string): LongInt;
begin
Result:=StrToInt('$' + HexNum);
end;
---------------------------------

IntToBin, BinToInt

First, to be more familiar with binary numbers, why not read: An Introduction to Binary Arithmetic.
Like HexToInt, there are no IntToBin and BinToInt functions in Delphi. Therefore, here they are:
------------------------------
function IntToBin(Value: LongInt;
Digits: Integer): String;
var
i: Integer;
begin
Result:='';
for i:=Digits downto 0 do
if Value and (1 shl i)<>0 then
Result:=Result + '1'
else
Result:=Result + '0';
end;
---------------------------------

function BinToInt(Value: String): LongInt;
var i: Integer;
begin
Result:=0;
//remove leading zeros
while Copy(Value,1,1)='0' do
Value:=Copy(Value,2,Length(Value)-1);
//do the conversion
for i:=Length(Value) downto 1 do
if Copy(Value,i,1)='1' then
Result:=Result+(1 shl (i-1));
end;
---------------------------------

Romans

The number system in most common use today is the Arabic system. The ten single-digit numerals, "0" through "9", make up the symbols of our numbering system. An example of a different numeral system is the system of Roman numerals, which could represent all the numbers from 1 to 1,000,000 using only seven symbols: I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000. Example: 1999 (Arabic) is MCMXCIX (Roman).
---------------------------
function IntToRoman(Value: LongInt): String;
const
Arabics: Array[1..13] of Integer =
(1,4,5,9,10,40,50,90,100,400,500,900,1000);
Romans: Array[1..13] of String =
('I','IV','V','IX','X','XL','L','XC','C','CD','D', 'CM','M');
var
i: Integer;
begin
for i := 13 downto 1 do
while (Value >= Arabics[i]) do begin
Value := Value - Arabics[i];
Result := Result + Romans[i];
end;
end;
------------------------------

_I_Play_Chess
10-25-2003, 11:08 AM
DISK IN DRIVE A:
---------------------
In this article, you will find some useful routines/techniques when playing with floppy disk and Delphi.

Preparations
Let's see some of the functions and API calls that are going to be used in the following examples/procedures:

SetErrorMode
-----------------
The SetErrorMode API function controls how the operating system handles several types of serious errors. When SEM_FAILCRITICALERRORS is set the operating system does not display the critical-error-handler message box when such an error occurs. Instead, the operating system sends the error to the calling process.

DiskSize
----------
Function returns the size in bytes of the specified drive number, where 0 = Current, 1 = A, 2 = B, etc. DiskSize returns -1 if the drive number is invalid.

DiskFree
-----------
Function returns the number of free bytes on the specified drive number, where 0 = Current, 1 = A, 2 = B, and so on. DiskFree returns -1 if the drive number is invalid.

GetVolumeInformation
----------------------------
This API function fills some variables passed as formal parameters to give you information such as the disk serial number and volume name, the file system employed, and various things the drive supports such as compression and long file names.

ShFormatDrive
------------------
SHFormatDrive function is not documented in the help files neither is it declared by Delphi. We will have to declare this function form the Shell32.dll. It provides access to the Widows format dialog box. To declare functions from a DLL, append the reserved word external and the name of the DLL to the end of a normal procedure or function header. You will also have to add calling convention of stdcall since we are using a WIN32 API DLL. As I am using this function only in this one unit, I declare it just before the procedure that will use it.


Is disk in Drive?
----------------------
Before trying to save or load a file you can "quietly" check if a floppy drive has a floppy disk in it and present the user with a meaningful error message rather than just getting a critical error box that Windows displays.
--------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var EMode: Word;
begin
EMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
if DiskSize(Ord('A')-$40) <> -1 then
ShowMessage('Disk in drive A: !')
else
ShowMessage('No disk in drive A: !');
finally
SetErrorMode(EMode);
end;
end;
------------------------------

Disk free space
----------------------
If you need to do a backup on a floppy disk, it is a good idea to check amount of free disk space.
------------------------------
procedure TForm1.Button2Click(Sender: TObject);
var Drive: Byte;
sFD, sSD : string;
DFree, DSize : integer;
begin
Drive:=1;
DFree:=DiskFree(Drive);
DSize:=DiskSize(Drive);
if (DFree <> -1) and (DSize <> -1) then begin
sFD:='Disk Free: '+IntToStr(DFree div 1024)+' Kb';
sSD:='Disk Size: '+IntToStr(DSize div 1024)+' Kb';
ShowMessage(sFD + #13 + sSD);
end;
end;
-------------------------------

Serial number
--------------------
Just for fun. (With some modifications, you can use this code to get serial number of any disk - e.g. C:)
(See a complete program below on how to Open/Close and much more of your CD's drives on your computer)....
------------------------------
procedure TForm1.Button3Click(Sender: TObject);
var VolumeSerialNumber : DWORD;
MaximumComponentLength : DWORD;
FileSystemFlags : DWORD;
SerialNumber : string;
begin
GetVolumeInformation('A:\',
nil,
0,
@VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
nil,
0);
SerialNumber:=IntToHex(HiWord(VolumeSerialNumber), 4)
+ ' - ' +
IntToHex(LoWord(VolumeSerialNumber),4);

ShowMessage(SerialNumber);
end;
--------------------------------

Windows format
-----------------------
The idea here is to handle disk formatting using the same dialog box that the Shell uses. If you want to, you can even silently use DOS format function.
Note: add ShellApi to unit's uses clause.
-----------------------------
function SHFormatDrive(hWnd : HWND;
Drive : Word;
fmtID : Word;
Options : Word) : Longint
stdcall; external 'Shell32.dll' name 'SHFormatDrive';
-----------------------------

procedure TForm1.Button4Click(Sender: TObject);
const
SHFMT_DRV_A = 0;
SHFMT_DRV_B = 1;
SHFMT_ID_DEFAULT = $FFFF;
SHFMT_OPT_QUICKFORMAT = 0;
SHFMT_OPT_FULLFORMAT = 1;
SHFMT_OPT_SYSONLY = 2;
SHFMT_ERROR = -1;
SHFMT_CANCEL = -2;
SHFMT_NOFORMAT = -3;
var
FmtRes : LongInt;
begin
try
FmtRes:=ShFormatDrive(Handle,
SHFMT_DRV_A,
SHFMT_ID_DEFAULT,
SHFMT_OPT_QUICKFORMAT);
case FmtRes of
SHFMT_ERROR:
ShowMessage('Error formatting the drive');
SHFMT_CANCEL:
ShowMessage('User canceled formatting the drive');
SHFMT_NOFORMAT:
ShowMessage('Drive is not formatable')
else
ShowMessage('Disk has been formatted');
end;
except
ShowMessage('Error occurred!')
end;
end;
----------------------------
Here is the complete code of the Floppy:

**
Disk in drive A:

Some useful routines when playing with floppy disk and Delphi.

********************************************
}


unit floppy;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Button3: TButton;
Button2: TButton;
Button4: TButton;
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
** Private declarations }
public
** Public declarations }
end;

var
Form1: TForm1;

implementation
**$R *.DFM}

procedure TForm1.Button3Click(Sender: TObject);
var VolumeSerialNumber : DWORD;
MaximumComponentLength : DWORD;
FileSystemFlags : DWORD;
SerialNumber : string;
begin
GetVolumeInformation('A:\',
nil,
0,
@VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
nil,
0);
SerialNumber:=IntToHex(HiWord(VolumeSerialNumber), 4)+
' - ' +
IntToHex(LoWord(VolumeSerialNumber),4);

ShowMessage(SerialNumber);
end;

procedure TForm1.Button1Click(Sender: TObject);
var EMode: Word;
begin
EMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
if DiskSize(Ord('A')-$40) <> -1 then
ShowMessage('Disk in drive A: !')
else
ShowMessage('No disk in drive A: !');
finally
SetErrorMode(EMode);
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var FreeTotal, SizeTotal : Integer;
sFD, sSD : string;
begin
FreeTotal := DiskFree(1);
if FreeTotal <> -1 then begin
SizeTotal := DiskSize(1);
if SizeTotal <> -1 then begin
FreeTotal := FreeTotal div 1024;
SizeTotal := SizeTotal div 1024;
sFD := 'Disk Free: '+Format('%d',[FreeTotal]) + ' Kb';
sSD := 'Disk Size: '+Format('%d',[SizeTotal]) + ' Kb';
ShowMessage(sFD + #13 + sSD);
end;
end;
end;

function SHFormatDrive(hWnd : HWND;
Drive : Word;
fmtID : Word;
Options : Word) : Longint
stdcall; external 'Shell32.dll' name 'SHFormatDrive';

procedure TForm1.Button4Click(Sender: TObject);
const
SHFMT_DRV_A = 0;
SHFMT_DRV_B = 1;
SHFMT_ID_DEFAULT = $FFFF;
SHFMT_OPT_QUICKFORMAT = 0;
SHFMT_OPT_FULLFORMAT = 1;
SHFMT_OPT_SYSONLY = 2;
SHFMT_ERROR = -1;
SHFMT_CANCEL = -2;
SHFMT_NOFORMAT = -3;
var
FmtRes : LongInt;
begin
try
FmtRes:=ShFormatDrive(Handle,
SHFMT_DRV_A,
SHFMT_ID_DEFAULT,
SHFMT_OPT_QUICKFORMAT);
case FmtRes of
SHFMT_ERROR:
ShowMessage('Error formatting the drive');
SHFMT_CANCEL:
ShowMessage('User canceled formatting the drive');
SHFMT_NOFORMAT:
ShowMessage('Drive is not formatable')
else
ShowMessage('Disk has been formatted');
end;
except
ShowMessage('Error occurred!')
end;
end;

end.
----------------------------------------------
Compile it and have fun :(see the form picture attached below)

Conclusion
In some cases, you will need to handle floppy disk. These functions are here to help you, and to save the time and energy you might spend in searching for right solution. Don't panic if you don't understand some of the code here, try to play with it for a while, and you'll see that Windows API is not so hard as it seems.
Note: It is very easy to implement such procedures (some of them) to work with CD-ROM or any other removable media.

_I_Play_Chess
10-25-2003, 11:11 AM
---------------------------------
here is another interesting code for Open/Close CD drives on you computer:
Home work to do: You will find it in the code below:
---------------------------
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
MMSystem, StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ComboBox1: TComboBox;
Label1: TLabel;
Panel1: TPanel;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);

procedure Button3Click(Sender: TObject);


private
** Déclarations privées }
public
** Déclarations publiques }
end;

var
Form1: TForm1;

procedure OpenDoor(DriveLetter: string);
procedure CloseDoor(DriveLetter: string);

implementation

**$R *.DFM}

procedure OpenDoor(DriveLetter: string) ;
var
AliasName: string;
st: string;
begin
AliasName := 'Laufwerk' + DriveLetter ;
st := 'Open ' + DriveLetter + ': Alias ' + AliasName + ' Type CDAudio';
mciSendString(@st[1], nil, 0, 0);
st := 'Set ' + AliasName + ' Door Open';
mciSendString(@st[1], nil, 0, 0);
end;

procedure CloseDoor(DriveLetter: string);
var
AliasName: string;
st: string;
begin
AliasName := 'Laufwerk' + DriveLetter;
st := 'Open ' + DriveLetter + ': Alias ' + AliasName + ' Type CDAudio';
mciSendString(@st[1], nil, 0, 0 ) ;
st := 'Set ' + AliasName +' Door Closed';
mciSendString(@st[1], nil, 0, 0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
OpenDoor(ComboBox1.Text);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CloseDoor(ComboBox1.Text);
end;

procedure TForm1.Button3Click(Sender: TObject);
var VolumeSerialNumber : DWORD;
MaximumComponentLength : DWORD;
FileSystemFlags : DWORD;
SerialNumber : string;

begin
//Here we Showed you how to get the serial number of the drive D as exemple :
// Your home work is to show me:
//How to give the other drives "E,F,G...." them serial numbers?
// Remenber you learned that already.

GetVolumeInformation('D:\',
nil,
0,
@VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
nil,
0);
SerialNumber:=IntToHex(HiWord(VolumeSerialNumber), 4)
+ ' - ' +
IntToHex(LoWord(VolumeSerialNumber),4);

ShowMessage('The Serial Number of this drive is: ' + SerialNumber);

end;

procedure TForm1.FormCreate(Sender: TObject);
var
Drive: char;
begin
for Drive := 'A' to 'Z' do
begin
if (GetDriveType(PChar(Drive + ':\')) = DRIVE_CDROM) then ComboBox1.Items.Add(Drive + ':');
end;
ComboBox1.ItemIndex := 0;
end;

end.
-------------------------------
Compile it and have fun.
Don't forget to show me in a REPLY what is your code to make all drives automatically shown them serial numbers not only the "D".
Good luck.

_I_Play_Chess
10-25-2003, 11:18 AM
START FROM DELPHI
-------------------------

Executing and running applications and files from Delphi.

Start

How many times have you wanted to execute some program from your Delphi application?
Let's say we have a database application that uses some external backup utility. The Back Up utility takes parameters from your application, archives data, while your program waits until backup finishes.
On the other hand, have you ever needed to open documents presented in a file listbox, just by double clicking on them, without opening the associated program first?
Finally, imagine a link-label in your program that will take the user to your home page (by executing the Internet Explorer). Moreover, what do you say about sending an e-mail directly from your Delphi application through default Windows e-mail client program (like MS Outlook Express).

ShellExecute

To launch an application or execute a file in Win32 environment we will use the ShellExecute Windows API function. Check out the help on ShellExecute for full description of parameters and error codes returned.
As you will see we can open any type of document from our program without knowing which program is associated with it (this link is defined in the Windows Registry).

Let's see some shell action!
Be sure to add ShellApi to your Unit's uses clause.

-------------------
Run Notepad
uses ShellApi;
...
ShellExecute(Handle, 'open',
'c:\Windows\notepad.exe', nil, nil, SW_SHOWNORMAL);
------------------

Open SomeText.txt with Notepad
ShellExecute(Handle,'open',
'c:\windows\notepad.exe','c:\SomeText.txt',
nil, SW_SHOWNORMAL);
------------------

Display the contents of the "DelphiDownload" folder
------------------
ShellExecute(Handle,'open',
'c:\DelphiDownload',
nil, nil, SW_SHOWNORMAL);
------------------

Execute a file according to its extension
------------------
ShellExecute(Handle, 'open',
'c:\MyDocuments\Letter.doc',nil,nil,SW_SHOWNORMAL) ;
------------------

Open web site or a *.htm file with the default web explorer
------------------
ShellExecute(Handle, 'open',
'http://delphi.about.com',nil,nil, SW_SHOWNORMAL);

Send an e-mail with the subject and the message body
------------------
var em_subject, em_body, em_mail : string;
begin
em_subject := 'This is the subject line';
em_body := 'Message body text goes here';

em_mail := 'mailto:delphi.guide@limpkinw.com?subject=' +
em_subject + '&body=' + em_body ;

ShellExecute(Handle,'open',
PChar(em_mail), nil, nil, SW_SHOWNORMAL);
end;
------------------

Execute a program and wait until it has finished. The following example uses the ShellExecuteEx API function.

-----------------
// Execute the Windows Calculator and pop up
// a message when the Calc is terminated.
uses ShellApi;
...
var
SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
ExecuteFile, ParamString, StartInString: string;
begin
ExecuteFile:='c:\Windows\Calc.exe';

FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(TShellExecuteInfo);
with SEInfo do begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(ExecuteFile);
**
ParamString can contain the
application parameters.
}
// lpParameters := PChar(ParamString);
**
StartInString specifies the
name of the working directory.
If ommited, the current directory is used.
}
// lpDirectory := PChar(StartInString);
nShow := SW_SHOWNORMAL;
end;
if ShellExecuteEx(@SEInfo) then begin
repeat
Application.ProcessMessages;
GetExitCodeProcess(SEInfo.hProcess, ExitCode);
until (ExitCode <> STILL_ACTIVE) or
Application.Terminated;
ShowMessage('Calculator terminated');
end
else ShowMessage('Error starting Calc!');
end;

-----------------------

WinExec

If you are working with Windows 3.xx and 16 bit applications use the WinExec function, like:
----------------------
// run Notepad
WinExec('c:\windows\NOTEPAD.EXE', SW_SHOWNORMAL);

// run Notepad and display SomeText.txt
WinExec('c:\windows\NOTEPAD.EXE C:\SomeText.txt',
SW_SHOWNORMAL);

// execute a DOS DIR command
WinExec('COMMAND.COM /C DIR *.*', SW_SHOWNORMAL);
----------------------

_I_Play_Chess
10-25-2003, 11:26 AM
AUTO COMPLETING DATES
---------------------------------

Date manipulation: improve your code, let them type faster.
Little background
Faster, safer, better. Today, developing (Windows) applications requires faster data input/manipulating functions and ways. In most occasions our users are required to input date values.
Components like TDateTimePicker and similar that are designed specifically for entering dates or times are useful when we want some visual representation of a date. However, why bother with visual components that are 'not-so-input-friendly when everything we want is just one Edit box to type the date into.
In this article you will find one great function designed to make date processing a bit faster.

Date manipulation

The following DateComplete function is used to auto complete the given string value to a date representation.
The whole idea is to allow our users to only start typing the date and then to finish it from code when appropriate (in most cases in the OnExit event of some edit-enabled control.)
For example, if the default Windows short date format is 'dd.mm.yyyy' then assigning '29' to the StrLikeDate variable will, after calling the DateComplete procedure, result in '29.01.2000'. Of course, this is all true if the current month and year are January, 2000.
----------------------
procedure DateComplete
(var StrLikeDate:string;
const NowIfError:boolean = True);
var
DateStr : string;
Year, Month, Day : Word;
i, SepCount : Integer;
begin
DateStr:=StrLikeDate;

if DateStr = '' then Exit;
SepCount := 0;
for i := 1 to Length(DateStr) do begin
if not (DateStr[i] in ['0'..'9']) then begin
DateStr[i] := DateSeparator;
inc(SepCount);
end;
end;
while (DateStr <> '') and
(DateStr[Length(DateStr)]=DateSeparator) do
begin
Delete(DateStr, Length(DateStr), 1);
Dec(SepCount);
end;
DecodeDate(Now, Year, Month, Day);
if SepCount = 0 then begin
case Length(DateStr) of
0 : DateStr := DateToStr(Now);
1, 2 :
DateStr := DateStr+DateSeparator+IntToStr(Month);
4 : Insert(DateSeparator, DateStr, 3);
6, 8 : begin
Insert(DateSeparator, DateStr, 5);
Insert(DateSeparator, DateStr, 3);
end;
end; {case}
end; {if SepCount}
try
StrLikeDate := DateToStr(StrToDate(DateStr));
except
if NowIfError = true then
StrLikeDate := DateToStr(Date)
else
StrLikeDate := '';
end;{try/except}
end;
-----------------------

DateComplete procedure

As we can see from the procedure header:
-----------------------
procedure DateComplete
(var StrLikeDate:string;
const NowIfError:boolean = True);
-----------------------

The DateComplete takes the StrLikeDate string parameter by reference using the var keyword, meaning that DateComplete function is able to alter the value in StrLikeDate. The second parameter (optional, defaults to True) NowIfError is used in the exception handler part to check for bad date (for example: letters in StrLikeDate). If NowIfError is True (default if omitted) and there is an error while trying to convert the StrLikeDate value to date representation, the value of StrLikeDate will become the current date (Now), otherwise (NowIfError = False) the StrLikeDate will be returned as an empty string ('').

With the previous discussion in our mind, the DateComplete function can be called as:
------------------------
procedure TForm1.edDateExit(Sender: TObject);
var s : string;
begin
s := edDate.Text;
DateComplete(s, True); {or DateComplete(s)}
edDate.Text := s;
end;
-------------------------

Note: The DateComplete procedure will alter the StrLikeDate value to a date format 'dd.mm.yyyy', where date separator '.' is stored in the global variable DateSeparator (Delphi reads this value from the Regional Settings in the Control Panel).
(See picture below)

mm/dd/yyyy
If you (your users) are not using the 'dd.mm.yyyy' but 'mm/dd/yyyy' date format then DateComplete needs some modification to work properly. Take a look at the next line:

case Length(DateStr) of
...
1, 2 :
DateStr:=DateStr + DateSeparator + IntToStr(Month);
...
-----------------------

This piece of code handles the situation when only one or two digits are entered - only day (remember: 'dd.mm.yyyy'). DateStr becomes DateStr + Month (current).
If you are working with 'mm/dd/yyyy' short date format, simply change the previous code to:

case Length(DateStr) of
...
1, 2 :
DateStr:=DateStr + DateSeparator + IntToStr(Day);

_I_Play_Chess
10-25-2003, 11:41 AM
TEXT FILES IN DELPHI
---------------------------
Handling ASCII files from Object Pascal code.
The world isn't only about Paradox, Access, Interbase, MySQL, MS' SQL Server ...
Simply put, text files contain readable ASCII characters. We can think of working with text file in Delphi as analogous to playing or recording information on a cassette tape.
Although it is possible to make changes within text file, jump around when processing information or add some data to the file other than at the end, it is advisable to use a text file only when we know that we are working with ordinary text and no such operations are necessary.
Text files are considered to represent a sequence of characters formatted into lines, where each line is terminated by an end-of-line marker (a carriage-return / linefeed combination). Just think of Win.ini or Autoexec.bat.

Assign

In order to start working with text files from Delphi we have to link a file on a disk to a file variable in our program. To create this link we must first declare a variable of type TextFile and then use AssignFile procedure in order to associate a file on a disk with a file variable.
------------------------
...
var
SomeTxtFile : TextFile;
begin
AssignFile(SomeTxtFile, FileName)
...
-------------------------

Note: Unless the file named FileName is in the current directory, we need to provide enough information to identify its path. Be sure that value of a text variable has a legal Windows filename.

Reading information from a Text File

If we want to read back the contest of a file into a string list, our task is easy. Just one line of code will do the job.
-------------------------
...
Memo1.Lines.LoadFromFile('c:\autoexec.bat')
...
-------------------------

On the other hand, to read information from a file line by line, we must open the file for input by using the Reset procedure. The Reset opens the existing file with the name assigned to TextFile variable. An error results if no existing external file of the given name exists.

Once a file is reset, we can use ReadLn to read information from a file:
------------------------
...
var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buffer);
Memo1.Lines.Add(buffer);
CloseFile(SomeTxtFile);
end;
...
-------------------------

Procedure called ReadLn, reads one line of text from a file then moves to the next line.

After adding one line of text from a file to a memo component SomeTxtFile needs to be closed. This is done by the Close keyword.

Note: We can also use Read procedure to read information from a file. Read works just like ReadLn, except it does not move the pointer to the next line. As the next example shows, we can use multiple variables in each Read statement:
-----------------------
var
SomeTxtFile : TextFile;
buf1,buf2 : string[5];
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buf1,buf2);
ShowMessage(buf1 + ' ' +buf2);
CloseFile(SomeTxtFile);
end;
------------------------

The EOF

Eof is the EndOfFile checking function. We can use this function to make sure that we are not trying to read beyond the end of the file. Let's say we want to display the contest of the file in message boxes - one line at a time, until we get to the end of a file:
------------------------
var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\autoexec.bat');
Reset(SomeTxtFile);
while not EOF(SomeTxtFile) do begin
ReadLn(SomeTxtFile, buffer);
ShowMessage(buffer);
end;
CloseFile(SomeTxtFile);
end;
-------------------------

Note: It is better to use While loop than an Until loop to take into account the (unlikely) possibility that the file exists but does not contain any data.

Sending information to a Text File
Writing text to a file is as easy as reading text from a file. The WriteLn command is probably the most common way to send individual pieces of information to a file. The following code will read a text from a Memo1 component (line by line) and send it to some newly created text file.
-------------------------
var
SomeTxtFile : TextFile;
i: integer;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
Rewrite(SomeTxtFile);
for i := 0 to (Memo1.Lines.Count - 1) do
WriteLn(SomeTxtFile, Memo1.Lines[i]);
CloseFile(SomeTxtFile);
end;
-------------------------

Depending on the state of the file provided to the Rewrite procedure in the previous example, the Rewrite creates a new file (opens the file for output) with the name assigned to SomeTextFile. If a file with the same name already exists, it is deleted and a new empty file is created in its place. If SomeTextFile is already open, it is first closed and then re-created. The current file position is set to the beginning of the empty file.

Note: Memo1.Lines.SaveToFile('c:\MyTextFile.txt') will do the same.

Sometimes we'll just need to add some text data to the end of an existing file. If this is the case, we'll call Append to ensure that a file is opened with write-only access with the file pointer positioned at the end of the file. Something like:
------------------------
var
SomeTxtFile : TextFile;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
Append(SomeTxtFile);
WriteLn(SomeTxtFile, 'New line in my text file');
CloseFile(SomeTxtFile);
end;
------------------------

Be aware
In general, you should always use exception handling when working with files. I/O is full of surprises. Always use CloseFile in a finally block to avoid the possibility of corrupting a user's FAT. All the previous examples should be rewritten as follows:
------------------------
var
SomeTxtFile : TextFile;
buffer : string;
begin
AssignFile(SomeTxtFile, 'c:\MyTextFile.txt');
try
Reset(SomeTxtFile);
ReadLn(SomeTxtFile, buffer);
finally
CloseFile(SomeTxtFile);
end;
end;
------------------------

To be sure that a given file exists we have to use FileExists boolean function. This function will return True if the file exists, Else otherwise. The syntax is

function FileExists(const FileName: string): boolean


Final words
Delphi has the ability to handle both ASCII files and files that hold binary data.

_I_Play_Chess
10-25-2003, 11:44 AM
ERRORS AND EXCEPTIONS
---------------------------------

"The most bug-free line of code is the one you don't have to write."

Unfortunately, building applications includes coding. Regardless of how carefully you write/debug your program, it will be impossible to imagine every situation that can go wrong. Inexperienced user might, for example, try to open a nonexisting file or input a bad value into a data field.
Users make mistakes and we should be prepared to handle/prevent these errors wherever and whenever possible.

Errors, Exceptions?

An exception is generally an error condition or other event that interrupts normal flow of execution in an application. Whenever an error results from processing a line of code, Delphi creates (raises) an object descendent from TObject called the exception object.

Guarded Blocks

An application responds to an exception either by executing some termination code, handling the exception, or both. The way to enable error/exception trapping within a given code, the exception must occur within a guarded block of statements. The general code looks like:
-----------------------
try
{guarded block of code}
except
on <ESomeException> do begin
{exception block-handles SomeException}
end;
end;
-----------------------

A try...except statement executes the statements in the guarded block of code. If the statements execute without any exceptions being raised, the exception block is ignored, and control is passed to the statement following the end keyword.

Example:
...
Zero:=0;
try
dummy:= 10 / Zero;
except
on EZeroDivide do
MessageDlg('Can not divide by zero!',
mtError, [mbOK], 0);
end;
...
-----------------------

Protecting Resources

When a section of code acquires a resource, it is often necessary to ensure that the resource is released again, regardless of whether the code completes normally or is interrupted by an exception. In this case, the syntax uses finally keyword and looks like:
-------------------------
{some code to allocate resources}
try
{guarded block of code}
finally
{termination blok - code to free resources}
end;
-------------------------

Example:
...
AboutBox:=TAboutBox.Create(Self);
try
AboutBox.ShowModal;
finally
AboutBox.Release;
end;
...
-------------------------

Application.OnException

If your application doesn't handle the error that caused the exception, then Delphi will use its default exception handler - it will just pop up a message box. You may consider writing code in the OnException event for TApplication object, in order to trap errors at the application level.

Break On Exceptions

When building a program with exception handling, you may not want Delphi to break on Exceptions. This is a great feature if you want Delphi to show where an exception has occurred; however, it can be annoying when you test your own exception handling.

leblitzer
10-27-2003, 12:27 PM
damn chapter 7 yet???

_I_Play_Chess
10-29-2003, 08:50 AM
Guys where are at?

Let me know....

Do you finish all these chapters? from 1 to 7?

_I_Play_Chess
10-29-2003, 08:51 AM
I would ask where are you AT?