VS2015采用loadlibrary方式调用dll库
参考: //blog..net/luoyu510183/article/details/93666808 //blog..net/SonnAdolf/article/details/80339070 //blog..net/blade1080/article/details/81538384
Loadlibrary方式不在需要.lib库,当我们编译动态库的时候,会生成两个文件,.dll和.lib ,lib和静态库不同,只是有一些函符号,真正的实现在dll里。所以说,编译动态库时生成的lib是可以不需要的。但是,如果你不采用Loadlibrary的方式,那么两个文件都需要。
下面写了一个小例子:
1、编译库
我们先编译一个库文件,然后采用Loadlibrary的方式调用。 mydll.h
#pragma once #include <windows.h> #include <iostream> using namespace std; #define MY_DLL_EXPORTS #ifdef MY_DLL_EXPORTS #define MY_DLL_API __declspec(dllexport) #else #define MY_DLL_API __declspec(dllimport) #endif extern "C" MY_DLL_API int open_device(int handle); extern "C" MY_DLL_API int open_seesion(int hseion);
mydll.cpp
#include "mydll.h" extern "C" MY_DLL_API int open_device(int handle) { cout << "display func: open_device,"<<"handle is:"<< handle << endl; return 0; } extern "C" MY_DLL_API int open_seesion(int session) { cout << "display func: open_seesion,"<<"session is:"<< session << endl; return 0; }
默认的调用方式为:
属性->C/C+±>高级-> 调用约定: __cdecl (/Gd)
编译完后,我们用dumpbin看一下导出符号:
说明库里边已经把函数导出来了,使用loadlibrary的时候需要和导出名字对应上。
2、编译调用app
注意,你的应用程序和库文件要在同一个目录下。
Loadlibrary_test.cpp
#include <iostream> #include <Windows.h> #include "mydll.h" using namespace std; int main(void) { HMODULE hMod = LoadLibrary(TEXT("lib_dll.dll"));//载入dll,TEXT为了兼容格式,防止报类型错误 if (hMod == nullptr) { cout << "load dll error!" << endl; return -1; } typedef int(* Open_Device)(int); typedef int(* Open_Seesion)(int); Open_Device opendev = (Open_Device)GetProcAddress(hMod, "open_device");//获取函数地址 if (opendev == nullptr) { cout << "load open_device error!" << endl; return -1; } int rv = opendev(1);//通过函数指针调用函数 Open_Seesion openses = (Open_Seesion)GetProcAddress(hMod, "open_seesion"); if (openses == nullptr) { cout << "load open_session error!" << endl; return -1; } rv = openses(2);//通过函数指针调用函数 FreeLibrary(hMod); system("pause"); return 0; }
现象:
3、备注
顺便再讲下关于调用约定和函数符号的关系,即_stdcall, _cdecl.还有就是extern "c"对函数名符号的影响。
extern “C” + _stdcall,函数导出符号为 : _+函数名+@+传参字节数
由于_stdcall是被调用方清理堆栈,所以函数符号里面包含了传参的信息
extern “C” + _cdecl,函数导出符号为 : 函数名
由于_cdecl是调用方清理堆栈,所以只需要函数名就可以
不使用extern的情况下,是C++的导出方式,函数符号如下: :?+函数名+@@YG+返回类型+参数1类型…+@Z 如果是_cdecl @YG变为@YA 如果没有参数即参数为void,则以Z结尾,例如: : ?+函数名+@@YA+返回类型+XZ 以上 X表示 void类型,H表示int参数类型
配置属性里边如果生成调试信息选否,到出库里就会只有函数名: