3

私はDelphi2007を使用していますが、次のような場合があります。

{ CommonUnit.pas }
type
  // there is a callback which I want to process
  TFooBar = procedure(Sender: IInterface) of object; stdcall;

  // there is an interface which is used by all modules
  IFoo = interface
  ['{0FAA4B2B-E82A-4A2A-B55F-C75EC53A1318}']
    procedure Bar(Callback: TFooBar); stdcall;
  end;

{ UnitInModuleCompiledWithoutPackages.pas }
type
  // there is a class which implements IFoo
  // and it's defined in Module One compiled without packages
  TFoo = class(TInterfacedObject, IFoo)
  public
    // implementation is ommited
    procedure Bar(Callback: TFooBar); stdcall;
  end;

{ UnitInModuleCompiledWithPackages.pas }
// there is a code in Module Two compiled with packages
type
  TSomeClass = class
  public
    // implementation is ommited
    procedure SomeMethod(Sender: IInterface); stdcall;
  end;

var
  SomeObject: TSomeClass; // assigned by somehow
  Foo: IFoo; // assigned by somehow

begin
  // ...
  Foo.Bar(SomeObject.SomeMethod); // so it is safe?
  // ...
end;

Foo.Bar次のように宣言されている場合、オブジェクト参照を渡そうとすると、メモリが破損することはわかっています。

type
  IFoo = interface
  ['{0FAA4B2B-E82A-4A2A-B55F-C75EC53A1318}']
    // TSomeClass now declared in CommonUnit.pas
    procedure Bar(CallbackObject: TSomeClass); stdcall;
  end;

これはTSomeClass、モジュール1での実装がモジュール2での実装と同じではないためです(異なるメモリマネージャーなど)。
しかし、メソッド参照はどうですか?
Embarcaderoのドキュメントには、このことを解決するためのものは何も見つかりませんでした。

4

2 に答える 2

5

あなたのコードは大丈夫です。メソッドポインタTFooBarを渡すと、関数ポインタとインスタンスポインタの2つのポインタが渡されます。そのメソッドを呼び出すと、呼び出し規約が正確なバイナリインターフェイスを強制するため、Delphiのすべてのバージョンがメソッドを呼び出すためにまったく同じことを行います。また、Delphiのすべてのバージョンは、同じ方法でメソッドポインタを表します。

あなたが懸念している問題は次のとおりです。

  1. さまざまなメモリマネージャー。ヒープ割り当てを行っていないため、ここでは問題ありません。
  2. 異なるコンパイラでの異なるオブジェクト表現。メソッドポインタの呼び出しはオブジェクト表現に依存しないため、ここでは問題ありません。これは、コードポインタとデータポインタ(モジュール間で値によって渡される)と呼び出し規約(規約によって同じであることに同意)に依存しています。
于 2012-04-23T06:36:26.177 に答える
3

David Heffernanがすでに答えているように、メソッドポインタを使用することは問題ありません。メソッドポインタの代わりにあらゆる種類の「コールバックオブジェクト」を使用する唯一の理由は、次の場合です。

  • Barが戻った後、IFooインスタンスがポインターを保持する場合があります。その場合、コールバックはイベントとして記述し、適切なライフタイム管理を保証するイベントシンクインターフェイスを渡す必要があります。
  • IFoo.Barの実装が呼び出す可能性のある複数の代替コールバックメソッドがあります。その場合、複数のメソッドポインターではなく、単一のインターフェイス(クラスインスタンスではなく、自分で説明するため)を渡すことも検討する必要があります。
于 2012-04-23T07:17:40.260 に答える