3

クラスをCヘッダーからDelphiで使用するように変換するのに問題があります。

Cヘッダーファイルの宣言のスニペットは次のようになります。

class __declspec(uuid("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
ISomeInterface
{    
public:
  virtual
  BOOL
  SomeBoolMethod(
    VOID
  ) const = 0;
}

ISomeInterfaceパラメーターを受け入れるメソッドをエクスポートするDLLを作成しています。

function MyExportFunc (pSomeInterface: ISomeInterface): Cardinal; export; stdcall;
var
  aBool: BOOL;
begin
  aBool := pSomeInterface.SomeBoolMethod;
end;

DelphiでISomeInterfaceを次のように宣言しました。

type ISomeInterface = class
  function SomeBoolMethod: BOOL; cdecl; virtual; abstract;
end;

pSomeInterface.SomeBoolMethodを呼び出すと、アクセス違反が発生します。

私は根本的に間違ったことをしていますか?

実際のCヘッダーはhttpserv.hであり、DelphiでIIS7ネイティブモジュールを実装しようとしています。

動作するいくつかのc++コードは次のようになります。

HRESULT
__stdcall
RegisterModule(
    DWORD                           dwServerVersion,
    IHttpModuleRegistrationInfo *   pModuleInfo,
    IHttpServer *                   pHttpServer
)
{
  // etc
}

デバッグすると、pModuleInfoパラメーターに__vfptrメンバーが含まれ、その下に6つのメンバー([0]から[5]の名前が付けられ、値としてアドレスがあります)が含まれていることがわかります。これは、IHttpModuleRegistrationInfoクラスの仮想メソッドへのポインターであると推測されます。

DelphiRegisterModuleのエクスポートは次のようになります。

function RegisterModule (dwServerVersion: DWORD; var pModuleInfo: Pointer; var pHttpServer: Pointer): HRESULT; export; stdcall;
begin
  // etc
end;

pModuleInfoには、cppの例の__vfptrメンバーと同等のアドレスが含まれており、__ vfptrの順序がヘッダーファイルのクラス宣言と同じであると仮定して、メソッドアドレスを抽出します。

function RegisterModule (dwServerVersion: DWORD; var pModuleInfo: Pointer; var pHttpServer: Pointer): HRESULT; export; stdcall;
var
  vfptr: Pointer;
  ptrGetName: Pointer;
  ptrGetId: Pointer;
begin
  vfptr := pModuleInfo;
  ptrGetName := Pointer (Pointer (Cardinal(vfptr))^);
  ptrGetId := Pointer (Pointer (Cardinal(vfptr) + 4)^);
end;

呼び出すメソッドアドレスができたので、なんとかして呼び出す必要があります。私はおそらくこれをすべて間違った方法で行っています!

4

3 に答える 3

3

として宣言しないでくださいcdecl。32 ビット COM メソッドの呼び出し規約は、C がstdcallエイリアス CALLBACK および WINAPI として参照するものです。Delphiに同等のものがあるかどうかを確認してください。Delphi が COM をサポートしている場合は、COM があります。

また、C インターフェイスが IUnknown から派生していないことを確認してください。実質的にすべての COM インターフェイスが IUnknown から派生しています。そうである場合は、Delphi の同等のものからインターフェイスを派生させます。

また、Delphi のオブジェクト レイアウトが COM のオブジェクト レイアウトと一致するかどうかもわかりません (最初のデータ項目としての仮想関数ポインター テーブル)。ここでも、Delphi が COM を実装する方法を見つけます。

于 2011-10-04T22:38:40.793 に答える
2

TObjectDelphi では、指定するかどうかに関係なく、すべてのクラスが派生します。これは、次の Delphi 宣言を意味します。

type
  ISomeInterface = class
    function SomeBoolMethod: BOOL; cdecl; virtual; abstract;
  end;

これと同じです:

type
  ISomeInterface = class(TObject)
    function SomeBoolMethod: BOOL; cdecl; virtual; abstract;
  end;

そのためISomeInterface、Delphi のクラスの VMT はISomeInterfaceC++ のクラスの VMT とは異なり、AV につながる可能性があります。

同様に、他の人が言及したように、DelphiISomeInterfaceinterfaceを a ではなくan として宣言すると、C++ クラスも行っていないclassから暗黙的に派生します。IUnknown

要するに、Delphi は、C++ が再現できる単純なバニラ クラスの型を単純に再現できません。Delphi で得られる最も近い方法は (Delphi との互換性を高めるために C++ コードを変更することなく)、型またはrecord型の代わりに型を宣言することです。ただし、仮想メソッドが使用されているため、Delphi で C++ VMT を手動で再現する必要があり、 ( Delphi では) ポインターの明示的なパラメーターを持つようにすべてのメソッドを宣言する必要があります。classinterfacethisSelf

それ以外の場合は、C++ コードと Delphi コードの両方を代わりに COM インターフェイスを使用するように切り替えます。COM インターフェイスはバイナリ標準であるため、両方の言語は相互に互換性があります。

于 2011-10-05T00:31:06.273 に答える
1

__declspec(uuid__uuidofoperatorによって要求されたときにコンパイラがコード内の別の場所に適用できるように、UUID をクラス定義に添付しました。

つまり、Delphi に移植する場合は、基本的にこの仕様をクラスから省略できる可能性があります。インターフェイスに関しては、Delphi でインターフェイスを宣言するときに、この定義に IID を提供する機会が間違いなくあります。

ただし、コード内のアクセス違反は __declspec とはまったく関係ありません。C++ISomeInterfaceは から継承されていないため、厳密にはインターフェイスではありませんIUnknown。IIRC では、Delphi では、この種のインターフェイスを宣言することはできません。宣言するものは、少なくとも から派生する必要がありますIUnknown。そのため、インターフェイスを安全かつ簡単に変換する方法はありません (正確には、クラス - 有効な COM インターフェイス定義ではないため)。

正しく行われた一致/変換は次のとおりです。

MIDL_INTERFACE("56a86897-0ad4-11ce-b03a-0020af0ba770")
IReferenceClock : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTime( 
        /* [out] */ REFERENCE_TIME *pTime) = 0;
// ...

そして、http://code.google.com/p/dspack/source/browse/trunk/src/DirectX9/DirectSound.pas#456の Delphi ツイン

type
  IReferenceClock = interface(IUnknown)
    ['{56a86897-0ad4-11ce-b03a-0020af0ba770}']
    // IReferenceClock methods
    function GetTime(out pTime: TReferenceTime): HResult; stdcall;
// ...
于 2011-10-04T22:37:55.190 に答える