Delphi 重新调整实例类内存分配的大小

Delphi 重新调整实例类内存分配的大小,delphi,class,instance,Delphi,Class,Instance,我在运行时将此示例用于Change类: procedure PatchInstanceClass(Instance: TObject; NewClass: TClass); type PClass = ^TClass; begin if Assigned(Instance) and Assigned(NewClass) and NewClass.InheritsFrom(Instance.ClassType) and (NewClass.InstanceSize = In

我在运行时将此示例用于Change类:

procedure PatchInstanceClass(Instance: TObject; NewClass: TClass);
type
  PClass = ^TClass;
begin
  if Assigned(Instance) and Assigned(NewClass)
    and NewClass.InheritsFrom(Instance.ClassType)
    and (NewClass.InstanceSize = Instance.InstanceSize) then
  begin
    PClass(Instance)^ := NewClass;
  end;
end;

type
  TMyButton = class(TButton)
  Private
    FLogEvent : TNotifyEvent;
  public
    Property  Log : TNotifyEvent Read FLogEvent Write FLogEvent;
    procedure Click; override;
  end;

procedure TMyButton.Click;
begin
  Inherited;
  if Assigned(FLogEvent) then
     FLogEvent(Self);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  PatchInstanceClass(Button1, TMyButton);
end;
我的问题是TMyButton的大小与TButton不同,因为我将此事件添加到TMyButton中。
我的问题是如何重新调整NewClass同一实例的内存分配大小。:-)

你试图做的是不切实际的。如果可以找到对该对象的所有引用,或许可以这样做。您需要这样做,因为重新分配可能会导致内存驻留在不同的地址。因此,您需要更新这些引用

因此,您需要找到:

  • 代码中的所有引用,以及
  • VCL代码中的所有引用
后者要难得多。父对象保存对其子对象的引用。按钮的所有者保存引用。如果我没记错的话,action框架可以保存引用。我肯定还有其他地方可以参考

如果您能找到所有参考资料,那么您需要:

  • 使用新大小重新分配内存块
  • 对派生类中的新字段执行任何初始化
  • 更改对象的类
  • 更新对对象的所有引用
  • 坦率地说,这是一种很糟糕的UI事件检测方法。您有许多更好的选择:

    • 使用插入器类
    • 使用虚拟方法拦截器
    • 处理应用程序的OnMessage事件以筛选消息队列

    你真的应该放弃目前解决问题的方法。

    虽然我同意其他人的观点,但你应该重新考虑你的方法,因为这有点老套。然而,我喜欢黑客的东西-所以我要告诉你如何才能实现你的要求

    关键是不要在新类中放入任何内容(因为InstanceSize需要相同)将其放在其他地方-如果您使用的是较新的Delphi版本(2010或更高版本),您可以这样做。否则,您需要对代码进行一些修改,但我想您会明白这一点:

    uses
      Generics.Collections;
    
    procedure PatchInstanceClass(Instance: TObject; NewClass: TClass);
    begin
      if Assigned(Instance) and Assigned(NewClass)
        and NewClass.InheritsFrom(Instance.ClassType)
        and (NewClass.InstanceSize = Instance.InstanceSize) then
      begin
        PPointer(Instance)^ := NewClass;
      end;
    end;
    
    type
      TMyButton = class(TButton)
      private
        function GetLogEvent: TNotifyEvent;
        procedure SetLogEvent(const Value: TNotifyEvent);
      public
        destructor Destroy; override;
        procedure Click; override;
    
        property LogEvent: TNotifyEvent read GetLogEvent write SetLogEvent;
      end;
    
      TMyButtonHelper = class helper for TMyButton
      private
        class var fLogEvents: TDictionary<TObject, TNotifyEvent>;
      public
        class constructor Create;
        class destructor Destroy;
      end;
    
    { TMyButtonHelper }
    
    class constructor TMyButtonHelper.Create;
    begin
      fLogEvents := TDictionary<TObject, TNotifyEvent>.Create;
    end;
    
    class destructor TMyButtonHelper.Destroy;
    begin
      fLogEvents.Free;
    end;
    
    { TMyButton }
    
    destructor TMyButton.Destroy;
    begin
      fLogEvents.Remove(Self);
      inherited;
    end;
    
    procedure TMyButton.Click;
    begin
      inherited;
      if Assigned(LogEvent) then
         LogEvent(Self);
    end;
    
    function TMyButton.GetLogEvent: TNotifyEvent;
    begin
      fLogEvents.TryGetValue(Self, Result);
    end;
    
    procedure TMyButton.SetLogEvent(const Value: TNotifyEvent);
    begin
      fLogEvents.AddOrSetValue(Self, Value);
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      PatchInstanceClass(Button1, TMyButton);
      TMyButton(Button1).LogEvent := Button1Click;
    end;
    
    使用
    仿制药。收藏;
    过程PatchInstanceClass(实例:TObject;新类:TClass);
    开始
    如果已分配(实例)和已分配(新类)
    和NewClass.InheritsFrom(Instance.ClassType)
    和(NewClass.InstanceSize=Instance.InstanceSize)然后
    开始
    PPointer(实例)^:=NewClass;
    结束;
    结束;
    类型
    TMyButton=类(TButton)
    私有的
    函数GetLogEvent:TNotifyEvent;
    过程SetLogEvent(常量值:TNotifyEvent);
    公众的
    毁灭者毁灭;推翻
    程序点击;推翻
    属性LogEvent:TNotifyEvent read GetLogEvent write SetLogEvent;
    结束;
    TMyButtonHelper=TMyButton的类帮助器
    私有的
    分类变量fLogEvents:t字典;
    公众的
    类构造函数创建;
    类析构函数销毁;
    结束;
    {TMyButtonHelper}
    类构造函数TMyButtonHelper.Create;
    开始
    fLogEvents:=TDictionary.Create;
    结束;
    类析构函数TMyButtonHelper.Destroy;
    开始
    免费的;
    结束;
    {TMyButton}
    析构函数TMyButton.Destroy;
    开始
    絮状物。移除(自身);
    继承;
    结束;
    程序TMyButton。单击;
    开始
    继承;
    如果已分配(LogEvent),则
    LogEvent(Self);
    结束;
    函数TMyButton.GetLogEvent:TNotifyEvent;
    开始
    fLogEvents.TryGetValue(自身、结果);
    结束;
    过程TMyButton.SetLogEvent(const值:TNotifyEvent);
    开始
    fLogEvents.AddOrSetValue(Self,Value);
    结束;
    过程TForm1.FormCreate(发送方:TObject);
    开始
    PatchInstanceClass(按钮1,TMyButton);
    TMyButton(Button1).LogEvent:=按钮1单击;
    结束;
    
    使用interposer类,您不需要任何黑客攻击。您想实现什么?这是错误的解决方案,概率>0.999。您不应该这样做,因为调整对象实例的大小通常会重新定位内存中的实例,并使对实例的引用无效。最好在这样做时使用虚拟方法拦截器this@Farzad问题不是问了如何重新调整实例的大小吗?