Saturday, August 1, 2020

Applications Built With Delphi ( Add yours with 3 clicks )

Here is a link to a web page I found that lists applications built with Delphi.

The best part about this site... you can add your own software if it's not listed. It comes with a built in editor:

When you click on "Edit" and edit window pops up. Scroll down until you find the appropriate spot to add your software. Click on the left cell and it becomes highlighted.

Click on the little arrow to the left and you will be prompted to insert a row above or below the highlighted cell.

Then simply add your software product and give it a link to your product page. Then add your software description in the right cell.

If you know of a website or web page that maintains a list of applications created with Delphi please add it using the comments. I will keep this post updated with all the links provided.

Gunny Mike

Tuesday, June 30, 2020

The question "What do you want to be when you grow up?" is not just for kids.

  1. Stop your busy life for just three-and-a-half minutes. 
  2. Watch this video.
  3. Answer this question, "What do you want to be when you grow up?" in the comments.

How I use my "Like Buckets"

When I grow up, I want to tell stories. Not just any kind of stories. Stories that inspire people. People just like you. To help me get there, I joined Toastmasters two years ago. Right now, I have three priorities all competing for my spare time. One of those priorities is getting an updated copy of my software out there. The sooner this is done, the less competition there is for my spare time. 😃

What do you want to be when you grow up?

( Answer in the comments below )

Semper Fi
Gunny Mike

Sunday, June 28, 2020

How to create a "Cheat Sheet" of your favorite @Lynda courses

I finally purchased Camtasia a couple weeks ago so I could create videos in support the upgrade I'm doing of my Zilch Standard software. This is just an interim upgrade that I'm doing using an old copy of Delphi 5 with source code from 2006, even though I have Delphi 10.3 😎

I love There are so many courses available on many different subjects. The best part is my free access through the Boston Public Library ( I was paying $40 a month until a co-worker told me I could get access for free using my BPL e-card. Check and see if your local library offers free access to @Lynda.

It's a shame that there are no Delphi or Object Pascal courses on @Lynda. There's a story there but you'll have to ask me in person about this one.

Anyway, had forgotten what the instructor said was the best screen resolution to use. So, I logged back into my account and pulled up my course history. Did a search for what I was looking for and then discovered a hidden gem inside all the courses.

"I discovered a hidden gem inside all the courses"

Notes. I knew you could take notes but I didn't know you could turn those notes into a permanent "cheat sheet". So, I decided to just make a video on how to take notes. It's good practice for me and hopefully you find it beneficial.

Please like this video and subscribe to my YouTube channel.

These are the two courses I took on Lynda:
Camtasia 2019 Essential Training: The Basics (2hr 5min)

Camtasia 2019 Essential Training: Advanced Techniques (2hr 21min)

For voice recording I used my Microsoft LifeChat LX-6000 headphones with built in microphone which I purchased in March 2014.

Semper Fi
Gunny Mike

Friday, May 1, 2020

Delphi Class References - Complete List

I mistakenly hit "Publish" instead of "Save" last night which wound up making this post go live before it was finished. Oh well... it is what it is.

 If you've read some of my earlier posts you know I have been struggling with thinking like a Delphi OOP programmer. I am self-taught. I started with Turbo Pascal 3. And I've been stuck in the top-down, structured mindset for a very long time. Until now.

A few days ago I rediscovered an older (still relevant) book that has been siting on my bookshelf for over twenty years. It's called Delevoping Custom Delphi 3 Components. It was written by Ray Konopka (

"This book is the greatest Delphi book ever."

I posted this image to the Delphi Developer group on Facebook.Warren Postma, who writes the Delphi Code Monkey blog (, made this comment about the book. "This book is the greatest Delphi book ever."

I have only read through the first 43 pages. And I agree 100% with Postma. This is probably the greatest Delphi book ever written.

I never heard of Class References before. Maybe I did and just don't remember. But it doesn't matter.  Konopka introduces Delphi's Class References on page 42. He says, "Class references are typically used to treat a number of different classes as a single class." Then he goes on to explain how this works with a short, concise, extremely meaningful example. The Class Reference used is TControlClass.

Click! I get the concept. It's extremely powerful. Do I see an immediate need for implementing the use of a Class Reference? No. That doesn't mean it's not worth knowing about. Just having the knowledge that this is available is valuable.

I used to coach little league baseball when my boys were younger. There were usually twelve or thirteen kids on a team. You can only field nine kids at a time. So, a few of the kids sat on the bench and would get subbed into other positions as the game went on. One would become a right-fielder, one would become the second-baseman. And sometimes I'd do a double swap and replace the pitcher with a kid off the bench and replace the left-fielder with the kid who was pitching.

That's a nice little story Riley, but what does this have to do with Delphi's Class References?

Each position on a baseball team is filled by a baseball-player. Each individual position on the baseball team is slightly different but they all have one thing in common. They are all baseball-players for example;

  • TRightFielder : TBaseballPlayer;
  • TSecondBaseman : TBaseballPlayer;
  • TPitcher : TBaseballPlayer;
  • TLeftFielder : TBaseballPlayer;
There comes a time when you need to substitute a player or two, or three. Because we all know how mad the parents get when their kid doesn't play. So you have a player-substitute. But this player needs to play any position or quite possibly switch positions.

TBasballPlayerClass = class of TBaseballPlayer;

This lets you do suff like this:

Sub  : TBaseballPlayerClass;
Sub1 : TBaseballPlayer;
Sub2 : TBaseballPlayer;
Sub3 : TBaseballPlayer;

Sub1 :=  Sub.Create ( Self  ); //Sitting on the bench waiting to play
Sub2 :=  Sub.Create ( Self  ); //Sitting on the bench waiting to play
Sub3 :=  Sub.Create ( Self  ); //Sitting on the bench waiting to play

Sub1 :=  TBaseballPlayerClass ( TRightFielder  ); //Play Right Field
Sub2 :=  TBaseballPlayerClass ( TSecondBaseman ); //Play Second Base
Sub3 :=  TBaseballPlayerClass ( TPitcher ); //Go Pitch

or if you change your mind at the last minute

Sub1 :=  Sub3; //You pitch instead
Sub3 :=  TBaseballPlayerClass ( TRightFielder  ); //You go to Right Field

Once I understood the power and concept of Delphi's Class References I wondered just how many Class References are out there. So I did a search and created this list.

Semper Fi
Gunny Mike

Feedback is always welcome

File LocationClass Reference
data\Data.DB.pasTCheckConstraintClass = class of TCheckConstraint;
data\Data.DB.pasTCheckConstraintsClass = class of TCheckConstraints;
data\Data.DB.pasTDataSetClass = class of TDataSet;
data\Data.DB.pasTFieldClass = class of TField;
data\Data.DB.pasTFieldDefClass = class of TFieldDef;
data\Data.DB.pasTFieldDefListClass = class of TFieldDefList;
data\Data.DB.pasTFieldDefsClass = class of TFieldDefs;
data\Data.DB.pasTFieldListClass = class of TFieldList;
data\Data.DB.pasTFieldsClass = class of TFields;
data\Data.DB.pasTIndexDefClass = class of TIndexDef;
data\Data.DB.pasTIndexDefsClass = class of TIndexDefs;
data\Data.DB.pasTLookupListClass = class of TLookupList;
data\Data.DB.pasTParamClass = class of TParam;
data\Data.DB.pasTParamObjectClass = class of TParamObject;
data\Data.DB.pasTParamsClass = class of TParams;
data\datasnap\Datasnap.DSHTTPClient.pasTDSHTTPClass = class of TDSHTTP;
data\datasnap\Datasnap.DSReflect.pasTDSAdapterClassType = class of TDSAdapterClass;
data\datasnap\Datasnap.DSServer.pasTServerClassAdapterClass = class of TServerClassAdapter;
data\dbx\Data.DBXClient.pasTDBXClientDriverLoaderClass = class of TObject;
data\dbx\Data.DBXCommon.pasTDBXDriverClass = class of TDBXDriver;
data\dbx\Data.DBXCommon.pasTDBXDriverLoaderClass = class of TDBXDriverLoader;
data\dbx\Data.DBXCommon.pasTDBXPropertiesClass = class of TDBXProperties;
data\dbx\Data.DBXDynalink.pasTDBXDynalinkDriverCommonLoaderClass = class of TDBXDynalinkDriverCommonLoader;
data\dbx\Data.DBXDynalink.pasTDBXDynalinkDriverLoaderClass = class of TClassRegistryObject; // class of TObject;
data\dbx\Data.DBXPlatform.pasTObjectClass = class of TFactoryObject;
data\dbx\Data.DBXPlatform.pasTTransportFilterClass = class of TBaseTransportFilter;
data\dsnap\Datasnap.DataBkr.pasTRemoteDataModuleClass = class of TRemoteDataModule;
data\ems\EMS.DataSetResource.pasTEMSDataSetAdaptorClass = class of TEMSDataSetAdaptor;
data\firedac\FireDAC.Comp.BatchMove.pasTFDBatchMoveDriverClass = class of TFDBatchMoveDriver;
data\firedac\FireDAC.Comp.Client.pasTFDCustomConnectionClass = class of TFDCustomConnection;
data\firedac\FireDAC.Comp.Client.pasTFDCustomManagerClass = class of TFDCustomManager;
data\firedac\FireDAC.Comp.Script.pasTFDScriptCommandClass = class of TFDScriptCommand;
data\firedac\FireDAC.DatS.pasTFDDatSMechBaseClass = class of TFDDatSMechBase;
data\firedac\FireDAC.DatS.pasTFDDatSObjectClass = class of TFDDatSObject;
data\firedac\FireDAC.Phys.MongoDBWrapper.pasTOperationClass = class of TOperation;
data\firedac\FireDAC.Phys.ODBCWrapper.pasEODBCNativeExceptionClass = class of EODBCNativeException;
data\firedac\FireDAC.Phys.ODBCWrapper.pasTODBCLibClass = class of TODBCLib;
data\firedac\FireDAC.Phys.OracleWrapper.pasTOCILobLocatorClass = class of TOCILobLocator;
data\firedac\FireDAC.Phys.OracleWrapper.pasTOCICollectionClass = class of TOCICollection;
data\firedac\FireDAC.Phys.pasTFDPhysConnectionClass = class of TFDPhysConnection;
data\firedac\FireDAC.Phys.pasTFDPhysDriverClass = class of TFDPhysDriver;
data\firedac\FireDAC.Phys.PGWrapper.pasTPgVariableClass = class of TPgVariable;
data\firedac\FireDAC.Phys.SQLiteWrapper.pasTSQLiteExtensionClass = class of TSQLiteExtension;
data\firedac\FireDAC.Phys.SQLiteWrapper.pasTSQLiteVModuleClass = class of TSQLiteVModule;
data\firedac\FireDAC.Stan.Def.pasTFDDefinitionClass = class of TFDDefinition;
data\firedac\FireDAC.Stan.Error.pasEFDDBEngineExceptionClass = class of EFDDBEngineException;
data\firedac\FireDAC.Stan.Error.pasEFDExceptionClass = class of EFDException;
data\firedac\FireDAC.Stan.Error.pasTFDDBErrorClass = class of TFDDBError;
data\firedac\FireDAC.Stan.Factory.pasTFDObjectClass = class of TFDObject;
data\firedac\FireDAC.Stan.Intf.pasTFDConnectionDefParamsClass = class of TFDConnectionDefParams;
data\firedac\FireDAC.Stan.Intf.pasTFDStorableObjectClass = class of TFDStorableObject;
data\firedac\FireDAC.Stan.Option.pasTFDFetchOptionsClass = class of TFDFetchOptions;
data\firedac\FireDAC.Stan.Option.pasTFDResourceOptionsClass = class of TFDResourceOptions;
data\firedac\FireDAC.Stan.Option.pasTFDUpdateOptionsClass = class of TFDUpdateOptions;
data\firedac\FireDAC.Stan.Util.pasTFDThreadMsgClass = class of TFDThreadMsgBase;
data\rest\REST.Authenticator.OAuth.pasTOAuth1SignatureMethodClass = class of TOAuth1SignatureMethod;
data\rest\REST.Backend.EMSApi.pasTEMSClientHTTPErrorClass = class of EEMSClientHTTPError;
data\rest\REST.Backend.KinveyApi.pasTKinveyAPIErrorClass = class of EKinveyAPIError;
data\rest\REST.Backend.ParseAPI.pasTParseAPIErrorClass = class of EParseAPIError;
data\vclctrls\Vcl.DBGrids.pasTColumnClass = class of TColumn;
databinding\components\Data.Bind.Components.pasTBindEditorFactoryClass = class of TBindEditorFactory;
databinding\components\Data.Bind.Components.pasTContainedBindCompClass = class of TContainedBindComponent;
databinding\components\Data.Bind.DBLinks.pasTBaseDBGridLinkColumnClass = class of TBaseDBGridLinkColumn;
databinding\components\Data.Bind.DBLinks.pasTBindDBColumnFactoryClass = class of TBindDBColumnFactory;
databinding\components\Data.Bind.Grid.pasTBaseLinkGridToDataSourceColumnClass = class of TBaseLinkGridToDataSourceColumn;
databinding\components\Data.Bind.Grid.pasTLinkGridToDataSourceColumnFactoryClass = class of TLinkGridToDataSourceColumnFactory;
databinding\components\Data.Bind.ObjectScope.pasTBindFieldDefClass = class of TBindFieldDef;
databinding\components\Data.Bind.ObjectScope.pasTBindFieldDefsClass = class of TBindFieldDefs;
databinding\components\Data.Bind.ObjectScope.pasTGeneratorBindFieldDefsClass = class of TGeneratorFieldDefs;
databinding\components\Data.Bind.ObjectScope.pasTValueGeneratorClass = class of TValueGenerator;
databinding\engine\System.Bindings.CustomScope.pasTScopeClass = class of TCustomScope;
databinding\graph\GraphView.pasTGraphEdgeClass = class of TGraphEdge;
databinding\graph\GraphView.pasTGraphNodeClass = class of TGraphNode;
DUnit\Contrib\DUnitWizard\Source\Common\XPWinBase.pasTTEXPWin32 = class of EXPWin32;
"DUnit\Contrib\DUnitWizard\Source\DelphiExperts\DUnitProject\ dunit\Examples\TestedUnitParserTest_1.pas"TTClass = class of TXPStubClass1;
DUnit\examples\testexception\Unit1Test.pasExceptionClass = class of Exception;
DUnit\src\TestFramework.pasExceptionClass = class of Exception;
DUnit\src\TestFramework.pasTTestCaseClass = class of TTestCase;
DunitX\DUnitX.ComparableFormat.pasTDUnitXComparableFormatClass = class of TDUnitXComparableFormat;
DunitX\DUnitX.InternalDataProvider.pasTTestDataProviderClass = class of TTestDataProvider;
DunitX\DUnitX.Utils.pasTCustomAttributeClass = class of TCustomAttribute;
Experts\DSServerMethodsExpertsCreators.pasTDSServerMethodsCreatorModuleClass = class of TDSServerMethodsCreatorModule;
fmx\FMX.ActnList.pasTActionLinkClass = class of TActionLink;
fmx\FMX.Controls.Model.pasTDataModelClass = class of TDataModel;
fmx\FMX.Controls.pasTCustomTextSettingsClass = class of TCustomTextSettings;
fmx\FMX.Controls.pasTHintClass = class of THint;
fmx\FMX.Controls.Presentation.pasTPresentationProxyClass = class of TPresentationProxy;
fmx\FMX.Filter.pasTFilterClass = class of TFilter;
fmx\FMX.Gestures.pasTCustomGestureRecognizerClass = class of TCustomGestureRecognizer;
fmx\FMX.Gestures.pasTGestureEngineClass = class of TCustomGestureEngine;
fmx\FMX.Gestures.pasTGestureEngineType = class of TGestureEngine;
fmx\FMX.Gestures.pasTGestureStreamDataClass = class of TGestureStreamData;
fmx\FMX.Graphics.pasTCanvasClass = class of TCanvas;
fmx\FMX.Graphics.pasTCustomBitmapCodecClass = class of TCustomBitmapCodec;
fmx\FMX.Graphics.pasTFontClass = class of TFont;
fmx\FMX.Graphics.pasTFontColorForStateClass = class of TFontColorForState;
fmx\FMX.Graphics.pasTPrinterCanvasClass = class of TPrinterCanvas;
fmx\FMX.Graphics.pasTTextSettingsClass = class of TTextSettings;
fmx\FMX.Grid.iOS.pasTColumnLinkClass = class of TColumnLink;
fmx\FMX.Grid.iOS.pasTiOSCellControlClass = class of TiOSCellControl;
fmx\FMX.Grid.pasTColumnClass = class of TColumn;
fmx\FMX.Helpers.Mac.pasTOSXMessageClass = class of TOSXMessage;
fmx\FMX.ImgList.pasTDestinationItemClass = class of TCustomDestinationItem;
fmx\FMX.ImgList.pasTImageListClass = class of TCustomImageList;
fmx\FMX.ImgList.pasTLayerClass = class of TLayer;
fmx\FMX.ImgList.pasTSourceItemClass = class of TCustomSourceItem;
fmx\FMX.ListBox.pasTListBoxSelectorClass = class of TListBoxSelector;
fmx\FMX.ListView.Appearances.pasTGroupClass = class of TPresetItemObjects;
fmx\FMX.ListView.Appearances.pasTItemAppearanceObjectsClass = class of TItemAppearanceObjects;
fmx\FMX.ListView.Appearances.pasTListItemObjectClass = class of TListItemDrawable;
fmx\FMX.ListView.Types.pasTListItemViewType = class of TListItemView;
fmx\FMX.Media.pasTCaptureDeviceClass = class of TCaptureDevice;
fmx\FMX.Media.pasTCustomMediaCodecClass = class of TCustomMediaCodec;
fmx\FMX.MultiResBitmap.pasTFixedBitmapItemClass = class of TFixedBitmapItem;
fmx\FMX.MultiResBitmap.pasTCustomBitmapItemClass = class of TCustomBitmapItem;
fmx\FMX.MultiView.pasTMultiViewPresentationClass = class of TMultiViewPresentation;
fmx\FMX.Presentation.Android.pasTAndroidNativeViewClass = class of TAndroidNativeView;
fmx\FMX.Presentation.iOS.pasTiOSNativeViewClass = class of TiOSNativeView;
fmx\FMX.Presentation.Style.Common.pasTNativeStyledControlClass = class of TNativeStyledControl;
fmx\FMX.Presentation.Style.pasTStyledPresentationClass = class of TStyledPresentation;
fmx\FMX.Presentation.Win.pasTWinPresentationClass = class of TWinPresentation;
fmx\FMX.Printer.pasTPrinterClass = class of TPrinter;
fmx\FMX.StdActns.pasTCustomValueRangeClass = class of TCustomValueRange;
fmx\FMX.TabControl.pasTTabItemClass = class of TTabItem;
fmx\FMX.Text.pasTTextServiceClass = class of TTextService;
fmx\FMX.TextLayout.pasTTextLayoutClass = class of TTextLayout;
fmx\FMX.Types.pasTCaretClass = class of TCustomCaret;
fmx\FMX.Types.pasTFmxObjectClass = class of TFmxObject;
fmx\FMX.Types.pasTTabListClass = class of TTabList;
fmx\FMX.Types3D.pasTContextClass = class of TContext3D;
fmx\FMX.Types3D.pasTMaterialClass = class of TMaterial;
Indy10\Core\IdCommandHandlers.pasTIdCommandHandlerClass = class of TIdCommandHandler;
Indy10\Core\IdContext.pasTIdContextClass = class of TIdContext;
Indy10\Core\IdCustomTCPServer.pasTIdServerContextClass = class of TIdServerContext;
Indy10\Core\IdCustomTransparentProxy.pasTIdCustomTransparentProxyClass = class of TIdCustomTransparentProxy;
Indy10\Core\IdIOHandler.pasTIdIOHandlerClass = class of TIdIOHandler;
Indy10\Core\IdReply.pasTIdRepliesClass = class of TIdReplies;
Indy10\Core\IdReply.pasTIdReplyClass = class of TIdReply;
Indy10\Core\IdServerIOHandlerSocket.pasTIdIOHandlerSocketClass = class of TIdIOHandlerSocket;
Indy10\Core\IdThread.pasTIdThreadClass = class of TIdThread;
Indy10\Core\IdThread.pasTIdThreadWithTaskClass = class of TIdThreadWithTask;
Indy10\Core\IdUDPServer.pasTIdUDPListenerThreadClass = class of TIdUDPListenerThread;
Indy10\Protocols\IdAttachment.pasTIdAttachmentClass = class of TIdAttachment;
Indy10\Protocols\IdAuthentication.pasTIdAuthenticationClass = class of TIdAuthentication;
Indy10\Protocols\IdCoder.pasTIdDecoderClass = class of TIdDecoder;
Indy10\Protocols\IdCoder.pasTIdEncoderClass = class of TIdEncoder;
Indy10\Protocols\IdCoder3to4.pasTIdEncoder3to4Class = class of TIdEncoder3to4;
Indy10\Protocols\IdCookie.pasTIdCookieClass = class of TIdCookie;
Indy10\Protocols\IdDNSResolver.pasTResultRecordClass = class of TResultRecord;
Indy10\Protocols\IdDNSServer.pasTIdMWayTreeNodeClass = class of TIdMWayTreeNode;
Indy10\Protocols\IdFTPListParseBase.pasTIdFTPListParseClass = class of TIdFTPListBase;
Indy10\Protocols\IdHash.pasTIdHashClass = class of TIdHash;
Indy10\Protocols\IdHeaderCoderBase.pasTIdHeaderCoderClass = class of TIdHeaderCoder;
Indy10\Protocols\IdMessageCoder.pasTIdMessageEncoderClass = class of TIdMessageEncoder;
Indy10\Protocols\IdMessageCollection.pasTIdMessageItems = class of TIdMessageItem;
Indy10\Protocols\IdMessageParts.pasTIdMessagePartClass = class of TIdMessagePart;
Indy10\Protocols\IdSSL.pasTIdClientSSLClass = class of TIdSSLIOHandlerSocketBase;
Indy10\Protocols\IdSSL.pasTIdServerSSLClass = class of TIdServerIOHandlerSSLBase;
Indy10\Protocols\IdSSLOpenSSLHeaders.pasTIdOpenSSLAPICryptoError = class of EIdOpenSSLAPICryptoError;
Indy10\Protocols\IdSSLOpenSSLHeaders.pasTIdOpenSSLAPISSLError = class of EIdOpenSSLAPISSLError;
Indy10\Protocols\IdZLibCompressorBase.pasTIdZLibCompressorBaseClass = class of TIdZLibCompressorBase;
Indy10\System\IdException.pasTClassIdException = class of EIdException;
Indy10\System\IdStack.pasTIdSocketListClass = class of TIdSocketList;
Indy10\System\IdStack.pasTIdStackClass = class of TIdStack;
internet\WBComp.pasTBehaviorElementEventsClass = class of TBehaviorElementEvents;
internet\WBComp.pasTCustomElementBehaviorClass = class of TCustomElementBehavior;
internet\Web.CGIHTTP.pasTCGIRequestClass = class of TCGIRequest;
internet\Web.CGIHTTP.pasTCGIResponseClass = class of TCGIResponse;
internet\Web.CGIHTTP.pasTWinCGIRequestClass = class of TWinCGIRequest;
internet\Web.CGIHTTP.pasTWinCGIResponseClass = class of TWinCGIResponse;
internet\Web.DBWeb.pasTHTMLTableColumnClass = class of THTMLTableColumn;
internet\Web.HTTPApp.pasTContentParserClass = class of TAbstractContentParser;
internet\Web.Win.ISAPIThreadPool.pasTISAPIThreadPoolClass = class of TISAPIThreadPool;
Property Editors\BindCompEdit.pasTBindScopeFactoryClass = class of TBindScopeFactory;
Property Editors\BindCompEdit.pasTComponentClassFactoryClass = class of TControlClassFactory;
Property Editors\BindCompEdit.pasTControlFactoryClass = class of TControlFactory;
Property Editors\BindCompEdit.pas// TControlFrameFactoryClass = class of TControlFrameFactory;
Property Editors\BindCompEdit.pasTDataBindingListDesignerClass = class of TDataBindingListDesigner;
Property Editors\BindCompEdit.pasTNavigatorFactoryClass = class of TNavigatorFactory;
Property Editors\BindCompExprEdit.pasTBindCompExprDesignerClass = class of TBindCompExprDesigner;
Property Editors\BindCompExprEdit.pas// TItemStateClass = class of TItemState;
Property Editors\BindVisualizers.pasTBindExpressionVisualizerClass = class of TBindExpressionVisualizer;
Property Editors\ColnEdit.pasTCollectionEditorClass = class of TCollectionEditor;
Property Editors\DSDesign.pasTDSDesignerClass = class of TDSDesigner;
Property Editors\DSDefine.pasTFieldAccessClass = class of TFieldAccess;
Property Editors\OCXReg.pasTOleObjectEditorClass = class of TOleObjectEditor;
rtl\common\System.Actions.pasTContainedActionClass = class of TContainedAction;
rtl\common\System.Actions.pasTContainedActionLinkClass = class of TContainedActionLink;
rtl\common\System.Actions.pasTContainedActionListClass = class of TContainedActionList;
rtl\common\System.Classes.pasTBasicActionClass = class of TBasicAction;
rtl\common\System.Classes.pasTBasicActionLinkClass = class of TBasicActionLink;
rtl\common\System.Classes.pasTCollectionItemClass = class of TCollectionItem;
rtl\common\System.Classes.pasTComponentClass = class of TComponent;
rtl\common\System.Classes.pasTPersistentClass = class of TPersistent;
rtl\common\System.Notification.pasTBaseNotificationCenterClass = class of TBaseNotificationCenter;
rtl\common\System.Permissions.pasTPermissionsServiceClass = class of TPermissionsService;
rtl\common\System.Rtti.pasTRttiClass = class of TRttiObject;
rtl\common\System.Sensors.pasESensorExceptionClass = class of ESensorException;
rtl\common\System.Sensors.pasTGeocoderClass = class of TGeocoder;
rtl\common\System.Sensors.pasTGpsStatusClass = class of TGpsStatus;
rtl\common\System.Sensors.pasTSensorManagerType = class of TSensorManager;
rtl\common\System.Win.ComObj.pasTAutoClass = class of TAutoObject;
rtl\common\System.Win.ComObj.pasTComClass = class of TComObject;
rtl\common\System.Win.ComObj.pasTTypedComClass = class of TTypedComObject;
rtl\common\System.Win.VCLCom.pasTComponentProtectedAccessClass = class of TComponentProtectedAccess;
rtl\net\System.Beacon.pasTBeaconManufacturerDataParserClass = class of TBeaconManufacturerDataParser;
rtl\net\System.Bluetooth.pasTBluetoothManagerClass = class of TBluetoothLEManager;
rtl\net\System.Bluetooth.pasTBluetoothManagerClass = class of TBluetoothManager;
rtl\net\System.Net.URLClient.pasTURLClientClass = class of TURLClient;
rtl\sys\System.pasTClass = class of TObject;
rtl\sys\System.pasTClassHelperBaseClass = class of TClassHelperBase;
rtl\sys\System.pasTInterfacedClass = class of TInterfacedObject;
rtl\sys\System.SysUtils.pasExceptClass = class of Exception;
rtl\sys\System.Types.pasTMultiWaitEventClass = class of TMultiWaitEvent;
rtl\sys\System.Variants.pasTCustomVariantTypeClass = class of TCustomVariantType;
soap\Soap.InvokeRegistry.pasERemotableExceptionClass = class of ERemotableException;
soap\Soap.InvokeRegistry.pasTInvokableClassClass = class of TInvokableClass;
soap\Soap.InvokeRegistry.pasTRemotableClass = class of TRemotable;
soap\Soap.InvokeRegistry.pasTRemotableXSClass = class of TRemotableXS;
soap\Soap.InvokeRegistry.pasTSOAPAttachmentClass = class of TSOAPAttachment;
soap\Soap.InvokeRegistry.pasTSOAPHeaderClass = class of TSOAPHeader;
soap\wsdlimporter\WSDLCppWriter.pasTWSDLCppWriterClass = class of TWSDLCppWriter;
soap\wsdlimporter\WSDLImpWriter.pasTWSDLWriterClass = class of TWSDLWriter;
soap\wsdlimporter\WSDLpasWriter.pasTWSDLpasWriterClass = class of TWSDLpasWriter;
tethering\System.Tether.Manager.pasTTetheringAdapterClass = class of TTetheringAdapter;
tethering\System.Tether.Manager.pasTTetheringProfileClass = class of TTetheringProfile;
tethering\System.Tether.Manager.pasTTetheringProtocolClass = class of TTetheringProtocol;
ToolsAPI\ActionEditors.pasTIDEActionsClass = class of TIDEActions;
ToolsAPI\DataExplorerAPI.pasTFrameClass = class of TFrame;
ToolsAPI\DesignIntf.pasTComponentEditorClass = class of TBaseComponentEditor;
ToolsAPI\DesignIntf.pasTComponentGuidelinesClass = class of TBaseComponentGuidelines;
ToolsAPI\DesignIntf.pasTCustomModuleClass = class of TBaseCustomModule;
ToolsAPI\DesignIntf.pasTDragTargetClass = class of TDragTarget;
ToolsAPI\DesignIntf.pasTPropertyEditorClass = class of TBasePropertyEditor;
ToolsAPI\DesignIntf.pasTSelectionEditorClass = class of TBaseSelectionEditor;
ToolsAPI\PropertyCategories.pasTPropertyCategoryClass = class of TPropertyCategory;
ToolsAPI\TreeIntf.pasTComponentSprigClass = class of TComponentSprig;
ToolsAPI\TreeIntf.pasTRootSprigClass = class of TRootSprig;
ToolsAPI\TreeIntf.pasTSprigClass = class of TSprig;
vcl\CtlPanel.pasTAppletModuleClass = class of TAppletModule;
vcl\CtlPanel.pasTCPLAppletClass = class of TAppletModule;
vcl\CtlPanel.pasTDataModuleClass = class of TDataModule;
vcl\Vcl.ActnCtrls.pasTCustomToolScrollBtnClass = class of TCustomToolScrollBtn;
vcl\Vcl.ActnList.pasTActionLinkClass = class of TActionLink;
vcl\Vcl.ActnMan.pasTActionBarItemClass = class of TActionBarItem;
vcl\Vcl.ActnMan.pasTActionBarsClass = class of TActionBars;
vcl\Vcl.ActnMan.pasTActionClientClass = class of TActionClient;
vcl\Vcl.ActnMan.pasTActionClientItemClass = class of TActionClientItem;
vcl\Vcl.ActnMan.pasTActionClientLinkClass = class of TActionClientLink;
vcl\Vcl.ActnMan.pasTActionClientsClass = class of TActionClients;
vcl\Vcl.ActnMan.pasTCommandPropertiesClass = class of TCommandProperties;
vcl\Vcl.ActnMan.pasTCustomActionBarClass = class of TCustomActionBar;
vcl\Vcl.ActnMan.pasTCustomActionClass = class of TCustomAction;
vcl\Vcl.ActnMan.pasTCustomActionControlClass = class of TCustomActionControl;
vcl\Vcl.ActnMan.pasTCustomColorMapClass = class of TCustomActionBarColorMap;
vcl\Vcl.ActnMenus.pasTAddRemoveItemClass = class of TCustomAddRemoveItem;
vcl\Vcl.ActnMenus.pasTCustomAddRemoveItemClass = class of TCustomAddRemoveItem;
vcl\Vcl.ActnMenus.pasTCustomizeActionToolBarClass = class of TCustomizeActionToolBar;
vcl\Vcl.ActnMenus.pasTCustomMenuExpandBtnClass = class of TCustomMenuExpandBtn;
vcl\Vcl.ActnMenus.pasTCustomPopupClass = class of TCustomActionPopupMenu;
vcl\Vcl.ActnMenus.pasTMenuButtonControlClass = class of TCustomMenuButton;
vcl\Vcl.ActnMenus.pasTMenuItemControlClass = class of TCustomMenuItem;
vcl\Vcl.AxCtrls.pasTActiveFormClass = class of TActiveForm;
vcl\Vcl.AxCtrls.pasTActiveXControlClass = class of TActiveXControl;
vcl\Vcl.AxCtrls.pasTPropertyPageClass = class of TPropertyPage;
vcl\Vcl.ButtonGroup.pasTGrpButtonItemClass = class of TGrpButtonItem;
vcl\Vcl.ButtonGroup.pasTGrpButtonItemsClass = class of TGrpButtonItems;
vcl\Vcl.CaptionedDockTree.pasTCaptionedDockTreeClass = class of TCaptionedDockTree;
vcl\Vcl.CaptionedDockTree.pasTDockCaptionDrawerClass = class of TDockCaptionDrawer;
vcl\Vcl.CategoryButtons.pasTBaseButtonItemClass = class of TBaseButtonItem;
vcl\Vcl.CategoryButtons.pasTButtonCategoriesClass = class of TButtonCategories;
vcl\Vcl.CategoryButtons.pasTButtonCategoryClass = class of TButtonCategory;
vcl\Vcl.CategoryButtons.pasTButtonItemActionLinkClass = class of TButtonItemActionLink;
vcl\Vcl.CategoryButtons.pasTButtonItemClass = class of TButtonItem;
vcl\Vcl.ComCtrls.pasECommonCalExceptClass = class of Exception;
vcl\Vcl.ComCtrls.pasTComboBoxExStringsClass = class of TComboBoxExStrings;
vcl\Vcl.ComCtrls.pasTComboExItemClass = class of TComboExItem;
vcl\Vcl.ComCtrls.pasTComboExItemsClass = class of TComboExItems;
vcl\Vcl.ComCtrls.pasTConversionClass = class of TConversion;
vcl\Vcl.ComCtrls.pasTHeaderSectionClass = class of THeaderSection;
vcl\Vcl.ComCtrls.pasTListColumnClass = class of TListColumn;
vcl\Vcl.ComCtrls.pasTListColumnsClass = class of TListColumns;
vcl\Vcl.ComCtrls.pasTListItemClass = class of TListItem;
vcl\Vcl.ComCtrls.pasTStatusPanelClass = class of TStatusPanel;
vcl\Vcl.ComCtrls.pasTToolButtonActionLinkClass = class of TToolButtonActionLink;
vcl\Vcl.ComCtrls.pasTTreeNodeClass = class of TTreeNode;
vcl\Vcl.Controls.pasTControlActionLinkClass = class of TControlActionLink;
vcl\Vcl.Controls.pasTControlClass = class of TControl;
vcl\Vcl.Controls.pasTDockTreeClass = class of TDockTree;
vcl\Vcl.Controls.pasTDragObjectClass = class of TDragObject;
vcl\Vcl.Controls.pasTHintWindowClass = class of THintWindow;
vcl\Vcl.Controls.pasTPanningWindowClass = class of TCustomPanningWindow;
vcl\Vcl.Controls.pasTWinControlActionLinkClass = class of TWinControlActionLink;
vcl\Vcl.Controls.pasTWinControlClass = class of TWinControl;
vcl\Vcl.DockTabSet.pasTTabDockPanelClass = class of TTabDockPanel;
vcl\Vcl.ExtCtrls.pasTCategoryPanelClass = class of TCustomCategoryPanel;
vcl\Vcl.ExtCtrls.pasTCategoryPanelSurfaceClass = class of TCategoryPanelSurface;
vcl\Vcl.ExtCtrls.pasTEditButtonClass = class of TEditButton;
vcl\Vcl.Forms.pasTCustomFormClass = class of TCustomForm;
vcl\Vcl.Forms.pasTCustomFrameClass = class of TCustomFrame;
vcl\Vcl.Forms.pasTFormClass = class of TForm;
vcl\Vcl.Graphics.pasTGraphicClass = class of TGraphic;
vcl\Vcl.Imaging.GIFImg.pasTColorLookupClass = class of TColorLookup;
vcl\Vcl.Imaging.GIFImg.pasTGIFAppExtensionClass = class of TGIFApplicationExtension;
vcl\Vcl.Imaging.GIFImg.pasTGIFExtensionClass = class of TGIFExtension;
vcl\Vcl.Imaging.pngimage.pasExceptClass = class of Exception;
vcl\Vcl.Imaging.pngimage.pasTChunkClass = class of TChunk;
vcl\Vcl.ListActns.pasTListControlItemClass = class of TListControlItem;
vcl\Vcl.Menus.pasTMenuActionLinkClass = class of TMenuActionLink;
vcl\Vcl.OleAuto.pasTAutoClass = class of TAutoObject;
vcl\Vcl.ScreenTips.pasTScreenTipsWindowClass = class of TScreenTipsWindow;
vcl\Vcl.StdActns.pasTCommonDialogClass = class of TCommonDialog;
vcl\Vcl.StdCtrls.pasTButtonActionLinkClass = class of TButtonActionLink;
vcl\Vcl.StdCtrls.pasTCustomComboBoxStringsClass = class of TCustomComboBoxStrings;
vcl\Vcl.StdCtrls.pasTPushButtonActionLinkClass = class of TPushButtonActionLink;
vcl\Vcl.SvcMgr.pasTServiceClass = class of TService;
vcl\Vcl.Themes.pasTCustomElementServicesClass = class of TCustomElementServices;
vcl\Vcl.Themes.pasTCustomStyleEngineClass = class of TCustomStyleEngine;
vcl\Vcl.Themes.pasTCustomStyleServicesClass = class of TCustomStyleServices;
vcl\Vcl.Themes.pasTStyleHookClass = class of TStyleHook;
vcl\Vcl.Themes.pasTSysStyleHookClass = class of TSysStyleHook;
vcl\Vcl.Touch.GestureMgr.pasTGestureStreamDataClass = class of TGestureStreamData;
vcl\Vcl.Touch.Gestures.pasTCustomGestureRecognizerClass = class of TCustomGestureRecognizer;
vcl\Vcl.Touch.Gestures.pasTGestureEngineClass = class of TCustomGestureEngine;
vcl\Vcl.Touch.Keyboard.pasTCustomKeyboardButtonClass = class of TCustomKeyboardButton;
vcl\Vcl.WinXCtrls.pasTToggleSwitchActionLinkClass = class of TToggleSwitchActionLink;
vcl\Vcl.WinXPanels.pasTCardClass = class of TCard;
vcl\Vcl.WinXPickers.pasTPickerColumnClass = class of TPickerColumn;
xml\Xml.adomxmldom.pasTox4DOMNodeClass = class of Tox4DOMNode;
xml\Xml.Internal.AdomCore_4_3.pasTXmlSignalClass = class of TXmlSignal;
xml\Xml.Internal.CodecUtilsWin32.pasTUnicodeCodecClass = class of TUnicodeCodec;
xml\Xml.Internal.EncodingUtils.pasTEncodingInfoClass = class of TEncodingInfo;
xml\Xml.Internal.OmniXML.pasOmniTXMLAttrClass = class of OmniTXMLAttr;
xml\Xml.Internal.OmniXML.pasOmniTXMLCDATASectionClass = class of OmniTXMLCDATASection;
xml\Xml.Internal.OmniXML.pasOmniTXMLCommentClass = class of OmniTXMLComment;
xml\Xml.Internal.OmniXML.pasOmniTXMLDocumentTypeClass = class of OmniTXMLDocumentType;
xml\Xml.Internal.OmniXML.pasOmniTXMLElementClass = class of OmniTXMLElement;
xml\Xml.Internal.OmniXML.pasOmniTXMLProcessingInstructionClass = class of OmniTXMLProcessingInstruction;
xml\Xml.Internal.OmniXML.pasOmniTXMLTextClass = class of OmniTXMLText;
xml\Xml.omnixmldom.pasTODOMNodeClass = class of TODOMNode;
xml\Xml.Win.msxmldom.pasTMSDOMNodeClass = class of TMSDOMNode;
xml\Xml.Win.msxmldom.pasTMSXMLDOMDocumentFactoryClass = class of TMSXMLDOMDocumentFactory;
xml\Xml.XMLDoc.pasTXMLNodeClass = class of TXMLNode;
xml\Xml.XMLDoc.pasTXMLNodeCollectionClass = class of TXMLNodeCollection;
xml\Xml.XMLSchema.pasTSchemaTranslatorClass = class of TXMLSchemaTranslator;

Monday, April 20, 2020

Delphi Tip of the Day - Export to CSV

This weekend I had a bunch of data inside a FireDAC FDMemtable and I wanted to play around with that data in Excel. So, the first thing I did was review which data formats Excel would accept.

That's excellent! Excel allows both importing from XML and JSON both of which can done using FDMemtable.SaveToFile method. ( SaveToFile documentation )

I created an XML file using the SaveToFile method and then tried to import that file into Excel.

That didn't go so well. Where's my data? I'm starting to feel that "I hate Delphi" thing happening again! Let's try JSON. So. I created a JSON file using the SaveToFile method and then tried importing into Excel. 

"I just want the data in Excel."

That didn't go so well either. I've imported text files hundreds of times into Excel and it just worked. I wasn't in the mood to figure out what was going on. I'll save that for another day. I just want the data in Excel. 

"I know CSV works. Let's find a solution."

I know that text or csv files import just fine into Excel so let's see how to create a CSV file using Delphi. A quick google search turned up exactly what I was looking for, a simple solution written by Uwe Rabbe six years ago. Thank you Uwe!

This works with any TDataSet descendent! And just like that I love Delphi again.

Enjoy - Semper Fi
Gunny Mike

Feedback is always appreciated!

Wednesday, April 15, 2020

Delphi Tip of the Day - First Chance Exception

I'm in the process of upgrading a very old Delphi program that I wrote with my Turbo Pascal, top-down, structured-programming, mindset. One of the major updates I want is for the data to be in a database. So, I'm cruising right along making very good progress. After two days I finally get the algorithm working. And it's producing good results.

Now it's time to get those results into a database table. No big deal. FDMemtable and LocalSQL will do the trick. I'll just add a DataModule to the project. Drop in the necessary components. Add the fields using the fields editor.

I get everything working in the IDE. I'm good to go. All I need to do now is add the SQL. I code up the insert statements. I'm very excited. I will soon have the data in a database table. I push F9 and... BOOM!

"What the hell is a First chance exception?"

You've got to be kidding. I was so close. I started googling all over the internet trying to figure out what a First chance exception is. I just wanted an answer. After an hour or two I gave up. I was tired. I was frustrated. I'll deal with it in the morning. Off to bed I went.

"It turned out to be a very simple fix!"

The next day with a fresh attitude I returned to my project. It turns out this was a very simple fix. I didn't see or think about this the night before. When I added the DataModule to the project it was added to the bottom of the list.

The OnCreate method of Form1 calls the logic in another unit, which in-turn communicates with DataModule1. Because DataModule1 is created after Form1 gets created it caused an exception. All I had to do was move the DataModule1 before Form1.

I literally had the cart before the horse. I remember getting burned by this in the past but totally forgot about it.

Semper Fi,
Gunny Mike

Feedback is always appreciated.

Sunday, March 22, 2020

Delphi Tip of the Day - Object Inspector Search

I was watching an excellent video on how to use the batch move capabilities within Delphi to import text data into a database and had one of those "What the heck just happened" moments. The object inspector was only displaying the "Name" property.

What the heck just happened...

I rewound the video by about 20 seconds and paid careful attention to what was going on. The presenter used the "search" box associated with the Object Inspector. What? I had no idea you could do that. Wow! Game Changer!

I've been staring at the object inspector for years and never even saw the search box even though it's right there, plain as day, in my face. Sure beats scrolling up and down through all the properties anytime I wanted to make a change.

Game Changer!

Alternate Game Changer!

I'd like to thank Bruce McGee for the following "Quick Edit" tip:

Right-click on a control at design time and select Quick Edit from the drop-down menu. It works for VCL and FMX controls. The VCL image on DocWiki is not correct. It actually reads "Caption" instead of "Text" in my version of Delphi.

Semper Fi,
Gunny Mike

Saturday, March 21, 2020

Delphi - SQLite Sample Projects

I've been exploring SQLite within Delphi. There are several sample SQLite applications that come with Delphi if you selected to install the samples during setup. I've put together the list of SQLite samples that are available.

The common samples file path is located here:
..\Studio\20.0\Samples\Object Pascal\Database\FireDAC\Samples\

FireDAC.SQLiteIniFile Demo Sample 

This sample uses FireDAC to connect to an SQLite database that emulates the structure and the operations of an INI File.


FireDAC.TFDLocalSQL MegaFMX Sample 

The sample shows different TFDLocalSQL applications.

Comp Layer\TFDLocalSQL\MegaFMX\LSQLMega.dproj

FireDAC.SQLite Encryption Sample 

This sample demonstrates how to encrypt/decrypt an SQLite database.

DBMS Specific\SQLite\Encryption\SQLite_Encrypt.dproj

Controlling Database Access Rights 

The SQLite is an embedded DBMS. This implies that it is a single user DBMS and does not need such concepts as a user, access rights, and so on. Still, some application can benefit from an access right control, for example:

  •  An application can restrict rights depending on an end-user license. A demo license means less possibilities, a full license provides all possibilities. 
  • Multi-tier data access frameworks can use their own user concept and control data access rights using some generic approach. 

 Again, SQLite provides a unique feature allowing you to authorize or not SQL commands. To work with this API, a Delphi application should set the OnAutorize event handler of the TSQLiteDatabase object, which is a database connection wrapping object. Hook this event after a database connection is opened.

DBMS Specific\SQLite\OnAuthorize\SQLite_OnAuthorize.dproj

Hooking Database Updates 

SQLite provides an unique API allowing you to monitor all updates to a database. This feature can be used, for example, to log all updates to a DB. To work with this API, a Delphi application should set the OnUpdate event handler of the TSQLiteDatabase object, which is a database connection wrapping object. Hook this event after a database connection is opened.

DBMS Specific\SQLite\OnUpdate\SQLite_OnUpdate.dproj

Custom Collations 

SQLite stores and handles all character data either in UTF8 or UTF16, depending on the OpenMode connection parameter. When SQLite needs to compare or sort a character data, it has to know what rules to use for this. The rules are known as a collation.

DBMS Specific\SQLite\UserCollation\SQLite_UserColl.dproj

Custom Functions 

SQLite does not support the stored procedure or function concept, as it allows you to use the host language environment to extend the engine functionality. SQLite allows you to register host language functions in the SQLite engine and use them in the SQL commands. FireDAC simplifies this by introducing the TFDSQLiteFunction component.

DBMS Specific\SQLite\UserFunc\SQLite_UserFunc.dproj

The SQLite R*Tree Module 

An R-Tree is a special index that is designed for doing range queries. R-Trees are most commonly used in geospatial systems where each entry is a rectangle with minimum and maximum X and Y coordinates. Given a query rectangle, an R-Tree is able to quickly find all entries that are contained within the query rectangle or which overlap the query rectangle.

This idea is easily extended to three dimensions for use in CAD systems. R-Trees also find use in time-domain range look-ups. For example, suppose a database records the starting and ending times for a large number of events. A R-Tree is able to quickly find all events that were active at any time during a given time interval, or all events that started during a particular time interval, or all events that both started and ended within a given time interval. And so forth. 

DBMS Specific\SQLite\UserRTree\SQLite_UserRTree.dproj

Title: SQLite 

Brief Description: This snippet shows you how to populate a listbox from a SQLite database using FireDAC and LiveBindings. See the section called "Accessing a Database" in the Mobile Tuturials topic in the documentation for more information and licensing requirements.

Platforms supported: iOS, Android

..\Mobile Snippets\FireDACSQLite\FireDAC_SQLite.dproj

Semper Fi,
Gunny Mike

Delphi Tip of the Day - OnShow SetFocus or Form1.ActiveControl

I'm creating a simple database program to explore how SQLite works within Delphi. I want to be able to switch between three databases: Album, Test, and World. So I added a TComboBox and populated the Items property with three values; Album, Test, World. I also set TextHint := 'Choose Database...';

object ComboBox1: TComboBox
    Left = 8
    Top = 8
    Width = 121
    Height = 21
    ParentShowHint = False
    ShowHint = False
    TabOrder = 0
    TextHint = 'Choose database...'
    Items.Strings = (

When I ran the program the TextHint for the ComboBox did not display:

That is not what I was expecting. The Combox was the active control which negates being able to see the TextHint "Choose database..."

So I added a little piece of code to the form's onShow event.

procedure TForm1.FormShow(Sender: TObject);

Now when I run the program right from the get-go the StatusBar componet has the focus and the ComboBox displays as intended.

Sometimes it's the small things that make all the difference!

An alternative  to using the OnShow event was suggested in the comments.

Form1.ActiveControl := StatusBar1

I love Delphi! 

Semper Fi
Gunny Mike

Sunday, February 23, 2020

Delphi Tip of the Day - Autosave Project Desktop

I am not a full-time Delphi guy. So, when I'm learning Delphi by reading OPC (other people's code) I want to make the best of my time. I was studying some code from Cary Jensen that goes with Chapter 6 of his Delphi in Depth: FireDAC book.

When I was done understanding a section of his code, I simply folded it. I figured I beat that code up enough in my mind. I understood it. And I don't need to look at it again, at least not right now. I also didn't want to be distracted by having those code blocks expanded. 

I started a brand new project in Delphi to write some of my own code that was similar but different, just to reinforce what I learned. When I was finished, I reopened Jensen's code and the pieces of code I had folded were no longer folded. 

It turns out this is an easy fix. Simply enable "Save project desktop when closing".
Tools > Options > IDE > Saving and Desktop

Not only did this keep sections of the code I had folded, folded, it remembered whether my last view was Code view or Design view. It also kept track of where in the code view I left off. I was looking at line 522 in the source code when I close the project, Delphi put me right back at line 522 the next time I reopened the project. How cool is that.

Semper Fi
Gunny Mike