在TWinControl类上添加属性

时间:2010-01-18 13:47:36

标签: delphi vcl

我想将已发布的属性添加到TWinControl中。 有没有必要重新编译基本源代码?

如果没有,有一些方法可以重新编译基本源代码而不会有太多麻烦吗?

提出建议......

编辑'新想法的原因

好吧,我正在考虑做什么我试图从System.pas覆盖_GetMem用于类 继承自TWinControl。 为什么?因为我会为对象分配一些额外的空间足够一个整数。 为什么是整数?因为这样我可以添加任何指向对象的指针。 所以在TWinControl的辅助类上,我可以创建一个Get a Set函数来访问这个内存空间。 好不是吗?这该怎么做 ? 重写GetMem过程我可以使用在FastCode上使用的相同策略,创建一个跳转到新过程。

我现在需要了解内存分配如何使用InstanceSize来覆盖它。 总之,我正在研究Delphi如何做到这一点...而在DFM上添加它我将以同样的方式,我将创建一个跳线到文件管理器。

有人有想法在对象中添加新空间吗?我需要覆盖哪种方法?跳线我知道怎么做。

再来一次。

编辑=演变

我认为我注射了内存。 我需要做更多的测试。 我刚刚做到了,我现在不关心优化,如果有人想测试它,这里就是代码。 只需将该单元添加为项目的第一个单元即可。

unit uMemInjection;


interface

uses
  Controls;

type
  THelperWinControl = class Helper for TWinControl
  private
    function RfInstanceSize: Longint;
    function GetInteger: Integer;
    procedure SetInteger(const Value: Integer);
  public
    property RfInteger: Integer read GetInteger write SetInteger;
  end;

implementation

uses
  Windows;

procedure SInstanceSize;
asm
  call TWinControl.InstanceSize
end;

function THelperWinControl.GetInteger: Integer;
begin
  Result := Integer(PInteger(Integer(Self) + (Self.InstanceSize - SizeOf(Integer)))^);
end;

function THelperWinControl.RfInstanceSize: Longint;
begin
  Result := PInteger(Integer(Self) + vmtInstanceSize)^;
  Result := Result + SizeOf(Integer);
end;

/////////////////////////////////////////////// FastCode ///////////////////////////////////////////////
type
  PJump = ^TJump;
  TJump = packed record
    OpCode: Byte;
    Distance: Pointer;
  end;

function FastcodeGetAddress(AStub: Pointer): Pointer;
begin
  if PBYTE(AStub)^ = $E8 then
  begin
    Inc(Integer(AStub));
    Result := Pointer(Integer(AStub) + SizeOf(Pointer) + PInteger(AStub)^);
  end
  else
    Result := nil;
end;

procedure FastcodeAddressPatch(const ASource, ADestination: Pointer);
const
  Size = SizeOf(TJump);
var
  NewJump: PJump;
  OldProtect: Cardinal;
begin
  if VirtualProtect(ASource, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    NewJump := PJump(ASource);
    NewJump.OpCode := $E9;
    NewJump.Distance := Pointer(Integer(ADestination) - Integer(ASource) - 5);

    FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump));
    VirtualProtect(ASource, Size, OldProtect, @OldProtect);
  end;
end;

/////////////////////////////////////////////// FastCode /////////////////////////////////////////////// 


{ THelperWinControl }
procedure THelperWinControl.SetInteger(const Value: Integer);
begin
  PInteger(Integer(Self) + (Self.InstanceSize - SizeOf(Integer)))^ := Value;
end;

initialization
  FastcodeAddressPatch(FastcodeGetAddress(@SInstanceSize), @TWinControl.RfInstanceSize);


end.

5 个答案:

答案 0 :(得分:9)

感谢Smasher,我记得Delphi团队如何使用类帮助程序和设计器技巧为Delphi 2007添加属性,而不会破坏与Delphi 2006的二进制兼容性。

great article Hallvard Vassbotn了解如何执行此操作。

我认为它解决了大部分(如果不是全部)问题。

在文章中查找这些内容:

  • TCustomFormHelper = TCustomForm的类助手
  • FPixelsPerInch存储黑客
  • 注入设计时属性
  • 定义流媒体属性

但是,当你从外部世界挂钩进入TWinControl时,你必须以自己的方式进行流式传输,但这也许是可能的。

- 的Jeroen

答案 1 :(得分:4)

Delphi2007及更高版本有“级助手”。

您可以引入新的功能和属性,但不能引入字段/变量。因此,您必须将新属性的值存储在.Tag属性中的额外对象(通过工厂或其他)或(非常难看)......

不知道类助手是否也能在包/设计时工作?

答案 2 :(得分:2)

如果您仅在应用程序级别使用此属性,则可以使用以下方法:

  • 组合:将对TWinControl对象的引用与其他属性捆绑到新类中,并在调用中传递/操作此类的对象
  • 类似字典的函数:GetMyPropertyFor(AWinControl:TWinControl):和SetMyPropertyFor(AWinControl:TWinControl:AValue:),它在内部为每个被调用的TWinControl对象维护附加属性

其他:根据您的其他评论,现有的Tag属性应该可以满足您的需求。您甚至可以通过使用不同的值来定义“级别”。

答案 3 :(得分:1)

不,没有重新编译VCL就无法修改TWinControl。此外,我不建议更改VCL(因为具有“自定义”VCL会影响项目的可移植性 - 至少在Delphi安装之间)。我的目标是创建另一个继承自TWinControl的类,然后将已发布的属性添加到这个新类中。

如果您仍想更改VCL,请参阅以下帖子: http://www.delphigroups.info/2/6/744173.html

请注意“您将无法再使用运行时进行编译 包” ...

答案 4 :(得分:0)

(我知道答案有点密集,请评论您需要了解更多信息的详细信息)

你可以做的是例如TGridPanel的作用:它将Column,Row,ColumnSpan和RowSpan'属性'添加到对象检查器中,用于GridPanel上的所有组件。 这将解决您的设计时支持。

我以为我有一个关于TGridPanel如何做到这一点的参考(和TFlowPanel做类似的事情),但我现在找不到它。 Ray Konopka可能在会议期间对此进行了解释,但该信息可能不会在线。

对于运行时支持,您可以使用类助手。 使用类帮助程序时,请注意只应用类的最近可见的帮助程序。

您可能遵循的另一个路线是使用Tag属性(它是一个Integer,但您可以将其强制转换为指针或TObject),但是您也可能被其他人使用。 您必须为这些标签属性创建自己的设计时支持。

- 的Jeroen