天天看点

vc调用dev动态链接库的方法

由于不同的编译器对函数的命名方法不同,使跨编译器进行动态库调用变得困难。对于调用g++的一般函数,在dev编写库文件时,在头文件中函数前声明extern "C",然后可以直接在vc中调用,但这种方法对于类是不行的。

下面介绍两种调用导出类的方法。

1.我们利用vc可以调用普通函数库的能力,将类成员函数全部转化为普通函数进行调用,这种方法的缺点是调用麻烦,封装性不好。

2.类似COM原理,我们用dev建立一个中间dll库,然后让vc调用这个中间库。在该库中,在头文件中建立一个抽象类,抽象类中的成员函数为要调用的链接库中的类的成员函数,并声明为虚函数,另外添加两个普通函数,作为与外界的接口,得到一个对象的指针和释放该指针,然后在源文件中建立它的派生类,添加一个成员变量为要导入类的对象,重写基类的成员函数,实现时利用成员变量调用导入类的函数。

例如,我们有一个只有声明的类,和其实现的dll和动态导入库.a文件。

class DLLIMPORT Column

{

  public:

    Column(double r,double h);

    virtual ~Column(void);

    double GetArea();

    double GetVolume();

    void SetRadical(double r);

    void SetHeight(double h);

  private:

  double radical;

  double height;

};

然后建立一个中间库,调用原始库,头文件声明为

class baseColumn

{

  public:

     virtual double _stdcall GetArea()=0;

     virtual double _stdcall GetVolume()=0;

     virtual void _stdcall SetRadical(double r)=0;

     virtual void _stdcall SetHeight(double h)=0;

  private:

};

extern "C"{

       DLLIMPORT baseColumn* _stdcall new_Column(double r,double h);

       DLLIMPORT void _stdcall delete_Column(baseColumn* bc);

}

实现中,定义一个派生类

class ColumnImp1:public baseColumn

{

      private:

             Column m_Column;

       public:

              _stdcall ColumnImp1(double r,double h);

              virtual double _stdcall GetArea();

              virtual double _stdcall GetVolume();

              virtual void _stdcall SetRadical(double r);

              virtual void _stdcall SetHeight(double h);

 };

每个实现调用Column类的成员函数,

 _stdcall ColumnImp1::ColumnImp1(double r,double h):m_Column(r,h){}

 double _stdcall ColumnImp1::GetArea()

 {

     return m_Column.GetArea();

  }

  double _stdcall ColumnImp1::GetVolume()

 {

        return m_Column.GetVolume();

  }

  void _stdcall ColumnImp1::SetRadical(double r)

 {

        m_Column.SetRadical(r);

  }

  void _stdcall ColumnImp1::SetHeight(double h)

 {

       m_Column.SetHeight(h);

  }

实现普通接口函数,

  baseColumn* _stdcall new_Column(double r,double h)

  {

      return new ColumnImp1(r,h);       

   }

  void _stdcall delete_Column(baseColumn* bc)

  {

      delete bc;  

  }

在vc源程序中调用中间库,采用显式链接如下,

 typedef baseColumn* (*pc1)(double,double);

 typedef void (*pc2)(baseColumn*);

 HINSTANCE Hind=LoadLibrary("libvirclass.dll");

 pc1 f1=(pc1)GetProcAddress(Hind,"new_Column");

 pc2 f2=(pc2)GetProcAddress(Hind,"delete_Column");

 baseColumn* bc=f1(1,1);

 cout<<bc->GetVolume()<<endl;

 cout<<bc->GetArea()<<endl;

 bc->SetRadical(2);

 bc->SetHeight(2);

 cout<<bc->GetVolume()<<endl;

 cout<<bc->GetArea()<<endl;

 f2(bc);

需要注意的地方是在声明普通函数时前面添加 extern "C",指定采用c编译方式,在中间库中类的所有函数都指定为_stdcall函数调用约定,同样vc中默认调用约定为_cdecl,更改为_stdcall,使保持一致。