dll概述

一、概论
  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。
  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
   对动态链接库,我们还需建立如下概念:
 (1)DLL 的调用与具体的编程语言及编译器无关
  只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。
 (2)动态链接库随处可见
  我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这三个DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面; gdi32.dll中的函数则负责图形方面的操作。
  (3)VC动态链接库的分类
  Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。本文只介绍非MFC动态库。
  非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。
  (4)DLL内的函数分类
   DLL内的函数分为两种:
   a.DLL导出函数,可供应用程序调用;
  b.DLL内部函数,只能在DLL程序使用,应用程序无法调用它们。
    当然c++中除了函数还可以导出类。
  (5)加载DLL的方式
    加载DLL有两种方式:

    a.显式加载:由“LoadLibrary-GetProcAddress-FreeLibrary”系统Api提供的三位一体“DLL加载-DLL函数地址获取-DLL释放”方式,这种调用方式称为DLL的动态调用。动态调用方式的特点是完全由编程者用 API 函数加载和卸载 DLL,程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。
    b.隐式加载:由编译系统完成对DLL的加载和应用程序结束时 DLL 的卸载。当调用某DLL的应用程序结束时,若系统中还有其它程序使用该DLL,则Windows对DLL的应用记录减1,直到所有使用该DLL的程序都结束时才释放它。静态调用方式简单实用,但不如动态调用方式灵活。
二、操作步骤

I、导出库函数
a.创建动态链接库项目:
1、打开Microsoft Visual Studio 2010,选择File->New->Project。
2、在New Project中选择Installed Templates->Visual C++->Win32。
3、选择Win32 Console Application,设置名称:lib_dll,设置解决方案名:test_dll。
4、单击OK,在出现的Win32 Application Wizard的Overview对话框中点击Next。
5、在Application Settings中,选择Application type下的DLL。
6、勾选Additional options下的Empty project。
7、单击Finish创建项目。
b.添加函数
1.创建头文件lib.h
#ifndef LIB_H
#define LIB_H
extern "C"  __declspec(dllexport) int add(int x, int y);
#endif
2.创建源文件lib.cpp
#include "lib.h"
int add(int x, int y)
{
 return x + y;
}
完成后对lib_dll进行生成(右键点击lib_dll->生成)。
c.在test_dll中创建一个新项目use_dll(win32控制台应用程序)

显式加载:
1.创建源文件main.cpp

#include
#include
#include
using namespace std;

typedef int(*lpAddFun)(int, int); //宏定义函数指针类型

int main(char argc, char**argv)
{
 HMODULE hDll;//DLL句柄
 lpAddFun addFun; //函数指针
 hDll = LoadLibrary(_T("lib.dll"));
 if (hDll != NULL)
 {
  addFun = (lpAddFun)GetProcAddress(hDll, "add");
  if (addFun != NULL)
  {
   int result = addFun(2, 3);
   cout<<result;
  }
  FreeLibrary(hDll);
 }
 return 0;
}
完成后运行即可。
隐式加载:
将main.cpp的内容改为如下:
#pragma comment(lib,"dllTest.lib")
//.lib文件中仅仅是关于其对应DLL文件中函数的重定位信息

extern "C" __declspec(dllimport) add(int x,int y);

int main(int argc, char* argv[])
{
 int result = add(2,3);
 printf("%d",result);
 return 0;
}
--------------------------
II、导出类
a.创建动态链接库项目:
  步骤相同。
b.向动态链接库添加类:
1、添加新类头文件simpledll.h
//------------------ simpledll.h ----------------

#pragma once;
#ifdef DLL_IMPLEMENT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
//导出类
class DLL_API SimpleDll
 {
 public:
  SimpleDll();
  ~SimpleDll();
  int add(int x, int y);
 };
2、添加新类源文件simpledll.cpp
//------------------ simpledll.cpp ----------------
#define DLL_IMPLEMENT
#include "simpledll.h"
SimpleDll::SimpleDll()
{

}

SimpleDll::~SimpleDll()
{

}

int SimpleDll::add(int x, int y)
{
 return x+y;
}
完成后点击生成。
c.创建一个win32控制台应用程序。
1.添加main.cpp
//------------------ main.cpp -------------------
#include "simpledll.h"
#include
using namespace std;

int main(char argc, char**argv)
{
 SimpleDll sd;
 cout << "sd.add: 3+5=" << sd.add(3, 5)<<endl;
    return 0;
}
2、引用simpledll项目。右键单击usesimpledll项目,选择Properties->Common Properties->Framework and References。点击Add New Reference,选择simpledll项目,单击OK。
3、设置头文件路径。选择Properties->Configuration Properties->VC++ Directories。在Include Directories项添加$(SolutionDir)\simpledll\,选择应用,确定。
4、设置usesimpledll项目为活动项目。右键单击usesimpledll项目,选择Set up StartUp Project。
5、生成解决方案。

附:
下面对涉及到的一些知识点进行问答式解说:

1.导出函数的头文件中为什么要加:extern "C"  __declspec(dllexport) int add(int x, int y);?
答:
extern"C"的意思是将其后声明的函数按照C语言的语法进行编译,也就是不改变函数的名称。否则在c++下编译会改变函数的名称。__declspec(dllexport)的意思是其后声明的函数是一个DLL中要导出的函数,要将该函数的地址信息放入lib文件中,供其它应用程序调用。
2. HMODULE是什么?
答:HMODULE 是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。也可以用HINSTANCE代替,HINSTANCE 在win32下与HMODULE是相同的东西。使用HMODULE必须包含windows.h头文件。
在头文件中HMODULE定义如下:
typedef HINSTANCE HMODULE;
再看看HINSTANCE定义,
typedef HANDLE HINSTANCE;
再看看HANDLE定义,
typedef PVOID HANDLE;
再看看PVOID定义,
typedef void *PVOID;
其实这些都可以称为句柄,为了表述的方便,所以对于不同类型的句柄都用不同样式的typedef,比如说HINSTANCE表示实例句柄,HMODULE是模块句柄,实际上他们本质上都是VOID指针,是可以指向任何类型的指针。
3.loadlibrary,GetProcAddress,FreeLibrary是什么?
答:由“LoadLibrary-GetProcAddress-FreeLibrary”系统Api提供的三位一体“DLL加载-DLL函数地址获取-DLL释放”方式,这种调用方式称为DLL的动态调用。动态调用方式的特点是完全由编程者用 API 函数加载和卸载 DLL,程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。使用这三个API必须包含windows.h头文件。
hDll = LoadLibrary(_T("lib.dll"));//加载动态链接库lib.dll给模块句柄dDll.
addFun = (lpAddFun)GetProcAddress(hDll, "add");//获取模块中函数指针。
FreeLibrary(hDll);//卸载DLL库
4._T("")是什么?
答:它是一个宏,定义于tchar.h下,hDll = LoadLibrary(_T("lib.dll"));VS2010采用UNICODE编码,他的作用是让你的程序支持Unicode编码方式。
如果不加会报如下错误:IntelliSense: "const char *" 类型的实参与 "LPCWSTR" 类型的形参不兼容。
5.#ifdef DLL_IMPLEMENT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
的作用是什么?

 答:在源文件中包含.h,如果源文件中定义了DLL_API  ”_declspec(dllexport)“(必须位于DLL库的.H之前)那么在.h中就不定义了,可以用于导出函数的声明,而如果在调用dll的程序中包含这个头就可以,因为程序中没有定义DLL_API,所以DLL_API被定义为 "_declspec(dllimport)" 这时作为导入函数的声明了,这是一个非常巧妙的设置方法。
6.隐式加载和显式加载的步骤如何?
显式加载参考问题3.
隐式加载:
a.告诉编译器与DLL相对应的.lib文件所在的路径及文件名,#pragma comment(lib,"simpledll.lib")就是起这个作用。当然首先要将生成的dll和lib文件放在使用它的项目文件夹下。
b.声明导入函数,extern "C" __declspec(dllimport) int add(int x,int y)语句中的__declspec(dllimport)发挥这个作用.静态调用方式不再需要使用系统API来加载、卸载DLL以及获取DLL中导出函数的地址。这是因为,当程序员通过静态链接方式编译生成应用程序时,应用程序中调用的与.lib文件中导出符号相匹配的函数符号将进入到生成的EXE 文件中,.lib文件中所包含的与之对应的DLL文件的文件名也被编译器存储在 EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows将根据这些信息发现并加载DLL,然后通过符号名实现对DLL 函数的动态链接。这样,EXE将能直接通过函数名调用DLL的输出函数,就象调用程序内部的其他函数一样

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值