将Delphi类传递给期望具有__thiscall方法的类的C++函数/方法

Ato*_*ian 6 c++ delphi dll calling-convention

我有一些MSVC++编译的DLL,我已经创建了COM-like(lite)接口(抽象的Delphi类).其中一些类具有需要指向对象的指针的方法.这些C++方法是使用__thiscall调用约定(我无法更改)声明的,就像__stdcall一样,除了这个指针在ECX寄存器上传递.

我在Delphi中创建类实例,然后将其传递给C++方法.我可以在Delphi中设置断点并看到它在我的Delphi类中遇到暴露的__stdcall方法,但很快我得到一个STATUS_STACK_BUFFER_OVERRUN并且应用程序必须退出.是否可以在Delphi方面模拟/处理__thiscall?如果我传递一个由C++系统实例化的对象,那么一切都很好,并调用该对象的方法(如预期的那样),但这没用 - 我需要传递Delphi对象.

编辑2010-04-19 18:12这就是更详细的情况:第一个调用的方法(setLabel)退出时没有错误(尽管它是一个存根方法).第二种方法叫做(init),然后在尝试读取vol参数时进入 .

C++ Side

#define SHAPES_EXPORT __declspec(dllexport) // just to show the value
class SHAPES_EXPORT CBox
{
  public:
    virtual ~CBox() {}
    virtual void init(double volume) = 0;
    virtual void grow(double amount) = 0;
    virtual void shrink(double amount) = 0;
    virtual void setID(int ID = 0) = 0;
    virtual void setLabel(const char* text) = 0;
};
Run Code Online (Sandbox Code Playgroud)

德尔福方面

IBox = class
public
  procedure destroyBox; virtual; stdcall; abstract;
  procedure init(vol: Double); virtual; stdcall; abstract;
  procedure grow(amount: Double); virtual; stdcall; abstract;
  procedure shrink(amount: Double); virtual; stdcall; abstract;
  procedure setID(val: Integer); virtual; stdcall; abstract;
  procedure setLabel(text: PChar); virtual; stdcall; abstract; 
end;

TMyBox = class(IBox)
protected
  FVolume: Double;
  FID: Integer;
  FLabel: String; //
public
  constructor Create;
  destructor Destroy; override;
  // BEGIN Virtual Method implementation
  procedure destroyBox; override; stdcall;             // empty - Dont need/want C++ to manage my Delphi objects, just call their methods
  procedure init(vol: Double); override; stdcall;      // FVolume := vol;
  procedure grow(amount: Double); override; stdcall;   // Inc(FVolume, amount);
  procedure shrink(amount: Double); override; stdcall; // Dec(FVolume, amount);
  procedure setID(val: Integer); override; stdcall;    // FID := val;
  procedure setLabel(text: PChar); override; stdcall;  // Stub method; empty.
  // END Virtual Method implementation      
  property Volume: Double read FVolume;
  property ID: Integer read FID;
  property Label: String read FLabel;
end;
Run Code Online (Sandbox Code Playgroud)

我有一半期望单独使用stdcall工作,但是有些事情搞砸了,不确定是什么,或许与使用ECX寄存器有关?非常感谢帮助.

编辑2010-04-19 17:42可能是ECX寄存器需要在进入时保留并在函数退出后恢复吗?是这个 指针由C++要求?我可能只是根据一些激烈的Google搜索来实现这一目标.我找到了相关的东西,但似乎正在处理这个问题的反面.

klu*_*udg 3

让我们假设您已经创建了一个具有 VMT 的 MSVC++ 类,它完美地映射到 Delphi 类的 VMT(我从未这样做过,我只是相信您这是可能的)。现在您可以从 MSVC++ 代码中调用 Delphi 类的虚拟方法,唯一的问题是 __thiscall 调用约定。由于Delphi中不支持__thiscall,因此可能的解决方案是在Delphi端使用代理虚拟方法:

更新

type
  TTest = class
    procedure ECXCaller(AValue: Integer);
    procedure ProcProxy(AValue: Integer); virtual; stdcall;
    procedure Proc(AValue: Integer); stdcall;
  end;

implementation

{ TTest }

procedure TTest.ECXCaller(AValue: Integer);
asm
  mov   ecx,eax
  push  AValue
  call  ProcProxy
end;

procedure TTest.Proc(AValue: Integer);
begin
  ShowMessage(IntToStr(AValue));
end;

procedure TTest.ProcProxy(AValue: Integer);
asm
   pop  ebp            // !!! because of hidden delphi prologue code
   mov  eax,[esp]      // return address
   push eax
   mov  [esp+4],ecx    // "this" argument
   jmp  Proc
end;
Run Code Online (Sandbox Code Playgroud)