【发布时间】:2020-06-10 05:48:52
【问题描述】:
几年前,我将一个旧的 unix 应用程序移植到 Delphi 5。对于链表迭代,它使用通过地址传递给全局“迭代器”函数的本地过程。
下面是一个简化的例子:
type TPerformProc = procedure;
procedure Perform(proc:TPerformProc);
begin
proc;
end;
procedure Test;
var loc_var:integer;
procedure loc_proc;
begin
loc_var:=loc_var+10;
end;
begin
loc_var:=0;
writeln('loc var: ',loc_var);
Perform(addr(loc_proc));
writeln('loc var: ',loc_var);
writeln('-----');
end;
示例程序在 Delphi 中崩溃,但在 unix 上运行良好。
在一些帮助下,我已经能够让它像这样工作:
type TPerformProc = procedure;
var loc_bp:integer;
procedure Perform(proc:TPerformProc);
begin
asm
push loc_bp
end;
proc;
asm
pop eax
end;
end;
procedure Test;
var loc_var:integer;
procedure loc_proc;
begin
loc_var:=loc_var+10;
end;
begin
loc_var:=0;
writeln('loc var: ',loc_var);
asm
mov loc_bp,ebp
end;
Perform(addr(loc_proc));
writeln('loc var: ',loc_var);
writeln('-----');
end;
为了解决这个问题,我存储了对本地过程的堆栈帧的引用,然后我调用了本地过程。
我很清楚,上面的解决方案不是一个正确的解决方案,而是一个 hack,我知道新的 Delphi 版本可能会以不同的方式处理本地程序并破坏 hack。幸运的是,这部分 Delphi 保持不变,即使在最新的德里,代码也能正常工作。
但是,我想将应用程序编译为 64 位应用程序,并且该 hack 不再有效。到目前为止,我无法找到类似的解决方案,但对于 64 位。这里有人可以帮忙吗?
谢谢。
【问题讨论】:
-
您应该使用匿名方法来实现它。那么就不需要破解了。
-
如果你跳过
Addr,你会得到一个很好的错误信息。我的 10.3 编译器显示“E2094 本地过程/函数 'loc_proc' 分配给过程变量”。正如@DavidHeffernan 建议的那样,最好的最小努力解决方案可能是使用匿名方法。 -
伙计们,我知道这不受官方支持,但我正在寻找如何让它工作的技巧。我同意,匿名方法是一种可能的解决方案(但是在 Delphi 5 时代它不是一个选项),但是经常使用本地过程进行回调(1200 多次),所以你可以想象多长时间需要将其转换为匿名方法。
-
@David David,我刚刚注意到您关闭了这个问题并将其标记为另一个问题的副本。这不正确,请重新打开它。我很清楚这样一个事实,即官方不支持我的要求 - 但是有一个不受支持的 32 位解决方案(参见我的示例),也许有一个 64 位解决方案 - 这实际上是什么我在找
-
会有一个 hack,您需要检查 asm 以查看这些方法所需的隐藏额外参数是如何在 x64 中传递的。不会很难。困难的是转换你做这个黑客的所有地方。正确的解决方案是使用匿名方法,考虑到您目前采用的方法是非常愚蠢的。
标签: delphi callback 64-bit 32bit-64bit