在 TWinControl 类上添加属性
我想将已发布的属性添加到 TWinControl 中。 有没有办法在不需要重新编译基本源代码的情况下做到这一点?
如果没有,有什么方法可以重新编译基本源代码而不需要太多麻烦?
谢谢建议...
编辑新想法
好吧,我想做的就是尝试覆盖 System.pas 中的 _GetMem 类 继承自 TWinControl。 为什么 ?因为我会为对象分配一些额外的空间,足以达到一个整数。 为什么是整数?因为这样我就可以添加任何指向对象的指针。 因此,在 TWinControl 的辅助类上,我可以创建一个 Get an 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.
I want to add a published property into TWinControl.
Is there someway to do this without the necessity of recompiling the base source code ?
If not, some way to recompile the base source code without too much troubles ?
Tks in advice...
EDIT 'CAUSE OF NEW IDEAS
Alright, What I'm thinking to do I'm trying to override the _GetMem from System.pas for classes
inherited from TWinControl.
Why ? 'Cause I'll alloc some extra space to the objects enough to an integer.
Why an integer ? 'Cause this way I can add any pointer to object.
So on the helper class to TWinControl I can make a Get an Set function to access this space of memory.
Good isn't it ? How to do this ?
Overrideing the GetMem procedure I can use the same strategy used on FastCode, create a jumper to the new procedure.
What I need now is understand how this memory alloc works InstanceSize to override this.
At all I'm studding how do Delphi do this... And to add this on DFM I will do the same way, I'll create a jumper to the filer.
Someone have some idea to add the new space in objects ? What method I need to override ? The jumper I know how to do.
Tks Again.
EDIT = Evolution
I think that I did the injection of memory.
I need to do more tests.
I've just did it, I'm not caring about optimizations at the moment, if some one would like to test it, here goes the code.
Just add the unit as the first unit of your project.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
感谢 Smasher,我记得 Delphi 团队如何使用类帮助器和设计技巧向 Delphi 2007 添加属性而不破坏二进制文件与 Delphi 2006 的兼容性。
请参阅很棒Hallvard Vassbotn 撰写的文章介绍了如何执行此操作。
我认为它可以解决您的大部分(如果不是全部)问题。
在文章中查找以下内容:
不过,当您从外部世界挂钩时,您必须以自己的方式进行流处理进入 TWinControl,但这也是可能的。
——杰罗恩
Thanks to Smasher, I remembered how the Delphi team used class helpers and a designer trick to add properties to Delphi 2007 without breaking binary compatibility with Delphi 2006.
See this great article by Hallvard Vassbotn on how to do this.
I think it solves most, if not all, of your problems.
look for these things in the article:
You'll have to work your own way to do the streaming, though, as you hook from the outside world into TWinControl, but that might be possible too.
--jeroen
Delphi2007及更高版本有“类助手”。
您可以引入新的函数和属性,但不能引入字段/变量。因此,您必须将新属性的值存储在额外的对象中(通过工厂或其他方式)或(非常丑陋)在 .Tag 属性中...
不知道类助手是否也可以在包/设计时工作?
Delphi2007 and higher have "class helpers".
You can introduce new functions and properties, but no fields/variables. So you have to store the value of you new property in a extra object (via factory or whatever) or (very ugly) in the .Tag property...
Don't know if class helper also work in packages/design time?
如果您仅在应用程序级别使用此属性,则可以使用以下方法:
附加:根据您的附加评论,现有的 Tag 属性应该可以很好地满足您的需求。您甚至可以通过使用不同的值来定义“级别”。
If you are using this property only on the application level, you may use the following approaches:
ADDITION: Based on your additional comment, existing Tag property should play well for your needs. You can even define 'levels' by using different values there.
不,不重新编译 VCL 就无法修改 TWinControl。另外,我不建议更改 VCL(因为拥有“自定义”VCL 会影响项目的可移植性 - 至少在 Delphi 安装之间)。我的目标是创建另一个从 TWinControl 继承的类,然后将您发布的属性添加到这个新类中。
如果您仍然想更改 VCL,请参阅以下帖子:
http://www.delphigroups.info/2/6/744173.html
请注意“您将不再能够使用运行时进行编译
包”...
No, there is no way to modify TWinControl without recompiling the VCL. Also I don't recommend changing the VCL (since having a "custom" VCL can impact the portability of your project - at the very least between Delphi installations). I would aim at making another class that inherit from TWinControl and then add your published property to this new class.
If you still want to change the VCL see the following post:
http://www.delphigroups.info/2/6/744173.html
Note that "you will no longer be able to compile using runtime
packages"...
(我知道答案有点密集,评论一下您需要更多信息的详细信息)
您可以做的就是 TGridPanel 所做的:它将 Column、Row、ColumnSpan 和 RowSpan“属性”添加到对象检查器中GridPanel 上的所有组件。
这将解决您的设计时支持问题。
我以为我有关于 TGridPanel 如何执行此操作的参考(并且 TFlowPanel 执行类似的操作),但我现在找不到它。雷·科诺普卡 (Ray Konopka) 可能在一次会议上解释了这一点,但该信息可能不在网上。
对于运行时支持,您可以使用类助手。
使用类助手时,请注意,只有类中最接近的可见助手才会适用。
您可能遵循的另一种途径是使用 Tag 属性(它是一个 Integer,但您可以将其转换为 Pointer 或 TObject),但其他人也可能会使用它。
不过,您必须为这些标记属性创建自己的设计时支持。
——杰罗恩
(I know the answer is a bit dense, comment on it what details you need more info about)
What you could do is what for instance TGridPanel does: it adds the Column, Row, ColumnSpan and RowSpan 'properties' to the object inspector for all components that are on the GridPanel.
That will solve your design-time support.
I thought I had a reference on how the TGridPanel does this (and TFlowPanel does similar things), but I can't find it right now. Probably Ray Konopka explained this during a conference, but that info might not be on-line.
For run-time support, you could go with class helpers.
When using class helpers, note that only the nearest visible one for a class will apply.
Another route you might follow is to use the Tag property (which is an Integer, but you can cast it to a Pointer or a TObject), but you might be bitten by others using that too.
You'd have to create your own design-time support for those tag properties though.
--jeroen