Home

News

Articles

Forums / Groups

Mozilla-Delphi Project

Pascal Newsletter
Issue 52
Back Issues

Software

Links

Search

Vote For Us:
Irongut's Delphi Pages
Pascal Newsletter

Contact Details

Legal Stuff

News Archive
Pascal Newsletter Issue 52
Pascal Newsletter #52 - 21-DECEMBER-2004

Contents

1. A Few Words From the Editors
2. How to Add a Program to the Explorer Send To Menu
3. Introductory Principles of Indexed Searching
4. Extracting Records in a Field into a TStringList
5. Returning Classes from a DLL
6. Simplified Collision Detection in Game Programming
7. Forums / Mailing Lists
8. 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


Welcome to the last issue of the Pascal Newsletter for 2004. We'd like
to thank all the authors who contributed articles or prizes this year.
We've got five articles in this issue to give you plenty of reading over
the holiday period and we'd like to thank the authors who contributed
them: Peter Johnson, Jim McKeeth, Stewart Moss, Max Kleiner, John Pears.
We're pleased to award Stewart Moss, Max Kleiner and John Pears the
prizes for this issue:

* Stewart Moss - 'Extracting Records in a Field into a TStringList'
  InstallAWARE 3.0 Express Edition - by MimarSinan Int. ($69.95)
  InstallAWARE 3.0 for Windows Installer - by MimarSinan International
  Develop setups for Windows Installer without any knowledge of MSI!
  InstallAWARE automatically converts a conditionally flowing script
  into a logo certifiable, ICE-compliant MSI database at build time.
  The IDE features a visual UI which generates your setup script for
  you automatically and you can fully customize the script behavior.
  Special limited offer: 30% off all editions, Enterprise only $559.95!
  http://www.installaware.com/landingea.html

* John Pears - 'Simplified Collision Detection in Game Programming'
  KnowedgeBASE Vortex 2.9 by Delphinium Software ($49.35)
  KnowledgeBASE Vortex 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/KnowledgeBase-Vortex/3000-2064-10342084.html

* Max Kleiner - 'Returning Classes from a DLL'
  KylixDriver v1.1 - by ET Kimberliteware Ltd ($39 / $69 with source)
  KylixDriver is a RAD Kylix-oriented and integrated toolkit for PC 
  hardware access. This toolkit can be efficiently used for writing 
  Linux device drivers for ISA and PCI hardware.
  http://www.geocities.com/etkimberliteware/kylixdriver/index.html

Special thanks to Delphinium Software for donating KnowledgeBASE Vortex 
as an ongoing prize for future issues. In the next issue we have three
prizes up for grabs: InstallAWARE 3.0 Enterprise Edition, KnowedgeBASE 
Vortex and YAPI Professional.

* 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/

We're also proud to offer readers a special discount on InstallAWARE 3,
thanks to the nice people at at MimarSinan International. InstallAWARE 3
was developed completely in Delphi and helps you author MSI setups with
zero knowledge of Windows Installer. Rather than just providing a visual
UI (like Wise or InstallShield), InstallAWARE has its own RAD scripting
language which is automatically converted to a logo-certifiable MSI
database at build time. Unique features include: Partial Web Deploy;
Genuine Scripting for Windows Installer; Powerful Dialog Editor with
Unique Controls (such as Flash and HTML containers); Advanced 7ZIP
Compression (.NET runtime is 11MB instead of 23MB!). For a limited time,
readers can get 30% off any edition of InstallAWARE 3 by following the
links in this issue.

Next year we're planning to publish seven issues of the newsletter - in
January, March, May, July, September, November and Christmas / New Year.
Now, on with the code...

Regards,

Dave Murray and Ernesto De Spirito
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 Add a Program to the Explorer Send To Menu

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


Why Do It
---------

If you are writing a general purpose file-related program it can be
useful to add it to the Windows Explorer "Send To" menu. For example I
place Windows Notepad on the "Send To" menu so I can easily view any
file in the text editor.


How It's Done
-------------

There are two stages achieving our goal:

 1. Ensuring our program can receive files sent from the "Send To" menu.
 2. Creating an entry for our program in the "Send To" menu.

Although you can create a special handler for the "Send To" menu, we 
will take the simple approach of simply storing a shortcut to our 
program in the menu.


Receiving Files From the "Send To" Menu
---------------------------------------

This is very simple. If the user selects one or more files, right clicks
and selects Send To | Our program, Windows will simply start our program
and pass the names of the selected files on the command line. So, to
read the files sent from the "Send To" menu, we simply need to check our
command line parameters.

We can do this in our application's FormCreate event handler as follows:

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := 1 to ParamCount do
    ProcessFile(ParamStr(I));
end;

Where ProcessFile processes a given file in an application defined way.
(In the demo program that accompanies this article we simply display the
file names in a memo control).

That's all there is to handling the files. Now let's look at how we
create the "Send To" menu entry.


Creating the "Send To" Menu Item
--------------------------------

Windows stores the contents of a user's "Send To" menu in a special
folder. We will need to create a shortcut to our program in that folder.

We must first find the path to the "Send To" folder. Each user has their
own copy of this folder. We find its location by using the
SHGetSpecialFolderLocation and SHGetPathFromIDList API calls (defined in
the ShlObj unit) as follows:

function GetSendToFolder: string;
var
  pidl: PItemIDList;
  PPath: array[0..MAX_PATH] of AnsiChar;
begin
  Result := '';
  if SHGetSpecialFolderLocation(0, CSIDL_SENDTO, pidl) = NOERROR then
  begin
    try
      if SHGetPathFromIDList(pidl, PPath) then
        Result := PPath;
    finally
      CoTaskMemFree(pidl);
    end;
  end;
end;

We first use SHGetSpecialFolderLocation to get a PIDL representing the
required folder. We pass CSIDL_SENDTO to the function to get the PIDL
for the current user's "Send To" folder. If we succeed in getting the
PIDL we then get the path to the folder by passing the PIDL to
SHGetPathFromIDList which stores the required path in a PChar buffer we
supply. We convert the PChar to a string and return this from the
function. Windows allocated memory for the PIDL using its task
allocator. It is our responsibility to free the PIDL, using the
CoTaskMemFree function (defined in the ActiveX unit).

Having found the path to the user's "Send To" folder we can now create a
shortcut to our application in the folder. We may choose to do this in a
set up program or by making this an option in our application. Whatever
our choice, the next section shows how to create a shell link.


Creating a Shell Link
---------------------

The following function can create any shell link -- not only those for
use in the shell link folder.

function CreateShellLink(const LinkFileName, AssocFileName, Desc, 
  WorkDir, Args, IconFileName: string; const IconIdx: Integer): Boolean;
var
  SL: IShellLink;    // shell link object
  PF: IPersistFile;  // persistant file interface to shell link object
begin
  // Assume failure
  Result := False;
  // Ensure COM is initialised
  CoInitialize(nil);
  try
    // Create shell link object
    if Succeeded(
      CoCreateInstance(
        CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, SL
      )
    ) then
    begin
      // Store required properties of shell link
      SL.SetPath(PChar(AssocFileName));
      SL.SetDescription(PChar(Desc));
      SL.SetWorkingDirectory(PChar(WorkDir));
      SL.SetArguments(PChar(Args));
      if (IconFileName <> '') and (IconIdx >= 0) then
        SL.SetIconLocation(PChar(IconFileName), IconIdx);
     // Create persistant file interface to shell link to save link file
      PF := SL as IPersistFile;
      Result := Succeeded(
        PF.Save(PWideChar(WideString(LinkFileName)), True)
      );
    end;
  finally
    // Finalize COM
    CoUninitialize;
  end;
end;

The function has numerous parameters. They are:
const , , , , : string; const : Integer

  1. LinkFileName: the full path to the shortcut file -- in our example
     we use the name of the "Send To" folder that was returned by 
     GetSendToFolder, followed by the name of the shortcut file. Note 
     that the "Send To" menu displays the name of this file, stripped of
     it's extension, so give the file a descriptive name.
      
  2. AssocFileName: the name and of the file referenced by the shortcut
     -- here we provide the full path to the program to be started from
     the "Send To" menu. ParamStr(0) stores this file name.
      
  3. Desc: a description of the shortcut -- this is not displayed in the
     "Send To" menu so we pass ''.
       
  4. WorkDir: the program's working directory -- can supply '' if not
     required.
      
  5. Args: any command line that is to be passed to the program -- we do
     not use this parameter in this example. Remember that the "Send To"
     menu also passes file names on the command line.

  6. IconFileName: specifies the file containing the shortcut's icon
     -- in our example don't specify this file and so the icon is 
     assumed to be in the program file.

  7. IconIdx: the index of the icon in IconFileName or -1 to cause the
     program's default icon to be used -- we specify -1.

From the above we can see we need to call CreateShellLink and follows:

...
CreateShellLink(
  GetSendToFolder + '\' + 'My SendTo Item.lnk',
  ParamStr(0),
  'My SendTo Sample Program',
  ExtractFileDir(ParamStr(0)),
  '',
  '',
  -1
);
...


Summary
-------

We have now covered the basics of adding an item to the "Send To" menu
and in handling files "sent" to our program from the menu. The code
presented can be used as a basis for implementing "Send To" menu support
in your programs.

A demo application is also included with this issue's source code zip.
It has been tested with Delphi 4 and Delphi 7.

__________________

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-12-demo.zip
________________________________________________________________________

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


3. Introductory Principles of Indexed Searching

   By Jim McKeeth <jim at mckeeth dot org>


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

There are really two main ways to search a large collection of text
documents. The simplest method would be to load each document and scan
through it for the search terms, this would be referred to as a full
text scan. The second, much faster method is to create an index and then
search the index. An index is a list of terms found in a document or set
of documents. Each word only appears once per document so it is much
shorter then the original document.


Creating An Index
-----------------

Finding The Words
-----------------

In order to create an index you must first parse the document. Parsing,
is the process of picking out the individual tokens (terms or words) in
a piece of text. A parser is a type of state machine. There are many
existing parsing routines available. "The Tomes of Delphi Algorithms and
Data Structures" by Julian Bucknall contains many very good parsers. An
example: http://www.delphi3000.com/articles/article_1265.asp

A simple parser would scan through a string of text, starting at the
beginning, looking at each character. If it is a letter or number then
it is part of a word, if it is white space or punctuation then it is a
separator. Each word is added to a list (i.e. TStringList) in the order
it is found in the document. Typically each word is converted to the
same case (upper or lower). 

It is really important to consider what you are indexing and how your
index will be used when creating your index and parsing. For example if
you are parsing HTML then you want to exclude most tags (with the
obvious exception of META tags, which are handled specially). Other
times you might only want to index summery information about each
document.

Indexing The Words
------------------

Now that we have a parsed token list we need to index it. The simplest
index is just a list of each word found in a document, and a reference
to the document. This reference may be a URL, a document name or any
other unique identifier (a GUID or a foreign key to another table
describing the document). A more complex index may include the number of
times the word is found in the document or a ranking for where it is in
the document (in the title, keyword section, first paragraph, middle,
last, etc.) This additional information stored with each word is part of
what differentiates one search engine's performance from another.

Many times certain words are left out. These are called stop words. Stop
words are common words, words that will not be searched on, or words
that will not enhance the meaning of a search. An example of stop words
includes "THE, A, AN, AND, IF, BUT", words with numbers in them, or
anything else you want to filter out. Selecting stop words is another
point of separation of performance.

Some web search engines used to leave out words like "HTML" or "WEB"
because they were so common while other search engines would include
every word. Other search engines start with a dictionary list and only
index words found in that dictionary list. This leads to trouble when
you are indexing names, technical terms or anything else not found in
your original dictionary.

One time I was creating a search engine for a collection newsgroup
articles. I discovered that there was UUEncoded (similar to MIME or
Base64) binaries in the articles. This resulted in my parser finding
words that were hundreds of characters long and total gibberish. I
decided to omit any word longer then 50 characters or shorter then 4.
Making the choices about what to include and what to omit is an
important decision, and will vary based on what content you are
indexing.

So here is an example table structure for your index:

Table: WordList
---------------
Document: Number (foreign key to Documents table)
Word : String[20] (if our longest word is 20 characters)
Count : Number (how many times the word is found)

The primary key would be a compound of Document and Word since each word
is listed once per document.

Table: Documents
----------------
Document : Number(primary key index)
Title : string (title of document)
Location : string (URL or full filename and path)

Optionally you could include the entire document as a blob in this
table. You could also have other tables that lists terms (from the meta
section of the document) or include authors. Again this design choice
depends on the type of documents you are indexing and the purpose of
your search engine.


Searching Your Index
--------------------

Once all the indexes are stored in a database you need to be able to
search the index for a document. A simple SQL statement to search for a
document that contains a single word could look like this:

SELECT *
FROM WordList
WHERE Word = :v_search_term
ORDER BY Count DESC

This returns all documents containing your single search term and they
are ordered by the number of times the word is found. If you want to use
SQL then to search on multiple terms involves an join for each term.
Instead you could retrieve a list for each term and then merge them
manually. This is where you would support AND, OR or NOT key words.

If you want to allow phrase searching then you could search for each
word in the phrase and then search those documents for the phrase. The
same technique could be used for the NEAR key word. There are other more
advanced techniques to do this that are much quicker, but they are
beyond the scope of this document.

Once the hits are found and ranked then display the title of each
document, possibly a summary or the context of the hits, and provide a
way for your user to reach the document.


Variations
----------

One thing Google does a little differently is they look at how pages are
linked. This works really well with the hyper linked nature of the web.
For example if you search for Borland most pages that mention Borland
link to www.borland.com. This is assumed to indicate that
www.borland.com is a very important site about Borland. Google also
limits the number of hits you get on each domain.

Many search engines also rank pages higher if the search term appears in
the URL or title of the page. They also look at the description and
keywords meta tags for ranking. Some search engines will actually ignore
a word if it appears too often in a page. This weeds out sites that try
to artificially inflate their rankings.

Phonetics or Soundex is another technique that can be used. This could
be done with an additional table similar to the word table, but instead
store the soundex value for the words instead of the actual word.


Third Party Search Tools
------------------------

dtSearch  http://www.dtsearch.com/
--------

dtSearch provides a full range of text search products. These products
target everyone: from the end user to the media publisher and finally
the developer. Their dtSearch Text Retrieval Engine is the core of all
their products and they provide an API with Delphi examples. This
product is just about creating a full text index of documents and
searching it. They use their own data format. Using their API you can
create a Delphi application to index just about any document (PDF,
Office, ZIP, etc. and Text too!) and then search that index to find the
matching documents.

They recently added support for Linux and .NET but I haven't tested
these with Linux or Delphi for .NET yet.

Depending on what type of project you are working on, one of their other
product lines might be a good match. Their dtSearch Publish, for
example, lets you create a CD / DVD of searchable content quickly and
easily. While their dtSearch Web is idea for building a web search
engine.

Rubicon  http://www.fulltextsearch.com/
-------

Tamarack Associates' provides their flagship product Rubicon to Delphi
and C++Builder developers who want indexed searching without building a
system from scratch. Beyond the basics we cover here, they also offer
many advanced features and speed improvements.

If you visit their web site you can download a demo version of their
search tools or test their newsgroup search in Borland and Microsoft's
newsgroups. Not only does Rubicon allow searching of documents (It comes
with a parser to handle text, HTML, and RTF), but it will also allow you
to search your database for data. It supports logical expression (and,
or, not, near and like), as well as support for full phrases. It is all
pure Delphi source, and really offers the developer a very high level of
control over the process.

Rubicon's FastPhrase technology builds a much larger table that allows
it to perform phrase searches without performing a full text scan of the
target document. This is done by not only storing each word, but also
storing a concatenation of each word and it's two adjacent words, for a
total of up to there entries per word.

Rubicon boasts very comprehensive database compatibility. Supported
databases include the BDE and dbExpress as well as ADO, Advantage,
Apollo, Direct Oracle Access, DBISAM, FlashFiler, Halcyon, Interbase
Express, Interbase Objects, ODBC Express and Topaz. Other databases are
supported through building your own packages. When installing Rubicon
(either demo or full version) be sure to follow the directions to
install it correctly and so it will support your selected database.

Summary
-------

Based on my comparisons between dtSearch and Rubicon, they both perform
about the same in the search speed department. dtSearch's advantage is
in their additional product lines and simpler interface, but you suffer
from less configurability. Rubicon gives you access to every detail of
your search project by providing you with the complete Delphi source and
your choice of databases instead of dtSearch's closed database and DLL.


Database Search Features
------------------------

Many databases provide features to allow you to index and search
documents stored within the database. Oracle offers an additional add-in
to index documents. MySQL by default allows you to search stored text
documents just like you would any other field. DBISAM (a native Delphi
BDE replacement with no deployment) now has text indexing and searching
as well.


Conclusion
----------

Searching a shorter and well organized index is much quicker then
searching an entire document. Creating and searching an index takes a
lot more planning and effort up front, but quickly pays off if the text
is searched very often. Typically the larger and more complex the index,
the more effective the search. If your index gets too large or complex
then the search speed will degrade.

There are off the shelf searching tools available to end users and
developers alike. dtSearch and Rubicon are both extremely fast and 
useful, but don't let that stop you from designing your own, especially 
if you have a specialized need. 

See also: http://www.dtsearch.com/dtsoftware.html#Art_of_The_Text_Query

________________________________________________________________________

   InstallAWARE 3.0 for Windows Installer by MimarSinan International
 Special time limited offer: 30% off Enterprise Edition, only $559.95!
InstallAWARE is a next generation setup authoring tool with unique 
features such as partial web deployment, Flash and HTML progress
billboards, ten striking setup themes, fully customizable installation
dialogs, and a setup script that automatically gets converted to a
Windows Installer file. >> http://www.installaware.com/landingea.html <<
________________________________________________________________________


4. Extracting Records in a Field into a TStringList

   By Stewart Moss <stewart at new-heights.co.za>
      http://www.new-heights.co.za/

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

Often the programmer needs a quick and dirty method to extract a set of
records from a specific field in a dataset in a convenient way.

Examples of this in my own programming are when I needed to populate a
TListBox or TComboBox (on a modal form) with values that the user can
select for reporting or other purposes.

This simple class is a safe and convenient way to do this. The current
record in the dataset is restored, and the dataset's active state (ie
open or closed).

A demo application is also included with this issue's source code zip.


Implementation
--------------

The code simply gets a TField object from a specified field name
(property called "FieldName") belonging to the dataset (property called
"Dataset") and iterates through the records returning each value in the
field, from start to finish.

The TField class is handy because it allows us to handle any field type
based on any dataset :)

Only datatypes which support the .AsString method (ie not blobs) are
returned.

A boolean property of the class (called "emptyNulls") will allow you to
return blank rows if found. This is useful if you need to return the
"offset" in the dataset of the required record (ie matching
DataSet.RecNo) or if blank rows are meaningful.

The output is in a read only property called Strings of type
TStringList. This property can be used to directly populate a TListBox
or even Strings.SaveToFile(). The output is based on system formatting
variables (for dates etc) so beware!

The Refresh method is fired then the Strings property is read and the
list needs to be refreshed. This happens when you change the dataset or
the fieldname for the first time, you can also call this manually.

The output can be padded with leading and trailing and leading strings.
This is useful if you need to pad the text for formatting. However this
padding needs to be removed from the return of the TListBox or TComboBox
(for use in lookup queries etc). Honestly I don't use this this padding
feature in my own code.

The class has a method called "quickSearch", this allows you to perform
a lookup based on any return value. This is just a wrapper of the
TDataset.Locate() on the current dataset. For example you could present
all CustomerNames in a drop down list, and quickSearch() will allow you
to locate the CustomerID of the selected CustomerName. The lookup is
returned as a String.


Example of Usage
----------------

This populates the TListBox called SrcList on TfrmSelectData with the
names of the active stock as returned from the TQuery named
qryPortfolio. Then performs a lookup to determine the StockID of the
stock name.

procedure TFormMain.thingy;
var
  StockID, StockName : string;
  DatasetExtract : TDatasetExtract;
begin
  DatasetExtract := TDatasetExtract.Create;
  try
    // any field
    DatasetExtract.FieldName := 'StockName';
    // any dataset
    DatasetExtract.DataSet := qryPortFolio;

    // create the form
    with TfrmSelectData.Create(Self) do 
    begin
    
      // add a copy of the DatabaseExtract TStringlist to the TListBox
      // Getting the strings could generate an exception.
      SrcList.Items.AddStrings(DatasetExtract.Strings);
      
      // show the form
      ShowModal;
      
      // if he pressed ok
      if ModalResult = mrOK then
      begin
      
        // Return the stock name from the selected index in the list
        StockName := SrcList.Items[SrcList.selectedindex];
        
        // Lookup the StockID from qryPortfolio query using the class
        StockID := DatasetExtract.Search('StockName', StockName, 
                   'StockID',[]);
        
        showmessage('The StockID of '+StockName+' is '+StockID);
      end;
      free;
      
    end;                                //with

  finally
    DatasetExtract.free;
  end;
end;  


Class Code
----------

{-----------------------------------------------------------------------
 Unit Name: unitDatasetExtract2

 Modification Date: 18 December 2004
 Creation Date: 04 June 02 00:39:21
 Documentation Date: 04 June 02 00:39:21

 Release Date: 15 Jan 2003
 Version: 2.0

 Author: Stewart Moss

 Compiler version:
  Delphi 5 and Delphi 6 tested

 Purpose:
  To Extract a specific field from a dataset in a TStringList. Useful
  for populating TListBoxes that you dont want to be data aware...
  (Released originally on Delphi3000.com)

 Description:
        At the moment it only support TStringLists. It will convert
        most TField.FieldType into a string

 Notes:

 Dependancies:

 History:
  15 Jan 2003: Posted at wwww.delphi3000.com. Article number 3512.
               1122 visits by Dec 2004

          Copyright 2002, 2003, 2004 by Stewart Moss
          All rights reserved.
          You must not modify this Unit Header.
-----------------------------------------------------------------------}
unit unitDatasetExtract2;

interface

uses Classes, db{$IFDEF VER140}, Variants{$ENDIF};

type
  TDatasetExtract = class
  private
    fEmptyNulls: boolean;
    recPos: integer;
    fFieldname,
      fappend,
      fprepend: string;
    fDataset: TDataset;
    fStrings: TStringList;
    refreshed: boolean;

    function FieldToString(Field: TField): string;

    function Get_Strings: TStringList;
    procedure Set_Dataset(const Value: TDataset);
    procedure Set_Fieldname(const Value: string);

  public
    constructor create;
    destructor destroy; override;

    procedure Refresh;
    function Search(searchField, searchValue, ReturnField: string; 
                                 Locateoptions: TLocateOptions): string;

  published
    // You have the option of appending and prepending any information
    // to the begining of each record.
    // Useful for creating delimited records easily (ie you can just add
    // the StringList items together) (maybe not really that useful :P )
    property append: string read fappend write fappend;
    property prepend: string read fprepend write fprepend;

    // Whether or not nulls must be translated into blank values,
    // or ignored
    property EmptyNulls: boolean read fEmptyNulls write fEmptyNulls 
      default true;

    // The field name to return in the string list
    property FieldName: string read fFieldname write Set_Fieldname;

    // The dataset of the field
    property Dataset: TDataset read fDataset write Set_Dataset;

    // This is the TStringList output of the class. Reading this string
    // triggers the action of the class.
    property Strings: TStringList read Get_Strings;
  end;

implementation

uses Sysutils;                          // allow exception objects

{ TDatasetExtract }

constructor TDatasetExtract.create;
begin
  fDataset := nil;
  fStrings := TStringList.create;
  EmptyNulls := true;                   // allow null rows by default
  refreshed := false;                   // we do not have data
end;

destructor TDatasetExtract.destroy;
begin
  fStrings.free;
  inherited;
end;

procedure TDatasetExtract.Refresh;
{-----------------------------------------------------------------------
  Procedure: TDatasetExtract.Refresh

  Starts at the beginning of the record set and appends the required
  field in each consecutive record to the string list using the TField.
 ----------------------------------------------------------------------}
var
  Field             : TField;
  isactive          : boolean;
begin
  with fDataset do
  begin
    try
      // turn off any data-aware components related to current dataset
      disablecontrols;

      // save Dataset open state
      isactive := fDataset.Active;
      if not isactive then
        fDataset.open;

      // Save our current place in the dataset
      recPos := RecNo;

      // go to the start
      First;
      while not eof do
      begin
        // Get the TField object for field FieldName at
        // the current position (we don't care what type)
        Field := FieldByName(fFieldname);

        // Ok is it null?
        if not varisnull(Field.asvariant) then
          // use our "safer" .AsString
          fStrings.add(fprepend + FieldToString(Field) + fappend)
        else if EmptyNulls then
          // we are allowed to insert nulls
          fStrings.add(fprepend + fappend);
        next;
      end;                              // while not eof
    finally
      // Restore our current place in the dataset
      RecNo := recPos;

      // if the dataset was closed then close it
      if not isactive then
        fDataset.close;

      // turn on the data-aware components related to current dataset
      enablecontrols;
    end;                                // finally
  end;                                  // with fDataset
end;

function TDatasetExtract.FieldToString(Field: TField): string;
{-----------------------------------------------------------------------
  Procedure: TDatasetExtract.FieldToString
  Arguments: Field: TField
  Result:    string

 This actually reads the field from the database and swallows any 
 EDatabaseErrors.
 ----------------------------------------------------------------------}
begin
  try
    result := Field.AsString;
  except
    on e: EDatabaseError do
    begin
      // nothing
    end
  else
    // re-raise the exception if it is something else
    raise;
  end;
end;

function TDatasetExtract.Get_Strings: TStringList;
begin
  result := fStrings; // always return what you have (even if exception)

  if refreshed then                     // if we have clean data
    exit;                               // then we are done

  fStrings.clear;

  if (fDataset = nil) or (fFieldname = '') then
    // uber cool error message
    raise exception.create(self.ClassName +
      ': Two manditory fields not supplied');

  Refresh;
end;

function TDatasetExtract.Search(searchField, searchValue, 
            ReturnField: string; Locateoptions: TLocateOptions): string;
{-----------------------------------------------------------------------
  Procedure: TDatasetExtract.quickSearch
  Arguments: searchField, searchValue, ReturnField : string;
              Locateoptions: TLocateOptions
  Result:    string

  Searches for a field value in a specified field name and returns the
  specified field returns '' is nothing is found.

  eg
    Ask for a customer id of 10 and return the customer name
 ----------------------------------------------------------------------}
var
  isactive          : boolean;
begin
  with fDataset do
  begin
    // turn off any data-aware components related to the current dataset
    disablecontrols;

    // save Dataset open state
    isactive := fDataset.Active;
    if not isactive then
      fDataset.open;

    try
      result := '';
      First;
      if not locate(searchField, searchValue, Locateoptions) then
        exit;

      // use our "safer" .AsString method
      result := FieldToString(FieldByName(ReturnField));
    finally
      // our current place obeys TDataset.Locate()

      // if the dataset was closed then close it
      if not isactive then
        fDataset.close;

     // turn on any data-aware components related to the current dataset
      enablecontrols;
    end;
  end;
end;

procedure TDatasetExtract.Set_Dataset(const Value: TDataset);
begin
  fDataset := Value;
  refreshed := false;                   // we are dirty again
end;

procedure TDatasetExtract.Set_Fieldname(const Value: string);
begin
  fFieldname := Value;
  refreshed := false;                   // we are dirty again
end;

end.

________________________________________________________________________

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


5. Returning Classes from a DLL

   By Max Kleiner <max@kleiner.com>
   Kleiner Kommunikation Reference: http://max.kleiner.com/
   Component Download: http://max.kleiner.com/download/dllplus.zip

  
Question/Problem/Abstract:
--------------------------

Export an object-reference from a DLL is one approach to get real
OO-access to a DLL. The DLL must create and return the object, so the
client gets the methods without encapsulating. Let's see how this
framework, called DLL+, works...


Answer:
-------

There is also an example uploaded with UML-Diagrams (*.tif) from
ModelMaker. We always work with MM since we had to redesign a big
project.

First, we have to built an abstract class in a separate unit (see below
the same with a real interface). You might consider this unit like an
interface:

unit income1;
interface
type
  IIncome = class
  public
    function GetIncome(const aNetto: Currency): Currency;
                                                      virtual; abstract;
    procedure SetRate(const aPercent, aYear: integer);
                                                      virtual; abstract;
    function queryDLLInterface(var queryList: TStringList):
                                         TStringList; virtual; abstract;
  end;

Second we built the DLL in a new unit (*.dpr) with the corresponding
class, which has to implement the methods from the interface:

type
  TIncomeReal = class(IIncome)
  private
    FRate: Real;
  public
    constructor Create;
    function GetIncome(const aNetto: Currency): Currency; override;
    procedure SetRate(const aPercent, aYear: integer); override;
...

And now comes the export, cause objects in DLL+ are created by calling a
global Constructor function, you can see that returning objects from the
function that creates them is acceptable by the client:

{-------------------------------------------------------------}
function CreateIncome: TIncomeReal; stdcall;
begin result:= TIncomeReal.Create; end;

exports CreateIncome resident;
begin {fake} end.
{-------------------------------------------------------------}

At last we take a look at the client. In managing objects the client
consider who owns the object and is responsible for freeing it up:

Uses income1;
  private
    IncomeRef: IIncome; //member
...

function CreateIncome:IIncome; stdcall; external('income.dll');
...
procedure TfrmIncome.FormCreate(Sender: TObject);
  begin
  IncomeRef:=createIncome;
end;

So the access is easy, stable and improves maintenance of the DLL. It
should be mandatory to implement a function called queryDLLInterface, in
order to reproduce the interface and all the parameters in case of lost
(see example).

procedure TfrmIncome.BitBtnOKClick(Sender: TObject);
begin
  incomeRef.SetRate(strToInt(edtZins.text), strToInt(edtJahre.text));
  cIncome:= incomeRef.GetIncome(StrToFloat(edtBetrag.Text));
  edtBetrag.text:= Format('%m',[cIncome]);
end;



Calling an Interface
--------------------

Now the client calls an InterfaceReference:

private
  incomeIntRef: IIncomeInt;

procedure TfrmIncome.BitBtnOKClick(Sender: TObject);
begin
  incomeIntRef:=createIncome;
  try
    with incomeIntRef do begin
    if QueryInterface(IIncomeInt, incomeIntRef) = S_OK then begin
      SetRate(strToInt(edtZins.text), strToInt(edtJahre.text));
      cIncome:=strTofloat(edtBetrag.text);

The Unit Income1 is enlarged with the interface:

  IIncomeInt = interface (IUnknown)
    ['{DBB42A04-E60F-41EC-870A-314D68B6913C}']
    function GetIncome(const aNetto: Currency): Currency; stdcall;
    function GetRate: Real;
    function queryDLLInterface(var queryList: TStringList):
                                                   TStringList; stdcall;
    procedure SetRate(const aPercent, aYear: integer); stdcall;
    property Rate: Real read GetRate;
  end;

The DLL now exports a real Interface-Pointer:

  TIncomeRealIntf = class (TInterfacedObject, IIncomeInt)
  private
    FRate: Real;
    function Power(X: Real; Y: Integer): Real;
  protected
    function GetRate: Real;
  public
    constructor Create;
    destructor destroy; override;
    function GetIncome(const aNetto: Currency): Currency; stdcall;
    function queryDLLInterface(var queryList: TStringList):
                                                   TStringList; stdcall;
    procedure SetRate(const aPercent, aYear: integer); stdcall;
    property Rate: Real read GetRate;
  end;

function CreateIncome: IIncomeInt; stdcall;
begin
  result:= TIncomeRealIntf.Create;
end;

When n-classes implements one interface push a parameter to the export
routine in the DLL:

function CreateIncome(intfID: byte): IIncomeInt; stdcall;
begin
  case intfID of
  1: result:= TIncomeRealIntf.Create;
  2: result:= TIncomeRealSuper.Create;
  3: result:= TIncomeRealSuper2.Create;
  end;
end;

exports CreateIncome;

Client-calling looks like this:

  incomeIntRef := createIncome(3);

________________________________________________________________________

       KnowedgeBASE Vortex 2.9 by Delphinium Software ($49.35 US)
  KnowledgeBASE Vortex 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/KnowledgeBase-Vortex/3000-2064-10342084.html
________________________________________________________________________


6. Simplified Collision Detection in Game Programming

   By John Pears <j.pears@coventry.ac.uk>

The, so called, 'simple collision detection algorithms' only detect
collisions between two rectangles yet the most simple of them seem to be
over complicated. Each sprite has x and y coordinates (usually the 
centre of the sprite) and a rectangle used for placing the image.
Sometimes, a separate 'bounding rectangle' is used for collision 
detection.

Each time the sprite's x,y is moved, the positions of the rectangle(s)
have to recalculated. The collision detection then tests left, top, 
right and bottom of BOTH sprites rectangles to see if a collision
occurred. All of this has to be done for each sprite on each step of the
game.

How about only moving the x,y (centre) of the sprite and "fixing" the 
offsets to the left and top?

Consider the following data structure:

type
  TSpriteRec = record
  Centre : tpoint;
  OffSet : tpoint; // never changes unless change of image.picture
  Image : TImage;
  end;
var
  Invader : array[1..A_NUMBER] of tSpriteRec;
  Rocket : array[1..ANOTHER_NUMBER] of tSpriteRec;


Placing the sprite becomes:

  Image.Left = ( Centre.x - OffSet.x );
  Image.Top = ( Centre.y - OffSet.y );

No more code, its there, job done, the offsets never change.

We can now write a simple function to detect collision:

Function Collided(Spr1, Spr2 : TSpriteRec) : Boolean;
begin
  result :=
  (abs(Spr1.Centre.x-Spr2.Centre.x) < (Spr1.OffSet.x+Spr2.OffSet.x)) and
  (abs(Spr1.Centre.y-Spr2.Centre.y) < (Spr1.OffSet.y+Spr2.OffSet.y));
end;

And, our main code becomes:

  if Collided (Rocket[10], Invader[77]) then begin
    // some code
    end;

The demo application included in this issue's source code zip is a 
simple 'Space Invaders' type game. It was written with Delphi 6 and has
no DirectX or DelphiX. It is just raw Delphi moving TImages around.
The code is not identical to the above examples but the principle is.

In the demo try changing the following constants in U_Sprites.pas:

INVADER_COLS = 16;
INVADER_ROWS = 6;

________________________________________________________________________

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


7. 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

________________________________________________________________________

Delphi-PRAXiS · One of the fastest growing German Delphi-forums, with
unique services like our "Delphi-PRAXiS Expert" (add-on which allows
access to our libraries directly from within the IDE). Our database
contains more than 50,000 articles. >>> http://www.delphipraxis.net <<<
________________________________________________________________________


8. Delphi on the Net

   By Dave Murray <irongut at vodafone dot net>


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

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

* InstallAWARE 3.0 for Windows Installer - by MimarSinan International
  Develop setups for Windows Installer without any knowledge of MSI!
  InstallAWARE automatically converts a conditionally flowing script
  into a logo certifiable, ICE-compliant MSI database at build time.
  The IDE features a visual UI which generates your setup script for
  you automatically and you can fully customize the script behavior.
  Special limited offer: 30% off all editions, Enterprise only $559.95!
  http://www.installaware.com/landingea.html

* KnowedgeBASE Vortex 2.9 by Delphinium Software ($49.35)
  KnowledgeBASE Vortex 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/KnowledgeBase-Vortex/3000-2064-10342084.html

* 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/


Freeware
--------

* CSV Parser v1.0 - by Patrick Beekmans (with source)
  Parse any CSV-file with this component. You have the ability to choose
  the desired separator. This component has three events: 
  OnNewColumnHeader, OnNewRow and OnNewValue.
  http://www.torry.net/vcl/vcltools/text/PBParsers.zip

* GExperts v1.21 - by GExperts Inc. (with source)
  GExperts is a set of open source tools that increase productivity by
  adding features to the IDE. Includes: Editor Experts to find matching
  delimiters, insert unit headers, etc; IDE enhancements that add a
  Windows menu and show hidden menu items; Palette enhancements that add
  multi-line tabs or add tabs to the context menu; and much more. Now
  supports Delphi 5/6/7/8/2005 and C++Builder 6.
  http://www.gexperts.org/

* Indy v10.0.51 - by The Indy Pit Crew (with source)
  Open source suite of more than 120 protocols and Internet standards.
  Each protocol is robust with rich support, the need to add additional
  support to existing protocols is rare. Indy is easy to use because it
  uses blocking sockets; everything happens in a sequence, just like
  accessing a file. Now supports .Net.
  http://www.indyproject.org/Sockets/index.en.html

* PGP Components for Delphi v4.0.1 - Michael in der Wiesche (w. source)
  Provides a Delphi (2-7) direct interface to PGP 6.5.x, 7.x or 8.x. New
  in Version 4.0.1: Checking and restarting of the PGPsdkService have
  been fixed, modified and enhanced; Error handling in TPGPDecode's data
  analysis has been slightly adjusted for special cases.
  http://idw-doc.homepage.t-online.de/PGPcomp.htm

* ProDelphi v17.3 - by Helmuth J. H. Adolph
  Source code profiler for Delphi (runtime measurement). Features 
  include: Cyclic storage of measurement results for long period 
  measurement; Open the source in the Delphi editor by clicking a 
  procedure in the viewer; Conditional compilation; Integrated into the
  Delphi IDE; Measures runtimes in DLL's; Delphi 2005 Win32 supported.
  http://www.prodelphi.de/

* ProDelphi.Net v3.0 - by Helmuth J. H. Adolph
  Source code profiler for Delphi 8 and Delphi 2005. It has the same 
  features as ProDelphi except measuring functions written with the 
  inline assembler (not supported for .Net platform).
  http://www.prodelphi.de/

* TscFontCombobox v1.1 - by Stefan Cruysberghs (with source)
  An advanced combobox which shows the available Windows fonts. A lot of
  features for preview, used fonts, show font types (truetype, printer, 
  symbol), etc are provided. This component provides all features of the
  Microsoft and Corel font combobox.
  www.torry.net/news.php?id=26&SID=d05e863b8b4107c854fa651e2bbfdeaa

* Vector Graphics ActiveX v1.6.0 - by Stas Semenov
  A graphics component for creating technical drawings, illustrations 
  and presentation, training material and business reports, charts and
  diagrams and more. Based on Layer-Class-Shape architecture that
  repeatedly reduces the size of the stored data, to increase speed of
  loading and displaying documents, and also to provide excellent speed of
  execution with documents containing around 1,000,000 shapes.
  http://www.script-debugger.com/

* XP Graph v2.1	- by JLx Soft
  A Delphi Chart component equal like that one in Windows' task manager 
  with bar and history, plus additional extensions.
  http://comps.jlxsoft.com/


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

* Delphi 2005: The Ultimate Delphi
  The complete development solution for Windows. With all of the Windows
  languages and SDKs you need in one environment for modern Windows
  rapid application development (RAD), Delphi 2005 takes the power of
  Delphi to the next level. With Delphi, C#, Microsoft .NET Framework
  and Win32 support for GUI, Web, database, modeling, and ALM in one
  hyperproductive RAD environment, Delphi 2005 makes Windows development
  tasks faster, better, and easier.
  http://www.borland.com/delphi/


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

* BDNradio: Delphi 2005 Live Chat on Interop with Chris Bensen
  In this audio replay, Chris discusses his work on ActiveX, COM, .NET
  interop, VLI and the New Component wizard.
  http://community.borland.com/article/0,1410,32858,00.html

* BDNRadio: Log from Chat with Corbin Dunn on Delphi 2005 IDE Features
  Read the chat room log for questions answered by Corbin on Delphi 2005
  IDE features, and listen to the replay.
  http://community.borland.com/article/0,1410,32850,00.html

* BDNRadio: Delphi 2005 IDE Chat with Allen Bauer
  This is a log for the live audio chat from November 24th 2004 on
  Delphi 2005 with Allen Bauer, a Borland Principal Engineer, and
  Delphi IDE architect. Allen discusses his work on Delphi 2005.
  http://community.borland.com/article/0,1410,32843,00.html

* Delphi 2005 Fixes for QualityCentral Bug Reports
  There are currently 263 QualityCentral bug reports closed with the
  release of Delphi 2005.
  http://community.borland.com/article/0,1410,32837,00.html

* Namespaces in Delphi 2005
  To make Delphi code friendlier towards other .NET languages Borland
  has changed the way Delphi 2005 produces namespaces. This article
  discusses the changes that have been made and how they affect you.
  http://community.borland.com/article/0,1410,32765,00.html

* Advanced Markup Language Generation for IntraWeb
  Describes how to use an undocumented feature in IntraWeb to create
  complex controls that require multiple tags.
  http://community.borland.com/article/0,1410,32758,00.html

* BDNradio: Chat Room Log of Live Chat with Danny Thorpe on Delphi 2005
  This is the chat log for the live audio chat from November 19th 2004
  on Delphi 2005 with Danny Thorpe, a Borland Chief Scientist and
  architect of the Delphi compilers. Danny discusses changes and
  enhancements to the Delphi Win32 and Microsoft.NET compilers, the run
  time framework and .NET support in general.
  http://community.borland.com/article/0,1410,32789,00.html

* Using XMLDoc For API Documentation And HelpInsight With Delphi 2005
  How to use Borland's XMLDoc tool to quickly and easily document your
  software and generate HelpInsight for your components.
  http://community.borland.com/article/0,1410,32770,00.html

* What's New in Delphi 2005 - by Bob Swart
  A Technical White Paper on all that's new in Delphi 2005.
  http://community.borland.com/article/0,1410,32778,00.html

* Building a custom data provider for .Text
  A case study on the porting of .Text from SQL Server to InterBase
  using Delphi for .NET.
  http://community.borland.com/article/0,1410,32419,00.html

* Borland Conference 2004 Blogs
  An impressive compilation of blog entries that were created during
  BorCon 2004. It's not as good as being there, but it's close.
  http://community.borland.com/article/0,1410,32752,00.html

* How to Check if a Document in a TWebBrowser is Located on a Local
  (or Network) Drive - by Zarko Gajic
  If you need to know the location of a document displayed in a
  TWebBrowser component, you need to get the Protocol property of the
  IHTMLLocation. Here's a function that returns true if a document in a
  WebBrowser is stored locally.
  http://delphi.about.com/od/adptips2004/a/bltip1204_5.htm

* Using the TDBGrid Component - by Zarko Gajic
  Contrary to most other Delphi data-aware controls the DBGrid component
  has many nice features and is more powerful than you would have
  thought. There are many ways to customise the output of a DBGrid...
  http://delphi.about.com/od/usedbvcl/a/tdbgrid.htm

* Retrieving All Image Links from an HTML Document - by mrbaseball34
  Here's how to obtain all image links from an HTML document using Indy.
  http://delphi.about.com/od/adptips2004/a/bltip1204_3.htm

* Making Delphi 2005 Independent from .NET - by Alvaro Garcia Pascual
  Despite what Borland says, Delphi 2005 doesn't require .NET. If you
  are a Delphi Win32 developer and don't like that Delphi 2005 comes
  polluted with .NET stuff, read this article to learn how to remove
  .Net from Delphi 2005.
  http://delphi.about.com/od/delphifornet/a/delphi2005win32.htm

* A First Look at Delphi 2005 - by Zarko Gajic
  The time has come to take a sneak peak into a new Delphi version:
  Delphi 2005. Delphi 2005 is the ultimate weapon for developers:
  Delphi, C#, Win32 and .NET in one RAD environment.
  http://delphi.about.com/od/productreviews/ss/delphi2005first.htm

* How to write a Ping utility using ICMP.dll - by Serge Perevoznyk
  Raw Sockets are subject to security checks and are accessible only to
  members of the administrator's group. Icmp.dll provides functionality
  that allows developers to write Internet ping applications on Windows
  systems without Winsock 2 support and without security problems.
  http://www.delphi-central.com/tutorials/icmp-ping.aspx

* How To Find an Item in a Tree Control Via its Label - Serge Perevoznyk
  The "tree view" control does not have a built-in method for searching
  the entire tree or for selecting an item given its label. This article
  provides code that returns the location of any item in a tree when
  given a specific label to search for.
  http://www.delphi-central.com/tutorials/FindTreeViewNode.aspx


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

* Installable Delphi 2005 Examples
  Download an installation for dozens of tested Delphi 2005 examples for
  use directly from the IDE. These examples include the C# and Delphi
  languages and both the Win32 and .NET platforms with text that
  introduces and explains them.
  http://community.borland.com/article/0,1410,32857,00.html

* BDNtv: C++Builder in Delphi
  In this quick preview, Troy Kitch shows integration of C++Builder
  features in Delphi 2005. Flash
  http://bdntv.borland.com/cppbuilder/CPPinDelphi8x6.html

* BDNtv: Unit testing in Delphi 2005
  This BDNtv episode shows the unit testing integration for DUnit for a
  Delphi/Win32 application in Delphi 2005. Unit testing for C#, Delphi
  for .NET, and Delphi for Win32 with both NUnit and DUnit are supported
  in Delphi 2005. Flash
  http://dotnet.borland.com/bdntv/delphi/d2005unittesting8x6.html

* GOF Behavioural Patterns with C#: Part 1 - by Barry Mossman
  This is the third article in a series upon the GOF Design patterns
  from a C# and .Net Framework perspective. It is covers some of the
  Behavioral Patterns: Chain of Responsibility, Command, Interpreter.
  http://community.borland.com/article/0,1410,32710,00.html

* GOF Behavioural Patterns with C#: Part 2 - by Barry Mossman
  This is the fourth article in a series upon the GOF Design patterns
  from a C# and .Net Framework perspective. It is a continuation of the
  Behavioral Patterns this time looking at Iterator, Mediator, Observer
  and Memento (Momento) patterns.
  http://community.borland.com/article/0,1410,32795,00.html

* Deriving a Model From an Existing Database with ECO II in Delphi 2005
  Henrik Jondell demonstrates how easy it is to create model-powered
  applications for your existing databases with ECO II. Flash
  http://dotnet.borland.com/bdntv/delphi/eco2modelderivation.html

* An Introduction to COM Programming with Delphi (1/6) - by Curtis Socha
  A brief historical rundown on COM's glorious past. Abstract methods
  vs. Interfaces. Classes and Interfaces: An interesting paradox.
  http://delphi.about.com/library/weekly/aa112304a.htm

* An Introduction to COM Programming with Delphi (2/6) - by Curtis Socha
  What is an Interface? How to implement an Interface? Describing the
  TInterfacedObject.
  http://delphi.about.com/library/weekly/aa113004a.htm

* An Introduction to COM Programming with Delphi (3/6) - by Curtis Socha
  What is the implements directive? What is the Method Resolution
  Clauses? Pseudo-Multiple Interface Inheritance. Interface properties
  and other fine tales of horror.
  http://delphi.about.com/library/weekly/aa120704a.htm

* An Introduction to COM Programming with Delphi (4/6) - by Curtis Socha
  A Com Object walk-a-bout. A Class Factory tour. Our first true COM
  Object program. Homework Assignment.
  http://delphi.about.com/library/weekly/aa121404a.htm

* An Introduction to COM Programming with Delphi (5/6) - by Curtis Socha
  Marshaling Data. Oh, the glory of leadership! Variant Reference Page.
  Using Variants and Variant Arrays.
  http://delphi.about.com/library/weekly/aa122104a.htm

* Programming a Memory Game in Delphi: Part 1 - by Delphi Central
  In this tutorial, we will see how the TDrawGrid component can be used
  to help us develop a "Memory" game. Firstly we will describe what is
  involved with the Memory game.
  http://www.delphi-central.com/tutorials/memory_game.aspx

* Programming a Memory Game in Delphi: Part 2 - by Delphi Central
  In part 1 we explained how to create the form and drawgrid at design
  time. Now we will move onto writing the actual code.
  http://www.delphi-central.com/tutorials/memory_game_2.aspx

* Programming a Memory Game in Delphi: Part 3 - by Delphi Central
  In part 1 we explained how to create the form and drawgrid at design
  time, in part 2 we started writing the actual code. In the third part
  of the tutorial we will draw the grid that the game is played on.
  http://www.delphi-central.com/tutorials/memory_game_3.aspx


News
====

* Delphi 2005 Architect Review
  Delphi has grown up since it launched nearly ten years ago. The latest
  version provides support for developing Win32 and .NET applications as
  well as supporting the C# language. There are many enhancements to
  almost all areas with the main goal of increasing developer
  productivity.
  http://www.builderau.com.au/program/0,39024614,39170720,00.htm

* Global 2000 Companies Select Borland to Elevate Software Quality
  An unprecedented number of high-profile customers spanning a wide
  spectrum of industries and regions selected CaliberRM and StarTeam in
  2004 as their preferred requirements management and software
  configuration and change management solutions. Companies that selected
  CaliberRM or StarTeam this year include: British Telecom, Comcast,
  EDS, Gap, HP, Jaguar Cars, Siemens AG, Symantec and Verizon Wireless.
  http://home.businesswire.com/portal/site/google/index.jsp?
  ndmViewId=news_view&newsId=20041206005289

* BDNradio Interviews with Borland's R&D staff for Delphi 2005
  Don't miss these live interviews with Borland R&D engineers.
  http://community.borland.com/article/0,1410,32786,00.html

* Software Delivery Optimisation Enables Disciplined Approach
  At the Borland Conference 2004, Dale Fuller, President and CEO,
  presented their vision and product strategy for transforming software
  development from an unpredictable art form into a more manageable and
  repeatable business process.
  http://www.itweb.co.za/sections/business/2004/0411150801.asp

* Borland's ALM Products Receive Numerous Accolades in 2004
  Borland today announced 2004 as a banner year for its products, with
  receiving numerous industry accolades and awards from around the
  globe. Industry recognition of their innovative solutions provides the
  company with significant momentum leading into 2005 and underscores
  their ongoing focus on technical excellence and customer value.
  http://home.businesswire.com/portal/site/google/index.jsp?
  ndmViewId=news_view&newsId=20041110005673&newsLang=en

* Borland to Provide UML Support to MS Visual Studio 2005 Team System
  Borland joined Microsoft and other industry leaders in announcing
  support and future plans for Software Factories, a new industry
  approach to improve software development. As part of Borland's support
  for Software Factories, the company plans to deliver a domain-specific
  modeling solution providing UML capabilities within the Microsoft
  Visual Studio 2005 Team System.
  http://www.tmcnet.com/usubmit/2004/Oct/1087428.htm

* Borland Focuses on UML Modeling
  Borland is breaking up Together ControlCenter for UML modeling into
  separate products for developing, designing, and architecting
  applications. The move is intended to align Together with the SDO
  strategy of providing a disciplined approach to development.
  http://www.infoworld.com/article/04/10/25/HNborcontrolcenter_1.html

* IBM and Borland Upgrade Developer Tools
  IBM unveiled new Rational developer tools and Borland rolled out the
  new version of its Delphi Windows development tool. Both are
  maneuvering to infuse their platforms with business process automation
  commonly used in other areas of enterprise operations.
  http://www.computerweekly.com/articles/article.asp?liArticleID=134236

* Native Win32 and .Net Framework Support for New Delphi
  Delphi, the grand-daddy of visual programming environments, has been
  updated. Delphi 2005 works with both Win32 and .Net frameworks, and
  also supports Microsoft's C# as well as the Delphi language itself.
  http://www.pcpro.co.uk/news/64469/
  native-win32-and-net-framework-support-for-new-delphi.html


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

* The Daily WTF: Curious Perversions In Information Technology
  The Daily WTF presents scary code examples. If you are looking for a
  good laugh visit the site, I just hope your code is not there! :)
  http://thedailywtf.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.latiumsoftware.com/en/pascal/delphi-newsletter.php

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
http://top200.jazarsoft.com/delphi/rank.php3?id=latium

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 but we are particularly
interested in articles about Kylix because there is so little available
online to help Kylix developers. Send articles 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 on the Latium Software
and Irongut's Delphi Pages websites. 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.latiumsoftware.com/download/p0052.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.latiumsoftware.com/en/legal.php
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.latiumsoftware.com/en/pascal/delphi-newsletter.php
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
________________________________________________________________________

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

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