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参数类型

配置属性里边如果生成调试信息选否,到出库里就会只有函数名:

经验分享 程序员 微信小程序 职场和发展