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 ‘Conferences’ Category

Delphi: some notes on HModule while tracking down an access violation in TRegGroups.UnregisterModuleClasses

Posted by jpluimers on 2021/06/08

Too bad the whole mechanism involving TRegGroups.UnregisterModuleClasses is not documented anywhere

It is the underlying storage to support TClassFinder, which was introduced in Delphi 6, documented on-line in Delphi 2007, documented slightly in Delphi 2009, and since Delphi 2010 only one line of documentation was added (including the unchanged “instatiated”):

  • Delphi 2007: [WayBack] TClassFinder Class

    This is class Classes.TClassFinder.

  • Delphi 2009:[WayBack] TClassFinder Class

    The TClassFinder allows the list of registered persistent classes to be retrieved. Objects instatiated from persistent classes are those that can be stored (serialised) beyond the operation of the current application.

  • Delphi 2010:[WayBack] Classes.TClassFinder – RAD Studio VCL Reference

    TClassFinder allows registered persistent classes to be retrieved.

    The TClassFinder allows the list of registered persistent classes to be retrieved. Objects instatiated from persistent classes are those that can be stored (serialised) beyond the operation of the current application.

Back to TRegGroups.UnregisterModuleClasses: it takes a HMODULE parameter and ultimately gets called through the (since Delphi 2007) on-line documented [WayBack] Classes.UnRegisterModuleClasses Function

procedure UnRegisterModuleClasses(Module: HMODULE);

Call UnRegisterModuleClasses to unregister all object classes that were registered by the module with the handle specified by the Module parameter. When a class is unregistered, it can’t be loaded or saved by the component streaming system.

After unregistering a class, its name can be reused to register another object class.

To get more context about the access violation, I used both the stack trace and a debugging watch for GetModuleName(Module) (using the [WayBack] SysUtils.GetModuleName Function).

In order to see which classes were registered by what module, I set a breakpoint at in TRegGroup.AddClass (which can be called through various code paths):

procedure TRegGroup.AddClass(AClass: TPersistentClass);
begin
  FGroupClasses.Add(AClass);
end;

HModule

That gave me the class, but I also needed the HModule for a class, so I did a windows get module of currently executing code – Google Search, giving me these links, all C/C++ related:

Here you already see some confusion: there is HINSTANCE and HMODULE. That’s a historic thing, as described by Raymond Chen in [WayBack] What is the difference between HINSTANCE and HMODULE? | The Old New Thing:

They mean the same thing today, but at one time they were quite different.
It all comes from 16-bit Windows.
In those days, a “module” represented a file on disk that had been loaded into memory, and the module “handle” was a handle to a data structure that described the parts of the file, where they come from, and where they had been loaded into memory (if at all). On the other hand an “instance” represented a “set of variables”.
One analogy that might (or might not) make sense is that a “module” is like the code for a C++ class – it describes how to construct an object, it implements the methods, it describes how the objects of the class behave. On the other hand, an “instance” is like a C++ object that belongs to that class – it describes the state of a particular instance of that object.
In C# terms, a “module” is like a “type” and an instance is like an “object”. (Except that modules don’t have things like “static members”, but it was a weak analogy anyway.)

GetModuleName

Searching for delphi “__ImageBase” – Google Search then got me [WayBack] c++ – Get DLL path at runtime – Stack Overflow with a nice Delphi related answer by [WayBack] Ian Boyd:

For Delphi users:

SysUtils.GetModuleName(hInstance);              //Works; hInstance is a special global variable
SysUtils.GetModuleName(0);                      //Fails; returns the name of the host exe process
SysUtils.GetModuleName(GetModuleFilename(nil)); //Fails; returns the name of the host exe process

In case your Delphi doesn’t have SysUtils.GetModuleName, it is declared as:

...

This reassured my use of [WayBack] SysUtils.GetModuleName code was OK:

function GetModuleName(Module: HMODULE): string; 
var
  ModName: array[0..MAX_PATH] of Char; 
begin
  SetString(Result, ModName, GetModuleFileName(Module, ModName, Length(ModName))); 
end;

HInstance in Delphi

The example from Ian Boyd also brought back memories from long ago about the [WayBack] HInstance Variable – Delphi in a Nutshell [Book]:

Read the rest of this entry »

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

VMware ESXi: VMware Tools Installed but not running

Posted by jpluimers on 2021/06/04

Sometimes you get this situation on a Windows VM, usually after a reboot but not logging on:

Networking No network information
VMware Tools Installed but not running

“Windows” “VMware Tools” “Installed but not running” – Google Search mostly gives results about the VMware tools installation ISO being malformed, the registry not being correct, or having Linux as guest:

In practice though, there is a really good change that your default power settings allow Windows to go to sleep after some time of activity. The Windows VM then really sleeps, including services and network adapters. Then VMware ESXi thinks the machine has no VMware tools running:

I have noticed this on ESXi 6.5 and 6.7 with both Windows 7 and Windows 10. It is broader though, as others have seen this in ESXi 5.x as well: [WayBack] VMware Communities : All Content – VMware ESXi 5.

Verifying sleep is enabled

This little trick shows you the various possible sleep states:

C:\>powercfg /availablesleepstates
The following sleep states are available on this system: Standby ( S1 )
The following sleep states are not available on this system:
Standby (S2)
        The system firmware does not support this standby state.
Standby (S3)
        The system firmware does not support this standby state.
Hibernate
        Hibernation has not been enabled.
Hybrid Sleep

Disabling sleep

If you search for “sleep” in the [WayBack] Powercfg command-line options | Microsoft Docs, you have a hard time finding these:

/change or /X

Modifies a setting value in the current power scheme.

Syntax:

/change  setting  value

Arguments:

setting
Specifies one of the following options:

  • monitor-timeout-ac
  • monitor-timeout-dc
  • disk-timeout-ac
  • disk-timeout-dc
  • standby-timeout-ac
  • standby-timeout-dc
  • hibernate-timeout-ac
  • hibernate-timeout-dc
value
Specifies the new value, in minutes.

Examples:

powercfg /change monitor-timeout-ac 5

in order to disable sleep, you hav disable the standby timeouts (suffix -ac means “Plugged in” and -d means “On battery”) by setting their values to 0 (zero) minutes as UAC elevated Administrator:

powercfg /change standby-timeout-ac 0
powercfg /change standby-timeout-dc 0

This is far less than in WayBack – FutureMark forums – windows 7 – how do i disable SLEEP mode via command line ? (via [WayBack] Disable Sleep mode using powercfg – it.megocollector.com), but this is really all you need, as it correctly disables sleeping:

Later I found that [WayBack] windows 7 – How to disable sleep mode via CMD? – Super User also shows this shorter solution.

Note you need to run those on as UAC elevated user, which you can check for using the net session trick in [WayBack] windows – Batch script: how to check for admin rights – Stack Overflow.

–jeroen

Posted in Conference Topics, Conferences, ESXi6.5, ESXi6.7, Event, Power User, Virtualization, VMware, VMware ESXi | Leave a Comment »

Delphi: Passing build variables to batch files; I think the easiest is to use environment variables

Posted by jpluimers on 2021/06/02

A long time ago, I wrote about Delphi prebuild/prelink/postbuild events.

In practice, especially that you cannot inherit build events, then add new ones (), it is convenient to put all you need in a script, for instance a batch file.

Passing parameters to that script, then in my experience, is easiest to do as environment variables.

That way you can do this in a script:

> %temp%\build.txt echo ~dp0=%~dp0
>> %temp%\build.txt echo $(BDS)=%BDS%
>> %temp%\build.txt echo $(INPUTDIR)=%INPUTDIR%
>> %temp%\build.txt echo $(PROJECTDIR)=%PROJECTDIR%
>> %temp%\build.txt echo $(OUTPUTDIR)=%OUTPUTDIR%
>> %temp%\build.txt echo $(Platform)=%Platform%

if "%OUTPUTDIR:~0,2%"==".." set OUTPUTDIR=%INPUTDIR%%OUTPUTDIR%
>> %temp%\build.txt echo $(OUTPUTDIR)=%OUTPUTDIR%

Passing the parameters and calling the script results in this build event contents:

set Platform=$(Platform)
set INPUTDIR=$(INPUTDIR)
set PROJECTDIR=$(PROJECTDIR)
set OUTPUTDIR=$(OUTPUTDIR)
call ..\post-build-event.bat

The IDE then shows this fragment in the project output:

Target PostBuildEvent:
    set Platform=Win32&&set INPUTDIR=D:\Versioned\TestRepostitory\Test Project With Spaces\&&set PROJECTDIR=D:\Versioned\TestRepostitory\Test Project With Spaces&&set OUTPUTDIR=..\EXE Output Directory With Spaces\&&call ..\post-build-event.bat

The above batch file also shows things:

  1. how to handle relative directories in the OUTPUTDIR build parameter: check if the first two characters are .. (trick via [WayBack] Check if Batch variable starts with “…” – Stack Overflow).
  2. spaces are handled fine without any need to double quote the set assignments
  3. build-event lines are concatenated using the && success operator
  4. Parameters INPUTDIR and OUTPUTDIR end with a backslash, but PROJECTDIR does not (Delphi prebuild/prelink/postbuild events explains more about the parameters).

Note:

  • environment variable BDS does not end in a backslash
  • expansion %~dp0 does end in a backslash

With this trick now you can copy BPL files for the right platform:

xcopy /y "%BDS%\Redist\%Platform%\rtl250.bpl" "%OUTPUTDIR%"

Note that the LibSuffix (with value 250 for Delphi 10.2 Tokyo) is not available as environment variable, nor build parameter. The environment variable ProductVersion however (with value 19.0 for Delphi 10.2 Tokyo) is. So technically, you could make a mapping.

–jeroen

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

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 »

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 »

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 »