更换功能单元 [英] Replace function units
问题描述
创建具有相同接口的SysUtils单元不被欣赏通过编译器。
我在想的是在运行时挂钩我的模拟功能。这是可能现在吗?
其他任何建议?
请问,
Peter
在运行时更换功能很困难,但通常在技术上是可能的。 所有您需要做的是:
- 拿出有问题的功能的地址
- 拆卸前5个字节(以检查RET指令 - 非常小的例程可能会与另一个例程相抵触,阻止您更换)
- 更改其页面保护(使用
VirtualProtect
)可写入 - 使用JMP rel32指令重写前5个字节(即E9
) - 实现您的版本功能正常,确保它具有与您嘲笑的功能相同的参数和调用约定
更简单的方法要链接到不同版本的SysUtils.pas。这将需要您重新编译依赖于SysUtils.pas的RTL和VCL中的所有单元,但它可能比上述功能文件格式更容易。
最简单的方法是语言级别,您不必直接依赖于SysUtils(因此可以在较高级别切换),或者您修改使用
声明有条件地引用不同的单位。
I am writing a unit test infrastructure for a large Delphi code base. I would like to link calls to pure functions in SysUtils.FileExists for example to a "MockSysUtils.FileExists" instead.
Creating a SysUtils unit with the same interface is not appreciated by the compiler.
What I am thinking of is to hook in my mock function at runtime. Is this possible nowadays?
Any other suggestions?
Regards,
Peter
Replacing a function at runtime is difficult but usually technically possible. "All" you need to do is:
- take the address of the function in question
- disassemble the first 5 bytes or so (to check for a RET instruction - very small routines may abut another routine, preventing you from replacing it)
- change its page protection (with
VirtualProtect
) to be writable - rewrite the first 5 bytes with a JMP rel32 instruction (i.e. E9 <offset-to-your-func>)
- implement your version function as normal, making sure it has the same arguments and calling convention as the function you are mocking
An easier approach would be to link against a different version of SysUtils.pas. That will require you to also recompile all the units in the RTL and VCL that depend on SysUtils.pas, but it is likely quite a bit easier than the function intrumentation approach described above.
The easiest approach is the language-level one, where either you don't directly rely on SysUtils at all (and so can switch at a higher level), or you modify the uses
declaration to conditionally refer to a different unit.
这篇关于更换功能单元的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!