将Delphi类传递给需要使用__thiscall方法的类的C ++函数/方法 [英] Pass a Delphi class to a C++ function/method that expects a class with __thiscall methods

查看:320
本文介绍了将Delphi类传递给需要使用__thiscall方法的类的C ++函数/方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些MSVC ++编译的DLL,我已经创建了类似COM(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)//只显示值
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;
};

Delphi Side

  IBox = class 
public
procedure destroyBox;虚拟; STDCALL;抽象;
procedure init(vol:Double);虚拟; STDCALL;抽象;
程序增长(amount:Double);虚拟; STDCALL;抽象;
程序缩减(金额:双);虚拟; STDCALL;抽象;
procedure setID(val:Integer);虚拟; STDCALL;抽象;
procedure setLabel(text:PChar);虚拟; STDCALL;抽象;
结束

TMyBox = class(IBox)
protected
FVolume:Double;
FID:整数;
FLabel:String; //
public
构造函数创建;
析构函数覆盖;
// BEGIN虚方法实现
procedure destroyBox;覆盖; STDCALL; //空 - 不需要/想要C ++管理我的Delphi对象,只需调用他们的方法
procedure init(vol:Double);覆盖; STDCALL; // FVolume:= vol;
程序增长(amount:Double);覆盖; STDCALL; // Inc(FVolume,amount);
程序缩减(金额:双);覆盖; STDCALL; // Dec(FVolume,amount);
procedure setID(val:Integer);覆盖; STDCALL; // FID:= val;
procedure setLabel(text:PChar);覆盖; STDCALL; // Stub方法;空。
// END虚方法实现
属性卷:双读FVolume;
属性ID:整数读取FID;
属性Label:String read FLabel;
结束

我有一半预期使用stdcall单独工作,但有些东西搞砸了,不知道什么,可能与使用ECX寄存器有关吗?帮助将不胜感激。


编辑2010-04-19 17:42 可能是ECX注册需要
保留进入并恢复一次
函数退出? C ++需要这个
指针吗?我现在可能是
根据
刚刚达成的一些激烈的Google搜索。 I
发现相关内容,但它
似乎正在处理这个问题的反向



解决方案

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



更新

  type 
TTest = class
procedure ECXCaller(AValue:Integer);
procedure ProcProxy(AValue:Integer);虚拟; STDCALL;
procedure Proc(AValue:Integer); STDCALL;
结束

执行

{TTest}

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

程序TTest.Proc(AValue:Integer);
begin
ShowMessage(IntToStr(AValue));
结束

程序TTest.ProcProxy(AValue:Integer);
asm
pop ebp // !!!因为隐藏的delphi prologue代码
mov eax,[esp] // return address
push eax
mov [esp + 4],ecx //thisargument
jmp Proc
结束


I have some MSVC++ compiled DLL's for which I have created COM-like (lite) interfaces (abstract Delphi classes). Some of those classes have methods that need pointers to objects. These C++ methods are declared with the __thiscall calling convention (which I cannot change), which is just like __stdcall, except a this pointer is passed on the ECX register.

I create the class instance in Delphi, then pass it on to the C++ method. I can set breakpoints in Delphi and see it hitting the exposed __stdcall methods in my Delphi class, but soon I get a STATUS_STACK_BUFFER_OVERRUN and the app has to exit. Is it possible to emulate/deal with __thiscall on the Delphi side of things? If I pass an object instantiated by the C++ system then all is good, and that object's methods are called (as would be expected), but this is useless - I need to pass Delphi objects.

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++ 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;
};

Delphi Side

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;

I would have half expected using stdcall alone to work, but something is messing up, not sure what, perhaps something to do with the ECX register being used? Help would be greatly appreciated.

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.

解决方案

Let us assume that you have created a MSVC++ class with VMT that maps perfectly into the VMT of a Delphi class (I have never done it, I just believe you that is possible). Now you can call the virtual methods of a Delphi class from MSVC++ code, the only problem is __thiscall calling convention. Since __thiscall is not supported in Delphi, the possible solution is to use proxy virtual methods on Delphi side:

UPDATED

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;

这篇关于将Delphi类传递给需要使用__thiscall方法的类的C ++函数/方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆