VS2017创建DLL动态链接库,并隐式与显式调用

VS2017创建DLL动态链接库,并隐式与显式调用


一、DLL基础知识

动态链接库(dynamic-link library,DLL),Windows应用程序编程接口(API)提供的所有函数都包含在DLL中。其中三个最重要的DLL分别是:Kernel32.dll,包含的函数用来管理内存、进程以及线程;User32.dll,包含的函数用来执行与用户界面相关的任务,如创建窗口和发送消息;GDI32.dll,包含的函数用来绘制图像和显示文字。著名的ActiveX技术也是基于这种运行时加载机制实现的。
Winows下的DLL文件和EXE文件实际上是一个概念,它们都是PE格式的二进制文件,稍微有些不同的是PE文件头部中有个符号位表示该文件是EXE或是DLL。需要通过在链接开关进行控制,来告诉编译器编译成DLL或者EXE。
DLL通常由一组可供任何应用程序使用的独立函数组成。在DLL中,通常没有用来处理消息循环或创建窗口的代码。DLL只不过是一组源代码模块,每个模块包含一些可供应用程序(可执行文件)或其他DLL调用的函数。

二、VS2017生成dll

1.新建空白项目,新建.h头文件MyDLL.h

代码如下):

#pragma once

// 使用__declspec(dllexport)告诉编译器我们对外暴露的函数以及全局变量
__declspec(dllexport) int ans = 10;
__declspec(dllexport) int Add(int, int);

2.编写对应的c++文件MyDLL.cpp

代码如下(示例):

#include"MyDLL.h"

int Add(int a, int b) {
	ans = a + b;
	return ans;
}

3.修改配置,将默认生成exe改成生成dll

右键项目->属性->常规->配置类型改成动态库dll
在这里插入图片描述
右键生成,即可生成dll文件,同时还有符号表文件.lib文件(如果链接器检测到DLL的源文件输出了至少一个函数或变量,那么链接器还会产生一个.lib文件。这个.lib文件非常小,它只是列出了所有被导出的函数和变量的符号名。为了构建可执行模块,这个文件时必须的。)

在这里插入图片描述

三、 隐式调用dll文件

vs隐式调用dll文件十分简单

1 新创建空白项目,将上一步生成的.lib,.dll以及MyDLL.h均拷贝到当前项目文件夹下

在这里插入图片描述

2.编写代码,隐式调用dll 不要忘记#include "MyDLL.h"头文件

静态调用方式的特点是由编译系统完成对DLL的加载和应用程序结束时DLL的卸载。当调用某DLL的应用程序结束时,若系统中还有其它程序使用该DLL,则Windows对DLL的应用记录减,直到所有使用该DLL的程序都结束时才释放它。静态调用方式简单实用,但不如动态调用方式灵活。
静态调用方式不再需要使用系统API来加载、卸载DLL以及获取DLL中导出函数的地址。这是因为,当程序员通过静态链接方式编译生成应用程序时,应用程序中调用的与.lib文件中导出符号相匹配的函数符号将进入到生成的EXE 文件中,.lib文件中所包含的与之对应的DLL文件的文件名也被编译器存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows将根据这些信息发现并加载DLL,然后通过符号名实现对DLL 函数的动态链接。这样,EXE将能直接通过函数名调用DLL的输出函数,就像调用程序内部的其他函数一样。
(必须把DLL工程的.h, .lib, .dll文件放在EXE工程文件夹下):

#include"MyDLL.h"
#include<iostream>
using namespace std;

int main() {

	int c = Add(10, 5);
	cout << "Add():" << c << endl;
	cout << "ans:" << ans << endl;
	system("pause");
	return 0;
}

运行即可调用DLL

在这里插入图片描述

3、显式调用dll

可以让程序自己在运行时控制加载指定的模块,并且可以在不需要该模块时将其卸载。当程序需要用到某个插件或者驱动的时候,才将相应的模块装载进来,而不需要从一开始就将他们全部装载进来,从而减少了程序启动时间和内存的使用。

#include <windows.h>
#include <iostream>
//显示调用DLL (运行时加载)

typedef int(*lpAddFun) (int, int);
using namespace std;
//需要使用系统API来加载、卸载DLL以及获取DLL中导出函数的地址。
int main(int argc, char* argv[])
{
	HINSTANCE hDll; //DLL句柄
	lpAddFun addFun; //函数指针
//进程中的每个DLL模块被全局唯一的字节的HINSTANCE句柄标识,只有
//在特定的进程内部有效,句柄代表了DLL模块在进程虚拟空间中的起始地址
	hDll = LoadLibrary("CreateDLL.dll");
	//(用来装载一个DLL到进程的地址空间)
	if (hDll != NULL)
	{
		cout << "dLL 加载成功" << endl;
		//(用来查找某个符号的地址)
				//addFun = (lpAddFun)GetProcAddress(hDll, "Add");
		addFun = (lpAddFun)GetProcAddress(hDll,MAKEINTRESOURCE(1));
		if (addFun != NULL)
		{
			int result = addFun(2, 3);
			std::cout << "addFun(2, 3) = " << result << std::endl;
		}
		else {
			cout << "函数加载失败" << endl;
		}
		FreeLibrary(hDll); //(用来卸载某个已加载的模块)
	}
	system("pause");
	return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值