- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图使用下面的代码将 TObject.AfterConstruction 重定向到另一个过程,但一段时间后开始出现很多异常。注意:我使用这种重定向到许多其他解决方案。
unit Unit109;
interface
uses
Windows;
implementation
uses
SyncObjs, SysUtils;
type
PJump = ^TJump;
TJump = packed record
OpCode: Byte;
Distance: Pointer;
end;
TObjectHack = class(TObject)
public
procedure AfterConstruction;
end;
function GetMethodAddress(AStub: Pointer): Pointer;
const
CALL_OPCODE = $E8;
begin
if PBYTE(AStub)^ = CALL_OPCODE then
begin
Inc(Integer(AStub));
Result := Pointer(Integer(AStub) + SizeOf(Pointer) + PInteger(AStub)^);
end
else
Result := nil;
end;
procedure AddressPatch(const ASource, ADestination: Pointer);
const
JMP_OPCODE = $E9;
SIZE = SizeOf(TJump);
var
NewJump: PJump;
OldProtect: Cardinal;
begin
if VirtualProtect(ASource, SIZE, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
NewJump := PJump(ASource);
NewJump.OpCode := JMP_OPCODE;
NewJump.Distance := Pointer(Integer(ADestination) - Integer(ASource) - 5);
FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump));
VirtualProtect(ASource, SIZE, OldProtect, @OldProtect);
end;
end;
procedure OldAfterConstruction;
asm
call TObject.AfterConstruction;
end;
{ TCriticalSectionHack }
procedure TObjectHack.AfterConstruction;
begin
end;
initialization
AddressPatch(GetMethodAddress(@OldAfterConstruction), @TObjectHack.AfterConstruction);
end.
也许 AfterConstruction 存储在 VMT (vmtAfterConstruction = -28) 中,并且必须以其他方式更改?像:
PatchCodeDWORD(PDWORD(Integer(Self) + vmtAfterConstruction), DWORD(@TObjectHack.AfterConstruction));
procedure PatchCodeDWORD(ACode: PDWORD; AValue: DWORD);
var
LRestoreProtection, LIgnore: DWORD;
begin
if VirtualProtect(ACode, SizeOf(ACode^), PAGE_EXECUTE_READWRITE, LRestoreProtection) then
begin
ACode^ := AValue;
VirtualProtect(ACode, SizeOf(ACode^), LRestoreProtection, LIgnore);
FlushInstructionCache(GetCurrentProcess, ACode, SizeOf(ACode^));
end;
end;
我尝试了两种方法,但没有成功,有人可以帮助我吗?
如果有人想了解这种方法:
谢谢
最佳答案
已编辑 - 现在正在努力增加和减少项目数量。要使其工作,只需将该单位作为 dpr 的第一个单位即可。现在,我将优化一些方法并将我想要的输出放在这里。 (我不会重新编辑帖子,没有必要)但如果您想使用,可以随意测试并报告错误。如果您想测试,我会放置一个简单输出,过程SaveInstancesToFile,它会在您的应用程序路径中创建一个包含计数器输出的 test.txt 文件。
unit ObjectCounter;
{ Develop by rodrigofrezino@gmail.com
Stackoverflow: http://stackoverflow.com/users/225010/saci
Please, any bug let me know}
interface
procedure SaveInstancesToFile;
implementation
uses
Windows, SysUtils, Classes, TypInfo;
type
PClassVars = ^TClassVars;
TClassVars = class(TObject)
private
class var ListClassVars: TList;
public
InstanceCount: integer;
BaseClassName: string;
constructor Create;
class procedure SaveToDisk;
end;
PJump = ^TJump;
TJump = packed record
OpCode: Byte;
Distance: Pointer;
end;
TObjectHack = class(TObject)
private
class procedure SetClassVars(AClassVars: TClassVars);
class function GetClassVars: TClassVars;
procedure IncCounter;
procedure DecCounter;
procedure OldFreeInstace;
public
class function InitInstance(Instance: Pointer): TObject;
end;
var
FOldFreeInstance: Pointer;
procedure SaveInstancesToFile;
begin
TClassVars.SaveToDisk;
end;
function GetMethodAddress(AStub: Pointer): Pointer;
const
CALL_OPCODE = $E8;
begin
if PBYTE(AStub)^ = CALL_OPCODE then
begin
Inc(Integer(AStub));
Result := Pointer(Integer(AStub) + SizeOf(Pointer) + PInteger(AStub)^);
end
else
Result := nil;
end;
procedure AddressPatch(const ASource, ADestination: Pointer);
const
JMP_OPCODE = $E9;
SIZE = SizeOf(TJump);
var
NewJump: PJump;
OldProtect: Cardinal;
begin
if VirtualProtect(ASource, SIZE, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
NewJump := PJump(ASource);
NewJump.OpCode := JMP_OPCODE;
NewJump.Distance := Pointer(Integer(ADestination) - Integer(ASource) - 5);
FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump));
VirtualProtect(ASource, SIZE, OldProtect, @OldProtect);
end;
end;
procedure PatchCodeDWORD(ACode: PDWORD; AValue: DWORD);
var
LRestoreProtection, LIgnore: DWORD;
begin
if VirtualProtect(ACode, SizeOf(ACode^), PAGE_EXECUTE_READWRITE, LRestoreProtection) then
begin
ACode^ := AValue;
VirtualProtect(ACode, SizeOf(ACode^), LRestoreProtection, LIgnore);
FlushInstructionCache(GetCurrentProcess, ACode, SizeOf(ACode^));
end;
end;
procedure OldAfterConstruction;
asm
call TObject.InitInstance;
end;
{ TCriticalSectionHack }
procedure TObjectHack.DecCounter;
begin
if (Self.ClassType <> TClassVars) then
Dec(GetClassVars.InstanceCount);
OldFreeInstace;
end;
class function TObjectHack.GetClassVars: TClassVars;
begin
Result := PClassVars(Integer(Self) + vmtAutoTable)^;
end;
class procedure TObjectHack.SetClassVars(AClassVars: TClassVars);
begin
AClassVars.BaseClassName := Self.ClassName;
PatchCodeDWORD(PDWORD(Integer(Self) + vmtAutoTable), DWORD(AClassVars));
end;
procedure RegisterClassVarsSupport(const Classes: array of TObjectHack);
var
LClass: TObjectHack;
LRestoreProtection: DWORD;
LIgnore: DWORD;
LVMT: Pointer;
begin
for LClass in Classes do
if LClass.GetClassVars = nil then
begin
LClass.SetClassVars(TClassVars.Create);
//Change de mvt to object mvt
LVMT := PPointer(Integer(TObject) + vmtFreeInstance)^;
if VirtualProtect(LVMT, SizeOf(LVMT^), PAGE_EXECUTE_READWRITE, LRestoreProtection) then
begin
LVMT := @TObjectHack.DecCounter;
VirtualProtect(LVMT, SizeOf(LVMT^), LRestoreProtection, LIgnore);
FlushInstructionCache(GetCurrentProcess, LVMT, SizeOf(LVMT^));
end;
end
else
raise Exception.CreateFmt('Class %s has automated section or duplicated registration.', [LClass.ClassName]);
end;
procedure TObjectHack.IncCounter;
begin
if (Self.ClassType = TClassVars) then
Exit;
if GetClassVars = nil then
RegisterClassVarsSupport(Self);
Inc(GetClassVars.InstanceCount);
end;
class function TObjectHack.InitInstance(Instance: Pointer): TObject;
asm
PUSH EBX
PUSH ESI
PUSH EDI
MOV EBX,EAX
MOV EDI,EDX
STOSD
MOV ECX,[EBX].vmtInstanceSize
XOR EAX,EAX
PUSH ECX
SHR ECX,2
DEC ECX
REP STOSD
POP ECX
AND ECX,3
REP STOSB
MOV EAX,EDX
MOV EDX,ESP
@@0: MOV ECX,[EBX].vmtIntfTable
TEST ECX,ECX
JE @@1
PUSH ECX
@@1: MOV EBX,[EBX].vmtParent
TEST EBX,EBX
JE @@2
MOV EBX,[EBX]
JMP @@0
@@2: CMP ESP,EDX
JE @@5
@@3: POP EBX
MOV ECX,[EBX].TInterfaceTable.EntryCount
ADD EBX,4
@@4: MOV ESI,[EBX].TInterfaceEntry.VTable
TEST ESI,ESI
JE @@4a
MOV EDI,[EBX].TInterfaceEntry.IOffset
MOV [EAX+EDI],ESI
@@4a: ADD EBX,TYPE TInterfaceEntry
DEC ECX
JNE @@4
CMP ESP,EDX
JNE @@3
@@5: MOV EBX,EAX
CALL TObjectHack.IncCounter
MOV EAX,EBX
POP EDI
POP ESI
POP EBX
end;
procedure TObjectHack.OldFreeInstace;
asm
call FOldFreeInstance;
end;
procedure InitFreeInstance;
begin
FOldFreeInstance := PPointer(Integer(TObject) + vmtFreeInstance)^;
end;
{ TClassVars }
constructor TClassVars.Create;
begin
ListClassVars.Add(Self);
end;
class procedure TClassVars.SaveToDisk;
var
LStringList: TStringList;
i: Integer;
begin
LStringList := TStringList.Create;
try
LStringList.Add('CLASS | NUMBER OF INSTANCES');
for i := 0 to ListClassVars.Count -1 do
LStringList.Add(TClassVars(ListClassVars.Items[I]).BaseClassName + '|' + IntToStr(TClassVars(ListClassVars.Items[I]).InstanceCount));
LStringList.SaveToFile(ExtractFilePath(ParamStr(0)) + 'test.txt');
finally
FreeAndNil(LStringList);
end;
end;
initialization
TClassVars.ListClassVars := TList.Create;
InitFreeInstance;
AddressPatch(GetMethodAddress(@OldAfterConstruction), @TObjectHack.InitInstance);
end.
关于delphi - 将 TObject.AfterConstruction 重定向到其他过程时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10503531/
我刚读 "Any class that implements the IEqualityComparer interface is expected to provide the implementa
我一次又一次地看到使用 Func 的 API(尤其是在 .NET 框架中)什么时候Predicate似乎是一个完全负责任的选择。 API 设计者这样做的好理由是什么? 最佳答案 在 LINQ 中,Fu
我目前正在考虑一个场景,我想要一个通用类,它在其项目上调用 Free IF 这些都是对象类型。所以我尝试了以下方法: if (PTypeInfo (TypeInfo (T)).Kind = tkCla
我有一个过程需要 TObject 类型的参数,如下所示: MyProcedure (const AValue : TObject); 我有一个 Variant 数组,我正在循环调用该过程,如下所示:
(发件人:TObject)是什么意思?如: procedure TForm1.Button1Click(Sender:TObject); var s: Integer; begin ..... ...
TObject.InstanceSize 返回 8,但 TObject 未声明任何数据成员。根据TObject.ClassType的实现,前4个字节可以解释为指向对象的TClass元数据的指针。有人知
我们正试图弄清楚我们的软件中是否存在内存泄漏。所以,我一直在使用各种工具和程序来帮助我找到可能的内存泄漏。我使用的软件之一是 AQTime。由于它与 Delphi XE 一起提供,它只是一个演示。所以
如何将当前状态的对象保存到文件中?这样就可以立即读取并恢复它的所有变量。 最佳答案 您正在寻找的称为对象持久性。这个article可能会有所帮助,如果你用谷歌搜索“delphi持久对象”,还有很多其他
我正在 Delphi XE2 中编写一个支持触摸屏的应用程序。 我有一个带有 TEdits 的表单。当我单击它们时,我调用我编写的过程来显示另一个最大化的始终位于顶部的窗体,其中带有带有标签(用于标题
我似乎无法通过搜索找到答案,所以这里...... 我知道我可以通过使用这种类型的代码将 Class 对象一般地传递给其他类: public class ClsGeneric where TObje
请了解此代码: type TClient = class(TObject) public Host: String; Queue: TIdThreadSafeStringLis
想使用 Sender 作为 TObject 作为我的案例的选择标准...声明 procedure TForm.ShowGUI (Sender: TObject); begin case sende
基于之前的一个答案 post ,我正在研究以下设计的可能性 TChildClass = class(TObject) private FField1: string; FField2: s
我试图使用下面的代码将 TObject.AfterConstruction 重定向到另一个过程,但一段时间后开始出现很多异常。注意:我使用这种重定向到许多其他解决方案。 unit Unit109; i
这里是一些示例代码,它是 Delphi 中的一个独立控制台应用程序,它创建一个对象,然后创建一个 TInterfacedObject 对象,并将 Interface 引用分配给 TObject 中的字
我怎样才能让我的代码工作? :) 我试图提出这个问题,但经过几次失败的尝试后,我认为你们通过查看代码会比阅读我的“解释”更快地发现问题。谢谢。 setCtrlState([ memo1, edit1,
我有一个需要返回一个对象的方法。当然,只有当 T 是一个对象时才有意义: function TGrobber.Swipe: TObject; var current: T; begin
看看这个类: TTest = class(TObject) public constructor Create(A:Integer);overload; constructor Crea
除此之外post其接受的答案仍然非常神秘: @Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject) be
目前Delphi XE只能在我的盒子上使用,我不知道Delphi 2010/XE2是否引入了一些突破性的变化。 请帮我更新以下定义: TVmt = packed record SelfPtr
我是一名优秀的程序员,十分优秀!