Delphi:如何获取事件变量的地址?
如何获取保存事件处理程序的变量的地址?
例如,
TExample = class(TObject)
private
FOnChange: TNotifyEvent;
end;
我想要 FOnChange
私有成员、事件处理程序、变量的地址。
为什么?
我试图找出谁用垃圾覆盖我的 FOnChange
处理程序变量。
我正在单步执行代码:
if Assigned(FOnChange) then
FOnChange(Self);
没有分配任何事件处理程序,并且一段时间观察窗口中的FOnChange
变量为nil
:
@FOnChange: nil
Addr(FOnChange): nil
但稍后FOnChange
变量正在变成垃圾:
@FOnChange: $2C
Addr(FOnChange): $2C
所以我想在 CPU 窗口的数据窗格中观察 FOnChange
变量,以便我可以从以下位置观察它:
00410018 00000000
到
00410018 0000002C
except我不知道FOnChange
的地址;我刚刚凑了$410018
。
如何找到事件变量的地址?
我尝试过的事情
监视列表
OnChange: nil
@OnChange: nil
@@OnChange: Variable required
@FOnChange: nil
Assigned(OnChange): False
Assigned(FOnChange): False
@@FOnChange: $253B588
addr(addr(FOnChange)): $253B588
Alt+F5
- OnChange:
OnChange: TNotifyEvent $253B588
- FOnChange: 检查“FOnChange”时出错:表达式错误
- Self.FOnChange: 检查“Self.FOnChange”时出错:表达式错误
- @OnChange:
@OnChange:指针$253B588
- @@OnChange:检查“@@OnChange”时出错:表达式错误
- @FOnChange:
@FOnChange:指针 $253B588
- @@FOnChange:
@@FOnChange: ^未键入(无地址)
数据: @@FOnChange $253B588`
共识似乎在地址处0x253B588
。
然而,当我运行一些示例代码时:
MyControl1.OnChange := TheOnChangeHandler;
这变成了:
mov edx,[ebp+$08] ;move stack variable $08 into edx
mov [eax+$00000208],edx ;and then into offset $208 of my control
mov edx,[ebp+$0c] ;move stack variable $0c into edx
mov [eax+$0000020c],edx ;and then into offset $20c of my control
难怪我找不到 FOnChange
的地址,它是两个地址!
How do i get the address of the variable holding an event handler?
e.g.
TExample = class(TObject)
private
FOnChange: TNotifyEvent;
end;
i want the address of the FOnChange
private member, event handler, variable.
Why?
i'm trying to figure out who is overwriting my FOnChange
handler variable with junk.
i am stepping through code:
if Assigned(FOnChange) then
FOnChange(Self);
No event handler is ever assigned, and for a while the FOnChange
variable is nil
in the Watch Window:
@FOnChange: nil
Addr(FOnChange): nil
But later the FOnChange
variable is getting turned into junk:
@FOnChange: $2C
Addr(FOnChange): $2C
So i want to watch the FOnChange
variable in data pane of the CPU window, so that i can watch it to from:
00410018 00000000
to
00410018 0000002C
Except i don't know the address of FOnChange
; i just made up the $410018
.
How can i find the address of an event variable?
Things i've tried
Watch List
OnChange: nil
@OnChange: nil
@@OnChange: Variable required
@FOnChange: nil
Assigned(OnChange): False
Assigned(FOnChange): False
@@FOnChange: $253B588
addr(addr(FOnChange)): $253B588
Alt+F5
- OnChange:
OnChange: TNotifyEvent $253B588
- FOnChange: Error inspecting 'FOnChange': expression error
- Self.FOnChange: Error inspecting 'Self.FOnChange': expression error
- @OnChange:
@OnChange: Pointer $253B588
- @@OnChange: Error inspecting '@@OnChange': expression error
- @FOnChange:
@FOnChange: Pointer $253B588
- @@FOnChange:
@@FOnChange: ^Untyped (no address)
Data: @@FOnChange $253B588`
The concensus seems to be at address 0x253B588
.
Yet when i run some sample code:
MyControl1.OnChange := TheOnChangeHandler;
That turns into:
mov edx,[ebp+$08] ;move stack variable $08 into edx
mov [eax+$00000208],edx ;and then into offset $208 of my control
mov edx,[ebp+$0c] ;move stack variable $0c into edx
mov [eax+$0000020c],edx ;and then into offset $20c of my control
No wonder i can't find an address of FOnChange
, it's two addresses!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以通过调试检查器获取该地址。要获取字段的地址,请在更改发生之前的某个时刻在代码中放置一个断点,例如在调用构造函数之后。然后在调试检查器中打开您的对象。不知道如何在旧的 IDE 风格中获得它,但在 D2010 中,您可以通过“运行”->“检查...”菜单命令、“评估/修改”中的按钮或通过按键盘上的 ALT-F5 来获得它。 (小心不要按 ALT-F4!)
调试检查器将向您显示对象及其所有字段。双击其中一个字段,它将在新的调试检查器窗口中打开。在顶部类似编辑框的栏中将显示您的字段的地址。您可以使用它来设置内存断点以查找值发生变化的位置。
You can get the address through the Debug Inspector. To get the address of a field, put a breakpoint in your code at some point before the change has happened, for example right after you call the constructor. Then open your object in the Debug Inspector. Not sure how you get it in the old IDE style, but in D2010 you can get this from the Run->Inspect... menu command, from a button in Evaluate/Modify, or by hitting ALT-F5 on the keyboard. (Be careful you don't hit ALT-F4!)
The Debug Inspector will show you your object with all its fields. Double-click on one of the fields and it will open in a new Debug Inspector window. In the edit box-like bar at the top will be the address of your field. You can use this to set a memory breakpoint to find where the value changes.
在 Delphi 5 中不确定,但您应该能够在 AExample.FOnChange 上放置数据断点(或地址断点)。
每当值发生变化时它就会中断。
Not sure in Delphi 5 but you should be able to put a Data Breakpoint (or an Address Breakpoint) on your AExample.FOnChange.
It would break whenever the value changes.
由于您无法使用 François 建议的智能解决方案,因此是时候进行黑客攻击了!在任何可以放置制动点的地方,编写如下代码:
将制动点放在 X.OnChange := nil 行上;当调试器停在那里时,查看反汇编窗格,您将看到类似这样的内容:
您不关心编译器使用的寄存器,您关心 $288,即第一个 MOV 指令使用的偏移量。这是从“X”地址到 FOnChange 字段的偏移量。记下来。现在回到有问题的程序,在某处设置一个制动点,按 Alt+F5 调用调试检查器(如果没有出现空编辑框来输入查询,则按 Ctrl+N)并写入“Integer(我的示例变量)”;无论您得到什么,将您在上一步中记下的数字相加,您就获得了为 MyExampleVariable 实例归档的 FOnChange 地址,现在您可以设置地址制动点。
Since you can't use the smart solution suggested by François, it's time to get hacking! Somewhere, anywhere you can put a brakepoint, write code like this:
Put a brakepoint on the X.OnChange := nil line; When the debugger stops there, take a look at the disassembly pane, you'll see something like this:
You don't care about the registers used by the compiler, you care about the $288, the offset used for the first MOV instruction. That's the OFFSET from the "X" address to the FOnChange field. Note it down. Now go back to your buggy program, set a brakepoint somewhere, hit Alt+F5 to invoke the Debug Inspector (followed by Ctrl+N if you're not presented with an empty edit box to type your query in) and write "Integer(MyExampleVariable)"; Whatever you get, add up the number you noted down at the previous step and you've got the address of the FOnChange filed for the MyExampleVariable instance, you can now set a address brakepoint.
我不知道它们是否存在于 Delphi 5 中,但类型 TMethod函数 MethodAddress 应该会有所帮助。
I don't know if they exists in Delphi 5, but the type TMethod and the function MethodAddress should be helpful.
我可以回答这个问题——你是!或者您正在查看未正确创建的错误实例?没有正确引用?会是这样的。 Delphi 调试器擅长使一些不存在的东西看起来像它存在的那样,直到……
退后一步,尝试只见木头而不是树。我去过你很多次,你可能找错了树(抱歉,双关语),很快就会给自己起各种各样的名字:)
I can answer that bit - you are! Or you are looking at the wrong instance that is not created correctly? not referenced correctly? It will be something like that. The Delphi debugger is good at making some thing that does not exist look like it does, until...
Step back a bit, try and see the wood not the trees. I have been where you are many times, you are probably barking up the wrong tree (sorry pun intended) and shortly will call yourself all sorts of names :)