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,839 other subscribers

Archive for the ‘Delphi’ Category

Delphi: creating copies of installed components to repositories for portability across use cases

Posted by jpluimers on 2021/05/25

Often it is useful to have 3rd party components part of a repository so it is easier to increase portability.

For instance when you want to include or exclude some of them in certain projects by installing/deinstalling them to/from the IDE.

This can be useful for cases where components bite each other, or you want to vary the components in use by version without spinning up new VMs (Delphi registration counts can be a pain for new VMs; you need to be very careful as you can never decrease your registration count).

I usually do this by having 3 batch files:

  1. copy from an installed 3rd party library to a repository in a relative way
  2. register any needed relative files into the IDE
  3. unregister any needed relative files in from the IDE

If successful, I can uninstall the library.

I especially take this approach with 3rd party libraries that stuff to global places (inside the Delphi installation directory, or worse, inside the Windows directories).

That way, I can try to ensure that compilation of running only uses files from the repository, making my options for portability larger.

Examples I did this for are for instance QuickReports and ODAC.

Some bits are tricky to get right, especially loading dependencies.

It helps to understand that for executable files Windows also searches for dependencies in the directory of the executable file.

For libraries, that does not happen. Which means that if a BPL has dependencies, they either have to be explicitly loaded before (for instance by being in the Known Packages registry entries), or on the search PATH.

Delphi has the %BDSCOMMONDIR% directory in the search PATH. It usually points to “%PUBLIC%\Documents\Embarcadero\Studio\%ProductVersion%\Bpl” (where ProductVersion=19.0 for Delphi 10.2 Tokyo).

There might be a away around this using manifests, but this means modifying the BPL files, which is beyond the point of having these copy scripts.

More on those environment variables in a later blog post.

Related:

–jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Delphi 10.2 Tokyo (Godzilla), Development, Event, Software Development | Leave a Comment »

I wanted to know the loaded DLLs in a process like Process Explorer shows, but from the console: Sysinternals ListDLLs to the rescue

Posted by jpluimers on 2021/05/20

In Windows, historically most people approach investigation GUI first. Having turned 50 a while ago, I am no exception.

My real roots however are on the command-line and scripting: roughly 1980s Apple DOS, CP/M, SunOS (yay sh Bourne shell!), MS-DOS, 4DOS, and VAX/VMS (yay DCL shell!), from the 1990s on, some Solaris, a little bit of AIX, HP-UX and quite a bit of Linux, MacOS (né OS/XMac OS),  and some BSD descendants derivatives (SunOS, AIX and MacOS are based on the Berkeley Software Distribution), and this century a more growing amount of PowerShell).

So I was glad to find out the makers of Process Explorer also made [WayBack] ListDLLs – Windows Sysinternals | Microsoft Docs (via windows get dlls loaded in process – Google Search)

List all the DLLs that are currently loaded, including where they are loaded and their version numbers.

ListDLLs is a utility that reports the DLLs loaded into processes. You can use it to list all DLLs loaded into all processes, into a specific process, or to list the processes that have a particular DLL loaded. ListDLLs can also display full version information for DLLs, including their digital signature, and can be used to scan processes for unsigned DLLs.

Usage

listdlls [-r] [-v | -u] [processname|pid]
listdlls [-r] [-v] [-d dllname]

Parameter Description
processname Dump DLLs loaded by process (partial name accepted).
pid Dump DLLs associated with the specified process id.
dllname Show only processes that have loaded the specified DLL.
-r Flag DLLs that relocated because they are not loaded at their base address.
-u Only list unsigned DLLs.
-v Show DLL version information.

Download: [WayBack] ListDlls.zip.

Now it is much easier to generate a draft deploy list of DLLs (and for Delphi: BPLs) based on a process running on a development machine.

Example output (the -r flags relocation warnings; the first part is the [WayBack] shim that Chocolatey created around the second which is from SysInternals):

Read the rest of this entry »

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

ODAC default install paths for Delphi 10.2 Tokyo

Posted by jpluimers on 2021/05/20

A few notes on the ODAC install:

  1. Download of x.x.x is at [WayBack] www.devart.com/odac/odac25.exe via [WayBack] www.devart.com/odac/download.html

    The 25 is DllSuffix minus trailing zero for Delphi 10.2 Tokyo, or the “real” Delphi version; see Delphi version info table.

  2. It requires local administrator access when installing
  3. When installing it installs the Demos using the %USERPROFILE% directory of the local administrator user that installed it: %USERPROFILE%\Documents\Devart\ODAC for RAD Studio 10.2\Demos
    • You can replace this directory at install time; I prefer %PUBLIC%\Documents\Devart\ODAC for RAD Studio 10.2\Demos
  4. The rest of the files are in the global directory %ProgramFiles(x86)%\Devart\ODAC for RAD Studio 10.2
  5. If your Delphi license does not include certain targets (like Linux) they do not get installed at all.

–jeroen

 

 

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

Much Turbo Pascal history (via What is a Delphi DCU file? – Stack Overflow)

Posted by jpluimers on 2021/05/19

Editing [WayBack] What is a Delphi DCU file? – Stack Overflow for more historic correctness and adding links prompted me to archive some older material and search for some more, basically because while historically very relevant, link rot makes a lot of that stuff harder and harder to find.

The legendary full page colour advert published in the 12th 1983 issue of Byte Magazine on page 456 is at the bottom of this post (Many BYTE magaine issues have been archived at https://archive.org/details/byte-magazine).

The smaller version below is from WayBack: Sip from the Firehose : November 2008 marks the 25th anniversary of Turbo Pascal v1.0! (this article is not available on the Embarcadero or Idera site any more).

I also included more adverts in reverse chronological order at the end:

The last two via [WayBack] saundby.com: Software for the Ampro Little Board.

--jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, CP/M, Delphi, Development, Event, History, MS-DOS, Pascal, Power User, Software Development, Turbo Pascal, UCSD Pascal, Z80 | Leave a Comment »

SQL Server: RowVersion is not the same format as BigInt

Posted by jpluimers on 2021/05/18

A while ago, I needed to get RowVersion binary data out of SQL Server. People around me told me it is stored as BigInt.

I luckily bumped into [WayBack] sql server – Cast rowversion to bigint – Stack Overflow.

That post explains RowVersion is not stored as BigInt. Both RowVersion and BigInt take up 8 bytes of storage, but RowVersion is big-endian and unsigned, whereas BigInt is little-endian and signed.

A few quotes from it:

In my C# program I don’t want to work with byte array, therefore I cast rowversion data type to bigint:

SELECT CAST([version] AS BIGINT) FROM [dbo].[mytable]

So I receive a number instead of byte array. Is this conversion always successful and are there any possible problems with it? If so, in which data type should I cast rowversion instead?

and

You can convert in C# also, but if you want to compare them you should be aware that rowversion is apparently stored big-endian, so you need to do something like:

byte[] timestampByteArray = ... // from datareader/linq2sql etc...
var timestampInt = BitConverter.ToInt64(timestampByteArray, 0);
timestampInt = IPAddress.NetworkToHostOrder(timestampInt);

It’d probably be more correct to convert it as ToUInt64, but then you’d have to write your own endian conversion as there’s no overload on NetworkToHostOrder that takes uint64. Or just borrow one from Jon Skeet (search page for ‘endian’).

Code: [WayBack] Jon Skeet: Miscellaneous Utility Library

Related:

--jeroen

Posted in .NET, Database Development, Delphi, Development, Jon Skeet, Software Development, SQL Server | Leave a Comment »

JclRTTI: type has not type info

Posted by jpluimers on 2021/05/18

[WayBack] Any idea why we get this error, or even better, how to fix it : [dcc32 Error] JclRTTI.pas(663): E2134 Type ‘<void>’ has no type info We compile same c… – Tommi Prami – Google+

So the JCL needs to have the compiler setting Emit runtime type information set to true (which is the default for projects, but can be turned off).

Thanks Stefan Glienke for reporting the fix.

–jeroen

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

Delphi: EInvalidOp exception, might just mean you have a use-after free scenario, or an out-of-bounds value

Posted by jpluimers on 2021/05/13

Quite some time ago, I was researching spurious exceptions in a Delphi application, then finally replicated them in a unit test suite.

One of them was occurring almost all of the time: EInvalidOp.

It is one of the floating point exceptions (incidentally exampled at [WayBack] Exceptions: Declaring Exception Types) all inheriting from the [WayBack] EMathError Class:

EMathError is the base class for floating-point math exception classes. EMathError itself is never raised.

The following exceptions descend from EMathError:

Meaning
Parameter out of range
Processor encountered an undefined instruction
Floating-point operation produced result too large to store
Floating-point operation produced result with no precision
Attempt to divide by zero

Run-time exception information is saved in fields provided by [WayBack] EExternal.

Use-after-free

In my first case (which I described in delphi – Invalid floating point operation calling Trunc()), not all input scenarios had been tested in a certain scenario. In a production environment, one of the inputs was really high.

In a later case, the actual cause was not a floating point problem at all, but a use-after-free scenario that overwrite a floating point value with something not so compatible also causing a simple Trunc statement to fail in the same way.

In that case, the production data could never reach the big numbers that failed, so no new tests were needed.

–jeroen

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

FastMM4: turn warnings W1047 and W1048 off

Posted by jpluimers on 2021/05/12

(Tagged FastMM4 as that’s the first code I saw these warnings to be turned off)

Delphi 7 introduced introduced warnings for unsafe constructs like W1047 and W1048 so you could prepare your code for the first Delphi .NET compilers .

The oldest online documentation on this is in Delphi 2007:

After Delphi 2007, the .NET compiler got shelved, but the errors and warning stayed as they serve a good purpose for native code as well.

Delphi 2007 did not document any of the other directives.

Unlike the D2007 documentation, however, the UNSAFECODE should be written UNSAFE_CODE as with using {$WARN UNSAFECODE ON}, you will get this error:

E1030 Invalid compiler directive: 'UNSAFECODE'

Looking at the library code and example code that ships with Delphi, these are the valid $WARN compiler directives having to do with UNSAFE:

  • UNSAFE_CAST (since Delphi 7, but only used in Vcl.WinXPanels.pas introduced in Delphi 10.2 Tokyo and up)
  • UNSAFE_CODE (since Delphi 7, but still documented as UNSAFECODE)
  • UNSAFE_TYPE (since Delphi 7)
  • UNSAFE_VOID_POINTER (since Delphi XE3, as precursor to the NEXTGEN compilers)

The ultimate source for these is the file DCCStrs.pas that has shipped since Delphi 2009: [WayBack] warnings – Identifiers for Delphi’s $WARN compiler directive – Stack Overflow.

A problem is that current documentation still lists the wrong name in many places:

This one finally got it right: [WayBack] Warning messages (Delphi) – RAD Studio

UNSAFE_TYPE W1046
UNSAFE_CODE W1047
UNSAFE_CAST W1048

Note it also documented UNSAFE_VOID_POINTER:

UNSAFE_VOID_POINTER W1070

[WayBack] W1070 Use of untype pointer can disrupt instance reference counts (Delphi) – RAD Studio

And these warning messages still do not contain the directives, but do explain the underlying code construct better:

You have to use these directives:

// Get rid of "W1047 Unsafe code 'ASM'", "W1047 Unsafe code '^ operator'", "W1047 Unsafe code '@ operator'" and similar

{$WARN UNSAFE_CODE OFF}

// Get rid of "W1048 Unsafe typecast of 'TFreedObject' to 'PByte'" and similar

{$WARN UNSAFE_CAST OFF}

Back in the days, some people were not amused and disabled the warnings, for instance in [Archive.is] Re: How can I eliminate these warnings in Delphi 7 which did not appear in Delphi 5. – Google Groups:

Dennis Passmore:
I have one include file that I usually include in all projects as follows—– WarningsOff.inc —————-
{$IFDEF CONDITIONALEXPRESSIONS}
  {$IF CompilerVersion >= 14}
{$WARN SYMBOL_PLATFORM OFF}
{$WARN SYMBOL_DEPRECATED OFF}
{$WARN SYMBOL_LIBRARY OFF}
{$WARN UNIT_DEPRECATED OFF}
{$WARN UNIT_LIBRARY OFF}
{$WARN UNIT_PLATFORM OFF}

{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}

  {$IFEND}
{$ENDIF}
———————and it gets ride of all unwanted warnings in the IDE or even DCC32.exe when compiling the project
from the command line.

I just add the following line to the project .dpr file and do not worry about the rest.

{$I WarningsOff.inc}

Dennis Passmore

“If you cannot conceive the idea you
will never achieve the desired results”

I disagree with such an approach, as those warnings have their purpose.

Knowing how to selectively disable/enable them however, is important.

–jeroen

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

file – String format procedure similar to writeln – Stack Overflow

Posted by jpluimers on 2021/05/11

Cool Format feature from [WayBack] file – String format procedure similar to writeln – Stack Overflow:

The cool thing about using Format is that you use for Format Strings not only to parameterize things like width and precision inside that Format String, but also as parameters like you normally would provide values.

You can get very close to using a width of 8 and a precision of 2, like the example in your question.

For instance, to quote the documentation:

Format ('%*.*f', [8, 2, 123.456]);

is equivalent to:

Format ('%8.2f', [123.456]);

That is a much overlooked feature of Format and Format Strings.

Edit 20250910:

This was part of my answer¹ there to mimic WriteLn formatting behaviour which was not even documented at the now deleted [Wayback/Archive] Standard Routines and I/O.

Normally deleted information like above results in worse information at their current documentation site.

This time however was an exception: the current documentation is better².

¹ the start of my answer:

Read the rest of this entry »

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

Delphi: types you cannot deprecate

Posted by jpluimers on 2021/05/06

Deprecating all types in a unit besides deprecating the unit itself will cause a hint and warning storm. Especially in projects having a lot of hints and warnings (taking over maintenance of a legacy project comes to mind) this can be very helpful to spot these locations inside many files where some obscure unmaintained unit like GIFImage.pas is still used.

[WayBack] TGIFImage for Delphi | MelanderBlog got donated to (then CodeGear, now Embarcadero) for inclusion in Delphi 2007. It was, as GifImg unit, but only documented since the [WayBack] Delphi 2009 GIFImg Namespace). For more information: delphi 2007 gifimg unit – Google Search

Delphi allows you to deprecate a lot of types, but you cannot deprecate these forms:

  • array [...] of TSomeType
  • ^TSomeType
  • class of TSomeType
  • procedure(...) ...
  • function(...): TSomeType ...
  • reference to procedure(...) ...
  • reference to function(...): TSomeType ...

Putting a deprecated 'use SomeUnit.TSomeOtherType' will fail with:

  • either a compiler error  pair
    • E2029 ';' expected but identifier 'deprecated' found“.
    • E2029 '=' expected but string constant found
  • a compiler error
    • E1030 Invalid compiler directive: 'DEPRECATED'

You can enumerate these kinds of types:

  • enumerations
  • records
  • classes, but only a full class declaration, so
    • not the class forward declaration like TMyClass = class
    • not a shortened class declaration like TMyException = class(Exception), this has to be the full TMyException = class(Exception) end deprecated 'reason';
  • methods only after the last separating ; of the method (so the virtual form is like procedure Name(...); virtual; deprecated 'use another method';)
  • named constants
  • global variables

The last few are not technically types, but included for completeness.

–jeroen

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