lib文件和dll文件是什么数据
lib文件: 存放的是代码,还没有被编译, <相当如储存了一些函数, C++库函数也是由lib文件构成>
dll文件: 存放的是已经编译好的数据, 可以直接LoadLibrary()调用
静态链接库
静态链接库的编写:
(1) 创建一个lib工程
(1.1) 然后写代码,
(1.2) 生成lib文件
(1.3) 把生成的lib文件和头文件给别人, 别人就能调用了
静态链接库的使用要求:
(1) 需要一个头文件和一个 xxx.lib文件
静态链接库的使用:
(1) 添加头文件
(2) #pragma comment(lib, "xxx.lib")
优点: 实现了代码重用, 很方便, 是一个二进制文件
缺点: (1) 直接把代码编译到了EXE里面了, 不能动态替换
(1) 分不清是我们写的代码还是xx.lib文件里的代码
(2) 不便如修改, 例如: 修改xx.lib文件有缺陷, 需要修改, xx.lib文件修改了, exe文件也需要修改<而DLL不需要>
动态链接库 <基于__stdcall, 默认的__cdecl很简单>
Dll编写:
(1) 创建项目 -> Win32项目 -> 选择DLL -> 去掉预编译头
(2) DllMain()函数的第二个参数为加载这个模块的原因 < DLL_PROCESS_ATTACH 为被加载, 现在可以执行代码>
(3)
导出函数:
(1) //头文件定义 extern "C" __declspec(dllexport) 返回值 __stdcall 函数名(参数···);
(2) //CPP实现 extern "C" __declspec(dllexport) 返回值 __stdcall 函数名(参数···){ return 函数代码;}
导出变量:
(1) //头文件定义 extern __declspec(dllexport) 类型 变量名;
(2) //CPP实现 __declspec(dllexport) 类型 变量名 = 0;
导出类Class:
(1) //头文件定义
class __declspec(dllexport) 类名 {
public:
类名(void);
};
(2) //CPP实现
类名::类名() { return;}
(4) 生成文件, 生成了一个DLL和一个lib文件
注意:
(1) 一般DLL使用 __stdcall <内平栈>
(2) 取消C++函数重载: extern "C"
(3) _stdcall方式调用会改变导出函数名, 需要配置def文件
(3.1) 创建def文件: 项目右键 -> 新建项目 -> vc++ -> 代码 -> def文件
(3.2) 取消__stdcall调用改变, 编译器改变函数名
LIBRARY DLL文件名 //def文件中添加这些代码
EXPORTS
函数名 @ 1
DLL调用之隐式调用
(1) 把 DLL 和 Lib文件复制到工程目录
(2) (2.1) 导入头文件
(2.2) 没有头文件: 声明函数: extern "C" __declspec(dllimport) 返回值 __stdcall 函数名(参数···);
(3) 导入静态库: #pragma comment(lib,"xx.lib")
(4) 直接就可以调用这个DLL中函数了
DLL调用之显示调用
(1) typedef int(*pFun )(); // 定义函数指针类型
(2) // hDll : DLL的加载基址
HMODULE hDll = LoadLibrary(L"xx.dll");
(3) pFun pfnFun = nullptr ; // 函数指针类型的变量
// 1.2 获取DLL中的函数的地址
pfnFun = (pFun)GetProcAddress(hDll , "函数名");
(4)// 1.3 调用函数
pfnFun();
(5) //1.4 释放DLL
FreeLibrary(hDll);
__stdcall 和 __cdcall
(1) __stdcall是: 在函数内部平栈
(1.1) 改变了导出函数名, 改为 (_函数名@8)<不确定>
(2) __cdcall是: 在函数外部平栈
DLL调试
自己的EXE和DLL
(1) 创建一个EXE工程
(2) 如果DLL项目也在同一个解决方案,
<F11 DLL导出函数就能进去DLL的源代码>
(3) DLL工程必须和EXE工程必须在一起
别人的EXE, 自己的DLL <写插件>
(1) 将EXE
(2) 将使用DLL文件的EXE路径填入
项目 -> 属性 -> 调试 -> 命令
(3) 然后直接调试