Quantcast
Channel: Delphi XE – The Wiert Corner – irregular stream of stuff
Viewing all 310 articles
Browse latest View live

Delphi: a memento that executes any code at end of method

$
0
0

Following up on yesterdays Delphi: using IInterface to restore cursor at end of mehod (prelude to a memento that executes any code at end of method) here is the memento I meant.

They are based on anonymous methods, which in Delphi are closures: they capture location.

The location is kept just as long as needed, based on a well known Delphi reference counting mechanism: interfaces. The same one I used for the TTemporaryCursor class (and one of the reasons the TTemporaryCursor will keep functioning).

My goal was to simplify code like this:

procedure TTemporaryCursorMainForm.TemporaryCursorClassicButtonClick(Sender: TObject);
var
  Button: TButton;
  SavedCursor: TCursor;
  SavedEnabled: Boolean;
begin
  Button := Sender as TButton;
  SavedEnabled := Button.Enabled;
  try
    Button.Enabled := False;
    SavedCursor := Screen.Cursor;
    try
      Screen.Cursor := crHourGlass;
      Sleep(3000);
    finally
      Screen.Cursor := SavedCursor;
    end;
  finally
    Button.Enabled := SavedEnabled;
  end;
end;

Into this:

procedure TTemporaryCursorMainForm.TemporaryCursorMementoButtonClick(Sender: TObject);
var
  Button: TButton;
  SavedEnabled: Boolean;
begin
  TTemporaryCursor.SetTemporaryCursor();
  Button := Sender as TButton;
  SavedEnabled := Button.Enabled;
  TAnonymousMethodMemento.CreateMemento(procedure begin Button.Enabled := SavedEnabled; end);
  Button.Enabled := False;
  Sleep(3000); // sleep 3 seconds with the button disabled crHourGlass cursor
  // Delphi will automatically restore the cursor
end;

We’ve already seen one of the try…finally…end blocks vanish by using TTemporaryCursor. Now lets look at TAnonymousMethodMemento:

unit AnonymousMethodMementoUnit;

interface

uses
  System.SysUtils;

type
  IAnonymousMethodMemento = interface(IInterface)
  ['{29690E1E-24C8-43A5-8FDF-5F21BB32CEC2}']
  end;

  TAnonymousMethodMemento = class(TInterfacedObject, IAnonymousMethodMemento)
  strict private
    FFinallyProc: TProc;
  public
    constructor Create(const AFinallyProc: TProc);
    destructor Destroy; override;
    procedure Restore(const AFinallyProc: TProc); virtual;
    class function CreateMemento(const AFinallyProc: TProc): IAnonymousMethodMemento;
  end;

implementation

{ TAnonymousMethodMemento }
constructor TAnonymousMethodMemento.Create(const AFinallyProc: TProc);
begin
  inherited Create();
  FFinallyProc := AFinallyProc;
end;

destructor TAnonymousMethodMemento.Destroy;
begin
  Restore(FFinallyProc);
  inherited Destroy();
end;

class function TAnonymousMethodMemento.CreateMemento(const AFinallyProc: TProc): IAnonymousMethodMemento;
begin
  Result := TAnonymousMethodMemento.Create(AFinallyProc);
end;

procedure TAnonymousMethodMemento.Restore(const AFinallyProc: TProc);
begin
  AFinallyProc();
end;

end.

Like TTemporaryCursor, I’ve kept it self-contained.

It uses a TProc parameter – a parameterless anonymous method – called AFinallyProc that needs to be executed right before the memento goes out of scope.

It can be called like any method, as to the compiler it is a method.

–jeroen


Filed under: Delphi, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Software Development

Delphi: interesting unit uExecFromMem from DelphiBasics.info: start an executable from binary memory image

$
0
0

A long while ago, DelphiBasics.info (they are hosted on Google Sites) posted a very interesting via: uExecFromMem unit. It was only a code snippet, not much usage info.

One of the things you can do with this unit, is load the memory image of an executable from a database BLOB, then execute that.

bummi showed this as an uExecFromMemory example on StackOverflow including a small memory leak fix.

It opens way for some interesting deployment scenarios. Not for the everyday ones, but for the occassional situation where a regular deployment is impractical.

–jeroen

via: uExecFromMem by steve10120 – fixed for Win7x64 by testest – DelphiBasics.

Comment by Craig Peterson at G+: https://plus.google.com/109418621512564781181/posts/WZSa6Nt44rK

It’s a handy looking unit, but has a licensing bomb in it: The PerformBaseRelocation routine is lifted directly from BTMemoryModule.pas, which is only licensed LGPL without the binary linking exception.  That means providing your DCUs so anyone can relink your app.  It’s also a bit less maintainable than BTMemoryModule, since they replaced a bunch of declared constants with magic numbers.


Filed under: Delphi, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Software Development

The dreaded with… Debugging today, I found another gotcha (: – via: Lars Fosdal

$
0
0

In the With Statement series:

Lars Fosdal – Code Rants

The dreaded with…

Debugging today, I found another gotcha.

In this case, both Self and DisconnectedClient has a property named ClientIdentifier.

Note the difference for the mouse-over and the evaluation.

–jeroen

via The dreaded with… Debugging today, I found another gotcha. In this case,….

In this case, both Self and DisconnectedClient has a property named ClientIdentifier.  Note the difference for the mouse-over and the evaluation.

In this case, both Self and DisconnectedClient has a property named ClientIdentifier. Note the difference for the mouse-over and the evaluation.


Filed under: Appmethod, Borland Pascal, Delphi, Delphi 1, Delphi 2, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Pascal, Software Development, Turbo Pascal, With statement

Delphi and C++ Builder VCL Library Buffer Overflow

$
0
0

Since this did not make it to DelphiFeeds yet: I’ve seen the function PaletteFromDIBColorTable in Graphics.pas go back as far at least until Delphi 2006, and references on the web as far back as Delphi 4.

So: this bug is old, but as it is a security one, make sure you patch soon.

For Delphi XE6, download 29913 BMP Buffer Overflow hotfix – Delphi, C++Builder, RAD Studio XE6.

For older Delphi versions, read this piece that was adapted from the EDN article Delphi and C++ Builder VCL Library Buffer Overflow:

For users of prior versions of Delphi and C++Builder: these steps should be followed to modify the VCL source code and add it to your application.

For each application:

  1. Add the modified Edit Vcl.Graphics.pas or Graphics.pas or Borland.Vcl.Graphics.pas to your project
  2. For C++Builder: Under Project | Options | Packages | Runtime Packages, set “Link with runtime packages” to false
  3. Rebuild your application

Once for the native VCL and .NET VCL:

  • Note: Variable names and scoping might be slightly different depending on your product version.
  1. Edit Vcl.Graphics.pas or Graphics.pas or Borland.Vcl.Graphics.pas
  2. Locate the function PaletteFromDIBColorTable.
  3. Add the following code just before the line assigning a value to Pal.palNumEntries when the DIBHandle = 0
    if ColorCount > 256 then
      InvalidGraphic{$IFNDEF CLR}@{$ENDIF}SInvalidBitmap;;

–jeroen

via Delphi and C++ Builder VCL Library Buffer Overflow.


Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Development, Software Development Tagged: Buffer Overflow, Delphi, Delphi versions, vcl

JEDI.INC got updated a few months ago: Delphi XE7 seems to be ahead…

$
0
0

While updating a project to a more recent version of Delphi, I also updated the JEDI.INC reference.

Note that since writing Delphi – finding the VERxxx define for a particular Delphi version: use JEDI.INC, the Delphi JEDI project moved from SoureForge to GitHub.

The fun thing: JEDI.INC got updated a few months ago to support Delphi XE7 provisionally.

Given the Delphi release cycle of twice a year, the Delphi Carpathia aka XE7 rumours this summer, I presume Delphi XE7 is near because of:

By then the list of Delphi Versionen | Delphi-Treff will likely also be updaed.

I’m anxious to see if the (Dutch + English) BIG Delphi Conference organized by Barnsten and Blaise from September 11-12 in the Netherlands will be part of the launch tour.

Anyway: here is the JEDI.INC portion with defines:    

    {$IFDEF VER280} // RAD Studio XE7
      {$DEFINE BDS}
      {$DEFINE BDS15}
      {$DEFINE COMPILER21}
      {$IFDEF BCB}
        {$DEFINE BCB21}
      {$ELSE}
        {$DEFINE DELPHI21}
        {$DEFINE DELPHIXE7} // synonym to DELPHI21
        {$DEFINE DELPHICOMPILER21}
      {$ENDIF BCB}
      {$DEFINE RTL280_UP}
      {$UNDEF UNKNOWN_COMPILER_VERSION}
    {$ENDIF VER280}

–jeroen

via: jedi/jedi.inc at master · project-jedi/jedi.


Filed under: Delphi, Delphi 1, Delphi 2, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development

A way for a VCL TFrame to be notified when it is actually shown (via G+)

$
0
0

Interesting, as I didn’t think this was possible. Thanks Oliver Funcke!

Notification when a `TFrame` becomes visible.

TMyCommonFrame = class(TFrame)
  private
    FOnShow: TNotifyEvent;
    procedure CMShowingChanged(var M: TMessage); message CM_SHOWINGCHANGED;
  public
    property OnShow : TNotifyEvent read FOnShow write FOnShow;
  end;
...
procedure TMyCommonFrame.CMShowingChanged(var M: TMessage);
begin
  inherited;
  if Showing and Assigned(FOnShow) then
    FOnShow(Self);
end;

–jeroen

via Is there any way for a VCL TFrame to be notified when it is actually shown to….


Filed under: Delphi, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Development, Software Development

Delphi: always watch the compiler Warnings

$
0
0

Quiz questions:

  1. Does the below unit test succeed or fail?
  2. Why?
procedure TestHResult.Test_EOleException;
var
  OleException: EOleException;
  IResult: LongInt; // == HResult
  UResult: Cardinal; // == DWord
begin
  IResult := $800A11FD;
  UResult := $800A11FD;
  try
    OleException := EOleException.Create('message', $800A11FD, 'source', 'helpfile', -1);
    raise OleException;
  except
    on E: EOleException do
    begin
      if E.ErrorCode = $800A11FD then
        Exit;
      Self.CheckEquals(E.ErrorCode, $800A11FD, 'E.ErrorCode should equal $800A11FD');
    end; // E: EOleException
  end;
end;

I partially gave away the answers in the title of the title of the post.

But first some background information:

The above code is inspired by code I see in a lot of applications at clients: tons of compiler warnings (and even more hints).

That is not the way you should program your applications (be it Delphi or any other): always make them Warning free. And try to make them Hint free too.

This particular test came of an application that tried to do handling of EOleException using the ErrorCode field which is of type HResult which – like for instance the .NET ExternalException.ErrorCode – is a 32-bit signed Integer (the 32-bit unsigned data type is Cardinal).

HResult is the Delphi equivalent of the Windows (and in the past OS/2) HRESULT. Most documentation will give you error codes in hexadecimal, is it is much easier to formulate the bit fields in HRESULT using hexadecimal values than decimal ones.

Now for the Warnings and why they are caused.

The assignment of the hexadecimal literal value to IResult will give the first warning: the literal is larger than the High(Integer) value (which is the same MaxInt). It won’t fit in a 4-byte Integer, but the compiler – despite the warning – will make it fit. If you ask the debugger for the hexadecimal value of IResult, it will happily return $800A11FD.

The signed decimal equivalent that gets assigned to UResult is 2148143613: no warning as it will fit.

  // [DCC Warning] TestHResultUnit.pas(35): W1012 Constant expression violates subrange bounds
  IResult := $800A11FD; // Does not fit, but will cast 4-byte Cardinal into a 4-byte Integer with value -2146823683 ($800A11FD)
  UResult := $800A11FD; // Fits, will have value 2148143613 ($800A11FD)

The second warning is the same one as the first. Which means that OleException.ErrorCode will get the same value as IResult:

    // [DCC Warning] TestHResultUnit.pas(41): W1012 Constant expression violates subrange bounds
    OleException := EOleException.Create('message', $800A11FD, 'source', 'helpfile', -1);

The difference btween IResult and UResult also explain the next two warnings: they basically come down to comparing  -2146823683 (the stored value in E.ErrorCode) and 2148143613 (the signed equivalent of $800A11FD).

Since $800A11FD is bigger than MaxInt, the comparison will always be false.

      // [DCC Warning] TestHResultUnit.pas(48): W1021 Comparison always evaluates to False
      // [DCC Warning] TestHResultUnit.pas(48): W1023 Comparing signed and unsigned types - widened both operands
      if E.ErrorCode = $800A11FD then // Integer can never match a Cardinal larger than High(Integer);
        Exit;

You can workaround these warnings in two ways – either cast to HResult or to Cardinal:

      if E.ErrorCode = HResult($800A11FD) then
        Exit; // Succeed
      if Cardinal(E.ErrorCode) = $800A11FD then
        Exit; // Succeed

Finally no warning, but still a failure: both E.ErrorCode and $800A11FD is now passed as Int64 because there are no better overloads for TTestCase.CheckEquals in the TestFramework unit of DUnit.

Which again means that -2146823683 is compared to 2148143613. Which fails the test case.

      // No warning, but both are passed as Int64, so comparison fails
      Self.CheckEquals(E.ErrorCode, $800A11FD, 'E.ErrorCode should equal $800A11FD');

To answer the questions:

  1. Does the below unit test succeed or fail?
    Fail.
  2. Why?
    Because of compiler warnings, and the TTestCase.CheckEquals overload chosen by the compiler.

–jeroen

unit TestHResultUnit;

interface

uses
  TestFramework, System.SysUtils;

type
  TestHResult = class(TTestCase)
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure Test_EOleException;
  end;

implementation

uses
  System.Win.ComObj, Winapi.Windows;

// 1 Fool the optimizer
procedure Touch(var X);
begin

end;

procedure TestHResult.Test_EOleException;
var
  OleException: EOleException;
  IResult: LongInt; // == HResult
  UResult: Cardinal; // == DWord
begin
  // [DCC Warning] TestHResultUnit.pas(35): W1012 Constant expression violates subrange bounds
  IResult := $800A11FD; // Does not fit, but will cast 4-byte Cardinal into a 4-byte Integer with value -2146823683 ($800A11FD)
  UResult := $800A11FD; // Fits, will have value 2148143613 ($800A11FD)
  Touch(IResult);
  Touch(UResult);
  try
    // [DCC Warning] TestHResultUnit.pas(41): W1012 Constant expression violates subrange bounds
    OleException := EOleException.Create('message', $800A11FD, 'source', 'helpfile', -1);
    raise OleException;
  except
    on E: EOleException do
    begin
      // [DCC Warning] TestHResultUnit.pas(48): W1021 Comparison always evaluates to False
      // [DCC Warning] TestHResultUnit.pas(48): W1023 Comparing signed and unsigned types - widened both operands
      if E.ErrorCode = $800A11FD then // Integer can never match a Cardinal larger than High(Integer);
        Exit; // Succeed
      // No warning, but both are passed as Int64, so comparison fails
      Self.CheckEquals(E.ErrorCode, $800A11FD, 'E.ErrorCode should equal $800A11FD');
    end; // E: EOleException
  end;
end;

procedure TestHResult.SetUp;
begin
end;

procedure TestHResult.TearDown;
begin
end;

initialization

RegisterTest(TestHResult.Suite);

end.

Filed under: Delphi, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Development, Software Development

Continua CI Version 1.5 has been released (build 1.5.0.268); smaller, faster, loads of new features; Spring4D XE7 builds automated

$
0
0

I’m really happy that Continua CI Version 1.5 got released a few hours ago as per the Continua 1.5 released announcement.

It means that my Build Automation Session during the Dutch Delphi 2014 conference tomorrow can range from:

  • build using MSbuild from the command-line
  • build batch files
  • build using a custom front-end
  • build using Continuous Integration front-end

The session will explain lots of details about what various Delphi versions do, how to cope with dependencies, etc.

In the mean time, the preliminary Spring4D work on build automation is visible to guest users. Those include building for Delphi XE7 for the Win32, Win64 and OSX32 targets (in Debug and Release mode).

There is a huge list of Version 1.5 History @ Continua CI changes, which is partially quoted below.

For me these are the most important:

  • in-place upgrade without having to do any changes on my part
  • truckload of new features (including Delphi XE7, NuGet and Fake F# support)
  • smaller
  • faster

(as a side note: also FinalBuilder 7 was recently updated to support Delphi XE7)

In general, I like Continua CI a lot, most importantly because:

  • it is very stable
  • it has native support for a wide range of software development tools (including Delphi, Visual Studio and much more)
  • supports DVCS (like Git/Mercurial) just as you expect it to
  • if something breaks, you get a response and fix very very soon

You can download the new version through the Downloads @ Continua CI. These are the direct links:

For a breaking issue, there has been an important bug fix, so the new downloads are:

I created an RSS feed through Page2RSS to watch any new releases of Continua CI.

Parts of the changes in 1.5.0.268 1.5.0.278

The full list of changes are at Version 1.5 History @ Continua CI.

Be sure to also look at the official Continua 1.5 released announcement.

  • Reworked UI:
    • Now using bootstrap framework for styling
    • Redesigned Project detail view to show more information including graphs.
    • Added stages information to the Project tile and list views
    • Disabled configurations are now displayed as faded
  • Cloning:
    • Can now clone whole projects and clone configurations between projects.
  • Stage Conditions:
    • Auto Promote conditions – stages can now use conditions to control whether to auto-promote to the next stage.
    • Skip conditions – you can now provide conditions for skipping stages or disable a stage completely.
  • New Actions:
    • Fake (F#) build runner.
    • NuGet restore action.
    • Update GitHub Status Action is now deprecated (use event handler instead – see below).
  • Repository Tags: (Git, Mercurial and Subversion repositories only)
    • Continua CI can now detect and list repository tags.
    • Tags are now displayed in changeset tabs on configuration and build views.
    • Repository trigger can now be set to trigger on tag changes (new tags, edits and deletions) changes).
    • You can now run a build on a tagged changeset.
  • Build Event Handlers: allowing you execute various tasks on the server based on build status changes.
    • Octopus Deploy: Create/Deploy/Promote Octopus Deploy releases.
    • Tag Repository Changeset – Apply tags to a repository changeset (Git, Mercurial and Subversion repositories only)
    • Update GitHub Status – replaces the Update GitHub Status action.
  • Various other changes including:
    • Report ordering: you can choose which one is displayed first on the build view.
    • New expression functions: Utils.NewGuid() and Utils.RandomNumber() can be used for generation of temporary paths for example

Note : You will need to update your agents after upgrading the server to this build.<


Filed under: .NET, Continua CI, Continuous Integration, Delphi, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development, Spring4D

Delphi poor mans debugging trick: approximate the source location of an exception address

$
0
0

A while ago, I had a client with an exception on a workstation.

There was no permission to run a debugger on their system, or use something like MadExcept or Exceptional Magic in their code base.

The exception looked like this:

---------------------------
Application Error
---------------------------
Exception EInOutError in module MyApplication.exe at 001656B1.File access denied.
---------------------------
OK
---------------------------

These are the steps to get at the source line in an x86 Delphi program (I still have to try the x64, but presume it works similarly):

  1. Go to the Project Options dialog
  2. Browse to Delphi Compiler; Linking
  3. Note the value of the Image Base setting (in this case $400000
  4. Add that to the value from the error dialog ($001656B1 + $400000 = $005656B1)
  5. Use F7 to step into your executable
  6. In the menu goto View; Debug Windows; CPU Windows; Entire CPU
  7. Press Ctrl-G then enter $005656B1
  8. Press Ctrl-V to go to the source code line

Convoluted, but it works (:

 

–jeroen


Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 7, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Software Development

Delphi hinting directives: deprecated, experimental, library and platform

$
0
0

I’ve been experimenting with the Delphi hinting directives lately to make it easier to migrate some libraries to newer versions of Delphi and newer platforms.

Hinting directives (deprecated, experimental, library and platform) were – like the $MESSAGE directive – added to Delphi 6.

Up to Delphi 5 you didn’t have any means to declare code obsolete. You had to find clever ways around it.

Warnings for hinting directives

When referring to identifiers marked with a hinting directive, you can get various warning messages that depend on the kind of identifier: unit, or other symbol.

Note the warning numbering is not in the alphabetic order of the hinting directive.

Unit identifiers can get these warnings:

  • W1006 Unit ‘HintingDirectivesUnit’ is deprecated
    //unit HintingDirectivesUnit deprecated;
  • W1007 Unit ‘HintingDirectivesUnit’ is experimental
    //unit HintingDirectivesUnit experimental;
  • W1004 Unit ‘HintingDirectivesUnit’ is specific to a library
    //unit HintingDirectivesUnit library;
  • W1005 Unit ‘HintingDirectivesUnit’ is specific to a platform
    //unit HintingDirectivesUnit platform;

Non-unit symbols can get these warnings:

  •  W1000 Symbol ‘FieldDepracated’ is deprecated
    //Default.FieldDepracated := 1;
  •  W1003 Symbol ‘FieldExperimental’ is experimental
    //Default.FieldExperimental := 1;
  •  W1001 Symbol ‘FieldLibrary’ is specific to a library
    //Default.FieldLibrary := 1;
  •  W1002 Symbol ‘FieldPlatform’ is specific to a platform
    //Default.FieldPlatform := 1;

Hinting directives: deprecated differs from the others

Of the hinting directives, deprecated is more versatile than experimental, library and platform as it allows two forms: with and without a ‘comment’.

I wasn’t aware of this part of the deprecated syntax until recently. The syntax part was introduced in Delphi 12.0 (aka Delphi 2009). You can for instance see it in the RTLConsts unit:

SInvalidDate = '''''%s'''' is not a valid date' deprecated 'Use SysConsts.SInvalidDate';
SInvalidDateTime = '''''%s'''' is not a valid date and time' deprecated 'Use SysConsts.SInvalidDateTime';
SInvalidInteger = '''''%s'''' is not a valid integer value' deprecated 'Use SysConsts.SInvalidInteger';
SInvalidTime = '''''%s'''' is not a valid time' deprecated 'Use SysConsts.SInvalidTime';
STimeEncodeError = 'Invalid argument to time encode' deprecated 'Use SysConsts.STimeEncodeError';

ModelMaker Code Explorer does not support this syntax yet, but they are aware of this.

But depending on the kind of identifier you use it on, the compiler warnings can be different.

When used on a unit, you can use both forms, but when using the unit, you get one kind of compiler warning:

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated
//unit HintingDirectivesUnit deprecated;

No warning about the ‘comment’:

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated
//unit HintingDirectivesUnit deprecated 'use a different one';

But when using it on a variable,

var
I: Integer deprecated 'do not use global variables';
J: Integer deprecated;
K: Integer deprecated platform library experimental;

the forms result in different compiler warnings:

// W1000 Symbol 'I' is deprecated: 'do not use global variables'
I := 1;

// W1000 Symbol 'J' is deprecated
J := 2;

// W1000 Symbol 'K' is deprecated
// W1001 Symbol 'K' is specific to a library
// W1002 Symbol 'K' is specific to a platform
// W1003 Symbol 'K' is experimental
K := 3;

The effects of a unit hinting directive

The hinting directive documentation states that hinting directives on units apply on references to all the symbols on the unit:

When a hint directive appears in a unit declaration, it means that the hint applies to everything in the unit. For example, the Windows 3.1 style OleAuto.pas unit on Windows is completely deprecated. Any reference to that unit or any symbol in that unit produces a deprecation message.

But this also has a twist on all the unit symbols referenced from within the unit: when a symbol is marked with the same hinting directive as the unit, you will not get a warning referencing that symbol in the unit itself.

So a symbol marked deprecated, will not show a warning when referenced from inside the unit if the unit is also marked deprecated. The same holds for the other hinting directives.

Hinting directives on properties are still a no-go

Despite QC96350 (Cannot apply ‘deprecated’ keyword to property declarations) being open for 2 years, and the StackOverflow question How can I mark a property as deprecated in delphi? you can’t use hinting directives on properties.

So far for consistency (I will blog more on that later).

You cannot do either of these:

type
  TTest = class
  protected
    FValue: Integer;
  public
    property Value: Integer read FValue write FValue; deprecated; // E2169 Field definition not allowed after methods or properties
    property Value2: Integer read FValue write FValue deprecated; // E2029 ';' expected but identifier 'deprecated' found
  end;

Applying and combining hinting directives

A few rules for using hinting directives

  • The semicolon between the hinting directive and the symbol declaration usually has to be left out, except for methods where it has to be there.
  • There is no semicolon between combined hinting directives.
  • The abstract directive comes after the last hinting directive and does get separated by a semicolon.

So you get code like this:

THinted = class
end deprecated platform library experimental;

FieldDepracated: Integer deprecated;
FieldAll: Integer deprecated platform library experimental;

function Func: Integer; virtual; abstract;
function FuncDeprecated: Integer; virtual; deprecated; abstract;

procedure Proc; virtual; abstract;
procedure ProcDeprecated virtual; deprecated; abstract;

Full sample code

The full sample code is a BeSharp SVN change-set; the main unit is below.

Have fun with it!

–jeroen

unit HintingDirectivesUnit;

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated
//unit HintingDirectivesUnit deprecated;

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1007 Unit 'HintingDirectivesUnit' is experimental
//unit HintingDirectivesUnit experimental;

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1004 Unit 'HintingDirectivesUnit' is specific to a library
//unit HintingDirectivesUnit library;

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1005 Unit 'HintingDirectivesUnit' is specific to a platform
//unit HintingDirectivesUnit platform;

//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated
//unit HintingDirectivesUnit deprecated 'use a different one';

interface

var
  I: Integer deprecated 'do not use global variables';
  J: Integer deprecated;
  K: Integer deprecated platform library experimental;

type
  THinted = class
  end deprecated platform library experimental;

// W1000 Symbol 'THinted' is deprecated
// W1001 Symbol 'THinted' is specific to a library
// W1002 Symbol 'THinted' is specific to a platform
// W1003 Symbol 'THinted' is experimental
// W1000 Symbol 'THinted' is deprecated
  THintedClass = class of THinted;

  TDefault = class(TObject)
  strict private
    FMember: Integer;
  public
    Field: Integer;
    FieldDepracated: Integer deprecated;
    FieldExperimental: Integer experimental;
    FieldLibrary: Integer library;
    FieldPlatform: Integer platform;
    FieldAll: Integer deprecated platform library experimental;
    function Func: Integer; virtual; abstract;
    function FuncDeprecated: Integer; virtual; deprecated; abstract;
    function FuncExperimental: Integer; virtual; experimental; abstract;
    function FuncLibrary: Integer; virtual; library; abstract;
    function FuncPlatform: Integer; virtual; platform; abstract;
    procedure Proc; virtual; abstract;
    procedure ProcDeprecated; virtual; deprecated; abstract;
    procedure ProcExperimental; virtual; experimental; abstract;
    procedure ProcLibrary; virtual; library; abstract;
    procedure ProcPlatform; virtual; platform; abstract;
    property Member: Integer read FMember write FMember;
  strict protected
    procedure ProcDeprecatedComment; virtual; deprecated 'use some other Proc in stead'; abstract;
  strict private
    // E2169 Field definition not allowed after Procs or properties
    // procedure ProcAbstractDeprecated; virtual;  abstract; deprecated;

    // E2029 ';' expected but string constant found
    // procedure ProcExperimentalComment; virtual; experimental 'Experimental Proc'; abstract;

    // E2029 ';' expected but string constant found
    // procedure ProcLibraryComment; virtual; library 'Library Proc'; abstract;

    // E2029 ';' expected but string constant found
    // procedure ProcPlatformComment; virtual; platform 'Platform Proc'; abstract;

    // E2169 Field definition not allowed after Procs or properties
    // property MemberDeprecated: Integer read FMember write FMember; deprecated;
  end;

// W1001 Symbol 'THinted' is specific to a library
// W1002 Symbol 'THinted' is specific to a platform
// W1003 Symbol 'THinted' is experimental
implementation

procedure UseDefault;
var
  Default: TDefault;
begin
// W1000 Symbol 'I' is deprecated: 'do not use global variables'
  I := 1;
// W1000 Symbol 'J' is deprecated
  J := 2;
// W1000 Symbol 'K' is deprecated
// W1001 Symbol 'K' is specific to a library
// W1002 Symbol 'K' is specific to a platform
// W1003 Symbol 'K' is experimental
  K := 3;
// W1000 Symbol 'FuncDeprecated' is deprecated
// W1003 Symbol 'FuncExperimental' is experimental
// W1001 Symbol 'FuncLibrary' is specific to a library
// W1002 Symbol 'FuncPlatform' is specific to a platform

// W1000 Symbol 'ProcDeprecated' is deprecated
// W1003 Symbol 'ProcExperimental' is experimental
// W1001 Symbol 'ProcLibrary' is specific to a library
// W1002 Symbol 'ProcPlatform' is specific to a platform

// W1000 Symbol 'ProcDeprecatedComment' is deprecated: 'use some other Proc in stead'
  Default := TDefault.Create();
  try
    Default.Field := 1;
// W1000 Symbol 'FieldDepracated' is deprecated
    Default.FieldDepracated := 1;
// W1003 Symbol 'FieldExperimental' is experimental
    Default.FieldExperimental := 1;
// W1001 Symbol 'FieldLibrary' is specific to a library
    Default.FieldLibrary := 1;
// W1002 Symbol 'FieldPlatform' is specific to a platform
    Default.FieldPlatform := 1;
  finally
    Default.Free;
  end;
end;

end.

Filed under: Apple Pascal, Borland Pascal, DEC Pascal, Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 6, Delphi 7, Delphi 8, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Encoding, FreePascal, ISO-8859, ISO8859, Java, Lazarus, MQ Message Queueing/Queuing, Reflection, Software Development, Sybase, Unicode, UTF-8, UTF8

Delphi: RandomizeIfNeeded

$
0
0

Calling Randomize too often can make your Random numbers even less random.

Sometimes having the Randomize call in a unit initialization section is not practical.

Hence this little method that I think I first wrote back in the Turbo Pascal days:

procedure RandomizeIfNeeded();
begin
  if RandSeed = 0 then
    Randomize();
end;

–jeroen


Filed under: Delphi, Delphi 1, Delphi 2, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi for PHP, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Pascal, Software Development, Turbo Pascal

Files in your Delphi settings directory; How to relocate the Favourites on your Welcome page

$
0
0

Delphi and 3rd party tools keep some of the settings in your %AppData% directory. Much more convenient than the registry as they are easier to read and modify when needed (also easier to damage <g>). We’ll start with an overview where various versions of Delphi store their configuration files, then show how the Favourites on the Welcome Page are stored, then end with an overview of BDS, Company Names and Product Names.

Configuration files

Depending on the Delphi version, the files are under one of these directories:

  • %AppData%\%CompanyName%\BDS\#.0 %AppData%\%CompanyName%\RadStudio\#.0
  • %AllUsersProfile%\Application Data\%CompanyName%\RadStudio\#.0

%AppData% is for user specific settings; %AllUsersProfile% for system global settings. BDS stands for Borland Developer Studio, the official name for the (then new) Gailileo IDE foundation that was the successor of the old IDE architecture used from Delphi until 7. In practice, I’ve never seen any file stored under the RadStudio directory within %AppData%.

Registry paths.

Note the registry key paths used for configuring Delphi are constructed in a way similar to the directory names:

  • HKEY_CURRENT_USER\Software\%CompanyName%\BDS\#.0
  • HKEY_LOCAL_MACHINE\Software\%CompanyName%\BDS\#.0

Note the registry only uses BDS, not RadStudio. Both %CompanyName% and # depend on the BDS versions. So further below are two lists: one mapping the BDS version to CompanyName, the other to Delphi version. But first about the files in the Delphi settings directory, so we can start looking at how favourites are stored.

BTW: Though not covered any further here, Delphi 2-7 had different registry roots as mentioned in a SO comment by Remy Lebeau:

  • HKEY_CURRENT_USER\Software\Borland\Delphi\#.0

  • HKEY_LOCAL_MACHINE\Software\Borland\Delphi\#.0

Delphi settings directory files

These are the files you usually have in the directory %AppData%\%CompanyName%\BDS\#.0:

myFavorites.xml: the Favourites in your Welcome page

Back to the Favourites that you can organize in your Welcome page. These are stored in myFavorites.xml which has a remarkably simple XSD structure (both links are to Pastebin as WordPress regularly screws up XML). Normally the XML is on one line, but with an online tool like Free Online XML Formatter – FreeFormatter.com you can put everything into a human-readable form. Delphi can work with both. This allowed me to move my source directory tree from C:\Develop to another directory in a small search/replace manner.

CompanyName mapping

  • CompanyName=Borland (from BDS 1 until BDS 5)
  • CompanyName=CodeGear (from BDS 6 until BDS 7)
  • CompanyName=Embarcadero (BDS 8 and up)

You see that CodeGear only lived for a short period of time. There is quite a bit confusion on the internet about this, just look at these searches to get a feel for that:

BDS number to product version mapping

I’ve included the table below as the data is not in the table I referenced from Found a table with Delphi Conditional defines over the Delphi versions/compiler platforms/bitness.

The # depends on the BDS/Galileo version number which started with Borland Development Studio 1.0 a.k.a. C# Builder 1.0.

For each product version, I noted which products were added/removed compared to the previous one.

  1. C# Builder (contained only C# Builder)
  2. Delphi 8 (added Delphi .net)
  3. Delphi 2005 (added Delphi win32)
  4. Delphi 2006 (added C++ Builder)
  5. Delphi 2007
  6. Delphi 2009
  7. Delphi 2010
  8. Delphi XE
  9. Delphi XE2 (added Delphi win64)
  10. Delphi XE3 (added C++ Builder win64, OS X x86 and iOS x86/arm through FreePascal)
  11. Delphi XE4 (replaced FreePascal with native Delphi compiler for iOS x86/arm)
  12. Delphi XE5 (added Android ARMv7)

I verified most of these from either my own Delphi / C# Builder installations or from the uDelphiVersions unit in WMI Delphi Code Creator.

And at the time of writing, I’m guessing BDS 12, and wondering if BDS 13 will be skipped like Delphi 13, jokingly or not like mentioned in The Oracle at Delphi » What happened to version 13?.

–jeroen


Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 8, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, History, Software Development

The Delphi MESSAGE directive: don’t forget quotes!

$
0
0

The Delphi MESSAGE directive is a very powerful one, you can generate compiler hints, warnings and errors with it, even fatal ones that abort compilation.
The compiler will return error codes H1054 (hint), W1054 (warning), E1054 (error) or F1054 (fatal error), which in the documentation are known under the catch-all x1054.

You need to take a bit of care with message directives, especially with the quotes. For instance

{$Message Error 'Not implemented'}

gives you the error below, but continues compiling:

[DCC Error] E1054 Not implemented

However, if you forget the single quotes

{$Message Error Not implemented}

it gives you error E1030  (not x1054), which is a bit confusing as it is a catch-all for invalid directives:

[DCC Error] E1030 Invalid compiler directive: 'message'

Here is a full example of all the message directives and compiler reactions you can get:

program Message_Directive;

{$APPTYPE CONSOLE}

{$R *.res}

begin
  {$MESSAGE 'Boo!'}
  {$Message Hint 'Feed the cats'}
  {$messaGe Warn 'Looks like rain.'}
  {$Message Error 'Not implemented'}
  {$Message Fatal 'Bang.  Yer dead.'}
{
[DCC Hint] Message_Directive.dpr(8): H1054 Boo!
[DCC Hint] Message_Directive.dpr(9): H1054 Feed the cats
[DCC Warning] Message_Directive.dpr(10): W1054 Looks like rain.
[DCC Error] Message_Directive.dpr(11): E1054 Not implemented
[DCC Fatal Error] Message_Directive.dpr(12): F1054 Bang.  Yer dead.
}
end.

–jeroen

via: MESSAGE directive (Delphi) – RAD Studio.

PS: for a full list of Delphi hint/warning/error compiler messages, see Marc Durdin’s excellent post  Delphi XE2’s Hidden Hints and Warnings.


Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development

Barry Kelly on “Implementing Closures” in Delphi (via: Google Groups)

$
0
0

It is always nice to see one of the compiler engineers write down how something was implemented.

In this case, Barry Kelly explains in comp.compilers on Implementing Closures in Delphi 2009. The post is about 4.5 years old, but still very relevant.

About 9 months earlier, he participated in a Reddit thread about a similar topic. Worth reading too!

–jeroen

via: Implementing Closures – Google Groups.


Filed under: Delphi, Delphi 2009, Delphi 2010, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development

Barry Kelly on how the Delphi Compiler used to be compiled (via: Google Groups)

$
0
0

Delphi, C#, VB.NET and SQL all have escapes to use reserved words as identifiers

$
0
0

Normally you would not want to use a reserved word as an identifier. But sometimes it can be very convenient, for instance for a code generator that wraps remoting calls or does ORM.

Both Delphi and C# have an escape for this:

The prefixes are to tell the compiler knows you really know what you are doing, and are using a reserved word as an identifier.

The cool thing: in the Run Time Type Information (Delphi) or Reflection (C# and VB.NET) you will see the names without the prefix.

Some examples from StackOverflow:

& prefix for Delphi

private &string: Integer;

Kenny Cason answered delphi – Is it possible to use reserved words for field names? – Stack Overflow.

@ prefix for C#

private long @string;

Jon Skeet answered Use the long reserved word as a variable name in C# – Stack Overflow.

[] embedding for VB.NET

Private [string] As Integer;

Tobias Wittenburg asked vb.net – Reserved Keyword in Enumeration in C# – Stack Overflow.

The VB.NET way also works in Microsoft SQL Server and Microsoft Access.

“” embedding in many SQL syntaxes

Examples:

Exception: Microsoft SQL Server and Microsoft Access use [] embedding.

Note:

Some SQL implementations uses the embedding not only to allow for reserved words, but also to allow embedding spaces in identifiers.

Delphi, C# and VB.NET cannot do that, so be aware of that when performing ORM work.

–jeroen


Filed under: .NET, .NET 1.x, .NET 2.0, .NET 3.0, .NET 3.5, .NET 4.0, .NET 4.5, C#, C# 1.0, C# 2.0, C# 3.0, C# 4.0, C# 5.0, Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 8, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development, VB.NET, VB.NET 10.0, VB.NET 11.0, VB.NET 7.0, VB.NET 7.1, VB.NET 8.0, VB.NET 9.0

Delphi; Conditional defines in the .dpr: FastMM4 disappearing – via: G+ I’ve got an old problem, in which the IDE…

$
0
0

Vin Colgin posted on G+:

The kind of text that the Delphi IDE often removes in a .dpr file.

The kind of text that the Delphi IDE often removes in a .dpr file.

FastMM4 and lines in the *.dpr

I’ve got an old problem, in which the IDE will take the lines required out of the “uses” clause in the *.dpr. Something I’m sure we’re all aware of, but is there a solution to keep it from doing it?

The comments indicate the problem is less severe in more recent Delphi versions:

Daniela Osterhagen Actually it has become much better. The IDE doesn’t meddle as much with the DPR files as it used to.

One option for solving this issue is adding a new unit as the first entry that permanently stays there and moving the ifdef to that unit.

That’s what I did a long time ago and even put on-line, and even put it on-line at CodePlex as FastMM4BootstrapUnit.pas. Too bad CodePlex isn’t indexed on Google, so I commented this:

I’m using a FastMM4BootstrapUnit for that at the top of my DPR; it  looks like this […]

It will eventually end up at my BeSharp.net repository any way.Let me know if you need it there soon, and I can probably get something published after the Entwickler Konferenz next week.

So various people are now using this:

  • Vin Colgin:  very nice. Thanks for the tip!
  • Warren Postma: This works fine for me in xe6 and up.
  • Bruce McGee: Nice. May I steal this? And by “steal”, I mean giving credit in the code comments.

Since I could use this unit during my EKON 2014 talk about Delphi Unit Testing, I expedited the publication:

https://bitbucket.org/jeroenp/besharp.net/src/tip/Native/Delphi/Library/FastMM/FastMM4BootstrapUnit.pas

And explained the usage in this Unit testing session session materials.

Note: this file isn’t indexed either (as BitBucket doesn’t allow it), but since the repository will be git based in the foreseeable future anyway, I can then move it to GitHub which does allow Google to crawl the master branch.

–jeroen

via FastMM4 and lines in the *.dpr I’ve got an old problem, in which the IDE….


Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development

Delphi and Batch Files

$
0
0

Two interesting links today about Delphi and Batch files.

–jeroen

PS: If you want to see some serious Batch file and PowerShell related scripts, then read through the Build Automation part of my session materials I posted to ITDevCon and EKON session materials on Delphi Unit Testing + Build Automation and Continuous Integration on-line.

More details are in the batch files here:

and PowerShell scripts here:


Filed under: Batch-Files, Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 7, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Scripting, Software Development

ITDevCon and EKON session materials on Delphi Unit Testing + Build Automation and Continuous Integration on-line

$
0
0

The last couple of weeks I taught two sessions at both ITDevCon 2014 in Milano, Italy and EKON 2014 in Köln, Germany.

The EKON materials are slightly more up to date and elaborate (sessions there were 75 minutes), so below are all the links.

Notes:

  • I’ve switched to Markdown for presenting as that is very version control friendly
  • GitHub very good at handling relative links from your Markdown files to other resources, that I’ve switched the Conference repository to GitHub from BitBucket.
  • Somewhere over the next few months, the BeSharp.net repository will convert from Mercurial to Git and also move to GitHub.


Unit testing:

Directory with documents:

Document page:

Demos:

Build Automation:

Directories with documents:

Actual document pages:

Demos:

Enjoy it!

–jeroen


Filed under: Delphi, Delphi 2007, Delphi 2009, Delphi 2010, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Software Development

Windows .RES/Resource editors

$
0
0

While researching the manifest problem I will post about next week, I made a short list of free Windows Resource Editors:

All other resource editors I found were not free, and someof them not maintained for an even longer period than the free ones.

–jeroen


Filed under: Delphi, Delphi 2, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Development, Power User, Software Development, Windows, Windows 7, Windows 8, Windows Server 2000, Windows Server 2003, Windows Server 2003 R2, Windows Server 2008, Windows Server 2008 R2, Windows Vista, Windows XP
Viewing all 310 articles
Browse latest View live