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