The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,862 other subscribers

Archive for the ‘Delphi’ Category

Be careful changing the DataContext of a TRemotable

Posted by jpluimers on 2020/11/11

Still not sure why the RTL code is like this:

procedure TRemotable.SetDataContext(Value: TDataContext);
begin
  if (RemotableDataContext <> nil) and (RemotableDataContext = Self.DataContext) then
  begin
    TDataContext(RemotableDataContext).RemoveObjectToDestroy(Self);
  end;
  FDataContext := Value;
end;

It means that if you ever have to change the DataContext property from the default global RemotableDataContext, it will be removed, but not added to the new DataContext.

When you assign it nil (so you can dump it to JSON, which often is easier to read than XML), and back to the old value, this results in a memory leak:

function TNotificationKeyPortTypeImplementation.prematchChanged(const prematchChangedRequest: prematchChangedRequest): prematchChangedResponse;
var
  DataContext: TDataContext;
begin
  // ...
  DataContext := prematchChangedRequest.DataContext;
  try
    prematchChangedRequest.DataContext := nil; // otherwise the JSON serializer will stackoverflow because DataContext points back to the TRemotable instance.
    Result := Format('prematchChanged: prematchChangedRequest=%s', [TJson.ObjectToJsonString(prematchChangedRequest)]);
  finally
    // `prematchChangedRequest.DataContext := nil` removed `prematchChangedRequest` from `DataContext.FObjsToDestroy`
    DataContext.AddObjectToDestroy(prematchChangedRequest);
    prematchChangedRequest.DataContext := DataContext; // does not add `prematchChangedRequest` to `DataContext.FObjsToDestroy`
  end;
end;

or when you are outside an incoming SOAP call where DataContext might not be assigned at all:

function ToJSON(const Value: TRemotable): string;
var
  DataContext: TDataContext;
  RemotableDataContext: Pointer;
begin
  if Assigned(Value) then
  begin
    DataContext := Value.DataContext;
    try
      Value.DataContext := nil; // otherwise the JSON serializer will stackoverflow because DataContext points back to the TRemotable instance.
      Result := TJson.ObjectToJsonString(Value);
      Result := TRegExSanitiser.ReplaceSecretInText(Result, [rttJSON]);
    finally
      // `Value.DataContext := nil` removed `Value` from `DataContext.FObjsToDestroy`
      if Assigned(DataContext) then
      begin
        RemotableDataContext := GetRemotableDataContext();
        if Assigned(RemotableDataContext) and (RemotableDataContext = DataContext) then
          DataContext.AddObjectToDestroy(Value);
        Value.DataContext := DataContext; // does not add `Value` to `DataContext.FObjsToDestroy`
      end;
    end;
  end
  else
    Result := '';
end;

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Register and use a custom clipboard format in Delphi – twm’s blog

Posted by jpluimers on 2020/11/05

Cool post: [WayBack] Register and use a custom clipboard format in Delphi – twm’s blog.

It is about transmitting GPS (WGS 84) coordinates from one program to another via the clipboard.

One day I will find some time to dust off some draft clipboard posts that I have been dormant for too long.

These already got published:

Via [WayBack] I just now had the need to transmit GPS (WGS 84) coordinates from one program to another. First, I simply copied longitude and latitude separately using… – Thomas Mueller (dummzeuch) – Google+

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Pointers are dangerous – twm’s blog

Posted by jpluimers on 2020/11/04

TL;DR

  1. Do not keep pointers to objects in memory that can be relocated.
  2. SetLength can relocate the memory

[WayBack] Pointers are dangerous – twm’s blog

Via: [WayBack] Pointers can be really helpful, especially they can improve performance and readability, but they are also dangerous. I spent nearly a day tracking down… – Thomas Mueller (dummzeuch) – Google+

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Since Delphi still does not include a TDateTimeHelper: use the one by colini which has tests

Posted by jpluimers on 2020/11/03

These are quite OK: [WayBack] GitHub – colinj/TDateTimeHelper: Helper record for TDateTime type in [WayBack] DateTimeHelper.pas with DUnitX tests in [WayBackTDateTimeHelper.Tests.pas.

Via: [WayBackDoes Delphi XE 10.2.2 ship with type helpers for TDateTime type? Or do I need to implement my own. – Graeme Geldenhuys – Google+.

It got even promoted at [WayBack] Delphi XE3: Record Helpers for Intrinsic Types.

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Learned about the {$EXTENSION zzz} or {$E zzz} Delphi directive: {$EXTENSION yyy.zzz} fails

Posted by jpluimers on 2020/10/29

I totally missed that this has been added in Delphi a long time ago (at least in Delphi 2007 or maybe even before): the {$EXTENSION zzz} or {$E zzz} Delphi directive that sets the file extension of the output: [WayBack] Executable extension (Delphi 2007)

[WayBack] Executable extension (Delphi 10.3 Rio) – RAD Studio explains this is equivalent to using the -TZ

The documentation explains the zzz to be a string, but in practice, using {$EXTENSION yyy.zzz} and {$E yyy.zzz} fail:

[WayBack] Little funny bug… I wanted to quickly make two x86 EXE builds, with 3GB and normal 2GB of available memory. Just to pass it for heavy testing, as 3rd… – Arioch The – Google+ explains how to use this as a trick to have a different extension for 3GB aware compiled 32-bit executables:

{$DEFINE g3} // or obvious {.$DEFINE g3}
{$IFDEF g3}
  {$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
  {$EXTENSION 3GB.EXE}
{$ENDIF}

This kind of work in XE2 but with two funny bugs:

  1. the IDE ignores it and shows filename.exe in the compile progress dialog
  2. linker partially ignores it and creates filename.4gb instead of filename.3gb.exe

I did know about the various $LIBxxx directives that were introduced in Delphi 2009 when it [WayBack] was released in 2008.

Related:

One day, I might create an overview of which directives are valid in what Delphi versions. That would be a big change of List-Delphi-Installed-Packages.ps1, which would need at least these:

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

FastMM PushAllocationGroup

Posted by jpluimers on 2020/10/29

Few people seem to know about the FastMM PushAllocationGroup method.

This search returned almost nothing: fastmm PushAllocationGroup -site:github.com -site:sourceforge.net -site:stackoverflow.com – Google Search.

These results were convoluted:

These posts were interesting though, but most of them did not get any deeper into the topic than “look at the FastMM source”:

There were the only post giving a bit more insight:

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, FastMM, Software Development | Leave a Comment »

Spring4D Mock – Delphi Unit Testing : Writing a simple spy for the CUT – Stack Overflow

Posted by jpluimers on 2020/10/28

Reminder to self: write a longer article on Delphi mocking as Spring4D mocking is much better than Delphi Mocks, especially because of code-completion reasons.

Spring4D has a Mock record that can return a Mock<T> on which you can verify using methods like Received.

See:

I got some code that I need to dig up from an old project with many more Spring4D Mock examples.

Note that:

For now, these are a start [WayBack] Delphi Unit Testing : Writing a simple spy for the CUT – Stack Overflow:

Sounds like a use case for a mock (I am using the term mock here because most frameworks refer to their various kinds of test doubles as mock)

In the following example I am using DUnit but it should not make any difference for DUnitX. I am also using the mocking feature from Spring4D 1.2 (I did not check if Delphi Mocks supports this)

unit MyClass;

interface

type
  TMyClass = class
  private
    fCounter: Integer;
  protected
    procedure MyProcedure; virtual;
  public
    property Counter: Integer read fCounter;
  end;

implementation

procedure TMyClass.MyProcedure;
begin
  Inc(fCounter);
end;

end.

program Tests;

uses
  TestFramework,
  TestInsight.DUnit,
  Spring.Mocking,
  MyClass in 'MyClass.pas';

type
  TMyClass = class(MyClass.TMyClass)
  public
    // just to make it accessible for the test
    procedure MyProcedure; override;
  end;

  TMyTest = class(TTestCase)
  published
    procedure Test1;
  end;

procedure TMyClass.MyProcedure;
begin
  inherited;
end;

procedure TMyTest.Test1;
var
  // the mock is getting auto initialized on its first use
  // and defaults to TMockBehavior.Dynamic which means it lets all calls happen
  m: Mock<TMyClass>;
  o: TMyClass;
begin
  // set this to true to actually call the "real" method
  m.CallBase := True;
  // do something with o
  o := m;
  o.MyProcedure;

  // check if the expected call actually did happen
  m.Received(Times.Once).MyProcedure;

  // to prove that it actually did call the "real" method
  CheckEquals(1, o.Counter);
end;

begin
  RegisterTest(TMyTest.Suite);
  RunRegisteredTests();
end.

Keep in mind though that this only works for virtual methods.

  • In case you need to test a method from a base class which cannot be affected by the $RTTI directive, you can use a little trick and redefine it in subclass in public section as override; abstract; this will cause the RTTI to be generated. – Honza RFeb 5 ’16 at 8:02

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development, Spring4D | Leave a Comment »

Optional sort by name in `LogMemoryManagerStateToFile` · Issue #64 · pleriche/FastMM4 · GitHub

Posted by jpluimers on 2020/10/27

If not done yet, try to improve this: [WayBack] Optional sort by name in LogMemoryManagerStateToFile · Issue #64 · pleriche/FastMM4 · GitHub

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

delphi – Can I use an Edit Mask to format output? (not just validate input) – Stack Overflow

Posted by jpluimers on 2020/10/27

From a while ago, and – being on the back-end side mostly – I sometimes forget: [WayBack] delphi – Can I use an Edit Mask to format output? (not just validate input) – Stack Overflow

You can use the TField.OnGetText event or TNumericField.DisplayFormat property to modify how the text is being displayed.

Since you have a TStringField holding numbers, you have two choices:

  • use a TNumericField and the DisplayFormat property
  • use the OnGetText event and do your own string formatting

Edit:

Sam used this approach:

I implemented OnSetText and OnGetText event handlers. I already had the Edit Mask 9999 9999 9999 9999;1;_ so the OnSetText was just

TStringField(Sender).Value := Trim(Text);

and OnGetText was just

sValue := TStringField(Sender).Value;  
Text := Format('%s %s %s %s', [Copy(sValue, 1, 4), Copy(sValue, 5, 4), Copy(sValue, 9, 4), Copy(sValue, 13, 4)]);

It works fine. Thanks.

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

My toolkit – Roald’s blog

Posted by jpluimers on 2020/10/22

Always interesting to see what others put on their Windows development systems, for instance: [WayBack] My toolkit – Roald’s blog

Everytime I (re)install my development computer I need to think about all the tools I need and use on a regular basis. For that reason, and maybe to inspire others, here’s my list of essentia…

–jeroen

Posted in .NET, Delphi, Development, Software Development, Windows Development | Leave a Comment »