Larry Hengen
Members-
Content Count
90 -
Joined
-
Last visited
-
Days Won
1
Larry Hengen last won the day on April 18 2020
Larry Hengen had the most liked content!
Community Reputation
39 ExcellentRecent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Serialize/Deserialize Enums with no RTTI
Larry Hengen replied to Larry Hengen's topic in RTL and Delphi Object Pascal
What I ended up doing was using Neon for serialization because it seems to be easier to create custom serializers than the stock framework. I used Uwe's approach above, so my enums have RTTI which Neon also requires. The Neon serializer then just calls the record helper method to substitute the proper integer value for the enum. Thanks to both of you for responding. Your suggestions were quite helpful. -
Serialize/Deserialize Enums with no RTTI
Larry Hengen posted a topic in RTL and Delphi Object Pascal
I am trying to figure out the best way to deal with a REST API that has rather large and numerous codes that are mapped to Enums in Delphi. Unfortunately, Delphi doesn't automatically handle the enums because they are assigned values so no RTTI is generated. For Example: TReportTypeCode = (reportTypeCodeSTR=102, reportTypeCodeLCTR=106, reportTypeCodeCDR=113, reportTypeCodeLVCTR=14, reportTypeCodeEFTR=145); I have enabled Scoped_Enums to prevent confusion between the many similarly named enums and eliminate the convention of using a neumonic prefix. Since the object graph is deep, with many such enum values I would like to find a way to serialize/deserialize the root object without using TJSONWriter/Reader and coding the entire de/serialization. Is it possible to use Interceptors with the native Delphi JSON libraries? Are there any other third party (preferably open source) libraries that can handle such enums? -
Delphi Parser/Compiler Limitation?
Larry Hengen posted a topic in Algorithms, Data Structures and Class Design
I am implementing a REST API Client for fun and it uses ISO Country and Currency Codes. I wanted to use enums, and GetEnumName() for display rather than prefixed enum values and a constant array of strings to get their string equivalents. I like Scoped enums as it's easier to find the enum value applicable without getting suggestions of other enums that use the same prefix. This may no longer be an issue with the LSP, but I still prefer it. Unfortunately, Delphi flags any enum values that are also keywords as you can see in the code below. Is the only way to work around this an enum and const array of string? program Project2; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; {$SCOPEDENUMS ON} //many enums use same value name so scope them to eliminate conflicts type TEnums = (TRY, SHR, XOR, IS, AS); //results in compiler error "[dcc32 Error] Project2.dpr(12): E2029 Identifier expected but 'TRY' found" //same for all other values as they are keywords. Why can't the parser deal with this? It's a real problem with ISO country and currency codes //would be nice to use GetEnumName() instead of creating a constant array [TCountryCode] of strings....much DRYer begin try { TODO -oUser -cConsole Main : Insert code here } except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. -
Delphi Developer wanted
Larry Hengen replied to sakura's topic in Job Opportunities / Coder for Hire
I see the job post is in German. Do you have an English translation? Is the position open to remote developers, or on-site? If open to remote devs, what time zones will be considered? -
I've been working with Delphi since D2 shipped. Would prefer to keep working with Delphi so if you need a remote developer please send me an email at lhengen@duck.com and I will provide my CV.
-
I am attempting to get FastMM4 working in a legacy product that currently uses Delphi Berlin so the team can use Full Debug mode to eliminate existing leaks and prevent new ones. The solution integrates .NET assemblies using ManagedVCL, and uses a combination of statically linked run-time packages and dynamically loaded packages with RTTI used to invoke methods. Currently FastMM4 is the first unit in the main EXE's DPR, and when the application is terminated at the login form, FastMM reports huge leaks followed by an AV just as documented in the FastMM4 FAQ which indicates this is a DLL ordering issue. I am looking for some advice from anyone else with a similar experience on how they tracked down the offending DLL/BPLs and fixed the issues. It takes quite some time for FastMM4 to report the leaks each run, and if I stop the process, the Berlin debugger becomes unstable after the 2nd or 3rd time. I've already fixed a circular BPL reference which according to Windows LoadLibrary can confuse things, but it didn't seem to resolve anything. Most core third party components and a minimal set of BPLs are loaded at the login form, so I expect more issues will arise as I get into different areas of the application. I was thinking about using CodeSite to trace all the initialization/finalization sections, but the product uses a lot of third party components. Looking for suggestions on how to approach this in a structured manner.
-
Thanks @Dmitry Arefiev I knew there must be some info out there I just hadn't found.
-
I am using an old version of FireDAC (Berlin time frame) and when opening an updateable query it implicitly calls sp_pkeys which can take ~1.5s to return. It seems to do so only once and then caches the PK info for the table appearing in the SQL FROM clause. Grepping the source has yielded no information, and my Google fu is failing me. Depending on the use case, this sometimes results in poor performance. For instance if the user fires up the app and goes into a screen to update some data and then closes the app, they trigger all of the metadata queries during their usage. Over slower VPN connections this can be a real problem. It would be nice to be able to prevent FireDAC from making such a metadata call. Can we specify the PK column at design-time or run-time and prevent the metadata query? After all the database PKs seldom change.
-
Thanks all for the responses. Turns out the AVs are due to the debugger in Berlin exploding when attempting to inspect the variables and not my actual code. Injected CodeSite Messages to find out the actual values at run-time and validate the code was correct.
-
I am using an ancient version (17.1.5) of the ExpressEditors and have a simple frame in which I am attempting to validate one editor based on the contents of two others. From what I have found on-line and in the help it seems to me that accessing the EditValue of a TcxCustomEdit descendant should be fine at run-time, but I get an AV or other error in the debugger (Berlin) and the application does not behave correctly. i have explored all other public properties as well, and none seem appropriate. Anyone know the cause without tracing through all the DevExpress code? In the TFrameDailyHours.editHoursPropertiesValidate method I am attempting to make sure the Hours edit does not contain a value that exceeds the difference of the two other time edit controls: unit UnitFrameDailyHours; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters, cxContainer, cxEdit, cxSpinEdit, cxTextEdit, cxMaskEdit, cxTimeEdit, Vcl.StdCtrls, Vcl.ExtCtrls; type TFrameDailyHours = class(TFrame) PanelDay7: TPanel; labelDayofWeek: TStaticText; CheckBoxOvernight: TCheckBox; TimeEditStart: TcxTimeEdit; TimeEditStop: TcxTimeEdit; editHours: TcxSpinEdit; procedure TimeEditStartPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); procedure TimeEditStopPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); procedure editHoursPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); public end; implementation {$R *.dfm} procedure TFrameDailyHours.TimeEditStartPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); begin ErrorText := ''; //Start Date is a required field Error := VarIsNull(DisplayValue); if Error then ErrorText := 'Start of Time Range cannot be Empty'; Exit; //if we have a StopTime then the StartTime must be < StopTime Error := (DisplayValue >= TimeEditStop.EditValue); if Error then ErrorText := 'Start of Time Range must precede End of Time Range'; end; procedure TFrameDailyHours.TimeEditStopPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); begin ErrorText := ''; if not (DisplayValue = EmptyStr) then begin Error := (DisplayValue < TimeEditStart.EditValue); if Error then ErrorText := 'End of Time Range must be Empty or after Start of Time Range'; end; end; procedure TFrameDailyHours.editHoursPropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean); begin ErrorText := ''; Error := False; if not (TimeEditStart.DisplayValue = '00:00:00') and not (TimeEditStop.DisplayValue = '00:00:00') then begin Error := VarIsNull(DisplayValue); if Error then begin ErrorText := 'Hours cannot be Empty'; Exit; end; Error := (DisplayValue < 0) or (DisplayValue > 24); if Error then begin ErrorText := 'Hours must be > 0 and < 24'; Exit; end; //check that Hours does not exceed duration between Start and Stop Times if TimeEditStop.EditValue > TimeEditStart.EditValue then begin Error := (TimeEditStop.EditValue - TimeEditStart.EditValue) * 24 < DisplayValue; if Error then begin ErrorText := 'Hours exceeds duration between Start and End Times'; Exit; end; end; end; end; end.
-
Changes IDE Recommends for Compatibility with other Installed Packages
Larry Hengen replied to Larry Hengen's topic in Databases
Thanks for the suggestions. I changed all the packages to Explicit ReBuild, not that it was the cause, but a good change anyway. Turns out I isolated the issue to the IDE injecting the FireDAC.FMXUI.Wait unit into the Interface section every time the unit was saved/compiled despite the fact it was already present, just wrapped in an IFDEF. Took me a while to find out why it was adding the unit. Turns out I had dropped a TFDGUIxWaitCursor component on the data module at some point. Creating that component in code with the Provider set appropriately fixed the issue. The dialog is obviously misleading as it has nothing to do with what packages are installed in the IDE. -
Changes IDE Recommends for Compatibility with other Installed Packages
Larry Hengen posted a topic in Databases
I have a DataAcess package which is UI framework neutral and uses FireDAC. When I build the package it prompts me to add FMX in order to be compatible with other installed packages. The interesting thing is that it is a RunTime Only Package with Rebuild as Needed. There is only one package in the project group that is a design-time package and it does not require the DataAccess package. If I cancel the IDE dialog, everything works as expected, but it's very annoying and I would like to understand the root cause. I have a couple of defines {$IFDEF FMX} FireDAC.FMXUI.Wait, {$endif} that might be factors except that FMX is not defined. The package is a single datamodule unit. with an interface uses as follows: uses System.SysUtils, System.Classes, hcSQLMapper, hcTransactMgrIntf, hcComponent, hcFactoryPool, Data.DB, hcObject, hcPrimaryKeyConstraint, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.FB, FireDAC.Phys.FBDef, FireDAC.Comp.Client, hcFireDAC, FireDAC.Phys.IBBase, FireDAC.DApt, FireDAC.Comp.ScriptCommands, FireDAC.Stan.Util, hcLookupList, {$IFDEF FMX} FireDAC.FMXUI.Wait, {$endif}FireDAC.Comp.UI, FireDAC.Phys.IBDef, FireDAC.Phys.IB, FireDAC.FMXUI.Wait; and an implementation uses as follows: {$IFDEF FMX} {%CLASSGROUP 'FMX.Controls.TControl'} {$ENDIF} {$R *.dfm} uses hcQueryIntf, {$IFNDEF FMX} Vcl.Forms, VCL.Dialogs {$ELSE} FMX.DialogService, FMX.Forms, FMX.Dialogs {$ENDIF}, System.UITypes, FireDAC.Comp.Script; The message content in the dialog is as follows: Add fmx. fmx contains implicit unit(s) FMX.Printer.Win, FMX.Consts, FMX.Graphics, FMX.Utils, FMX.Types, FMX.Styles, FMX.Forms, FMX.AcceleratorKey, FMX.StdActns, FMX.VirtualKeyboard, FMX.Controls, FMX.Menus, FMX.MultiResBitmap, FMX.Platform, FMX.Clipboard, FMX.Clipboard.Win, FMX.Helpers.Win, FMX.Surfaces, FMX.ImgList, FMX.ActnList, FMX.Platform.Common, FMX.BehaviorManager, FMX.Platform.Win, FMX.Forms.Border, FMX.Controls.Presentation, FMX.Presentation.Win, FMX.ZOrder, FMX.ZOrder.Win, FMX.Presentation.Messages, FMX.Controls.Model, FMX.Controls.Win, FMX.Presentation.Win.Style, FMX.Presentation.Factory, FMX.Presentation.Style.Common, FMX.Ani, FMX.Presentation.Style, FMX.TextLayout, FMX.Text, FMX.Effects, FMX.Filter.Custom, FMX.Types3D, FMX.Materials, FMX.Filter, FMX.StdCtrls, FMX.Switch.Win, FMX.Styles.Switch, FMX.Styles.Objects, FMX.Objects, FMX.FontGlyphs, FMX.FontGlyphs.Win, FMX.Switch.Style, FMX.Dialogs, FMX.DialogService.Sync, FMX.MultiTouch, FMX.AcceleratorKey.Win, FMX.KeyMapping, FMX.WebBrowser, FMX.WebBrowser.Win, FMX.Controls.Ole, FMX.MultiTouch.Win, FMX.Gestures.Win, FMX.Gestures, FMX.DialogService, FMX.Forms.Border.Win, FMX.Edit, FMX.Edit.Win, FMX.Edit.Style, FMX.SpellChecker, FMX.MagnifierGlass, FMX.Layouts, FMX.InertialMovement, FMX.ExtCtrls, FMX.Pickers, FMX.Pickers.Default, FMX.Calendar, FMX.Calendar.Style, FMX.ListBox, FMX.ListBox.Selection, FMX.DateTimeCtrls, FMX.DateTimeCtrls.Types, FMX.Canvas.GPU, FMX.StrokeBuilder, FMX.Canvas.GPU.Helpers, FMX.Materials.Canvas, FMX.TextLayout.GPU, FMX.Context.DX11, FMX.Context.DX9, FMX.Canvas.D2D, FMX.Canvas.GDIP, FMX.Printer, FMX.Dialogs.Win, FMX.DialogHelper, FMX.Dialogs.Default, FMX.Header. Add fmxFireDAC. fmxFireDAC contains implicit unit(s) FireDAC.FMXUI.Wait. Is the IDE missing the fact that FMX is not defined, or what am I missing? -
Best Practices for FireDAC FetchMode/RecordCount Settings
Larry Hengen replied to Larry Hengen's topic in Databases
@Hans J. Ellingsgaard I am using SQL Server. The query uses an inner join on about 5 tables, a left outer on one and a cross apply with a group by and order by on the results Pretty much a worst case scenario. Some of the criteria is not indexed, and due to the data layout requires a large # of reads. Some work has been done on the query to optimize it, and it's now better, but the question remains; what are the best settings to use for FireDAC when the cost and row count of a particular query is not generally known at design-time, as is the case with many dynamically built SQL queries. -
Best Practices for FireDAC FetchMode/RecordCount Settings
Larry Hengen replied to Larry Hengen's topic in Databases
I beg to differ. The situation I encountered was that a very expensive SQL Server query wrapped in a select count(*) from() was causing major performance issues. Result set was about 1500 rows. In this case I think it's far easier to bring back the entire result set. What I was looking for was guidelines other devs are using to make such decisions since the actual row counts are not well known. -
Best Practices for FireDAC FetchMode/RecordCount Settings
Larry Hengen replied to Larry Hengen's topic in Databases
That is exactly what FireDAC does for you so why would I write additional code to do the same thing? I want to avoid a second query because it can be detrimental to your SQL back end's performance. Imagine doubling it's workload for every user... A less intensive approach is to fetch all records, but that can cause a delay in processing while they are streamed to the client, and if the query is in the main thread, the application will "freeze".