@映射方法入口点时的运算符用法

时间:2017-09-06 14:34:04

标签: delphi dll

当动态加载DLL DoSomething是方法类型变量时,我们可以

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

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

这两个似乎在现代版本的Delphi中表现相同。我的问题是 - @运算符是否始终是可选的,如果没有,Delphi的版本是否可选?

文档指出@与例程(函数/过程)类型一起使用时,返回类型为Pointer的函数的入口点。当直接使用变量时,它自然具有声明的任何特定类型,但也返回该方法的入口点。 GetProcAddress返回Pointer,因此我假设在加载DLL时包含@的习惯来自这些不匹配类型不兼容的时间。是这种情况吗?

是否有任何合理的理由可以选择这些风格?

1 个答案:

答案 0 :(得分:5)

我不相信自德尔福的原始版本以来发生了任何变化。

GetProcAddress的官方标题翻译的返回类型为FARPROC,它是无类型Pointer类型的别名。因此,你可以在赋值语句的左侧放置几乎任何指针式的东西,因为当其中一个操作数为Pointer时,类型检查会被暂停。

另一方面,请考虑以下程序:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := Proc;
end.

无法编译:

  

E2010不兼容的类型:'指针'和'程序,无类型指针或无类型参数'

简单的解决方法是使用@运算符:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := @Proc;
end.

许多Delphi示例肯定会使用:

@Proc := GetProcAddress(...);

而不是

Proc := GetProcAddress(...);

我宁愿怀疑这里没有什么深刻的东西。仅仅是作者在第一篇关于该主题的在线文章中做出选择的案例,这些文章在历史上传播并没有充分的理由。这让我想起了测试HMODULE是否大于32的可怕Rosetta code example动态加载,这是一个错误的检查,可以在每周的Stack Overflow问题中看到!

您是否应该在这些情况下使用@?在我看来,你不应该。它并没有太大的区别,并且考虑到为什么要打扰不必要的标点符号?

还有一个其他方案,我知道您需要使用@的位置,在这种情况下,您确实需要@@。请考虑以下程序:

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  Proc: procedure;
  Ptr: Pointer;

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

<强>输出

00000000
00423EBC

第一个赋值获取Proc变量中保存的值,因为它是默认的初始化全局变量,为零。第二个赋值获取Proc变量的地址。为此你需要@@。需要这么大的间接性是非常不寻常的,但在编写与动态链接相关的代码时往往会突然出现。