当动态加载DLL DoSomething
是方法类型变量时,我们可以
DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
或
@DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
这两个似乎在现代版本的Delphi中表现相同。我的问题是 - @
运算符是否始终是可选的,如果没有,Delphi的版本是否可选?
文档指出@
与例程(函数/过程)类型一起使用时,返回类型为Pointer
的函数的入口点。当直接使用变量时,它自然具有声明的任何特定类型,但也返回该方法的入口点。 GetProcAddress
返回Pointer
,因此我假设在加载DLL时包含@
的习惯来自这些不匹配类型不兼容的时间。是这种情况吗?
是否有任何合理的理由可以选择这些风格?
答案 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
变量的地址。为此你需要@@
。需要这么大的间接性是非常不寻常的,但在编写与动态链接相关的代码时往往会突然出现。