2004. március 31., szerda

Are we On-Line


Problem/Question/Abstract:

Are we On-Line?

Answer:

The following code is a possibility to detect a connection to the internet,
altough it is not 100%.

I have tested it on Windows NT with LAN connections (DSL and cable)
and it worked in these cases.

uses
  WinInet;
..
..

function InternetConnected: Boolean;
const
  INTERNET_CONNECTION_MODEM = 1; // local system uses a modem to connect to the Internet.
  INTERNET_CONNECTION_LAN = 2; // local system uses a local area network to connect to the Internet.
  INTERNET_CONNECTION_PROXY = 4; // local system uses a proxy server to connect to the Internet.
  INTERNET_CONNECTION_MODEM_BUSY = 8; // local system's modem is busy with a non-Internet connection.
var
  dwConnectionTypes: DWORD;
begin
  dwConnectionTypes :=
    INTERNET_CONNECTION_MODEM +
    INTERNET_CONNECTION_LAN +
    INTERNET_CONNECTION_PROXY;
  Result := InternetGetConnectedState(@dwConnectionTypes, 0);
end;

Note: this solution only works if IE is installed, so it would fail on
'older' machines, like most Windows NT 4 computers. You app would then
display an error during program startup if you referred to Wininet.  

2004. március 30., kedd

Controlling Margins when printing RichEdit contents


Problem/Question/Abstract:

How can I control margins when printing text that I have loaded into a TRichEdit?

Answer:

Printing from a RichEdit is really rather easy - all you need to do is to call the Print method:

RichEdit1.Print(const Caption: string);

The Caption parameter shown here specifies the title that appears in the Print queue.  Therefore you would, for example, call something like:

RichEdit1.Print(MyAppName + ': ' + DocumentTitle);

From this call the system will carefully format and print the contents of the RichEdit automatically over the required number of pages.  That is all well and good, but it does have an unwanted side effect - there is no control over the margins whatsoever. It will simply use the default margins as reported by the Printer when it returns its printable page size.

In order to be able to define the margins you need to know a number of things... The available space on the page, the unprintable area of the page, whether to calculate the margins as Inches or Centimetres, and so on. Much of this can be retrieved from the Printer object, and the rest we will need to provide in our code.

The first thing to decide is how to determine the measurements. You could pass this as a String (e.g. 'inches' or 'centimetres'), you could pass it as a number (e.g. 1 for inches, 2 for centimetres) but perhaps the easiest way is to declare your own data type that will make the code easier to read. For this example I have defined TRichTextMeasurements in the Interface section of the unit:

type
  TRichTextMeasurements = (rtmNone, rtmInches, rtmCentimetres);

Now we can determine whether to use the default margins (rtmNone) or to create our own margins in the selected measurement.

Now all we need is the code to implement the margins if needed. This example function accepts parameters to describe the margins required, the type of measurements to be used for creating margins and the number of copies to be printed.

function PrintRichText(RTLeftMargin, RTRightMargin, RTTopMargin, RTBottomMargin:
  Extended;
  RichTextMeasurement: TRichTextMeasurements; Copies: Integer): Boolean;
var
  ��PixelsX, PixelsY, LeftSpace, TopSpace: Integer;
  ��LeftMargin, RightMargin, TopMargin, BottomMargin: Extended;
begin
  Result := False; // default return value
  ��if RichTextMeasurement <> rtmNone then
    ����begin
    ������ // get pixels per inch
  ������PixelsX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
  ������PixelsY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);

  ������ // get non-printable margins
  ������LeftSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
  ������TopSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);

  ������LeftMargin := RTLeftMargin;
  ������RightMargin := RTRightMargin;
  ������TopMargin := RTTopMargin;
  ������BottomMargin := RTBottomMargin;

  ������ // If the measurement is set in Centimetres, recalculate
  ������if RichTextMeasurement = rtmCentimetres then
    ��������begin
    ����������LeftMargin := LeftMargin / 2.54;
  ����������RightMargin := RightMargin / 2.54;
  ����������TopMargin := TopMargin / 2.54;
  ����������BottomMargin := BottomMargin / 2.54;
  ��������end;

  �������� // Set the Margins
  ��������R.Left := Round(PixelsX * LeftMargin) - LeftSpace;
  ��������R.Right := Printer.PageWidth - Round(PixelsX * RightMargin) - LeftSpace;
  ��������R.Top := Round(PixelsY * TopMargin) - TopSpace;
  ��������R.Bottom := Printer.PageHeight - Round(PixelsY * BottomMargin) - TopSpace;
  ��������RichEdit1.PageRect := R;
  ��������Application.ProcessMessages;
  ����end;

  // Print the required number of copies
  ��while Copies > 0 do
    ����begin
    ������RichEdit1.Print('MyApp: Copy ' + IntToStr(Copies));
  ������Dec(Copies);
  ������Application.ProcessMessages;
  ����end;
  Result := True;
end;

To call the example code to print one copy with a 1 inch margin all round, you could do something like this:

procedure TForm1.PrintButtonClick(Sender: TObject);
begin
  ��if PrintRichText(1, 1, 1, 1, rtmInches, 1) then
    ����ShowMessage('Printing was successful')
    ��else
    ����ShowMessage('Printing failed');
end;

Note that if you want to use the default margins you still have to pass a number for each margin in the function call. What that number is does not matter as they are all ignored, but perhaps for clarity using a zero would be best:

procedure TForm1.PrintButtonClick(Sender: TObject);
begin
  if PrintRichText(0, 0, 0, 0, rtmNone, 1) then
    ShowMessage('Printing was successful')
  else
    ShowMessage('Printing failed');
end;

This example can easily be extended to provide visual print progress feedback, or to add margin measurements in millimetres.  However, it will not replace a full implementation as provided by commercial Word Processing products. On the other hand, for many purposes it will more than suffice.

2004. március 29., hétfő

Search for duplicate files on large drives


Problem/Question/Abstract:

I have a list of items that I will need to deal with (looking for duplicate files on a drive) that can be upto 2 to 5 million in size. So I will be populating this list and then searching it over and over and over. Normally when dealing with smaller lists like this I would simply use a TStringList and attach an object. However, this seems a little large for TStringList and the main reason, the searching with IndexOf, I don't think is reason enough to use it. So what I am looking for is a list of some sort (TObjectList ?) that is fast and good to deal with and can easily handle this size of entries. It would be really nice it there was a way to create multiple indexes into the in-memory list, as that would greatly speed up my processing of the information. The best solution would be an in-memory database of some sort (at least I think it would be), but my issue with in-memory databases is that of the String sizes for File Name and directory. If I use a regular String variable in an object, then the size can be variable. If I use a standard DB field, then the size in the ones I have seen are all static. So I have to define a huge field to handle all file names which wastes space on all other entries in the list. Any thoughts as the best container to handle this sort of thing?

Answer:

{$A+,B-,D-,E+,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-,Y-}

program FindDup;

{$APPTYPE CONSOLE} // 2002-12-16 - Delphi 32 console app

{Usage: FINDDUP [D:]

This program finds all duplicate files on the specified drive. The algorithm uses a hash table where each hash value contains a linked list of files that match a given hash. Every file found is inserted into the hash table linked list unless it's already there and therefore a duplicate. All duplicates are added to a red-black tree, where each node contains the file ame and a pointer to a linked list of records containing size, date, and path information.

This program can be compiled in either real or protected modes. Protected mode will allow it to search larger drives. Informal benchmarks on a 1.6 Gig drive with > 900 directories, Pentium 90, compiled for p-mode:

TEST 16 sec. (simple do-nothing recursive dir searcher)
FINDDUP 18 sec. - 16 = 2 sec.
REP-DPMI 36 sec. - 16 = 20 sec.

Subtracting the overhead of FindFirst/ FindNext, this program runs in about 2 seconds as compared to REP-DPMI's 20 seconds. Without ignoring the overhead, it's still twice as fast. Please note that this program is pure pascal.}

{$DEFINE DRBOB} // Do not search hidden directories or find hidden files
{.$DEFINE SAFE}// Checks memory allocations for out of memory conditions
{.$DEFINE CLEANUP}// Frees allocated memory - slows things down a bit

uses
  SysUtils;

const
  DosDelimSet: set of Char = ['\', ':', #0];
  MaxHash = 16381; {largest prime number < 16K}

type
  PathStr = string;
  NameString = string[12];
  St2 = string[2];

  pPath = ^PathRecord; {we will only keep one copy of each unique directory path}
  PathRecord = record
    Next: pPath;
    Path: PathStr;
  end;

  pDataRec = ^DataRec; {detailed information unique to each dupliacte}
  DataRec = record
    Time: longint;
    Size: longint;
    Path: pPath;
    Next: pDataRec;
  end;

  link = ^RBTreeNode;
  RBTreeNode = record {Red/ black tree node}
    Key: NameString; {Name of file}
    red: boolean;
    l, r: link;
    DataP: pDataRec; {linked list of detail information}
  end;

  pFileRec = ^MyFileRec;
  MyFileRec = record
    {Hash table record. There will only be one record for each duplicate file name}
    Name: NameString;
    Time: longint;
    Size: longint;
    Path: pPath;
    Node: link; {let's quickly insert duplicate into tree}
    next: pFileRec; {next record in linked list}
  end;

  tHashTable = array[0..MAXHASH] of pFileRec;

var
  Head, z: link;
  HashTable: ^tHashTable;
  PathHead, TempPathHead: pPath;
  OldName: NameString;

procedure RBTreeInitialize;
{Initialize red/ black tree}
begin
  New(Z);
{$IFDEF SAFE}
  if Z = nil then
    exit;
{$ENDIF}
  z^.l := z;
  z^.r := z;
  z^.red := false;
  New(Head);
{$IFDEF SAFE}
  if Head = nil then
    exit;
{$ENDIF}
  Head^.r := z;
  Head^.l := z;
  Head^.Key := '';
  Head^.Red := false;
end;

function Rotate(const Value: MyFileRec; y: link): link;
var
  c, gc: link;
begin
  if Value.Name < Y^.Key then
    c := y^.l
  else
    c := y^.r;
  if Value.Name < c^.Key then
  begin
    gc := c^.l;
    c^.l := gc^.r;
    gc^.r := c;
  end
  else
  begin
    gc := c^.r;
    c^.r := gc^.l;
    gc^.l := c;
  end;
  if Value.Name < Y^.Key then
    y^.l := gc
  else
    y^.r := gc;
  Rotate := gc;
end;

function Split(const Value: MyFileRec; gg, g, p, x: link): link;
begin
  x^.red := true;
  x^.l^.red := false;
  x^.r^.red := false;
  if p^.red then
  begin
    g^.red := true;
    if (Value.Name < g^.Key) <> (Value.Name < p^.Key) then
      p := Rotate(Value, g);
    x := rotate(Value, gg);
    x^.red := false;
  end;
  Head^.r^.red := false;
  split := x;
end;

function RBTreeInsert(const Value: MyFileRec; x: link): link;
{Insert file record into red/ black tree}
var
  gg, g, p: link;
begin
  p := x;
  g := x;
  repeat
    gg := g;
    g := p;
    p := x;
    if Value.Name < x^.Key then
      x := x^.l
    else
      x := x^.r;
    if x^.l^.red and x^.r^.red then
      x := split(Value, gg, g, p, x);
  until
    x = z;
  new(x);
{$IFDEF SAFE}
  if x = nil then
    exit;
{$ENDIF}
  x^.Key := Value.Name;
  New(x^.DataP);
{$IFDEF SAFE}
  if x^.DataP = nil then
    exit;
{$ENDIF}
  x^.DataP^.Next := nil;
  x^.DataP^.Time := Value.Time;
  x^.DataP^.Size := Value.Size;
  x^.DataP^.Path := Value.Path;
  x^.l := z;
  x^.r := z;
  if Value.Name < p^.Key then
    p^.l := x
  else
    p^.r := x;
  RbTreeInsert := x;
  x := Split(Value, gg, g, p, x);
end;

procedure Traverse(p: link);
{Traverse red/ black tree, printing out results}
var
  TempQ, q: pDataRec;
begin
  if (p^.l <> z) and (p^.l <> nil) then
    Traverse(p^.l);
  if (p <> head) then
  begin
    if p^.Key <> OldName then
    begin
      OldName := p^.Key;
      writeln(OldName);
    end;
    q := p^.DataP;
    while q <> nil do
    begin
      with q^ do
        writeln(size: 10, '   ', FormatDateTime('yyyy-mm-dd hh:nn:ss',
          FileDateToDateTime(Time)), '   ', Path^.Path);
{$IFDEF CLEANUP}
      TempQ := q;
      q := q^.Next;
      Dispose(TempQ);
{$ELSE}
      q := q^.Next;
{$ENDIF}
    end;
    writeln;
  end;
  if (p^.r <> z) and (p^.r <> nil) then
    Traverse(p^.r);
{$IFDEF CLEANUP}
  Dispose(p);
{$ENDIF}
end;

function AddBackSlash(const DirName: string): string;
{Add a default backslash to a directory name}
begin
  if DirName[Length(DirName)] in DosDelimSet then
    AddBackSlash := DirName
  else
    AddBackSlash := DirName + '\';
end;

function Hash(const Key: NameString): word;
var
  h: word;
  j: integer;
  Len: integer;
begin
  Len := Length(Key);
  h := ord(Key[1]);
  for j := 2 to Len do
  begin
    h := ((h * 32) + Ord(Key[j])) mod MAXHASH;
  end;
  Hash := h;
end;

procedure Add(var SR: tSearchRec; DirP: pPath);
{Add a new search record/ path to the hash table}
var
  p, q, r: pFileRec;
  h: word;
  TempData: pDataRec;
begin
  h := Hash(SR.Name);
  New(r);
{$IFDEF SAFE}
  if r = nil then
    exit;
{$ENDIF}
  r^.Name := SR.Name;
  r^.Time := SR.Time;
  r^.Size := SR.Size;
  r^.Path := DirP;
  r^.Next := nil;
  r^.Node := nil;
  p := HashTable^[H];
  if p = nil then
  begin {Hash slot not used}
    HashTable^[h] := r;
  end
  else
  begin
    q := p;
    while (p <> nil) and (p^.Name < SR.Name) do
    begin
      q := p;
      p := p^.Next;
    end;
    if (p <> nil) and (p^.Name = SR.Name) then
    begin {Found duplicate file}
      if p^.Node = nil then
      begin {was not already in tree}
        p^.Node := RBTreeInsert(p^, Head);
          {save link so we don't have to search tree next time}
      end;
      New(TempData);
{$IFDEF SAFE}
      if TempData = nil then
        exit;
{$ENDIF}
      TempData^.Time := Sr.Time;
      TempData^.Size := Sr.Size;
      TempData^.Path := DirP;
      TempData^.Next := p^.Node^.DataP; {Add to linked list on tree node}
      p^.Node^.DataP := TempData;
      Dispose(r); {didn't need it after all}
    end
    else
    begin {Not a duplicate}
      if p = q then
      begin {Add at start of linked list}
        HashTable^[H] := r;
        r^.Next := P;
      end
      else
      begin {Insert into linked list}
        q^.Next := r;
        r^.Next := p;
      end;
    end;
  end;
end;

procedure Find(const Path: PathStr);
{Recursive file/directory searcher}
var
  Sr: tSearchRec;
  DirP: pPath;
  r: integer;
begin
  New(DirP);
{$IFDEF SAFE}
  if DirP = nil then
    exit;
{$ENDIF}
  DirP^.Path := Path;
  DirP^.Next := PathHead;
  PathHead := DirP;
  r := FindFirst(AddBackSlash(Path) + '*.*', faAnyFile, Sr);
  while r = 0 do
  begin
{$IFDEF DRBOB} {only do non-hidden directories}
    if ((Sr.Attr and faDirectory) <> 0) and ((Sr.Attr and faHidden) = 0) then
    begin
{$ELSE} {do them all}
    if (Sr.Attr and Directory) <> 0 then
    begin
{$ENDIF}
      if Sr.Name[1] <> '.' then
        Find(AddBackSlash(Path) + Sr.Name);
      r := 0;
    end
    else
    begin
{$IFDEF DRBOB}
      if (Sr.Attr and faHidden) = 0 then {Only do non-hidden files}
{$ENDIF}
        Add(Sr, DirP);
    end;
    r := FindNext(Sr);
  end;
end;

function HeapFunc(Size: Word): Integer; far;
begin
  HeapFunc := 1;
end;

procedure Init;
begin
  OldName := '';
  PathHead := nil;
{$IFDEF SAFE}
  HeapError := @HeapFunc;
{$ENDIF}
  New(HashTable);
{$IFDEF SAFE}
  if HashTable = nil then
    halt;
{$ENDIF}
  FillChar(HashTable^, sizeof(HashTable^), 0);
  RBTreeInitialize;
end;

procedure Process;
begin
  Find(ParamStr(1) + '\');
  Traverse(Head);
end;

procedure Done;
var
  i: integer;
  q, tempq: pFileRec;
begin
{$IFDEF CLEANUP}
  Dispose(Z);
  for i := 0 to MAXHASH - 1 do
  begin
    if HashTable^[i] <> nil then
    begin
      q := HashTable^[i];
      while q <> nil do
      begin
        tempq := q^.next;
        Dispose(q);
        q := tempq;
      end;
    end;
  end;
  Dispose(HashTable);
  TempPathHead := PathHead;
  while PathHead <> nil do
  begin
    TempPathHead := PathHead^.Next;
    FreeMem(PathHead, Length(PathHead^.Path) + 5);
    PathHead := TempPathHead;
  end;
{$ENDIF}
end;

begin
  Init;
  Process;
  Done;
end.

2004. március 28., vasárnap

How to shift focus between buttons programmatically


Problem/Question/Abstract:

I have 4 buttons on a form, let's say button1 and button2 on the left side on the form and button3 and button4 on the right side on the form. When Button1 has the focus and I press the RightArrow I want to have Button3 to get the focus instead of Button2. When Button3 has the focus and I press the LeftArrow I want to have Button1 to get the focus. I've tried the onkeydown event on the button but it ignores to trap the arrowkeys.

Answer:

Buttons do not process navigation keys, so they go to the form in the guise of CM_DIALOGKEY messages and the form processes them to move to the next/ previous control in tab order. You may be able to achieve what you want by simply changing the tab order of your buttons (assuming they are all sitting on the same parent control).

To handle this all yourself you would add a handler for the CM_DIALOGKEY message to the form.

{form private section}

procedure CMDialogKey(var msg: TCMDialogKey); message CM_DIALOGKEY;

  procedure TForm1.CMDialogKey(var msg: TCMDialogKey);
  begin
    case Msg.Charcode of
      VK_RIGHT:
        begin
          if ActiveControl = Button1 then
          begin
            Button3.Setfocus;
            msg.result := 1; {mark key handled}
            Exit;
          end;
          if ActiveControl = Button2 then
          begin
            Button4.Setfocus;
            msg.result := 1; {mark key handled}
            Exit;
          end;
        end;
      VK_LEFT:
        begin
          if ActiveControl = Button3 then
          begin
            Button1.Setfocus;
            msg.result := 1;
            Exit;
          end;
          if ActiveControl = Button4 then
          begin
            Button2.Setfocus;
            msg.result := 1;
            Exit;
          end;
        end;
    end;
    inherited;
  end;
end;

2004. március 27., szombat

How to assign an application to have a smaller percentage of the CPU cycles


Problem/Question/Abstract:

How to assign an application to have a smaller percentage of the CPU cycles

Answer:

The rest of this may take a little time, and is quite CPU intensive, so try and drop to a lower priority if possible. Drop to low priority for CPU-intensive parts.


saved_priority_class := GetPriorityClass(GetCurrentProcessID);
if saved_priority_class <> 0 then
  SetPriorityClass(GetCurrentProcess, IDLE_PRIORITY_CLASS);

{ CPU intensive stuff here ... }

{Restore normal priority}
if saved_priority_class <> 0 then
  SetPriorityClass(GetCurrentProcess, saved_priority_class);

2004. március 26., péntek

Definitions of PRIVATE, PROTECTED, PUBLIC, and PUBLISHED sections of a unit


Problem/Question/Abstract:

What do the PRIVATE, PROTECTED, PUBLIC and PUBLISHED sections of a unit mean?

Answer:

They define the level of visibility of properties and methods of an object. In a nutshell, they are as follows:

PRIVATE - Things contained in this section are private to the object. External objects do not have access to any elements contained here.

PROTECTED - Similar to private with one exception: Descendants of the object have access to the methods and properties contained here.

PUBLIC - All external objects have access to elements here.

PUBLISHED - Similar to PUBLIC, but properties listed here show up at design time under the Object Inspector.

These sections really come into play when you're building components. Typically, you'll put the local field variables assigned to properties in the PRIVATE section, along with functions and procedures that act only within the scope of the object itself. In the PROTECTED methods, if you know the object will be inherited at some point, you'll put properties, functions and procedures to give access to your descendants, but maintain privacy from external objects. In the PUBLIC section, you'll place methods and procedures that usually don't have a corresponding property, but require full access by other entities; or, insert properties that you don't want visible in the Object Inspector. The PUBLISHED section by convention is for properties only, though I've put procedures there just to see if I still had access to them.

TForms have PRIVATE and PUBLIC sections as well. In most cases you won't put them to use; however, there will be times when you want to add functionality and capabilities to the form that need to be assigned levels of visibility.

Play around with this stuff. The more you understand it, the more you'll understand object-oriented programming. By the way, I suggest getting a book on general object-oriented programming principles. Understanding the theory behind objects will help you get a better handle on Delphi programming.

2004. március 25., csütörtök

How to convert a hex color to its HTML counterpart


Problem/Question/Abstract:

How to convert a hex color to its HTML counterpart

Answer:

Solve 1:

This may run faster using shl/ shr and the bitwise AND operator to separate R, G and B parts before converting to a string:

function ColorToHTML(C: TColor): string;
begin
  Result := IntToHex(C, 6);
  Result := '#' + Copy(Result, 5, 2) + Copy(Result, 3, 2) + Copy(Result, 1, 2);
end;

function HTMLToColor(C: string): TColor;
begin
  if Copy(C, 1, 1) = '#' then
    C := Copy(C, 2, Length(C));
  Result := StrToInt('$' + Copy(C, 5, 2) + Copy(C, 3, 2) + Copy(C, 1, 2));
end;


Solve 2:

The HTML color code is the other way round as TColor :

TColor = $DDBB ggrr
HTML = $00 RRGGBB

So you just have to swap bytes:


{ ... }
var
  HTMLColor, mycolor: Integer;
  { ... }

  HTMLColor := (((MyColor and $FF) shl 16) or ((MyColor and $FF00)) or
    ((MyColor and $FF0000) shr 16));
  YourHTMLColor := IntToHex(HTMLColor, 8);

2004. március 24., szerda

How to get the process ID's of all running programs


Problem/Question/Abstract:

I am trying to build a component to get info about the programs executing in my NT4 environment. I managed to get the names for all the windows running (title text). Now, how can I get the process ID for each of them? Which function should I use? Is there any function that tells me for how long my process is running?

Answer:

It is better to use the EnumWindows function instead of FindWindow/GetWindow, because the latter isn't sensitive to windows being destroyed halfway through the loop and you can end up getting invalid handles. Here's an example:

function EnumWindowsProc(hWnd: LongWord; Form: TForm1): WordBool; stdcall;
begin
  Form.FoundAWindow(hWnd);
  Result := True
end;

procedure TForm1.FoundAWindow(hWnd: LongWord);
var
  ProcessID: LongWord;
  Title: array[0..255] of Char;
begin
  GetWindowThreadProcessID(hWnd, @ProcessID);
  GetWindowText(hWnd, Title, 256);
  {Now, do whatever you want with Title and ProcessID, e.g.:}
  Memo1.Lines.Add(Title + ' [' + IntToStr(ProcessID) + ']')
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  EnumWindows(@EnumWindowsProc, Integer(Self))
end;

2004. március 23., kedd

Retrieve version information from an executable or DLL


Problem/Question/Abstract:

Is there a quick way to include the build number created by Project/ Options/ Version Info in my About Box?

Answer:

Solve 1:

Here's a function which will read the version info:

{Get Major, Minor, Release, Build for an EXE or DLL file.
returns true = success.
returns false = failure, probably info not found in the file.}

function GetFileVersion(const FileName: string; var Major, Minor, Release, Build:
  Integer;
  var PreRelease, Debug: Boolean; var Description: string): Boolean;
var
  Zero: DWORD; {set to 0 by GetFileVersionInfoSize}
  VersionInfoSize: DWORD;
  PVersionData: pointer;
  PFixedFileInfo: PVSFixedFileInfo;
  FixedFileInfoLength: UINT;
  FileFlags: WORD;
begin
  {ask Windows how big a data buffer to allocate to hold this EXE or DLL version info}
  VersionInfoSize := GetFileVersionInfoSize(pChar(FileName), Zero);
  {if no version info in the EXE or DLL}
  if VersionInfoSize = 0 then
  begin
    result := False;
    exit;
  end;
  {allocate memory needed to hold version info}
  PVersionData := AllocMem(VersionInfoSize);
  try
    {load version resource out of EXE or DLL into our buffer}
    if GetFileVersionInfo(pChar(FileName), 0, VersionInfoSize, PVersionData) = false
      then
    begin
      raise Exception.Create('Can''''t get version info');
    end;
    {get the fixed file info portion of the resource in buffer}
    if VerQueryValue(PVersionData, '\', pointer(PFixedFileInfo), FixedFileInfoLength)
      = false then
    begin
      {no fixed file info in this version resource !}
      result := False;
      exit;
    end;
    {extract the info from the the fixed file data structure}
    Major := PFixedFileInfo^.dwFileVersionMS shr 16;
    Minor := PFixedFileInfo^.dwFileVersionMS and $FFFF;
    Release := PFixedFileInfo^.dwFileVersionLS shr 16;
    Build := PFixedFileInfo^.dwFileVersionLS and $FFFF;
    FileFlags := PFixedFileInfo^.dwFileFlags;
    PreRelease := (VS_FF_PRERELEASE and FileFlags) < > 0;
    Debug := (VS_FF_DEBUG and FileFlags) < > 0;
    Description := Format('Ver %d.%d, Release %d Build %d', [Major, Minor, Release,
      Build]);
    if PreRelease then
    begin
      Description := Description + ' Beta';
    end;
    if Debug then
    begin
      Description := Description + ' Debug';
    end;
  finally
    FreeMem(PVersionData);
  end;
  result := True;
end;


Solve 2:

{ ... }

TVer = record
  case integer of
    0: (both: integer);
    1: (LowPart, HighPart: Word);
end;

TVersion = record
  Major: Word;
  Minor: Word;
  Release: Word;
  Build: Word;
end;

function GetVersionInfo(FileName: string): TVersion;
var
  Len: DWord;
  Size: DWord;
  buf: pChar;
  Info: pVSFixedFileInfo;
begin
  fillChar(result, sizeOf(TVersion), #0);
  Size := GetFileVersionInfoSize(pChar(FileName), Len);
  if Size = 0 then
    exit;
  GetMem(buf, Size);
  try
    GetFileVersionInfo(pChar(FileName), 0, Size, buf);
    if VerQueryValue(buf, '\', pointer(Info), Len) then
      with Result do
      begin
        Major := TVer(Info.dwFileVersionMS).HighPart;
        Minor := TVer(Info.dwFileVersionMS).LowPart;
        Release := TVer(Info.dwFileVersionLS).HighPart;
        Build := TVer(Info.dwFileVersionLS).LowPart;
      end;
  finally
    FreeMem(buf);
  end;
end;


Solve 3:

Get the version info stored inside a DLL.

function dgGetBuildInfo: string;
var
  V1, V2, V3, V4: Word;
  VerInfoSize: DWORD;
  VerInfo: Pointer;
  VerValueSize: DWORD;
  VerValue: PVSFixedFileInfo;
  Dummy: DWORD;
begin
  VerInfoSize := GetFileVersionInfoSize(PChar(ParamStr(0)), Dummy);
  GetMem(VerInfo, VerInfoSize);
  try
    GetFileVersionInfo(PChar(ParamStr(0)), 0, VerInfoSize, VerInfo);
    VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
    with VerValue^ do
    begin
      V1 := dwFileVersionMS shr 16;
      V2 := dwFileVersionMS and $FFFF;
      V3 := dwFileVersionLS shr 16;
      V4 := dwFileVersionLS and $FFFF;
    end;
    Result := IntToStr(V1) + '.' + IntToStr(V2) + '.' + IntToStr(V3) + '.' +
      IntToStr(V4);
  finally
    FreeMem(VerInfo, VerInfoSize);
  end;
end;

2004. március 22., hétfő

How to generate coherent noise


Problem/Question/Abstract:

How to generate coherent noise

Answer:

{Coherent noise function over 1, 2 or 3 dimensions by Ken Perlin}

unit perlin;

interface

function noise1(arg: double): double;
function noise2(vec0, vec1: double): double;
function noise3(vec0, vec1, vec2: double): double;
function PNoise1(x, alpha, beta: double; n: integer): double;
function PNoise2(x, y, alpha, beta: double; n: integer): double;
function PNoise3(x, y, z, alpha, beta: double; n: integer): double;

{High Alpha: smoother intensity change, lower contrast
Low Alpha: rapid intensity change, higher contrast
High Beta: coarse, big spots
Low Beta: fine, small spots}

implementation

uses
  SysUtils;

const
  defB = $100;
  defBM = $FF;
  defN = $1000;

var
  start: boolean = true;
  p: array[0..defB + defB + 2 - 1] of integer;
  g3: array[0..defB + defB + 2 - 1, 0..2] of double;
  g2: array[0..defB + defB + 2 - 1, 0..1] of double;
  g1: array[0..defB + defB + 2 - 1] of double;

function s_curve(t: double): double;
begin
  result := t * t * (3.0 - 2.0 * t);
end;

function lerp(t, a, b: double): double;
begin
  result := a + t * (b - a);
end;

procedure setup(veci: double; var b0, b1: integer; var r0, r1: double);
var
  t: double;
begin
  t := veci + defN;
  b0 := trunc(t) and defBM;
  b1 := (b0 + 1) and defBM;
  r0 := t - int(t);
  r1 := r0 - 1.0;
end;

procedure normalize2(var v0, v1: double);
var
  s: double;
begin
  s := sqrt(v0 * v0 + v1 * v1);
  v0 := v0 / s;
  v1 := v1 / s;
end;

procedure normalize3(var v0, v1, v2: double);
var
  s: double;
begin
  s := sqrt(v0 * v0 + v1 * v1 + v2 * v2);
  v0 := v0 / s;
  v1 := v1 / s;
  v2 := v2 / s;
end;

procedure init;
var
  i, j, k: integer;
begin
  for i := 0 to defB - 1 do
  begin
    p[i] := i;
    g1[i] := (random(defB + defB) - defB) / defB;
    for j := 0 to 1 do
      g2[i, j] := (random(defB + defB) - defB) / defB;
    normalize2(g2[i, 0], g2[i, 1]);
    for j := 0 to 2 do
      g3[i, j] := (random(defB + defB) - defB) / defB;
    normalize3(g3[i, 0], g3[i, 1], g3[i, 2]);
  end;
  i := defB;
  while i > 0 do
  begin
    k := p[i];
    j := random(defB);
    p[i] := p[j];
    p[j] := k;
    dec(i);
  end;
  for i := 0 to defB + 1 do
  begin
    p[defB + i] := p[i];
    g1[defB + i] := g1[i];
    for j := 0 to 1 do
      g2[defB + i, j] := g2[i, j];
    for j := 0 to 2 do
      g3[defB + i, j] := g3[i, j];
  end;
end;

function noise1(arg: double): double;
var
  bx0, bx1: integer;
  rx0, rx1, sx, u, v: double;
begin
  if start then
  begin
    init;
    start := false;
  end;
  bx0 := trunc(arg + defN) and defBM;
  bx1 := (bx0 + 1) and defBM;
  rx0 := frac(arg + defN);
  rx1 := rx0 - 1.0;
  sx := rx0 * rx0 * (3.0 - 2.0 * rx0);
  u := rx0 * g1[p[bx0]];
  v := rx1 * g1[p[bx1]];
  result := u + sx * (v - u);
end;

function noise2(vec0, vec1: double): double;
var
  i, j, bx0, bx1, by0, by1, b00, b10, b01, b11: integer;
  rx0, rx1, ry0, ry1, sx, sy, a, b, u, v: double;
begin
  if start then
  begin
    init;
    start := false;
  end;
  bx0 := trunc(vec0 + defN) and defBM;
  bx1 := (bx0 + 1) and defBM;
  rx0 := frac(vec0 + defN);
  rx1 := rx0 - 1.0;
  by0 := trunc(vec1 + defN) and defBM;
  by1 := (by0 + 1) and defBM;
  ry0 := frac(vec1 + defN);
  ry1 := ry0 - 1.0;
  i := p[bx0];
  j := p[bx1];
  b00 := p[i + by0];
  b10 := p[j + by0];
  b01 := p[i + by1];
  b11 := p[j + by1];
  sx := rx0 * rx0 * (3.0 - 2.0 * rx0);
  sy := ry0 * ry0 * (3.0 - 2.0 * ry0);
  u := rx0 * g2[b00, 0] + ry0 * g2[b00, 1];
  v := rx1 * g2[b10, 0] + ry0 * g2[b10, 1];
  a := u + sx * (v - u);
  u := rx0 * g2[b01, 0] + ry1 * g2[b01, 1];
  v := rx1 * g2[b11, 0] + ry1 * g2[b11, 1];
  b := u + sx * (v - u);
  result := a + sy * (b - a);
end;

function noise3orig(vec0, vec1, vec2: double): double;
var
  i, j, bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11: integer;
  rx0, rx1, ry0, ry1, rz0, rz1, sx, sy, sz, a, b, c, d, u, v: double;
begin
  if start then
  begin
    start := false;
    init;
  end;
  setup(vec0, bx0, bx1, rx0, rx1);
  setup(vec1, by0, by1, ry0, ry1);
  setup(vec2, bz0, bz1, rz0, rz1);
  i := p[bx0];
  j := p[bx1];
  b00 := p[i + by0];
  b10 := p[j + by0];
  b01 := p[i + by1];
  b11 := p[j + by1];
  sx := s_curve(rx0);
  sy := s_curve(ry0);
  sz := s_curve(rz0);
  u := rx0 * g3[b00 + bz0, 0] + ry0 * g3[b00 + bz0, 1] + rz0 * g3[b00 + bz0, 2];
  v := rx1 * g3[b10 + bz0, 0] + ry0 * g3[b10 + bz0, 1] + rz0 * g3[b10 + bz0, 2];
  a := lerp(sx, u, v);
  u := rx0 * g3[b01 + bz0, 0] + ry1 * g3[b01 + bz0, 1] + rz0 * g3[b01 + bz0, 2];
  v := rx1 * g3[b11 + bz0, 0] + ry1 * g3[b11 + bz0, 1] + rz0 * g3[b11 + bz0, 2];
  b := lerp(sx, u, v);
  c := lerp(sy, a, b);
  u := rx0 * g3[b00 + bz1, 0] + ry0 * g3[b00 + bz1, 1] + rz1 * g3[b00 + bz1, 2];
  v := rx1 * g3[b10 + bz1, 0] + ry0 * g3[b10 + bz1, 1] + rz1 * g3[b10 + bz1, 2];
  a := lerp(sx, u, v);
  u := rx0 * g3[b01 + bz1, 0] + ry1 * g3[b01 + bz1, 1] + rz1 * g3[b01 + bz1, 2];
  v := rx1 * g3[b11 + bz1, 0] + ry1 * g3[b11 + bz1, 1] + rz1 * g3[b11 + bz1, 2];
  b := lerp(sx, u, v);
  d := lerp(sy, a, b);
  result := lerp(sz, c, d);
end;

function noise3(vec0, vec1, vec2: double): double;
var
  i, j, bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11: integer;
  rx0, rx1, ry0, ry1, rz0, rz1, sx, sy, sz, a, b, c, d, u, v: double;
begin
  if start then
  begin
    start := false;
    init;
  end;
  bx0 := trunc(vec0 + defN) and defBM;
  bx1 := (bx0 + 1) and defBM;
  rx0 := frac(vec0 + defN);
  rx1 := rx0 - 1.0;
  by0 := trunc(vec1 + defN) and defBM;
  by1 := (by0 + 1) and defBM;
  ry0 := frac(vec1 + defN);
  ry1 := ry0 - 1.0;
  bz0 := trunc(vec2 + defN) and defBM;
  bz1 := (bz0 + 1) and defBM;
  rz0 := frac(vec2 + defN);
  rz1 := rz0 - 1.0;
  i := p[bx0];
  j := p[bx1];
  b00 := p[i + by0];
  b10 := p[j + by0];
  b01 := p[i + by1];
  b11 := p[j + by1];
  sx := rx0 * rx0 * (3.0 - 2.0 * rx0);
  sy := ry0 * ry0 * (3.0 - 2.0 * ry0);
  sz := rz0 * rz0 * (3.0 - 2.0 * rz0);
  u := rx0 * g3[b00 + bz0, 0] + ry0 * g3[b00 + bz0, 1] + rz0 * g3[b00 + bz0, 2];
  v := rx1 * g3[b10 + bz0, 0] + ry0 * g3[b10 + bz0, 1] + rz0 * g3[b10 + bz0, 2];
  a := u + sx * (v - u);
  u := rx0 * g3[b01 + bz0, 0] + ry1 * g3[b01 + bz0, 1] + rz0 * g3[b01 + bz0, 2];
  v := rx1 * g3[b11 + bz0, 0] + ry1 * g3[b11 + bz0, 1] + rz0 * g3[b11 + bz0, 2];
  b := u + sx * (v - u);
  c := a + sy * (b - a);
  u := rx0 * g3[b00 + bz1, 0] + ry0 * g3[b00 + bz1, 1] + rz1 * g3[b00 + bz1, 2];
  v := rx1 * g3[b10 + bz1, 0] + ry0 * g3[b10 + bz1, 1] + rz1 * g3[b10 + bz1, 2];
  a := u + sx * (v - u);
  u := rx0 * g3[b01 + bz1, 0] + ry1 * g3[b01 + bz1, 1] + rz1 * g3[b01 + bz1, 2];
  v := rx1 * g3[b11 + bz1, 0] + ry1 * g3[b11 + bz1, 1] + rz1 * g3[b11 + bz1, 2];
  b := u + sx * (v - u);
  d := a + sy * (b - a);
  result := c + sz * (d - c);
end;

{Harmonic summing functions}

{In what follows "alpha" is the weight when the sum is formed. Typically it is 2. As this
approaches 1 the function is noisier.
"beta" is the harmonic scaling/spacing, typically 2.
persistance = 1/alpha
beta = frequency
N = octaves}

function PNoise1(x, alpha, beta: double; n: integer): double;
var
  i: integer;
  val, sum, p, scale: double;
begin
  sum := 0;
  scale := 1;
  p := x;
  for i := 0 to n - 1 do
  begin
    val := noise1(p);
    sum := sum + val / scale;
    scale := scale * alpha;
    p := p * beta;
  end;
  result := sum;
end;

function PNoise2(x, y, alpha, beta: double; n: integer): double;
var
  i: integer;
  val, sum, px, py, scale: double;
begin
  sum := 0;
  scale := 1;
  px := x;
  py := y;
  for i := 0 to n - 1 do
  begin
    val := noise2(px, py);
    sum := sum + val / scale;
    scale := scale * alpha;
    px := px * beta;
    py := py * beta;
  end;
  result := sum;
end;

function PNoise3(x, y, z, alpha, beta: double; n: integer): double;
var
  i: integer;
  val, sum, px, py, pz, scale: double;
begin
  sum := 0;
  scale := 1;
  px := x;
  py := y;
  pz := z;
  for i := 0 to n - 1 do
  begin
    val := noise3(px, py, pz);
    sum := sum + val / scale;
    scale := scale * alpha;
    px := px * beta;
    py := py * beta;
    pz := pz * beta;
  end;
  result := sum;
end;

end.



Used like this:


unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  perlin;

procedure TForm1.Button1Click(Sender: TObject);
var
  x, y, z, c: integer;
begin
  image1.Canvas.Brush.Color := 0;
  image1.Canvas.FillRect(image1.Canvas.ClipRect);
  for x := 0 to 511 do
    for y := 0 to 511 do
    begin
      z := trunc(pnoise2(x / 100, y / 100, 2, 2, 10) * 128) + 128;
      c := z + (z shl 8) + (z shl 16);
      image1.Canvas.Pixels[x, y] := c;
    end;
  c := 0;
  repeat
    image1.Canvas.Pixels[519, c] := $FFFFFF;
    c := c + 10;
  until
    c > 510;
end;

end.

2004. március 21., vasárnap

How to extract a string from the middle of a sentence


Problem/Question/Abstract:

I need to extract a string from the middle of a sentence. For example: An email will come in with the following subject: Order from the Web : a.dyble@ntlworld.com. My method is to start at the @ sign and work outwards using copy.

Answer:

Solve 1:

This may not be the most efficient, but

function MyWord(const Token: Char; const S: string): string;
var
  B, M, E: Integer;
  K: string;
begin
  Result := '';
  M := Pos(Token, S);
  if M > 0 then
  begin
    K := ' ' + S + ' '; {wrap in spaces cause I'm lazy}
    B := M + 1;
    repeat
      Dec(B);
    until
      K[B] in [' ', #9, #10];
    E := M;
    repeat
      Inc(E);
    until
      K[E] in [' ', #9, #13];
    Result := Copy(S, B, E - B - 1);
  end;
end;

Example of using:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption := MyWord('@', Memo1.Text);
end;


Solve 2:

{Parse item}

procedure ParseItem(var Source, Item: string; Delimiter: Char);
var
  CurrentPosition: Integer;
begin
  CurrentPosition := Pos(Delimiter, Source);
  if CurrentPosition = 0 then
  begin
    {No delimeter - item is the remaining string}
    Item := Source;
    Source := '';
  end
  else
  begin
    {There is a delimeter}
    Item := Copy(Source, 1, CurrentPosition - 1);
    Delete(Source, 1, CurrentPosition);
  end;
end;

function GetEmailAddress(ASource: string): string;
var
  AWord: string;
begin
  Result := '';
  while ASource <> '' do
  begin
    ParseItem(ASource, AWord, ' ');
    if Pos('@', AWord) <> 0 then
    begin
      Result := AWord;
      Break;
    end;
  end;
end;

procedure TForm1.Button30Click(Sender: TObject);
begin
  ShowMessage(GetEmailAddress('Order from theWeb : a.dyble@ntlworld.com'));
end;


Solve 3:

Can we assume that you always have the colon / blank sequence? If so then this may be easier:

P := Pos(':', Subject) + 2; {Position following the colon / blank}
{Grab everything after}
EMailAddress := Copy(Subject, P, Length(Subject) - P - 1);


Solve 4:

If you can't count on the ' :' as Kurt suggests, perhaps the following will do:

function ExtractEMailAddress(const s: string): string;
const
  goodEMailChars = ['A'..'Z', 'a'..'z', '@', '.', '_', '-'];
var
  i, j, lth: integer;
begin
  i := pos('@', s);
  if i > 0 then
  begin
    j := i + 1;
    while (i > 0) and (s[i] in goodEMailChars) do
      dec(i);
    inc(i);
    lth := Length(s);
    while (j <= lth) and (s[j] in goodEMailChars) do
      inc(j);
    result := Copy(s, i, j - i);
  end
  else
    result := '';
end;


Solve 5:

You can use Pos to locate the substrings and Copy to copy the text to a new string. Something like:

function FindSubString(const S, Prefix, Suffix: string): string;
var
  P: Integer;
begin
  Result := EmptyStr;
  P := Pos(Prefix, S);
  if P > 0 then
  begin
    Result := Copy(S, P + Length(Prefix), Length(S));
    P := Pos(Suffix, Result);
    if P > 0 then
      SetLength(Result, P - 1)
    else
      Result := EmptyStr;
  end;
end;

The code isn't very efficient, but it should get you started.

2004. március 20., szombat

Retrieve the computer name


Problem/Question/Abstract:

How to retrieve the computer name

Answer:

Solve 1:

function ComputerName: string;
var
  size: DWORD;
begin
  size := MAX_COMPUTERNAME_LENGTH + 1;
  SetLength(Result, size - 1);
  if not GetComputerName(PChar(Result), size) then
    Result := '';
end;


Solve 2:

uses
  Windows;

procedure GetPCName(var PCName: string);
var
  nSize: DWORD;
begin
  nSize := MAX_COMPUTERNAME_LENGTH + 1;
  PCName := '';
  SetLength(PCName, nSize);
  if GetComputerName(PChar(PCName), nSize) then
    SetLength(PCName, nSize);
end;


Solve 3:

function GetLocalComputerName: string;
var
  iLen: cardinal;
begin
  iLen := 255;
  SetLength(Result, iLen + 1);
  if (GetComputerName(PChar(Result), iLen) = false) then
  begin
    RaiseLastWin32Error;
  end;
  SetLength(Result, iLen);
end;

2004. március 19., péntek

Change the position of a list item in a TListView (4)


Problem/Question/Abstract:

I want to keep one row as the topmost visible row in a TListView. Each time it will vary according to my search, which one I found I want to make that one as a topmost row. How can I do this?

Answer:

Scroll a listview item to the top:

procedure ScrollItemtoTop(lv: TLIstview; index: Integer);
var
  num: Integer;
  scrollcode: Integer;
begin
  num := lv.TopItem.Index - index;
  if num < 0 then
  begin
    scrollcode := SB_LINEDOWN;
    num := Abs(num);
  end
  else
    scrollcode := SB_LINEUP;
  lv.Items.BeginUpdate;
  try
    while num > 0 do
    begin
      lv.Perform(WM_VSCROLL, scrollcode, 0);
      Dec(num);
    end;
    lv.Perform(WM_VSCROLL, SB_ENDSCROLL, 0);
  finally
    lv.Items.EndUpdate;
  end;
end;

2004. március 18., csütörtök

How to determine file and tree sizes larger 2 GB


Problem/Question/Abstract:

How to determine file and tree sizes larger 2 GB

Answer:

Solve 1:

You will need to use the FindFirstFile, FindNextFile and FindClose functions, e.g.:

function GetFileSize(const FileName: string): Int64;
var
  F: TWin32FindData;
  H: THandle;
begin
  H := FindFirstFile(PChar(FileName), F);
  if H = INVALID_HANDLE_VALUE then
    RaiseLastWin32Error;
  try
    Result := F.nFileSizeHigh shl 32 + F.nFileSizeLow;
  finally
    Windows.FindClose(H);
  end;
end;

function GetTreeSize(FileName: string): Int64;

  procedure TreeSize(const FileName: string);
  var
    F: TWin32FindData;
    H: THandle;
  begin
    H := FindFirstFile(PChar(FileName), F);
    if H = INVALID_HANDLE_VALUE then
      RaiseLastWin32Error;
    try
      repeat
        if ((F.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) > 0) and (F.cFileName[0]
          <> '.') then
          TreeSize(ExtractFilePath(FileName) + F.cFileName + '\*.*')
        else
          Result := Result + F.nFileSizeHigh shl 32 + F.nFileSizeLow;
      until not FindNextFile(H, F);
    finally
      Windows.FindClose(H);
    end;
  end;

begin
  Result := 0;
  TreeSize(IncludeTrailingBackslash(ExtractFilePath(FileName)) + '*.*');
end;

I would add one little detail to your function. By calculating the filesize, you should cast the values to Int64. In the helpfile you can read, that this is necessary, because the operation would normally return an integer. In this case, (F.nFileSizeHigh shl 32) would return an Integer and not an Int64.

Result := Int64(F.nFileSizeHigh) shl 32 + Int64(F.nFileSizeLow);

I think, casting "nFileSizeLow" is not necessary, but better to make it safe.


Solve 2:

Use the WinAPI version of the function GetFileSize() as follows:

procedure CardinalsToI64(var I: Int64; const LowPart, HighPart: Cardinal);
begin
  TULargeInteger(I).LowPart := LowPart;
  TULargeInteger(I).HighPart := HighPart;
end;

{ ... }
var
  fLOdword: dword;
  fHIdword: dword;
  FFilesize: Int64;
  FFileHandle: THandle;
begin
  FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  fLOdword := GetFileSize(FFileHandle, @fHIdword);
  CardinalsToI64(FFilesize, fLOdword, fHIdword);

2004. március 17., szerda

Simultaneous 16- and 32bit-Development


Problem/Question/Abstract:

Simultaneous 16- and 32bit-Development

Answer:

If you need to develop 16bit- and 32bit-versions of the same program simultaneously, you just have to consider the following:

Delphi 1 DFM files can be read by Delphi 2 and 3, but not vice versa. Start your work in Delphi 1, then port to Delphi 2/3.
Any Delphi 2/3 enhancements can be "protected" with IFDEFs in the .PAS files, so the same .PAS file can be used by all Delphi versions:

{$IFDEF ver80}
   this is Delphi 1 specific..
{$ENDIF}
{$IFDEF ver90}
   this is Delphi 2 specific..
{$ENDIF}
{$IFDEF ver100}
   this is Delphi 3 specific..
{$ENDIF}
{$IFDEF ver120}
   this is Delphi 4 specific..
{$ENDIF}
{$IFDEF ver130}
   this is Delphi 5 specific..
{$ENDIF}
{$IFDEF ver140}
   this is Delphi 6 specific..
{$ENDIF}
{$IFDEF ver150}
   this is Delphi 7 specific..
{$ENDIF}
{$IFDEF WIN32}
   this is specific to Delphi 2 and 3..
{$ENDIF}
{$IFDEF ver93}
   this is specific to C++ Builder..
{$ENDIF}
{$IFDEF ver110}
   this is specific to C++ Builder 3..
{$ENDIF}

The only serious incompatibility are the .DCR-files. You will have to load them with the Delphi 2/3 Image-Editor, and save them again to convert a 16bit .DCR-file to a 32bit one.

2004. március 16., kedd

Obtain the Julian date


Problem/Question/Abstract:

How to obtain the Julian date

Answer:

function julian(year, month, day: Integer): real;
var
  yr, mth: Integer;
  noleap, leap, days, yrs: Real;
begin
  if year < 0 then
    yr := year + 1
  else
    yr := year;
  mth := month;
  if (month < 3) then
  begin
    mth := mth + 12;
    yr := yr - 1;
  end;
  yrs := 365.25 * yr;
  if ((yrs < 0) and (frac(yrs) <> 0)) then
    yrs := int(yrs) - 1
  else
    yrs := int(yrs);
  days := int(yrs) + int(30.6001 * (mth + 1)) + day - 723244.0;
  if days < -145068.0 then
    julian := days
  else
  begin
    yrs := yr / 100.0;
    if ((yrs < 0) and (frac(yrs) <> 0)) then
      yrs := int(yrs) - 1;
    noleap := int(yrs);
    yrs := noleap / 4.0;
    if ((yrs < 0) and (frac(yrs) <> 0)) then
      yrs := int(yrs) - 1;
    leap := 2 - noleap + int(yrs);
    julian := days + leap;
  end;
end;

2004. március 15., hétfő

Create a DBGrid that displays graphic fields


Problem/Question/Abstract:

How to create a DBGrid that displays graphic fields

Answer:

unit DBPicGrd;

interface

uses
  DBGrids, DB, DBTables, Grids, WinTypes, Classes, Graphics;

type
  TDBPicGrid = class(TDBGrid)
  protected
    procedure DrawDataCell(const Rect: TRect; Field: TField; State: TGridDrawState);
      override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property DefaultDrawing default False;
  end;

procedure Register;

implementation

constructor TDBPicGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  DefaultDrawing := False;
end;

procedure TDBPicGrid.DrawDataCell(const Rect: TRect; Field: TField; State:
  TGridDrawState);
var
  bmp: TBitmap;
begin
  with Canvas do
  begin
    FillRect(Rect);
    if Field is TGraphicField then
    try
      bmp := TBitmap.Create;
      bmp.Assign(Field);
      Draw(Rect.Left, Rect.Top, bmp);
    finally
      bmp.Free;
    end
    else
      TextOut(Rect.Left, Rect.Top, Field.Text);
  end;
end;

procedure Register;
begin
  RegisterComponents('Custom', [TDBPicGrid]);
end;

end.

2004. március 14., vasárnap

Mouse working only in your application


Problem/Question/Abstract:

I suppose that to somebody it will be he useful this trick.
Have I outlined it to me as a simple exercise of those that you tell yourself to yourself ' that would happen if? '.
It is that the mouse only works in your application. Neither in the Windows desktop, neither in the window's taskbar, neither in any
other place that in your form...
Of course, care with him... if you are happened to print something and the driver of your printer it jumps you with the typical
message ' papaer empty' you won't be able to close the dialogue that it appears... in short, better you prove it and you see if it is
good you for something:

Answer:

function CallBackDelHook(Code: Integer;
  wParam: WPARAM;
  lParam: LPARAM
  ): LRESULT; stdcall;

var
  DatosMouse: PMouseHookStruct;
  Intentos: integer;

  {Esta es la funcion CallBack a la cual llamar� el hook.}
  {This is the CallBack function called by he Hook}
begin
  {Si hay un nuevo evento de raton...}
  {if there is a new mouse event...}
  if code = HC_ACTION then
  begin
    {Miramos si existe el fichero}
    {if the mapfile exists}
    FicheroM := OpenFileMapping(FILE_MAP_READ, False, 'ElReceptor');
    {Si no existe, no enviamos nada a la aplicacion receptora}
    {If dont, send nothing to receiver application}
    if FicheroM <> 0 then
    begin
      Compartido := MapViewOfFile(FicheroM, FILE_MAP_READ, 0, 0, 0);

      {Apuntamos hacia los datos del evento del raton}
      DatosMouse := Pointer(lparam);

      UnmapViewOfFile(Compartido);
      CloseHandle(FicheroM);
    end;
  end;
  {Llamamos al siguiente hook de la cadena}
  {call to next hook of the chain}
  if Compartido^ <> DatosMouse^.hwnd then
    Result := 1
  else
    Result := CallNextHookEx(HookDeMouse, Code, wParam, lParam);
end;

and the relevant part is this:

if Compartido^ <> DatosMouse^.hwnd then
  Result := 1
else
  Result := CallNextHookEx(HookDeMouse, Code, wParam, lParam);

that is to say, if the recipient of the message that has captured the hook is our application, we call to the following mouse hook that
has installed in the chain, if it is not this way, because we give the message like treaty, miscarrying this way his processed later for
the application that is...

Well, like in any hook at system level, we will build ourselves first a DLL that is where anger the procedure CallBack of the hook,
and then an example application that will communicate somehow with the DLL.
Therefore:

Hook's DLL

library HookMouse;

{Demo de Hook de Rat�n a nivel de sistema, Radikal.}

uses Windows, Messages;

type
  PCompartido = ^THandle;

var
  HookDeMouse: HHook;
  FicheroM: THandle;
  Compartido: PCompartido;

function CallBackDelHook(Code: Integer;
  wParam: WPARAM;
  lParam: LPARAM
  ): LRESULT; stdcall;

var
  DatosMouse: PMouseHookStruct;
  Intentos: integer;

  {Esta es la funcion CallBack a la cual llamar� el hook.}
  {This is the CallBack function called by he Hook}
begin
  {Si hay un nuevo evento de raton...}
  {if there is a new mouse event...}
  if code = HC_ACTION then
  begin
    {Miramos si existe el fichero}
    {if the mapfile exists}
    FicheroM := OpenFileMapping(FILE_MAP_READ, False, 'ElReceptor');
    {Si no existe, no enviamos nada a la aplicacion receptora}
    {If dont, send nothing to receiver application}
    if FicheroM <> 0 then
    begin
      Compartido := MapViewOfFile(FicheroM, FILE_MAP_READ, 0, 0, 0);

      {Apuntamos hacia los datos del evento del raton}
      DatosMouse := Pointer(lparam);

      UnmapViewOfFile(Compartido);
      CloseHandle(FicheroM);
    end;
  end;
  {Llamamos al siguiente hook de la cadena}
  {call to next hook of the chain}
  if Compartido^ <> DatosMouse^.hwnd then
    Result := 1
  else
    Result := CallNextHookEx(HookDeMouse, Code, wParam, lParam);
end;

procedure HookOn; stdcall;
{Procedure que instala el hook}
{procedure for install the hook}
begin
  HookDeMouse := SetWindowsHookEx(WH_MOUSE, @CallBackDelHook, HInstance, 0);
end;

// stops this type of watch

procedure HookOff; stdcall;
begin
  {procedure para desinstalar el hook}
  {procedure to uninstall the hook}
  UnhookWindowsHookEx(HookDeMouse);
end;

exports
  {Exportamos las procedures...}
  {Export the procedures}
  HookOn,
  HookOff;

begin
end.

Demo application

In a clean form, put this code in its unit:

unit Unit1;

interface

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

const
  NombreDLL = 'HookMouse.dll';

type
  PCompartido = ^THandle;
  THookMouse = procedure; stdcall;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FicheroM: THandle;
    Compartido: PCompartido;
    HandleDLL: THandle;
    HookOn,
      HookOff: THookMouse;

  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  HandleDLL := LoadLibrary(PChar(ExtractFilePath(Application.Exename) +
    NombreDLL));
  if HandleDLL = 0 then
    raise Exception.Create('No se pudo cargar la DLL');

  @HookOn := GetProcAddress(HandleDLL, 'HookOn');
  @HookOff := GetProcAddress(HandleDLL, 'HookOff');

  if not assigned(HookOn) or
    not assigned(HookOff) then
    raise Exception.Create('No se encontraron las funciones en la DLL' + #13 +
      'Cannot find the required DLL functions');

  {Creamos el fichero de memoria}
  FicheroM := CreateFileMapping($FFFFFFFF,
    nil,
    PAGE_READWRITE,
    0,
    SizeOf(THandle),
    'ElReceptor');

  {Si no se cre� el fichero, error}
  if FicheroM = 0 then
    raise Exception.Create('Error al crear el fichero' +
      '/Error while create file');

  {Direccionamos nuestra estructura al fichero de memoria}
  Compartido := MapViewOfFile(FicheroM, FILE_MAP_WRITE, 0, 0, 0);

  {Escribimos datos en el fichero de memoria}
  Compartido^ := Handle;
  HookOn;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  {Desactivamos el Hook}
  {Uninstall the Hook}
  if Assigned(HookOff) then
    HookOff;

  {Liberamos la DLL}
  {Free the DLL}
  if HandleDLL <> 0 then
    FreeLibrary(HandleDLL);

  {Cerramos la vista del fichero y el fichero}
  {Close the memfile and the View}
  if FicheroM <> 0 then
  begin
    UnmapViewOfFile(Compartido);
    CloseHandle(FicheroM);
  end;
end;

end.

Note: If you use this technique in an application with several forms, you will put in ' Compartido' the handle of the form that you will
activate, but it won't receive mouse events. For example, you can make it in the event OnShow of the form...


2004. március 13., szombat

Dynamic SQL Creation: Using a TStrings Descendant to Create a SQL Statement on the Fly


Problem/Question/Abstract:

How do I retrieve the text from a list box to add to the SQL property of a TQuery then create both a Paradox and dBase table?

Answer:

One thing I love about Delphi is that since it's object oriented, you can perform a lot of quick and dirty code tricks that wouldn't be possible with other languages. For instance, the ability to assign values of like properties from one object to another saves so much coding time. Take a list box, for example, as in your question.

What you essentially want to do is create a SQL statement from fields listed in a list box. If you think about it, a list box's Items property and a TQuery's SQL property are both TStrings descendants. This means that you can do a direct assignation between the two.

Actually, that's only half true. You have to format the fields into a proper SQL statement format first, and that requires an intermediate TStrings object.

Luckily though, we can easily accomplish the conversion for field list to SQL statement with a simple function. The function listed below takes a list of fields, a Boolean value to determine whether or not the query is a DISTINCT select, and a table name, and puts all of those together into a valid SQL statement that can easily be
assigned to a TQuery's SQL property. Here's the listing:

{==========================================================
This function will create a SELECT or SELECT DISTINCT SQL
statement given input from a TStrings descendant like a
list. It will properly format the list into field decla-
rations of a SQL statement then, using the supplied
TableNm parameter, will construct an entire statement that
can be assigned to the SQL property of a TQuery.

Params:  Distinct  SELECT DISTINCT or regular SELECT
          TableNm   Table name: Should either be a fully
                    qualified table name, or preceeded by
                    an alias (ie, ':DbName:MyTable.db')
          FieldList Any TStrings descendant will work here,
                    like the Items property of a TListBox.
==========================================================}

function CreateSelect(Distinct: Boolean;
  TableNm: string;
  const FieldList: TStrings)
  : TStrings;
var
  Sql: TStringList;
  I: Integer;
  buf,
    QueryType: string;
begin
  //First, instantiate the SQL lines list
  Sql := TStringList.Create;

  //Determine whether or no this is a regular SELECT
  //or a SELECT DISTINCT query.
  if Distinct then
    QueryType := 'SELECT '
  else
    QueryType := 'SELECT DISTINCT ';

  buf := QueryType;

  try
    //Now add the fields to the select statement
    //Notice that if we're on the last item,
    //we don't want to add a trailing comma.
    for I := 0 to (FieldList.Count - 1) do
      if (I <> FieldList.Count - 1) then
        buf := buf + FieldList[I] + ', '
      else
        buf := buf + FieldList[I];

    //Now, put the query together
    Sql.Add(buf);
    Sql.Add('FROM "' + TableNm + '"');
    Result := Sql;
  finally
    Sql.Free;
  end;
end;

To use this, let's say you have a list box call ListBox1, and a query called Query1. You also have a TEdit called Edit1 that holds the table name value. Here's how you'd make the call:

with Query1 do
begin
  Active := False;
  SQL.Clear;
  //This will create a SELECT DISTINCT statement
  SQL := CreateSelect(True, Edit1.Text, ListBox1.Items);
  Open;
end;

Okay, now that we've finished creating the statement and running the query, we have to move the answers to both Paradox an dBase. This is easily accomplished with a TBatchMove component.

Building on the previous example,. let's say you have a TBatchMove component embedded on your form. We'll call it BatchMove1. To move the answer to a Paradox and a dBase table, you need to use the BatchMove to move the contents of the answer from Query1 to two new tables. The listing below lists an entire procedure that will accomplish this:

procedure GetFieldsAndMove;
var
  tblPdox,
    tbldBas: TTable;
begin

  with Query1 do
  begin
    Active := False;
    SQL.Clear;
    //This will create a SELECT DISTINCT statement
    SQL := CreateSelect(True, Edit1.Text, ListBox1.Items);
    Open;
  end;

  tblPdox := TTable.Create(nil);
  with tblPdox do
  begin
    Active := False;
    DatabaseName := ExtractFilePath(Application.EXEName);
    TableName := 'MyPdoxTable';
    TableType := ttParadox;
  end;

  tbldBas := TTable.Create(nil);
  with tbldBase do
  begin
    Active := False;
    DatabaseName := ExtractFilePath(Application.EXEName);
    TableName := 'MydBaseTable';
    TableType := ttDBase;
  end;

  try
    with BatchMove1 do
    begin
      Source := Query1;
      Destination := tblPdox;
      Execute;
    end;

    with BatchMove1 do
    begin
      Source := Query1;
      Destination := tbldBase;
      Execute;
    end;
  finally
    tblPdox.Free;
    tbldBase.Free;
  end;
end;

Again, this is pretty straight-forward stuff. If you need more information on the TBatchMove component, it is well-documented in the online help.

2004. március 12., péntek

How to synchronize two controls


Problem/Question/Abstract:

I have a frame with two panels on it (right and left). The left panel is a pretty standard treeview. The right panel is a representation of the data record for the selected node in the tree view. The right panel is dynamic, that is it is constructed on the fly at run time as the users have the ability to define what fields they wish to show and what the labels are for those fields.

I need the right panel to change the treeview node text when the record in the right panel is posted. The general consensus is that it'd best be done with a callback, but I've never done one before. Can anyone give me a simple example of how to do this?

Answer:

What you are describing is a Mediator Pattern. In essence, you set up a class which is aware of your two (or more) components. Set up properties to record changes and then in the appropriate event handler, simply assign the new values. The Mediator is solely responsible for synchonizing the two.

Very simple example (yours will be slightly more complex, but surprisingly probably won't have too much more code):

TEditBoxMediator = class
private
  FIsChanging: boolean;
  FFirstBox: TEdit;
  FSecondBox: TEdit;
  function GetText: string;
  procedure SetText(Value: string);
public
  property Text: string read GetText write SetText;
  constructor Create(const FirstBox, SecondBox: TEdit);
end;

constructor TEditBoxMediator.Create(const FirstBox, SecondBox: TEdit);
begin
  inherited Create;
  FFirstBox := FirstBox;
  FSecondBox := SecondBox;
  FIsChanging := False;
end;

function TEditBoxMediator.GetText: string;
begin
  Result := FFirstBox.Text;
end;

procedure TEditBoxMediator.SetText(Value: string);
begin
  if FIsChanging then
    Exit;
  FIsChanging := True;
  if FFirstBox.Text <> Value then
    FFirstBox.Text := Value;
  if FSecondBox.Text <> Value then
    FSecondBox.Text := Value;
  FIsChanging := False;
end;

procedure TForm1.Create {...}
begin
  FEditBoxMediator := TEditBoxMediator.Create(Edit1, Edit2);
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  FEditBoxMediator.Text := Edit1.Text;
end;

and so on.

The idea is that the mediator handles the changes (and uses the internal flag to prevent an endless
loop).

2004. március 11., csütörtök

Sorting a TListView by the column clicked by the user


Problem/Question/Abstract:

How to sort a ListView in ascending or descending order by a given column?

Answer:

Solve 1:

We want the following behaviour for a ListView:


When the user clicks on a column header, the ListView should be sorted by that column

The initial sort order should be ascending. If the user clicks on the same column again, the sort order should be toggled. If the user clicks on another column, the sort order of the new column should be the same as the last sorted column.


For the implementation we need two variables to hold the last column clicked by the user and the current sort order:

var
  LastSortedColumn: integer;
  Ascending: boolean;

We can initialize them when the form is created:

procedure TForm1.FormCreate(Sender: TObject);
begin
  LastSortedColumn := -1;
  Ascending := True;
end;

In the ColumnClick event of the ListView we determine the sort order and perform the sort:

procedure TForm1.ListView1ColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  if Column.Index = LastSortedColumn then
    Ascending := not Ascending
  else
    LastSortedColumn := Column.Index;
  TListView(Sender).CustomSort(@SortByColumn, Column.Index);
end;

SortByColumn is a function that should be previously declared and is the function used by CustomSort to compare two items. The value passed to the Data parameter of CustomSort will be passed as the Data parameter to SortByColumn and we use it for the sort column:

function SortByColumn(Item1, Item2: TListItem; Data: integer):
  integer; stdcall;
begin
  if Data = 0 then
    Result := AnsiCompareText(Item1.Caption, Item2.Caption)
  else
    Result := AnsiCompareText(Item1.SubItems[Data - 1],
      Item2.SubItems[Data - 1]);
  if not Ascending then
    Result := -Result;
end;

Solve 2:

Instead of calling the custum sort procedure we also can use the OnColumnClick and the OnCompare events ion conjunction... That way the compare routine is kept within the class, here a TForm decedant.

Like this:

procedure TfrmMain.lvThingyColumnClick(Sender: TObject; Column: TListColumn);
begin
  if Column.Index = fColumnClicked then
    fSortAscending := not fSortAscending
  else
  begin
    fSortAscending := true;
    fColumnClicked := Column.Index;
  end; // else

  Screen.Cursor := crHourglass;
  try
    (Sender as TListView).AlphaSort;
  finally
    Screen.Cursor := crDefault;
  end; // try
end;

procedure TfrmMain.lvThingyCompare(Sender: TObject; Item1, Item2: TListItem; Data:
  Integer; var Compare: Integer);
begin
  case fColumnClicked of
    0: Compare := CompareStr(Item1.Caption, Item2.Caption);
  else
    Compare := CompareStr(Item1.SubItems[fColumnClicked - 1],
      Item2.SubItems[fColumnClicked - 1]);
  end; // case
  if not fSortAscending then
    Compare := -Compare;
end;

2004. március 10., szerda

Working with files of records

{\*\pnseclvl3\pndec\pnstart1\pnhang\pnindent720{\pntxtb}{\pntxta{.}}}
{\*\pnseclvl4\pnlcltr\pnstart1\pnhang\pnindent720{\pntxtb}{\pntxta{)}}}
{\*\pnseclvl5\pndec\pnstart1\pnhang\pnindent720{\pntxtb{(}}{\pntxta{)}}}
{\*\pnseclvl6\pnlcltr\pnstart1\pnhang\pnindent720{\pntxtb{(}}{\pntxta{)}}}
{\*\pnseclvl7\pnlcrm\pnstart1\pnhang\pnindent720{\pntxtb{(}}{\pntxta{)}}}
{\*\pnseclvl8\pnlcltr\pnstart1\pnhang\pnindent720{\pntxtb{(}}{\pntxta{)}}}
{\*\pnseclvl9\pndec\pnstart1\pnhang\pnindent720{\pntxtb{(}}{\pntxta{)}}}
\endnhere\sectdefaultcl{\footer \pard{\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f0\fs22\cf0\i Delphi Knowledge Base (http://dkb.kastu.lt)}}
{\pard\wpparprot{\ql\li195\fi0\ri0\sb0\sl\sa0 \plain\f41\fs22\cf0\b Title: Working with files of records\par
\wpparprot\ql\li195\fi0\ri0\sb0\sl\sa0 \plain\f42\fs22\cf0\b Author: Lou Adler\par
\wpparprot\ql\li195\fi0\ri0\sb0\sl\sa0 \plain\f43\fs22\cf0\b Product: Delphi 2.x (or higher)\par
\wpparprot\ql\li195\fi0\ri0\sb0\sl\sa0 \plain\f44\fs22\cf0\b Post Date: 01/08/2003\par
\wpparprot\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f45\fs22\cf0\b \par
\wpparprot\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f45\fs22\cf0\b\shad Problem/Question/Abstract:\par
\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\shad \par
\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Working with files of records\par
\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\shad \par
\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\b\shad Answer:\par
\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\shad \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 As a local or client/server database application development tool, Delphi is hard to beat. The data access and data \plain\f1\fs22\cf0 control components included in the VCL make building database applications easy. And the Borland Database \plain\f1\fs22\cf0 Engine (BDE), which provides multi- platform support for several types of databases, makes compiling disparate \plain\f1\fs22\cf0 information from a variety of data sources seem routine. Unfortunately, this simplicity comes at a price: You can't \plain\f1\fs22\cf0 distribute a database application without the BDE, which means adding no less than two diskettes to your installation \plain\f1\fs22\cf0 set. While you may not consider this too big a price to pay, for simple database applications (i.e., data-entry and \plain\f1\fs22\cf0 retrieval), the BDE may be overkill. So what other alternatives do you have besides using the BDE? One answer that \plain\f1\fs22\cf0 comes to mind is storing data in a file of records.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Building database applications with files of records\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Let me start out with a sort of caveat: Constructing from scratch even the simplest database application based on a \plain\f1\fs22\cf0 file of records is not a trivial matter. Complications arise because all the elements you're used to having at hand \plain\f1\fs22\cf0 when using data access components just don't exist. For example, the posting and navigation rules that we take for \plain\f1\fs22\cf0 granted as built into Tables (like what happens if the user moves beyond the end of a table), you must write into the \plain\f1\fs22\cf0 program.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Furthermore, you can't insert or delete a record in the middle of a file; it's one more thing you have to program. \plain\f1\fs22\cf0 Sounds pretty dismal, right? And I'm willing to bet that since those items I mentioned aren't present, most \plain\f1\fs22\cf0 programmers won't dive into writing applications around files of records because doing so seems too difficult. \plain\f1\fs22\cf0 That's too bad, because despite the fact that building a database from scratch isn't a trivial matter, the mechanics of \plain\f1\fs22\cf0 building such a database aren't that difficult to master.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Another positive to building an application around a file of records is this: You're limited in what you can do with a \plain\f1\fs22\cf0 file of records. This limitation simplifies things a great deal. Also, the mechanics behind building an application \plain\f1\fs22\cf0 around a file of records merely involve making the right combination of calls to perform a desired action. You don't \plain\f1\fs22\cf0 need to be a rocket scientist; you just need a bit of patience and some ingenuity. Also, if you take some time to plan \plain\f1\fs22\cf0 out your application, you'll save yourself a lot time.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Just give it to me simple\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 The biggest stumbling block for most developers who are new to this type of application seems to be achieving a \plain\f1\fs22\cf0 sense of what the program is supposed to do; that is, defining its basic functionality. Many developers erroneously \plain\f1\fs22\cf0 start out with some sort of feature set they want to include in the program, then build the program around that set--a \plain\f1\fs22\cf0 valid approach if you have a foundation of basic functionality already present. However, if you don't have that \plain\f1\fs22\cf0 luxury, then you have no choice but to take a much more elemental approach to building the application. This means \plain\f1\fs22\cf0 establishing its basic functionality before adding the bells and whistles.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Actually, you could use the following as a rule of thumb for building any type of application: Get a handle on what \plain\f1\fs22\cf0 your program should ultimately accomplish before you write a single line of code. For some, seeing the big picture \plain\f1\fs22\cf0 involves intensive design meetings and reviews. For others, it's a simple statement that says, "My program does X." \plain\f1\fs22\cf0 But no matter which route you take, establishing your goal ahead of time makes the job of achieving it that much \plain\f1\fs22\cf0 easier. So with respect to the application we discussed in the main article, let's talk about what its basic functionality \plain\f1\fs22\cf0 will be.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 You've all seen and have probably written several data-entry and retrieval programs. And if you think about it, any \plain\f1\fs22\cf0 simple database application revolves around three basic editing actions:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\pntext\f17 l\tab}{{\*\pn \pnlvlblt\pnf17\pnhang\pnindent360{\pntxtb{l}}}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Adding new records\par
{\pntext\f17 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Deleting unwanted records\par
{\pntext\f17 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Updating existing records\par
}\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 In addition, an application requires a limited set of navigation actions:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\pntext\f18 l\tab}{{\*\pn \pnlvlblt\pnf18\pnhang\pnindent360{\pntxtb{l}}}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Moving to the first record of a file\par
{\pntext\f18 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Moving to the last record of a file\par
{\pntext\f18 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Moving to the next record\par
{\pntext\f18 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Moving to the previous record\par
{\pntext\f18 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Searching for an existing record\par
}\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 That's it. Here you have the basic functionality of any simple database application. You'll notice that printing isn't in \plain\f1\fs22\cf0 this list. I omitted it intentionally because hard-copy reporting is more an ancillary than a core function, and we're \plain\f1\fs22\cf0 concerned at this point with core functionality. The actions we've discussed here represent that functionality.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b A record for your files\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 A file of records is a binary file that stores records in sequential order and has a specific structure, like this:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b type\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MyRecord = \plain\f6\fs20\cf0\b record\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     ID: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     First, Last: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
}}\pard \plain\s0\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 If you've used arrays of records in the past, think of a file of records as a persistent array of records, very much akin \plain\f1\fs22\cf0 to a simple database. Working with a file of records in Delphi is like working with any DOS file: You assign a file to \plain\f1\fs22\cf0 an appropriate file variable, open the file with the appropriate File Open function, perform your manipulations, then \plain\f1\fs22\cf0 close the file. However, to successfully work with files of records, you need to take certain characteristics into \plain\f1\fs22\cf0 account:  \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\pntext\f21 l\tab}{{\*\pn \pnlvlblt\pnf21\pnhang\pnindent360{\pntxtb{l}}}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 A file of records is like a persistent array, although unlike a Pascal array, a file of records can grow \plain\f1\fs22\cf0 (though shrinking one down is another matter entirely, one which we'll cover below).\par
{\pntext\f21 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 A file of records is a binary file, meaning that you can't easily view the files with a text editor. Therefore, \plain\f1\fs22\cf0 all editing must take place in a program that can read the file.\par
{\pntext\f21 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Just as you do with an array variable representing a record structure, you must always declare the \plain\f1\fs22\cf0 variable assigned to a file of records as file of <type>.\par
{\pntext\f21 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 The Read and Write functions operate much\par
{\pntext\f21 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 like ReadLn and WriteLn for text files, which increment the file pointer to the next line; they always \plain\f1\fs22\cf0 increment the pointer to the next record. This operation is in sharp contrast to the Read and Write \plain\f1\fs22\cf0 functions for a text file, which will read or write a line of text but won't increment the file pointer.\par
{\pntext\f21 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Each record in a file of records is implicitly assigned a record number, starting with 0 (like an array). \plain\f1\fs22\cf0 Using the Seek function, you can go directly to a specific position within the file.\par
}\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b File access: Opening and closing files of records\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Just as with text files, you open a file of records using AssignFile, along with the Reset procedure to open up an \plain\f1\fs22\cf0 existing file or the Rewrite procedure to create a new file. Note that Append isn't an applicable FileOpen procedure, \plain\f1\fs22\cf0 since that's strictly a text file function. To close a file of records, you use the CloseFile procedure--the same \plain\f1\fs22\cf0 procedure you use with a text file. Pascal old-timers should notice that I didn't mention the standard procedures \plain\f1\fs22\cf0 Assign and Close for opening and closing. While not necessarily obsolete, these procedure names conflict with VCL \plain\f1\fs22\cf0 method names. In order to use them safely, you have to use dot notation and specify the System unit (e.g., \plain\f1\fs22\cf0 System.Assign); otherwise, you're likely to get a compilation error due to making one of these calls within the \plain\f1\fs22\cf0 context of a VCL object. Note that even the online help suggests you use AssignFile and CloseFile going forward.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Now, you can't open a file of records unless you have first defined a record structure and have an appropriate \plain\f1\fs22\cf0 variable declaration as mentioned above. For example, if you define a record structure TAddressRec, the file \plain\f1\fs22\cf0 variable declaration would be as follows:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   AddrFile: \plain\f6\fs20\cf0\b file\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b of\plain\f6\fs20\cf0  TAddressRec;\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Once that's done, it's easy to open a file:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 AssignFile(AddrFile, \plain\f6\fs20\cf11 'Address.DAT'\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b if\plain\f6\fs20\cf0  FileExists(\plain\f6\fs20\cf11 'Address.DAT'\plain\f6\fs20\cf0 ) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Reset(AddrFile)\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Rewrite(AddrFile);\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 (The FileExists function is a simple utility function that I use to confirm the existence of a file.)\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Where am I? Record numbers and the file pointer\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Records in a file of records are implicitly numbered sequentially, starting with zero for the first record. For example, \plain\f1\fs22\cf0 if you have a file of 10 records, the records would be numbered 0 to 9. This setup is similar to standard Pascal \plain\f1\fs22\cf0 zero-based arrays, in which the last element is always equal to the element count minus one. When you open up a \plain\f1\fs22\cf0 file of records, the file variable has a sort of positional indicator property associated with it called a file pointer. \plain\f1\fs22\cf0 Initially, the file pointer is set at the beginning of the file, that is, at record 0. However, you can use the Seek function \plain\f1\fs22\cf0 to move to any position in the file. For instance, let's say you want to move to record 51 in a file. To do that, you'd \plain\f1\fs22\cf0 make a call similar to the following:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 Seek(AddrFile, \plain\f6\fs20\cf11 51\plain\f6\fs20\cf0 );\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 From there you could read or write a file variable\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 depending on the prescribed action. Each read or write operation will always position the file pointer at the record \plain\f1\fs22\cf0 following the record that received the action. For example, if the record your program just read was record 2, \plain\f1\fs22\cf0 immediately following the call the file pointer would be placed on record 3.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 This positioning isn't much of an issue for sequential writes to a file; however, it's a serious issue for sequential \plain\f1\fs22\cf0 reads. Were you to read the last record of a file, then immediately attempt to read the next record (which is \plain\f1\fs22\cf0 nonexistent), you'd get a runtime error because you've attempted to read beyond the end of the file. As luck would \plain\f1\fs22\cf0 have it, though, you can call on a useful routine named FilePos to determine your position in the file.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 FilePos is a function that returns the current record in a file of records. If you're doing sequential reads in a file, \plain\f1\fs22\cf0 you'll want to make use of this function and compare its value against the FileSize function, which returns the total \plain\f1\fs22\cf0 count of records in the file. But since the last record in a file is always numbered as one less than the total number of \plain\f1\fs22\cf0 records, you must always subtract one from the FileSize function to safely make a comparison between your current \plain\f1\fs22\cf0 position and the end of the file. Below is the skeleton of a looping structure that illustrates positional\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 comparison:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b while\plain\f6\fs20\cf0  (FilePos(AddrFile) <= (FileSize(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 )) \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Read(AddrFile, AddrRec);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf11\i // ...do some stuff\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Reading and writing records\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Now that we've covered the basics of opening and closing a file, and determining and manipulating our position in a \plain\f1\fs22\cf0 file of records, we're ready to discuss the editing functions--or more simply, reading and writing to a file. To read a \plain\f1\fs22\cf0 record from a file of records, you simply call the Read procedure and specify file and record variables as formal \plain\f1\fs22\cf0 parameters such as\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 Read(AddrFile, AddrRec);\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 where AddrFile is the file variable and AddrRec is a record variable. Pretty simple stuff. Similarly, to write a record \plain\f1\fs22\cf0 into a file of records, you call the Write procedure and provide the same formal parameters as in the Read \plain\f1\fs22\cf0 procedure:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 Write(AddrFile, AddrRec);\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 It's possible to read several records from and write several records to a file of records at one time by overloading \plain\f1\fs22\cf0 the record parameter. For instance, let's say you want to read three records from a file simultaneously. In that case, \plain\f1\fs22\cf0 you'd do something like the following:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 Read(AddrFile, AddrRec1, AddrRec2, AddrRec3);\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 One thing you must keep in mind when using these functions: The file pointer is always positioned at the next record \plain\f1\fs22\cf0 following the call. I mentioned earlier that this is a serious consideration when you're performing sequential reads \plain\f1\fs22\cf0 from a file of records, but it can also be serious when you're editing a record. For instance, let's say you want to \plain\f1\fs22\cf0 read record 5 from the file, edit it, then write it back to file. The proper way to write back to the original record \plain\f1\fs22\cf0 would be as follows:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  ChangeLastName(RecNum: Integer; NewValue: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   recBuf: TAddressRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, RecNum);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Read(AddrFile, recBuf);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b with\plain\f6\fs20\cf0  recBuf \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     LastName := NewValue;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf11\i \{Go back to the original record, then write!\}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, RecNum);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Write(AddrFile, recBuf);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 As you can see, I use an extra Seek immediately before the Write to move the file pointer back to the proper \plain\f1\fs22\cf0 position. Strangely enough, both novices and experts make this fairly common error. The most important thing to \plain\f1\fs22\cf0 remember regarding manipulating files of records is the fate of the file pointer position in relation to a Read or a \plain\f1\fs22\cf0 Write operation.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b A quick review\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 We've just covered a lot of ground, so let's quickly review the various functions discussed above. \plain\f1\fs22\cf0\b Table A\plain\f1\fs22\cf0  lists the \plain\f1\fs22\cf0 functions and the resulting actions.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\b Table A\plain\f1\fs22\cf0 : Record file functions\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\*\wptable}{\pard\trowd\trgaph0\trleft0\clbrdrt\brdrs\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\brdrw0\cellx10772\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\clbrdrl\brdrs\brdrw0\brsp40\clshdng0\clcbpat16\clcfpat12\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\clbrdrt\brdrs\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\brdrw0\cellx10772\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\intbl{\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs24\cf0 Function Action\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 AssignFile Assigns a file on disk to a file variable\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Reset Opens a file for editing\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Rewrite Creates a new file\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 CloseFile Closes a file\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 FileSize Returns the number of records in a file\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 FilePos Returns the current position of the file pointer\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Seek Moves the file pointer to a specific position in a file\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Read Reads a record into a record variable\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Write Writes a record variable to a record in a file\line \plain\f1\fs24\cf0 \line \plain\f1\fs24\cf0 Truncate Deletes the remainder of a file from a given position\cell}\row
}\pard{\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 As you can see, you need to know only a handful of routines in order to manipulate files of records. With this \plain\f1\fs22\cf0 information, you can now write applications that revolve around the concepts we've explored.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Before you begin, though, notice that I made no mention of the record structure with respect to any of the functions \plain\f1\fs22\cf0 above. That's the beauty of these routines! They're so generalized that all you have to do is supply the right type of \plain\f1\fs22\cf0 file variable, and the functions do all the work. These functions don't care what your record structure is, so long as \plain\f1\fs22\cf0 your file variable points to a file that's of the correct type. Pretty nifty. In any case, play around with this stuff. Once \plain\f1\fs22\cf0 you get the hang of working with files of records, you'll probably use them more often.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Sometimes you need a go-between\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 You move data back and forth between the database and the user interface (i.e., read or write a record) by writing to \plain\f1\fs22\cf0 a record variable that acts as a temporary buffer between the edit fields and the fields of a record in the database. \plain\f1\fs22\cf0 This buffer is necessary because, unlike data-aware components, there's no such thing as a data link that will link \plain\f1\fs22\cf0 TEdit objects to fields in a record. To accomplish this linking in my applications, I use two procedures called \plain\f1\fs22\cf0 ReadRec and SetRecVals. The ReadRec function reads the record at the current position in the file into a global \plain\f1\fs22\cf0 record variable named AddrRec (of type TAddressRec) and then writes the variable's fields to the appropriate TEdit \plain\f1\fs22\cf0 components' Text properties. The SetRecVals function, on the other hand, writes the values stored in the TEdit \plain\f1\fs22\cf0 components' Text properties to AddrRec. However, you'll use the individual write methods to write data to the \plain\f1\fs22\cf0 database, since these methods are position-dependent.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Adding and updating records to the database\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Updating a record to the database merely involves moving the data from the TEdit components to the temporary \plain\f1\fs22\cf0 buffer variable, then writing the record variable's contents to the file. However, no such thing as a field-level update \plain\f1\fs22\cf0 exists when you're working with a file of records. When you update a record at a particular position within the file, \plain\f1\fs22\cf0 you're actually completely overwriting the record at that position. In fact, the mechanics for adding a new record to \plain\f1\fs22\cf0 the end of the database and overwriting an existing record are nearly identical. The only difference is that when \plain\f1\fs22\cf0 appending a record to the database, the program merely performs a Seek beyond the end of the file, then writes the \plain\f1\fs22\cf0 record variable.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b The problem with inserting and deleting\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 I mentioned earlier that it's impossible to insert or delete a record in a particular position in a file of records. It's true \plain\f1\fs22\cf0 that Delphi offers no functions that deal with these actions directly; however, that doesn't mean you can't code for \plain\f1\fs22\cf0 them. To insert or delete a record in a file of records, you employ a buffer to temporarily hold records that you want \plain\f1\fs22\cf0 to write back to the file. Let's quickly go over the logic of each operation before we examine the code. To insert a \plain\f1\fs22\cf0 new record, you follow these basic steps:\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\pntext\f30 l\tab}{{\*\pn \pnlvlblt\pnf30\pnhang\pnindent360{\pntxtb{l}}}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Initialize an array of records of the appropriate record type.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Get the current position of the file pointer and save it.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Transfer the contents of the TEdit components into a temporary record variable.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Seek to the beginning of the file.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Read each record from the beginning of the file up to the record just before the insert position. (If you \plain\f1\fs22\cf0 want to make an insertion at the beginning of the file, skip this step.)\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Write the record to be inserted into the file to the array.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Continue reading the file from the insert position into the array until you reach the end of the file.\par
{\pntext\f30 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Write the entire array's contents back to the file.\par
}\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Deleting a record isn't quite as complex as inserting a record. With a delete, you're not concerned with the records \plain\f1\fs22\cf0 before the deletion point--only the records following it. For this reason, the steps to accomplish a delete are very \plain\f1\fs22\cf0 simple: \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\pntext\f31 l\tab}{{\*\pn \pnlvlblt\pnf31\pnhang\pnindent360{\pntxtb{l}}}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Read all the records following the deletion point into a temporary record buffer.\par
{\pntext\f31 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Truncate the file from the deletion point.\par
{\pntext\f31 l\tab}\qj\li1080\fi-360\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Write the buffered records back to the file from the deletion point.\par
}\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Truncate is a function that will remove all the records from a file starting at the current file position, then reset the \plain\f1\fs22\cf0 current position of the file with the end of file (EOF) marker. To use the function, you have to Seek to the record you \plain\f1\fs22\cf0 want to delete first. This step is imperative because you may delete in the wrong place, and once you call this \plain\f1\fs22\cf0 function, there's no undo. (I'm warning you based on direct experience. Ugh!)\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\ql\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Movin' on up\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Navigating through a file of records (that is, moving from record to record) is actually ridiculously easy. However, it \plain\f1\fs22\cf0 can't hurt to look at a good example of how to put to use the techniques described above. So now that we've \plain\f1\fs22\cf0 covered the basic principles of manipulating a file of records, let's employ them in a sample application that \plain\f1\fs22\cf0 maintains a simple address and phone number database. (If you're not accustomed to creating database applications \plain\f1\fs22\cf0 without using a true database, see "Building Database Applications with Files of Records.")\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Address pattern\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 To begin, create a new blank form application. Next, add the appropriate components to make the form resemble \plain\f1\fs22\cf0 the one shown in \plain\f1\fs22\cf0\b Figure A\plain\f1\fs22\cf0 . As shown in \plain\f1\fs22\cf0\b Figure A\plain\f1\fs22\cf0 , you'll use standard components to implement the example \plain\f1\fs22\cf0 application's functionality. (For the time being, you can use the default names for the different components, but go \plain\f1\fs22\cf0 ahead and set the \plain\f1\fs22\cf0\b Caption\plain\f1\fs22\cf0  properties to match this figure.) You'll notice that it's a simple form comprised of buttons \plain\f1\fs22\cf0 at the top and sides for navigation and editing, respectively, and TEdit components for entering basic contact \plain\f1\fs22\cf0 information. The section below the contact information is for searching the database on a last name.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\b Figure A\plain\f1\fs22\cf0 :\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 {\*\wptools{110e0d005457504f476966496d61676500545046300c5457504f476966496d61676500075769647468545703ad1608486569676874545703ea15064f626a54616702000c57726974655254464d6f6465070f776f624f6e6c795374616e646172640b5472616e73706172656e7408105472616e73706172656e74436f6c6f720707636c426c61636b00004749460047494638396183017601f70000000000800000008000808000000080800080008080c0c0c0c0dcc0a6caf0330000660000990000cc0000003300333300663300993300cc3300ff3300006600336600666600996600cc6600ff6600009900339900669900999900cc9900ff990000cc0033cc0066cc0099cc00cccc00ffcc0033ff0066ff0099ff00ccff00000033330033660033990033cc0033ff0033003333333333663333993333cc3333ff3333006633336633666633996633cc6633ff6633009933339933669933999933cc9933ff993300cc3333cc3366cc3399cc33cccc33ffcc3300ff3333ff3366ff3399ff33ccff33ffff33000066330066660066990066cc0066ff0066003366333366663366993366cc3366ff3366006666336666666666996666cc6666ff6666009966339966669966999966cc9966ff996600cc6633cc6666cc6699cc66cccc66ffcc6600ff6633ff6666ff6699ff66ccff66ffff66000099330099660099990099cc0099ff0099003399333399663399993399cc3399ff3399006699336699666699996699cc6699ff6699009999339999669999999999cc9999ff999900cc9933cc9966cc9999cc99cccc99ffcc9900ff9933ff9966ff9999ff99ccff99ffff990000cc3300cc6600cc9900cccc00ccff00cc0033cc3333cc6633cc9933cccc33ccff33cc0066cc3366cc6666cc9966cccc66ccff66cc0099cc3399cc6699cc9999cccc99ccff99cc00cccc33cccc66cccc99ccccccccccffcccc00ffcc33ffcc66ffcc99ffccccffccffffcc3300ff6600ff9900ffcc00ff0033ff3333ff6633ff9933ffcc33ffff33ff0066ff3366ff6666ff9966ffcc66ffff66ff0099ff3399ff6699ff9999ffcc99ffff99ff00ccff33ccff66ccff99ccffccccffffccff33ffff66ffff99ffffccffff0d0d0d1b1b1b2828283636364343435151515e5e5e6b6b6b797979868686949494a1a1a1aeaeaebcbcbcc9c9c9d7d7d7e4e4e4f2f2f2f0caa6f0fbffa4a0a0ffefceffffc2ffffd0e0ffbfe0ffdfe0ffffc2effffffbf0a0a0a4808080ff000000ff00ffff000000ffff00ff00ffffffffff21f90400000000002c00000000830176014008ff000f081c48b0a0c18308132a5cc8b0a1c38710234a9c48b1a2c58b18336adc8810c0817f0209881c499240807c28039424f0afe5bf912d57ca24197366c99a2b718ad469b3a7cf9f40830a1d4ab4a8d1a348932a05c9101f00a600a24a952ad0e9ce86560954f5c85424007cf7c28abde771c080a8375dc27c19b32d5b972f59c6859b96e65cba72d5e2c49b776d5ca580030b1e4cb8b0e1994c0f4c8d4ad029d4c5540f644dac30ebd68f1c336bdeccb9b3e7cfa0438ba6e814f3e8d3a853ab5ecdba75ead29425c6765d79366d84a56f37f5a8bb32efdec0615bb40df1b7408fc6791b97888f38c1e58a8f1b442efd3775e9d813e69e685df974efa4a117ff2f687d20f889db81eb16aebebdfbf7f0e3df665f713972e5f8e5cb871e59717efd000658117d021668e08108ba4720734fc1e5e083104628e184145668e18518b6641a560d66e8e187208628225c1b32e45c448c65175a7abe95c8e08830c628238c2efa36e38d38e608618d099df8106429ae28de410b2668e491482ee423802c6ac71546d71d17d954fe49d99d79e20d99e4965c2ef9e374e685195d464de2f6249768a6a9e69a9779e9a48e70c629e79c74d639228f08b9a990960df1e95099449e199e9d84166ae8a1886688e7417a7614a46a801a54249b94564a5ba3ef455ad0a49676eaa9689892f79c8ad1d9472a7a7e0ec4a944a696e76a76d7c5ff3aeaa7b4d6aaa0a0a802a9ebaebcf6eaebafc0062becb0c4166becb1c81ebba8ad812ebb5ba2d0462bedb4383acb6c63b8be48edb6dc76ebad86a1d2baeab5e4966bae99d62ec45f95e731cb1f7efff5876298549e6baf93e9deabefbe6c8efbecb7853aeb588c0277286dbefcbae6ef4203036c67c132424c2dc209b3b670c518676ce0c51a77ecf1ad141fb46e75f4964c6abb069a4af2981fb78c6ac82ec72c33681c9be930a112df0c27cc336b5673a03ad79973d0d586db33473f1fadf4d21625cdf4d350efc673d454572d59b65667adb5a458d727eaca51c27a9eaca58a09ebd9afb21c65aa5bb78dedd46ec7edb1d336136d37483e1a1ddc727af7ffa669a65da37ab7ddcef6fdb5c9659f1a5e417ab68a7872589e9a22db571f48b7dc0d193e1fdf49fe0db2e698877eefe5a2973efa99f85c5a556b4ca56ebae9ffe0e37a9babbbd63aebb5bfae75eca9f3fe91ec6f7775d8f0c4176ffcf1c827affcf24ad17e804d51053095f476edf5965cd8d7e416f6dcafb5d35ddf73bfbdf8d76fcf13f3e8a7affefa2c710895c85b5d45de7296552e3c011ee1638001a997661600ec0ba0000748c0021af028ced39d02e716b8053af074708b20cb184239dc2c097290aae077ccb6a70169104c5f5a9cc6481741c878a6391b3121d23ea8aec5acb03e2eec8ce7cc45c207da704d3574dc98c2a63495258e87378c0f09ff9d92ac221af188c542181191c8c4263a91317a029dc2283744830dae5b4ab4e215b78530295e69826503e2cb3814c1866d915b593ca3b72458a91a06b16d529c60aa58882e32f64d8789fba1c9c836ab3752ca8b2a14d29f1ac8a1271af290884ca4221719ac2e768e8a84fc971a2749493446114a67c38ecae8b8294896518b950ca5281f164735b9d18f59bb631f0fb7ca8bccd07e1c095bbda834b920d9524b9c44657bf4a6ab0c0e928dba0c6680aa38ca621a734ec0ec57241906ca633af3991f4a260e9729cc6a1ee994d6cca67a7238aab5e53249e5d9e11e39a82ef885539bafa1a69318c94e6115cc88ef6c672f4b193a6242f3424313513ea125ff4dd1d9f39e15da2788048aa87ed6539de84ca81011da916e56c94ad5e9cec85006a07781478c0abd264333cad1f56cb493f20c29afe229d2921a1473ff04e88408aad293ca2da52a8d104b01ead2b861b3a338a5d94773cad3d3dcb4a740ddc84d2d1ab987820d4bf032aabcc008d1a6d6d23b930b6ac57e2ad5aa2e4e8a4b2ca9569d58b84732ceab1bdb29d0628ab3bca5705e64e29c433e989c7376908c614da619c98a4cb3228945f4f4655cf36ad5befe92af7e0d2cbe6e67bbdca986b0824d58eb50a73ac9e0ceb1892d97ef7ca7aafcc9eeb298cdac6637cbd9ce7af6b3a00dad68474bdad29af6b4a84dad6a57cbdad6baf6b59b156b64672bb5fbfff50400f938a06e77cbdbde220f43cd841000f352a1e13aaf2727c9c73e50925bef01e67c32e18b5deae2dbea5af7ba37719fe2783399e7fce76a22396e4900708f03dc03b300380b62c067beeb65cfbdd17550f8de1b3eedfd65bacec5ae7ef77b182f3966bbf16b5f5183543ff68c247ffbeb5f59d4fbdcfbf2f7c1108e70507807daa78876b814feac716149db0e0b55b61e0e71656b2ae2be52b5c4813d318a4d0c62c3b9f09bb5a160bd429856af91d367df84f1435e492e12ba784ae2cc237a2e384bb4952c6d7ac41745c896368cc275c90991552e797c2d1f5f048fb61cd00541e81f0ceef0965f66a68dc57651c53d993bb39c925b21426566f918ffb670d66c86e30ce7afd099ce76be336c75dc4610af98b6dc5c2bd434c8671107fa7137ee9945c7f6670f92b8d13d5531a4810a53ba166dc7c1b5348d2e99112f0bd28e4dcbb4a6f5a9a7b98e3a629cc664998fcad431d636d4a7ce511a637d234776ba8ffd59b3a341ed415ad7bad4a2f63586baa8e7626bd6937d9bddd24a0d35c07ad5d993de521c63289a579e72483e5cf2a3a2ed996917f9a885b6b69fc389e4587ddbcc85e6b692cefa9d2fb69a417f5577c6e66c6c3d235bdeeaaeb4b0f73d385b5b24dd227c75aff94df02bfadbc65185ea385d79ef8117fce1413b3894d52625a46672d7021f14c437ee3062d7bbde0d270dbe03046d8d3e7ae407ffbae35259b919719f1ce50552a5985ed5e4449fb945f4c436cb596573984744e5db06729767be6d36871c939a4434bca26a7380a39cde1f8ff3d17d5e6249533d9bfae6b8d6a3f5f204657deb603754d711f4f5b09b9d4e63b71c884d7df6b6d775846bbffa7b4a6e24abcb5d9876bfbb2e0f4d717d91bba1ecd67b0227eed0209f6b6c54593a5b45a56b79e7fddda673ba601f2ff820969dac331db68fd85e50ba67edf231cd3c3e371f6c527614f42d253daa99c945cf5b0df534553dc1643fadb4536d88f6dafc4674af1bd7578df295b721f083ef40be3b99e790d78fe4898f69098e2c8f6beb72d0cd5cd1767f97f91fb63df64d37fced73dfcfdec7fbffda4b1f7bd69f5afb5083fd3d45ff4cf43f4dfdd064bf33ddcf34f8b79ff69aa6ffd2707f2ede33cbf7b7077ee1b7770238807ed47d06f852a813750cd8800ef88010188112388183978094568016287c184868f3d373e3417d82968180234d8b76714927514c267d3aa78256c247262882b4818030f879183883ba238336188072457e6dd75577a55626b7571ac1796ee7203ed869b4544e3546108d93846fa52200d7669bb38345185076858409a7702068745fb5564096701c9482e0f64b42985655482147887488267d43088414c47844f7285e267414d52c658811cad66cebf6835d1884058283cd3681afc53782e85acbf719809883ef57838ae84f8cffd88828c558850559ab815890d858ec9187876558a96189975889b3938998f8589af889a13159a12889a4b88aa6788ac0838a230680ada834b07186b6788bd39288b3e832060614c32561c0188cc2388c32215ec88512bf488ccab88ccc9813dab51bf2c34ce1c561b7c55c29815fd035610e6613d9c813d9d88ce0088efef5142d1843dd557145556067e213d68812f8355d10f23d6a413ed0255df2455c6f7117d6f317f3188efe585de3f83e20748e48651cea681a33415e97f53f59415ded455ff4f5200e093e10393e12d93d18f98f1aa95b010960e0256005892dd3d88b5e515eb2735ef9c360ce655f11e95e0f89913a61912e3993f5553ef0b59138ff39408911485723905f439072c85d1bd68b60311697b5605fd16039b9944cb914cf288d20e91b23b98e5e2119095639ffd3945ab995cc63485e112c5389905c399664599624e13c59023f5cd64a1eb973ad96966b996870e99673c9966fa99674899776599772a9977d19976db9977e19987f9997807997b1b88b58f7888af97b8cd99851c31e7c499894899886799982799893699999899985d999a0f999a259999b599a83c999a3899a2aa28b900977fad79aae298bb0f93192799abf818b17c283d4a29bd2e269a9699a9a699bc2b99656c624b21970f221857a9531c539666fa865cfb98532944b59169df0e69cd61911ca292e2d76658c172f53b665f4ff925414479ee4e627db996443274e454786846771e8d89e379730b5199c02e16270f882da299eb3124352b686a9929e5ae89f75e89edc617dfad97cbf399c9e499a0cba4acdf99e49767c4dc19f336736e51666057a1984c7747a3465397638ff899c53d59dc6394c8788634c92a2cf361cc3749cae969c2c9a7db1e9a0e5b855389aa33abaa3bd129a36daa0aa19a475c99ab3499f8f59a44793434ed836333a69f58999155487c009a453eaa342aa971c58a50b6a9f54faa05bdaa55c6aa555aaa460c89e831665661a7c7c27641b1a333ef4776a3a6ef9a9544f43a0b5e48128f7a456fa8160daa762eaa53f2aa181faa57f1aa6847aa8839aa89c49a448ffaa2f43548890aa5aa516a9946a5a51544c53a79dbcc971b3869b1247760d37a544e8761b3297a3da833b89978084a799511a433a7eb8092e9816ab78f3105e647874289df3892ec9b6a91bd7a9b8f8a913676e8917464b98718213abc07a8bc27aa0f179a1babaabcde2939d79aa6757aa7869ad6687ad5c06a32ff4aa9f44abcb6a8bcdfa87996a74e20a6ce9fa233c9a2cf1e670c1aaaecaeaad326a1a534aab24d296f8ea1285694c62649047daa82eca87bc26b0c0316d76e996318a73b7e6977cd6a4ea86b07138607ce672d42a9affaab068e5a7887aa586aaa85a0ab280eab19729b1b896a02f03aef899742ba39e23fa7c9068b2189aa67878aec5ff716ed127a57b3a83f4da86ef2aa14bd7826a0366e8a8b130d8b3c72a66175b99b411b2245ba81c2bb21ffbb41debb428d8ae49a4b206ab816554a95efbb560eb80973a4a363b48fb7ab6a367ab602570a2eaab68cbaca9daad6ae8aca1b6a8b0fab678bb23a986704a255115279f0a8aacda92b7842bab0ea1398c36b4c59a7c06cab0f05ab8785bae21547335c770efdab6905bb8dc7a38485bb3761bae999bb7928ba23f9baca1fbb60883b5c852ba837bba67fb9a0b65af0ceaba9aabaf98fab99dbbb50391bb755bb0badb581d8aa68749a283f5bbbdf76fb8c6746ad6540b5bbc54ab1b563bb2d13bb5d31bb5cf7bbdf78abc71c818f7b1b8d4a6a9b8ff9b192bc8aa3206b17f26737d67acacc6b84a26b8dec997e966be28c6bb18a7b481c76895fba14c9b80f44bbcbcaaa82c589e0bc74a305bbd507bc0552bbd0a4cbd0b7c99aaab2c5adbb0db2bb47e5bb4413763c64bbafd9bc19ec2a81c5c2b7a5a98613bc2245cc2ae15b7d66bc0094c9c774bbbfb0abbf0617f2e0c76303c82bd3ac32fbcc11e25bb5caaad38bcad288cc0529bc27a29c33ffcab3a3c85377cc49e9ac431d8c24c4cae4e3c453c7c993e1cc59c1ac42b4cc40cccc2a08bc56758c39f331c60eca9cc19b01f5ca2552cc4d8dbc06cacc243fcc66ebcc572dcc55c7cc71c96c60725c67adc296e746efbb272e26b42f27b816bfc99e36bc775ff8cc76c99c84f28bc80c7c8714cc7943cc971bca6136a2eb9062689cba7d04775982c8687c7b2eab9b16b08737f9cabecdb29f212b45f466884cc86a07c264eeb288a5cc96d2c1a8bb7c8bc8ccb709ccb923c411edcc796f2a8265c6c9bf75ac91ca9538c31466c4cf28786f8c775cdacc64b6b99571c7f5abc15aba738d92c279bdbcb960ccce2fcb4cf5c4cd1bc52d3cc4fd56ca45f4c6be92c21f11c277ccc8b501c6bf3acb7e6577bedcc2f21dc96df3c7fdbdc93b3976801bd3303fdcb0a3dc7e33ca6f77c7eeb3c5011dd79a7f7d0a396cf0f82d1b2d6cffb72cea3a4d12432d18752cf2df3cf96f97089266b8af32dbeccd0e4dcd28a3cccc44c2932ff3dd3d344d2369d2626bd99a7b1d0b7ac113e1dcc415dce430dd3ac44a61e8a74853cc8822cb0c6b7ca7df2bd05b2d4de87d4f1529e5a08466dba1f2be7828db9d358ca65398b38f33363450dc06f5ab442edd267fdd20dcdd66e1cca13db775d4dca02528259ad98359dd368b2d77cbd2560fdd36e3dd86d5dd8702dd8868dd887eda77efdd77c986cc78ccc0c13d970c6d18e6ad1f927d2e5c751817d38070dcd03fdd99514ce464dd48b6dda89f9b810bdcf995dd1ef8ccf9abd7e960d414bec6b203d4938cd40870cd06e8bcea1dddb9444da6fadd8c4bdd65e5cdbf01cdbdaecdac80ddbac6d69b9dd311e2d4ab7ad46d15da3248bd22b2d6ca5ddddc3ff6ddc15e8d89189c6e2ed66e45dde204ccba7eddd84bddedf8ddae00ddff24dc78d8dde6a77ddf66daef89ddf1a7c9f65fcdffb16defcdd33f53de02bbadf061ebbd7ccd3f692d8f1cdde0e3edfefcd4143a5bdd15abe739be0022ea88f4ca7196ee11abee174cbc92dbbbe0b177dde754e3ae42a5bedd89d9db0696dd7436b64342bbc698d328dd7dec52de13afee0137ec91b9866770a85c9cbbd2cdbd54189828a4be3035ee0216ec34f4ee0eabde310eede3dcee3115ee554fee3e11be532834d947dcc7973bb4c48e6fa8d55c08dc47be887f7b9b602f2e2069de61027dc082e354ce8e6574ea8602ee7287d8575e7865e47d59e8be6689b86dee9c9bdffbbbb34168216dc278d7be084feba7e7ee847a6e4499bba70784b7288abca6b542d52864e2bda599cd281d7b228eeb977cee8a69ebe694aa0d1ca22591e987b5ee8930ee29f9ce3d7a9e8aa7eeb613860e3e44977c870b4bee67fde87c51eecb026e9c41ee8c6ceeca03eb2844bea04abeb6c9ee781eae4f386e7b36d87679e530f6c2c65fdedee84ec5eaedb0b6ee5b16eedea9eeeec8eeeee1ed3e75dee801deff2fed8f55ed2f47eefccde3a85c8ef12e8ef611ef0023ff09fb558a6518aa8e18909cf894f6ef00adf890c7f1a0f9fe089218a9388f0a012f1034e591c86f1a331f1194f8914ff8aa9edf1216ff29f01f2e28d8aa978f0a3c81a2acfd72c2bbf2116cf8a95a8f132ff8a3adff24c81461f517b3f0fe0f8da7cdbaeef3e25ee489ff44abff44cff440101003b}}\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 To give life to the form, we'll need to add some functionality to the user interface. To do so, open the code editing \plain\f1\fs22\cf0 window for the main form, and modify the code to match \plain\f1\fs22\cf0\b Listing A\plain\f1\fs22\cf0 . However, you might just \plain\f1\fs22\cf0\uldb open up the sample \plain\f1\fs22\cf0\uldb application\plain\f1\fs22\cf0\v http://www.delphicorner.f9.co.uk/files/filerec.zip\plain\f1\fs22\cf0  in Delphi, compile it, then run it. It'll save you time.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Listing A: MAIN.PAS\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s2{\brdrl\brdrs\brdrw0\brsp40\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b unit\plain\f6\fs20\cf0  Main;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b interface\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b uses\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Windows, Messages, SysUtils, Classes,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Graphics, Controls, Forms, Dialogs,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   StdCtrls, ComCtrls, ExtCtrls;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf11\i \{Address Record\}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b type\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   TAddressRec = \plain\f6\fs20\cf0\b record\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     First: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 20\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Last: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 20\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Add1: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 40\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Add2: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 40\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     City: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 30\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     ST: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 2\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Zip: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 10\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Phone: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 20\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Fax: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 20\plain\f6\fs20\cf0 ];\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf11\i \{Direction Type\}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b type\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   TRecMove = (recFirst, recLast, recNext, recPrev);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b type\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   TForm1 = \plain\f6\fs20\cf0\b class\plain\f6\fs20\cf0 (TForm)\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit1: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit2: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit3: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit4: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit5: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit6: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit7: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label1: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label2: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label3: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label4: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label5: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label6: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label7: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnNew: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnFirst: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnLast: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnNext: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnPrev: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnDelete: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnUpdate: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit8: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label8: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit9: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label9: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     StatusBar1: TStatusBar;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Label10: TLabel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit10: TEdit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnFind: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnFindNext: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Bevel1: TBevel;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     btnInsert: TButton;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  FormCreate(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnNewClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnFirstClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnLastClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnNextClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnPrevClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  FormClose(Sender: TObject;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf0\b var\plain\f6\fs20\cf0  Action: TCloseAction);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       btnDeleteClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       btnUpdateClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  btnFindClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       btnFindNextClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       btnInsertClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b private\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  SetRecVals;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       EnableButtons(EnableIt: Boolean);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       MoveToRec(Direction: TRecMove);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  LocateRec(Value: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       FromBOF: Boolean);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  CreateNewRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  InsertRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  UpdateRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  DeleteRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b public\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf11\i \{ Public declarations \}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     NewRec: Boolean;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Form1: TForm1;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   AddrFile: \plain\f6\fs20\cf0\b file\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b of\plain\f6\fs20\cf0  TAddressRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   AddrRec: TAddressRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b const\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MAXRECS = \plain\f6\fs20\cf11 2000\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b implementation\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf11\i \{$R *.DFM\}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.FormCreate(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   AssignFile(AddrFile, \plain\f6\fs20\cf11 'Address.DAT');\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  FileExists(\plain\f6\fs20\cf11 'Address.DAT') then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         Reset(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FileSize(AddrFile) > \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0           Seek(AddrFile, \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0           ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0           NewRec := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf0\b end\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Rewrite(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     NewRec := True;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnNew.Enabled := True;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnInsert.Enabled := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnUpdate.Caption := \plain\f6\fs20\cf11 '&Update';\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.FormClose(Sender: TObject;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b var\plain\f6\fs20\cf0  Action: TCloseAction);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   CloseFile(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.SetRecVals;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b with\plain\f6\fs20\cf0  AddrRec \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     First := Edit1.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Last := Edit2.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Add1 := Edit3.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Add2 := Edit4.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     City := Edit5.text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     ST := Edit6.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Zip := Edit7.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Phone := Edit8.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Fax := Edit9.Text;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Read(AddrFile, AddrRec);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b with\plain\f6\fs20\cf0  AddrRec \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit1.Text := First;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit2.Text := Last;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit3.Text := Add1;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit4.Text := Add2;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit5.text := City;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit6.Text := ST;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit7.Text := Zip;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit8.Text := Phone;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Edit9.Text := Fax;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, FilePos(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   TForm1.EnableButtons(EnableIt: Boolean);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnNew.Enabled := EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnFirst.Enabled := EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnPrev.Enabled := EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnNext.Enabled := EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnLast.Enabled := EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnInsert.Enabled := \plain\f6\fs20\cf0\b not\plain\f6\fs20\cf0  EnableIt;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.CreateNewRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   I: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  NewRec \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     LockWindowUpdate(Handle);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b for\plain\f6\fs20\cf0  I := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b to\plain\f6\fs20\cf0  ComponentCount - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (Components[I] \plain\f6\fs20\cf0\b is\plain\f6\fs20\cf0  TEdit) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       TEdit(Components[I]).Clear;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   LockWindowUpdate(\plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   NewRec := True;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   EnableButtons(False);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnUpdate.Caption := \plain\f6\fs20\cf11 '&Post to end';\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.InsertRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     numRecs,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     I: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   RecBuf: \plain\f6\fs20\cf0\b array\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ..MAXRECS] \plain\f6\fs20\cf0\b of\plain\f6\fs20\cf0  TAddressRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   SetRecVals;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos := FilePos(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   numRecs := FileSize(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  FilePos(AddrFile) > \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     I := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b while\plain\f6\fs20\cf0  FilePos(AddrFile) < curPos \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Read(AddrFile, RecBuf[I]);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Inc(I);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   RecBuf[curPos] := AddrRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   I := curPos + \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b while\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b not\plain\f6\fs20\cf0  EOF(AddrFile) \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Read(AddrFile, RecBuf[I]);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Inc(I);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   I := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b while\plain\f6\fs20\cf0  (I <= numRecs) \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Write(AddrFile, RecBuf[I]);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Inc(I);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, curPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnUpdate.Caption := \plain\f6\fs20\cf11 '&Update';\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     EnableButtons(True);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.UpdateRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos := FilePos(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   SetRecVals;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  NewRec \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, FileSize(AddrFile));\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     curPos := FileSize(AddrFile) + \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Write(AddrFile, AddrRec);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FileSize(AddrFile) > \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, curPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     NewRec := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   EnableButtons(True);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   btnUpdate.Caption := \plain\f6\fs20\cf11 '&Update';\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.DeleteRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     numRecs,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     I: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   RecBuf: \plain\f6\fs20\cf0\b array\plain\f6\fs20\cf0 [\plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ..MAXRECS] \plain\f6\fs20\cf0\b of\plain\f6\fs20\cf0  TAddressRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  MessageDlg(\plain\f6\fs20\cf11 'Are you sure you want to '\plain\f6\fs20\cf0  +\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf11 \tab \tab 'delete this record?'\plain\f6\fs20\cf0 ,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     mtConfirmation, [mbYes, mbNo], \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ) =\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     mrNo \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Exit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  NewRec \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     NewRec := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     EnableButtons(True);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Exit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos := FilePos(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   numRecs := FileSize(AddrFile) - curPos - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FilePos(AddrFile) <\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     (FileSize(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 )) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, FilePos(AddrFile) + \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 );\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     I := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b while\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b not\plain\f6\fs20\cf0  EOF(AddrFile) \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Read(AddrFile, RecBuf[I]);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Inc(I);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, curPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Truncate(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b for\plain\f6\fs20\cf0  I := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b to\plain\f6\fs20\cf0  numRecs - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Write(AddrFile, RecBuf[I]);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Truncate(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Dec(curPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, curPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnDeleteClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   DeleteRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.MoveToRec(Direction: TRecMove);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   pos: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   EnableButtons(True);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   pos := FilePos(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FileSize(AddrFile) = \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Exit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b case\plain\f6\fs20\cf0  Direction \plain\f6\fs20\cf0\b of\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     recFirst: pos := \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     recLast: pos :=\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       FileSize(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     recNext: \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FilePos(AddrFile) <\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         (FileSize(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 )) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         pos := FilePos(AddrFile) + \plain\f6\fs20\cf11 1\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         Exit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     recPrev: \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (FilePos(AddrFile) > \plain\f6\fs20\cf11 0\plain\f6\fs20\cf0 ) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         pos := FilePos(AddrFile) - \plain\f6\fs20\cf11 1\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0         Exit;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Seek(AddrFile, pos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   NewRec := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.LocateRec(Value: \plain\f6\fs20\cf0\b string\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   FromBOF: Boolean);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b var\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos,\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     SearchPos: Integer;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Found: Boolean;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   curPos := FilePos(AddrFile);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  FromBOF \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     SearchPos := \plain\f6\fs20\cf11 0\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b else\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     SearchPos := curPos + \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   Found := False;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b while\plain\f6\fs20\cf0  (SearchPos <=\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     (FileSize(AddrFile) - \plain\f6\fs20\cf11 1\plain\f6\fs20\cf0 )) \plain\f6\fs20\cf0\b and\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     (\plain\f6\fs20\cf0\b not\plain\f6\fs20\cf0  Found) \plain\f6\fs20\cf0\b do\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Seek(AddrFile, SearchPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Read(AddrFile, AddrRec);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (AddrRec.Last = Value) \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Found := True;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       MessageBeep(MB_OK);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       Seek(AddrFile, SearchPos);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       \plain\f6\fs20\cf11\i \{Read the record in to the fields\}\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       ReadRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     Inc(SearchPos)\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  \plain\f6\fs20\cf0\b not\plain\f6\fs20\cf0  Found \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     ShowMessage(\plain\f6\fs20\cf11 'Last Name not found in file');\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnNewClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   CreateNewRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnUpdateClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   UpdateRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnFirstClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MoveToRec(recFirst);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnLastClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MoveToRec(recLast);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnNextClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MoveToRec(recNext);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnPrevClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   MoveToRec(recPrev);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnFindClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  (Edit10.Text <> \plain\f6\fs20\cf11 '') then begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     \plain\f6\fs20\cf0\b if\plain\f6\fs20\cf0  NewRec \plain\f6\fs20\cf0\b then\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0       btnUpdateClick(Self);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0     LocateRec(Edit10.Text, True);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnFindNextClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   LocateRec(Edit10.Text, False);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b procedure\plain\f6\fs20\cf0  TForm1.btnInsertClick(Sender: TObject);\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b begin\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0   InsertRec;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 ;\par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0 \par
\plain\s2\shading0\cbpat16\cfpat12\ql\li0\fi0\ri0\sb0\sl\sa0 \f6\fs20\cf0\b end\plain\f6\fs20\cf0 .\par
}}\pard \plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 When you finish entering the code, you'll need to assign event handlers to the appropriate components. Table B \plain\f1\fs22\cf0 contains a list of the component names, their captions, and the corresponding event handlers.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\b Table B\plain\f1\fs22\cf0 : Event handler assignments\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
{\*\wptable}{\pard\trowd\trgaph0\trleft0\clbrdrt\brdrs\clbrdrb\brdrs\clbrdrl\brdrs\clbrdrr\brdrs\brdrw0\cellx10772\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\cellx42\intbl{\ql\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Form1: TForm1\line \plain\f1\fs22\cf0 Caption = 'Simple Address'\line \plain\f1\fs22\cf0 OnClose = FormClose\line \plain\f1\fs22\cf0 OnCreate = FormCreate\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnNew: TButton\line \plain\f1\fs22\cf0 Caption = '&New'\line \plain\f1\fs22\cf0 OnClick = btnNewClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnFirst: TButton\line \plain\f1\fs22\cf0 Caption = '&First'\line \plain\f1\fs22\cf0 OnClick = btnFirstClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnLast: TButton\line \plain\f1\fs22\cf0 Caption = '&Last'\line \plain\f1\fs22\cf0 OnClick = btnLastClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnNext: TButton\line \plain\f1\fs22\cf0 Caption = 'N&ext'\line \plain\f1\fs22\cf0 OnClick = btnNextClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnPrev: TButton\line \plain\f1\fs22\cf0 Caption = 'Pre&vious'\line \plain\f1\fs22\cf0 OnClick = btnPrevClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnDelete: TButton\line \plain\f1\fs22\cf0 Caption = '&Delete'\line \plain\f1\fs22\cf0 OnClick = btnDeleteClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnUpdate: TButton\line \plain\f1\fs22\cf0 Caption = '&Post'\line \plain\f1\fs22\cf0 OnClick = btnUpdateClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnFind: TButton\line \plain\f1\fs22\cf0 Caption = 'Find'\line \plain\f1\fs22\cf0 OnClick = btnFindClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnFindNext: TButton\line \plain\f1\fs22\cf0 Caption = 'Find Next'\line \plain\f1\fs22\cf0 OnClick = btnFindNextClick\line \plain\f1\fs22\cf0 \line \plain\f1\fs22\cf0 btnInsert: TButton\line \plain\f1\fs22\cf0 Caption = '&Insert'\line \plain\f1\fs22\cf0 OnClick = btnInsertClick\cell}\row
}\pard{\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 After you've entered all the event handler assignments, build and test the application. Now you have a functional \plain\f1\fs22\cf0 address book application that doesn't require any traditional database overhead.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\plain\s1\qj\li0\fi0\ri0\sb0\sl\sa0 \f34\fs32\cf0\b Why bother with files of records?\par
\plain\s0\qj\li0\fi0\ri0\sb0\sl\sa0 \f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Whew! We're almost at the end...\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Many of you, especially the more experienced developers, are probably wondering why you should bother with the \plain\f1\fs22\cf0 process we present in the accompanying article. The main reason is one I mentioned in that article: Sometimes the \plain\f1\fs22\cf0 BDE is overkill for a simple database application. Not only that, there are also distribution concerns.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Application EXEs compiled for manipulating files of records are relatively small compared to those that use Delphi \plain\f1\fs22\cf0 database VCL components. For instance, the accompanying article's sample application compiles to a mere 195K; \plain\f1\fs22\cf0 on the other hand, a simple database application that has a TTable, a TDataSource, and a TDBGrid as the only \plain\f1\fs22\cf0 components on its main and only form compiles to about 420K--more than twice as much disk space. Furthermore, \plain\f1\fs22\cf0 you must install the BDE along with the latter application if you're going to distribute it to other computers. Three \plain\f1\fs22\cf0 disks as compared to one? I'll take the latter.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 Someone played devil's advocate with me just before I wrote this article and asked, "\plain\f1\fs22\cf0\b What advantages does an \plain\f1\fs22\cf0\b application built around a file of records have over one that manipulates a memory-mapped file?\plain\f1\fs22\cf0 " Admittedly, \plain\f1\fs22\cf0 I didn't think about this comparison when I began writing the article, but after considering what it takes to create a \plain\f1\fs22\cf0 file mapping, I responded with a single word: "Simplicity." Creating a map view of a file isn't that difficult, but it \plain\f1\fs22\cf0 does require going to the Windows API. For many people, that foray may not be an alternative they want to consider, \plain\f1\fs22\cf0 especially if the task is something simple.\par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0 \par
\qj\li0\fi0\ri0\sb0\sl\sa0 \plain\f1\fs22\cf0\uldb There's a sample application to accompany this article\plain\f1\fs22\cf0\v http://www.delphicorner.f9.co.uk/files/filerec.zip}}
}