2. DLL程序:动态链接库DLL 和 在VS2017中创建dll和显示引用dll文件

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,查看
在这里插入图片描述
在这里插入图片描述

参考:https://blog.csdn.net/zbbzb/article/details/80049103

使用VS2015编译和调用动态链接库dll 1. 首先建工程,选择dll,记得勾上“导出符号” 后面不用自己搞那些宏定义会省事很多。 建立工程myDll,记得勾上“导出符号” 类型选择dll 2. IDE自动生成的代码已经把整个架构弄好了,其和项目同名的.h和.cpp文件就是我们自己写代码的地方了。我想写的dll是导出一个类,在这里我就直接在它自动生成的CmyDll类上面改了。 myDll.h myDll.cpp 在mydll.h和mydll.cpp给类添加成员函数 //mydll.h class MYDLL_API CmyDll { public: CmyDll(void); // TODO: 在此添加您的方法。 int myFunction(int a, int b); }; //mydll.cpp int CmyDll::myFunction(int a, int b) { return a*b; } 3.编译的时候我选择了release,这里可以用默认的debug也行 在mydll.h和mydll.cpp给类添加成员函数 最后生成解决方案后产生的mydll.lib和mydll.dll就是我们需要的二进制文件了。lib文件是编译是要用的,而dll是调用这个库的程序运行时需要的。 调用dll 1.重新建立一个工程 这回选择普通的控制台程序就行了。我建了个名为myDllCall的工程。 2.把库的头文件include进来,以及连接lib文件 include进来的 myDll.h 和 **#pragma comment()**的lib根据自己的路径写。 #include "stdafx.h" #include "../../myDll/myDll/myDll.h" //头文件 #pragma comment(lib,"../../myDll/Release/myDll.lib") //调用自己写的外部库 #include int main() { CmyDll mydll; int a, b; std::cin >> a >> b; std::cout << mydll.myFunction(a, b) <> a >> b; std::cout << mydll.myFunction(a, b) << std::endl; return 0; } 3.dll放到可执行文件同一目录下面 刚刚的代码直接编译没问题,运行会报错. 直接编译没问题,运行会报错 原因是dll要和生成的可执行文件在同一个目录下,我把mydll.dll放进去之后就解决了。 我们成功的在自己的工程里调用了外部的类 可以看到我们成功的在自己的工程里调用了外部的类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值