代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

Delphi:如何获取事件变量的地址?

  •  3
  • Ian Boyd  · 技术社区  · 14 年前

    如何获取保存事件处理程序的变量的地址?

    例如

    TExample = class(TObject)
    private
        FOnChange: TNotifyEvent;
    end;
    

    我想要 地址 FOnChange 私有成员,事件处理程序,变量。


    为什么?

    我想知道是谁在重写我的 换热器 处理程序变量带有垃圾。

    我正在逐步通过代码:

    if Assigned(FOnChange) then
        FOnChange(Self);
    

    从未分配任何事件处理程序,并且 一会儿 这个 换热器 变量是 nil 在监视窗口中:

    @FOnChange: nil
    Addr(FOnChange): nil
    

    但后来 换热器 变量正在变成垃圾:

    @FOnChange: $2C
    Addr(FOnChange): $2C
    

    所以我想看 换热器 CPU窗口的数据窗格中的变量,以便我可以从以下位置监视它:

    00410018 00000000
    

    00410018 0000002C
    

    除了我没有 知道 地址 换热器 ;我刚刚弥补了 $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: Pointer $253B588
    • @改变 :检查“@@onchange”时出错:表达式错误
    • @ FOnChange : @FOnChange: Pointer $253B588
    • @换字 : @@FOnChange: ^Untyped (no address) 数据: @@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
    

    难怪我找不到 换热器 ,这是两个地址!

    5 回复  |  直到 14 年前
        1
  •  6
  •   Mason Wheeler    14 年前

    您可以通过调试检查器获取地址。要获取字段的地址,请在更改发生之前的某个时间点(例如,在调用构造函数之后)在代码中放置一个断点。然后在调试检查器中打开对象。不确定如何以旧的IDE样式获得它,但在D2010中,您可以从运行中获得它->检查…菜单命令,从“评估/修改”中的按钮,或按键盘上的alt-f5。(小心不要按ALT-F4!)

    调试检查器将向您显示对象及其所有字段。双击其中一个字段,它将在新的调试检查器窗口中打开。在编辑框中,如顶部的栏将是您的字段地址。您可以使用它设置内存断点,以查找值的更改位置。

        2
  •  4
  •   Francesca    14 年前

    在Delphi5中不确定,但您应该能够将数据断点(或地址断点)放在您的aeexample.fonchange上。
    它将在值更改时中断。

        3
  •  3
  •   Cosmin Prund    14 年前

    既然你不能使用fran_ois建议的智能解决方案,现在是黑客攻击的时候了!在某个地方,任何可以放置制动点的地方,编写如下代码:

    var X:TExample;
    X.OnChange := nil;
    

    在x.onchange:=nil行上放置一个brakepoint;当调试器停在那里时,查看“反汇编”窗格,您将看到如下内容:

    ; assembler blah blah to get the address of X
    xor EDX ; or whatever the compiler finds appropriate this time of day
    mov [eax + $00000288], edx
    mov [eax + $0000028c], edx
    

    你不关心编译器使用的寄存器,你关心288美元,第一条MOV指令使用的偏移量。这是从“x”地址到fonchange字段的偏移量。记下来。现在回到bugy程序,在某个地方设置一个brakepoint,点击alt+f5调用调试检查器(如果没有空的编辑框输入查询,则按ctrl+n),然后写“integer(myexamplevariable)”;无论得到什么,都要加上在上一步中记下的数字,并得到fonchange的地址。对于myExampleVariable实例,现在可以设置地址brakepoint。

        4
  •  1
  •   splash    14 年前

    我不知道Delphi5中是否有,但是类型 TMethod 以及功能 MethodAddress 应该会有帮助。

        5
  •  0
  •   Ian Boyd    14 年前

    为什么?

    我正在试图找出是谁在用垃圾覆盖我的fonchange处理程序变量。

    我可以回答那一点-你是!或者您所看到的实例不正确?引用不正确?会是那样的。Delphi调试器擅长使不存在的东西看起来像它所做的那样,直到…

    退后一点,试着看木头而不是树。我去过你很多次的地方,你可能是大错特错了(不好意思,双关语是故意的),很快就会给自己起各种各样的名字。