考虑这个用于方法跟踪的典型代码(为了说明而简化):
type
IMethodTracer = interface
end;
TMethodTracer = class(TInterfacedObject, IMethodTracer)
private
FName: String;
FResultAddr: Pointer;
FResultType: PTypeInfo;
public
constructor Create(
const AName: String;
const AResultAddr: Pointer = nil;
const AResultType: PTypeInfo = nil);
destructor Destroy; override;
end;
constructor TMethodTracer.Create(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo);
begin
inherited Create();
FName := AName;
FResultAddr := AResultAddr;
FResultType := AResultType;
Writeln('Entering ' + FName);
end;
destructor TMethodTracer.Destroy;
var
lSuffix: String;
lResVal: TValue;
begin
lSuffix := '';
if FResultAddr <> nil then
begin
//there's probably a more straight-forward to doing this, without involving TValue:
TValue.Make(FResultAddr, FResultType, lResVal);
lSuffix := ' - Result = ' + lResVal.AsString;
end;
Writeln('Leaving ' + FName + lSuffix);
inherited Destroy;
end;
function TraceMethod(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo): IMethodTracer;
begin
Result := TMethodTracer.Create(AName, AResultAddr, AResultType);
end;
//////
function F1: String;
begin
TraceMethod('F1', @Result, TypeInfo(String));
Writeln('Doing some stuff...');
Result := 'Booyah!';
end;
F1();
这是按预期工作的。输出是:
我现在正在寻找一种方法来最小化调用
TraceMethod()
所需参数的数量,理想情况下允许我完全跳过与 Result
相关的参数。我自己没有汇编程序或堆栈布局的经验,但如果我没有弄错,根据我看到其他人所做的“魔术”判断,至少应该可以以某种方式获得隐含的魔术 Result
-变量的内存地址,不应该它?也可能有人可以从那里工作以获取其类型信息?当然,如果有可能甚至确定“周围”函数本身的名称,这将完全消除将参数传递给
TraceMethod
的需要......我使用的是 Delphi XE2,因此可以使用所有最近引入的语言/框架功能。
在任何人提到它之前:我的实际代码已经使用
CodeSite.EnterMethod
/ExitMethod
而不是 Writeln
-calls。我也知道这个简化的例子不能处理复杂的类型,也不执行任何错误处理。 最佳答案
最好的办法是直接传入 @Result
。如果不这样做,则无法保证 Result
甚至有地址。返回简单类型(如 Integer
和 Boolean
)的函数将结果放在 EAX 寄存器中。如果结果没有理由有地址,那么编译器就不会为其分配任何内存。使用表达式 @Result
强制编译器给它一个地址。
但是,仅仅知道地址不会让您获得返回类型。可能有一种方法可以通过 RTTI 发现它。它将涉及三个步骤:
Invoke
。)此外,您从调试信息中获得的方法名称不一定与 RTTI 名称匹配。您可以不尝试匹配名称,而是循环遍历所有类的方法,搜索其
CodeAddress
属性与调用者地址匹配的方法。不过,事实证明,确定如何获取调用者起始地址(而不是返回地址)比我预期的更难找到。 Handle
属性最终得到你想要的 PTypeInfo
值。 关于Delphi 汇编程序/RTTI 大师 : Can I obtain the memory address and type info of the implied Result variable in a function?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10819770/