Tuesday, February 26, 2008

TDM Rerun #5: SvCom 4.0

When you get into really serious Windows development, you may well need to create NT service applications. Borland's input is half-hearted: Delphi includes support for NT service application writing, but as you work with this framework, you'll soon discover its less-polished parts!

- SvCom 4.0, The Delphi Magazine 69, May 2001

In the TDM #69 I reviewed SvCom, "an integrated package of classes and tools for development of service applications and use of NT Security framework." (as the current SvCom web page states). Good stuff, I'm still using it for service development.

Links: article (PDF, 67 KB), SvCom

Monday, February 11, 2008

TDM Rerun #4: Let's Cooperate

Every serious Windows programmer who has developed at least one multi-threaded application knows about thread synchronisation. You know what I mean: critical sections, mutexes, semaphores, signals and so on. ... But to write truly distributed applications, running on different computers, we need new tools.

- Let's Cooperate, The Delphi Magazine #68, April 2001

Figure 5: Receiving a messageI don't remember what was the exact reason for this article, but obviously I was working on some multi-process multi-computer solution and I needed a way to synchronise those computers. Of course, once I started writing the article, it got completely out of hand and I finished with file system based mutex, critical section, group, event, and even with a message queue and single-writer-multiple-readers synchronisation primitive. There were also many state diagrams like the one of the right dispersed through the article. Poor readers. >:-(

The plan was to make most of them work on Linux as well, but as I discovered in File Sharing on Linux (not yet published on my blog), but as I found later, this was nearly impossible to do as Linux implements file locking in completely different way.

I never used those primitives much as TCP/IP communication became much more prominent in later years. Still, they can be very useful if you want to quickly put together a multi-computer demo or quick and dirty solution.

The GpFileSync unit never made it to my web so I'm linking to the current version at the bottom of this article.

Links: article (PDF, 117 KB), source code (ZIP, 47 KB), current GpFileSync unit

Wednesday, February 06, 2008

TDM Rerun #3: Time Is The Simplest Thing

'Time, I'll tell you about time. Time is the simplest thing.'

- Time Is The Simplest Thing, The Delphi Magazine #65, January 2001
[quote from Clifford D. Simak's The Fisherman]

Now this is one of my favorite articles. It deals with time and more specifically with time zones. As most of my articles this one also builds on real-world problems I encounter during my programming practice. In this case, it was motivated by a big coding flop which taught me an important lesson: "Never store local time in a database." [No, I still don't want to recall all the details. It was related to daylight savings time transitions, that's all I'm willing to tell.]

Anyway, I fixed the problems in the abovementioned code and during that process I found out that there is almost no support for time zones built in Delphi and that Windows APIs on that area are really not that simple to use. So I built a time zone manipulation library that handles time zone information access and time zone conversions with daylight savings time support. This GpTimezone unit is still alive and I'm using it regularly - mostly the NowUTC function.

The article also dealt with the (now happily forgotten) Swatch Time.

Also included was a neat utility (if I'm allowed to say so) for timezone conversions, which I'm still using today without any changes to the original code.

GpTimezone demo application

 

Links: article (PDF, 134 KB), source code (ZIP, 162 KB), current GpTimezone unit

TWinControl.Controls Enumerator, Revisited

Fredrik Loftheim made an interesting observation to my previous article on TWinControl.Controls enumerator - namely that the enumerator factory doesn't have to be interface based. It can be replaced by a record. Source is almost the same as before, but we can skip the interface declaration. Generated code is simpler as the enumerator factory is simply allocated from the stack and automatically destroyed when it goes out of scope. No interface support and no reference counting is required. Simpler and faster, that's the way to go.

interface

type
TControlEnumerator = record
strict private
ceClass : TClass;
ceIndex : integer;
ceParent: TWinControl;
public
constructor Create(parent: TWinControl; matchClass: TClass);
function GetCurrent: TControl;
function MoveNext: boolean;
property Current: TControl read GetCurrent;
end; { TControlEnumerator }

TControlEnumeratorFactory = record
strict private
cefClass : TClass;
cefParent: TWinControl;
public
constructor Create(parent: TWinControl; matchClass: TClass);
function GetEnumerator: TControlEnumerator;
end; { TControlEnumeratorFactory }

function EnumControls(parent: TWinControl; matchClass: TClass = nil): TControlEnumeratorFactory;

implementation

function EnumControls(parent: TWinControl; matchClass: TClass = nil): TControlEnumeratorFactory;
begin
Result := TControlEnumeratorFactory.Create(parent, matchClass);
end; { EnumControls }

{ TControlEnumerator }

constructor TControlEnumerator.Create(parent: TWinControl; matchClass: TClass);
begin
ceParent := parent;
ceClass := matchClass;
ceIndex := -1;
end; { TControlEnumerator.Create }

function TControlEnumerator.GetCurrent: TControl;
begin
Result := ceParent.Controls[ceIndex];
end; { TControlEnumerator.GetCurrent }

function TControlEnumerator.MoveNext: boolean;
begin
Result := false;
while ceIndex < (ceParent.ControlCount - 1) do begin
Inc(ceIndex);
if (ceClass = nil) or (ceParent.Controls[ceIndex].InheritsFrom(ceClass)) then begin
Result := true;
break; //while
end;
end; //while
end; { TControlEnumerator.MoveNext }

{ TControlEnumeratorFactory }

constructor TControlEnumeratorFactory.Create(parent: TWinControl; matchClass: TClass);
begin
cefParent := parent;
cefClass := matchClass;
end; { TControlEnumeratorFactory.Create }

function TControlEnumeratorFactory.GetEnumerator: TControlEnumerator;
begin
Result := TControlEnumerator.Create(cefParent, cefClass);
end; { TControlEnumeratorFactory.GetEnumerator }

The new version of the TWinControl.Controls enumerator plus some other stuff is available at http://gp.17slon.com/gp/files/gpvcl.zip.

Friday, February 01, 2008

TWinControl.Controls Enumerator

I'm still having fun with enumerators. The latest I wrote is a filtering enumerator for TWinControl.Controls[] that allows me to write code like this:

var
control: TControl;

for control in EnumControls(pnlAttributes, TSpeedButton) do
TSpeedButton(control).Enabled := false;

I found it interesting that Borland built a Components[] enumerator in the VCL, but not a Controls[] enumerator.


The EnumControls interface is simple. It takes a starting point for enumeration and an optional class filter. By specifying the latter, you tell the enumerator that you're only interested in child controls of a specified class.

function EnumControls(parent: TWinControl; 
matchClass: TClass = nil): IControlEnumeratorFactory;

As it is used in a for..in loop, EnumControl must return a class or interface that implements GetEnumerator function and that is exactly what it does. GetEnumerator, on the other hand, creates an instance of the TControlEnumerator class, which implements the actual enumeration.

type
TControlEnumerator = class
strict private
ceClass : TClass;
ceIndex : integer;
ceParent: TWinControl;
public
constructor Create(parent: TWinControl; matchClass: TClass);
function GetCurrent: TControl;
function MoveNext: boolean;
property Current: TControl read GetCurrent;
end; { TControlEnumerator }

IControlEnumeratorFactory = interface
function GetEnumerator: TControlEnumerator;
end; { IControlEnumeratorFactory }

On the implementation side, EnumControls creates an instance of the TControlEnumeratorFactory class, which implements the IControlEnumeratorFactory interface.

function EnumControls(parent: TWinControl; matchClass: TClass = nil): IControlEnumeratorFactory;
begin
Result := TControlEnumeratorFactory.Create(parent, matchClass);
end; { EnumControls }

type
TControlEnumeratorFactory = class(TInterfacedObject, IControlEnumeratorFactory)
strict private
cefClass: TClass;
cefParent: TWinControl;
public
constructor Create(parent: TWinControl; matchClass: TClass);
function GetEnumerator: TControlEnumerator;
end; { GetEnumerator }

TControlEnumeratorFactory just stores parent and matchClass parameters for later use in the GetEnumerator function.

constructor TControlEnumeratorFactory.Create(parent: TWinControl; matchClass: TClass);
begin
cefParent := parent;
cefClass := matchClass;
end; { TControlEnumeratorFactory.Create }

function TControlEnumeratorFactory.GetEnumerator: TControlEnumerator;
begin
Result := TControlEnumerator.Create(cefParent, cefClass);
end; { TControlEnumeratorFactory.GetEnumerator }

GetEnumerator creates an instance of the TControlEnumerator class, which implements the actual enumeration in a pretty standard manner. Only the MoveNext method is slightly more complicated than usual because it must optionally check the matchClass parameter.

constructor TControlEnumerator.Create(parent: TWinControl; matchClass: TClass);
begin
inherited Create;
ceParent := parent;
ceClass := matchClass;
ceIndex := -1;
end; { TControlEnumerator.Create }

function TControlEnumerator.GetCurrent: TControl;
begin
Result := ceParent.Controls[ceIndex];
end; { TControlEnumerator.GetCurrent }

function TControlEnumerator.MoveNext: boolean;
begin
Result := false;
while ceIndex < (ceParent.ControlCount - 1) do begin
Inc(ceIndex);
if (ceClass = nil) or (ceParent.Controls[ceIndex].InheritsFrom(ceClass)) then begin
Result := true;
break; //while
end;
end; //while
end; { TControlEnumerator.MoveNext }

It's instructive to see how all those parts play together when the code fragment from the beginning of this blog entry is executed.

for control in EnumControls(pnlAttributes, TSpeedButton) do
TSpeedButton(control).Enabled := false;


  • EnumControls is called. It creates an instance of the IControlEnumeratorFactory. TControlEnumeratorFactory constructor stores parent and matchClass parameters into internal fields.

    • TControlEnumeratorFactory.GetEnumerator is called. It creates an instance of the TControlEnumerator and passes it internal copies of parent and matchClass parameters.

      • TControlEnumerator's MoveNext and Current are used to enumerate over the parent's child controls.

    • For..in loop terminates and compiler automatically destroys the object, created by the GetEnumerator method.

  • Sometime later, the method containing this for..in loop terminates and compiler automatically frees the IControlEnumeratorFactory instance created in first step.

The TWinControl.Controls enumerator plus some other stuff is available at http://gp.17slon.com/gp/files/gpvcl.zip.