动态加载链接库--修改中

前提知识:

一.动态(共享)链接库

用于解决静态链接库缺陷的一个现代新型产物.

其是一个目标模块,在运行和加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来.

备注1:解决静态链接库的问题是:所有静态链接库链接的执行程序或多或少包含了该链接库的某一部分,不同执行程序的相同代码程序占用了内存这一稀缺资源,动态链接库使得所有执行程序都只访问内存中的唯一一个链接库,该链接库被所有执行程序共享.
备注2:动态链接库在使用时也需要部分静态链接,这部分链接指链接器复制了一些重定位和符号表信息,它们的存在使得执行程序知道链接库中存在哪些函数或变量可以调用(相当于执行程序拿到了链接库不同函数变量的名字(前提是这些东西是链接库对外公开的))
二.函数调用约定

__stdcall

__cdecl

备注:不需要深入理解这两个约定的含义(参数入栈的区别),只需要记得统一约定即可,如显式声明的函数为 void __stdcall function(void); 或 void __cdecl function(void); 在链接库和调用模块中一致.
三.不同操作系统的调用库
Linux:
#include<dlfcn.h>
//@param filename 文件名称如"./libvector.so"
//@param flag 类似枚举值 RTLD_GLOBAL|RTLD_NOW|RTLD_LAZY
void *dlopen(const char *filename,int flag);//若成功则返回指向句柄的指针handle,若出错则为NULL
//@param handle open函数返回的句柄
//@param symbol 链接库中的函数名称
void *dlsym(void *handle,char *symbol);//若成功则返回指向该symbol的指针,否则返回NULL
//@param handle open函数返回的句柄
int dlclose(void *handle); //若成功则为0,若出错则为-1,用于卸载该共享库
const char *dlerror(void);//返回上述函数发生的最近的错误,如果没有错误发生,则返回NULL
备注: 调用示例,错误检测省略,假定全部顺利
void (*function) (void);	//返回的函数指针
void *handle;

handle = dlopen("./###.so",RTLD_LAZY);
function = dlsym(handle,"###");
function();
dlclose(handle);
Windows:
#include<windows.h>
//不同编码下的调用宏声明,L的字符串添加与否
#ifdef UNICODE
#define LoadLibrary  LoadLibraryW
#else
#define LoadLibrary  LoadLibraryA
#endif // !UNICODE
//@param lpFileName 动态库名,如"QtGui.dll"
HMODULE LoadLibrary(LPCTSTR lpFileName);	//装载动态库

//@param [in] hModule 包含函数或变量的 DLL 模块的句柄。
//@param [in] lpProcName 函数或变量名称,或函数的序号值。 如果此参数是序号值,则它必须在低序位字中;高序位字必须为零。
FARPROC GetProcAddress(
  [in] HMODULE hModule,
  [in] LPCSTR  lpProcName
); //如果函数成功,则返回值是导出的函数或变量的地址。如果函数失败,则返回值为 NULL。
备注:调用示例
void __stdcall func1(void);
int main(int argc, char** argv)
{
	func1();
	return 0;
}

typedef void (__stdcall * FUNC1)(void);
typedef void(__stdcall* FUNC2)(int, int);
typedef float(__stdcall* FUNC3)(float, float);

void __stdcall func1(void)
{
	auto handle = LoadLibrary(L"dllTest.dll");
	if (handle == NULL)
	{
		printf("handle is 0,exit");
		exit(0);
	}

	FUNC1 a = (FUNC1)GetProcAddress(handle, "add");
	FUNC2 b = (FUNC2)GetProcAddress(handle, "sub");
	FUNC3 c = (FUNC3)GetProcAddress(handle, "convert");
}	//省略,a,b,c从此按照函数调用
四.链接库开发函数头

_declspec(dllexport) //导出

_declspec(dllimport) //导入

//如上Windows示例代码
extern "C" _declspec(dllexport) void __stdcall add();

extern "C" _declspec(dllexport) void __stdcall sub(int, int);

extern "C" _declspec(dllexport) float __stdcall convert(float, float);

//未完

posted @ 2024-06-30 15:04  Neko_Code  阅读(19)  评论(0编辑  收藏  举报