<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Art of Delphi Programming</title>
	<atom:link href="http://www.uweraabe.de/Blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.uweraabe.de/Blog</link>
	<description>Opinions, thoughts and ideas mostly related to Delphi Programming</description>
	<lastBuildDate>Wed, 01 Jun 2011 12:42:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Windows 7 Previews &#8211; the Delphi Way</title>
		<link>http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/</link>
		<comments>http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 12:42:59 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=165</guid>
		<description><![CDATA[In the ancient days of Windows XP and Delphi 7 I used to provide a preview of the proprietary file content inside the file open dialog of one of my applications. This was accomplished by deriving from TOpenDialog, just like &#8230; <a href="http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the ancient days of Windows XP and Delphi 7 I used to provide a preview of the proprietary file content inside the file open dialog of one of my applications. This was accomplished by deriving from <em>TOpenDialog</em>, just like the <em>TOpenPictureDialog</em> does that comes with Delphi itself.</p>
<p>The drawback was that since Windows Vista this was no way to go when you wanted to use the new Vista style dialogs. This was an even more nuisance as the new dialogs already come with a preview ability &#8211; so why not use it directly?<span id="more-165"></span></p>
<p>Googling a bit reveiled that others have to fight with the same problem, but no one seemed to have bitten the bullet to make a nice Delphi wrapper around the usual hurdles encountered when programming directly against the operating system. Looks like it was my turn to volunteer and here are the results. A simple implementation of a preview handler the Delphi way can be written in 45 lines:</p>
<pre class="brush:delphi">unit MyPreviewHandler;

interface

uses
  PreviewHandler, Classes, Controls, StdCtrls;

const
  CLASS_MyPreviewHandler: TGUID = '{64644512-C345-469F-B5FB-EB351E20129D}';

type
  TMyPreviewHandler = class(TFilePreviewHandler)
  private
    FTextLabel: TLabel;
  public
    constructor Create(AParent: TWinControl); override;
    procedure DoPreview(const FilePath: string); override;
    property TextLabel: TLabel read FTextLabel;
  end;

implementation

uses
  SysUtils;

constructor TMyPreviewHandler.Create(AParent: TWinControl);
begin
  inherited;
  FTextLabel := TLabel.Create(AParent);
  FTextLabel.Parent := AParent;
  FTextLabel.AutoSize := false;
  FTextLabel.Align := alClient;
  FTextLabel.Alignment := taCenter;
  FTextLabel.Layout := tlCenter;
  FTextLabel.WordWrap := true;
end;

procedure TMyPreviewHandler.DoPreview(const FilePath: string);
begin
  TextLabel.Caption := GetPackageDescription(PWideChar(FilePath));
end;

initialization
  TMyPreviewHandler.Register(CLASS_MyPreviewHandler, 'bplfile', 'BPL Binary Preview Handler', '.bpl');
end.</pre>
<p>This is all that must be done to display the description of a BPL file in the preview pane, whereas most of the work is actually setting up a <em>TLabel</em> do display it nicely. </p>
<p>Overriding <strong>DoPreview</strong> is obiligatory as the inherited declaration is abstract. If you refuse to override it, you actually don&#8217;t want to write your own preview handler, so stop reading further and mind your own business. </p>
<p>The overridden constructor <strong>Create</strong> is the place to establish the needed controls for the preview and connect it to the passed parent. You can easily place a derived TFrame instance onto the parent control, which allows the use of the visual form designer for your preview. Be aware that the constructor has to be declared as <em>override</em>.</p>
<p>Overriding the <strong>Unload</strong> method is optional in case you have to clear the preview and/or free some resources. It just didn&#8217;t make sense in this example, unless you want to clear the label caption. (and it would have increased the line count to 51)</p>
<p>Don&#8217;t forget to <strong>register</strong> your preview handler in the initialization part of the unit using a fresh GUID. <em>(Pre-emptive comment: No, class constructors are not the way to go here)</em></p>
<p>Of course the compiled DLL has to be registered with <em>regsvr32</em>. Make sure to run it <em>as Administrator</em>.</p>
<p>OK, I admit that the overall benefit of this preview handler is somewhat limited, but it does serve well as an example. I also admit that I suppressed the project file, which in turn is quite simple.</p>
<pre class="brush:delphi">library MyPreviewHandlerLib;

uses
  ComServ,
  PreviewHandler in 'PreviewHandler.pas' {PreviewHandler: CoClass},
  MyPreviewHandler in 'MyPreviewHandler.pas';

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer,
  DllInstall;

{$R *.RES}

begin
end.</pre>
<p>I tried to get rid of the {PreviewHandler: CoClass} entry in the uses clause, but the IDE insisted to put it in again. So, be it&#8230;</p>
<p>The real work (as usual) is done under the hood in unit <em>PreviewHandler.pas</em>, which I will explain shortly in the following. </p>
<p>The interface section declares a base class <em>TPreviewHandler</em> and two derived classes <em>TStreamPreviewHandler</em> and <em>TFilePreviewHandler</em>.</p>
<pre class="brush:delphi">type
  TPreviewHandler = class abstract
  public
    constructor Create(AParent: TWinControl); virtual;
    class function GetComClass: TComClass; virtual; abstract;
    class procedure Register(const AClassID: TGUID; const AName, ADescription, AFileExtension: string);
    procedure Unload; virtual;
  end;

  TStreamPreviewHandler = class abstract(TPreviewHandler)
  public
    procedure DoPreview(Stream: TStream); virtual; abstract;
    class function GetComClass: TComClass; override; final;
  end;

  TFilePreviewHandler = class abstract(TPreviewHandler)
  public
    procedure DoPreview(const FilePath: String); virtual; abstract;
    class function GetComClass: TComClass; override; final;
  end;</pre>
<p>Microsoft recommends to implement the stream based preview handler as it will also work for previews, say, inside a zip file, but there are cases when a file based preview handler is just a bit more handy. You would have difficulties to implement the sample preview handler from above on a stream with the same simplicity. There is indeed a third possibility to implement a preview handler based on an <em>IShellItem</em>, but let&#8217;s say I left the implementation as an exercise.</p>
<p>You may have noticed that <em>TPreviewHandler</em> is derived from <em>TObject</em> instead of <em>TComObject</em>, which actually was my first approach. I decided to separate the COM stuff from the preview implementation to get a lean inheritance and small base classes not cluttered with methods you better shouldn&#8217;t know about. The actual COM class is retrieved from the virtual class function <em>GetComClass</em>, which is overriden in both of the derived preview handler classes. The declaration of the derived function as <em>final</em> ensures that no one can override this function in a descendant class. This is necessary because the underlying factory assumes that the COM class descends from a specific private class (I&#8217;m open for suggestions on that). If you are going to implement your own COM classes you should better implement your own complete preview handler framework at all. For anyone else, just ignore the <em>GetComClass</em> function.</p>
<p>The implementing COM classes resemble the file/stream structure of the preview handler classes, just because they have to implement either <a href="http://msdn.microsoft.com/en-us/library/bb761818%28v=vs.85%29.aspx">IInitializeWithFile</a> or <a href="http://msdn.microsoft.com/en-us/library/bb761810%28v=VS.85%29.aspx">IInitializeWithStream</a>. The base class <em>TComPreviewHandler</em> is responsible for most of the internal stuff and the implementation is mostly straight forward. The mapping to the Delphi type <em>TWinControl</em> properties is made with a class helper just to bundle all that stuff (and to make it harder to port it to older Delphi versions). </p>
<p>The <em>TComPreviewHandlerFactory</em> class is responsible for updating the various registry entries needed to make Windows aware of the preview handler. It also takes care of doing the right things to use a 32-bit handler in a 64-bit environment. The code to check for this situation is taken from <a href="http://www.delphidabbler.com">www.delphidabbler.com</a> and I expanded it a little bit so that it hopefully will also work with the <a href="http://www.embarcadero.com/products/delphi/64-bit">upcoming 64-bit Delphi compiler</a>.</p>
<p>As a gimmick you get a <em>TStream</em> implementation that maps to an <a href="http://msdn.microsoft.com/en-us/library/aa380034%28v=VS.85%29.aspx">IStream</a> interface with the <em>TIStreamAdapter</em> class. The other way round is already available in Delphi, but it didn&#8217;t fit in here very well.</p>
<p>The sources for Delphi XE can be downloaded here: <a href='http://www.uweraabe.de/Blog/wp-content/uploads/2011/06/PreviewHandler.zip'>PreviewHandler.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2011/06/01/windows-7-previews-the-delphi-way/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>On Upgrading Delphi</title>
		<link>http://www.uweraabe.de/Blog/2011/05/14/on-upgrading-delphi/</link>
		<comments>http://www.uweraabe.de/Blog/2011/05/14/on-upgrading-delphi/#comments</comments>
		<pubDate>Sat, 14 May 2011 10:34:53 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=160</guid>
		<description><![CDATA[Back from Delphi Developer Days (Kudos to Marco and Cary) and after cleaning up the mess in my inbox I would like to share some thought I had during one of the sessions named &#8220;Delphi: Today and Tomorrow&#8221;. Some of &#8230; <a href="http://www.uweraabe.de/Blog/2011/05/14/on-upgrading-delphi/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Back from <a title="Delphi Developer Days" href="http://www.delphideveloperdays.com/">Delphi Developer Days</a> (Kudos to Marco and Cary) and after cleaning up the mess in my inbox I would like to share some thought I had during one of the sessions named &#8220;Delphi: Today and Tomorrow&#8221;.</p>
<p>Some of the attendants mentioned they were still working with older Delphi versions and even if the newer versions were laying around they refused to make the step migrating their applications to the current Delphi XE. One argument from a fellow developer working still with Delphi 2007 actually alerted myself as he rated the step from Delphi 2007 to Delphi 2009 a very big one regarding the Unicode migration, but the step from Delphi 2010 to Delphi XE seems rather small, which makes himself unsure wether to make the migration to Delphi XE now or wait for the next version to come.</p>
<p>Honestly, I don&#8217;t get that. There already <em>is</em> a large step from Delphi 2007 to Delphi XE. Why making it even larger? What about &#8220;divide and conquer&#8221;? Do you really expect the migration to XE2 being easier than that to XE?<span id="more-160"></span></p>
<p>The big step, at least for some of us, may indeed be from Delphi 2007 to Delphi 2009. For myself it was merely waiting for the third party libraries to keep up or to replace some of them with those currently supported (OK, that has been some work). The steps to Delphi 2010 and Delphi XE were simply opening the project, compile and start using the new features.</p>
<p>Since migrating to Delphi 2009 I have been able to make use of all the new and exciting features that made it into the product since then. My code and my coding has improved a lot. I learned a whole bunch of new technologies and new techniques that makes my programming life easier. Staying with Delphi 2007 would have been a huge loss of time. Time to work with new technologies and gain experience.</p>
<p>When Delphi XE2 will be delivered I can concentrate on what is new in that version. I am eager to make my applications compile for the Mac (remembers me that I have to buy one before). I can&#8217;t even imagine to bother with Unicode, Generics and Anonymous Methods at that time.</p>
<p>IMHO not keeping up with the current Delphi is similar to not using version control, only the other way round. While using version control allows you to revert to a previous version of your application easily, staying up-to-date with your Delphi version allows you to create the future versions of your applications much easier.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2011/05/14/on-upgrading-delphi/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Synchronize and Queue with Parameters</title>
		<link>http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/</link>
		<comments>http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 14:40:30 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=135</guid>
		<description><![CDATA[In Delphi&#8217;s TThread class there is Synchronize to call a method in the context of the GUI thread. This is necessary in case, for example, you want to update a progressbar or a status label in a form, because the &#8230; <a href="http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In Delphi&#8217;s <em>TThread</em> class there is <em>Synchronize</em> to call a method in the context of the GUI thread. This is necessary in case, for example, you want to update a progressbar or a status label in a form, because the VCL is not thread safe. While <em>Synchronize</em> is a blocking method (i.e. the thread code continues when the GUI thread has finished the method call), recent versions of Delphi introduced a non-blocking <em>Queue</em> method.</p>
<p>The drawback of using <em>Synchronize</em> is that it is very cumbersome to handle parameters during such a call. The standard solution is to use fields in the <em>TThread</em> descendant holding the parameters during <em>Synchronize</em>, but this won&#8217;t work properly with <em>Queue</em>. <span id="more-135"></span>As <em>Queue</em> is non-blocking there might be multiple calls to <em>Queue</em> waiting to be processed, which often cannot share the same field. Worse, using <em>Queue</em> access to these fields have to be thread safe, too. The queuing thread may just set this field for the next call to <em>Queue</em> while a previous <em>Queue</em> call is executed in the main thread just using this field. As this problem doesn&#8217;t exist with <em>Synchronize</em>, switching from <em>Synchronize</em> to <em>Queue</em> just has to be done more careful.</p>
<p>One way to deal with parameters for <em>Synchronize</em> is the use of <em>Anonymous Methods</em>. There is an overloaded version of <em>Synchronize</em> and <em>Queue</em> taking a <em>TThreadProcedure</em> as parameter:</p>
<pre class="brush:delphi">TThreadMethod = procedure of object;
TThreadProcedure = reference to procedure;

procedure Queue(AMethod: TThreadMethod); overload;
procedure Synchronize(AMethod: TThreadMethod); overload;
procedure Queue(AThreadProc: TThreadProcedure); overload;
procedure Synchronize(AThreadProc: TThreadProcedure); overload;</pre>
<p>A simple example for a parametrized call to <em>Synchronize</em> could be like this:</p>
<pre class="brush:delphi">type
  TMyProgressEvent = procedure(PercentComplete: Integer) of object;

  TMyThread = class(TThread)
  private
    FOnMyProgress: TMyProgressEvent;
  protected
    procedure CallMyProgress(PercentComplete: Integer);
    procedure Execute; override;
  public
    property OnMyProgress: TMyProgressEvent
      read FOnMyProgress
      write FOnMyProgress;
  end;

procedure TMyThread.CallMyProgress(PercentComplete: Integer);
begin
  if GetCurrentThreadId = MainThreadID then begin
    if Assigned(FOnMyProgress) then
      FOnMyProgress(PercentComplete);
  end
  else begin
    Synchronize(
      procedure
      begin
        CallMyProgress(PercentComplete);
      end);
  end;
end;

procedure TMyThread.Execute;
var
  I: Integer;
begin
  for I := 0 to 100 do begin
    CallMyProgress(I);
    Sleep(10);
  end;
end;
</pre>
<p>The magic is that the <em>Anonymous Method</em> captures the value of the <em>PercentComplete</em> variable. Thus it will be totally safe to use <em>Queue</em> instead of <em>Synchronize</em> here.</p>
<p>I&#8217;m using a little trick here to ensure that the critical code is called inside the GUI thread without having a separate method. The ID of the GUI thread is stored in <em>MainThreadID</em>, so I just check if the result of the function <em>GetCurrentThreadID</em> matches this value and call <em>Synchronize</em> otherwise.</p>
<p>One note using <em>Queue</em>: when the thread is freed, all pending <em>Queue</em> calls are removed. So if your code depends on all these calls being handled in the GUI thread you have to make sure that the thread instance lives at least that long.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>The Visitor Pattern &#8211; Part 4</title>
		<link>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-4/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-4/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:17:43 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=105</guid>
		<description><![CDATA[The interface approach introduced in Part 2 of this series and extended in Part 3 did cover most of our needs. But there is nothing that can&#8217;t be done better with the right tools. I&#8217;ve been using this approach for &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The interface approach introduced in Part 2 of this series and extended in Part 3 did cover most of our needs. But there is nothing that can&#8217;t be done better with the right tools.<br />
<span id="more-105"></span><br />
I&#8217;ve been using this approach for a couple of years and it made my life a lot easier. You need an export as DXF? No problem! Displaying in OpenGL? I&#8217;ll write a new visitor!</p>
<p>Writing the additional interfaces was easy done with the help of a customized code template, so that has never been a pain. The only thing that bothered me over time was that I could only apply the Visitor Pattern to classes I have control of. I just wasn&#8217;t able to visit, say, all the components of a TForm in a descent fashion (i.e. not queueing <em>if component is something then &lt;typecast&gt;</em>).</p>
<p>While digging through the new features of Delphi 2010 I discovered a solution which is as clean, lean, flexible and elegant as it could be. A little RTTI and some decent naming convention did the trick. Here is the code:</p>
<pre class="brush:delphi">unit uVisitor;

interface

type
  TVisitor = class
  public
    procedure Visit(Instance: TObject); virtual;
  end;

implementation

uses
  Rtti;

procedure TVisitor.Visit(Instance: TObject);
var
  context: TRttiContext;
  currentClass: TClass;
  params: TArray
;
  paramType: TRttiType;
  selfMethod: TRttiMethod;
  S: string;
begin
  context := TRttiContext.Create;
  currentClass := Instance.ClassType;
  repeat
    S := currentClass.ClassName;
    Delete(S, 1, 1); // remove "T"
    for selfMethod in context.GetType(self.ClassType).GetMethods('Visit' + S) do begin
      params := selfMethod.GetParameters;
      if (Length(params) = 1) then begin
        paramType := params[0].ParamType;
        if ParamType.IsInstance and (ParamType.AsInstance.MetaclassType = currentClass)then begin
          selfMethod.Invoke(Self, [Instance]);
          Exit;
        end;
      end;
    end;
    currentClass := currentClass.ClassParent;
  until currentClass = nil;
end;

end.
</pre>
<p>And here is a visitor capable of handling some VCL controls on a form together with an example of its usage:</p>
<pre class="brush:delphi">type
  TMyVisitor = class(TVisitor)
  public
    procedure VisitButton(Instance: TButton);
    procedure VisitLabel(Instance: TLabel);
    procedure VisitEdit(Instance: TEdit);
    procedure VisitMemo(Instance: TMemo);
  end;

procedure TMyVisitor.VisitButton(Instance: TButton);
begin
  Instance.Caption := 'a button';
end;

procedure TMyVisitor.VisitEdit(Instance: TEdit);
begin
  Instance.Text := 'an edit';
end;

procedure TMyVisitor.VisitLabel(Instance: TLabel);
begin
  Instance.Caption := 'a label';
end;

procedure TMyVisitor.VisitMemo(Instance: TMemo);
begin
  Instance.Lines.Clear;
  Instance.Lines.Add('a memo');
end;

procedure TForm40.Button1Click(Sender: TObject);
var
  I: Integer;
  visitor: TMyVisitor;
begin
  visitor := TMyVisitor.Create;
  try
    for I := 0 to ComponentCount - 1 do
      visitor.Visit(Components[I]);
  finally
    visitor.Free;
  end;
end;
</pre>
<p>If you need to visit some class, just introduce a new method with a suitable name and signature and you are done. No new interfaces, no fiddling around with classes. It just works right out of the box.</p>
<p>I&#8217;m still visualizing some possible scenarios where this approach can be useful, too. Stay tuned.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-4/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Visitor Pattern &#8211; Part 3</title>
		<link>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-3/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-3/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 08:13:37 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=103</guid>
		<description><![CDATA[In Part 2 of this series we learned about a more flexible implementation of the Visitor Pattern than the traditional approach. But we can do better. When we have a usual class inheritance within our shape or whatever classes, it &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In Part 2 of this series we learned about a more flexible implementation of the Visitor Pattern than the traditional approach. But we can do better.<br />
<span id="more-103"></span><br />
When we have a usual class inheritance within our shape or whatever classes, it might be desirable to handle groups of classes with a common ancestor all the same. For now we have to implement each interface individually. A slight change does the trick. We introduce a visitor interface for TAbstractShape, make TAbstractShape.Accept not abstract. Then we change the Accept implementations of the derived shapes to first check the visitor implementing the interface and call inherited otherwise.</p>
<pre class="brush:delphi">unit uShapeBase;

interface

uses
  Classes, SysUtils;

type
  ENotSupported = class(Exception);

type
  TAbstractShape = class
  public
    procedure Accept(Visitor: IInterface); virtual;
  end;

  IAbstractShapeVisitor = interface
    ['{7ED85A22-564A-4F23-AF32-37D29FD3C623}']
    procedure VisitAbstractShape(Instance: TAbstractShape);
  end;

  { we avoid ref-counting here }
  TShapeVisitor = class(TInterfacedPersistent)
  public
    procedure Visit(Instance: TAbstractShape);
  end;

type
  TShapeRectangle = class(TAbstractShape)
  private
    FX0: Double;
    FX1: Double;
    FY0: Double;
    FY1: Double;
  public
    procedure Accept(Visitor: IInterface); override;
    property X0: Double read FX0 write FX0;
    property X1: Double read FX1 write FX1;
    property Y0: Double read FY0 write FY0;
    property Y1: Double read FY1 write FY1;
  end;

  IShapeRectangleVisitor = interface
    ['{6F521E71-5DB8-4ECE-B453-60F9A3B8BE22}']
    procedure VisitShapeRectangle(Instance: TShapeRectangle);
  end;

type
  TShapeCircle = class(TAbstractShape)
  private
    FCenterX: Double;
    FCenterY: Double;
    FRadius: Double;
  public
    procedure Accept(Visitor: IInterface); override;
    property CenterX: Double read FCenterX write FCenterX;
    property CenterY: Double read FCenterY write FCenterY;
    property Radius: Double read FRadius write FRadius;
  end;

  IShapeCircleVisitor = interface
    ['{27D7DCD3-952A-4879-8667-E86023612BFB}']
    procedure VisitShapeCircle(Instance: TShapeCircle);
  end;

implementation

procedure TShapeVisitor.Visit(Instance: TAbstractShape);
begin
  Instance.Accept(Self);
end;

procedure TShapeCircle.Accept(Visitor: TShapeVisitor);
var
  myVisitor: IShapeCircleVisitor;
begin
  if Supports(Visitor, IShapeCircleVisitor, myVisitor) then
    myVisitor.VisitShapeCircle(Self)
  else
    inherited;
end;

procedure TShapeRectangle.Accept(Visitor: IInterface);
var
  myVisitor: IShapeRectangleVisitor;
begin
  if Supports(Visitor, IShapeRectangleVisitor, myVisitor) then
    myVisitor.VisitShapeRectangle(Self)
  else
    inherited;
end;

procedure TAbstractShape.Accept(Visitor: IInterface);
var
  myVisitor: IAbstractShapeVisitor;
begin
  if Supports(Visitor, IAbstractShapeVisitor, myVisitor) then
    myVisitor.VisitAbstractShape(Self)
  else
    raise ENotSupported.Create('Visitor doesn''t support ' + ClassName);
end;

end.</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/17/the-visitor-pattern-part-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Visitor Pattern &#8211; Part 2</title>
		<link>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-2/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-2/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 21:33:28 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=101</guid>
		<description><![CDATA[In Part 1 of this series we learned about the benefits of the Visitor Pattern and saw a basic approach according to the GoF description. As clean and elegant the visitor pattern might look in the first place, it nonetheless &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In Part 1 of this series we learned about the benefits of the Visitor Pattern and saw a basic approach according to the GoF description.</p>
<p>As clean and elegant the visitor pattern might look in the first place, it nonetheless has its disadvantages. Say, we want to add a new shape TShapeTriangle. We have to do it inside the same unit the other shapes are declared. As the shapes reference the visitor and the visitor references the shapes we have to put all shape classes together with the visitor into the same unit. Although this might work in some smaller scenarios, it definitely doesn&#8217;t in most of the real ones. Probably this is one of the reasons why the Visitor Pattern is not as famous as it should be.</p>
<p>Can we find a solution? Yes, we can!<br />
<span id="more-101"></span></p>
<p>Lets examine why there is such a close coupling between all the shapes and the visitor: The shapes use the visitor&#8217;s method corresponding to their own class and the visitor has to know about all the shapes it has to handle. How can we break this up?</p>
<p>The answer are <strong>interfaces</strong>! Instead of declaring a visitor capable of handling every defined shape, we declare an interface for each shape that only handles that specific shape.</p>
<pre class="brush:delphi">unit uShapeBase;

interface

uses
  Classes;

type
  TAbstractShape = class
  public
    procedure Accept(Visitor: IInterface); virtual; abstract;
  end;

  { we avoid ref-counting here }
  TShapeVisitor = class(TInterfacedPersistent)
  public
    procedure Visit(Instance: TAbstractShape);
  end;

type
  TShapeRectangle = class(TAbstractShape)
  private
    FX0: Double;
    FX1: Double;
    FY0: Double;
    FY1: Double;
  public
    procedure Accept(Visitor: IInterface); override;
    property X0: Double read FX0 write FX0;
    property X1: Double read FX1 write FX1;
    property Y0: Double read FY0 write FY0;
    property Y1: Double read FY1 write FY1;
  end;

  IShapeRectangleVisitor = interface
    ['{6F521E71-5DB8-4ECE-B453-60F9A3B8BE22}']
    procedure VisitShapeRectangle(Instance: TShapeRectangle);
  end;

type
  TShapeCircle = class(TAbstractShape)
  private
    FCenterX: Double;
    FCenterY: Double;
    FRadius: Double;
  public
    procedure Accept(Visitor: IInterface); override;
    property CenterX: Double read FCenterX write FCenterX;
    property CenterY: Double read FCenterY write FCenterY;
    property Radius: Double read FRadius write FRadius;
  end;

  IShapeCircleVisitor = interface
    ['{27D7DCD3-952A-4879-8667-E86023612BFB}']
    procedure VisitShapeCircle(Instance: TShapeCircle);
  end;

implementation

uses
  SysUtils;

procedure TShapeVisitor.Visit(Instance: TAbstractShape);
begin
  Instance.Accept(Self);
end;

procedure TShapeCircle.Accept(Visitor: TShapeVisitor);
begin
  (Visitor as IShapeCircleVisitor).VisitShapeCircle(Self);
end;

procedure TShapeRectangle.Accept(Visitor: TShapeVisitor);
begin
  (Visitor as IShapeRectangleVisitor).VisitShapeRectangle(Self);
end;

end.
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Visitor Pattern &#8211; Part 1</title>
		<link>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 14:12:01 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=99</guid>
		<description><![CDATA[Some of you might have already heard of the Visitor Pattern, especially if you have read the GoF book Design Patterns, but do you really use it? Do you use it often? The common answer to this question is No. &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Some of you might have already heard of the Visitor Pattern, especially if you have read the GoF book <a href="http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612" target="_blank"><em>Design Patterns</em></a>, but do you really use it? Do you use it often?</p>
<p>The common answer to this question is <em>No</em>. Once I was even confrontated with the question <em>&#8220;Does anybody use it in real code at all?&#8221;</em>.</p>
<p>Well, I do &#8211; and here I&#8217;m going to explain the <em>why</em> and the <em>how</em>. Actually there are different <em>hows</em> and at the end I will introduce a real elegant <em>how</em>&#8230;<br />
<span id="more-99"></span></p>
<p>Some basics: the Visitor Pattern is used to decouple an operation from the class it operates on and thus allows to create new operations without changing the class.</p>
<p>Let me give you an example: Assume we have a shape class providing the necessary properties to define the shape completely. To draw the shape onto a TCanvas we can introduce a Draw method with a Canvas as parameter. Easy done and easily extended to other shapes. We normally would introduce a TAbstractShape with an abstract Draw method ond override this in the derived classes.</p>
<p>Next task will be to store the shapes somehow into an inifile and read it back. The classical approach would be to introduce two methods LoadFromFile and SaveToFile each with a TCustomInifile parameter probably accompanied by a section name. I&#8217;m sure we&#8217;ve all done that before.</p>
<p>Requirements change: the drawing should be done with OpenGL and instead of inifiles we use XML now &#8211; but the other behaviour has to remain for compatibility reasons. I know, there are OpenGL wrappers that emulate a TCanvas and so are XML wrappers emulating a TCustomInifile, but honestly &#8211; such an approach is just crap, isn&#8217;t it? We have to introduce some overloaded methods with an OpenGL context for drawing and an XMLDocument for reading and writing to get this done properly. Oh, I just heard someone mentioning Direct3D&#8230;</p>
<p>We are actually following a pattern here: introduce an abstract method in the abstract ancestor and implement the specific behaviour in the derived classes. As a side effect we have to <em>use</em> a bunch of units in the abstract class that normally wouldn&#8217;t belong there. This can be really awkward when you need the classes, but don&#8217;t use the additional functionality, like drawing to OpenGL or writing to XML. Although a perfect valid object-oriented approach, it doesn&#8217;t contribute to the modularity of the application.</p>
<p>Here the Visitor Pattern steps in. Its goal is to move the operations from the class (in our case TAbstractShape and descendants) to different visitor classes. So there will be one for drawing to a TCanvas, one for the OpenGL output, two classes for reading and writing inifiles and two for reading and writing XML files.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Anticlimax</title>
		<link>http://www.uweraabe.de/Blog/2010/08/11/anticlimax/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/11/anticlimax/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 13:24:42 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=67</guid>
		<description><![CDATA[It looks like the recent preview of RAD Studio XE didn&#8217;t met expectations of many developers resulting in a massive popular outrage. Beleive it or not, but ranting and shouting will not change anything about the upcoming release. I suggest &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/11/anticlimax/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>It looks like the recent <a href="http://www.embarcadero.com/rad-studio-xe-preview" target="_blank">preview</a> of RAD Studio XE didn&#8217;t met expectations of many developers resulting in a massive popular outrage.</p>
<p>Beleive it or not, but ranting and shouting will not change anything about the upcoming release. I suggest to calm down and start talking decently with each other.</p>
<p>Obviously the people at Embarcadero have something to explain and just missed the point to do it properly in advance. That might have been the wrong way, but honestly, we are all human and talking about bad news is nothing we are keen to do.</p>
<p>So be generous. Imagine you were in their position. Let DavidI and Mike Rozlog take a breath, wait what they have to say and then decide on the information you get.</p>
<p>Staying with Delphi or going away is no decision that has to be done today or tomorrow. It should neither be done during a heated situation like we have now.</p>
<p>After all we are still developers. We are used to tackle a problem with logic instead of speculating and ranting. I am not aware of any bug that has been fixed by shouting at it.</p>
<p>There is something going wrong, no question. Lets start a debugging session and find out what it is and how to fix it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/11/anticlimax/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>&#8220;simulating a computer with an infinite amount of memory&#8221;</title>
		<link>http://www.uweraabe.de/Blog/2010/08/09/simulating-a-computer-with-an-infinite-amount-of-memory/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/09/simulating-a-computer-with-an-infinite-amount-of-memory/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 16:02:44 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=3</guid>
		<description><![CDATA[Thanks to this article by Raymond Chen we can read what garbage collection really is and (perhaps even more valuable) what it is not. I don&#8217;t want to start a new flame war about garbage collection (and even when &#8211; &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/09/simulating-a-computer-with-an-infinite-amount-of-memory/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Thanks to <a href="http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx" target="_blank">this</a> article by Raymond Chen we can read what garbage collection really is and (perhaps even more valuable) what it is <em>not</em>.</p>
<p>I don&#8217;t want to start a new flame war about garbage collection (and even when &#8211; hey, this is my blog!), but I for myself I&#8217;m glad that Delphi doesn&#8217;t offer such a feature. We are always tempted, aren&#8217;t we?</p>
<p>Not that I don&#8217;t have any memory leaks in my programs. Not that I don&#8217;t use memory already freed. But with the right tools you can actually spot those errors and solve them. Doing so I often find some other error lurking in my code, just waiting to pop up like a jack-in-the-box. If there were no more such leak hunting, I would know less about my code than I do now.</p>
<p>Delphi doesn&#8217;t lack garbage collection &#8211; Delphi doesn&#8217;t need one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/09/simulating-a-computer-with-an-infinite-amount-of-memory/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>A Magical Gathering &#8211; Part 2</title>
		<link>http://www.uweraabe.de/Blog/2010/08/07/a-magical-gathering-part-2/</link>
		<comments>http://www.uweraabe.de/Blog/2010/08/07/a-magical-gathering-part-2/#comments</comments>
		<pubDate>Fri, 06 Aug 2010 22:42:13 +0000</pubDate>
		<dc:creator>Uwe Raabe</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.uweraabe.de/Blog/?p=47</guid>
		<description><![CDATA[From Part 1: take an enumerator, mix it with a class helper and pour it over an invokeable custom variant There it is again. What is he just talking about? Well, it took me a while to find that thing, &#8230; <a href="http://www.uweraabe.de/Blog/2010/08/07/a-magical-gathering-part-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>From <a href="http://www.uweraabe.de/Blog/?p=19">Part 1</a>:</p>
<blockquote><p><em>take an </em>enumerator<em>, mix it with a </em>class helper<em> and pour it over an </em>invokeable custom variant</p></blockquote>
<p>There it is again. <em>What is he just talking about?</em></p>
<p>Well, it took me a while to find that thing, as it isn&#8217;t mentioned very often. But it turned out to be exactly what I needed. So I dived into the sources and figured out what <em>TInvokeableCustomVariant</em> is all about and how to use it. And even the help was in this case, um,  helpful: <a title="RAD Studio Help" href="http://docwiki.embarcadero.com/RADStudio/en/Supporting_Properties_and_Methods_in_Custom_Variants" target="_blank">RAD Studio Help</a><br />
<span id="more-47"></span></p>
<p>It turned out that you can use such variants just like classes with properties and methods. Realizing this it sprang directly to my mind: if our enumerator can return such a variant instead of that semi-usefull record index, we can access the record fields like properties:</p>
<pre class="brush:delphi">data.First_Name</pre>
<p>That was the kind of code I was looking for!</p>
<p>As the class helper seemed to be able to cope with a little bit more, I made it responsible for returning the appropriate variant. The changes were made quickly: the enumerator&#8217;s <em>Current</em> property had to be a <em>Variant</em> and the class helper got an additional property <em>CurrentRec</em> also of type <em>Variant</em>, which is used by the enumerator&#8217;s <em>GetCurrent</em> method.</p>
<p>You need a couple of things to make your own <em>TInvokeableVariantType</em> descendant work. Obviously we need that descendant:</p>
<pre class="brush:delphi">type
  TVarDataRecordType = class(TInvokeableVariantType)
  public
    procedure Clear(var V: TVarData); override;
    procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
    function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; override;
    function SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean; override;
  end;
</pre>
<p>We will only have one instance of that class, so we need a record type for storing the variant data:</p>
<pre class="brush:delphi">type
  TVarDataRecordData = packed record
    VType: TVarType;
    Reserved1, Reserved2, Reserved3: Word;
    DataSet: TDataSet;
    Reserved4: LongInt;
  end;
</pre>
<p>This is a simplified form of the <em>TVarData</em> record declared in <em>system.pas</em> and as we only have to store a reference to the dataset it can be kept as simple as possible.</p>
<p>At last we need a global variable holding that instance of <em>TVarDataRecordType</em>, a function returning the <em>VarType</em> of that instance and another function creating a <em>Variant</em> of that type.</p>
<pre class="brush:delphi">var
  VarDataRecordType: TVarDataRecordType = nil;

function VarDataRecord: TVarType;
begin
  result := VarDataRecordType.VarType;
end;

function VarDataRecordCreate(ADataSet: TDataSet): Variant;
begin
  VarClear(result);
  TVarDataRecordData(result).VType := VarDataRecord;
  TVarDataRecordData(result).DataSet := ADataSet;
end;
</pre>
<p>The <em>Clear</em> and <em>Copy</em> methods of <em>TVarDataRecordType</em> are pretty simple and just call predefined methods from <em>TCustomVariantType</em>. <em>GetProperty</em> and <em>SetProperty</em> is where the work is done:</p>
<pre class="brush:delphi">function TVarDataRecordType.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
var
  fld: TField;
begin
  { Find a field with the property's name. If there is one, return its current value. }
  fld := TVarDataRecordData(V).DataSet.FindField(Name);
  result := (fld &lt;&gt; nil);
  if result then
    Variant(dest) := fld.Value;
end;

function TVarDataRecordType.SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean;
var
  fld: TField;
begin
  { Find a field with the property's name. If there is one, set its value. }
  fld := TVarDataRecordData(V).DataSet.FindField(Name);
  result := (fld &lt;&gt; nil);
  if result then begin
    { Well, we have to be in Edit mode to do this, don't we? }
    TVarDataRecordData(V).DataSet.Edit;
    fld.Value := Variant(Value);
  end;
end;
</pre>
<p>The only thing left to do is the implementation of <em>GetCurrentRec</em> from the class helper:</p>
<pre class="brush:delphi">function TDataSetHelper.GetCurrentRec: Variant;
begin
  Result := VarDataRecordCreate(Self);
end;
</pre>
<p>That&#8217;s it! Now we can write code like:</p>
<pre class="brush:delphi">    for Employee in QuEmployee do begin
      S := Trim(Format('%s %s', [Employee.First_Name, Employee.Last_Name]));
      if Employee.Hire_Date &lt; EncodeDate(1991, 1, 1) then
        S := '*' + S;
      MemOutput.Lines.Add(S);
    end;
</pre>
<p>or</p>
<pre class="brush:delphi">  for Employee in QuEmployee do begin
    s := Employee.First_Name;
    Employee.First_Name := Employee.Last_Name;
    Employee.Last_Name := s;
  end;
</pre>
<p>Magic, isn&#8217;t it?</p>
<p>You can download the complete sources from CodeCentral: <a href="http://cc.embarcadero.com/Item/25386">25386</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.uweraabe.de/Blog/2010/08/07/a-magical-gathering-part-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

