代码之家  ›  专栏  ›  技术社区  ›  mjn anonym

如何在Delphi中动态地将代码注入事件处理程序?

  •  7
  • mjn anonym  · 技术社区  · 15 年前

    BeforeOpen AfterOpen 事件来捕获开始时间,并在AfterOpen中记录经过的时间。

    迭代所有组件并按其类型进行过滤很容易,但是对于已经分配了事件处理程序的组件,我需要一种方法

    所以这个代码

    procedure TMyDatamodule.OnBeforeOpen(Sender: TDataset);
    begin
      SomeProc;
    end;
    

    procedure TMyDatamodule.OnBeforeOpen(Sender: TDataset);
    begin
      StoreStartTime(Sender); // injected code
    
      SomeProc;
    end;
    

    有没有可以应用的设计模式,或者甚至是一些示例代码来说明如何在Delphi中实现这一点?

    5 回复  |  直到 15 年前
        1
  •  9
  •   Uwe Raabe    15 年前

    可以使用以下方案重新连接数据集:

    type
      TDataSetEventWrapper = class
      private
        FDataSet: TDataSet;
        FOrgAfterOpen: TDataSetNotifyEvent;
        FOrgBeforeOpen: TDataSetNotifyEvent;
        procedure MyAfterOpen(DataSet: TDataSet);
        procedure MyBeforeOpen(DataSet: TDataSet);
      protected
        property DataSet: TDataSet read FDataSet;
      public
        constructor Create(ADataSet: TDataSet);
        destructor Destroy; override;
      end;
    
    constructor TDataSetEventWrapper.Create(ADataSet: TDataSet);
    begin
      Assert(ADataSet <> nil);
      inherited Create;
      FDataSet := ADataSet;
      FOrgAfterOpen := FDataSet.AfterOpen;
      FOrgBeforeOpen := FDataSet.BeforeOpen;
      FDataSet.AfterOpen := MyAfterOpen;
      FDataSet.BeforeOpen := MyBeforeOpen;
    end;
    
    destructor TDataSetEventWrapper.Destroy;
    begin
      FDataSet.AfterOpen := FOrgAfterOpen;
      FDataSet.BeforeOpen := FOrgBeforeOpen;
      inherited;
    end;
    
    procedure TDataSetEventWrapper.MyBeforeOpen(DataSet: TDataSet);
    begin
      if Assigned(FOrgBeforeOpen) then
        FOrgBeforeOpen(DataSet);
    end;
    
    procedure TDataSetEventWrapper.MyAfterOpen(DataSet: TDataSet);
    begin
      if Assigned(FOrgAfterOpen) then
        FOrgAfterOpen(DataSet);
    end;
    

    在…内 MyAfterOpen MyBeforeOpen

    TObjectList 具有 OwnsObjects := true

        2
  •  3
  •   LukLed    15 年前

    我想试试这个:

    TDataSetBeforeOpenStartTimeStorer = class(TObject)
    
    constructor Create(MyDataModule : TMyDatamodule);
    begin
        OldBeforeOpen := MyDatamodule.OnBeforeOpen;
        MyDatamodule.OnBeforeOpen = NewBeforeOpen;
    end;
    
    procedure NewBeforeOpen(Sender: TDataset);
    begin
      StoreStartTime(Sender);
      if Assigned(OldBeforeOpen) then
        OldBeforeOpen(Sender);
    end;
    

    将一个tdatasetbeforeorestarttimestorer实例附加到每个TDataSet,您就拥有了自己的功能。

        3
  •  2
  •   Ritsaert Hornstra    15 年前

    如果要“钩住”的组件中的函数或过程是declard虚拟的或动态的,可以按以下方式完成:

    为了便于讨论,我们假设您希望看到来自TDataset的所有AfterOpen。从虚拟方法调用此事件处理程序:

    procedure TDataSet.DoAfterOpen;
    

    创建一个新的UnitDataSetter(在手册中键入)

    unit UnitDatasetTester;
    
    interface
    
    uses
      DB;
    
    type
      TDataset = class( DB.TDataset )
      protected
        procedure DoAfterOpen; override;
      end;
    
    implementation
    
    uses
      MySpecialLoggingUnit; 
    
    procedure TDataset.DoAfterOpen;
    begin
      inherited;
      SpecialLog.Add( 'Hello world' );
    end;
    

        4
  •  1
  •   Jeroen Wiert Pluimers    15 年前

    没有通用的方法可以做到这一点,而不是去真正的低水平。

    我将创建一个新的TDataSource并将其指向TDataSet实例。然后我将使用创建一个数据感知组件,并使用TDataLink捕获您感兴趣的内容。

    从零开始,这是几天的工作。但是您可以从我的会议会话“数据库和数据感知控件的智能代码”的示例代码开始。
    Conferences, seminars and other public appearances page wiert.wordpress.com 对于链接。

        5
  •  0
  •   André    15 年前

    (RTTI:搜索已发布的事件属性;迂回:钩住原来的函数,并将其重新路由/迂回到自己的函数)。

    我在我的开源Delphi profiler中使用detouring: http://code.google.com/p/asmprofiler/

    但是,如果您想要一种更“智能”的方式(比如关于beforeopen和afteropen的知识),您必须做一些额外的工作:您需要为TDataset子体等创建一个特殊的处理类。