天天看點

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,使保持一緻。