DLL的创建与使用
一、动态链接库(DLL)
动态链接库提供了一种方法,使进程可以调用不属于其执行代码的函数。函数的可执行代码位于一个.dll文件中,该文件包含一个或多个已被编译、链接并使用它们的进程分开存储的函数。
优点:
1.扩展了 应用程序的特性
2.可以使用多种编程语言来编写
3.简化项目的管理
二、依赖项
当某个程序或DLL使用其他DLL或DLL函数时,就会创建依赖项,因此程序就不会再独立了,依赖项如果被破坏,该程序可能出现问题。
三、入口点
在创建DLL时,可以有选择地指定入口点的函数。当进程或线程将它们自身附加到DLL或者将它们自身以DLL分离时,都会调用入口函数。入口函数应该只进行简单的初始化工作,而不应该调用其他DLL函数或者终止函数。
关于创建DLL,我的环境是VS2017,步骤为:文件->新建项目->选择动态链接库(DLL)->完成。在创建的项目中的源文件可以看到有一个已经创建好的dllmain.cpp,这个就DLL入口点的代码了。
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule, //模块句柄
DWORD ul_reason_for_call,//调用原因
LPVOID lpReserved //参数保留,好像没什么用
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //DLL被某个程序加载
case DLL_THREAD_ATTACH: //DLL被某个线程加载
case DLL_THREAD_DETACH: //DLL被某个线程卸载
case DLL_PROCESS_DETACH: //DLL被某个程序加载
break;
}
return TRUE;
}
四、如何导出(在DLL中实现的)
第一种:
步骤1:向所有需要导出的DLL函数中添加关键字__declspec(dllexport)。
步骤2:要在应用程序中使用导出的DLL函数,必须使用__declspec(dllexport)来声明要导入的各个函数。
本章使用的就是这种方法
通常最好使用一个包含define语句和ifdef语句的头文件,以便分隔导出语句和导入语句,代码如下。
说明:该DLL库实现的是简单的加减乘除运算,注意实现减法的这个函数,我这里特别使用了一个抽象类来实现,我发现有些企业代码都会有这种类似的抽象类,然后用纯虚函数做接口。
//__declspec(dllexport)修饰符指示编译器和链接器从
//DLL 导出函数或变量,以便其他应用程序可以使用它,在ExprotDll.h中
#pragma once
#ifdef EXPORTDLL_EXPORTS
#define EXPORTDLL_API __declspec(dllexport)
#else
#define EXPORTDLL_API __declspec(dllimport)
#endif //导出的类
class EXPORTDLL_API CExportDll {
public:
// TODO: 在此添加方法
//用纯虚函数做为接口
virtual int SUBTARCT(int a, int b) = ;
virtual ~CExportDll() {}; }; //导出函数,如果是在C++环境下,则执行"{" "}"中的内容
#ifdef __cplusplus
extern "C" {
#endif
EXPORTDLL_API CExportDll* Create();
EXPORTDLL_API void Destroy(CExportDll* ex);
#ifdef __cplusplus
}
#endif //也可用下列方法定义导出函数
extern "C" EXPORTDLL_API int nExportDll;
extern "C" EXPORTDLL_API int ADD(int a, int b);
extern "C" EXPORTDLL_API int MULTIPLY(int a, int b);
extern "C" EXPORTDLL_API float DIVIDE(float a, float b);
第二种:
创建模块定义文件.def以列出导出的DLL函数:
五、特别调用
需要注意以下一些情况:
1.如果使用了Win32 API,则应该使用关键字__stdcall修饰函数
2.如果将C++生成的DLL供标准C语言使用,输出文件用extern "C"来修饰,设置导出函数时采用.def文件形式,而不是__declspec(dllexport)
六、编写DLL
创建DLL工程并且定义了相应的导出函数、变量或类之后,接下来就是实现功能了。本章中因为CExportDll是一个抽象类,所以需要再创建一个它的子类(CExportDllChild.h中),实现相应的接口功能(EXportDll.cpp中),同时其他函数也在(EXportDll.cpp)中实现功能。
//ExportDllChild.h
#pragma once
#include "ExportDll.h" class CExportDllChild :public CExportDll
{
virtual int SUBTARCT(int a, int b);
virtual ~CExportDllChild() {};
};
// ExportDll.cpp : 定义 DLL 应用程序的导出函数。 #include "stdafx.h"
#include "ExportDllChild.h" //这是一个导出变量的一个示例
EXPORTDLL_API int nExportDll = ; //这是导出函数的几个示例
//当前使用的是C++编译出来的 //构造对象
EXPORTDLL_API CExportDll* Create()
{
return new CExportDllChild;
}
//析构对象
EXPORTDLL_API void Destroy(CExportDll* ex)
{
delete ex;
}
//加
EXPORTDLL_API int ADD(int a, int b)
{
return a + b;
}
//减
int CExportDllChild::SUBTARCT(int a, int b)
{
return a - b;
}
//乘
EXPORTDLL_API int MULTIPLY(int a, int b)
{
return a * b;
}
//除
EXPORTDLL_API float DIVIDE(float a, float b)
{
if (b != ) {
return a / b;
}
else
return -;
}
创建编写好后,进行生成,可以在项目Debugp目录下看到生成的动态库.dll和静态库.lib
七、调用DLL
调用DLL有两种方法,一种是显式链接方式,另一种是隐式链接方式。
在调用前,先创建一个Win32控制台应用程序或者MFC,这里创建的是一个简单的Win32程序(LoadDll)
1.显式链接:
在此项目中,需要将CExportDllChild.h放在LoadDll目录下。然后在cpp中添加以下代码
// LoadDll.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include "pch.h"
#include <Windows.h>
#include <iostream>
#include "ExportDll.h" /*-------------动态链接-------------*/
int main()
{
HMODULE hModule; //模块句柄
//定义函数指针
typedef int(*FUNC1)(int a, int b);
typedef CExportDll* (*CreateFun2)();
typedef void(*DestroyFun2)(CExportDll* ex);
typedef int(*FUNC3)(int a, int b);
typedef float(*FUNC4)(float a, float b);
//调用DLL,先找当前文件夹,如果没有,就会去system32下查找
hModule = ::LoadLibrary(L"ExportDll.dll"); if (hModule == NULL){
MessageBox(NULL, L"DLL加载失败", L"Mark", MB_OK);
}
//获取相应DLL函数的入口地址
FUNC1 add = (FUNC1)::GetProcAddress(hModule, "ADD");
CreateFun2 create = (CreateFun2)::GetProcAddress(hModule, "Create");
DestroyFun2 destroy = (DestroyFun2)::GetProcAddress(hModule, "Destroy");
FUNC3 multiply = (FUNC3)::GetProcAddress(hModule, "MULTIPLY");
FUNC4 divide = (FUNC4)::GetProcAddress(hModule, "DIVIDE");
//加
if (add != NULL){
std::cout << "a+b="<< add(, ) << std::endl;
}
//减
if (create&&destroy)
{
CExportDll* p = create();
std::cout << "a-b=" << p->SUBTARCT(, ) << std::endl;
destroy(p);
p = NULL;
}
//乘
if (multiply != NULL){
std::cout << "a*b=" << multiply(, ) << std::endl;
}
//除
if (divide != NULL)
{
std::cout << "a/b=" << divide(, ) << std::endl;
}
FreeLibrary(hModule); //释放句柄
return ;
}
调用结果:
2.隐式调用
在程序开始执行时就将DLL文件加载到应用程序中。隐式调用没用过,不做表述了。
DLL的创建与使用的更多相关文章
- simplest_dll 最简dll的创建与隐式调用(显式调用太麻烦,个人不建议使用)
首先需要有个头文件,名字随便写 假设test.h //test.h #ifndef _TEST_H #define _TEST_H #ifdef TEST_EXPORTS //通过宏定义控制是输入还 ...
- 关于DLL的创建与使用简单描述(C++、C#)
前言 前一段时间在学关于DLL的创建与调用,结果发现网络上一大堆别人分享的经验都有点问题.现在整理分享一下自己的方法. 工具 Microsoft Visual Studio 2017 depends ...
- Delphi中DLL的创建和使用(转)
Delphi中DLL的创建和使用 1.DLL简介: 2.调用DLL: 3.创建DLL: 4.两个技巧: 5.初始化: 6.例外处理. 1.DLL简介 ...
- 动态链接库DLL的创建生成及调用
一.背景 最近在做CANTOUSB底层驱动的调用,是调用别人已经封装好的库,看不到别人写的源程序.程序中调用的是隐式调用即 x.h+x.lib+x.dll,其中DLL即是动态链接库(Dynamic L ...
- Delphi DLL的创建、静态及动态调用
转载:http://blog.csdn.net/welcome000yy/article/details/7905463 结合这篇博客:http://www.cnblogs.com/xumenger/ ...
- Delphi中DLL的创建和使用
参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...
- C#中调用c++的dll具体创建与调用步骤,亲测有效~
使用的工具是VS2010哦~其他工具暂时还没试过 我新建的工程名是my21dll,所以会生成2个同名文件.接下来需要改动的只有画横线的部分 下面是my21dll.h里面的... 下面的1是自动生成的不 ...
- 在Dll中创建对话框并调用
1.第一步创建一“MFC AppWizard (dll)”工程,接下来选择“Regular Dll using shared MFC DLL”,点击“Finish”. 2.添加一对话框资源到工程中,从 ...
- 在DLL中创建窗口时一个值得注意的地方 — UnregisterClass
背景描述: 今天要测试一份注入代码,拿以前写的创建窗口的DLL来做测试. 第一次注入时一切正常,窗口被成功创建并显示,但在第二次加载时窗口没有显示出来. 经过研究发现在第二次加载DLL时Registe ...
随机推荐
- codevs 2804 最大最小数质因数 x
题目描述 Description 先输入n,n<=20;再依次输入n个不同的数,每个数<=1000000;找出最大数和最小数,并输出最大最小数的质 ...
- nu.random.seed()如何理解
结论: np.random.seed(a) # 按照规定的顺序生成随机数 # 参数a指定了随机数生成的起始位置: # 如果两处都采用了np.random.seed(a),且两处的参数a相同,则生成的随 ...
- sh_17_字符串的查找和替换
sh_17_字符串的查找和替换 hello_str = "hello world" # 1. 判断是否以指定字符串开始 print(hello_str.startswith(&qu ...
- 在CentOS 7上搭建WordPress
环境(ECS阿里云服务器) 服务器操作系统:CentOS 7.3 : 博客部署服务器:Apache HTTP: 数据库:MySql: 框架:WordPress: 步骤 一.安装 Apache HTTP ...
- JDK动态代理、CGLIB动态代理详解
Spring的AOP其就是通过动态代理的机制实现的,所以理解动态代理尤其重要. 动态代理比静态代理的好处: 1.一个动态代理类可以实现多个业务接口.静态代理的一个代理类只能对一个业务接口的实现类进行包 ...
- JavaScript数字计算精度丢失的问题和解决方案
一.JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加:0.1 + 0.2 != 0.3 // true,下图是firebug的控制台截图: 看看java的计算结果:是不是让你很不能接受 再来 ...
- Java 注解方式校验请求参数
1. 参数校验常用注解 注解 验证的数据类型 备注 Null 任意类型 参数值必须是 Null NotNull ...
- Samba windows 10 share: mount error(112): Host is down
Windows 10 Share File: //10.108.xx.xx/lnxvda-rf/ROBOT [root@rhels73 robot]# mount -t cifs -o usernam ...
- ReentrantLock源码探究1:非公平锁的获取和释放
1.AQS简单介绍 Sync是ReentrantLock的一个内部类,它继承了AbstractQueuedSynchronizer,即AQS,在CountDownLatch.FutureTask. ...
- JS字符串转换为JSON的方法
1.jQuery插件支持的转换方式: 示例: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象 2.浏览 ...