Home

News

Articles

Forums / Groups

Mozilla-Delphi Project

Pascal Newsletter
Issue 55
Back Issues

Software

Links

Search

Vote For Us:
Irongut's Delphi Pages
Pascal Newsletter

Contact Details

Legal Stuff

News Archive
Pascal Newsletter Issue 55
Pascal Newsletter #55 - 30-JUNE-2005

Contents

1. A Few Words From the Editors
2. How to Extract Version Information Using the Windows API
3. Convert BMP to *Any Format* (.NET)
4. Tidy Up Your Temporary Files
5. Universal Embedding of Files in Delphi Units
6. Forums / Mailing Lists
7. Delphi on the Net
   - Components, Libraries and Utilities
     - Shareware / Commercial
     - Freeware
     - Borland Product Updates
   - Articles, Tips and Tricks
   - Tutorials and Training
   - News
   - Other / Misc Sites

________________________________________________________________________


1. A Few Words From the Editors

I'd like to thank the authors who contributed articles to this issue:
Peter Johnson, Eber Irigoyen, John Lavelle and Max Kleiner. And, I'm
pleased to award the following prizes:

* John Lavelle - 'Tidy Up Your Temporary Files'
  KnowledgeBase Expedition 4.2 - by Delphinium Software ($49.35)
  KnowledgeBASE Expedition features a highly searchable and expandable
  information tree viewed in outline or audited within a built-in
  wordprocessor. Includes a database for stored references.
  http://www.download.com/3000-2064_4-10239072.html

* Eber Irigoyen - 'Convert BMP to *Any Format* (.NET)'
  YAPI Professional - by Owen Mooney ($95)
  Offers the easiest and yet powerful printing from Delphi. It provides:
  WYSIWYG setup, print preview, Non database, Database, text, Grids,
  tabs, bitmaps, TCanvas operation, precise positioning or free flow
  positioning - all using simple "writeln" statements.
  http://free.hostdepartment.com/o/owenmooney/

Special thanks to Delphinium Software and Owen Mooney for donating the
prizes for this and future issues. Issue #56 will be published in August
if I get enough articles so if you've got an idea, start writing!

Now, on with the code...

Regards,

Dave Murray
pascal-newsletter-owner@yahoogroups.com

________________________________________________________________________

Help & Manual 3.50 by EC Software - Shareware ($ 299) - Help & Manual is
a  WYSIWYG help authoring tool  that will aid you in  creating  standard
WinHelp files (.HLP), Adobe PDF files, HTML pages  and the new HTML HELP
(.CHM) files introduced in Windows 98, as well as other file formats and
printed documentation,  everything from a single source. This is a must-
have for any software developer. http://www.helpandmanual.com/hmpage.htm
________________________________________________________________________


2. How to Extract Version Information Using the Windows API

   By Peter Johnson, Copyright (c) 2005
      <delphidabbler at tiscali dot co dot uk>
      http://www.delphidabbler.com/


Introduction
============

The Windows API provides a method to extract version information from an
executable file. The API is rather arcane and some knowledge of how
version information is stored in an executable file is helpful.

This article starts with a brief overview of how version information is
laid out in a file. It then goes on to develop some code that tests
whether version information is present and extracts it if so. We then
wrap the code up in a class before finally looking at some of the
limitations of the approach we have taken.


Version Information Overview
============================

Version information is stored in an executable file's resources. The
binary format of this data is complex and is not described here.
Conceptually though, version information contains a record that provides
a machine-readable binary description of a file (fixed file information)
and one or more string tables that provide human-readable information.
String tables can be localised - so there can be a string table for each
supported language or code page. Because of this, version information
also contains a table of supported languages / code pages (the
translation table) that effectively provides an index into the string
tables.

Although version information supports multiple languages it is rare to
find executables that take advantage of this - version information
usually contains only one string table. Unlike most of the code
available on the net ours will handle multiple string tables.

Reflecting the organisation discussed above, version information is
structured in three main parts:

  * Fixed file information

    This is a data structure that contains binary information about the
    executable file. Windows declares this structure as VS_FIXEDFILEINFO
    and the Delphi equivalent is TVSFixedFileInfo, defined as follows:

    type
      tagVS_FIXEDFILEINFO = packed record
        dwSignature: DWORD;        // always $feef04bd
        dwStrucVersion: DWORD;     // version of structure
        dwFileVersionMS: DWORD;    // most significant file version
        dwFileVersionLS: DWORD;    // least significant file version
        dwProductVersionMS: DWORD; // most significant product version
        dwProductVersionLS: DWORD; // last significant product version
        dwFileFlagsMask: DWORD;    // masks valid flags in dwFileFlags
        dwFileFlags: DWORD;        // bit mask of attributes of file
        dwFileOS: DWORD;           // flags describing target OS
        dwFileType: DWORD;         // flag describing type of file
        dwFileSubtype: DWORD;      // sub type for file: keyboard driver
        dwFileDateMS: DWORD;       // most significant part of file date
        dwFileDateLS: DWORD;       // least significant part of date
      end;
      TVSFixedFileInfo = tagVS_FIXEDFILEINFO;

    The fields of this record are described in depth in the Windows help
    file so we won't discuss further here.

  * Variable file information

    According to the Windows documentation this section can be
    user-defined. However, in practise it always contains a table of
    "translation" information. Each entry in the table is a pair of
    language and character set identifiers that together provide a key
    used to specify a string table. We can define an entry in this table
    with the following record (not defined by Windows):

    type
      TTransRec = packed record
        Lang,           // language code
        CharSet: Word;  // character set (code page)
      end;

  * String file information

    This section stores a string table for each "translation" listed in
    the variable file information section. The entries in string tables
    are name / value pairs - i.e. the string values are accessed by
    specifying a string name. Windows defines several standard names:

          o Comments
          o CompanyName
          o FileDescription
          o FileVersion
          o InternalName
          o LegalCopyright
          o LegalTrademarks
          o OriginalFilename
          o PrivateBuild
          o ProductName
          o ProductVersion
          o SpecialBuild

    The intended purpose and restrictions on use of these names are set
    out in the Windows API help file under the VERSIONINFO resource
    topic. User defined names are also permitted.

These different sections of the resource are accessed using an
addressing system that is similar to a file path. The "paths" are:

  * "\" - i.e. the "root" path
    Accesses fixed file information.
  * "\VarFileInfo\Translation"
    Accesses the "translation" table. The table is a sequence of
    TTransRec records.
  * "\StringFileInfo\<translation-code>\<string-name>"
    Accesses a named entry in a given string table. <translation-code>
    is made up of the hexadecimal representation of the translation's
    language code and character set code. Unsurprisngly <string-name> is
    the name of the desired string value. For example to access the
    "ProductName" string in the string table associated with translation
    "040904E4" the "path" is "\StringFileInfo\040904E4\ProductName".

This all looks rather horrendous - and if you write code to access the
raw version information binary it is. However the Windows API provides
three functions that assist in extracting the code. In the next section
we'll review the API calls and write some Delphi wrappers to make them
easier to use before finally developing our version information class.


Writing The Code
================

Windows API Functions
---------------------

Windows provides the following functions to use to access version
information.

  * GetFileVersionInfoSize

    function GetFileVersionInfoSize(lptstrFilename: PChar;
      var lpdwHandle: DWORD): DWORD; stdcall;

    This function returns the size of the given executable file's
    version information. It returns 0 if there is no version information
    present. We have to pass a dummy variable as lpdwHandle - the
    function just sets it to 0!

  * GetFileVersionInfo

    function GetFileVersionInfo(lptstrFilename: PChar;
      dwHandle, dwLen: DWORD; lpData: Pointer): BOOL; stdcall;

    Once we know the size of the version information we have to create a
    buffer the same size and then call this function to copy the version
    information from the executable file into the buffer. We pass the
    name of the file, a dummy 0 value to dwHandle, followed by the size
    of the buffer and the buffer pointer itself. The function returns
    true on success and false on failure.

  * VerQueryValue

    function VerQueryValue(pBlock: Pointer; lpSubBlock: PChar;
      var lplpBuffer: Pointer; var puLen: UINT): BOOL; stdcall;

    This function is used to read data from the version information
    buffer we filled using GetFileVersionInfo. We pass the buffer as the
    first parameter. The next parameter takes a pointer to the "path"
    that specifies the information we need (as described above). The
    function sets the pointer variable passed as lplpBuffer to point to
    the requested data. puLen is set to the length of the data. The
    function returns true on success and false on failure. If the
    function fails lplpBuffer has an indeterminate value and can cause a
    GPF if read.

A full description of these functions can be read in the Windows API
help. As can be seen the calls we need to make are complex and require a
lot of pointer manipulation. In the next section we hide some of this
complexity in wrapper routines.

Delphi Wrapper Routines
-----------------------

Let us now define some wrapper functions that (a) hide the API routines
and (b) give easy access to the fixed file information, string values
and translation table.

We will create five routines:

1. GetVerInfoSize - a thin wrapper round the GetFileVersionInfoSize API
   function

2. GetVerInfo - a thin wrapper round the GetFileVersionInfo API function

3. GetFFI - gets the fixed file information from the version information
   buffer using VerQueryValue

4. GetTransTable - uses VerQueryValue to get and return the translation
   table as a dynamic array of TTransRec records

5. GetVerInfoStr - returns the value of a string table entry using
   VerQueryValue

Here is a description of the five routines:

  * GetVerInfoSize

      function GetVerInfoSize(const FileName: string): Integer;
      var
        Dummy: DWORD; // Dummy handle parameter
      begin
        Result := GetFileVersionInfoSize(PChar(FileName), Dummy);
      end;

    This function is a thin wrapper round the GetFileVersionInfoSize API
    routine - it simply prevents us from having to provide the dummy
    parameter that routine requires.

  * GetVerInfo

      procedure GetVerInfo(const FileName: string; const Size: Integer;
        const Buffer: Pointer);
      begin
        if not GetFileVersionInfo(PChar(FileName), 0, Size, Buffer) then
          raise Exception.Create('Can''t load version information');
      end;

    This is a thin wrapper that calls the GetFileVersionInfo API
    function and raises an exception if the call fails.

  * GetFFI

      function GetFFI(const Buffer: Pointer): TVSFixedFileInfo;
      var
        Size: DWORD;  // Size of fixed file info read
        Ptr: Pointer; // Pointer to FFI data
      begin
        // Read the fixed file info
        if not VerQueryValue(Buffer, '\', Ptr, Size) then
          raise Exception.Create('Can''t read fixed file information');
        // Check that data read is correct size
        if Size <> SizeOf(TVSFixedFileInfo) then
          raise Exception.Create('Fixed file information record wrong
            size');
        Result := PVSFixedFileInfo(Ptr)^;
      end;

    GetFFI gets fixed file information from the version information
    data. We call VerQueryValue with a "path" of "\". and then check if
    the call succeeds and that the returned data is the correct size.

  * GetTransTable

      type
        TTransRec = packed record
          Lang,                             // language code
          CharSet: Word;                    // character set (code page)
        end;
        PTransRec = ^TTransRec;             // pointer to TTransRec

        TTransRecArray = array of TTransRec; // translation table

      function GetTransTable(const Buffer: Pointer): TTransRecArray;
      var
        TransRec: PTransRec;  // pointer to a translation record
        Size: DWORD;          // size of data read
        RecCount: Integer;    // number of translation records
        Idx: Integer;         // loops thru translation records
      begin
        // Read translation data
        VerQueryValue(
          Buffer, '\VarFileInfo\Translation', Pointer(TransRec), Size
        );
        // Get record count and set length of array
        RecCount := Size div SizeOf(TTransRec);
        SetLength(Result, RecCount);
        // Loop thru table storing records in array
        for Idx := 0 to Pred(RecCount) do
        begin
          Result[Idx] := TransRec^;
          Inc(TransRec);
        end;
      end;

    This routine fetches the translation table from the version
    information. It gets the raw data using VarFileInfo then calculates
    the number of translation records by dividing the size of the raw
    data by the size of a translation record. We then size the dynamic
    array appropriately and copy each record into the array.

    We also need to define the TTransRec, PTransRec and TTransRecArray
    types required by the routine.

  * GetVerInfoStr

      function GetVerInfoStr(const Buffer: Pointer;
        const Trans, StrName: string): string;
      var
        Value: PChar;   // the string value data
        Dummy: DWORD;   // size of value data (unused)
        Path: string;   // "path" to string value
      begin
        // Build "path"  from translation and string name
        Path := '\StringFileInfo\' + Trans + '\' + StrName;
        // Read the string: return '' if string doesn't exist
        if VerQueryValue(Buffer, PChar(Path), Pointer(Data), Dummy) then
          Result := Data
        else
          Result := '';
      end;

    This function returns the value of given string from the string
    table associated with a given translation. We build the "path"
    needed to access the string value and use VerQueryValue to get the
    string value. If the string exists we return the data, cast to a
    string. Otherwise we return the empty string.

The demo program accompanying this article shows how to use these
routines. The next step is to encapsulate the whole process in a class.


Object Oriented Solution
========================

The class we will develop is rather simple but has all the needed
functionality. It can detect whether a file contains version information
and can extract fixed file information, the translation table and
strings from one or more string table. Here's the class declaration:

  type
    TVerInfo = class(TObject)
    private
      fFixedFileInfo: TVSFixedFileInfo;// fixed file info record
      fTransTable: TTransRecArray;     // translation table
      fHasVerInfo: Boolean;            // whether file contains ver info
      fVerInfo: Pointer;               // buffer storing ver info
      function GetString(const Trans, Name: string): string;
      function GetTranslation(Idx: Integer): string;
      function GetTranslationCount: Integer;
    public
      constructor Create(const FileName: string);
      destructor Destroy; override;
      property HasVerInfo: Boolean read fHasVerInfo;
      property FixedFileInfo: TVSFixedFileInfo read fFixedFileInfo;
      property Translations[Idx: Integer]: string read GetTranslation;
      property TranslationCount: Integer read GetTranslationCount;
      property Strings[const Trans,Name: string]: string read GetString;
    end;

The constructor receives the name of the file to be examined. The
HasVerInfo property is true if the file contains version information.
The FixedFileInfo property contains a copy of the fixed file info
record. TranslationCount records the number of translations in the file
while Translations is a zero based array of string values corresponding
to the translations. These values are used to specify which string table
the Strings property uses to get a specified string value.

Internally we store the translation table in a dynamic array of
TTransRec records. Both the translation and the fixed file information
are recorded when the class is created. String file information is read
from version information as values are requested from the Strings
property.

Most of the work is done in the constructor - and we use the routines
developed above to simplify the code. So, let us start by looking at the
constructor:

  constructor TVerInfo.Create(const FileName: string);
  var
    BufSize: Integer;     // size of ver info buffer
  begin
    inherited Create;
    // Get size of buffer: no ver info if size = 0
    BufSize := GetVerInfoSize(FileName);
    fHasVerInfo := BufSize > 0;
    if fHasVerInfo then
    begin
      // Read ver info into buffer
      GetMem(fVerInfo, BufSize);
      GetVerInfo(FileName, BufSize, fVerInfo);
      // Read fixed file info and translation table
      fFixedFileInfo := GetFFI(fVerInfo);
      fTransTable := GetTransTable(fVerInfo);
    end;
  end;

We first use GetVerInfoSize to find the size of the version information
data. We set the HasVerInfo property to record if there is version
information (by checking the size of the data), and if there is none, we
skip the rest of the code.

If we do have version information we allocate a buffer to hold it then
load the version information from the file using the GetVerInfo routine.
We next use the GetFFI and GetTransTable routines to store the fixed
file information and translation table in fields.

The destructor is very simple: we just free the version info buffer:

  destructor TVerInfo.Destroy;
  begin
    // Free ver info buffer
    FreeMem(fVerInfo);
    inherited;
  end;

We'll look at the GetTranslation method next. This simple method returns
a string representation of the translation at a given index in the
table. The string representation is simply the concatenation of the
translation's language code and character set / code page code in
hexadecimal:

  function TVerInfo.GetTranslation(Idx: Integer): string;
  begin
    Assert(fHasVerInfo);
    Assert((Idx >= 0) and (Idx < fTranslationCount));
    // Return string representation of translation at given index
    Result := Format(
      '%4.4x%4.4x', [fTransTable[Idx].Lang, fTransTable[Idx].CharSet]
    );
  end;

The GetTranslationCount method simply returns the size of the dynamic
array that stores the translation table:

  function TVerInfo.GetTranslationCount: Integer;
  begin
    Result := Length(fTransTable);
  end;

This leaves just the GetString method. Most of the work is done by the
GetVerInfoStr routine. We simply check we have version information and
then return the result of calling GetVerInfoStr.

  function TVerInfo.GetString(const Trans, Name: string): string;
  begin
    Assert(fHasVerInfo);
    Result := GetVerInfoStr(fVerInfo, Trans, Name);
  end;

That's the class completed. Again this can be tested using the demo
code.


Demo Code
=========

Some demo code is included in the newsletter's source code archive. It
includes the class, types and routines presented here, along with a test
program that exercises them.

The demo program can load version information from one of four supplied
executables. One of these is the demo program itself while the others
are do-nothing console programs whose sole purpose is to have their
version information checked by the demo. The example programs contain
various different configurations of version information as follows:

  * the demo program has a single translation / string table
  * one console program has two translations / string tables
  * another has no translations (just fixed file information)
  * the last has no version information at all

For a more comprehensive solution to the problem of extracting version
information see my Version Information Component available from
http://www.delphidabbler.com/software.php?id=verinfo


Limitations
===========

While the solution presented here works well in the majority of cases,
it is by no means perfect. There are two major shortcomings:

1. While standard and non-standard string information can be accessed,
   the user must know in advance what non-standard string names are
   present in the version information. The code cannot enumerate the
   string names. This can't be done using the official API and much more
   advanced methods are required. My Version Information Spy program can
   enumerate the strings in a string table. If you need to do this
   please examine this program's source code, available from:
   http://www.delphidabbler.com/software.php?id=vis

2. Several programs contain version information that does not follow the
   Microsoft guidelines - i.e. the structure of the binary version
   information is non-standard. The API functions can fail on some of
   these programs. Again the source to Version Information Spy
   illustrates how to get round this problem by partially ignoring the
   API and parsing the binary data directly.


Summary
=======

In this article we have reviewed how Windows handles version information
and makes it accessible to programmers via the API. We noted that the
API is rather cumbersome and so went on to develop wrapper routines to
hide some of the complexity. We then wrote a class that encapsulates the
version information and provides a simpler interface for the developer.
A demo program was provided that implements and tests the code. Finally
we reviewed some of the limitations of the code.

I hope the article has been useful. If you have any comments or
suggestions please contact me via my website at:
http://www.delphidabbler.com/

__________________

Peter Johnson is a hobbyist programmer living in West Wales (UK) who
maintains the DelphiDabbler website (http://www.delphidabbler.com/)
where his articles and freeware Delphi applications & components are
published. The code for this article is also available at:
http://www.delphidabbler.com/download.php?file=article-20-demo.zip
________________________________________________________________________

         Vote for the Pascal Newsletter in The Borland Top 100!
                 http://top100borland.com/in.php?who=20
________________________________________________________________________


3. Convert BMP to *Any Format* (.NET)

   By Eber Irigoyen


Originally published on delphi3000.com as article 4219:
http://www.delphi3000.com/articles/article_4219.asp

Question / Problem / Abstract:
==============================

When working in Delphi.NET you pretty much have to re-learn the VCL,
(FCL) to accomplish every single task. There is tons of code for Win32
to convert images to / from other formats, here I show you how to
convert an Image from BMP to any format (JPG, PNG, GIF, etc) in .NET.


Answer:
=======

The FCL provides methods to do many image manipulation tricks, you just
have to know where to find them. This function will do the job for you:

procedure TWinForm3.Bmp2AnyFormat(theBmp:Bitmap; const FileName:string;
  const ImgFormat:ImageFormat);
var
  fs:FileStream;
begin
  fs:=FileStream.Create(FileName, FileMode.CreateNew);
  try try
    theBmp.Save(fs, ImgFormat);
  except
    on E:Exception do
      raise Exception.Create('Error converting image: '+E.Message);
  end finally
    fs.Close
  end
end;

The Bitmap class comes from: System.Drawing.Imaging
The FileStream comes from: System.IO

So you'll need those namespaces in your uses clause.

Now an example of use. Say you have a PictureBox with a .BMP in it on
your form, and you wanted to save that as a jpeg...

You need some code to load a bmp at runtime:

procedure TWinForm3.TWinForm3_Load(sender: System.Object;
  e: System.EventArgs);
begin
  PictureBox1.Image:=Image.FromFile('c:\SomeFile.bmp');
end;

Then a button to convert the image (to JPEG) using the function:

procedure TWinForm3.Button1_Click(sender: System.Object;
  e: System.EventArgs);
begin
  Bmp2AnyFormat(Bitmap(PictureBox1.Image),'f:\new.jpg',ImageFormat.Jpeg)
end;

To get any image format you want, you can use

ImageFormat.Tiff
ImageFormat.Gif
ImageFormat.Png
ImageFormat.Jpeg
etc...

That's it, as you can see, is really easy. The hard part is to find
which class does what.

________________________________________________________________________

  InstallAWARE 2005 - by InstallAWARE Software Corporation ($69-$899)
What sets InstallAWARE apart from the competition is how it goes about
building an MSI. The graphical choices such as adding files and registry
entries are provided as most tools offer. However, when you switch to
the "script view" you do not see a list of sequences and actions, but an
easy to read (and manipulate) script that spells out each action to be
taken by the MSI and under what condition. When everything is just as
you wish, InstallAWARE builds a fully compliant Windows Installer setup
requiring no scripting runtimes or distributable.
   Special limited offer: 33% off all editions, Studio only $559.95!
  Order any cross-grade edition for a 33% discount on purchase price.
          >>>>    http://www.installaware.com/buy.asp    <<<<
________________________________________________________________________


4. Tidy up your Temporary Files

   By John Lavelle
      <john at jql dot co dot uk>
      http://www.jql.co.uk/


Originally published on delphi3000.com as article 4315:
http://www.delphi3000.com/articles/article_4315.asp

Question / Problem / Abstract:
==============================

Don't you just hate it when programs leave Temporary Files all over the
place and don't clean up after themselves? Here's a class that will
create unique Temporary Files in your temporary directory and clean up
after itself.

Answer:
=======

Introduction
------------

Every so often there is a requirement to store information in Temporary
Files either because there is an automatic backup feature in your
program or because of some processing on the file. In virtually all
cases you want your program to delete the temporary file when it closes
and/or offer the user the chance to save their work. If some other
program crashes the computer, you also need to be able to offer the user
a chance to recover their work. With all this in mind I wrote a small
class to look after my Temporary Files.

The class needed to do the following:
- Find the user's temporary directory
- Create a unique temporary file
- Store the name of the temporary file in case of a system crash
- Delete the temporary file either when the program had finished with it
  or when the program terminated


A Little History
----------------

From the early days of DOS, environment variables have been available
and one of the most common ones was the TMP, or TEMP, environment
variable. Until Windows 95 came along, this variable had to be set in
DOS usually in the AUTOEXEC.BAT file but it could also be changed on the
command line using the SET command (SET TEMP=C:\TEMP). If the TEMP
variable was not set then it usually defaulted to C:\. With the advent
of Windows 98, Microsoft changed the default value of the TEMP and TMP
environment variable to C:\WINDOWS\TEMP, but you are still able to alter
the location of the TEMP directory. If you are using profiles, then the
location of the TEMP directory could be in your profile directory or, on
rare occasions, on a network drive.

Thankfully, when Microsoft produced Windows 3.x, they also included an
API call to create unique Temporary Files, but it wasn't until Windows
95 came along that Microsoft included an API call to easily locate the
user's TEMP directory.


Class Structure
---------------

You need two private string variables, FTempDir and FTempFileName, to
hold the Temporary directory path and the Temporary File Name
respectively. The full class declaration is as follows:

type
  TTempFile = class
  private
    FTempDir: String;
    FTempFileName: String;
    procedure SetTempDir;
    procedure SetTempFileName;
    procedure SetINI(const INIValue: string);
  public
    constructor Create;
    destructor Destroy; override;
    function TempFileName: string;
    function TempDir: string;
    procedure DelTempFile;
  end;

SetTempDir and SetTempFileName call the Windows API functions
GetTempPath and GetTempFileName. These two functions do most of the
work. I'll deal with these two functions one at a time.


The Two Windows API Functions
-----------------------------

GetTempDir - The full Windows API declaration for this function is:

DWORD GetTempPath(
        DWORD nBufferLength,
        LPTSTR lpBuffer);

nBufferLength specifies the size, in characters, of the string buffer
identified by lpBuffer. You set lpBuffer to MAX_PATH in length and
nBufferLength to MAX_PATH. lpBuffer points to a string buffer that
receives the null-terminated string specifying the temporary file path -
in our case the private string variable FTempDir.

Because GetTempPath returns the length (excluding the null-terminator)
of the string copied to FTempDir it can be used to size itself. This
makes the SetTempDir procedure, to all intents and purposes, just two
lines of code (note the typecasting of FTempDir as a PChar).

procedure TTempFile.SetTempDir;
begin
  { Set the length of FTempDir to the maximum Path length }
  SetLength(FTempDir, MAX_PATH);

  { Get the TEMP directory and resize FTempDir
    to the length of the path returned}
  SetLength(FTempDir, GetTempPath(MAX_PATH, PChar(FTempDir)));
end;

Now that you have the location of the TEMP directory you can create a
unique Temporary File in it. This is done with GetTempFileName, which is
declared in the Windows API as follows:

UINT GetTempFileName(
       LPCTSTR lpPathName,
       LPCTSTR lpPrefixString,
       UINT uUnique,
       LPTSTR lpTempFileName);

As you can see this function is a little more complex, so I'll run
through each of the parameters:

lpPathName points to a null-terminated string that specifies the
directory path for the filename. Use the result of the GetTempPath
function for this parameter. If this parameter is NULL, the function
fails.

lpPrefixString points to a null-terminated prefix string. The function
uses the first three characters of this string as the prefix of the
filename. I used to use my initials JQL but users could identify the
file as coming from my programs and were opening them, or deleting them
while they were still in use causing one or two "unforeseen problems".
Therefore, I now use TMP as the prefix and the users tend to leave the
files alone. Note the file extension is always .TMP.

uUnique specifies an unsigned integer that the function converts to a
hexadecimal string for use in creating the temporary filename. If
uUnique is zero, which in our case it is, the function uses a
hexadecimal string derived from the current system time. The function
uses different values until it finds a unique filename, and then it
creates the file in the lpPathName directory. If uUnique is not zero,
the function adds the hexadecimal string to lpPrefixString to form the
temporary filename. In this case, the function does not create the
specified file, and does not test whether the filename is unique.

lpTempFileName points to the buffer that receives the temporary
filename. This buffer should be at least the length, in bytes, specified
by MAX_PATH to accommodate the path.

GetTempFileName returns the unique numeric value used in the temporary
filename, or zero if it fails, therefore we need to manually trim
FTempFileName to the correct length, which we do by searching for the
null-terminator (#0). The full SetTempFileName procedure is as follows:

procedure TTempFile.SetTempFileName;
begin
  { Set the length of FTempFileName to the maximum Path length }
  SetLength(FTempFileName, MAX_PATH);

  if GetTempFileName(PChar(TempDir), PChar('TMP'),
    0, PChar(FTempFileName)) <> 0 then
      SetLength(FTempFileName, Pos(#0, FTempFileName)-1)
  else
    FTempFileName := '';

  SetINI(FTempFileName);
end;

Notice that you passed the function TempDir as the directory path. Also
note that if the GetTempFileName function fails FTempFileName contains a
zero length string, which, if necessary, you can test for in your code.


Public Functions
================

Now that you have the TEMP directory path and a unique TempFileName you
need to make them available to the rest of your program, which you do by
using the two public functions TempDir and TempFileName.

Because it is vaguely possible the user could change the TEMP directory
"on the fly" it's a good idea to check that it hasn't been altered. The
TempDir function is shown below:

function TTempFile.TempDir: string;
begin
// The value of TEMP could change so check it
  SetTempDir;
  Result := FTempDir;
end;

The TempFileName function checks to see if a TempFileName has been
created. If it has, it returns the filename. If it hasn't, it creates
one then returns it:

function TTempFile.TempFileName: string;
begin
// If it doesn't exist - create it
  if FTempFileName = '' then
    SetTempFileName;

  Result := FTempFileName;
end;

Having created a TempFileName you also need to delete it when necessary.
That is accomplished in the aptly named DelTempFile procedure. This
public procedure checks to see if there is a Temporary File before
trying to delete it.

procedure TTempFile.DelTempFile;
begin
  { Do we have a temporary file? }
  if Length(FTempFileName) > 0 then
    If FileExists(FTempFileName) then
      DeleteFile(FTempFileName);

  FTempFileName := '';
  SetINI(FTempFileName);
end;

Bear in mind that when the class is Freed, it calls DelTempFile to tidy
up after itself. Therefore you must only free the class when you no
longer need the Temporary file.

destructor TTempFile.Destroy;
begin
  // Delete the Temporary file if it still exists
  DelTempFile;
  inherited Destroy;
end;


Persistence
-----------

It won't have escaped your notice that SetTempFileName and DelTempFile
both call the private procedure SetINI. SetINI is used in case of a
catastrophic system crash to hold the TempFileName, if there is one.
Your program can, on start up, test to see if a TempFileName entry
exists in the INI file and, if it does, offer to recover the
information. I use an INI file rather than the Registry because my
Registry has reached gargantuan proportions and it is easier for the
user to manually delete an INI file if necessary.

The SetINI procedure creates an INI file in the application directory,
with the same name as your application but with the extension '.INI'.
SetINI then checks the value passed to it. If the value is an empty
string it deletes the TempFileName key from the INI file otherwise it
writes the TempFileName to the TempFileName key as shown below.

procedure TTempFile.SetINI(const INIValue: string);
var
  TheINIFile: TINIFile;
begin
  TheINIFile := TINIFile.Create(ChangeFileExt(Application.ExeName,
    '.INI'));
  try
    with TheINIFile do
    begin
      if INIValue = '' then
        DeleteKey('TempFiles', 'TempFileName')
      else
        WriteString('TempFiles', 'TempFileName',
                    INIValue);
    end;
  finally
    TheINIFile.Free;
  end;
end;

Remember to add INIFiles to the uses clause in interface not in
implementation.


In Action
---------

To show the use of the TTempFile class I have incorporated it into
Borland's RichEdit Demo (without the "internationalisation") to add
rudimentary Auto Backup facilities to the program.

In the edit menu add an item named 'miAutoBackup'. Set its caption to
'&Auto Backup' and its checked property to 'True'. Add a Timer to the
form and change its name from 'Timer1' to 'Timer' and set it's enabled
property to 'True'. Listing 1 shows the code for the miAutoBackup
OnClick event, the Timer's OnTimer event and the TMainForm.FormDestroy
event.

In the TMainForm.OnCreate event add the following two lines:

  TempFile := TTempFile.Create;
  Timer.Interval := 300000; // 5 minutes

Change the TMainForm.FileSave procedure to include a test to see if we
are backing up or saving as follows:

procedure TMainForm.FileSave(Sender: TObject);
begin
  if FFileName = sUntitled then
    FileSaveAs(Sender)
  else
  begin
    Editor.Lines.SaveToFile(FFileName);
// if not backing up change the modified settings
    if FFileName <> TempFile.TempFileName then
    begin
      Editor.Modified := False;
      SetModified(False);
    end;
  end;
end;

Add TempFilesUnit to the uses clause in interface and TempFile:
TTempFile; to the var clause. There you have it. A simple word processor
with Auto Backup facilities.

The source code for the TTempFile class and a demo application are
included in the newsletter's archive or can be downloaded from my
website.


Conclusion
----------

Delphi makes it easy to use the Windows API by the easy typecasting of
strings to PChars and, although Borland have translated a great deal of
the Windows API functions for use in Delphi, there are still some left
that are useful. The WIN32SDK.HLP file which is in the
..\PROGRAM FILES\COMMON FILES\BORLAND SHARED\MSHELP directory (or click
the Windows SDK menu item) has more information on the Windows API
functions.

The TTempFile class, when first conceived, did not need to know how to
read and write to the temporary file or how to recover data after a
system crash, and I will leave it to you to decide whether you want
extend the class with that functionality.

__________________

John Lavelle lives on the edge of the beautiful English Lake District.
John has been programming since 1981 and has been using Delphi since
version 1. When he isn't programming, he is a consultant to some of the
local companies, builds computers, installs networks, teaches computer
skills and makes the tea ;-)
________________________________________________________________________

         Vote for the Pascal Newsletter in The Delphi Top 200!
         http://top200.jazarsoft.com/delphi/rank.php3?id=latium
________________________________________________________________________


5. Universal Embedding of Files in Delphi Units

   By Max Kleiner max@kleiner.com
   Kleiner Kommunikation Reference: http://max.kleiner.com/
   Component Download: http://www.softwareschule.ch/download/hexer2.zip


This article attempts to explain how to include files inside a Delphi
unit / application as different kinds of binaries and how to manage them
without using the resource technology.

The app is called the Hexer works on VCL and CLX.

//Update 1, 2005-05-29: Migration to Linux in one pas file
//Update 2, 2005-06-05: Call the bytearray from a dll (export)

You can put your files into your delphi project at design time and then
just compile it to get all into one or more units.

First you have to convert the file in a delphi unit by the Hexer. Then
you call it from your own app which embeds the unit. You can even store
waves or pictures and play it without the need to create a file, play it
from memory.

if not PlaySound(@UtopiaWinstarten_wav, 0, SND_MEMORY + SND_SYNC)

It is possible to embed any kind of file (also executables) in an
executable using the Hexer. First example is a picture:

procedure TForm1.btnPicloadClick(Sender: TObject);
var mybitmap: TBitmap;
    bitStream: TStream;
begin
  //mybitmap.LoadFromFile('dws_logo.bmp'); for the mortals
  mybitmap:= TBitmap.Create;
  bitStream:= TMemoryStream.Create;
  try
    bitStream.Writebuffer(dws_logo_bmp, sizeof(dws_logo_bmp));
    bitStream.Position:= 0;
    mybitmap.LoadFromStream(bitStream);
    if assigned(mybitmap) then begin
      image1.Picture.assign(mybitmap);
      image1.update;
    end;
  finally
    bitStream.Free;
    mybitmap.Free;
  end;
end;

Second example is an executable:

procedure TForm1.btnApploadClick(Sender: TObject);
var mybitmap: TBitmap;
    bitStream: TMemoryStream;
begin
  mybitmap:= TBitmap.Create;
  bitStream:= TMemoryStream.Create;
  try
    bitStream.Writebuffer(viergewinnt_exe, sizeof(viergewinnt_exe));
    bitStream.Position:= 0;
    bitstream.LoadFromStream(bitstream);
    bitstream.SaveToFile('vierg.exe');
    WinExec(pchar('vierg.exe'){ + ' ' + ParamStr},SW_NORMAL);
  finally
    bitStream.Free;
    mybitmap.Free;
  end;
end;


How Does Hexer Work?
--------------------

MainForm2.TForm1.btnConvertClick (97i)
  MainForm2.TForm1.ConvertToUnit (103i)
    MainForm2.WriteString (108i)
    MainForm2.EmbedFile (117i)
      MainForm2.WriteString (108i)

We open with createFile() the unit for write down the file in the unit.
The CreateFile function creates or opens objects and returns a handle
that can be used to access the object.

  f_hndoutput:= CreateFile(PChar(ChangeFileExt(edtUnitToCreate.Text,
    '.pas')), GENERIC_WRITE, 0, NIL, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL, 0);

Then we call EmbedFile which opens the file to be write down in the
unit. The WriteFile function writes data to a file and is designed for
both synchronous and asynchronous operation. The function starts writing
data to the file at the position indicated by the file pointer.

BOOL WriteFile(
    HANDLE hFile, // handle to file to write to
    LPCVOID lpBuffer, // pointer to data to write to file
    DWORD nNumberOfBytesToWrite, // number of bytes to write
    LPDWORD lpNumberOfBytesWritten, // pointer to bytes written
    LPOVERLAPPED lpOverlapped );

After the write operation has been completed, the file pointer is
adjusted by the number of bytes actually written.

  f_hndopen:= CreateFile(PChar(filename),  GENERIC_WRITE +
    GENERIC_READ, 0, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

Each time the file pointer is adjusted we write a block of

    abuf: array[0..19] of byte;
Result:= ReadFile(f_hndopen, abuf, sizeof(abuf), BytesRead, NIL);
          if bytesRead > 0 then begin

At least our generated unit looks like

Unit dws_logo2;

interface

const
   dws_logo_bmp: array[0..21717] of byte = (
$42,$4D,$D6,$54,$00,$00,$00,$00,$00,$00,$76,$00,$00,$00,$28,$00,$00,$00,
$F0,$00, $00,$00,$B4,$00,$00,$00,$01,$00,$04,$00,$00,$00,$00,$00,$60,
$54,$00,$00,$C4,$0E,$00,$00,$C4,$0E,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,
..............


Conclusion
----------

You have three possibilities to embed files:
1. Delphi3000.com articles 2606 or 4217 show the way with resources
2. Delphi3000.com article 2321 is based on TComponent and TStream with
   read and write
3. This article is more generic, the advantage is transparency at design
   time and protection at runtime of the embedded files, you can even
   use binaries which you control with an inline assembler format.

The project Hexer and loader / player is not included in the attached
source code archive due to its size. It can be downloaded from the URL
at the start of this article.


Update 1 - Some pointers for CLX
--------------------------------

Despite the low level stuff of the WinAPI no great obstacles were found
during the migration.

  QForms, QDialogs,
  QStdCtrls, QControls, QExtCtrls, Classes;

A few functions had to be re-selected, for example:

FileWrite writes Count bytes to the file given by Handle from the buffer
specified by Buffer. Handle is a file handle returned by the FileOpen or
FileCreate method.

Or another approach to define the file size has to be considered:

If the file is declared as a file of byte, then the record size defaults
to one byte, and FileSize returns the number of bytes in the file.


Update 2 - Exporting a great const from a DLL
---------------------------------------------


First you declare the type of the const and second you define a wrap
function around the type:


library hexerdll;

type Tviergewinnt_exe = array[0..88598] of byte;

const
   viergewinnt_exe: TViergewinnt_exe = (
   $4D,$5A,$00,$01,$01,$00,$00,$00,$08,$00,$10,$00,$FF,$FF,$08,$00,$00,
   $01,$00,$00,
   .............

function getArrayofByte: Tviergewinnt_exe;
   begin
     result:= viergewinnt_exe;
   end;

exports
   getArrayofByte;


The call of the client has the following structure:

The important thing is to declare a local var of the const in our case
dllexe: Tviergewinnt_exe;

unit playmain;
// examples to call the embedded file in the unit or the dll
........

type Tviergewinnt_exe = array[0..88598] of byte;

function getArrayofByte: Tviergewinnt_exe; external 'hexerdll';

procedure TForm1.btnApploadClick(Sender: TObject);
var bitStream: TMemoryStream;
    dllexe: Tviergewinnt_exe;
begin
  bitStream:= TMemoryStream.Create;
  //getArrayofByte
  dllexe:= getArrayofByte;
  try
    // import DLL const
    bitStream.Writebuffer(dllexe, sizeof(dllexe));
    bitStream.Position:= 0;
    bitstream.LoadFromStream(bitstream);
    bitstream.SaveToFile('viergewinnt.exe');
    case WinExec(PChar('viergewinnt.exe'), SW_SHOWDEFAULT) of
      0: ShowMessage('The system is out of memory or resources.');
      ERROR_BAD_FORMAT: ShowMessage('The .EXE file is invalid.');
      ERROR_FILE_NOT_FOUND: ShowMessage('The specified file was not
        found.');
      ERROR_PATH_NOT_FOUND: ShowMessage('The specified path was not
        found.');
    end;
  finally
    bitstream.Free;
  end;
end;

________________________________________________________________________

     KnowledgeBase Expedition 4.2 - by Delphinium Software ($49.35)
  KnowledgeBASE Expedition features a highly searchable and expandable
    information tree viewed in outline or audited within a built-in
       wordprocessor. Includes a database for stored references.
           http://www.download.com/3000-2064_4-10239072.html
________________________________________________________________________


6. Forums / Mailing Lists


To join any of our forums, the best way is to subscribe from the web,
since then you'll be able to access the website features (message
archive, files section, etc). A Yahoo! ID is required for that, and you
can get yours free by registering as a Yahoo! user, but you can also
subscribe by email (you'll only have email access).

* Delphi-En: A unique forum for intermediate-level Delphi programmers.
A large group with a helpful community of members. If you are a beginner
please stay as a listener and learn from others' questions and answers.
Home Page:    http://groups.yahoo.com/group/delphi-en/
Subscription: http://groups.yahoo.com/group/delphi-en/join
              delphi-en-subscribe@yahoogroups.com

* Kylix: Kylix programming.
Home Page:    http://groups.yahoo.com/group/KylixGroup/
Subscription: http://groups.yahoo.com/group/KylixGroup/join
              KylixGroup-subscribe@yahoogroups.com

* Components: This is a forum for searching / recommending software
components (VCL and CLX components, ActiveX objects, DLL libraries,
.Net, etc.), as well as utilities, tutorials, information, etc.
Home Page:    http://groups.yahoo.com/group/components/
Subscription: http://groups.yahoo.com/group/components/join
              components-subscribe@yahoogroups.com

* Software Developers: A place for subjects related to software
development and the industry. For developers to share their experiences
as an academic, professional or hobbyist. It is not a programming forum,
messages here are supposed to be more general or language independent.
Home Page:    http://groups.yahoo.com/group/software-developers/
Subscription: http://groups.yahoo.com/group/software-developers/join
              software-developers-subscribe@yahoogroups.com

________________________________________________________________________

      Vote for the Pascal Newsletter in The Delphi Resource Center!
  http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E
________________________________________________________________________


7. Delphi on the Net

   By Dave Murray <irongut at vodafone dot net>


Components, Libraries and Utilities
===================================

Shareware / Commercial
----------------------

* KnowledgeBase Expedition 4.2 - by Delphinium Software ($49.35)
  KnowledgeBASE Expedition features a highly searchable and expandable
  information tree viewed in outline or audited within a built-in
  wordprocessor. Includes a database for stored references.
  http://www.download.com/3000-2064_4-10239072.html


Freeware
--------

* AnyDAC v1.0.5 - by Dmitry Arefiev
  A multi DBMS, high-speed, flexible data access framework for Delphi
  with a multi-layered, plugable architecture. DBMS supported natively
  are: Oracle v8.0.3 and higher; MySQL v3.23 and higher; MSSQL 2000 and
  higher; MSAccess 2000 and higher; IBM DB2 UDB v8 and higher; Sybase
  ASA v8 and higher.  AnyDAC was optimized for these databases but also
  supports generic data sources through dbExpress and ODBC drivers.
  http://www.da-soft.com/

* BackgroundWorker v1.0	- by Mauro Venturini (with source)
  Windows Forms applications often require some sort of asynchronous
  invocation option. .NET 2.0 provides the BackgroundWorker component to
  facilitate easy asynchronous invocation with Windows Forms. This is a
  Delphi.NET BackgroundWorker component implementation for .NET 1.1.
  http://www.torry.net/net/system/threads/BackgroundWorker.zip

* GDI Plus Controls v1.0 - by Matt Harrison (with source)
  A set of GDI+ based components for Delphi. Includes: a GDI Plus font
  selector; HSV/RGB Color selector with Alpha Support with Frame and
  Dialog implementations; a Color Panel with alpha support; a GDI+
  Canvas, like a TPaintBox but GDI+ instead; a TGDIPlusWinControl to
  descend your own controls from.
  http://www.lummie.co.uk/content/view/52/42/

* THDDInfo v1.22 - by Artem Parlyuk (with source)
  Non-visual Delphi component providing low level information about IDE,
  ATAPI and SCSI (WinNT only) devices. Supports both Win9x and WinNT.
  Provides drive type; Model sting; Firmware revision; Serial number.
  For IDE also provides drive geometry (cylinders, heads, sectors); LBA
  sectors count; drive size (non-formatted); controller buffer size.
  http://artsoft.nm.ru/works.html

* Inno Setup v5.1.4 - by Jordan Russell (with source)
  A free installer for Windows that rivals commercial installers in
  features and stability. Key features: All 32-bit Windows versions;
  Creation of a single EXE; Standard Windows 2000/XP-style interface;
  Customizable setup types; Complete uninstall capabilities; Integrated
  "deflate", bzip2, and 7-Zip LZMA file compression; Create shortcuts,
  registry and .INI entries.; Integrated Pascal scripting engine.
  http://www.jrsoftware.org/isinfo.php


Borland Product Updates
-----------------------

* Update 3 for Delphi 2005 Available Now
  Delphi 2005 Update 3 is now available to download for registered
  users. It resolves the modeling performance issues that affected
  Delphi 2005 Update 2.
  http://community.borland.com/article/0,1410,33069,00.html

* CaliberRM Plugin for Delphi 2005 - A Technology Preview
  Got requirements? Got Delphi? Got CaliberRM? A Technology Preview for
  CaliberRM Integration in Delphi 2005 is now available from the Delphi
  2005 registered users download page.
  http://community.borland.com/article/0,1410,33077,00.html

* Free Download: Bold for Delphi 2005
  A Delphi 2005 compatible version of the award winning model-driven
  framework Bold for Delphi is now available for download from
  CodeCentral. This edition contains a few bug fixes beyond Delphi 7
  Architect Service Pack 2, but has no new features.
  http://community.borland.com/article/0,1410,33058,00.html


Articles, Tips and Tricks
=========================

* A New Look For BDN
  Information to help you make the best use of the new BDN web site.
  http://bdn.borland.com/article/0,1410,33078,00.html

* Wanted: VCL for Win32 to VCL for .NET Migration Stories!
  Borland normally pay $200 for articles submitted via GetPublished, but
  for awesome "VCL to VCL for .NET" migration stories they'll pay more.
  http://community.borland.com/article/0,1410,33070,00.html

* New Borland Delphi Survey
  Your opportunity to provide feedback directly to the Delphi team.
  http://community.borland.com/article/0,1410,33065,00.html

* Borland Delphi 2005 Compiler, Language, and Debugger Enhancements
  This article provides an overview of several of the new features found
  in Delphi 2005.
  http://community.borland.com/article/0,1410,33050,00.html

* Placing a TProgressBar into a TListView - by Zarko Gajic
  How to add a progress bar (or any other Delphi component) to a
  ListView control. Plus: full source code to the TListViewEx component
  (TListView descendant) with ColumnResize events!
  http://delphi.about.com/library/weekly/aa053105a.htm

* MDI Development in Delphi - by Zarko Gajic
  In an MDI application, more than one document or child window can be
  opened within a single parent window. Learn how to create a powerful
  "multiple document interface" application using Delphi.
  http://delphi.about.com/od/beginners/l/aa031103a.htm

* Delphi History: From Turbo Pascal to Delphi 2005 - by Zarko Gajic
  This document provides concise descriptions of Delphi versions and its
  history, along with a brief list of features and notes. Find out how
  Delphi evolved from Pascal to a RAD tool that can help you solve
  complex development problems not only for Windows but also for Linux
  and the .NET.
  http://delphi.about.com/cs/azindex/a/dhistory.htm

* TDBButton: Data Aware TButton Control - by Zarko Gajic
  Learn how to create a data-aware TButton Delphi control.
  http://delphi.about.com/library/weekly/aa050305a.htm


Tutorials and Training
======================

* BDNtv: The new Delphi 2005 CaliberRM plug-in
  Daniel Polistchuck, the developer of the new CaliberRM plug-in for
  Delphi, provides a quick overview of its functionality.
  http://community.borland.com/article/0,1410,33086,00.html

* BDNtv: Using StarTeam with the Delphi 2005 History View
  See how productive reviewing code changes can become with StarTeam
  integration into the Delphi history view. FLASH
  http://bdn.borland.com/article/0,1410,33082,00.html

* BDNtv: Accelerating Development with Enterprise Core Objects (ECO II)
  With ECO II, the model is the system. This BDNtv episode shows how
  this powerful architecture can dramatically accelerate the development
  process and at the same time reduce complexity and the amount of code
  required. (Flash)
  http://community.borland.com/article/0,1410,33061,00.html

* BDNtv: Maximizing the Business Value of Software
  Watch the BorCon 2004 keynote presentation by Boz Elloy introducing
  Software Delivery Optimization. (WMV)
  http://community.borland.com/article/0,1410,33049,00.html


News
====

* Developer spotlight:Danny Thorpe
  Danny Thorpe is the chief scientist at Borland, and was part of the
  original team that developed Delphi. Builder magazine caught up with
  Danny to talk about the move to .NET, Kylix, and the future of Delphi.
  http://www.builderau.com.au/architect/sdi/0,39024602,39194366,00.htm

* Borland Wins Coveted 'Jolt' Awards for Requirements and Modeling Tools
  CaliberRM 2005 and Together Designer 2005 both recently earned honors
  at the coveted Software Development Jolt Product Excellence and
  Productivity Awards.
  http://home.businesswire.com/portal/site/google/index.jsp?ndmViewId=news_view&newsId=20050506005402&newsLang=en

* People's Choice Awards - Your Vote Counts!
  Vote for Delphi 2005, Together 2005 for Visual Studio, StarTeam 2005
  and CaliberRM 2005 at MSD2D's 4rd Annual People's Choice Awards.
  http://community.borland.com/article/0,1410,33062,00.html

* Borland Honoured in SD Times 100 for Third Consecutive Year
  Borland today announced that it has been chosen as one of the SD Times
  100 leaders and innovators for the third consecutive year.
  http://www.itweb.co.za/sections/business/2005/0505300927.asp

* Borland Delivers Resources, Solutions for Software Risk Management
  Borland today announced the availability of a global seminar series,
  assessment workshops and other resources designed to help IT teams
  understand how to both minimise and harness risk to drive growth and
  competitive advantage.
  http://www.itweb.co.za/sections/business/2005/0505230846.asp


Other / Misc Sites
==================

* Take Part in the IDC Worldwide Developer Survey
  IDC is conducting a worldwide survey of software developers in
  collaboration with several large IT vendors, including Borland.
  http://www.idcswdc.com/cgi-bin/survey?id=105dez

* BDNradio: Trust in Borland
  Listen to the replay of the live chat with Dale Fuller discussing
  "Trust in Borland", and read the chat log.
  http://community.borland.com/article/0,1410,33056,00.html

* Koders
  Koders is a search engine for open source code in almost any language
  you can think of (including Delphi). Koders searches over 198,319,800
  lines of code and can be added to your website or integrated into the
  Mozilla and Firefox browsers as a search plugin.
  http://www.koders.com/

________________________________________________________________________

Irongut's Delphi Pages
Dedicated to programming with Borland Delphi and Kylix. We have articles
on programming, Borland and Delphi news, source code and components to
use in your applications and more.  >> http://www.paranoia.clara.net/ <<
________________________________________________________________________


YOU CAN HELP US


We need your help to keep this newsletter going and growing. You can
help by referring the newsletter to your colleagues:

http://www.paranoia.clara.net/delphi_newsletter.html

Or you can help by voting for us in some or all of these rankings to
give more visibility to our web site and thus increase the number of
subscriptions to this newsletter:

http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E
http://www.programmingpages.com/?r=latiumsoftwarecomenpascal
http://top100borland.com/in.php?who=20

It's just a few seconds for you that REALLY mean a lot to us.

Don't forget we also need articles and there are prizes available for
contributions. All articles will be considered, send them to:
pascal-newsletter-owner@yahoogroups.com

We are also looking for shareware authors who would like to offer their
components or applications as prizes for articles in the newsletter. In
return you will be promoted in the newsletter and website. For more info
contact: Dave Murray <irongut at vodafone dot net>

________________________________________________________________________

If you haven't received the full source code examples for this issue,
you can get them from http://www.paranoia.clara.net/downloads/p0055.zip
________________________________________________________________________

This newsletter is provided "AS IS" without warranty of any kind. Its
use implies the acceptance of our licensing terms and disclaimer of
warranty you can read at http://www.paranoia.clara.net/legal.html
where you will also find a note about legal trademarks. Articles are
copyright of their respective authors and they are reproduced here with
their permission. You can redistribute this newsletter as long as you do
it in full (including copyright notices), without changes, and gratis.
________________________________________________________________________

Main page: http://www.paranoia.clara.net/delphi_newsletter.html
Group Home:  http://groups.yahoo.com/group/pascal-newsletter/
Subscribe:   pascal-newsletter-subscribe@yahoogroups.com
Unsubscribe: pascal-newsletter-unsubscribe@yahoogroups.com
Problems with your subscription? pascal-newsletter-owner@yahoogroups.com
________________________________________________________________________

Irongut's Delphi Pages: http://www.paranoia.clara.net/
Latium Software:        http://www.latiumsoftware.com/en/index.php

Copyright 2005 by Ernesto De Spirito + Dave Murray. All rights reserved.
________________________________________________________________________
Copyright © 2005 Ernesto De Spirito and Dave Murray. All Rights Reserved.