MFC下DLL/lib的调用

来源:互联网 发布:mysql docker 编辑:程序博客网 时间:2024/04/29 04:59
 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中定义的函数原型,然后声明。

  2、显式的运行时链接

  隐式链接虽然实现较简单,但除了必须的*.dll文件外还需要DLL的*.h文件和*.lib文件,在那些只提供*.dll文件的场合就无法使用,而只能采用显式链接的方式。这种方式通过调用API函数来完成对DLL的加载与卸载,其能更加有效地使用内存,在编写大型应用程序时往往采用此方式。这种方法编程具体实现步骤如下:

  ①使用Windows API函数Load Library或者MFC提供的AfxLoadLibrary将DLL模块映像到进程的内存空间,对DLL模块进行动态加载。

  ②使用GetProcAddress函数得到要调用DLL中的函数的指针。

  ③不用DLL时,用Free Library函数或者AfxFreeLibrary函数从进程的地址空间显式卸载DLL。

 

调用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的工程名。

(二).动态调用其程序如下:
动态调用时只需做静态调用步骤1.
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 }

显式(静态)调用:
LIB + DLL + .H,注意.H中dllexport改为dllimport
隐式(动态)调用:
DLL + 函数原型声明,先LoadLibrary,再GetProcAddress(即找到DLL中函数的地址),不用后FreeLibrary

--------------------------------------
动态链接库DLL的链接
http://blog.donews.com/mmycly/archive/2006/06/15/917076.aspx

应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。Visual C++6.0在VC\bin目录下提供了一个名为Dumpbin.exe的小程序,用它可以查看DLL文件中的函数结构。另外,Windows系统将遵循下面的搜索顺序来定位DLL: 1.包含EXE文件的目录,2.进程的当前工作目录, 3.Windows系统目录, 4.Windows目录,5.列在Path环境变量中的一系列目录。

(一).隐式链接
隐式链接就是在程序开始执行时就将DLL文件加载到应用程序当中。实现隐式链接很容易,只要将导入函数关键字_declspec(dllimport)函数名等写到应用程序相应的头文件中就可以了。下面的例子通过隐式链接调用MyDll.dll库中的Min函数。首先生成一个项目为TestDll,在 DllTest.h、DllTest.cpp文件中分别输入如下代码:

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 }



在创建DllTest.exe文件之前,要先将MyDll.dll和MyDll.lib拷贝到当前工程所在的目录下面,也可以拷贝到windows的 System目录下。如果DLL使用的是def文件,要删除TestDll.h文件中关键字extern "C"。TestDll.h文件中的关键字Progam commit是要Visual C+的编译器在link时,链接到MyDll.lib文件,当然,开发人员也可以不使用#pragma comment(lib,"MyDll.lib")语句,而直接在工程的Setting->Link页的Object/Moduls栏填入 MyDll.lib既可。

编程时用ad.h,ad.lib,放在项目当前目录里
在头文件中加入#include "ad.h"
在Project Setting–>Link–>Object/library modules加入ad.lib
执行时将ad.dll跟你的程序放在同一目录

(二).显式链接
显式链接是应用程序在执行过程中随时可以加载DLL文件,也可以随时卸载DLL文件,这是隐式链接所无法作到的,所以显式链接具有更好的灵活性,对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态链接库调进来,动态链接库的文件名即是上述两个函数的参数,此后再用GetProcAddress()获取想要引入的函数。自此,你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Max函数的例子。

01 #include
02 #include
03 voidmain(void)
04 {
05     typedef int(*pMax)(inta,int b);
06     typedef int(*pMin)(inta,int b);
07     HINSTANCE hDLL;
08     PMax Max
09     HDLL=LoadLibrary("MyDll.dll");//加载动态链接库MyDll.dll文件;
10     Max=(pMax)GetProcAddress(hDLL,"Max");
11     A=Max(5,8);
12     Printf("比较的结果为%d\n"a);
13     FreeLibrary(hDLL);//卸载MyDll.dll文件;
14
 }


在上例中使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针,然后通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄,然后通过GetProcAddress()函数获取导入到应用程序中的函数指针,函数调用完毕后,使用 FreeLibrary()卸载DLL文件。在编译程序之前,首先要将DLL文件拷贝到工程所在的目录或Windows系统目录下。

使用显式链接应用程序编译时不需要使用相应的Lib文件。另外,使用GetProcAddress()函数时,可以利用 MAKEINTRESOURCE()函数直接使用DLL中函数出现的顺序号,如将GetProcAddress(hDLL,"Min")改为 GetProcAddress(hDLL, MAKEINTRESOURCE(2))(函数Min()在DLL中的顺序号是2),这样调用DLL中的函数速度很快,但是要记住函数的使用序号,否则会发生错误。

http://blog.csdn.net/tianmohust/article/details/6960942

个人结合上面的理解,感觉无论是动态链接还是静态链接都需要.dll文件,当为静态链接时同时需要dll及lib文件,动态链接只需要dll文件,而且在生成的exe运行时,其所在当前目录必须存在对应的dll文件,否则会提示找不到对应的dll。

感觉真是麻烦,如果能只用lib及对应的h文件多好





原创粉丝点击