首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >德尔菲:如何实现QueryInterface of IUnknown?

德尔菲:如何实现QueryInterface of IUnknown?
EN

Stack Overflow用户
提问于 2010-07-21 20:07:09
回答 3查看 9.3K关注 0票数 12

在Delphi中,IUnknown声明为:

代码语言:javascript
复制
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

注:输出参数是非类型化的

在我的TInterfacedObject后代中,我需要处理QueryInterface,因此我可以返回一个支持请求的接口的对象:

代码语言:javascript
复制
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
   begin
      Obj := (TFooBar.Create(Self) as IFooBar);
      Result := S_OK;
   end
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

问题就在眼前:

代码语言:javascript
复制
Obj := (TFooBar.Create(Self) as IFooBar);

德尔菲抱怨说:

运算符不适用于此操作数类型。

显然,我不知道如何或如何分配给非类型化的 out参数。我可以随意尝试一些事情,希望编译器不再抱怨:

代码语言:javascript
复制
Obj := TFooBar.Create(Self);

Obj := Pointer(TFooBar.Create(Self));

Obj := Pointer(TFooBar.Create(Self) as IFooBar);

忽略我编写的所有代码(如果需要):如何在来自TInterfacedObject的对象子代中实现TInterfacedObject

我一直试图解决的真正问题可以归结为我想要:

我想要覆盖接口中的方法

同样的方式:

代码语言:javascript
复制
TList = class(TObject)
...
   function GetItem(Index: Integer): Pointer; 
   procedure SetItem(Index: Integer; Value: Pointer);
   property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;

可以在子类中重写:

代码语言:javascript
复制
TStudentList = class(TList)
...
   function GetItem(Index: Integer): TStudent; 
   procedure SetItem(Index: Integer; Value: TStudent);
   property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;

对于接口,我也想这样做:

代码语言:javascript
复制
IFoo = interface(IUnknown)
...
   function GetItem(Index: Variant): Variant; 
   procedure SetItem(Index: Variant; Value: Variant);
   property Items[Index: Variant]: Variant read GetItem write SetItem;
end;

IFooGuidString = interface(IFoo)
...
   function GetItem(Index: TGUID): string ; 
   procedure SetItem(Index: TGUID; Value: string );
   property Items[Index: TGUID]: string read GetItem write SetItem;
end;

问题在于,我必须如何开始用以下方法加载实现对象:

代码语言:javascript
复制
TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );
end;

IFoo中不仅有两个方法,还有6个。如果我想添加另一个受支持的接口:

代码语言:javascript
复制
IFooInt64String = interface(IFoo)
...
   function GetItem(Index: Int64): string ; 
   procedure SetItem(Index: Int64; Value: string );
   property Items[Index: Int64]: string read GetItem write SetItem;
end;


TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );

   function IFooInt64String.GetItem = FooInt64StringGetItem;
   procedure IFooInt64String.SetItem = FooInt64StringSetItem;
   function FooInt64StringGetItem(Index: Int64): string ; 
   procedure FooInt64StringSetItem(Index: Int64; Value: string );
end;

事情很快就会变得不太好。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-07-21 20:39:27

您需要键入赋值语句的左侧。这样,非类型化参数有一个类型,编译器知道如何为它赋值:

代码语言:javascript
复制
IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;

请注意,您正在破坏一个COM的需求。如果您查询一个接口,您应该能够查询IUnknown的结果,并且始终获得相同的值:

代码语言:javascript
复制
Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);

如果您只想生成TFooBar类型的新对象,那么就给接口一个生成这些对象的方法:

代码语言:javascript
复制
function TFoo.NewFooBar: IFooBar;
begin
  Result := TFooBar.Create(Self) as IFooBar;
end;
票数 6
EN

Stack Overflow用户

发布于 2010-07-21 20:46:46

除了Rob关于在这里违反规则的评论之外,您甚至可以通过这样的构造获得成功:

代码语言:javascript
复制
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
      Result := TFooBar.Create(Self).QueryInterface(IID, obj)
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

我没有调查这个,但是你可能会在推荐信计数上遇到一些问题……

票数 3
EN

Stack Overflow用户

发布于 2010-07-21 20:37:05

基于TObject.GetInterface在System.pas中的实现,我建议如下:

代码语言:javascript
复制
  Pointer(Obj) := TFooBar.Create(Self);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3303362

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档