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 ...
随机推荐
- 洛谷 P1341 无序字母对(欧拉路)
P1341 无序字母对 题目提供者yeszy 标签 福建省历届夏令营 难度 提高+/省选- 最新讨论 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造 ...
- win7系统扩展双屏幕时,开启两个屏幕下都显示任务栏,第三方插件
Dual Monitor Taskbar 下载软件 下载地址 https://dual-monitor-taskbar.en.softonic.com/ 安装即可
- Another Filling the Grid
E. Another Filling the Grid 参考:Codeforces Round #589 (Div. 2)-E. Another Filling the Grid-容斥定理 容斥这个东 ...
- [CSP-S模拟测试]:任务分配(最短路+贪心+DP)
题目传送门(内部题149) 输入格式 每个测试点第一行为四个正整数$n,b,s,m$,含义如题目所述. 接下来$m$行,每行三个非负整数$u,v,l$,表示从点$u$到点$v$有一条权值为$l$的有向 ...
- tomcat配置加密的连接器https
对称加密:加密和解密用的是同样的密钥. 非对称加密:使用一对密钥,公钥和私钥,私钥只由一方保管,不能外泄:公钥可以发给任何请求它的人 那么得到公钥的一方怎么确定这个公钥是服务器发过来的呢? 这个就需要 ...
- IDEA内存设置
之前,博主的idea一直运行正常,今天,开发了一个接口,因为接口在项目中另一个模块,之前从来没有启动过这个模块,由于调试接口将该模块也放到tomcat容器中,结果我的idea不停崩溃,于是查看idea ...
- vue问题六:计算属性,依赖发生变化时,重新计算computed:
<el-form-item label="单价:" prop="price" > <el-input v-model="addfor ...
- adb shell am start -W查看APP启动时间(优化冷启动)
ThisTime:最后一个启动的Activity的启动耗时: TotalTime:自己的所有Activity的启动耗时: WaitTime::ActivityManagerService启动App的A ...
- 一个好的关于计算文件大小,及使其便于阅读的方法(php)
public function getReadableFileSize($retstring=null){ $sizes = array('byte','kB','MB','GB','TB','PB' ...
- 【转】hbase meta表修复
[From]https://www.iteye.com/blog/blackproof-2052898 meta表修复一 查看hbasemeta情况 hbase hbck .重新修复hbase met ...