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

Delphi threadvar: TLS thread local storage

Posted by jpluimers on 2019/02/07

Managing TLS correctly with all kinds of dynamic storage seems to be a nightmare.

From what I think it’s safe to use a TStopWatch [WayBackSystem.Diagnostics.TStopwatch (introduced in Delphi XE2) as threadvar (which gets into TLS: Thread-local storage) because it’s a record type and as a bonus will be zero-initialised in something like this:

threadvar
 ThreadStopwatch: TStopwatch; // threadvars are zero-initialised, like TStopwatch.Reset was called. Ensure TStopwatch.InitStopwatchType called before using this.

... thread code:
var
  lThreadElapsedMilliseconds: string;
begin
...
  if not ThreadStopwatch.IsRunning then
    ThreadStopwatch.Start;
  try
    lThreadElapsedMilliseconds := ThreadStopwatch.ElapsedMilliseconds.ToString();
    // log duration of call-to-call somewhere
... logic
    lThreadElapsedMilliseconds := ThreadStopwatch.ElapsedMilliseconds.ToString();
    // log duration of logic somewhere
  finally
    ThreadStopwatch := TStopwatch.StartNew; // resets new count
  end;

As long as I perform this in the main thread somwehere to pre-initialise the class variable, then no thread should have the penalty for that:

TStopwatch.Create(); // ensures non-public TStopwatch.InitStopwatchType is called, enabling the threadvar ThreadStopwatch get the penalty for that

If I ever need to dig deeper into TLS with Delphi, then these are starters:

–jeroen

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

Delphi Declarations and Statements: Hinting Directives

Posted by jpluimers on 2019/02/06

From [WayBackDeclarations and Statements: Hinting Directives you might remember this:

The ‘hint’ directives platformdeprecated, and library may be appended to any declaration. These directives will produce warnings at compile time. Hint directives can be applied to type declarations, variable declarations, class, interface and structure declarations, field declarations within classes or records, procedure, function and method declarations, and unit declarations.

However, it doesn’t as at least these fail:

type
{ [dcc32 Error] ClassConstUsageConsoleProject.dpr(14): E1030 Invalid compiler directive: 'DEPRECATED' }
  TMyProcedure = procedure() of object deprecated 'do not use TMyProcedure';
{ [dcc32 Error] E1030 Invalid compiler directive: 'DEPRECATED' }
  TMyReference = reference to procedure() deprecated 'do not use TMyReference';

These two helped me though:

This fails too:

type
{ [dcc32 Error] E2029 '=' expected but ';' found }
  TArrayChars = array of Char; deprecated;
{ [dcc32 Error] E2029 ';' expected but identifier 'deprecated' found }
  TArrayChars = array of Char deprecated;

But this is a workaround:

type
  TArrayCharsOld = array of Char;
  TArrayChars = TArrayCharsOld deprecated;

Which works for the procedure types as well:

type
  TMyProcedureOld = procedure() of object;
  TMyProcedure = TMyProcedureOld deprecated 'do not use TMyProcedure';
  TMyReferenceOld = reference to procedure();
  TMyReference = TMyReferenceOld deprecated 'do not use TMyReference';

Bug https://quality.embarcadero.com/browse/RSP-18316

–jeroen

Posted in Delphi, Development, Software Development | 1 Comment »

keyman/DevDelphiStarterCompileWrapper.pas at master · keymanapp/keyman

Posted by jpluimers on 2019/02/05

Cool: bds.exe -ns -b projectname.dproj will build a project from the command-line.

Should work in Starter Edition (and the now defunct AppMethod).

[WayBackkeyman/DevDelphiStarterCompileWrapper.pas at master · keymanapp/keyman.

Via: [WayBack] Question: is there any chance Embarcadero would reconsider and stop blocking the use of the command line compilers for Starter Edition?I run an open s… – Marc Durdin – Google+

–jeroen

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

Passing the `–symbol-report` to the Delphi compiler gives you a nice XML overview with all symbols used

Posted by jpluimers on 2019/01/31

Cool undocumented parameter --symbol-report at the [WayBack/Archive] Hatena Diary mid 2017:

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development, Undocumented Delphi | 7 Comments »

The G+ GExperts community does no longer accept new members and new posts: use the English DelphiPraxis GExperts sub-forum (which has RSS)

Posted by jpluimers on 2019/01/31

For GExperts: go to http://en.delphipraxis.net/forum/31-gexperts/ with these RSS feed https://en.delphipraxis.net/forum/31-gexperts.xml/

Via [WayBack] NOTE: This community does no longer accept new members and new posts. Since Google will shut down Google+ in April 2019, I have moved to the GExperts su… – Jeroen Wiert Pluimers – Google+ and[WayBack] NOTE: This community does no longer accept new members and new posts. Since Google will shut down Google+ in April 2019, I have moved to the GExperts su… – Thomas Mueller (dummzeuch) – Google+

–jeroen

 

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

delphi – in Delphi7, How can I retrieve hard disk unique serial number? – Stack Overflow

Posted by jpluimers on 2019/01/30

From long time ago, but since I needed it in Delphi 2007 again: [WayBack] delphi – in Delphi7, How can I retrieve hard disk unique serial number? – Stack Overflow:

Following the links in the question comments Sertac posted, I came across this interesting C++ question, where Fredou answered with a nice link to a codeproject example showing how to do this in .NET, which in turn was based on a link to Borland C++ code and article.

The cool thing is that this C++ code works as a non-administrator user too!

Now you need someone to help you translate this C++ code to Delphi.

EditFound a Delphi unit that does this for you.

I wrote some sample use for it:

program DiskDriveSerialConsoleProject;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  hddinfo in 'hddinfo.pas';

const
  // Max number of drives assuming primary/secondary, master/slave topology
  MAX_IDE_DRIVES = 16;

procedure ReadPhysicalDriveInNTWithZeroRights ();
var
  DriveNumber: Byte;
  HDDInfo: THDDInfo;
begin
  HDDInfo := THDDInfo.Create();
  try
    for DriveNumber := 0 to MAX_IDE_DRIVES - 1 do
    try
      HDDInfo.DriveNumber := DriveNumber;
      if HDDInfo.IsInfoAvailable then
      begin
        Writeln('VendorId: ', HDDInfo.VendorId);
        Writeln('ProductId: ', HDDInfo.ProductId);
        Writeln('ProductRevision: ', HDDInfo.ProductRevision);
        Writeln('SerialNumber: ', HDDInfo.SerialNumber);
        Writeln('SerialNumberInt: ', HDDInfo.SerialNumberInt);
        Writeln('SerialNumberText: ', HDDInfo.SerialNumberText);
      end;
    except
      on E: Exception do
        Writeln(Format('DriveNumber %d, %s: %s', [DriveNumber, E.ClassName, E.Message]));
    end;
  finally
    HDDInfo.Free;
  end;
end;

begin
  ReadPhysicalDriveInNTWithZeroRights;
  Write('Press <Enter>');
  Readln;
end.

Unit from http://www.delphipraxis.net/564756-post28.html

// http://www.delphipraxis.net/564756-post28.html

unit hddinfo;

interface

uses Windows, SysUtils, Classes;

const
  IOCTL_STORAGE_QUERY_PROPERTY = $2D1400;

type
  THDDInfo = class (TObject)
  private
    FDriveNumber: Byte;
    FFileHandle: Cardinal;
    FInfoAvailable: Boolean;
    FProductRevision: string;
    FProductId: string;
    FSerialNumber: string;
    FVendorId: string;
    procedure ReadInfo;
    procedure SetDriveNumber(const Value: Byte);
  public
    constructor Create;
    property DriveNumber: Byte read FDriveNumber write SetDriveNumber;
    property VendorId: string read FVendorId;
    property ProductId: string read FProductId;
    property ProductRevision: string read FProductRevision;
    property SerialNumber: string read FSerialNumber;
    function SerialNumberInt: Cardinal;
    function SerialNumberText: string;
    function IsInfoAvailable: Boolean;
  end;

implementation

type
  STORAGE_PROPERTY_QUERY = packed record
    PropertyId: DWORD;
    QueryType: DWORD;
    AdditionalParameters: array[0..3] of Byte;
  end;

  STORAGE_DEVICE_DESCRIPTOR = packed record
    Version: ULONG;
    Size: ULONG;
    DeviceType: Byte;
    DeviceTypeModifier: Byte;
    RemovableMedia: Boolean;
    CommandQueueing: Boolean;
    VendorIdOffset: ULONG;
    ProductIdOffset: ULONG;
    ProductRevisionOffset: ULONG;
    SerialNumberOffset: ULONG;
    STORAGE_BUS_TYPE: DWORD;
    RawPropertiesLength: ULONG;
    RawDeviceProperties: array[0..511] of Byte;
  end;

function ByteToChar(const B: Byte): Char;
begin
  Result := Chr(B + $30)
end;

function SerialNumberToCardinal (SerNum: String): Cardinal;
begin
  HexToBin(PChar(SerNum), PChar(@Result), SizeOf(Cardinal));
end;

function SerialNumberToString(SerNum: String): String;
var
  I, StrLen: Integer;
  Pair: string;
  B: Byte;
  Ch: Char absolute B;

begin
  Result := '';
  StrLen := Length(SerNum);

  if Odd(StrLen) then Exit;

  I := 1;

  while I < StrLen do
  begin
    Pair := Copy (SerNum, I, 2);
    HexToBin(PChar(Pair), PChar(@B), 1);
    Result := Result + Chr(B);
    Inc(I, 2);
  end;

  I := 1;

  while I < Length(Result) do
  begin
    Ch := Result[I];
    Result[I] := Result[I + 1];
    Result[I + 1] := Ch;
    Inc(I, 2);
  end;
end;

constructor THddInfo.Create;
begin
  inherited;

  SetDriveNumber(0);
end;

function THDDInfo.IsInfoAvailable: Boolean;
begin
  Result := FInfoAvailable
end;

procedure THDDInfo.ReadInfo;
type
  PCharArray = ^TCharArray;
  TCharArray = array[0..32767] of Char;

var
  Returned: Cardinal;
  Status: LongBool;
  PropQuery: STORAGE_PROPERTY_QUERY;
  DeviceDescriptor: STORAGE_DEVICE_DESCRIPTOR;
  PCh: PChar;

begin
  FInfoAvailable := False;
  FProductRevision := '';
  FProductId := '';
  FSerialNumber := '';
  FVendorId := '';

  try
    FFileHandle := CreateFile(
                     PChar('\\.\PhysicalDrive' + ByteToChar(FDriveNumber)),
                     0,
                     FILE_SHARE_READ or FILE_SHARE_WRITE,
                     nil,
                     OPEN_EXISTING,
                     0,
                     0
                   );

    if FFileHandle = INVALID_HANDLE_VALUE then
      RaiseLastOSError;

    ZeroMemory(@PropQuery, SizeOf(PropQuery));
    ZeroMemory(@DeviceDescriptor, SizeOf(DeviceDescriptor));

    DeviceDescriptor.Size := SizeOf(DeviceDescriptor);

    Status := DeviceIoControl(
                FFileHandle,
                IOCTL_STORAGE_QUERY_PROPERTY,
                @PropQuery,
                SizeOf(PropQuery),
                @DeviceDescriptor,
                DeviceDescriptor.Size,
                Returned,
                nil
              );

    if not Status then
      RaiseLastOSError;

    if DeviceDescriptor.VendorIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.VendorIdOffset];
      FVendorId := PCh;
    end;

    if DeviceDescriptor.ProductIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductIdOffset];
      FProductId := PCh;
    end;

    if DeviceDescriptor.ProductRevisionOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductRevisionOffset];
      FProductRevision := PCh;
    end;

    if DeviceDescriptor.SerialNumberOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.SerialNumberOffset];
      FSerialNumber := PCh;
    end;

    FInfoAvailable := True;
  finally
    if FFileHandle <> INVALID_HANDLE_VALUE then
      CloseHandle(FFileHandle);
  end;
end;

function THDDInfo.SerialNumberInt: Cardinal;
begin
  Result := 0;
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToCardinal(FSerialNumber)
end;

function THDDInfo.SerialNumberText: string;
begin
  Result := '';
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToString(FSerialNumber)
end;

procedure THDDInfo.SetDriveNumber(const Value: Byte);
begin
  FDriveNumber := Value;
  ReadInfo;
end;

end.

EditRAID configurations require special provisions.

For instance, I got a RAID system with multiple RAID 5 array; only the first one displays, and it does not show the drive serial numbers, but the serial number of the RAID array:

VendorId: AMCC
ProductId: 9550SXU-16ML
ProductRevision: 3.08
SerialNumber: 006508296D6A2A00DE82
SerialNumberInt: 688416000

–jeroen

–jeroen

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

Need to revisit: Grep search crashes with `Invalid class typecast.` · Issue #1 · jpluimers/GExperts · GitHub

Posted by jpluimers on 2019/01/29

One day I need to resivit [WayBackGrep search crashes with Invalid class typecast. · Issue #1 · jpluimers/GExperts · GitHub.

The reason is that I want to be able to:

  • bind shortcut keys for deleting entries in the list of grep searches
  • performing a search while watching the results of a different one

Via [WayBack] Small initial fix for a race condition https://github.com/jpluimers/GExperts/issues/1 in commit https://github.com/jpluimers/GExperts/commit/bcc365911ab… – Jeroen Wiert Pluimers – Google+

–jeroen

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

docs.embarcadero.com unreachable – via Docs – EmbarcaderoMonitoring

Posted by jpluimers on 2019/01/29

One reason to monitor your infrastructure is to signal longer outages, or even better review past outages and prevent longer ones.

It is not the reason I created [Archive.is] EmbarcaderoMonitoring (it was to rule out problems between my systems and the Embarcadero sites), but it does help me gain insight in their infrastructure.

In this case, the [Archive.is] Docs – EmbarcaderoMonitoring shows that after months of OK operation, it suddenly started failing, at the same day parts of the other infrastructure also failed. It recovered, just like the other parts, but unlike the other parts, it was now down for almost a day when I took the screenshots:

Hopefully someone at Embarcadero realises the downtime too.

Read the rest of this entry »

Posted in Delphi, Development, Software Development | 1 Comment »

[RSP-10484] GetIt shouldn’t block the IDE – Embarcadero Technologies

Posted by jpluimers on 2019/01/24

I was amazed that this was marked as “Closed; won’t fix” as every respectable IDE I use but Delphi has a package manager that by now can download and update packages in the background without blocking the IDE [RSP-10484] GetIt shouldn’t block the IDE – Embarcadero Technologies.

–jeroen

Read the rest of this entry »

Posted in Delphi, Development, Software Development | 1 Comment »

Chuck Jazdzewski links (ex co-architect of the Delphi VCL architecture)

Posted by jpluimers on 2019/01/24

While doing some research, I bumped into Chuck Jazdzewski on Twitter: “Doing some historical posts to resurrect my blog. http://t.co/kSXy3ARUhR” so I decided to archive a few more links about Chuck because few of the early Delphi R&D team on-line history is slowly fading away into bit-heaven.

Back in the Delphi days, together with Anders Hejlsberg, Chuck Jazdzweski he has co-architected the the Delphi VCL component architecture and the foundations of the Delphi IDE.

Nowadays he’s working at Google and even speaking on conferences, grown far beyond his “be at conferences, but just chat with people” in the Delphi days: [WayBackChuck Jazdzewski – NG-Conf April 18–20th 2018 – The World’s Original Angular Conference

Chuck is a Software Engineer on the Angular team at Google. He is a programming language geek, UI framework and component library veteran, and has a passion for simplifying the task of programming. Before Google, he worked at Microsoft and Borland.

–jeroen

Posted in Delphi, Development, Software Development | 2 Comments »