首页 > 编程语言 >【win编程0003】- 动态库

【win编程0003】- 动态库

时间:2023-01-02 00:22:28浏览次数:48  
标签:函数 lib 0003 win 编程 导出 dll 全局变量 加载

 

动态链接库(dynamic link library)介绍

代码放到exe中,肯定会造成磁盘冗余; 电脑ABCD四个软件,lib加入到代码中不是在编译期进入的,而是在运行期 (A进程启动,把dll加入到A进程中……),编译的时候不需要这份代码, 后缀是.dll

如果要更新软件,把dll换掉就可以了,所有软件都会跟着更新

 

分析DLL的工具

.dll中凡是能给外面用的函数叫 导出函数;

这个工具能看导出函数;

调win api的时候跟不到源码中,因为放到了dll中了

 

 

动态库的创建

 

文件导入并去掉宏,宏在静态库和动态库表现不一致

 

直接编译,生成dll文件,dll文件用工具打开, 然而并没有导出函数显示

 

导出函数

编译之后,用工具打开发现 默认的没有导出函数, 需要手动指定后,才导出;

就像类一样,默认时私有的;

用编译器命令导出

 

注意细节1:

两个cpp文件中把头文件注释掉了,编译之后,在工具中发现没有导出函数,为什么?

.h在预处理时期,预编译时把头文件中东西拷贝到.cpp文件中,没有包含头文件就没有导出函数了

 

注意细节2:

再把头文件加上,有了导出函数之后,编译之后生成了lib; 这里和静态的lib有区别,这里文件大小2kb;

这里只是一个描述性的lib,里面没有代码,这里描述dll中有哪些导出函数,是给开发者使用的

 

 

使用dll

使用dll, 头文件的这里改成dllimport, 告诉编译器这里用的是dll中的函数;

编译有误,找不到函数是在哪个dll文件中;

 

 

问题: 一个.cpp 两个.h声明,通过这些能判断这两个函数要加载哪个dll吗?

此时就用到了描述性的lib文件,拷到目录下(类似Makefile)

和静态的lib用法相同

编译的时候不需要dll,运行的时候需要;这里是运行状态; dll拿出来放到Debug文件里

 

1-导出全局变量

全局变量可以导出

VS的bug: dll中的全局变量,在VS的监视窗口中看不到值

 

 

2-导出类

类可以导出

但这样写不能导出,报错内容如下:

这样写就可以了

工具输出的内容,上面两个是构造还是有重载,下面那个是自己写的类

 

这个时候断点跟源码,能跟到自己写的库里,因为调试信息都放到.pdb文件里了;把这个删了就跟不进去了;

 

 

导出和导出函数的宏处理

这个东西,每次要用都要改,文件多了就很麻烦,用宏给它安排下

源码中 : 把宏的开关放到这里,全局的宏放置的位置

 

 

 

 

工具里导出的都是C++的符号,如果C的呢?

 

 

 

隐式/显示加载方式

隐式加载方式:

lib + .h (函数 全局变量 类 都可以用)

 

显示加载方式:

Ollydebug中强大的是插件,很多的dll,使用某个功能的时候,就会去加载dll

Ollydebug发布的时候,有没有用人家写的插件dll的lib和.h?没有啊, 所以它的加载方式和这里隐式加载方式不同,Ollydebug是显示的加载方式;

并不知道别人写的插件叫啥名字,是怎么加载别人写的dll呢?

做法: 当前路径下的某个文件夹,遍历文件夹下后缀为.dll的文件,加载到进程; 这时候的加载,只要有个文件名和文件路径就可以加载,显示加载 (函数 全局变量 类(很麻烦))

 

 

使用dll,调用导出函数的方法(Ollydebug加载dll的做法)

加载dll(加载到进程内存中) -> 获取导出函数的地址 -> 然后调用(通过函数地址的方式调用)-> 从进程中卸掉dll

01加载dll的api

参数: 的module指的是 dll / exe(主模块) 的地址 ;

返回值: 模块句柄和HINSTANCE两个是等价的;

HINSTANCE是可执行文件exe在内存中的首地址

HMODULE是dll在内存中的首地址

作用: 把dll加载到进程内存中

code:

注意细节:

调用多个 loadLibrary, 不会调用多个dll,而是句柄引用计数的值会增加;

调用两个loadLibrary,也要有两个FreeLibrary才能卸载掉;

02获取函数地址

模块句柄还有函数名填进去,返回的就是函数地址;

code: 用的函数指针接收

注意全局变量:

如果要拿全局变量怎么访问? 这里拿到的是地址

全局变量这样访问,指针p保存的是地址 *p访问值

 

 

调用: 普通调用就行

一步一步调试看现象

03从进程中卸掉dll

code:

 

code

#include <iostream>
#include <windows.h>

using PFN_ADD = int(*)(int, int);

int main()
{
    HMODULE hDll = LoadLibrary(R"(C:\Users\Yuna\Desktop\CR2\windows\win01\UseDll\Debug\dll.dll)");
    if (NULL == hDll)
    { 
        std::cout << "加载失败" << std::endl;
        return 0; 
    }

    PFN_ADD pfnAdd = (PFN_ADD)GetProcAddress(hDll,"Add");
    if (NULL == pfnAdd)
    {
        std::cout << "获取函数地址失败" << std::endl;
        return 0;
    }

    int nRet = pfnAdd(1,4);
    int i = 0;  //为了调试上一句
    FreeLibrary(hDll);
} 

标签:函数,lib,0003,win,编程,导出,dll,全局变量,加载
From: https://www.cnblogs.com/awmking/p/17019311.html

相关文章

  • 23.0101 winter training.2
    A-BasicDiplomacy题意某人有n个朋友要出去m天,第i天可以选着\(a_i\)个朋友中的一个一起出去玩,每个朋友被选择的次数不能超过\(\lceilm\rceil\)问是否存在一种方案......
  • 狂神说Go语言—并发编程
    聊聊进程、线程、协程多线程上方左图所示:在主线程中为main方法左图的右边为test方法,在main方法中调用test方法,mian方法执行就会先去执行test方法,执行完后再回到main......
  • unix网络编程3.2——UDP(二)UDP可靠性传输1——KCP协议(上)
    目录系列文章unix网络编程1.1——TCP协议详解(一)unix网络编程2.1——高并发服务器(一)基础——io与文件描述符、socket编程与单进程服务端客户端实现unix网络编程2.2——高并......
  • unix网络编程3.3——UDP(三)UDP可靠性传输2——KCP协议(下)
    目录系列文章unix网络编程1.1——TCP协议详解(一)unix网络编程2.1——高并发服务器(一)基础——io与文件描述符、socket编程与单进程服务端客户端实现unix网络编程2.2——高并......
  • Linux 中 java 访问 windows共享目录
    有两个方案(本文介绍方案1的使用)1、将windows共享目录,挂载到linux系统下,通过使用本地目录访问windows共享目录2、通过samba的java实现包,不过需要开个windows共享目录的账......
  • acwing.1205 买不到的数目
    acwing.1205买不到的数目小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。小朋友来买糖的时候,他就用这两种包装来组合。......
  • Flink:状态编程
    Flink中的状态在流处理中,数据是连续不断到来的。每个任务进行计算处理时,可以基于当前数据直接转换得到输出结果,也可以依赖一些其他数据。这些由一个任务维护,并且用来计算......
  • winform控件缩写 (集合)
    winform控件缩写(集合)文章内所有的控件都是博主从网上辛苦整理出来的,希望对大家有用winform控件缩写(一)标准控件winform控件缩写(二)容器控件winform控件缩写(三)菜单和工具栏wi......
  • php面向对象(OOP)编程
    大多数类都有一种称为构造函数的特殊方法。当创建一个对象时,它将自动调用构造函数,也就是使用new这个关键字来实例化对象的时候自动调用构造方法。构造函数的声明与其它操......
  • putty中pscp命令实现windows和linux中文件的互传
     001、pscp命令的目录,在安装putty的目录,如下图:  002、在pscp目录下打开cmd命令:鼠标放置任意空白处,按住shift键,然后鼠标右击弹出对话框,选择在此处打开powershell选......