DLL 程序的入口函数是 DllMain(),就像 DOS 程序的入口函数是 main()、Win32 程序的入口函数是 WinMain() 一样。前面我们一直在讲的就是DOS程序。
DllMain() 函数的原型为:
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
);
其中:
- hModule 表示本DLL程序的句柄。
- ul_reason_for_call表示DLL当前所处的状态,例如DLL_PROCESS_ATTACH表示DLL刚刚被加载到一个进程中,DLL_PROCESS_DETACH表示DLL刚刚从一个进程中卸载。
- lpReserved 表示一个保留参数,目前已经很少使用。
一个简单的DLL程序并不比 “Hello World” 程序难,下面就开始介绍如何利用VC6.0创建DLL及其调用方式。
首先利用VC6.0新建一个 Win32 Dynamic-Link Library 类型的工程,工程取名为 dllDemo,并选择“An empty Dll project"选项,即创建一个空的动态链接库工程。然后,为该工程添加 一个C源文件 main.c,并在其中编写完成加法运算和减法运算的函数,代码如下所示:
#include <objbase.h> // 也可以 #include <windows.h>
#include <stdio.h>
_declspec(dllexport) int add(int a, int b){
return a+b;
}
_declspec(dllexport)int sub(int a, int b){
return a-b;
}
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
){
if(ul_reason_for_call == DLL_PROCESS_ATTACH){
printf("Congratulations! DLL is loaded!");
}
}
然后利用Build命令生成dllDemo这一动态链接库程序。之后,在该工程的Debug目录下, 可以看到有一个dllDemo.dll文件,这就是生成的动态链接库文件。
读者要记住,应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数。为了导出一些函数,需要在函数前面添加标识符 _declspec(dllexport)。
为了查看一个DLL中有哪些导出函数,可 以利用VC6.0提供的命令行工具Dumpbin来实现。
Dumpbin.exe文件位于VC6.0安装目录下的VC98\bin目录下。在该目录下还有 一个批处理文件VCVARS32.bat,该文件的作用是用来建立VC6.0使用的环境信息。如果读者在其他目录下无法执行Dumpbin命令,原因可能就是你的VC6.0安装的环境信息被破坏了,那么可以运行VCVARS32.bat这个批处理文件,之后在其他目录下,就可以 执行Dumpbin命令了。
注意:当在命令行界面下执行VCVARS32.bat文件后,该文件所设置的环境信息只是在当前命令行窗口生效。如果关闭该窗口,并再次启动一个新的命令行窗口后,仍需要运行VCVARS32.bat文件。
在命令行界面下,cd 到工程目录下的debug目录,输入dumpbin -exports dllDemo.dll 命令,然后回车,即可查看DLL中的导出函数,如下图:
注意红色方框标出的信息:
ordinal hint RVA name
1 0 00001005 add
2 1 0000100A sub
在这段信息中,“ordinal” 列列出的信息 ‘1’ 和 ‘2’ 是导出函数的序号;“hint” 列列出的数字是提示码,该信息不重要;“RVA” 列列出的地址值是导出函数在DLL模块中的位置,也就是说,通过该地址值,可以在DLL中找到它们;最后一列 “name” 列出的是导出函数的名称。
将 add 函数前面的 _declspec(dllexport) 标识符去掉,再次编译 dllDemo 工程,然后执行 dumpbin -exports dllDemo.dll 命令,输出如下图所示:
可以看到,add 函数已经不是导出函数了。
打开项目目录下的Debug目录,发现有 dllDemo.dll 和 dllDemo.lib 两个文件。上节已经说过,.lib 文件包含DLL导出的函数和变量的符号名,.dll 文件才包含实际的函数和数据。主程序调用 DLL 需要这两个文件,下节会讲解如何使用。
注意:DllMain() 函数在DLL程序载入和卸载时执行,可以用来做一些初始化和清理的工作,如果仅仅是向外暴露函数,就可以省略 DllMain() 函数。但是如果有 DllMain() 函数,就一定要 #include <objbase.h> 或 #include <windows.h>。
例如,上面DLL如果只想暴露 add() 和 sub() 函数,而不想进行其他操作,那么可以这样写:
_declspec(dllexport) int add(int a, int b){
return a+b;
}
_declspec(dllexport)int sub(int a, int b){
return a-b;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Dll 和 静态链接库 :
Dll也就是 动态链接库(Dynamic Link Library) 的简称,动态链接库 则是 一个可以被其它应用程序(.exe)共享的程序模块,其中封装了一些可以被共享的例程和资源 ,在应用程序调用时 调用库里面的资源 这就是Dll的动态。
静态链接库在 程序链接阶段 将源文件中用到的库函数与汇编生成的目标文件.o合并生成可执行文件 ,这回使得生成的可执行文件 过大,而且对库的修改 不方便,但是可移植性强。
Dll 的创建 :
1. 创建dll项目:dllDemo
2. 创建与(项目名相同的.cpp文件)同名的头文件:dllDemo.h
3. 写dll
dllDemo.h
#pragma once
#define dllDemo_API _declspec(dllexport)
dllDemo_API int add(int a, int b);
dllDemo_API int sub(int a, int b);
dllDemo.cpp
// dllDemo.cpp : 定义 DLL 应用程序的导出函数。
#include "stdafx.h"
#include "dllDemo.h"
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
4. 生成解决方案,在Debug中生成了dllDemo.dll
显示链接Dll
1. 创建空项目UsedllDemo
2. 把dll 添加到项目中,在UsedllDemo项目的UsedllDemo文件夹中新建一个Demo文件夹,把dllDemo中Debug文件里的dllDemo.dll复制到Demo文件夹中
注意:一定要放在这个Demo文件夹中,LoadLibrary 中的 路径 就是从这里开始(写绝对路径的话),最好再给dll整合到一个文件夹中 。
3. 写代码调用
创建main.cpp
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
typedef int(*fadd)(int a, int b);
typedef int(*fsub)(int a, int b);
HMODULE dll = LoadLibrary("Demo/dllDemo.dll");
cout << GetLastError() << endl; // 获得错误信息,如果缺少dll,报126,正确返回0
if (dll != NULL)
{
fadd add = fadd(GetProcAddress(dll, MAKEINTRESOURCE(1)));
if (add != NULL)
{
cout << add(2, 3) << endl;
}
fsub sub = fsub(GetProcAddress(dll, MAKEINTRESOURCE(2)));
if (sub != NULL)
{
cout << sub(5, 1) << endl;
}
FreeLibrary(dll);
}
system("pause");
return 0;
}
4. 运行
第一个0原因:cout << GetLastError() << endl; // 获得错误信息,如果缺少dll,报126,正确返回0
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果缺少dll文件,会报126错误,即dll文件并没有加入这个工程。在解决缺少dll文件时,利用InspectExe,可以查看到dll。
安装路径自定义下,一直下一步。
使用方式:
1.右键dll属性
2.点击inspectexe,查看