tag:blogger.com,1999:blog-48182939672820967912023-12-01T01:44:14.329-08:00Delphi BarServing my thoughts and experiences of developing software with Embarcadero DelphiUnknownnoreply@blogger.comBlogger77125tag:blogger.com,1999:blog-4818293967282096791.post-5366570095964140852023-11-24T05:54:00.000-08:002023-11-24T05:54:20.284-08:00How to write try finally blocks<p> I recently came across code another developer had done and they write try..finally blocks like the following:</p><p><span style="font-family: courier;">procedure TSomeClass.DoSomething: string;<br /></span><span style="font-family: courier;">var<br /><span> myClass: TMyClass;<br /></span>begin<br /><span> myClass := nil;<br /><span> try<br /></span><span> </span><span> myClass := TMyClass.Create;<br /></span><span> </span><span> // Do stuff<br /></span><span> finally<br /></span><span> </span><span> myClass.Free;<br /><span> end;<br /></span>end;</span></span></span></p><p>Were I would write it as follows:</p><p><span style="font-family: courier;">procedure TSomeClass.DoSomething: string;<br /></span><span style="font-family: courier;">var<br /> myClass: TMyClass;<br />begin<br /> myClass := TMyClass.Create;<br /> try<br /> // Do stuff<br /> finally<br /> myClass.Free;<br /> end;<br />end;</span></p><p>I always create the object on the line before the try and would not set the object to nil just before creating it. I believe setting the object to nil before creating it and putting the create after the try to not be the correct way and do not know the reasoning why the developer does it like this.</p><p><br /></p>Unknownnoreply@blogger.com9Manchester, UK53.4807593 -2.242630525.170525463821157 -37.3988805 81.790993136178855 32.9136195tag:blogger.com,1999:blog-4818293967282096791.post-84713585295443294942022-02-12T09:02:00.000-08:002022-02-12T09:02:53.946-08:00Writing to and reading from the windows event Log<div style="text-align: left;">I've written some classes that writes to and reads from the Windows event log. The TRBWindowsEventLogs class contains the writer and reader objects, when creating the object from this class it requires the application name to be passed, this is can be different is required to the application, but is also used to retrieve the log entries.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><span style="font-family: courier; font-size: x-small;">unit uWindowsEvents;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">interface</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">uses classes, Windows, SvcMgr, Vcl.StdCtrls, Generics.Collections;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">type</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> { /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TRBWindowsEvent = class(TObject)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fRecordNumber: integer;</span></div><div><span style="font-family: courier; font-size: x-small;"> fMessage: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fComputerName: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fEventData: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fLogFile: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fCategory: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fEventCode: integer;</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> property Category: string read fCategory write fCategory;</span></div><div><span style="font-family: courier; font-size: x-small;"> property ComputerName: string read fComputerName write fComputerName;</span></div><div><span style="font-family: courier; font-size: x-small;"> property EventCode: integer read fEventCode write fEventCode;</span></div><div><span style="font-family: courier; font-size: x-small;"> property Message: string read fMessage write fMessage;</span></div><div><span style="font-family: courier; font-size: x-small;"> property RecordNumber: integer read fRecordNumber write fRecordNumber;</span></div><div><span style="font-family: courier; font-size: x-small;"> property LogFile: string read fLogFile write fLogFile;</span></div><div><span style="font-family: courier; font-size: x-small;"> property EventData: string read fEventData write fEventData;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> procedure Populate(aEvent: OLEVariant);</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> { /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> IRBEventReaderOutput = interface</span></div><div><span style="font-family: courier; font-size: x-small;"> ['{4ADA872A-C1DA-4B3B-BE67-0F628C61039C}']</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> function OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> { /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TRBWindowsEventLogsReader = class(TObjectList<TRBWindowsEvent>)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fApplicationName: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> fMaxNumberOfEntries: integer;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> function EventQuery: string;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> procedure GetWindowsEventLogs;</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddErrorMessage(aErrorMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> property MaxNumberOfEntries: integer read fMaxNumberOfEntries write fMaxNumberOfEntries;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create(aApplicationName: string; aMaxNumberOfEntries: integer);</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> procedure PopulateEvents(aReaderOutput: IRBEventReaderOutput);</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> { /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TRBWindowsEventLogsWriter = class(TObject)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEventLogger: TEventLogger;</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create(aApplicationName: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> destructor Destroy; override;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> procedure WriteInformationToWindowsEvents(aMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure WriteErrorToWindowsEvents(aMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> { /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TRBWindowsEventLogs = class(TObject)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fApplicationName: string;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> fWriter: TRBWindowsEventLogsWriter;</span></div><div><span style="font-family: courier; font-size: x-small;"> fReader: TRBWindowsEventLogsReader;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> property Writer: TRBWindowsEventLogsWriter read fWriter;</span></div><div><span style="font-family: courier; font-size: x-small;"> property Reader: TRBWindowsEventLogsReader read fReader;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create(aApplicationName: string); overload;</span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create(aApplicationName: string; aMaxNumberOfEntries: integer); overload;</span></div><div><span style="font-family: courier; font-size: x-small;"> destructor Destroy; override;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">implementation</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">uses SysUtils, ComObj, ActiveX, System.Variants, DateUtils;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TRBWindowsEvent }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEvent.Populate(aEvent: OLEVariant);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> insertion: array of String;</span></div><div><span style="font-family: courier; font-size: x-small;"> i: integer;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fCategory := string(aEvent.Category);</span></div><div><span style="font-family: courier; font-size: x-small;"> fComputerName := string(aEvent.ComputerName);</span></div><div><span style="font-family: courier; font-size: x-small;"> fEventCode := integer(aEvent.EventCode);</span></div><div><span style="font-family: courier; font-size: x-small;"> fMessage := string(aEvent.Message);</span></div><div><span style="font-family: courier; font-size: x-small;"> fRecordNumber := integer(aEvent.RecordNumber);</span></div><div><span style="font-family: courier; font-size: x-small;"> fLogFile := string(aEvent.LogFile);</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> if not VarIsNull(aEvent.InsertionStrings) then</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> insertion := aEvent.InsertionStrings;</span></div><div><span style="font-family: courier; font-size: x-small;"> for i := VarArrayLowBound(insertion, 1) to VarArrayHighBound(insertion, 1) do</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fEventData := fEventData + insertion[i];</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TRBWindowsEvents }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TRBWindowsEventLogs.Create(aApplicationName: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Create(aApplicationName, 100);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TRBWindowsEventLogs.Create(aApplicationName: string; aMaxNumberOfEntries: integer);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> fApplicationName := aApplicationName;</span></div><div><span style="font-family: courier; font-size: x-small;"> fWriter := TRBWindowsEventLogsWriter.Create(aApplicationName);</span></div><div><span style="font-family: courier; font-size: x-small;"> fReader := TRBWindowsEventLogsReader.Create(aApplicationName, aMaxNumberOfEntries);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">destructor TRBWindowsEventLogs.Destroy;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> FreeAndNil(fReader);</span></div><div><span style="font-family: courier; font-size: x-small;"> FreeAndNil(fWriter);</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TRBWindowsEventLogsWriter }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TRBWindowsEventLogsWriter.Create(aApplicationName: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEventLogger := TEventLogger.Create(aApplicationName);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">destructor TRBWindowsEventLogsWriter.Destroy;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> FreeAndNil(fWindowsEventLogger);</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEventLogsWriter.WriteErrorToWindowsEvents(aMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEventLogger.LogMessage(aMessage, EVENTLOG_ERROR_TYPE);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEventLogsWriter.WriteInformationToWindowsEvents(aMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEventLogger.LogMessage(aMessage, EVENTLOG_INFORMATION_TYPE);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TRBWindowsEventLogsReader }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TRBWindowsEventLogsReader.Create(aApplicationName: string; aMaxNumberOfEntries: integer);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> fApplicationName := aApplicationName;</span></div><div><span style="font-family: courier; font-size: x-small;"> fMaxNumberOfEntries := aMaxNumberOfEntries;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">function TRBWindowsEventLogsReader.EventQuery: string;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Result := 'SELECT * FROM Win32_NTLogEvent Where SourceName = "' + fApplicationName +</span></div><div><span style="font-family: courier; font-size: x-small;"> '" AND Logfile = "Application" AND TimeGenerated >= "' + DateTimeToStr(IncDay(Now(), -1)) + '"';</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEventLogsReader.AddErrorMessage(aErrorMessage: string);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> event: TRBWindowsEvent;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> event := TRBWindowsEvent.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> event.Category := 'Error';</span></div><div><span style="font-family: courier; font-size: x-small;"> event.Message := aErrorMessage;</span></div><div><span style="font-family: courier; font-size: x-small;"> Add(event);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEventLogsReader.GetWindowsEventLogs;</span></div><div><span style="font-family: courier; font-size: x-small;">const</span></div><div><span style="font-family: courier; font-size: x-small;"> wbemForwardOnly = 32;</span></div><div><span style="font-family: courier; font-size: x-small;"> wbemReturnImmediately = 16;</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> SWbemLocator: OLEVariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> WMIService: OLEVariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> WbemObjectSet: OLEVariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> WbemObject: OLEVariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> oEnum: IEnumvariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> iValue: LongWord;</span></div><div><span style="font-family: courier; font-size: x-small;"> iCount: integer;</span></div><div><span style="font-family: courier; font-size: x-small;"> event: TRBWindowsEvent;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> try</span></div><div><span style="font-family: courier; font-size: x-small;"> Clear;</span></div><div><span style="font-family: courier; font-size: x-small;"> iCount := 0;</span></div><div><span style="font-family: courier; font-size: x-small;"> SWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');</span></div><div><span style="font-family: courier; font-size: x-small;"> WMIService := SWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');</span></div><div><span style="font-family: courier; font-size: x-small;"> WbemObjectSet := WMIService.ExecQuery(EventQuery(), 'WQL', wbemReturnImmediately + wbemForwardOnly);</span></div><div><span style="font-family: courier; font-size: x-small;"> oEnum := IUnknown(WbemObjectSet._NewEnum) as IEnumvariant;</span></div><div><span style="font-family: courier; font-size: x-small;"> while oEnum.Next(1, WbemObject, iValue) = 0 do</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> event := TRBWindowsEvent.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> event.Populate(WbemObject);</span></div><div><span style="font-family: courier; font-size: x-small;"> Add(event);</span></div><div><span style="font-family: courier; font-size: x-small;"> WbemObject := Unassigned;</span></div><div><span style="font-family: courier; font-size: x-small;"> inc(iCount);</span></div><div><span style="font-family: courier; font-size: x-small;"> if iCount > fMaxNumberOfEntries then</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Break;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"> except</span></div><div><span style="font-family: courier; font-size: x-small;"> on E: EOleException do</span></div><div><span style="font-family: courier; font-size: x-small;"> AddErrorMessage(Format('EOleException %s %x', [E.Message, E.ErrorCode]));</span></div><div><span style="font-family: courier; font-size: x-small;"> on E: Exception do</span></div><div><span style="font-family: courier; font-size: x-small;"> AddErrorMessage(E.Classname + ':' + E.Message);</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TRBWindowsEventLogsReader.PopulateEvents(aReaderOutput: IRBEventReaderOutput);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> event: TRBWindowsEvent;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> GetWindowsEventLogs;</span></div><div><span style="font-family: courier; font-size: x-small;"> for event in Self do</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> aReaderOutput.AddEventLog(event);</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">end.</span></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: courier; font-size: xx-small;"><br /></span></div><div style="text-align: left;"><span style="font-family: inherit;">To use these classes I've created some output classes implemented from the IRBEventReaderOutput interface.</span></div><div style="text-align: left;"><span style="font-family: inherit;"><br /></span></div><div style="text-align: left;"><div><span style="font-family: courier; font-size: x-small;">unit uWindowsEventsOutput;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">interface</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">uses classes, Windows, uWindowsEvents, System.JSON;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">type</span></div><div><span style="font-size: x-small;"><span style="font-family: courier;"> </span></span><span style="font-family: courier; font-size: small;">{ /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TStringsReaderOutput = class(TInterfacedObject, IRBEventReaderOutput)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings: TStringList;</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> function OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> destructor Destroy; override;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"><span style="font-family: courier;"> </span></span><span style="font-family: courier; font-size: small;">{ /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TJSONReaderOutput = class(TInterfacedObject, IRBEventReaderOutput)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fJSON_Array: TJSONArray;</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> function OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> constructor Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> destructor Destroy; override;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"><span style="font-family: courier;"> </span></span><span style="font-family: courier; font-size: small;">{ /----------------------------------------------------------------------------------------------------------------- }</span></div><div><span style="font-family: courier; font-size: x-small;"> TCSVReaderOutput = class(TInterfacedObject, IRBEventReaderOutput)</span></div><div><span style="font-family: courier; font-size: x-small;"> strict private</span></div><div><span style="font-family: courier; font-size: x-small;"> fCSVString: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddHeader;</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddLine(aLine: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> public</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> function OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">implementation</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">uses SysUtils;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TStringsReaderOutput }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TStringsReaderOutput.Create;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings := TStringList.Create;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">destructor TStringsReaderOutput.Destroy;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> FreeAndNil(fStrings);</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">function TStringsReaderOutput.OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Result := fStrings.CommaText;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TStringsReaderOutput.SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.SaveToFile(aFileName);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TStringsReaderOutput.AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Category: ' + aEventLog.Category);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Computer Name: ' + aEventLog.ComputerName);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Event Code: ' + aEventLog.EventCode.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Message: ' + aEventLog.Message);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Record Number: ' + aEventLog.RecordNumber.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Log File: ' + aEventLog.LogFile);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('Event Data');</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add(aEventLog.EventData);</span></div><div><span style="font-family: courier; font-size: x-small;"> fStrings.Add('-------------------------');</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TJSONReaderOutput }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">constructor TJSONReaderOutput.Create;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> fJSON_Array := TJSONArray.Create;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">destructor TJSONReaderOutput.Destroy;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> FreeAndNil(fJSON_Array);</span></div><div><span style="font-family: courier; font-size: x-small;"> inherited;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">function TJSONReaderOutput.OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> if Assigned(fJSON_Array) then</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Result := fJSON_Array.ToJSON;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TJSONReaderOutput.SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> sl: TStringList;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> sl := TStringList.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> try</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.Text := fJSON_Array.ToJSON;</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.SaveToFile(aFileName);</span></div><div><span style="font-family: courier; font-size: x-small;"> finally</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.Free;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TJSONReaderOutput.AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object: TJSONObject;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object := TJSONObject.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('category', aEventLog.Category);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('computerName', aEventLog.ComputerName);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('eventCode', aEventLog.EventCode.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('message', aEventLog.Message);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('recordNumber', aEventLog.RecordNumber.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('logFile', aEventLog.LogFile);</span></div><div><span style="font-family: courier; font-size: x-small;"> JSON_Object.AddPair('eventData', aEventLog.EventData);</span></div><div><span style="font-family: courier; font-size: x-small;"> fJSON_Array.Add(JSON_Object);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">{ TCSVReaderOutput }</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TCSVReaderOutput.AddEventLog(aEventLog: TRBWindowsEvent);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> s: string;</span></div><div><span style="font-family: courier; font-size: x-small;"> procedure AddValue(aValue: string);</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> s := s + aValue + ',';</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> AddHeader;</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.Category);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.ComputerName);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.EventCode.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.Message);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.RecordNumber.ToString);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.LogFile);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddValue(aEventLog.EventData);</span></div><div><span style="font-family: courier; font-size: x-small;"> AddLine(s);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TCSVReaderOutput.AddHeader;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> if fCSVString = '' then</span></div><div><span style="font-family: courier; font-size: x-small;"> begin</span></div><div><span style="font-family: courier; font-size: x-small;"> AddLine('category,computerName,eventCode,message,recordNumber,logFile,eventData,');</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TCSVReaderOutput.AddLine(aLine: string);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fCSVString := fCSVString + aLine + chr(13) + chr(10);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">function TCSVReaderOutput.OutputString: string;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> Result := fCSVString;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TCSVReaderOutput.SaveToFile(aFileName: string);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> sl: TStringList;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> sl := TStringList.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"> try</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.Text := fCSVString;</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.SaveToFile(aFileName);</span></div><div><span style="font-family: courier; font-size: x-small;"> finally</span></div><div><span style="font-family: courier; font-size: x-small;"> sl.Free;</span></div><div><span style="font-family: courier; font-size: x-small;"> end;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">end.</span></div></div><div style="text-align: left;"><span style="font-family: inherit;"><br /></span></div><div style="text-align: left;">Here are some examples of how to use the output classes.</div><div style="text-align: left;"><br /></div><div style="text-align: left;">To write to the Events Log.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><span style="font-family: courier; font-size: x-small;">procedure TfrmWindowsEvents.AddLogBtnClick(Sender: TObject);</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEvents.Writer.WriteInformationToWindowsEvents(MessageEdt.Text);</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><br /></div></div><div style="text-align: left;">To read from the Events Log</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><span style="font-family: courier; font-size: x-small;">procedure TfrmWindowsEvents.StringBtnClick(Sender: TObject);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> stringsReader: IRBEventReaderOutput;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> stringsReader := TStringsReaderOutput.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEvents.Reader.PopulateEvents(stringsReader);</span></div><div><span style="font-family: courier; font-size: x-small;"> stringsReader.SaveToFile('stringsoutput.txt');</span></div><div><span style="font-family: courier; font-size: x-small;"> MemoEvents.Lines.CommaText := stringsReader.OutputString;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TfrmWindowsEvents.JsonBtnClick(Sender: TObject);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> jsonReader: IRBEventReaderOutput;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> jsonReader := TJSONReaderOutput.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEvents.Reader.PopulateEvents(jsonReader);</span></div><div><span style="font-family: courier; font-size: x-small;"> jsonReader.SaveToFile('jsonoutput.txt');</span></div><div><span style="font-family: courier; font-size: x-small;"> MemoEvents.Lines.Text := jsonReader.OutputString;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">procedure TfrmWindowsEvents.CsvBtnClick(Sender: TObject);</span></div><div><span style="font-family: courier; font-size: x-small;">var</span></div><div><span style="font-family: courier; font-size: x-small;"> csvReader: IRBEventReaderOutput;</span></div><div><span style="font-family: courier; font-size: x-small;">begin</span></div><div><span style="font-family: courier; font-size: x-small;"> csvReader := TCSVReaderOutput.Create;</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> fWindowsEvents.Reader.PopulateEvents(csvReader);</span></div><div><span style="font-family: courier; font-size: x-small;"> csvReader.SaveToFile('csvoutput.csv');</span></div><div><span style="font-family: courier; font-size: x-small;"> MemoEvents.Lines.Text := csvReader.OutputString;</span></div><div><span style="font-family: courier; font-size: x-small;">end;</span></div></div><div style="text-align: left;"><span style="font-family: inherit;"><br /></span></div><div style="text-align: left;"><span style="font-family: inherit;">One thing to note is that querying the events can be very slow depending on the amount of logs in the database. You can improve this in the Event Viewer application by selecting Windows Logs > Application and from either the main menu 'Action' or from the right click menu select 'Clear Logs'.</span></div><div style="text-align: left;"><span style="font-family: inherit;"><br /></span></div><div style="text-align: left;"><span style="font-family: inherit;"><br /></span></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-32933357396277370402021-05-11T01:13:00.002-07:002021-07-07T09:07:53.926-07:00FastReports Picture Issue<p> I've been using FastReports for a few months to produce PDF reports and most of the time it seems to work OK, but have one major problem with pictures. Here is what is happening</p><p>1) Multiple reports that need images on a report, these images are small icons.</p><p>2) The images are stored in the database and the dataset brings them back fine. </p><p>3) Previewing the report in the report designer shows the images OK.</p><p>4) Exporting the report to PDF, the images no longer appear. I am exporting the report in code not directly from the preview.</p><p>If I put a picture control on the report and load an image, this works OK, it is just when I set the 'DataSet' and 'DataField' properties of the picture component they do not appear.</p><p>I think the issue might relate to when I activate the Datasets, but it could be something else like a property I am failing to set.</p><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-size: x-small;"><span style="font-family: courier;">frxReport := TfrxReport.Create(nil);<br /></span></span><span style="font-size: x-small;"><span style="font-family: courier;">frxPDF := TfrxPDFExport.Create(nil);</span></span></div><div style="text-align: left;"><span style="font-size: x-small;"><span style="font-family: courier;">dsList := TObjectList<TfrxDBDataset>.Create();</span><span><span style="font-family: courier;"><br /></span></span><span><span style="font-family: courier;">try<br /></span></span><span><span style="font-family: courier;"><span> </span>frxReport.LoadFromFile(fr3file);<br /></span></span><span style="font-family: courier;"><span> </span>frxReport.DataSets.Clear;<br /></span><span style="font-family: courier;"><span> </span>frxReport.EngineOptions.SilentMode := true;</span></span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><span> </span>frxReport.EngineOptions.EnableThreadSafe := true;</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><span> </span>frxReport.EngineOptions.UseFileCache := False;</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><br /></span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><br /></span></div><div style="text-align: left;"><span style="font-size: x-small;"><span style="font-family: courier;"><span> </span></span><span style="font-family: courier;">frxPDF</span><span style="font-family: courier;">.fileName := aPDFFile;</span><span style="font-family: courier;"><div><span> </span>frxPDF.ShowDialog := False;</div><div><span> </span>frxPDF.ShowProgress := False;</div><div><span> </span>frxPDF.OpenAfterExport := False;</div><div><span> </span>frxPDF.Compressed := true;</div><div><span> </span>frxPDF.Background := true;</div><div><br /></div></span><span><span style="font-family: courier;"><span> </span>// Populate datasets - cannot show the code for this</span></span><span><span style="font-family: courier;"><br /></span></span></span><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><span> </span>for spBandDS in dsList do<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>begin<br /></span><span style="font-family: courier; font-size: x-small;"> <span> <span> </span></span>if not(spBandDS.DataSet as TStoredProc).Active then<br /></span><span style="font-family: courier; font-size: x-small;"> <span> </span>begin<br /></span><span style="font-family: courier; font-size: x-small;"> <span> <span> </span></span>(spBandDS.DataSet as TStoredProc).Open();<br /></span><span style="font-family: courier; font-size: x-small;"> <span> <span> </span></span>ActivateDataSource(frxReport, spBandDS);<br /></span><span style="font-family: courier; font-size: x-small;"> <span> </span>end;</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><span> </span>end;<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>frxReport.PrepareReport(true);<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>frxReport.Export(frxPDF);<br /></span><span style="font-family: courier; font-size: x-small;">finally<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>for spBandDS in dsList do<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>begin<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span><span> </span>spBandDS.DataSet.Close;</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><span> </span>end; <br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>dsList.Free;<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>frxPDF.Free;<br /></span><span style="font-family: courier; font-size: x-small;"><span> </span>frxReport.Free;<br /></span><span style="font-family: courier; font-size: x-small;">end;</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"><br /></span></div><p style="text-align: left;"><span style="font-family: inherit;">Has anyone else had similar issues with the Picture component and FastReports?</span></p><p style="text-align: left;"><span style="font-family: inherit;"><b>Latest</b></span></p><p style="text-align: left;"><span style="font-family: inherit;">I've managed to fix the problem by creating a function that does this:</span></p><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">var<br /> image: TFrxPictureView;<br /> m: TMemoryStream;<br />begin<br /> if (aDataset.Name = aDatasetName) then<br /> begin<br /> image := aReport.FindObject(aImageName) as TFrxPictureView;<br /> if Assigned(image) then<br /> begin<br /> image.DataSet := aDataset;<br /> if image.IsDataField and image.DataSet.IsBlobField(image.DataField) then<br /> begin<br /> m := TMemoryStream.Create;<br /> try<br /> image.DataSet.AssignBlobTo(image.DataField, m);<br /> image.LoadPictureFromStream(m);<br /> finally<br /> m.Free;<br /> end;<br /> end;<br /> end;<br /> end;</span></div><p><span></span></p><p style="text-align: left;">Then then passing in the parameters of the report, band dataset, name of the dataset and the image component name. Basically at runtime it needs to assign the dataset again.</p></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-22830893658515428452020-10-09T08:05:00.003-07:002020-10-09T08:05:28.922-07:00TWebModule could be a lot better<p>I've been using TWebModule on a project this year and even though it does what I want it to it is a bit rubbish when there are a lot of actions. It would be nice for it to do the following:</p><p></p><ul style="text-align: left;"><li>Remember the position of the actions form, I always have to move it to select the object inspector.</li><li>With over one hundred actions in there is would be useful to have a search option, filters (maybe for 'get' and 'post' methods) and sort options in the header. This would make it a lot easier to locate the action in the list.</li><li>Right click option, or double click to go to the 'OnAction' code.</li></ul>Not sure if many other Delphi developers use TWebModule or if there is a better alternative. <p></p>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-4818293967282096791.post-36484397810838273992020-10-09T07:22:00.002-07:002020-11-30T06:41:21.772-08:00Insert Only Database - Pros and Cons<p><span style="color: #255fa6; font-family: inherit;">Explanation</span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">In a traditional database updates and deletes are allowed, this destroys data which can sometimes be considered undesirable. In an ‘Insert’ only database or ‘Point in Time’ database only inserts can be performed.</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p1" style="color: #255fa6; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Additional Fields Required</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">DateCreated – Date and time the record was created.</span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">DateEffective – Date and time the record becomes effective, this can be different than DateCreated for numerous reasons.</span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">DateEnd – Date and time the record is ceased to be effective.</span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">DateReplaced – Date and time the record was replaced by another.</span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">OperatorID or SessionID – User related to the creation of the record.</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">The date and time fields may also require a UTC offset field. Therefore a total of 9 fields are required.</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p1" style="color: #255fa6; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">How are updates done?</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">This is more complex than a typical update.</span></p><ol class="ol1"><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Locate the existing record.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Flag it as ‘ended’ and ‘replaced’ with the current date time or the time the update will be applied.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Insert a new record and copy some of the existing field values and the new field values.</span></li></ol><p class="p1" style="color: #255fa6; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Pros and Cons</span></p><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Pros:</span></p><ul class="ul1"><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Rollback to a point in time is possible.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Triggers are not required.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>All changes are logged, it is not possible for a field to be added that is not included in the audit.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Less Locks.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Make data changes that do not ‘Go Live’ until a specified date and time.</span></li></ul><p class="p2" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 12px;"><span style="font-family: inherit;"><br /></span></p><p class="p3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;">Cons:</span></p><ul class="ul1"><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Table size is significantly larger if a lot of record changes are required. Additional 9 fields required for every table.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Need views on all tables.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>If replication is a requirement all audit database is also replicated on replication servers.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>No option to exclude fields from the audit.</span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span>Making a change (typically an update) is more complex.<span class="Apple-converted-space"> </span></span></li><li class="li3" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span style="font-family: inherit;"><span style="font-stretch: normal;"><span class="s1" style="font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal;"></span></span>Foreign key and relationships can be more complex.</span></li></ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-27758423802416217462020-09-23T09:22:00.000-07:002020-09-23T09:22:46.969-07:00How users should report software errors and bugs<p>Recently I have come across not just users and testers being vague on bugs, but also fellow developers giving minimum information on issues. Below is an article I wrote a few years.</p><span></span><span><a name='more'></a></span><p>This article is intended for software users to give a guide of how to report errors and bugs. The aim of a bug report is to enable the software developer to see the program fail in front of them. There are 2 ways of doing this, either to show them in person, or give them instructions of how to reproduce the problem.</p><p>In bug reports try to make it clear what are facts (this happened) and what are speculations (I think this might have happened). Leaving out speculations is OK, try not to report too many speculations, but do NOT leave out the facts.</p><p>In the bug report explain how to reproduce the problem with the screen or screens you opened, the buttons and controls which were clicked and the correct order of these operations. Screen shots can be useful, but they also need an explanation of which controls were pressed.</p><p>When the software reports an error, do not frantically start pressing buttons, this will most likely cause other problems and make the situation worse. Instead stop working, write down the error message and quickly write down all information you can think of.</p><p>After an error has occurred and the error dialog has closed, if you think things are working correctly again you could be wrong, and the error that occurred could have a knock on effect and cause more errors. Report the error to your IT department or to the company that suppliers the software and restart the software.</p><p>When reporting an error make sure it is an error and is not a feature of the software, for example if a message dialog appears telling you it cannot do that operation, think what you are trying to do and look at the message. If it has a red cross with ‘error’ at the top then it is an error, but if it shows an information icon and the message does not contain the word ‘error’ then it could be a feature and what you have tried to do is prohibited by design. As a software developer, it is very annoying for someone make a report as a ‘System Error’ when it was a message designed to stop the user doing something that is not allowed.</p><p>In the bug report try not to use generic or abstract words like ‘window’, be more specific and report the exact window either by what appears in the title bar along the top or by describing precisely the window.</p><p>Try to avoid acronyms or technical jargon related to your industry, what is an acronym in the industry you work in could mean something completely different in the software industry.</p><p>Summary</p><p>1) Do not leave out any facts.</p><p>2) Remember more information is always better than less.</p><p>3) When an error occurs, stop what you are doing and write down as much information as possible.</p><p>4) Make sure it is an error and not a feature.</p><p>5) Be very specific on what windows and buttons are pressed.</p>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-4818293967282096791.post-56598646304179579472020-01-21T03:06:00.000-08:002020-01-21T03:06:05.210-08:00Password HashingDelphi is great for all kinds of software development from Windows based applications to web sites and mobile apps, but one area that it seems to be weak is with hashing of passwords. I cannot find any components built in or 3rd party that really do what was easy to do with Visual Studio (C#), here is what I would like to do:<br />
<br />
<ol>
<li>Find a modern hashing algorithm PKBDF2 or Argon2. </li>
<li>Must allow hash to be salted and the salt to be different every-time.</li>
<li>Allow for the number of iterations to be specified.</li>
<li>Previously I have also store a version number with the hash, this would also be a useful option.</li>
<li>Validation should not require the original salt. Some solutions (one well known 3rd party company) says that you store the hash of the password and the salt in the database. </li>
<li>Works with existing Javascript hashing solutions e.g. CryptoJS, I imagine once the same parameters are applied it should work so that the hash can be created in Javascript and the validation can be done by Delphi.</li>
</ol>
<div>
Does anyone no of any 3rd party components that do password hashing well?</div>
<div>
<br /></div>
Unknownnoreply@blogger.com10tag:blogger.com,1999:blog-4818293967282096791.post-90469720119646169762019-10-17T01:04:00.002-07:002019-10-17T01:04:22.575-07:00Will the generic TObjectList bug with serialising to JSON get fixed? When I try to serialise a generic TObjectList to JSON doing something like this:<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Response.Content := TJSON.ObjectToJsonString(MyObjectList);</span></div>
<div>
<br /></div>
<div>
I get the error Type tkPointer is not currently supported. I am using 10.3 and I believe this bug (21685) has been around since XE8. I am currently having to think of workarounds and trying to find the best solution. It would be really useful if they would fix this bug, or give some idea of when it will be fixed, does anyone know?</div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-4818293967282096791.post-1788800065324888062019-08-20T05:28:00.000-07:002019-08-20T05:28:20.171-07:00What are the Delphi alternatives to RAD Server for REST?I am looking at the best solution for a REST service in Delphi (Berlin or Rio) and all the tutorials and examples I have come across use RAD Server, which is part of the Enterprise version and not in the Professional version, which is the version I am using. One possible alternative to RAD Server is to use 3rd party components like Habari. Does anyone have any advice on alternatives or is RAD Server the best option for RESTful services in Delphi? Unknownnoreply@blogger.com11tag:blogger.com,1999:blog-4818293967282096791.post-60685887669518784672019-07-22T08:29:00.001-07:002019-07-22T08:29:24.029-07:00ClientDataSet SaveToFile writes the field values in reverse orderI have noticed that when I have a TClientDataSet with a single record and I use 'SaveToFile' to save the values to an XML files the order of the fields in the XML is in reverse order. For example if you have the following in the TClientDataSet:<br />
<br />
TableID<br />
Name<br />
Address<br />
<br />
When this is saved to an XML file the meta data is in the correct order, but the values for the fields in the XML is in reverse order.<br />
<br />
Address<br />
Name<br />
TableID<br />
<br />
I wonder if this is done by design.<br />
<br />
The version of Delphi I am using is Tokyo.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-4818293967282096791.post-34533123827226777562018-09-14T00:17:00.000-07:002018-09-14T00:20:01.717-07:00Does Delphi have a future?I've been using Delphi for almost 20 years now, I have worked in various industries and have also used other languages and IDEs like C#, Xcode, VB.Net, but while developing in other languages I have always been doing something with Delphi and I am a big fan of it. There are many reasons why I enjoy and have a preference to develop some applications in Delphi, but recently I have one problem with it.<br />
<br />
The problem I have with Delphi is its future and the question that gets raised 'how easy is it to employ new developers?'. In the UK it is almost impossible to employ a good Delphi developer and can take years to find one. The other option is to employ a developer with good OOP skills and knowledge of a similar language like C# and for them to learn the language (currently no Pluralsight courses). The problem with employing a developer who does not know Delphi is they do not want to learn Delphi, it is not a big enough carrot on the stick and salaries in the UK are less than other languages.<br />
<br />
What I would like to know are the selling points of Delphi to a young person who knows OOP and has some experience in software development. I asked myself the question, 'if I was young and needed to choose a language and development environment, would I invest my future in Delphi?' The short and current answer is 'No'.Unknownnoreply@blogger.com9tag:blogger.com,1999:blog-4818293967282096791.post-2359834281854265972018-06-28T05:45:00.001-07:002018-06-28T05:46:57.936-07:00Delphi features that I was not aware ofThe other day I came across a feature of Delphi that in my 18+ years of using Delphi have never used, it is the 'Hide Non-Visual Components' (Ctrl+H) when design a form. I came across this because another Developer pointed out to me that he could not see the menu controls on a form. I thought there might be an option somewhere and on the right click menu was the option.<br />
<br />
I have never used this feature and it got me thinking what other features are there that I am not aware of (Delphi Berlin) and are there any that I might use. Here are 2 lists of features I have since discovered, one list is for ones that I think are pointless and I would never use and the other for features that I believe are useful.<br />
<br />
Features I've found that I think I will never use:<br />
<ol>
<li>Quick Icon - right click menu option in the form designer.</li>
<li>Quick Edit - right click menu option in the form designer.</li>
<li>Flip Children - right click menu option in the form designer. I think I'v seen this before, but have never used it and cannot think of when I would.</li>
<li>Lock Controls - main menu > edit. This feature locks some controls on forms from resizing and moving. This feature has strange behaviour as it sometimes locks the resize, but not the ability to move the control, try locking the controls, closing the form and opening it again and the size of the controls cannot be changed but the positions can. Clearly never been through QA.</li>
<li>Scale - main menu option > edit. This gives the developer the feature to scale a form and it's controls be a percentage. </li>
</ol>
<br />
Features I've found that could be useful:<br />
<ol>
<li>Surround > Region - right click menu option in the code editor. </li>
<li>Search for Usages - right click menu option in the code editor. </li>
</ol>
This is just a brief list of features that I have found over the last couple of day that I was not aware of, most of which I will never use. There are most likely other features in Delphi I have yet to discover that are of some use. <br />
<ol>
</ol>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-4818293967282096791.post-44217980633474465722018-06-19T06:43:00.002-07:002018-06-19T06:44:35.341-07:00Why does TSpinEdit not enforce the MaxValue property?With a TSpinEdit there is a property called 'MaxValue', from the name it implies that the maximum value for the control is what value you set for the property, but this is not the case. The property sets the maximum value for using the spin edit buttons, a user can enter a value exceeding the maximum value by using the keyboard up to the value of an Int64 (9,223,372,036,854,775,807).<br />
<div>
<br /></div>
<div>
This seems to have been done by design, but I cannot see a valid reason for this and it could be a little dangerous when being used to control the valid values entered. </div>
<div>
<br /></div>
<div>
By putting the following in the OnChange event I've managed to get around the problem. Not sure if there is a better solution. </div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">if (Sender is TSpinEdit) then</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">begin</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> if (Sender as TSpinEdit).Value > (Sender as TSpinEdit).MaxValue then</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> begin</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> (Sender as TSpinEdit).Value := (Sender as TSpinEdit).MaxValue;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> end;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">end;</span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-4818293967282096791.post-44137602320345208142018-03-06T01:22:00.000-08:002018-03-06T01:22:49.638-08:00Why is there no Delphi error provider?Recently I've been looking at the best solution for displaying a data entry validation error, for example when a user needs to enter a description that is not a duplicate and they enter a duplicate the user is informed of the error. Many web sites will display an error below the text box highlighting an error, or displaying an error icon next to the text box. In C# (Visual Studio 2017) when developing a forms application there is a 'ErrorProvider' component that is easy to use and displays an icon on the right (exclamation mark by default) with a hint that can contain the error text.<br />
<br />
What I am looking for is something similar in Delphi (I am currently using Berlin), and I am surprised there is no 'out of the box' standard component that ships with Delphi that can do this.<br />
<br />
I have looked at using a TButtonedEdit control with a right button visible with an exclamation mark as the icon when there is an error, but this does not work well.<br />
<br />
I imagine that how software informs a user of a data entry validation error is subjective and some developers will have different ideas, but I am interested in what other developers think and are there any decent 3rd party products that have a single error component. Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-4818293967282096791.post-13412064141580209052018-02-21T06:49:00.000-08:002018-02-21T06:51:31.370-08:00Animate opening and closing a panel<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Thought I would share an example of how I animate the opening and closing of a panel that can contain various controls and how each control can also be animated.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxBcFnzyCG7kWLeP39X7pum6tbgXSSdb5es6KnU1iv_GNnZhLmy5ZAYy0tCOgm7xZpnhlAF9ZqzvH0OmO_TwA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
Here is the example code:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">unit AnimatePanelFrm;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">interface</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">uses</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">type</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> TForm1 = class(TForm)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Panel1 : TPanel;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Shape1 : TShape;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Label1 : TLabel;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> BitBtn1 : TBitBtn;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> BitBtn2 : TBitBtn;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> BitBtn3 : TBitBtn;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> BitBtn4 : TBitBtn;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> procedure Label1Click(Sender : TObject);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {Private declarations}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> {Public declarations}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> end;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">var</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Form1 : TForm1;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">implementation</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{$R *.dfm}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">procedure TForm1.Label1Click(Sender : TObject);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">const</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Expanded_Height = 106;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Collapse_Height = 44;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Speed = 100;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Speed2 = 200;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">begin</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn1.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn2.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn3.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn4.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(Panel1.Handle, Speed2, AW_VER_NEGATIVE OR AW_SLIDE OR AW_HIDE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> if Panel1.Height = Expanded_Height then</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Panel1.Height := Collapse_Height</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> else</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Panel1.Height := Expanded_Height;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(Panel1.Handle, Speed2, AW_VER_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn4.Handle, Speed, AW_VER_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn3.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn2.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> AnimateWindow(BitBtn1.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">end;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">end.</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-64023723158872295752018-01-31T03:31:00.000-08:002018-01-31T03:31:54.432-08:00Project setting for absolute pathsI've noticed that with the current version of Delphi (Berlin) the project file (.dpr) uses relative paths and when you manually change the paths to absolute paths and then add a something to the project (e.g. a .pas file) it converts them back to relative paths.<br />
<br />
I prefer to use relative paths, however the problem I have is that both the MD and the Development Manager at the company insist on using absolute paths, the MD seems to think and apparently has heard that using relative paths can causes problems. I cannot find any project or environmental setting to force the paths for the project files in the .dpr file to be absolute. Does anyone know of such a setting or why relative paths in the .dpr file cause problems? Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-4818293967282096791.post-65490773593073685462018-01-24T02:53:00.001-08:002018-01-24T02:53:38.972-08:00Can and should user access permissions be stored in Active Directory?I am currently looking at various designs of how to store user permissions, it is most likely I will choose on a Role Based Access Control (RBAC) and my original thought was to store the various role permissions in the database and in the application there would be an area that would allow an administrator to control the various user roles and role permissions. But some developers have mentioned to me not to do this and allow 'Active Directory' to control the various user permissions. This would mean that the access definitions (rules) would not need to be in the database and the control of these permissions do not need to be done in an application. I imagine the access enforcement to the various areas of the software e.g. Purchase Orders would still need to be controlled by the application and how the application interrogates the active directory permissions I still do not know.<br />
<br />
The developers who have suggested doing this give the impression that it is possible and easier (saving time) than doing the access control using the database and application, although they have never done it themselves. Before I journey into how to develop for Active Directory, does anyone have experience of using it for access control for multiple areas of a Delphi application, and is this the direction access control is going for applications? Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-4818293967282096791.post-70426541791612104572017-12-21T00:57:00.001-08:002018-01-03T00:59:56.889-08:00Auto create forms and data modules does not quite workI've recently moved to Delphi 10.1 Berlin Update 2 from using XE and XE5. One thing that caught me out was that I forgot to turn off the 'Auto create forms and data modules' in the 'Form Designer' options. This setting means that when you add a form or data module to a project it gets auto-created at run-time.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS7qlKk8PEZBtJGiUrhkmPzDIsU0iJzyLKE4l_RiDYIzdl9MGXx4PtDdOZvKAUwlrfOK2jtddQ5xU5o81-FCl_Yhd7uAPYS0ZDO1qbO6lwhogqAe73L4F013qSYDmz-rEyhejwTdXRHc4F/s1600/Delphi-AutoCreateForms.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="74" data-original-width="499" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS7qlKk8PEZBtJGiUrhkmPzDIsU0iJzyLKE4l_RiDYIzdl9MGXx4PtDdOZvKAUwlrfOK2jtddQ5xU5o81-FCl_Yhd7uAPYS0ZDO1qbO6lwhogqAe73L4F013qSYDmz-rEyhejwTdXRHc4F/s1600/Delphi-AutoCreateForms.png" /></a></div>
<br />
<br />
The problem with this setting is that it does not fully work. I have a project where I do not want to auto create any forms or data modules, I have a class that is responsible for doing the initial creation of the required forms and objects, but if I add a form or data module to the project it always gets added to the auto create list in the project. This option assumes you want just one form in the list, once one is added it does not add anymore.<br />
<br />
This problem could occur in all versions of XE and the now the more recent versions (DX), I plan to check this with XE and will hopefully soon be updating to the latest version of Delphi.Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-4818293967282096791.post-62690759756892233782017-12-05T02:12:00.002-08:002017-12-05T02:12:52.099-08:00Delphi interesting skinning issue with .NET COM wrapperI've come across an interesting issue with skinning and invoking a .NET Windows form and messagebox. I have a test Delphi application that is skinned using either Alpha Skins or setting the custom styles, I then invoke a .NET wrapper DLL developed in Visual Studio 2015 (COM interop) and call the method to show a Windows form, this does not get skinned. However on the Windows form there is a button that shows a Windows messagebox, this does get skinned, see image below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNheBJAUADeuvwgLVRdYkQvbdUGxvmn6GZD0UIUaIm56KD8oVi1lQ0jObvJo2kACvXx3bplDe9Rv752XgwZ_N7DBSEbaGoT6A0z4kDrE5p8k7w13modnYBU94SsROcGbLT5K5TurWztAIu/s1600/Delphi-NET-Wrapper-Skin-Issue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="331" data-original-width="373" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNheBJAUADeuvwgLVRdYkQvbdUGxvmn6GZD0UIUaIm56KD8oVi1lQ0jObvJo2kACvXx3bplDe9Rv752XgwZ_N7DBSEbaGoT6A0z4kDrE5p8k7w13modnYBU94SsROcGbLT5K5TurWztAIu/s320/Delphi-NET-Wrapper-Skin-Issue.png" width="320" /></a></div>
<br />
It would be nice if the Windows form also was skinned to match the Delphi application and it seems strange that the Windows messagebox which is invoked by the Windows form is skinned.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-57156584003665463822017-09-21T10:46:00.000-07:002017-09-21T10:46:26.820-07:00TObjectList vs TObjectDictionaryWhen I need to store a list of objects I usually use a TObjectList (Generics.Collections), but I was speaking to another developer who uses TObjectDictionary to store a list of objects. I searched the net for when to use a TObjectDictionary instead of a TObjectList and vice-versa, but could not find any definitive answers. I decided to write a little test app to understand the difference, this simply did the following:<br />
<br />
<ul>
<li>Created 1 million objects for each list and added them to the list.</li>
<li>Cleared the list of the 1 million objects.</li>
<li>Populated the list with 1 million newly created objects.</li>
<li>Found 100 objects in the list.</li>
</ul>
<div>
Below are the results, time is in ms:</div>
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Clear - 47</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Populate - 344</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Find - 78</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Find - 78</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Find - 78</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectList Find - 79</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Clear - 265</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Populate - 579</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Find - 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Find - 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Find - 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ObjectDictionary Find - 0</span><br />
<div>
<br />
As you can see the TObjectDictionary was slower to clear and populate the list, but was faster finding the 100 objects. This is most likely due to the TObjectDictionary being derived from TDictionary which is a hash table and is optimised for lookups.<br />
<br />
So, generally from these results I am happy sticking with TObjectList, but if I need to store a lot of objects and also need to find a lot of objects then using a TObjectDictionary is a better choice. </div>
Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-4818293967282096791.post-13329771118863260702017-07-25T06:18:00.001-07:002017-12-21T07:11:13.133-08:00Windows 10 Notification<span style="font-family: inherit;">Here is a quick and simple example of a notification procedure. On a form I added a 'TNotificationCenter' component from the 'System' tool palette.</span><br />
<div>
<br /></div>
<div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">procedure TForm.DoNotification(aName, aTitle, aBody: string);</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">var</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification: TNotification;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">begin</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification := NotificationCenter1.CreateNotification;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> try</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification.Name := aName;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification.Title := aTitle;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification.AlertBody := aBody;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> NotificationCenter1.PresentNotification(appNotification);</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> finally</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> appNotification.Free;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> end;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">end;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">procedure TForm.ShowTestNotification;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">begin</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> DoNotification('Test Name', 'Test Title', 'This is an example');</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">end;</span></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; font-size: 11pt; margin: 0cm 0cm 0.0001pt;">
<br /></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
There is an event in the NotificationCenter component called 'OnReceiveLocalNotification', which is useful if you want to display a notification and when a user clicks on the notification the software performs an operation. </div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<br /></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
I did this example in Delphi 10.1 Berlin, it is a very limited example due to Delphi being very limited with what can be done with Windows Notifications. Looking at the documentation you can do more with iOS, I am not sure why they have made it so limited. I have briefly looked at some C# examples and you can do more with notifications like custom sounds, icons, images and actions. </div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
<br /></div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
One thing I have noticed is that when I run this example the notification is shown and then when it goes away it is automatically removed from the action centre. One thing I would require is that if the user does not acknowledge the notification, it should stay in the Action Centre list. For me it would be really useful to have the following:</div>
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
</div>
<ul>
<li>Custom image.</li>
<li>Custom sound.</li>
<li>FireDate to work in Windows 10.</li>
<li>Option for the notification to stay in the Action Centre.</li>
</ul>
<br />
<div class="x_MsoNormal" style="background-color: white; color: #212121; margin: 0cm 0cm 0.0001pt;">
I would like to see Embarcadero expand on what these notifications can do, obviously they are limited to what the OS can do. If they could persist in the Action Centre until clicked then I can think of multiple uses for notifications. </div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-46355813320632883092017-07-24T02:54:00.001-07:002017-12-21T07:10:39.030-08:00Delphi 10.1 Berlin fix for issue when opening older project I recently had an issue with a project that had been updated from XE to Delphi 10.1 Berlin. The issue was when opening the project it could not find some components on the main form (3rd party), however the correct packages are installed and if I started a new project I could add the components from the tool palette without any issues.<br />
<br />
One work-around I found was having adding these components to another project, then when I opened Delphi 10.1 Berlin I opened this project and then closed it before opening the project that had problems with the components, and it all worked fine.<br />
<br />
In the end the solution I found was the following:<br />
<br />
<ol>
<li>In the package itself, find the unit with the 'Register' procedure.</li>
<li>Check 'DesignInf' is in the uses clause.</li>
<li>At the top of the 'Register' procedure add 'ForceDemandLoadState(dlDisable);' </li>
<li>Install the package again.</li>
</ol>
<div>
What this does is disables the IDE from using the smart loading of installed packages, this means when the IDE starts it always loads the installed packages.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4818293967282096791.post-26313721665843594902017-07-20T01:45:00.000-07:002017-07-20T01:45:36.546-07:00How to create GUID at runtimeTo create a GUID (Globally Unique Identifier) at runtime I have two different ways of doing this.<br />
<br />
<b>First Method</b><br />
Add ComObj unit to the uses clause, if not already there, then to create the GUID as a string just do the following:<br />
<span style="font-family: Courier New, Courier, monospace;">FThisID := CreateClassID;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;"><b>Second Method</b></span><br />
<span style="font-family: inherit;">This method you need the SysUtils in the uses clause. The do something like the following:</span><br />
<span style="font-family: Courier New, Courier, monospace;">var</span><br />
<span style="font-family: Courier New, Courier, monospace;"> newGUID: TGUID;</span><br />
<span style="font-family: Courier New, Courier, monospace;">begin</span><br />
<span style="font-family: Courier New, Courier, monospace;"> SysUtils.CreateGUID(newGUID);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> FThisID := GUIDToString(newGUID); </span><br />
<span style="font-family: Courier New, Courier, monospace;">end;</span>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-4818293967282096791.post-47754481053018482582017-06-02T04:00:00.000-07:002017-06-02T04:00:15.528-07:00How to dock a form to a panel programmaticallyThis is a quick solution to a question I had on how to have a form that is set so it can dock into another form's panel. I have a main form with a panel on the right with the 'Docksite' property set to true. I have another form with the 'DragKind' property set to dkDock and the 'DragMode' set to dmAutomatic. I create the docking form at runtime and wanted it so that by default it was docked into the right panel. The quick solution that I found hard to find on the net is after I create the form do the following:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">DockingForm.ManualDock(PanelRight);</span><br />
<span style="font-family: Courier New, Courier, monospace;">DockingForm.Show;</span><br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-4818293967282096791.post-91145578507742666902017-05-25T01:50:00.000-07:002017-05-25T01:50:35.266-07:00Frame Inheritance - TabOrder: Property does not exist - Issue FixedI've been working on an application recently and it has a few frames (TFrame), I noticed that there were common properties and methods to all the frames, so I decided that they should derive from a base class. I created the base frame class and then in code derived the other frames from the base frame. It all seemed to work fine a build and ran OK, however after closing the project and then coming back to it a few days later, when I tried to open a frame I received an error stating the TabOrder property does not exist, I ignored it and received more property does not exist errors (I did not save any changes). The solution to this problem was simple, in the .dfm file at the top was:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">object TestFrame: TTestFrame </span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">This needed to be changed to:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">inherited TestFrame: TTestFrame</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">The ideal way to do this is at design time when designing the structure of the application, if there is an abstract or concrete frame class then this should be added to the repository so when a developer needs to create a new frame, they can simply inherit the frame from the one in the repository.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This is a very similar problem to inheriting datamodules, I've also had to do something similar. </span>Unknownnoreply@blogger.com1