Delphi 中如何将接口转换为对象

发布于 2024-10-01 02:09:12 字数 384 浏览 9 评论 0原文

在delphi 2009中,我有一个对IInterface的引用,我想将其转换为底层TObject

使用TObject(IInterface)显然不起作用在Delphi 2009中(虽然它应该在Delphi 2010中工作)

我的搜索引导我到一个应该可以解决问题的函数,但它对我不起作用,当我尝试调用返回对象的方法时,我得到了 AV。

我无法真正修改类,而且我知道这会破坏 OOP

In delphi 2009 I have a reference to a IInterface which I want to cast to the underlying TObject

Using TObject(IInterface) obviously doesn't work in Delphi 2009 (it's supposed to work in Delphi 2010 though)

My searches lead me to a function that should do the trick, but it doesn't work for me, I get AV's when I try to call methods on the returned object.

I can't really modify the Classes and I know that this breaks OOP

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

夏末 2024-10-08 02:09:12

你是对的。从 Delphi 2010 开始,您可以使用 as 运算符,例如通过 aObject := aInterface as TObject 甚至 aObject := TObject(aInterface)

as 运算符使用特殊的隐藏接口 GUID (ObjCastGUID) 来检索对象实例,调用增强版本的 TObject.GetInterface,这会Delphi 2010 之前不存在。请参阅 System.pas 单元的源代码以了解其工作原理。

我已经发布了一些适用于 Delphi 6 到 XE2 的代码,包括 Delphi 2009< /a>.

请参阅 http://blog .synopse.info?post/2012/06/13/从界面检索对象实例

You are right. Beginning with Delphi 2010, you are able to use the as operator, e.g. via aObject := aInterface as TObject or even aObject := TObject(aInterface).

This as operator use a special hidden interface GUID (ObjCastGUID) to retrieve the object instance, calling an enhanced version of TObject.GetInterface, which does not exist prior to Delphi 2010. See source code of System.pas unit to see how it works.

I've published some code working for Delphi 6 up to XE2, including Delphi 2009.

See http://blog.synopse.info?post/2012/06/13/Retrieve-the-object-instance-from-an-interface

两相知 2024-10-08 02:09:12

除了依赖 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;

Instead of relying on Delphi's internal object layout you could also have your objects implement another interface which would simply return the object. This, of course, only works if you have access to the source code of the objects to begin with, but you probably shouldn't even use these hacks if you don't have access the source code of the objects.

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;
满栀 2024-10-08 02:09:12

当您知道实现对象是 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;

There is a nice alternative when you know the implementing object is a TComponent descendant.

You can use the IInterfaceComponentReference interface, which is defined up in Classes unit:

IInterfaceComponentReference = interface
  ['{E28B1858-EC86-4559-8FCD-6B4F824151ED}']
  function GetComponent: TComponent;
end;

And then it's declared in TComponent (and implemented to return self):

  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)

So if you know the implementing object is a TComponent then you can do this:

function InterfaceToComponent(const AInterface: IInterface): TComponent;
var
  vReference: IInterfaceComponentReference;
begin
  if Supports(AInterface, IInterfaceComponentReference, vReference) then
    result := vReference.GetComponent
  else
    result := nil;
end;
莫多说 2024-10-08 02:09:12

简而言之:您不应该或添加一个带有为您返回指针的方法的接口。其他任何事情都是黑客行为。

请注意,接口“实例”可以用另一种语言实现(它们与 COM 兼容)和/或可以是进程外某些内容的存根等。

总而言之:接口实例仅同意该接口,而不同意其他任何内容,当然不是作为 Delphi TObject 实例实现的

In short: you shouldn't or add an interface with a method that returns the pointer for you. Anything else is hackery.

Note that an interface "instance" may be implemented in another language (they are COM compatible) and / or may be a stub for something out of process etc etc.

All in all: an interface instance only agrees to the interface and nothing else, certainly not being implemented as a Delphi TObject instance

南七夏 2024-10-08 02:09:12

Hallvard 的 hack 非常具体于 Delphi 编译器如何生成代码。这在过去一直非常稳定,但听起来他们在 Delphi 2009 中改变了一些重要的东西。我这里只安装了 2007,而 Hallvard 的代码工作得很好。

GetImplementingObject 返回 NIL 吗?

如果是这样,那么如果您在 GetImplementingObject 例程中的 case 语句上进行调试并设置断点,那么 QueryInterfaceThunk.AddInstruction 的值在调试器中的计算结果是什么?

Hallvard's hack is very specific to how the Delphi compiler generates code. That has been remarkably stable in the past, but it sounds like they changed something significant in Delphi 2009. I only have 2007 installed here, and in that, Hallvard's code works fine.

Does GetImplementingObject return NIL?

If so, then if you debug and set a break-point on the case statement in the GetImplementingObject routine, what does the value of QueryInterfaceThunk.AddInstruction evaluate to in the debugger?

薄荷梦 2024-10-08 02:09:12
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;
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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文