12

Delphiでは、次のIUnknownように宣言されています。

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

注:出力パラメーターは型指定されていません

私のTInterfacedObject子孫ではQueryInterface、を処理する必要があるので、要求されたインターフェイスをサポートするオブジェクトを返すことができます。

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;

問題は次のようになります。

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

Delphiは文句を言います:

このオペランドタイプに適用できない演算子

明らかに、型指定されていない outパラメータにどのように、または何を割り当てるかはわかりません。コンパイラが文句を言うのをやめることを期待して、私はランダムに物事を試すことができます:

Obj := TFooBar.Create(Self);

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

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

私が書いたすべてのコードを無視する(必要な場合):QueryInterfaceオブジェクトの子孫にどのように実装しますTInterfacedObjectか?


私が解決しようとしてきた本当の問題は、私がしたいことに要約することができます:

インターフェイスのメソッドをオーバーライドしたい

同じやり方で:

TList = class(TObject)
...
   function GetItem(Index: Integer): Pointer; 
   procedure SetItem(Index: Integer; Value: Pointer);
   property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;

子孫クラスでオーバーライドできます:

TStudentList = class(TList)
...
   function GetItem(Index: Integer): TStudent; 
   procedure SetItem(Index: Integer; Value: TStudent);
   property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;

私はインターフェースでも同じことをしたいです:

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;

問題は、実装オブジェクトのロードをどのように開始する必要があるかということです。

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;

そして、には2つのメソッドだけでなく、IFoo6つのメソッドがあります。次に、サポートされている別のインターフェイスを追加する場合は、次のようにします。

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;

そして、物事は非常に速く扱いにくくなります。

4

3 に答える 3

6

代入ステートメントの左側を型キャストする必要があります。このように、型指定されていないパラメーターには型があり、コンパイラーはそれに値を割り当てる方法を知っています。

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

COMの要件の1つに違反していることに注意してください。インターフェイスをクエリする場合、IUnknownの結果をクエリして、常に同じ値を取得できるはずです。

Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);

タイプTFooBarの新しいオブジェクトを生成するだけの場合は、それらを生成するメソッドをインターフェイスに指定します。

function TFoo.NewFooBar: IFooBar;
begin
  Result := TFooBar.Create(Self) as IFooBar;
end;
于 2010-07-21T20:39:27.417 に答える
3

ここでルールを破るというRobの発言に加えて、この構成で成功することもできます。

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;

私はこれを調査しませんでしたが、参照カウントでいくつかの問題が発生する可能性があります...

于 2010-07-21T20:46:46.900 に答える
2

System.pasでのTObject.GetInterfaceの実装に基づいて、私はこれを提案します:

  Pointer(Obj) := TFooBar.Create(Self);
于 2010-07-21T20:37:05.237 に答える