我们可以使用 dumpbin 来查看 dll中导出了什么样的函数
dumpbin是什么命令呢,它是VS 自带的命令,可以用来查看DLL导出函数名
随便使用一个dll进行查看:命令:dumpbin /exports qrencoded.dll
随便使用一个exe进行查看:命令:dumpbin /imports .exe
如何去使用一个DLL呢?
c 下面使用导出的DLL
方法一:
#pragma comment(lib,"DLLTest.lib") //加入.lib文件
//隐式加载 同时需要.lib 和 .dll文件 (这里的dll已经和源文件放在一起了)
方法二:
包含.lib文件的路径 ,否则可能找不到该.lib(不在原路径时,需要 附加库目录,如果同一路径可以不写)
需要用到的.lib
需要包含的导出DLL 的头文件
运行结果:
源码:
//多字符集 不需要带L
//Unicode 需要带L
#include <stdio.h>
#include <windows.h>
#pragma region 方法一
//#include "dllTest.h"
//#pragma comment(lib,"DLLTest.lib") //加入.lib文件
#pragma endregion
//使用dll 方法一
int main()
{
#pragma region 方法一 在配置的时候加入.lib 如上面的图
//SayHello();
#pragma endregion
#pragma region 方法二 DLL调用 里面函数使用
char path[255] = { 0 };
DWORD len = 0;
//是否已经加载了这个DLL
HMODULE hModule = GetModuleHandle(L"DLLTest.dll");
if (NULL == hModule)
{
//需要的时候调用DLL
hModule = LoadLibrary(L"DLLTest.dll");
if (NULL == hModule)
{
printf("load library failed \n");
getchar();
return 1;
}
len = GetModuleFileName(hModule, path, 255);
//printf 和 wprintf 分别对应 asiic 和 unicode 版本的输出函数,不同的编码要采用对应的输出形式。
//unicode
wprintf(L"%s\n", path);
//asiic
//printf("path:%s\n", path);
}
//不需要加 L""
//使用DLL中的SayHello函数
FARPROC fn = GetProcAddress(hModule, "SayHello");
fn();
//释放DLL
FreeLibrary(hModule);
#pragma endregion
getchar();
return 0;
}
c 语言 如何去 生成一个带参数 的 DLL呢?
源码
点击生成,即可看到到生成文件
查看导出的函数,但是并没有看到参数,只有函数名,这是C语言下的 DLL
.cpp文件下 去调用一个有参函数 的 DLL呢?
方法一:普通调用 有参函数的DLL 包含头 和 .lib文件
//如果用此方式去 调用 c语言写的DLL 时会报错,因为我们写的时候时.cpp文件 ,如果改成.c文件,就不会报错
解决办法:就是用 C语言 调用的方式 去调用 C 语言写的DLL,按照 C语言的规则 去调用
#include <stdio.h>
#include <windows.h>
#include "calc.h"
#pragma comment(lib,"DLLParametersTest.lib")
int main()
{
//方法一 普通调用
#if 1
int a = 10;
int b = 25;
int c = 0;
c = add1(a, b);
printf("%d\n", c);
double a2 = 1.0;
double b2 = 2.5;
double c2 = 0;
c2 = add2(a2, b2);
printf("%lf\n", c2);
char str1[255] = "hello ";
char str2[] = "world";
int len = 0;
len = add3(str1, 255, str2);
printf("%s\n", str1);
#endif
getchar();
return 0;
}
方法二:动态调用 DLL中的有参函数(动态方式 去 调用c语言写的DLL 不会报错)
#include <stdio.h>
#include <windows.h>
//定义几个函数指针 要与 我们在DLL 中的参数一样
typedef int (* ADD1)(int a, int b);
typedef double (* ADD2)(double a, double b);
typedef int (* ADD3)(char * str1, int size,char * str2);
int main()
{
#pragma region 方法二 动态调用dll中带参数的函数
char path[255] = { 0 };
DWORD length = 0;
char str1[255] = "hello ";
char str2[] = "world";
HMODULE hModule = GetModuleHandle(L"DLLParametersTest.dll");
if (hModule == NULL)
{
hModule = LoadLibrary(L"DLLParametersTest.dll");
if (hModule == NULL)
{
printf("加载动态库失败\n");
return 1;
}
length = GetModuleFileName(hModule, LPWSTR(path), 255);
wprintf(L"%s\n", path);
}
//强制转换为 ADD1类型
ADD1 add1 = (ADD1)GetProcAddress(hModule, "add1");
printf("%d\n", add1(10, 20));
ADD2 add2 = (ADD2)GetProcAddress(hModule, "add2");
printf("%.2f\n", add2(1.5, 2.3));
ADD3 add3 = (ADD3)GetProcAddress(hModule, "add3");
printf("%d\n", add3(str1, 255, str2));
printf("%s\n", str1);
FreeLibrary(hModule);
#pragma endregion
getchar();
return 0;
}
c ++ 如何去 生成一个 DLL呢?
将上面生成 C语言DLL 的 .c文件 换成的 .cpp文件 即可生成 cpp下的DLL
c++下 查看DLL 的 样式,与C语言还是有很大的区别,c++时带不带参数的,C语言是带参数的(参数大小)
c ++ 去 调用 c++生成的 DLL呢?
如果使用第一种方法去调用 c++生成的DLL 是没有问题的,但是第二种方式 随用 随加载的方式 就会出问题
因为我们可以看到 在dumpbin文件下的 函数时乱的,这与GetProcAddress()函数需要加载的函数名不一样,这时我们就需要修改 函数名 后才能调用
#include <stdio.h>
#include <windows.h>
#pragma region 方法一
//#include "calc.h"
//#pragma comment(lib,"DLLCPPTest.lib")
#pragma endregion
//初始化调用时不需要改变
//当cpp 调用cpp生成的DLL 时 需要将GetProcAddress 的参数2:改为c++的动态库函数名
typedef int (*ADD1)(int a, int b);
typedef double (*ADD2)(double a, double b);
typedef int (*ADD3)(char* str1, int size, char* str2);
int main()
{
#pragma region 方法一
#if 0
int a = 10;
int b = 25;
int c = 0;
c = add1(a, b);
printf("%d\n", c);
double a2 = 1.0;
double b2 = 2.5;
double c2 = 0;
c2 = add2(a2, b2);
printf("%lf\n", c2);
char str1[255] = "hello ";
char str2[] = "world";
int len = 0;
len = add3(str1, 255, str2);
printf("%s\n", str1);
#endif
#pragma endregion
#pragma region 方法二
#if 1
char path[255] = { 0 };
DWORD length = 0;
char str1[255] = "hello ";
char str2[] = "world";
HMODULE hModule = GetModuleHandle(L"DLLCPPTest.dll");
if (hModule == NULL)
{
hModule = LoadLibrary(L"DLLCPPTest.dll");
if (hModule == NULL)
{
printf("加载动态库失败\n");
return 1;
}
length = GetModuleFileName(hModule, LPWSTR(path), 255);
wprintf(L"%s\n", path);
}
//需要我们用 dumpbin 去查看 函数名 如果还写 一开始我们定义的add1 就会报错
ADD1 add1 = (ADD1)GetProcAddress(hModule, "?add1@@YAHHH@Z");
printf("%d\n", add1(10, 20));
ADD2 add2 = (ADD2)GetProcAddress(hModule, "?add2@@YANNN@Z");
printf("%.2f\n", add2(1.5, 2.3));
ADD3 add3 = (ADD3)GetProcAddress(hModule, "?add3@@YAHPADH0@Z");
printf("%d\n", add3(str1, 255, str2));
printf("%s\n", str1);
FreeLibrary(hModule);
#endif
#pragma endregion
getchar();
return 0;
}
c ++ 去 导出一个类 呢?
项目配置类型:dll(动态库类型)
一个是默认的构造函数 一个是析构函数 一个是自己定义的函数
c ++ 去 调用 一个 c++导出的类 呢?
c ++ 去 生成一个 c++导出复杂类 呢?
A公司定义一个标准
B公司 根据命名 去定义内容 供其他公司去调用
c ++ 去 调用 一个 c++导出的复杂类 呢?
__cdecl 与 __stdcall的区别
默认是: __cdecl
__stdcall : 标准调用 自己清理
_declspec(dllexport) int __cdecl add1(int a, int b);
_declspec(dllexport) double __cdecl add2(double a, double b);
_declspec(dllexport) int __cdecl add3(char* str1, int size, char* str2);
函数名需要加上调用规则
#include "calc.h"
#include <string.h>
int __cdecl add1(int a, int b)
{
return a + b;
}
double __cdecl add2(double a, double b)
{
return a + b;
}
int __cdecl add3(char* str1, int size, char* str2)
{
int total = strlen(str1) + strlen(str2);
if (total >= size)
{
return total;
}
strcat_s(str1, size, str2);
return total;
}
参数后面时参数类型的大小,如果是给其他语言用的 必须使用__stdcall
通过def文件 规范 c++语言导出符号
c导出符号就是我们用dumpbin 看到的
编写一个.def文件 然后 导入到项目中
通过 C语言的形式生成 ,并且用 .def 去规范我们的 导出符号