文章目录
静态链接库
1.使用VS2019创建静态链接库
2.创建完成后结构如下
3.在pch.h添加声明
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H
// 添加要在此处预编译的标头
#include "framework.h"
int Plus(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
int Div(int x, int y);
#endif //PCH_H
4.在StaticTestLib.cpp里面添加实现代码
// StaticTestLib.cpp : 定义静态库的函数。
//
#include "pch.h"
#include "framework.h"
int Plus(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
5.新建需要添加lib的工程调用lib
// 源.cpp :
#include <iostream>
#include "pch.h"
#pragma comment (lib,"StaticTestLib.lib")
int main()
{
printf("%d", Plus(2, 1));
}
5.运行结果
静态链接库的缺点:
1.使用静态链接生成的可执行文件体积较大,造成浪费
2.我们常用的printf、memcpy、strcpy等就来自这种静态库
3.并不是真正意义上的模块化
动态链接库
1.使用VS2019创建动态链接库
2.创建完成后结构如下
3.新建一个类用来装你需要的函数
//TestDll.h
#pragma once
#include "pch.h"
#ifdef IMPORT_DLL
#else
#define IMPORTSTD_DLL extern "C" _declspec(dllexport)
#endif
IMPORTSTD_DLL int _stdcall Plus(int x, int y);
IMPORTSTD_DLL int _stdcall Sub(int x, int y);
IMPORTSTD_DLL int _stdcall Mul(int x, int y);
IMPORTSTD_DLL int _stdcall Div(int x, int y);
//这里楼主写了两种隐式链接没加_stdcall ,显示连接加了_stdcall
//TestDll.cpp
#include "pch.h"
#include "TestDll.h"
int _stdcall Plus(int x, int y)
{
return x + y;
}
int _stdcall Sub(int x, int y)
{
return x - y;
}
int _stdcall Mul(int x, int y)
{
return x * y;
}
int _stdcall Div(int x, int y)
{
return x / y;
}
说明:
1、extern 表示这是个全局函数,可以供各个其他的函数调用;
2、“C” 按照C语言的方式进行编译、链接
__declspec(dllexport)告诉编译器此函数为导出函数;
_stdcall 内平栈;
4.使用Dll
方式一:隐式连接
步骤1:将 *.dll *.lib 放到工程目录下面
步骤2:将 #pragma comment(lib,“DLL名.lib”) 添加到调用文件中
步骤3:加入函数的声明
extern “C” __declspec(dllimport) __stdcall int Plus (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Sub (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Mul (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Div (int x,int y);
说明:
__declspec(dllimport)告诉编译器此函数为导入函数;
#include <iostream>
#pragma comment(lib,"TestDll.lib")
extern "C" __declspec(dllimport) int Plus(int x, int y);
extern "C" __declspec(dllimport) int Sub(int x, int y);
extern "C" __declspec(dllimport) int Mul(int x, int y);
extern "C" __declspec(dllimport) int Div(int x, int y);
int main()
{
printf("%d", Plus(2, 1));
}
方式二:显式连接
步骤1: //定义函数指针
typedef int(_stdcall* lpPlus)(int, int);
typedef int(_stdcall* lpSub)(int, int);
typedef int(_stdcall* lpMul)(int, int);
typedef int(_stdcall* lpDiv)(int, int);
步骤2: //声明函数指针变量
lpPlus myPlus;
lpSub mySub;
lpMul myMul;
lpDiv myDiv;
步骤3: // //动态加载dll到内存中
HINSTANCE hModule = LoadLibrary("TestDll.dll");
if (!hModule)
{
printf("%s","加载动态库失败!");
getchar();
}
步骤4: //获取函数地址
myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");
步骤5: //调用函数
int a = myPlus(10,2);
int b = mySub(10,2);
int c = myMul(10,2);
int d = myDiv(10,2);
特别说明:
Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。
HMODULE 是代表应用程序载入的模块
HINSTANCE 在win32下与HMODULE是相同的东西 Win16 遗留
HWND 是窗口句柄
其实就是一个无符号整型,Windows之所以这样设计有2个目的:
1、可读性更好
2、避免在无意中进行运算
完整调用Cpp:
#include <iostream>
#include <Windows.h>
#pragma comment(lib,"TestDll.lib")
typedef int(_stdcall* lpPlus)(int, int);
typedef int(_stdcall* lpSub)(int, int);
typedef int(_stdcall* lpMul)(int, int);
typedef int(_stdcall* lpDiv)(int, int);
int main()
{
lpPlus myPlus;
lpSub mySub;
lpMul myMul;
lpDiv myDiv;
HINSTANCE hModule = LoadLibrary("TestDll.dll");
if (!hModule)
{
printf("%s","加载动态库失败!");
getchar();
}
myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");
int a = myPlus(10, 2);
int b = mySub(10, 2);
int c = myMul(10, 2);
int d = myDiv(10, 2);
printf("%d", myPlus(2, 1));
getchar();
return 0;
}
使用Def导出
1.添加def文件
2.添加代码
LIBRARY
EXPORTS
Plus @12
Sub @15 NONAME
Mul @13
Div @16
3.编译查看结果
sub函数已经被隐藏了