MFC下DLL/lib的调用

 1、简介:

dll和.lib都是程序集合,便于代码重用。都是二进制的文件。


.dll也叫动态链接库,与程序链接的方式为运行时链接(run-time linked),为PE(portable executable)格式,也就是程完整的程序。.exe、.dll、.fon、.mod、.drv、.ocx等等都是动态链接库。如.exe为系统调用的函数集合。.dll不存在同名引用,且有导出表,与导入表。


.lib也叫静态链接库,在编译时与程序链接(link-time linked),将“嵌入”到程序中。会有冗余(程序文件代码的冗余和运行时内存存储的冗余),当两个lib相链接时地址会重新建立同。在使用.lib之前,要在程序源代码中引用lib对应的头文件.h,这些头文件告诉编译器.lib中有什么。


在生成.dll时,通常会生成一个.lib。这个.lib将被编译到程序文件中,在程序运行的时候,告诉操作系统将要加载的.dll。这个.lib包括对应.dll的文件名、顺序表(ordinal table包含.dll暴露出的函数的进入点),在程序运行的时候,通过顺序表实现函数的跳转。


如果不想使用或者找不到该.lib,可以用LoadLibrary () Win32 API和GetLibrary () Win32 API。


VC IDE为了实现程序调试,会生成.PDB(程序数据库,二进制),里面包含源文件调用的文件信息和行信息。这样就可以逐行调试了。


打开.lib,查看其ascii码,可以看到如@@My_Function1123的函数名,这些名称在编译时被编译器运用mangling mechanism进行了名称的mangling。


在程序的编译过程中,如果出现如下错误“unresolved symbol _some_funtion@1234”,通常是因为找不到引用过的外部函数对应的.lib文件,或者是.c、.cpp源文件。



2、使用:

用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同。Windows提供了两种将DLL映像到进程地址空间的方法:

1、隐式的加载时链接

  这种方法需要DLL工程经编译产生的LIB文件,此文件中包含了DLL允许应用程序调用的所有函数的列表,当链接器发现应用程序调用了LIB文件列出的某个函数,就会在应用程序的可执行文件的文件映像中加入一些信息,这些信息指出了包含这个函数的DLL文件的名字。当这个应用程序运行时,也就是它的可执行文件被操作系统产生映像文件时,系统会查看这个映像文件中关于DLL的信息,然后将这个DLL文件映像到进程的地址空间。
  系统通过DLL文件的名称,试图加载这个文件到进程地址空间时,它寻找DLL 文件的路径按照先后顺序如下:
  ·程序运行时的目录,即可执行文件所在的目录;
  ·当前程序工作目录
  ·系统目录:对于Windows95/98来说,可以调用GetSystemDirectory函数来得到,对于WindowsNT/2000来说,指的是32位Windows的系统目录,也可以调用GetSystemDirectory函数来得到,得到的值为SYSTEM32。
  ·Windows目录

  ·列在PATH环境变量中的所有目录


  VC中加载DLL的LIB文件的方法有以下三种:
  ①LIB文件直接加入到工程文件列表中
  在VC中打开File View一页,选中工程名,单击鼠标右键,然后选中"Add Files to Project"菜单,在弹出的文件对话框中选中要加入DLL的LIB文件即可。
  ②设置工程的 Project Settings来加载DLL的LIB文件
  打开工程的 Project Settings菜单,选中Link,然后在Object/library modules下的文本框中输入DLL的LIB文件。
  ③通过程序代码的方式

   加入预编译指令#pragma comment (lib,"*.lib"),这种方法优点是可以利用条件预编译指令链接不同版本的LIB文件。因为,在Debug方式下,产生的LIB文件是Debug 版本,如Regd.lib;在Release方式下,产生的LIB文件是Release版本,如Regr.lib。

  当应用程序对DLL的LIB文件加载后,还需要把DLL对应的头文件(*.h)包含到其中,在这个头文件中给出了DLL中定义的函数原型,然后声明。

1.把你的youApp.DLL拷到你目标工程(需调用youApp.DLL的工程)的Debug目录下;
2.把你的youApp.lib拷到你目标工程(需调用youApp.DLL的工程)目录下;
3.把你的youApp.h(包含输出函数的定义)拷到你目标工程(需调用youApp.DLL的工程)目录下;
4.打开你的目标工程选中工程,选择Visual C++的Project主菜单的Settings菜单;
5.执行第4步后,VC将会弹出一个对话框,在对话框的多页显示控件中选择Link页。然后在Object/library modules输入框中输入:youApp.lib
6.选择你的目标工程Head Files加入:youApp.h文件;
7.最后在你目标工程(*.cpp,需要调用DLL中的函数)中包含你的:#include "youApp.h"
注:youApp是你DLL的工程名

01 //Dlltest.h
02     #pragma comment(lib,"MyDll.lib")
03     extern "C"_declspec(dllimport)intMax(inta,int b);
04     extern "C"_declspec(dllimport)intMin(inta,int b);
05 //TestDll.cpp
06 #include
07 #include"Dlltest.h"
08 voidmain()
09 {
10     int a;
11     a=min(8,10)
12     printf("比较的结果为%d\n",a);
13 }

  2、显式的运行时链接

  隐式链接虽然实现较简单,但除了必须的*.dll文件外还需要DLL的*.h文件和*.lib文件,在那些只提供*.dll文件的场合就无法使用,而只能采用显式链接的方式。这种方式通过调用API函数来完成对DLL的加载与卸载,其能更加有效地使用内存,在编写大型应用程序时往往采用此方式。这种方法编程具体实现步骤如下:
  ①使用Windows API函数Load Library或者MFC提供的AfxLoadLibrary将DLL模块映像到进程的内存空间,对DLL模块进行动态加载。
  ②使用GetProcAddress函数得到要调用DLL中的函数的指针。
  ③不用DLL时,用Free Library函数或者AfxFreeLibrary函数从进程的地址空间显式卸载DLL。

01{
02     HINSTANCE hDllInst = LoadLibrary("youApp.DLL");
03     if(hDllInst)
04     {
05         typedef DWORD (WINAPI*MYFUNC)(DWORD,DWORD);
06        MYFUNCyouFuntionNameAlias=NULL;
07        // youFuntionNameAlias 函数别名
08        youFuntionNameAlias= (MYFUNC)GetProcAddress(hDllInst,"youFuntionName");
09        // youFuntionName 在DLL中声明的函数名
10         if(youFuntionNameAlias)
11        {
12            youFuntionNameAlias(param1,param2);
13        }
14        FreeLibrary(hDllInst);
15     }
16 }

查看DLL里有哪些函数的工具:VC自带的DUMPBIN.EXE,运行方法:开始-vs-tools-开发人员命令提示,在命令行里输入 "dumpbin  [选项]  [dll的路径]"

用法: DUMPBIN [选项] [文件]

   选项:

/ALL 

显示除”code disassembly”以外的所有信息。可以使用/DISASM选项来显示”code 
disassembly”。使用/RAWDATA:NONE和/ALL去删除每个段中的二进制数据。 
 
/ARCHIVEMEMBERS 

 显示库中成员的基本信息。


/CLRHEADER file 
 公共语言运行时。可参考微软官网的相关信息。


/DEPENDENTS 
 显示出所依赖的DLLs的名字,但不显示导入函数的名字。


/DIRECTIVES 
 显示编译器产生的.drective(链接时的参数)段中的信息。


/DISASM 
 
显示代码段反汇编的结果。/DISASM should only be used on native (not managed) 
images.(大概意思:不能使用在微软的C++“标准“中)。


/ERRORREPORT[NONE | PROMPT | QUEUE | SEND ] 
 
如果dumpbin.exe在运行时失败,你能使用”/ERRORREPORT”这个参数去发送错误信息到
微软。


/EXPORTS 
 显示可执行文件或DLL中导出的所有信息。


/FPO 
 显示FPO( frame pointer optimization)记录。


/HEADERS 
 显示文件和每个段的头部信息。当使用一个库文件时,它显示的是每个成员对象的头部信息。


/IMPORTS[:file] 
 显示可执行文件或DLL文件中导入的DLL文件和它的函数列表。


/LINENUMBERS 
 
如果编译时使用了/Zi,/C7/Zd选项,行编号才存在于目标文件中,或者在连接时产生了调试信息是才能够显示行编号。


/LINKERMEMBER[:{1|2}] 
 这个选项显示定义在库中的全局符号。如果”1”被指定将以对象的顺序显示对象以及他们相应的偏移量,如果”2”被指定将显示偏移和对象成员的索引,然后以字母顺序排序。


/LINKERMEMBER[:{1|2}] 
 这个选项显示定义在库中的全局符号。如果”1”被指定将以对象的顺序显示对象以及他们相应的偏移量,如果”2”被指定将显示偏移和对象成员的索引,然后以字母顺序排序。


/LOADCONFIG 
 这个选项会显示”IMAGE_LOAD_CONFIG_DIRECTORY”结构体中的相关信息,这个结构体
是在文件加载时加载选项。


/OUT:filename  

这个选项将信息输出到指定的文件中。


/PDATA 
这个参数只对RISC处理器才有用。显示.pdata中的相关信息。


/RAWDATA [: { 1 | 2 | 4 | 8 | NONE [, number ]  ] 
 显示原始数据(比如.text段中的指令数据)。你可以使用下列参数来格式化输出。



/RELOCATIONS 
 显示对象中的重定位信息。


/SECTION:section 
 显示由”section”指定段中的信息。你可以使用”/HEADERS”选项去显示每个段的头部信息。


/SUMMARY 
 显示每个段的基本信息(段名和大小),如果其他选项没有指定这个选项是默认的。


/SYMBOLS 
 这个参数会显示COFF文件的符号表(用于连接时从定位的)。在所有的对象中都存在符号表。一个COFF文件中的符号表只有在连接时使用了”/DEBUG”时才显示。前两句话感觉有点矛盾原文是这样的: “Symbol tables exist in all object files. A COFF symbol table appears 
in an image file only if it is linked with /DEBUG”。


/TLS  
 显示一个来自可执行文件中的“IMAGE_TLS_DIRECTORY”结构体的信息,此结构定义在
Winnt.h中,也显示回调函数的地址。如果你的程序中没有使用线程私有储存空间(”thread local storage”,)这个镜像文件中是不会包含“IMAGE_TLS_DIRECTORY”的。


/UNWINDINFO 
这个选项只能使用于 Itanium处理器。


注:上面的每个选项在使用时都有这么一个选项——只用在编译时使用”/GL”选项生成的文件才能够使用”/HEADERS”这个选项


VS2012中 C++创建DLL图解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值