Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ Operator usage when mapping method entry points

Tags:

dll

delphi

When dynamically loading a DLL where DoSomething is a method type variable we can do

 DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');

or

 @DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');

Both of these seem to behave identically in modern versions of Delphi. My question is - has the @ operator always been optional and, if not, in which version of Delphi did it become optional?

The documentation states that @, when used with routine (function/procedure) types returns the entry point of the function with type Pointer. When using the variable directly it naturally has whatever specific type it was declared with but also returns the entry point to the method. GetProcAddress returns a Pointer so I'm assuming that the habit of including @ when loading a DLL comes from a time when these mismatched types were not assignment compatible. Is this the case?

Are there any reasonable arguments to prefer either of these styles?

like image 580
J... Avatar asked Sep 06 '17 14:09

J...


1 Answers

I don't believe that anything has changed since the original versions of Delphi.

The official header translation for GetProcAddress has a return type of FARPROC which is an alias to the untyped Pointer type. Because of this, you can put pretty much anything pointer-esque on the left hand side of the assignment statement, because type checking is suspended when one of the operands is Pointer.

On the other hand, consider this program:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := Proc;
end.

This fails to compile with:

E2010 Incompatible types: 'Pointer' and 'procedure, untyped pointer or untyped parameter'

The simple fix is to use the @ operator:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := @Proc;
end.

It is certainly the case that many Delphi examples use:

@Proc := GetProcAddress(...);

rather than

Proc := GetProcAddress(...);

I rather suspect that there is nothing deep here. Just a case of a choice made by the author of one of the first online articles on the subject propagating throughout history with no good reason. Which reminds me of the terrible Rosetta code example of dynamic loading that tests whether an HMODULE is greater than 32, an erroneous check that can be seen in Stack Overflow questions on a weekly basis!

Should you use @ in these circumstances or not? In my view you should not. It doesn't make much difference, and given that why bother with a needless piece of punctuation?

There is one other scenario that I know where you need to use @, and in that case you actually need @@. Consider the following program:

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := @Proc;
  Writeln(Format('%p', [Ptr]));
  Ptr := @@Proc;
  Writeln(Format('%p', [Ptr]));
  Readln;
end.

Output

00000000
00423EBC

The first assignment gets the value held in the Proc variable, which because it is a default initialised global, is zero. The second assignment gets the address of the Proc variable. And for that you need @@. It's pretty unusual to need this much indirection, but it tends to crop up when writing code related to dynamic linking.

like image 191
David Heffernan Avatar answered Nov 02 '22 14:11

David Heffernan