一、动态链接库(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的创建与使用的更多相关文章

  1. simplest_dll 最简dll的创建与隐式调用(显式调用太麻烦,个人不建议使用)

    首先需要有个头文件,名字随便写  假设test.h //test.h #ifndef _TEST_H #define _TEST_H #ifdef TEST_EXPORTS //通过宏定义控制是输入还 ...

  2. 关于DLL的创建与使用简单描述(C++、C#)

    前言 前一段时间在学关于DLL的创建与调用,结果发现网络上一大堆别人分享的经验都有点问题.现在整理分享一下自己的方法. 工具 Microsoft Visual Studio 2017 depends ...

  3. Delphi中DLL的创建和使用(转)

    Delphi中DLL的创建和使用     1.DLL简介:   2.调用DLL:   3.创建DLL:   4.两个技巧:   5.初始化:   6.例外处理.            1.DLL简介  ...

  4. 动态链接库DLL的创建生成及调用

    一.背景 最近在做CANTOUSB底层驱动的调用,是调用别人已经封装好的库,看不到别人写的源程序.程序中调用的是隐式调用即 x.h+x.lib+x.dll,其中DLL即是动态链接库(Dynamic L ...

  5. Delphi DLL的创建、静态及动态调用

    转载:http://blog.csdn.net/welcome000yy/article/details/7905463 结合这篇博客:http://www.cnblogs.com/xumenger/ ...

  6. Delphi中DLL的创建和使用

    参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...

  7. C#中调用c++的dll具体创建与调用步骤,亲测有效~

    使用的工具是VS2010哦~其他工具暂时还没试过 我新建的工程名是my21dll,所以会生成2个同名文件.接下来需要改动的只有画横线的部分 下面是my21dll.h里面的... 下面的1是自动生成的不 ...

  8. 在Dll中创建对话框并调用

    1.第一步创建一“MFC AppWizard (dll)”工程,接下来选择“Regular Dll using shared MFC DLL”,点击“Finish”. 2.添加一对话框资源到工程中,从 ...

  9. 在DLL中创建窗口时一个值得注意的地方 — UnregisterClass

    背景描述: 今天要测试一份注入代码,拿以前写的创建窗口的DLL来做测试. 第一次注入时一切正常,窗口被成功创建并显示,但在第二次加载时窗口没有显示出来. 经过研究发现在第二次加载DLL时Registe ...

随机推荐

  1. BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs

    题意 直接照搬原题面 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...

  2. su: Authentication failure 的解决方法

    su命令不能切换root,提示su: Authentication failure 原因是 没有设置过 root密码 sudo passwd root 会提示输入密码 重新输入密码 下次再su的时候只 ...

  3. (转)linux中wget未找到命令

    转:https://blog.csdn.net/djj_alice/article/details/80407769 在装数据库的时候发现无法使用wget命令,提示未找到命令,如图所示 那是因为没有安 ...

  4. cdn and fallback

    https://www.davepaquette.com/archive/2015/05/06/link-and-script-tag-helpers-in-mvc6.aspx It is a com ...

  5. mysql 更新存在就累加,不存在就插入语法

    INSERT INTO tb_http_tomcat_monitor_1 (id,total_res_time,total_req_count,req_dispose_count,queue_size ...

  6. Zabbix - 实现对磁盘动态监控

        回到目录 前言 zabbix一直是小规模互联网公司服务器性能监控首选,首先是免费,其次,有专门的公司和社区开发维护,使其稳定性和功能都在不断地增强和完善.zabbix拥有详细的UI界面和分组策 ...

  7. Linux的组成

    1.内核:是系统的心脏,是运行程序和管理像磁盘和打印机等硬件设备的核心程序. 2.Shell:是系统的用户界面,提供了用户和内核进行交互操作的一种接口.它接收用户输入的命令并把它送入内核去执行,是一个 ...

  8. JavaScript中的bind,call和apply函数的用法和区别

    一直没怎么使用过JavaScript中的bind,call和apply, 今天看到一篇比较好的文章,觉得讲的比较透彻,所以记录和总结如下 首先要理解的第一个概念,JavaScript中函数调用的方式, ...

  9. 内存数据库:memcached与redis技术的对比试验

    本文以高性能nginx服务器为应用背景,想利用缓存技术来减轻系统负荷,加快响应时间,从而增加web服务器的吞吐量. redis是一种分布式内存数据库,memcached是一种内存缓存技术,它们都采用k ...

  10. 使用gimp画线、矩形、圆等

    使用gimp画线.矩形.圆等 https://blog.csdn.net/tody_guo/article/details/7628508 2012年06月03日 19:08:47 Tody Guo  ...