在delphi 2009中,我引用了IInterface
,我想将其转换为基础TObject
使用TObject(IInterface)
显然在Delphi 2009中不起作用(它应该在Delphi 2010中工作)
我的搜索引导我a function that should do the trick,但它对我不起作用,当我尝试在返回的对象上调用方法时,我得到了AV。
我无法真正修改类,我知道这会破坏OOP
答案 0 :(得分:18)
您可以让对象实现另一个简单地返回对象的接口,而不是依赖于Delphi的内部对象布局。当然,这只有在您可以访问对象的源代码时才有效,但如果您无法访问对象的源代码,则可能甚至不应该使用这些黑客。
interface
type
IGetObject = interface
function GetObject: TObject;
end;
TSomeClass = class(TInterfacedObject, IGetObject)
public
function GetObject: TObject;
end;
implementation
function TSomeClass.GetObject: TObject;
begin
Result := Self;
end;
答案 1 :(得分:16)
你是对的。从Delphi 2010开始,您可以使用as运算符,例如通过aObject := aInterface as TObject
甚至是aObject := TObject(aInterface)
。
此as
运算符使用特殊的隐藏接口GUID(ObjCastGUID
)来检索对象实例,调用TObject.GetInterface
的增强版本,该版本在Delphi 2010之前不存在。请参阅System.pas
单位的源代码,以了解其工作原理。
我已经发布了一些适用于Delphi 6的代码,直到XE2,including Delphi 2009。
请参阅http://blog.synopse.info/post/2012/06/13/Retrieve-the-object-instance-from-an-interface
答案 2 :(得分:3)
简而言之:您不应该添加具有为您返回指针的方法的接口。其他任何东西都是hackery。
请注意,接口“实例”可以用另一种语言实现(它们是COM兼容的)和/或可能是用于进程外等的存根。
总而言之:接口实例只同意接口而没有别的,当然不是作为Delphi TObject实例实现的
答案 3 :(得分:3)
当您知道实现对象是TComponent
后代时,有一个很好的选择。
您可以使用IInterfaceComponentReference
单位中定义的Classes
界面:
IInterfaceComponentReference = interface
['{E28B1858-EC86-4559-8FCD-6B4F824151ED}']
function GetComponent: TComponent;
end;
然后它在TComponent
中声明(并实现为返回self
):
TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)
因此,如果您知道,实施对象是TComponent
,那么您可以这样做:
function InterfaceToComponent(const AInterface: IInterface): TComponent;
var
vReference: IInterfaceComponentReference;
begin
if Supports(AInterface, IInterfaceComponentReference, vReference) then
result := vReference.GetComponent
else
result := nil;
end;
答案 4 :(得分:2)
Hallvard的hack特别针对Delphi编译器如何生成代码。这在过去一直非常稳定,但听起来他们在Delphi 2009中改变了一些重要的东西。我只在这里安装了2007,并且在那里,Hallvard的代码工作正常。
GetImplementingObject是否返回NIL?
如果是这样,那么如果在GetImplementingObject例程中对case语句进行调试并设置断点,那么QueryInterfaceThunk.AddInstruction的值在调试器中的值是多少?
答案 5 :(得分:-1)
var
N, F: NativeInt; // NativeInt is Integer(in delphi 32bit )
S: TObject;
begin
N := NativeInt(Args[0].AsInterface) - 12;
{subtract 12 byte to get object address(in x86 ,1 interface on class) }
S := TObject(N);
writeln(S.ToString);
end;