Home

News

Articles

Forums / Groups

Mozilla-Delphi Project

Pascal Newsletter
Issue 51
Back Issues

Software

Links

Search

Vote For Us:
Irongut's Delphi Pages
Pascal Newsletter

Contact Details

Legal Stuff

News Archive
Pascal Newsletter Issue 51
Pascal Newsletter #51 - 12-OCTOBER-2004

Contents

1. A Few Words From the Editors
2. How to Run a Single Instance of an Application (Part 2)
3. Inside Delphi's Classes and Interfaces (Part 2)
4. Forums / Mailing Lists
5. Delphi on the Net
   - Components, Libraries and Utilities
     - Shareware / Commercial
     - Freeware
     - Borland Product Updates
   - Articles, Tips and Tricks
   - Tutorials and Training
   - News
   - Other Links

________________________________________________________________________


1. A Few Words From the Editors


Welcome to another issue of the Pascal Newsletter. As usual we'd like to
thank the authors who contributed articles for this issue, Peter Johnson
and Ezra Hoch. And, we're pleased to award Ezra the prize for this
issue:

* Ezra Hoch - 'Inside Delphi's Classes and Interfaces'
  Delphi SWF SDK (Standard) v1.4 - by FeatherySoft ($170)
  Object Pascal library for creating SWF files, without using of any
  external dynamic libraries. Released features: visual objects (shape,
  button, text, morphing shape, sprite); all types of filling (solid,
  gradient, image); device and embedding fonts; action commands;
  sound (events, streaming); video; any transition and transformation.
  http://www.delphiflash.com/

In the next issue we have two prizes up for grabs. We don't have any
submissions yet and can't publish without your help so why not write an
article and get yourself some quality tools at the same time as
supporting your favourite newsletter. Those prizes include:

* 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

We are also looking for shareware authors who would like to offer their
components or applications as prizes. In return you will be promoted in
the newsletter and on the Latium Software and Irongut's Delphi Pages
websites.

Late Breaking News: Today Borland announced Delphi 2005 (Diamondback)
will ship in November. See 'Delphi on the Net' for a news link.

Thanks for reading, now on to the code...

Regards,

Dave Murray and Ernesto De Spirito
pascal-newsletter-owner@yahoogroups.com

__________________

Collaborated in this issue: Peter Johnson and Ezra Hoch

________________________________________________________________________

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 Run a Single Instance of an Application
   Part 2: A Re-usable Solution

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


Overview of an Object Oriented Solution
---------------------------------------

This section presents an object oriented, extensible, solution to the
problem of running a single application instance.

The main code is centralised in a single unit (USingleInst.pas) that
implements and creates a singleton object (TSingleInst) that manages the
single application instance and takes care of sending and receiving
parameter data. While TSingleInst provides a name for the main form's
window class, the window class name method can (and should) be
overridden to provide a unique class name. A watermark can also be
provided by overriding a method.

Some alteration of the project file and main form file is required, but
the changes are not as significant as in the earlier example and the
main functionality is isolated in USingleInst.pas.

The procedure for enabling single application instance support in a
project that uses USingleInst.pas is as follows:

* Add USingleInst.pas to the project.
* Create a new class derived from TSingleInst and override the methods
  that return the window class name and (optionally) the watermark.
* Register the new class as the one to use when creating the SingleInst
  singleton object.
* Modify the main form and project sources to call the required entry
  points into the SingleInst object.

In the rest of this section we will review the USingleInst unit, then
look at how to derive and register a new class from it and finally
describe the changes to be made to the project source and main form
source files.


The USingleInst Unit
--------------------

We will review parts of the unit in order. The full source of the unit
accompanies this article. Here is the interface part of the unit that
declares the class and supporting functions: 


unit USingleInst;

interface

uses
  Windows, Controls, Messages;

type
  TSingleInstParamHandler = procedure(const Param: string) of object;

  TSingleInstClass = class of TSingleInst;

  TSingleInst = class(TObject)
  private
    fOnProcessParam: TSingleInstParamHandler; // event handler
    fEnsureRestoreMsg: UINT;  // unique message for ensuring restoration
  protected
    function WdwClassName: string; virtual:
    function WaterMark: DWORD; virtual;
    function FindDuplicateMainWdw: HWND; virtual;
    function SendParamsToPrevInst(Wdw: HWND): Boolean; virtual;
    function SwitchToPrevInst(Wdw: HWND): Boolean;
    procedure EnsureRestore(var Msg: TMessage); dynamic;
    procedure WMCopyData(var Msg: TMessage); dynamic;
  public
    constructor Create;
    procedure CreateParams(var Params: TCreateParams);
    function HandleMessages(var Msg: TMessage): Boolean;
    function CanStartApp: Boolean;
    property OnProcessParam: TSingleInstParamHandler
      read fOnProcessParam write fOnProcessParam;
  end;

function SingleInst: TSingleInst;

procedure RegisterSingleInstClass(Cls: TSingleInstClass);


Reviewing the type declarations first, TSingleInstParamHandler is the
type on the OnProcessParam event handler that is triggered for each
parameter passed to the application in a WM_COPYDATA message while
TSingleInstClass is the class type of the TSingleInst and derived
classes. 

We will cover the class's methods in the implementation section. The
only other item worth mentioning now is the fEnsureRestoreMsg field.
This is used to store the id of the custom message used to ask an
application to restore and display its window. The message id is
provided by Windows and guaranteed to be unique. Unfortunately, use of
such a message means we can't use a Delphi message handler to handle the
message and must resort to intercepting messages from the message loop 
(see later).

Finally the SingleInst function is used to return an instance of the
TSingleInst (or descendant) singleton object while
RegisterSingleInstClass is used to register the type of class to be used
to create the singleton. 

We will examine the implementation section in segments. Here is the
first: 


implementation

uses
  SysUtils, Forms;

var
  // Globals storing SingleInst singleton and class of SingleInst
  gSingleInst: TSingleInst = nil;
  gSingleInstClass: TSingleInstClass = nil;

function SingleInst: TSingleInst;
begin
  if not Assigned(gSingleInst) then
  begin
    if Assigned(gSingleInstClass) then
      gSingleInst := gSingleInstClass.Create
    else
      gSingleInst := TSingleInst.Create;
  end;
  Result := gSingleInst;
end;

procedure RegisterSingleInstClass(Cls: TSingleInstClass);
begin
  gSingleInstClass := Cls;
end;


The private global variables gSingleInst and gSingleInstClass store a
reference to the singleton object and the type of the singleton object
(as registered in RegisterSingleInstClass) respectively. 

From the implementation of SingleInst it can be seen that the singleton
object is created the first time the object is referenced. If a derived
object type has been registered this is used to create the singleton,
otherwise the base class is used. This means that any derived
TSingleInst class needs to be registered before the object is first
accessed - it is recommended that RegisterSingleInstClass is called in
the initialization section of the unit where the derived class is
defined. This also explains why the singleton is not created in this
unit's intialization section, since this section would be called before
that in the derived classes unit. 

Moving on to the class definition, we first look at the class constructor
which simply registers the custom message with Windows. 


constructor TSingleInst.Create;
begin
  inherited;
  fEnsureRestoreMsg := 
    RegisterWindowMessage('USINGLEINST_ENSURERESTORE');
end;


There are various "entry points" into the class that must be called from
either the main unit or the project file. We will review these next: 


function TSingleInst.CanStartApp: Boolean;
var
  Wdw: HWND;
begin
  Wdw := FindDuplicateMainWdw;
  if Wdw = 0 then
    Result := True
  else
    Result := not SwitchToPrevInst(Wdw);
end;

procedure TSingleInst.CreateParams(var Params: TCreateParams);
begin
  inherited;
  StrPLCopy(Params.WinClassName, WdwClassName, 
    SizeOf(Params.WinClassName) - 1);
end;

function TSingleInst.HandleMessages(var Msg: TMessage): Boolean;
begin
  if Msg.Msg = WM_COPYDATA then
  begin
    WMCopyData(Msg);
    Result := True;
  end
  else if Msg.Msg = fEnsureRestoreMsg then
  begin
    EnsureRestore(Msg);
    Result := True;
  end
  else
    Result := False;
end;


The first of these "entry points" is CanStartApp which is called from
the project file and indicates whether the application should be started
or not. It works in a similar way to the CanStart function in the 
previous part of this article (Issue #50). 

The CreateParams method sets up the main form's window class name by
updating the form's create parameters. The main form must override its
inherited TForm.CreateParamsSingleInst.CreateParams from within that
method. 

The most complex of the "entry point" methods is the HandleMessages
method. This intercepts the WM_COPYDATA and the custom fEnsureRestoreMsg
from the main form and handles the processing by delegating to
WMCopyData and EnsureRestore respectively (see below). This method
returns true if it handles the given message and false otherwise. The
main form must override the TForm.WndProc method and call
SingleInst.HandleMessages from there, calling its inherited
TForm.WndProc method if HandleMessages returns false. 

Let us now examine the protected helper methods. Firstly we have two
methods that should be overridden in descendant classes: 


function TSingleInst.WdwClassName: string;
begin
  Result := 'SingleInst.MainWdw';
end;

function TSingleInst.WaterMark: DWORD;
begin
  Result := 0;
end;


WdwClassName simply returns the name to use as the window class name of
the main form. This should be overridden to return something unique to
the application. Similarly Watermark returns 0 as the watermark value
(watermarks were discussed in the previous part of this article). This
should be overridden to some unusual value if watermarks are to be used.

Next up are the two message handling helper methods:


procedure TSingleInst.EnsureRestore(var Msg: TMessage);
begin
  if IsIconic(Application.Handle) then
    Application.Restore;
  if Assigned(Application.MainForm) and not Application.MainForm.Visible
    then Application.MainForm.Visible := True;
  Application.BringToFront;
end;

procedure TSingleInst.WMCopyData(var Msg: TMessage);
var
  PData: PChar;
  Param: string;
begin
  if TWMCopyData(Msg).CopyDataStruct.dwData = WaterMark then
  begin
    PData := TWMCopyData(Msg).CopyDataStruct.lpData;
    while PData^ <> #0 do
    begin
      Param := StrPas(PData);
      if Assigned(fOnProcessParam) then
        fOnProcessParam(Param);
      Inc(PData, Length(Param) + 1);
    end;
    Msg.Result := 1;
  end
  else
    Msg.Result := 0;
end;


Notice that these methods are based closely on the form message handler
methods discussed in the previous part of this article except that they
are now no longer directly implemented in the form unit. The only
significant change is that WMCopyData now triggers the OnProcessParam
event rather than calling a hard-wired method to process parameters
directly. 

Finally we examine the three remaining protected methods:


function TSingleInst.FindDuplicateMainWdw: HWND;
begin
  Result := FindWindow(PChar(WdwClassName), nil);
end;

function TSingleInst.SendParamsToPrevInst(Wdw: HWND): Boolean;
var
  CopyData: TCopyDataStruct;
  I: Integer;
  DataSize: Integer;
  Data: PChar;
  PData: PChar;
begin
  DataSize := 0;
  for I := 1 to ParamCount do
    Inc(DataSize, Length(ParamStr(I)) + 1);
  Inc(DataSize);
  Data := StrAlloc(DataSize);
  try
    PData := Data;
    for I := 1 to ParamCount do
    begin
      StrPCopy(PData, ParamStr(I));
      Inc(PData, Length(ParamStr(I)) + 1);
    end;
    PData^ := #0;
    CopyData.lpData := Data;
    CopyData.cbData := DataSize;
    CopyData.dwData := WaterMark;
    Result := SendMessage(Wdw, WM_COPYDATA, 0, LPARAM(@CopyData)) = 1;
  finally
    StrDispose(Data);
  end;
end;

function TSingleInst.SwitchToPrevInst(Wdw: HWND): Boolean;
begin
  Assert(Wdw <> 0);
  if ParamCount > 0 then
    Result := SendParamsToPrevInst(Wdw)
  else
    Result := True;
  if Result then
    SendMessage(Wdw, fEnsureRestoreMsg, 0, 0);
end;


These methods are analogues of equivalent routines in the previous part
of this article and won't be further described here. 


Modifications to the Project File
---------------------------------

The project file must undergo a simple change to use the SingleInst
object to determine whether or not to start the application. Firstly,
the USingleInst should be added to the project and then the project file
must be changed to wrap the form creation and application run code in a
conditional statement as follows: 


...

begin
  if SingleInst.CanStartApp then
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end;
end.


Main Form Modification
----------------------

Slightly more work needs to be done in the main form unit. Firstly, add
the following declarations to the form class's protected section: 


  protected
    procedure WndProc(var Msg: TMessage); override;
    procedure HandleParam(const Param: string);
    procedure CreateParams(var Params: TCreateParams); override;


Now implement these methods to call into SingleInst as follows:


procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  SingleInst.CreateParams(Params);
end;

procedure TForm1.WndProc(var Msg: TMessage);
begin
  if not SingleInst.HandleMessages(Msg) then
    inherited;
end;


The CreateParams method calls inherited and then calls
SingleInst.CreateParams to set the window class name. The overridden
WndProc method calls SingleInst.HandleMessages to see if the message is
one of the ones handled by SingleInst (the function returns true if it
handles a message). If the message was not handled by
SingleInst.CreateParams the inherited WndProc method is called to handle
it. 

We will also want to handle the TSingleInst.OnProcessParam event so the
application gets notified when parameters are passed through the
WM_COPYDATA message. In this example we just add the parameters to a
list box. We assign the event handler in FormCreate, where we also
process parameters passed to the program when it first starts: 


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

procedure TForm1.HandleParam(const Param: string);
begin
  ListBox1.Items.Add(Param);
end;


Overriding TSingleInst
----------------------

We now look at an example of how to override the TSingleInst. We simply
provide a new watermark and a window class name. The whole unit
(UMySingleInst.pas) is listed below. The only point of note is how the
new class is registered as the class to use for the SingleInst singleton
object. 


unit UMySingleInst;

interface

uses
  Windows,
  USingleInst;

type
  TMySingleInst = class(TSingleInst)
  protected
    function WdwClassName: string; override;
    function WaterMark: DWORD; override;
  end;

implementation

{ TMySingleInst }

function TMySingleInst.WaterMark: DWORD;
begin
  Result := $DE1F1DAB;
end;

function TMySingleInst.WdwClassName: string;
begin
  Result := 'DelphiDabbler.SingleInst.1';
end;

initialization

RegisterSingleInstClass(TMySingleInst);

end.


Conclusion
----------

This article has demonstrated how to ensure that only a single instance
of an application is run. It also shows how to pass command line
parameters to an already running instance, ensuring its window is
displayed prominently. 

The method used was to detect the presence of the application's main
window class among the top level windows. Communication with the
previous application instance was by means of messages sent to the
instance's main window. In particular, a user defined message was used
to ensure the window was restored and visible and the WM_COPYDATA
message was used to send the command line parameters across the process
boundary. 

The skeleton of some source code for an application that runs as a
single instance was provided. 

Finally a reusable class was presented that can be used in developing a
program that runs only a single instance of the application. 

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

__________________

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. A full version of this article is available at:
http://www.delphidabbler.com/articles.php?article=13

________________________________________________________________________

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


3. Inside Delphi's Classes and Interfaces - Part 2

   By Ezra Hoch


Part 1 of Inside Delphi's Classes and Interfaces was published in the 
Pascal Newsletter Issue #49. You should read it before this article.
http://www.latiumsoftware.com/en/pascal/0049.php#4

In this article we'll finish covering Delphi's implementation of
Interfaces, and review a few useful conclusions.

Let's start with an indepth example: 

  type
   
    IInterface1 = interface 
      procedure ActA; 
      procedure ActB; 
    end; 
 
    IInterface2 = interface(IInterface1) 
      procedure ActC; 
      procedure ActD; stdcall; 
    end; 

    TSampleClass = Class(TInterfacedObject, IInterface1, IInterface2)
      procedure ActA; 
      procedure ActB; 
      procedure ActC; 
      procedure ActD; stdcall; 
    end; 

  var 
    Interface1 : IInterface1; 
    Interface2 : IInterface2; 
    Sample : TSampleClass; 
  begin 
    Sample := TSampleClass.Create; 
    Interface1 := Sample; 
    Interface2 := Sample; 
    Interface1.ActA; 
    Interface1.ActB; 
    Interface2.ActA; 
    Interface2.ActB; 
    Interface2.ActC; 
    Interface2.ActD; 
  end; 

Instead of looking at the compiled code for this example, I'll simlpy
note the interesting aspects of it. First, when assigning a value to
Interface1, we'd expect Delphi to take the value of what 'Sample' points
to and add a specific amount ($10) and be done with it. When assigning a
value to Interface2, we'd expect Delphi to do the same, just add a
smaller amount ($0C) because the interfaces are stored in memory from
the last to the first.

But Delphi doesn't do that. It assignes both Interface1 AND Interface2
the value that 'Sample' points to plus $0C. That's because IInterface2
inherites from IInterface1. Therefor, IInterface2 includes IInterface1.
Hence, any call to Interface1, will actually be executed through
IInterface2's method list.

Second, when we call Interface1.ActA, it calls the 4th (every interface
inherits from IUnknown) method on IInterface2's method list (because
IInterface2 inherits from IInterface1). When we call Interface1.ActB it
calls the 5th method on IInterface2's method list. When we call
Interface2.ActA it calls the 4th method on IInterface2's method list,
just the same as Interface1.ActA. That's because IInterface2 inherits
from IInterface1.

Third, when we call Interface2.ActD Delphi adds one additional
instruction before calling the 7th method of IInterface2. That's because
we've declared a different convention call to the method (stdcall).
Notice that all of IUnknown's methods are defined with the stdcall
directive.

The structure of an interface's method list always follows the following
rule:

  First Method 
  . 
  . 
  Last Method 
  The parent's interface's method list 

In our case, IInterface2's method list is as follows: 
   
  ActC 
  ActD 
  // IInterface1's method list 
    ActA 
    ActB 
    // IUnknown's method List 
      QueryInterface 
      _AddRef 
      _Release 

NOTE: The structure above is how the methods' code is organized in
memory. The first entry in any interface's method list will belong to
QueryInterface (the first method of IUnknown) but it will point to a
place in memory (the implementation of that specific interface's
QueryInterface method) that is higher than the interfaces' own methods'
implementation - as shown in the structure above. In our case,
IInterface2's QueryInterface's implementation is higher in memory than
IInterface2's ActB's implementation, which is higher in memory than
ActD's implementation. Thou ActD is the 7th entry, ActB is the 5th entry
and QueryInterface is the 1st entry in IInterface2's method list.

To fully understand what happens when Delphi calls an interface's
method, lets have a look at the compiled method list of IInterface2 in
the example above. The following code is an exact copy of the compiled
code (except for the comments):

  // ActC 
  add eax, -$0C 
  jmp TSampleClass.ActC 
  // ActD 
  add dword ptr [esp + $04], -$0C 
  jmp TSampleClass.ActD 
  // ActA 
  add eax, -$0C 
  jmp TSampleClass.ActA 
  // ActB 
  add eax, -$0C 
  jmp TSampleClass.ActB 
  // QueryInterface 
  add dword ptr [esp + $04], -$0C 
  jmp TInterfacedObject.QueryInterface 
  // _AddRef 
  add dword ptr [esp + $04], -$0C 
  jmp TInterfacedObject._AddRef 
  // _Release 
  add dword ptr [esp + $04], -$0C 
  jmp TInterfacedObject._Release 

As you remember, an object's method is actually a regular function or
procedure that accepts as a parameter an instance of the method's class.
As you can notice, before each call to the real method
('TSampleClass.ActD' for example) there is one line of code that changes
the value of either 'eax', or 'dword ptr [esp + $04]', depending on the
calling convention. As you can notice, in all cases we subtract $0C form
a variable. But, why 12 ($0C = 12) ? That's because this interface
(IInterface2) is in the 3rd (FRefcount, IUnknown are before it) place
after the pointer to VMT of the clasS TSampleClass. Therefore, the value
of any instance of IInterface2 of TSampleClass (Interface2 for example)
is actually the value of the pointer to that class' instance plus 12.

Here is another example that will help understand the section above. The
following code continues the definitions from the above code:

  type 
   
    IAnotherInterface = interface 
      procedure ActE; 
    end; 

    TAnotherSample = class(TInterfacedObject, IInterface2,
                       IAnotherInterface)
      procedure ActA; 
      procedure ActB; 
      procedure ActC; 
      procedure ActD; stdcall; 
      procedure ActE; 
    end; 

  var 
    Interface2: IInterface2; 
  begin 
    Interface2:= TAnotherSample.Create; 
    Interface2.ActC; 
  end; 

Now, let's compare the entry for this example's IInterface2 and the
previous' one:

  IInterface2 of TAnotherSample: 
  add eax, -$10 
  jmp TAnotherSample.ActC 

  IInterface2 of TSampleClass: 
  add eax, -$0C 
  jmp TSampleClass.ActC 

There are two obvious changes: 

a) The actual function that is called (either TAnotherSample.ActC or
   TSampleClass.ActC)
b) The amount that 'eax' is changed by. Notice that when calling
   IInterface2 of TAnotherSample, 'eax' is changed by 16 ($10 = 16) as
   opposed to being changed by 12. That's because on TAnotherSample,
   the IInterface2 is the second interface in the instance's structure
   in memory, and therefor it is "farther away" from the instance itself
   and needs to be changed by additional 4 bytes. 

And now to some useful stuff: 

First, if you want to check if 2 (or more) interface variables are of
the same instance, you cannot simply compare them, even if they are of
the same type. You must QueryInterface them to a single interface type,
and then compare. As a general rule, if you want to compare interfaces,
QueryInterface them to IUnknown and then compare.

Example: 

  type 

    IBooA = interface 
    end; 

    IBooB = interface 
    end; 

    TBoo = class(TInterfacedObject, IBooA, IBooB) 
    end; 

  var 
    Boo : TBoo; 
    BooA : IBooA; 
    BooB : IBooB; 
  begin 
    Boo := TBoo.create; 
    BooA := Boo; 
    BooB := Boo; 
   
    // This won't complie 
    if BooA = BooB then 
    begin 
      Beep; 
    end; 

    if Integer(BooA) = Integer(BooB) then 
    begin 
      // will never get here 
      Beep; 
    end; 

    if IUnknown(BooA) = IUnknown(BooB) then 
    begin 
      // will never get here 
      Beep; 
    end; 

    // the 'as' word is the same as QueryInterface when acting on
    // interfaces 
    if (BooA as IUnknown) = (BooB as IUnknown) then 
    begin 
      // Will always get here 
      Beep; 
    end; 
  end; 

Explanation: The first comparing won't compile, because BooA and BooB
are of 2 different types. The Second and third comparings will compile
but never return true. That's because typecasting doesn't change the
value of the variable that's being typecasted. It only allows the
compiler to compile the code though there are two different types
involved. Hence, if BooA is different from BooB, comparing them will
never return true, no matter what type casting is done to them.

But why do BooA and BooB have different values ? They were both assigned
using the ":= Boo;" statement. The answer is simple. Remember that I 
said that an interface's variable's value is actually the value of the
instance itself (or at least the value of the pointer to the instance)
plus a different number for each interface ? In our case, BooA is the
same as what Boo points to, added 16. And BooB is the same as what Boo
points to, added 12. That's why BooA and BooB are not that same.

The Forth comparing actually works. That's because if an interface is
from the same type, then comparing it to an interface of that type will
always return the expected result (if both interfaces were aquired via
QueryInterface, not by type casting). That's because if they are of the
same type, then the difference between them and the instance is the
same. And if they are of the same instance, then they must be equal.
 
That is, each interface is equal to it's instance + a specific Delta
(the Delta depends on the interface). In other words, Interface =
Instance + Delta. If 'Instance' is the same for both interfaces, and the
'Delta' is the same (cause they are of the same interface type), then
both interfaces must be equal.

Note: This is the way Delphi works, for good and for bad. You should
take this in mind when writing code for properties of interface type. 
The following code wouldn't work properly:

  TSample = class 
    private 
      FData : IUnknown; 
      procedure SetData(Value : IUnknown); 
    protected 
      procedure Changed; virtual; abstract; 
    public 
      property Data : IUnknown read FData write SetData; 
  end; 

  procedure TSample.SetData(Value : IUnknown); 
  begin 
    // This is incorrect. 
    if Value <> FData then 
    begin 
      FData := Value; 
      Changed; 
    end; 
  end;   

It might seem that this code should work, but it might not work when
someone would assign the property 'Data' with an IUnknown retrieved by a
type cast. The correct code should be:

  procedure TSample.SetData(Value : IUnknown); 
  begin 
    if (Value as IUnknown) <> (FData as IUnknown) then 
    begin 
      FData := Value; 
      Changed; 
    end; 
  end;   

Second, each interface you declare that a class implements (with
exception of interfaces that inherit from other interfaces) means that
each instance of that class will take up 4 more byte of memory. That
might seem like nothing (and probably is) except for one case. Consider
the following code:

  IInterfaceA = interface 
  end; 

  IInterfaceB = interface 
  end; 

  TSampleClass1 = class(TInterfacedObject, IInterfaceA) 
  end; 

  TSampleClass2 = class(TSampleClass1, IInterfaceA, IInterfaceB) 
  end; 

It would seem that each instance of TSampleClass1 should take up 16
bytes, and each instance of TSampleClass2 should take up 20 bytes (4
bytes more, because it supports one more interface). That is not true.
Each instance of TSampleClass1 does take up 16 byte. But, each instance
of TSampleClass2 takes up 24 bytes ! That's because Delphi creates an
interface entry even for interfaces that are already implemented by
parent classes.

The solution to this is simple. Just remove the declaration of
IInterfaceA from TSampleClass2. This will not change the fact that
TSampleClass2 implements IInterfaceA, cause TSamlpeClass2 inherits from
TSamlpeClass1, which implements IInterface1. This wouldn't have happened
if IInterfaceB was a descendant of IInterfaceA.
   
This might add up to quit a lot if you do your inheritence improperly.
For example:

  TSampleClass1 = class(TInterfacedObject, IUnknown) 
  end; 

  TSampleClass2 = class(TSampleClass1, IUnknown) 
  end; 

  TSampleClass3 = class(TSampleClass2, IUnknown) 
  end; 

  TSampleClass4 = class(TSampleClass3, IUnknown) 
  end; 

  TSampleClass5 = class(TSampleClass4, IUnknown) 
  end; 

Each instance of TSampleClass5 takes up 32 bytes of memory, though it
has no real data (except for FRefCount of TItnerfacedObject).

________________________________________________________________________

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


4. Forums / Mailing Lists


To join any of our forums, the best way is to subscribe from the web,
since that way you'll be able to access the features available at the
web site (like changing your subscription options, viewing the past
messages, accessing the files section, etc.). A Yahoo! ID is required
for that, and you can get yours free by registering as a Yahoo! user,
but if you don't want to register or if you don't have full Internet
access, 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 Top 200!
         http://top200.jazarsoft.com/delphi/rank.php3?id=latium
________________________________________________________________________


5. Delphi on the Net

   By Dave Murray <irongut at vodafone dot net>


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


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

* Delphi SWF SDK (Standard) v1.4 - by FeatherySoft ($170)
  Object Pascal library for creating SWF files, without using of any
  external dynamic libraries. Released features: visual objects (shape,
  button, text, morphing shape, sprite); all types of filling (solid,
  gradient, image); device and embedding fonts; action commands;
  sound (events, streaming); video; any transition and transformation.
  http://www.delphiflash.com/

* 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


Freeware
--------

* PGP Components for Delphi v4.0 - Michael in der Wiesche (with source)
  These sources provide a Delphi (2-7) direct interface to PGP requiring
  a preceding full installation of PGP 6.5.x, 7.x or 8.x. Features 
  include: Encoding and decoding (encrypt/decrypt/sign/verify); Creating
  and verifying file detached signatures; Key management; Key generation
  (DH/DSS, RSA); X509 Certificate support; Keyserver functions.
  http://home.t-online.de/home/idw.doc/PGPcomp.htm

* Synapse TCP/IP Library v.34 - by Lukas Gebauer (with source)
  TCP/IP library for Delphi, Kylix and FreePascal using blocking 
  sockets. Contains simple non-visual objects for easy programming of 
  command line utilities, visual projects, NT services, etc. New: 
  FreePascal 1.9.4 support; Experimental Delphi 8 support; Optional 
  support for ICONV library; New flexible FTP directory listing parser.
  http://synapse.ararat.cz/

* TPJDropFiles + TPJFormDropFiles v4.1 - by Peter Johnson (with source)
  Two components that catch files dragged and dropped from Explorer. 
  TPJFormDropFiles provides a window that can contain other controls and
  catch any files dropped anywhere on it or child controls. TPJDropFiles
  is a non-visual component that subclasses a form to catch files that 
  are dropped anywhere on the form.
  http://www.delphidabbler.com/software.php?id=dropfiles

* Merkes' Tiny Hex Editor v1.5.0.10 - by Merkes Pages
  A free hex editor for binary files. Allows you to edit multiple files 
  (mdi), disk sectors and virtual memory of other processes. Tiny Hex 
  Editor is scriptable, lets you view data structures and has a plugin 
  interface for third party extensions.
  http://www.mirkes.de/en/freeware/tinyhex.php


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

* Public Beta: Delphi 7.1 Update - Database Supplemental
  This is a public beta of database runtime files that address defects 
  introduced in the Delphi 7.1 update.
  http://community.borland.com/article/0,1410,32492,00.html


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

* Interview with Danny Thorpe about Diamondback
  Danny Thorpe talks about the next Delphi release.
  http://community.borland.com/article/0,1410,32708,00.html

* Interview with Corbin Dunn about the Diamondback IDE
  Corbin Dunn, Software Engineer, Research and Development at Borland, 
  talks about the Delphi IDE.
  http://community.borland.com/article/0,1410,32719,00.html

* Borland "Diamondback" Data Services over .NET Remoting
  Details on data remoting with the BorCon preview edition of 
  "Diamondback", the next version of Delphi.
  http://community.borland.com/article/0,1410,32718,00.html

* Diamondback Preview License Update
  A license update that does not require an NDA or Beta Agreement.
  http://community.borland.com/article/0,1410,32717,00.html

* BDNtv: Diamondback Preview of Data Remoting
  Demonstrates the ease of remoting data in a heterogeneous database 
  environment with Diamondback. Includes setting up a local DataHub for 
  SQL Server and InterBase then making it a remote server. And, creating
  a client that updates tables in both databases simply by calling one 
  method of the DataHub component. Flash
  http://dotnet.borland.com/bdntv/delphi/dataremoting.html

* BDNtv: Diamondback Sneak Peek
  A sneak peek at Diamondback's new IDE features and the new Delphi 
  language feature for enumeration. The multiple personality IDE, 
  refactoring for both .NET and Win32, Error Insight, Help Insight, the 
  History View and more are shown. The for .. in .. do (foreach) 
  enumerator syntax is also revealed. Flash
  http://dotnet.borland.com/bdntv/delphi/diamondbacksneakpeek.html

* Delphi 8 and Microsoft .NET version 1.1 Service Pack 1
  Delphi 8 has trouble compiling projects after .NET 1.1 Service Pack 1 
  has been installed. This article explains why and offers a workaround.
  Also affects the BorCon Diamondback preview release.
  http://community.borland.com/article/0,1410,32713,00.html

* Borland CEO Touts Software Process Management
  InfoWorld Editor-at-Large Paul Krill spoke with Dale Fuller, president
  and CEO of Borland, at the BorCon conference last week about Borland's
  tools and ALM strategies and issues such as Java vs. .Net, Web 
  services, and outsourcing.
  http://www.computerworld.com.au/index.php/id;954592276;fp;16;fpid;0

* Interview: Borland Aims for Better Code
  Better collaboration tools are the only route to superior software,
  argues Borland's David Intersimone. 
  http://www.computing.co.uk/analysis/1157073

* DB2 Web Service Engines on Linux with Kylix 3: Part 1 - by Bob Swart
  Demonstrates how to build a SOAP Web service engine with Kylix 3, 
  exposing the data from DB2 UDB database tables to the outside world.
  www-106.ibm.com/developerworks/db2/library/techarticle/dm-0406swart/

* DB2 Web Service Engines on Linux with Kylix 3: Part 2 - by Bob Swart
  Demonstrates how to build the user interface for a SOAP Web service 
  engine with Kylix 3 on Linux, exposing the data from DB2 UDB database 
  tables to the outside world.
  www-106.ibm.com/developerworks/db2/library/techarticle/dm-0407swart/

* Producing Dynamic Data-Entry Forms from DB2 Tables on Linux - B. Swart
  Uses Kylix 3 and dbExpress to analyze DB2 UDB database tables, fields 
  (names and types) to allow the user to select a specific table, toggle
  which fields are shown, and dynamically view the output in both a 
  datagrid and individual data-aware controls.
  www-106.ibm.com/developerworks/db2/library/techarticle/dm-0407swart2/

* Use Delphi Code to Create/Drop DB2 UDB Database Tables - by Bob Swart
  Examines the design and implementation of a Delphi application you can
  use to create or delete / drop tables inside IBM DB2 databases. It 
  provides several examples of sending SQL DDL to the DB2 DBMS using 
  Delphi and the cross-platform dbExpress data access technologies.
  www-106.ibm.com/developerworks/db2/library/techarticle/dm-0409swart/

* Work with IBM DB2 databases and SQL in Delphi for .NET - by Bob Swart
  Using Delphi code to create/drop DB2 database tables, focuses on the 
  use of SQL queries to build simple and more complex SQL SELECT queries
  to end up with master-detail relations. Also examines SQL joins in 
  detail, covering examples of inner joins, left/right outer joins, and 
  the differences between them.
  www-106.ibm.com/developerworks/db2/library/techarticle/dm-0409swart1/


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

* Free Web Seminars
  More than 10 on-demand Web seminars from Borland to help you optimize 
  your software delivery.
  http://community.borland.com/article/0,1410,32698,00.html


News
====

* Borland Delphi 2005 Boosts Microsoft Windows Productivity
  Borland today announced Delphi 2005, previously codenamed Diamondback.
  Delphi 2005 combines Win32, .NET, Delphi and C# support all within one
  environment, significantly advances developer and team productivity
  and integrates with Borland's leading ALM solutions.
  http://www.tmcnet.com/usubmit/2004/Oct/1081925.htm

* Software Delivery Strategy Gets Under Way at Borland
  Kicking off its Software Delivery Optimization campaign, Borland 
  announced upgrades to CaliberRM requirements management and StarTeam 
  configuration management software at BorCon. Also at the conference, 
  the company demonstrated the next version of its Delphi IDE for 
  Windows application development.
  http://sdtimes.com/news/111/story7.htm

* Borland Scheme Aims to Maximise Business Value of Software Work
  Borland aims to turn software development into a simple business 
  process with its Software Delivery Optimisation programme, announced 
  at the BorCon 2004 earlier this month.
  http://www.computerweekly.com/articles/article.asp?liArticleID=133397

* Borland Moving Forward with SDO
  Borland took a new direction this week, with the announcement of 
  Software Delivery Optimization. SDO will see three technology concepts
  delivered around Borland's ALM tools, as the company tries to lure 
  C-level executives and vice presidents of application development with
  a message that software and the business should - and can - function 
  as one.
  http://www.cbronline.com/article_feature.asp?guid=E077757F-B5CD-415C-8CCC-F10E19F6CC11

* (Turn and Face the Strain) Software Changes
  Borland this week stood atop its soapbox preaching the evils of 
  software projects gone awry, with projects beset by issues such as 
  last-minute changes and differing perspectives on the potential 
  success of development efforts. To stem the tide of botched projects, 
  Borland pitched its Software Delivery Optimization strategy.
  http://weblog.infoworld.com/techwatch/archives/000712.html

* Borland Adds Project-Management Features To CaliberRM
  Borland announced CaliberRM 2005 this week, a product designed to help
  software project managers take some of the guesswork out of software 
  development. New features include tools for estimating the cost, 
  scheduling and staffing of a project before any code gets written.
  http://informationweek.com/story/showArticle.jhtml?articleID=47208433

* Business Management for Software Projects
  End users will be able to manage software projects like a business 
  with Borland's Software Delivery Optimisation. It aims to enable users
  to manage software projects like a business, according to Boz Elloy, 
  senior vice-president of software products.
  http://www.computerweekly.com/articles/article.asp?liArticleID=133333

* Borland challenges Visual Studio with Diamondback
  With the Diamondback release of its Delphi tool for Windows 
  applications, Borland will challenge Microsoft while accommodating 
  .Net, Win32 and Delphi development. Michael Swindell, Borland director
  of product management for developer tools, said with Diamondback 
  Borland will compete with Microsoft's Visual Studio.
  http://www.computerweekly.com/articles/article.asp?liArticleID=133332

* Borland Touts Software Delivery Optimization
  At BorCon, Borland will reveal its software delivery optimization 
  strategy, which leverages the company's ALM and developer products to 
  ease software development and maintenance. The strategy ultimately 
  will feature a bundle of the company's products code-named Themis, due
  out in the first half of 2005, which purports to provide a platform 
  for integrated, repeatable development processes.
  http://www.javaworld.com/javaworld/jw-09-2004/jw-0913-iw-borland.html

* Borland Outlines Vision for Transforming Software Development
  Today at BorCon 2004, Dale Fuller, President and CEO of Borland, 
  presented Borland's vision and product strategy for transforming 
  software development from an unpredictable art form into a more 
  manageable and repeatable business process. Borland's vision for 
  Software Delivery Optimization builds on the technical efficiencies of
  ALM, and incorporates the business processes and management 
  capabilities companies seek to ensure business-to-IT alignment, and 
  the delivery of quality software, on time, within budget, for maximum 
  business value.
  http://home.businesswire.com/portal/site/google/index.jsp?ndmViewId=news_view&newsId=20040913005322&newsLang=en

* Borland and NEC Team on Online Communications
  Borland and NEC will partner to develop adaptor software in order to 
  rapidly integrate web-based applications with voice and video. This 
  will target communications over IP telephony, IP video and 
  conferencing over online applications.
  http://www.cbronline.com/article_news.asp?guid=2FE9728E-9350-49C4-BC59-2C25C62987BE

* Borland Acquires Software Project Planning Tool
  Borland has acquired of Estimate Professional, a software project 
  planning and estimation tool from Software Productivity Center. This 
  newly acquired tool will be embedded within the next version of the 
  Borland CaliberRM requirements management solution.
  http://www.infoworld.com/article/04/08/25/HNborlestimate_1.html

* Borland Joins ECMA to Help Shape Standards for the .NET Framework
  Borland has been elected as a member of ECMA International. As a 
  member of ECMA, Borland will help shape standards for the .NET 
  Framework and the C# and C++ programming languages.
  http://home.businesswire.com/portal/site/google/index.jsp?ndmViewId=news_view&newsId=20040812005195&newsLang=en

* Borland Developer News - .NET Edition, August 2004
  Your source for Delphi and C# related news. Covering mostly .NET with 
  some Win32 development.
  http://community.borland.com/article/0,1410,32491,00.html

________________________________________________________________________

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