动态链接库

动态连接库(Dynamic link library),是一些编译过的可以执行的代码模块,后缀为.dll
1 DLL的基本理论
  在使用普通函数库时,可以在程序连接时将库中的代码拷贝到执行文件中,这时静态链接,在多个同样程序执行时,体统保留了许多
代码副本,造成了内存资源的浪费。在使用dll时,不必将dll链接到程序中,而是在应用程序运行时动态的装载dll,装载dll被映射
到进程的地址空间中。同时,使用dll 并不时将库代码拷贝,只是在程序中记录了函数的入口点和接口。
2 DLL 的优点
 1) 节省系统资源
 2) 不仅可以包括可执行代码,还可以包括数据和各种资源
 3)支持多语言
 4)升级可以仅仅覆盖dll 文件
 5)dll 独立编程语言,c++builder 中的dll vc 也可以使用
3导入导出匹配
    DLL函数一般有两种函数,内部函数(internal)和导出函数(export).在实际情况下,许多DLL 调用了其他DLL里面的函数,因此
DLL可以同时有导入和导出函数。
     DLL 包含有一个导出函数表,可以通过函数的符号化的名字和称为序号的正书来识别这些函数,函数表中包含了函数在dll内部的
地址。在动态链接进程好建立一张表,把客户的调用与dll里的函数的地址连接起来。
    double dbValue(value);//内部函数
    double dbValue(value);//内部函数
    extern"c" _declspec(dllexpoert) double changeValue(double,bool);//外部函数
   double dblValue(double value)
   {
       return value*vlaue;
   }
   double changeValue(double value,bool whichOp)
  {
     return whichOp?doublValue(value):halfValue(value);
   }
  如果我们希望dll可以用于其他语言或不同版本的c++ 需要在声明导出函数的时候加上extern "C."
 4 隐式的链接和显示的链接
   隐式链接(前面所讲)在创建dll 的时候,链接器产生一个lib 文件把拿获了dll中的导出符号和序号
   显示链接调用Win32 的LoadLibrary 函数,使用完后,调用 FreeLibrary.
 5 查找dll
   依次顺序为包含exe 的目录,进程的当前目录,Windows 目录,path 环境变量里列出的目录。
 6 创建动态链接库
   (如何查看dll 文件的定义)
 7 导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
    extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();
    extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数
    导出类:class __declspec(dllexport) ExportType ClassName{...}
    class __declspec(dllexport) __stdcall MyDllClass { //导出类
     public:
    MyDllClass();
    void CreateAForm();
    TDllFrm* DllMyForm;
    };

     __declspec(dllimport) class __stdcall MyDllClass {
       public:
       MyDllClass();
       void CreateAForm();
       TDllFrm* DllMyForm;
    };
    静态调用,build 生成dll 文件和lib 文件,并把lib 文件导入到工程中
     void __fastcall TForm1::Button1Click(TObject *Sender)
    { // 导出类实现,导出类只能使用静态方式调用
       DllClass = new MyDllClass();
       DllClass->CreateAForm();  
    }
    void __fastcall TForm1::Button2Click(TObject *Sender)
    { // 导出函数实现
       CreateFromFunct();
     }
     void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
         delete DllClass;
     }
   动态调用
   class TForm1 : public TForm
  {
         ...
      private: // User declarations
      void (__stdcall *CreateFromFunct)();
           ...
   }
  HINSTANCE DLLInst = NULL;
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {  
     if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
     if (DLLInst) {
             CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
                          "CreateFromFunct");
      if (CreateFromFunct) CreateFromFunct();
      else ShowMessage("Could not obtain function pointer");
   }
      else ShowMessage("Could not load DLL.dll");
  }
   void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
  {
     if ( DLLInst ) FreeLibrary (DLLInst);
  }
8  bcb 调用vc 编写的DLL
  1) 名字分解
   1. 名字分解:
  没有名字分解的函数
    TestFunction1 // __cdecl calling convention
    @TestFunction2 // __fastcall calling convention
    TESTFUNCTION3 // __pascal calling convention
    TestFunction4 // __stdcall calling convention
  有名字分解的函数
    @TestFunction1$QV // __cdecl calling convention
    @TestFunction2$qv // __fastcall calling convention
    TESTFUNCTION3$qqrv // __apscal calling convention
    @TestFunction4$qqrv // __stdcall calling convention
  使用 extern "C" 不会分解函数名
   2)
      __cdecl 缺省
   是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留
  它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。
    extaern "C" bool __cdecl TestFunction();
   在 def 文件中显示为
    TestFunction @1
   注释: @1 表示函数的顺序数,将在“使用别名”时使用。

  __pascal Pascal格式
   这时函数名全部变成大写,第一个参数先压栈,然后清栈。
    TESTFUNCTION @1 //def file

  __stdcall 标准调用
   最后一个参数先压栈,然后清栈。
    TestFunction @1 //def file

  __fastcall 把参数传递给寄存器
   第一个参数先压栈,然后清栈。
    @TestFunction @1 //def file
  3)
   3. 解决调用约定:
   Microsoft 与 Borland 的 __stdcall 之间的区别是命名方式。 Borland 采用
  __stdcall 的方式去掉了名字起前的下划线。 Microsoft 则是在前加上下划线,在
  后加上 @ ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个
  参数都舍入为 4 的倍数加起来。这种 Miocrosoft 的 DLL 与系统的 DLL 不一样。
 4 查看dll 的调用接口tdump -ee MyDll.dll >1.txt (查看 1.txt 文件即可)
5 编辑c++ builder build 为一个可以直接调用的 .exe 。 点击project option  中linker 标签 去掉user dynamic RTL 选项 和package 中 去掉builder with runtime package 选项.
6 调用代参数的vl 编写的dll 调用的实例。
int (__cdecl *fun)(char*,char*,char*);

HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( NULL == DLLInst )
{
DLLInst = LoadLibrary("HollyIVRCard.dll");
}
if(DLLInst)
{
  fun=(int (__cdecl*)(char*,char*,char*))GetProcAddress(DLLInst,"hTrade");
  if(fun)
  {
    cardid=Edit1->Text.c_str();
    num=Edit2->Text.c_str();
    ShowMessage(fun(cardid,num,res));
    //cout<<cardid<<endl;
    //cout<<num<<endl;
  }
} else{
   ShowMessage("load dll fail");
}
   ShowMessage(AnsiString(res));
}

posted on 2006-09-06 18:13 康文 阅读(380) 评论(0)  编辑  收藏 所属分类: c\c++


只有注册用户登录后才能发表评论。


网站导航:
 
<2006年9月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜