在Delphi中如何调用C++动态链接库中输出的类 (200分)

  • 主题发起人 主题发起人 superlg
  • 开始时间 开始时间
S

superlg

Unregistered / Unconfirmed
GUEST, unregistred user!
用C++实现的一个输出类的动态链接库,怎样在Delphi中使用这些输出的类?
比如这个用C++实现的类(类的声明):
#ifndef __SIMPLY_INC__
#define __SIMPLY_INC__

#ifdef __EXPORTS__
#define CLASS_IMPL __declspec( dllexport )
#else
#define CLASS_IMPL
#endif

class CLASS_IMPL HelloWorld {
private:
char message[1024];
public:
HelloWorld();
~HelloWorld();

void setMessage( char *msg );
int getMessageLen( void );
void sayHello( void );
void sayHello( char *msg );
};

#endif //__SIMPLY_INC__
 
我来试试!
你能把源程序发过来吗?To dbssbd@etang.com
 
怎么没人响应呢!!!
我在等结果呢!!!
 
c 编写的动态库要申明成按“PASCAL”规则编译 才能让别的语言共享,而且
如果里面用mfc类库写的也不能直接让别的语言共享,要在动态库中转换好

只要是windows 标准的动态库(.dll) delphi 都一样调用

如果那个(.dll)delphi没有调用成功 我觉得是 C 写的dll的问题
(我正为这个问题头疼,但就是没找到“PASCAL”规则的写法,找到了 也告诉我吧)
(catyy1101@263.net)

 
理论上将是应该可以实现的,可以考虑,C++/ObjPascal 都支持虚基类,
既都具有 vtab, 那么我使用Pascal 定义一个相同的 vtab, 通过一个
全局的函数来获取这个 vtab 就可以了,然后该类就能为Pascal使用。

让我们先从 C++ 的角度测试以下,测试的代码如下:

DLL(VC)
----------------------------------------------------------------
#ifndef __SIMPLY_INC__
#define __SIMPLY_INC__

#ifdef __EXPORTS__
#define CLASS_IMPL __declspec( dllexport )
#else
#define CLASS_IMPL
#endif

class CLASS_IMPL HelloWorld {
private:
char message[1024];
public:
HelloWorld();
~HelloWorld();

virtual void __cdecl setMessage( char *msg );
virtual int __cdecl getMessageLen( void );
virtual void __cdecl sayHello( void );
virtual void __cdecl sayHello( char *msg );
virtual void __cdecl free( void );
};

extern "C" CLASS_IMPL HelloWorld *GetHelloWorld( void );

#endif //__SIMPLY_INC__
--------------------------------------------------------------
#include <windows.h>
#include "simply.h"

HelloWorld::HelloWorld()
{
lstrcpy( message, "Hello World!" );
MessageBox( 0, "Constrcuct class", "HelloWorld::HelloWorld()", MB_OK );
}

HelloWorld::~HelloWorld()
{
MessageBox( 0, "Destory class", "HelloWorld::~HelloWorld()", MB_OK );
}

void HelloWorld::setMessage( char *msg )
{
lstrcpy( message, msg );
}

int HelloWorld::getMessageLen( void )
{
return lstrlen( message );
}

void HelloWorld::sayHello( void )
{
::MessageBox( 0, message, "void HelloWorld::sayHello( void )", MB_OK );
}

void HelloWorld::sayHello( char *msg )
{
::MessageBox( 0, msg, "void HelloWorld::sayHello( char *msg )", MB_OK );
}

void HelloWorld::free( void )
{
delete this;
}

extern "C" CLASS_IMPL HelloWorld *GetHelloWorld( void )
{
return new HelloWorld;
}
——————————————————————————————
下面是测试上面DLL的C++代码:(VC)
#include <windows.h>

class HelloWorld {
public:
virtual void __cdecl setMessage( char *msg );
virtual int __cdecl getMessageLen( void );
virtual void __cdecl sayHello( void );
virtual void __cdecl sayHello( char *msg );
virtual void __cdecl free( void )

};

extern "C" HelloWorld *GetHelloWorld( void );

int main( int argc, char *argv[] )
{
HelloWorld *hw;

hw = GetHelloWorld();
hw->sayHello();
hw->sayHello( "This is my message!" );
hw->setMessage( "Hello Supper Ligang!!!" );
hw->sayHello();
hw->free();

return 0;
}
运行结果是正确的。

然后我们用Borland C++Builder 做一个从C++ 到Pascal的中间测试,
既用C++Builder使用上面动态链接库的输出类:(C++Builder)
class HelloWorld {
public:
virtual void __cdecl setMessage( char *msg );
virtual int __cdecl getMessageLen( void );
virtual void __cdecl sayHello( char *msg );
virtual void __cdecl sayHello( void );
virtual void __cdecl free( void );
};
extern "C" HelloWorld *GetHelloWorld( void );

void __fastcall TForm1::Button1Click(TObject *Sender)
{
HelloWorld *hw;

hw = GetHelloWorld();
hw->sayHello();
hw->sayHello( "This is my message!" );
hw->setMessage( "Hello Supper Ligang!!!" );
hw->sayHello();
hw->free();
}
也是可以通过的,但你没有注意到,在C++Builder的HelloWorld
声明中 sayHello 两个成员函数的顺序和 VC 中的不同,我认为
可能是 vtab 的排序规则不同(???????????????????????????)。

现在再试一下Pascal, 下面是Delphi关于vtab的描述:
The layout of a VMT is shown in the following table.
At positive offsets, a VMT consists of a list of 32-bit
method pointers梠ne per user-defined virtual method in
the class type梚n order of declaration. Each slot contains
the address of the corresponding virtual method抯 entry point.
This layout is compatible with a C++ v-table and with COM.
At negative offsets, a VMT contains a number of fields that
are internal to Object Pascal抯 implementation. Applications
should use the methods defined in TObject to query this information,
since the layout is likely to change in future implementations of
Object Pascal.
所以理论上是可行的:

HelloWorld = class(TObject)
public
procedure setMessage( msg:pchar )
virtual
cdecl
abstract;
function getMessageLen:Integer
virtual
cdecl
abstract;
procedure sayHello
overload
virtual
cdecl
abstract;
procedure sayHello( msg:pchar )
overload
virtual
cdecl
abstract;
procedure free
virtual
cdecl
abstract;
end;
PHelloWorld = ^HelloWorld;

function GetHelloWorld:PHelloWorld
cdecl
external 'simply.dll' name 'GetHelloWorld';

procedure TForm1.Button1Click(Sender: TObject);
var
hw: PHelloWorld;
begin
hw := GetHelloWorld();
hw.sayHello;
hw.sayHello( PChar('This is my message!') );
hw.setMessage( PChar('Hello Supper Ligang!!!') );
hw.sayHello;
hw.free;
end;

但是运行失败!!!WHY???
 
不知斑竹有何见解?
 
怎么还没反应呢,大富翁们都哪里去了???
 
>> PHelloWorld = ^HelloWorld;
>> function GetHelloWorld:PHelloWorld
cdecl
external 'simply.dll' name 'GetHelloWorld';

你没理解delphi的类,它本身已经是指针了,你又定义指针,当然错了
function GetHelloWorld:THelloWorld
cdecl
external 'simply.dll' name 'GetHelloWorld';
^^^^^^^^^^^^
只需要这样,应该可以了。

 
温柔一刀

你是对的!
 
多人接受答案了。
 
后退
顶部