다음 함수를 사용하여 기존 객체의 인스턴스 클래스를 패치합니다. 그 이유는 제 3 자 클래스의 보호 된 기능을 패치해야하기 때문입니다.인스턴스 클래스를 패치 할 때 기본 클래스가 동일한 단위로 있어야합니까?
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;
하지만 기본 클래스가 자체 단위로 정의 된 경우에만 코드가 작동합니다. 왜 그럴까요? 그것 없이는 작동하도록하는 해결 방법이 있습니까?
이 그 예에서 작업하는 동안
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, wwdblook, Wwdbdlg;
type
TwwDBLookupComboDlg = class(Wwdbdlg.TwwDBLookupComboDlg); // This is necessary
TForm1 = class(TForm)
Button1: TButton;
wwDBLookupComboDlg1: TwwDBLookupComboDlg;
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TButtonEx = class(TButton)
end;
TwwDBLookupComboDlgEx = class(TwwDBLookupComboDlg)
end;
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;
procedure TForm1.FormCreate(Sender: TObject);
begin
PatchInstanceClass(Button1, TButtonEx);
showmessage(Button1.ClassName); // Good: TButtonEx
PatchInstanceClass(wwDBLookupComboDlg1, TwwDBLookupComboDlgEx);
showmessage(wwDBLookupComboDlg1.ClassName); // Bad: TwwDBLookupComboDlg (should be TwwDBLookupComboDlgEx)
end;
end.
이 작동
이
type
TwwDBLookupComboDlg = class(wwdbdlg.TwwDBLookupComboDlg); // <------ added!
procedure TForm1.FormCreate(Sender: TObject);
begin
PatchInstanceClass(wwDBLookupComboDlg1, TwwDBLookupComboDlgEx);
showmessage(wwDBLookupComboDlg1.ClassName); // shows TwwDBLookupComboDlgEx :-)
end;
end.
(유일한 차이점은 TwwDBLookupComboDlg의 재 정의이다) 작동하지 않습니다, 나는 발견 이 현상은 TwwDBLookupComboDlg에서만 발생하지만 TButton에서는 발생하지 않습니다. 나는 이유를 모른다. 아쉽게도 wwdbdlg.pas는 무료가 아닙니다.
업데이트 : 발견
: 나는 TButton
및 TButtonEx
을 비교하면 내가 wwdlg.TwwDBLookupComboDlg
및 TwwDBLookupComboDlgEx
을 비교하면, 두 값이 모두 608
있으며, 그 크기는 940와 944이다.
Unit1.TwwDBLookupComboDlg
과 TwwDBLookupComboDlgEx
을 비교하면 크기는 944 및 944입니다.
실제 문제는 다음과 같습니다. TwwDBLookupComboDlg = class(Wwdbdlg.TwwDBLookupComboDlg);
을 정의하면 인스턴스 크기가 4 바이트 씩 커집니다!
간단한 데모. 이 프로그램이 문제가 TOpenDialog
에서 발생
220 220 220
하지만,이 발생하지 않습니다 출력은 XE7으로, 그러나 델파이 2007로 컴파일 할 때
{$APPTYPE CONSOLE}
uses
Dialogs;
type
TOpenDialog = class(Vcl.Dialogs.TOpenDialog);
TOpenDialogEx = class(TOpenDialog);
begin
Writeln(Vcl.Dialogs.TOpenDialog.InstanceSize);
Writeln(TOpenDialog.InstanceSize);
Writeln(TOpenDialogEx.InstanceSize);
Readln;
end.
이
188 192 192
을 방출 TCommonDialog
.
업데이트 2 : 최소한의 예를
program Project1;
{$APPTYPE CONSOLE}
uses
Classes, Dialogs;
type
TOpenDialog = class(TCommonDialog)
private
FOptionsEx: TOpenOptionsEx;
end;
TOpenDialogEx = class(Project1.TOpenDialog);
begin
Writeln(Project1.TOpenDialog.InstanceSize); // 100
Writeln(TOpenDialogEx.InstanceSize); // 104
Readln;
end.
직접 붙여 넣을 수있는 [mcve]가 없습니까? 그렇지 않으면 우리는 스스로 그것을 만들어야합니다. 우리 각자. 그렇게 비효율적이지 않습니까? 네가 해낸다면 우리는 모두 이익을 얻는다. 우리에게 당신을 도울 수있는 최대한 간단하게 만들어야하는 책임이 있습니까? –
자, 여기 있습니다 : http : //pastebin.com/SL2gKBTR. 이 예제를 작업하면서이 현상은 TwwDBLookupComboDlg에서만 발생하지만 TButton에서는 발생하지 않는다는 것을 알게되었습니다. 나는 이유를 모른다. 아쉽게도 wwdbdlg.pas는 무료가 아닙니다. –
오프 사이트 링크에 있어서는 안됩니다. 질문에 있어야합니다. 그러나 내가 가지고 있지 않은 컨트롤을 통해서만 발생한다면 나는 확실히 도울 수 없다. 또한 아직 완성되지 않았습니다. 콘솔 응용 프로그램에 넣으면 완료됩니다. –