我有一些 MSVC++ 编译的 DLL,我为其创建了类 COM(精简版)接口(interface)(抽象 Delphi 类)。其中一些类具有需要指向对象的指针的方法。这些 C++ 方法是使用 __thiscall 调用约定(我无法更改)声明的,这与 __stdcall 类似,只是传递了一个 this 指针在 ECX 寄存器上。
我在 Delphi 中创建类实例,然后将其传递给 C++ 方法。我可以在 Delphi 中设置断点,并看到它命中了我的 Delphi 类中公开的 __stdcall 方法,但很快我得到一个 STATUS_STACK_BUFFER_OVERRUN 并且应用程序必须退出。是否可以在 Delphi 方面模拟/处理 __thiscall?如果我传递一个由 C++ 系统实例化的对象,那么一切都很好,并且该对象的方法被调用(如预期的那样),但这没有用 - 我需要传递 Delphi 对象。
Edit 2010-04-19 18:12 This is what happens in more detail: The first method called (setLabel) exits with no error (though its a stub method). The second method called (init), enters then dies when it attempts to read the vol parameter.
C++ 端
#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;
};
德尔福方面
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;
我本来有一半希望单独使用 stdcall 来工作,但是有些事情搞砸了,不确定是什么,也许与正在使用的 ECX 寄存器有关?将不胜感激。
Edit 2010-04-19 17:42 Could it be that the ECX register needs to be preserved on entry and restored once the function exits? Is the this pointer required by C++? I'm probably just reaching at the moment based on some intense Google searches. I found something related, but it seems to be dealing with the reverse of this issue.
最佳答案
让我们假设您已经使用 VMT 创建了一个 MSVC++ 类,它完美地映射到 Delphi 类的 VMT 中(我从来没有这样做过,我只是相信你这是可能的)。现在您可以从 MSVC++ 代码调用 Delphi 类的虚方法,唯一的问题是 __thiscall 调用约定。由于 __thiscall 在 Delphi 中不受支持,可能的解决方案是在 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;
关于c++ - 将 Delphi 类传递给需要具有 __thiscall 方法的类的 C++ 函数/方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2667925/