我们可以使用 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#include #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"%sn", path); //asiic //printf("path:%sn", 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#include #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("%dn", c); double a2 = 1.0; double b2 = 2.5; double c2 = 0; c2 = add2(a2, b2); printf("%lfn", c2); char str1[255] = "hello "; char str2[] = "world"; int len = 0; len = add3(str1, 255, str2); printf("%sn", str1); #endif getchar(); return 0; }
方法二:动态调用 DLL中的有参函数(动态方式 去 调用c语言写的DLL 不会报错)
#include#include //定义几个函数指针 要与 我们在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"%sn", path); } //强制转换为 ADD1类型 ADD1 add1 = (ADD1)GetProcAddress(hModule, "add1"); printf("%dn", add1(10, 20)); ADD2 add2 = (ADD2)GetProcAddress(hModule, "add2"); printf("%.2fn", add2(1.5, 2.3)); ADD3 add3 = (ADD3)GetProcAddress(hModule, "add3"); printf("%dn", add3(str1, 255, str2)); printf("%sn", 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#include #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("%dn", c); double a2 = 1.0; double b2 = 2.5; double c2 = 0; c2 = add2(a2, b2); printf("%lfn", c2); char str1[255] = "hello "; char str2[] = "world"; int len = 0; len = add3(str1, 255, str2); printf("%sn", 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"%sn", path); } //需要我们用 dumpbin 去查看 函数名 如果还写 一开始我们定义的add1 就会报错 ADD1 add1 = (ADD1)GetProcAddress(hModule, "?add1@@YAHHH@Z"); printf("%dn", add1(10, 20)); ADD2 add2 = (ADD2)GetProcAddress(hModule, "?add2@@YANNN@Z"); printf("%.2fn", add2(1.5, 2.3)); ADD3 add3 = (ADD3)GetProcAddress(hModule, "?add3@@YAHPADH0@Z"); printf("%dn", add3(str1, 255, str2)); printf("%sn", 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" #includeint __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 去规范我们的 导出符号



