[NOTE] WindowsLinux动态链接库学习笔记

2024-01-31 08:18

本文主要是介绍[NOTE] WindowsLinux动态链接库学习笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Windows&Linux动态链接库学习笔记

-- By Water

       在一个开发项目中需要用到有着统一标准的接口,但是内部实际功能却各不相同的动态链接库的开发,并要在Window和Linux中去分别实现显示调用。

       基于这个需求学习了解一下相关动态库的知识,以下是相关的学习笔记。
       动态链接库在Windows里面叫做“Dynamic Link Library”简称 “DLL”,因此Window里面一般动态链接库文件后缀也就是dll。在Linux里面类似Windows动态链接库的叫做“Shared Object” (共享对象),在Linux系统下动态库文件名的后缀就是“so”。
       接下来将学习一些简单的Window & Linux 平台下 dll & so的创建和使用方法。先从最熟悉的Windows + MSVC开始学习实验。
       由于个人工作环境基本都是C语言,下面测试用的代码都是C语言为基础的代码,C++以及其他语言创建dll的差别这里不做研究。

Windows + msvc dll的创建和使用实验

我使用的是msvc++ 6.0,最新的版本应该是类似的方法。
实验步骤如下:

1. 先建立一个“dll_note”的WorkSpace以便将来便于工程管理


2. 在WorkSpace上创建“hello_dll”的project


创建一个空的dll工程。


3. 在WorkSpace上建立一个“dll_demo”的控制台dll测试程序



4. 在“hell_dll”中增加测试代码文件“hello_dll.h”和“hello_dll.c”

代码如下:

hello_dll.h

<span style="font-family:Microsoft YaHei;font-size:18px;">#ifndef __hello_h_
#define __hello_h_#ifdef __cplusplus
extern "C" {
#endifvoid hello_dll(void);#ifdef __cplusplus
}
#endif#endif /* #ifndef __hello_h_ */</span>


hello_dll.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include "hello_dll.h"void hello_dll(void)
{printf("hello dll\n");
}</span>

hello_dll  的代码很简单,就是一个hello_dll的函数,打印了“hello dll”字符串。


5. 在“dll_demo”project中添加测试代码文件“dll_demo.c”

代码如下: dll_demo.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include <wtypes.h>
#include <winbase.h>
#include <winerror.h>typedef void (*fp_hello_dll)(void);void main(void)
{HMODULE h_dll;DWORD error_code;fp_hello_dll hello_dll;printf("start load library\n");h_dll = LoadLibrary("hello_dll.dll");if (h_dll) {printf("get function entry from dll by symbol name\n");hello_dll = (fp_hello_dll)GetProcAddress(h_dll, "hello_dll");if (hello_dll) {hello_dll();} else {error_code = GetLastError();printf("can't get valid function entry, error code: %d\n", error_code);}FreeLibrary(h_dll);} else {error_code = GetLastError();printf("load library fail, error code: %d\n", error_code);}printf("\n__end__\n");
}
</span>


测试代码中主要用到了下面4个函数:“LoadLibrary”加载dll,“GetProcAddress”获取dll中对应Symbol的函数入口地址,“FreeLibrary”卸载dll,和“GetLastError”可以获得最后出错的代码便于出错分析。

6. 编译、运行、debu

分别编译“hello_dll”和“dll_demo”两个project,会发现都能编译过。

但运行“dll_demo”的时候出现如下出错信息:


<span style="font-family:Microsoft YaHei;font-size:18px;">start load library
load library fail, error code: 126</span>


到<winerror.h>中查找126出错代码有如下描述:

<span style="font-family:Microsoft YaHei;font-size:18px;">// MessageId: ERROR_MOD_NOT_FOUND// MessageText://  The specified module could not be found.#define ERROR_MOD_NOT_FOUND              126L</span>
 

实际上就是Windows程序调用LoadLibrary的时候找不到“hello_dll.dll”这个dll文件。

编译的时候产生的dll在“hello_dll”project 的Debug或者Release目录下面。

但Window在找dll的时候并不包含这个路径,Window搜索dll路径的优先级如下:

1. 当前程序运行的目录

2. Window目录

3. System目录

4. 环境变量PATH中罗列的所有目录

为了方便,将“hello_dll”Project 的Debug或Release目录下的“hello_dll.dll”文件拷贝到“dll_demo”Project目录下。

 

再运行“dll_demo”,仍然出现错误,信息如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">start load libraryget function entry from dll by symbol namecan't get valid function entry, error code: 127</span>
 

对应的127出错代码描述如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">// MessageId: ERROR_PROC_NOT_FOUND// MessageText://  The specified procedure could not be found.#define ERROR_PROC_NOT_FOUND             127L</span>

出错的意思是找不到“hello_dll”这个Symbol对应的函数入口地址。查了一下资料,原来Windows不同于Linux,dll需要export的函数需要添加修饰符:_declspec(dllexport)

修改后的“hello_dll.h”如下:

_declspec(dllexport) void hello_dll(void);

重新编译“hello_dll”后拷贝dll到“dll_demo”目录下再运行“dll_demo”结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">start load libraryget function entry from dll by symbol namehello dll</span>
这样的结果就符合预期了。

7. Windows + msvc dll小结

a) 需要export的函数要在头文件中对应的函数前添加修饰符:_declspec(dllexport)

b) 使用dll的代码需要添加<wtypes.h>和<winbase.h>两个头文件。

c) 使用前调用LoadLibrary加载dll

d) 使用GetProcAddress获得对应函数的函数入口

e) 如果遇到错误可以使用GetLastError获得出错的原因

f) 使用完毕调用FreeLibrary释放dll

8. 一些不足的改进

上面的例子发现一些不太爽的地方:

1. 每次修改编译完“hello_dll”都要拷贝一下hello_dll.dll

2. 使用dll的symbol对应的函数不是那么直观

为了解决这些问题,对msvc设定以及代码做了如下修改:

A) 在“dll_none”WorkSpace目录下创建“inc”、“lib”、“src”几个目录。

B) 把“hello_dll.h”和“hello_dll.c”、“dll_demo.c”文件分别从“hello_dll”&“dll_demo”Project转移到“inc”和“src”目录

C) 修改“hello_dll.h”代码如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">#ifndef __hello_h_
#define __hello_h_#ifdef __cplusplus
extern "C" {
#endif#ifdef BUILD_DLL_declspec(dllexport) void hello_dll(void);
#elsevoid (*hello_dll)(void);
#endif#ifdef __cplusplus
}
#endif#endif /* #ifndef __hello_h_ */</span>

这样build dll和引用dll可以使用同一份头文件,只需要在build dll的时候加上“BUILD_DLL”的config即可。

D) 对应的修改“hello_dll”Project 配置

增加BUILD_DLL definition。

增加include路径“..\inc”,使得“hello_dll”Project可以找到“hello_dll.h”这个头文件。

修改Debug版的dll输出到..\lib\hello_dll_d.dll

修改Release版的dll输出到“..\lib\hello_dll.dll”

这样就能让debug & release版本的dll都输出到lib目录下以便其他程序使用。

 

E) 修改“dll_demo”Project的Include设置

这样“dll_demo”Project就能与“hello_dll”访问同一个“hello_dll.h”头文件了。

F) 修改“dll_demo.c”部分代码如下

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include <wtypes.h>
#include <winbase.h>
#include <winerror.h>
#include "hello_dll.h"void main(int argc, char **argv)
{HMODULE h_dll;DWORD error_code;if (argc < 2) {printf("cmd fmt: <dll path>\n");return;}printf("start load library\n");h_dll = LoadLibrary(argv[1]);if (h_dll) {printf("get function entry from dll by symbol name\n");hello_dll = (void*)GetProcAddress(h_dll, "hello_dll");if (hello_dll) {hello_dll();} else {error_code = GetLastError();printf("can't get valid function entry, error code: %d\n", error_code);}FreeLibrary(h_dll);} else {error_code = GetLastError();printf("load library fail, error code: %d\n", error_code);}printf("\n__end__\n");
}
</span>

修改为指定“dll”的路径,这样不用修改代码或重新编译,就能同时测试Debug & Release版本的dll。此外引用了“hello_dll.h”这样就不用再写引用函数的类型定义,更加容易理解了。

Windows + mingw dll的创建和使用实验

在移植到Linux平台下面之前,先用mingw的gcc实验看看。

为了方便gcc & msvc共Code编译,并有更简单的对比测试环境。在dll_note同一个目录下创建obj、exe两个目录。在msvc 中设置“dll_demo”Project输出“dll_demo.exe”到exe目录下:



这样就让msvc & gcc编译的exe都输出到exe目录,dll都输出到lib目录。

先尝试用gcc编译hello_dll.c文件:

<span style="font-family:Microsoft YaHei;font-size:18px;">\dll_note>gcc -c -D BUILD_DLL -I .\inc .\src\hello_dll.c -o .\obj\hello_dll.o.\src\hello_dll.c: In function '_declspec':.\src\hello_dll.c:15:1: error: expected '=', ',', ';', 'asm' or '__attribute__'before '{' token{^In file included from .\src\hello_dll.c:12:0:.\inc/hello_dll.h:21:28: error: declaration for parameter 'hello_dll' but no such parameter_declspec(dllexport) void hello_dll(void);^.\src\hello_dll.c:17:1: error: expected '{' at end of input}^</span>

gcc有编译出错,因为gcc与msvc不同,不需要_declspec(dllexport)修饰符来导出Symbol到dll,只需要加-shared选项就可。为了让msvc & gcc公用一份code,对“hello_dll.h”做了如下修改:

<span style="font-family:Microsoft YaHei;font-size:18px;">#ifndef __hello_h_
#define __hello_h_#ifdef __cplusplus
extern "C" {
#endif#ifdef BUILD_DLL
#  if defined (__GNUC__)
#	define DLL_EXPORT
#  elif defined(_MSC_VER)
#	define DLL_EXPORT _declspec(dllexport)
#  else
#	define DLL_EXPORT
#  endif
#endif#ifdef BUILD_DLLDLL_EXPORT void hello_dll(void);
#elsevoid (*hello_dll)(void);
#endif#ifdef __cplusplus
}
#endif
#endif /* #ifndef __hello_h_ */
</span>


增加了DLL_EXPORT宏的定义,以区分msvc & gcc对dll export 函数Symbol的修饰符。让msvc和gcc可以共用这份Code。这样修改后gcc就能让“hello_dll.c”正常编译通过了。

为了便于用gcc编译dll和exe,写了如下makefile

Makefile

<span style="font-family:Microsoft YaHei;font-size:18px;"># this make file for dll study used by Water (sszhouplus@qq.com)
TGT_DLL = .\lib\gcc_hello_dll.dll
TGT_EXE=.\exe\gcc_dll_demo.execc = gcc.PHONY:all
all: .\obj\gcc_hello_dll.o .\obj\gcc_dll_demo.o$(cc) -shared -o $(TGT_DLL) .\obj\gcc_hello_dll.o$(cc) -o $(TGT_EXE) .\obj\gcc_dll_demo.o.\obj\gcc_dll_demo.o: .\src\dll_demo.c .\inc\hello_dll.h$(cc) -c -o $@ $< -I .\inc.\obj\gcc_hello_dll.o: .\src\hello_dll.c .\inc\hello_dll.h$(cc) -c -o $@ $< -I .\inc -D BUILD_DLL.PHONY:clean
clean:del /f /q .\obj\gcc_dll_demo.odel /f /q .\obj\gcc_hello_dll.odel /f /q $(TGT_DLL)del /f /q $(TGT_EXE)</span>

执行编译结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">.\note\dll_note>mingw32-make
gcc -c -o .\obj\gcc_hello_dll.o .\src\hello_dll.c -I .\inc -D BUILD_DLL
gcc -c -o .\obj\gcc_dll_demo.o .\src\dll_demo.c -I .\inc
gcc -shared -o .\lib\gcc_hello_dll.dll .\obj\gcc_hello_dll.o
gcc -o .\exe\gcc_dll_demo.exe .\obj\gcc_dll_demo.o</span>

运行结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">.\note\dll_note>.\exe\gcc_dll_demo.exe .\lib\gcc_hello_dll.dll
start load library
get function entry from dll by symbol name
hello dll__end__</span>

可见exe和dll都符合预期了。

接下来再做一些交叉测试,分别用msvc的dll_demo.exe测试gcc生成的gcc_hello_dll.dll,再用gcc生成的gcc_dll_demo.exe 测试msvc生成的hello_dll.dll。按照预期的应该都能够正常调用。

<span style="font-family:Microsoft YaHei;font-size:18px;">.\note\dll_note>.\exe\gcc_dll_demo.exe .\lib\hello_dll.
dll
start load library
get function entry from dll by symbol name
hello dll__end__.\note\dll_note>.\exe\dll_demo.exe .\lib\gcc_hello_dll.
dll
start load library
get function entry from dll by symbol name
hello dll__end__</span>

从结果可以看出都能够正常执行,实验达到了预期的效果。

同一份Code分别用msvc & gcc可以通过编译,并且生成的exe和dll都能够互相调用,体现了dll的独立性与编译器无关。


在MinGW下用Linux API显示调用dll实验

上面例子的dll_demo.c里面使用的仍然是windows的API来Load/Get/Free dll。Mingw支持使用Linux的方式来操作dll。

下面创建dll_demo_linux.c来实验Linux dll/so的使用方法。

1. 增加include Linux 调用dll相关的函数头文件是 <dlfcn.h>

2. 用dlopen 代替LoadLibrary 加载dll

3. 用dlsym 代替 GetProcAddress 获得dll symbol对应的函数入口地址

4. 用dlclose 代替 FreeLibrary 用于释放dll

5. 用dlerror 代替 GetLastError 获得出错信息

dll_demo_linux.c源代码如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include <dlfcn.h>
#include "hello_dll.h"
void main(int argc, char **argv)
{void *h_dll;char *p_err_str;if (argc < 2) {printf("cmd fmt: <dll path>\n");return;}printf("start load library\n");h_dll = dlopen(argv[1], RTLD_LAZY);if (h_dll) {printf("get function entry from dll by symbol name\n");hello_dll = dlsym(h_dll, "hello_dll");if (hello_dll) {hello_dll();} else {p_err_str = dlerror();printf("can't get valid function entry, error code: %s\n", p_err_str);}dlclose(h_dll);} else {p_err_str = dlerror();printf("load library fail, error code: %s\n", p_err_str);}printf("\n__end__\n");
}
</span>

创建相应的Makefile_linux.mk如下:

<span style="font-family:Microsoft YaHei;font-size:18px;"># this make file for dll study used by Water (sszhouplus@qq.com)
TGT_DLL = .\lib\gcc_hello_dll.dll
TGT_EXE=.\exe\gcc_dll_demo_linux.exe
cc = gcc.PHONY:all
all: .\obj\gcc_hello_dll.o .\obj\gcc_dll_demo_linux.o$(cc) -shared -o $(TGT_DLL) .\obj\gcc_hello_dll.o$(cc) -o $(TGT_EXE) .\obj\gcc_dll_demo_linux.o.\obj\gcc_dll_demo_linux.o: .\src\dll_demo_linux.c .\inc\hello_dll.h$(cc) -c -o $@ $< -I .\inc.\obj\gcc_hello_dll.o: .\src\hello_dll.c .\inc\hello_dll.h$(cc) -c -o $@ $< -I .\inc -D BUILD_DLL.PHONY:clean
clean:del /f /q .\obj\gcc_dll_demo_linux.odel /f /q .\obj\gcc_hello_dll.odel /f /q $(TGT_DLL)del /f /q $(TGT_EXE)</span>

执行make结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">.\note\dll_note>mingw32-make -f Makefile_linux.mk
gcc -c -o .\obj\gcc_hello_dll.o .\src\hello_dll.c -I .\inc -D BUILD_DLL
gcc -c -o .\obj\gcc_dll_demo_linux.o .\src\dll_demo_linux.c -I .\inc
gcc -shared -o .\lib\gcc_hello_dll.dll .\obj\gcc_hello_dll.o
gcc -o .\exe\gcc_dll_demo_linux.exe .\obj\gcc_dll_demo_linux.o</span>

执行dll_demo_linux.exe,实验结果也符合预期,都能正常执行。

<span style="font-family:Microsoft YaHei;font-size:18px;">.\dll_note>.\exe\gcc_dll_demo_linux.exe .\lib\hello_dll.dll
start load library
get function entry from dll by symbol name
hello dll
__end__.\note\dll_note>.\exe\gcc_dll_demo_linux.exe .\lib\gcc_hello_dll.dll
start load library
get function entry from dll by symbol name
hello dll
__end__</span>

这样看来使用Linux API调用dll在mingw下也实验完毕了,接下来到Linux下看看。


Linux so的创建和使用实验

将src、inc拷贝到Linux环境下,并在同一个目录下创建lib和exe目录。根据Linux的特性,创建相应的makefile:“make_linux.mk”如下:

<span style="font-family:Microsoft YaHei;font-size:18px;"># this make file for dll study used by Water (sszhouplus@qq.com)
TGT_DLL = ./lib/gcc_hello_dll.so
TGT_EXE=./exe/gcc_dll_demo_linux.out
cc = gcc.PHONY:all
all: ./obj/gcc_hello_dll.o ./obj/gcc_dll_demo_linux.o-mkdir exe-mkdir lib$(cc) -shared -o $(TGT_DLL) ./obj/gcc_hello_dll.o$(cc) -o $(TGT_EXE) ./obj/gcc_dll_demo_linux.o -ldl./obj/gcc_dll_demo_linux.o: ./src/dll_demo_linux.c ./inc/hello_dll.h-mkdir obj$(cc) -c -o $@ $< -I ./inc./obj/gcc_hello_dll.o: ./src/hello_dll.c ./inc/hello_dll.h-mkdir obj$(cc) -c -o $@ $< -I ./inc -D BUILD_DLL.PHONY:clean
clean:-rm -f ./obj/gcc_dll_demo_linux.o-rm -f ./obj/gcc_hello_dll.o-rm -f $(TGT_DLL)-rm -f $(TGT_EXE)</span>

针对Linux环境下的makefile主要做了如下几点的修改

1. 将路径里面的“\”修改为“/”

2. 将windows的del 改为linux的 rm命令

3. 在生成执行文件的命令里面增加 -ldl的编译选项,这样就能找到dlopen/dlsym/dlclose等函数

4. 增加了-mkdir obj/lib/exe 创建目录的命令 (mkdir前面的“-”目的是让命令执行失败也不影响makefile继续执行)。

 

执行make后结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">~/note$ make -f make_linux.mk
mkdir obj
gcc -c -o obj/gcc_hello_dll.o src/hello_dll.c -I ./inc -D BUILD_DLL
mkdir obj
mkdir: 无法创建目录"obj": 文件已存在
make: [obj/gcc_dll_demo_linux.o] 错误 1 (忽略)
gcc -c -o obj/gcc_dll_demo_linux.o src/dll_demo_linux.c -I ./inc
mkdir exe
mkdir lib
gcc -shared -o ./lib/gcc_hello_dll.so ./obj/gcc_hello_dll.o
gcc -o ./exe/gcc_dll_demo_linux.out ./obj/gcc_dll_demo_linux.o -ldl
~/note$ ls ./exe/
gcc_dll_demo_linux.out</span>

运行程序,结果如下:

<span style="font-family:Microsoft YaHei;font-size:18px;">~/note$ ./exe/gcc_dll_demo_linux.out ./lib/gcc_hello_dll.so 
start load library
get function entry from dll by symbol name
hello dll__end__</span>


在Linux环境下即使没有修改source code,程序也能正常编译通过并正确运行了。

至此,msvc、mingw、linux gcc的动态链接库实验基本已经完成了,但还有点小遗憾,windows的msvc & linux gcc调用动态库的方式是不同的,demo的code虽然差异不大,但是还是有所不同。

接下来尝试一下对dll的使用接口进行简单封装一下,以便统一window msvc & linux gcc的dll使用接口,让更多的code可以共用。

Win msvc & Linux gcc dll Simple Common API

定义的Simple Common DLL API 头文件“com_dll_api.h”如下:

com_dll_api.h

<span style="font-family:Microsoft YaHei;font-size:18px;">#ifndef __com_dll_api_h_
#define __com_dll_api_h_#ifdef __cplusplus
extern "C" {
#endif/*** Function: dll_open* @brief:   open dll library, and return dll module handle* @param:   dll_name : [in] the dll file name for open* @return:  void* the dll module handle*              0  : error occurs during the process of loading dll file *                More detailed diagnostic information will be available *                  through dl_get_error*              !0 : open dll libary ok and return the dll module handle*/
void *dll_open(const char *dll_name);/*** Function: dll_close* @brief:   close dll module* @param:   dll_module : [in] the dll module handle (by dll_open)* @return:  void* *              0  : close dll module ok*              !0 : close dll mdoule ng, and return input dll_module*                More detailed diagnostic information will be available *                  through dl_get_error*/
void *dll_close(void *dll_module);/*** Function: dll_get_symbol* @brief:   get function entry from dll module by symbol name* @param:   dll_module : [in] the dll module handle (by dll_open)*           sym_name:    [in] the symbol name for this function* @return:  void* *             0  : get function entry fail from this dll by this symbol name*                More detailed diagnostic information will be available *                  through dl_get_error*             !0 : get function entry ok and return function pointer addresss*/
void *dll_get_symbol(void *dll_module, const char *sym_name);/*** Function: dll_last_error* @brief:   after dll_open/close/get_symbol function failed*             could get the last detailed error information by this function.*           if dll_open/close/get_symbol return ok, and call this function*            the error information maybe incorrect.* @param:   null* @return:  char* *              0  : no error information*              !0 : the last error information*/
char *dll_last_error(void);#ifdef __cplusplus
}
#endif#endif /* #ifndef __com_dll_api_h_ */
</span>

com_dll_api.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include "com_dll_api.h"
#if defined (_MSC_VER)
# include "com_dll_api_msvc.c"
#elif defined (__GNUC__)
# include "com_dll_api_linux.c"
#else
# pragma "error: tbd compiler"
#endif</span>

com_dll_api_msvc.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include <wtypes.h>
#include <winbase.h>
#include <winerror.h>
#include "com_dll_api.h"
static char dll_msvc_error[64];void *dll_open(const char *dll_name)
{return LoadLibrary(dll_name);
}void *dll_close(void *dll_module)
{if (FreeLibrary(dll_module))return 0;return dll_module;
}void *dll_get_symbol(void *dll_module, const char *sym_name)
{return (void*)GetProcAddress(dll_module, sym_name);
}char *dll_last_error(void)
{sprintf(dll_msvc_error, "msvc dll last error code: [%d]", GetLastError());return dll_msvc_error;
}</span>

com_dll_api_linux.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <dlfcn.h>
#include "com_dll_api.h"void *dll_open(const char *dll_name)
{return dlopen(dll_name, RTLD_LAZY);
}void *dll_close(void *dll_module)
{if (0 == dlclose(dll_module))return 0;return dll_module;
}void *dll_get_symbol(void *dll_module, const char *sym_name)
{return dlsym(dll_module, sym_name);
}char *dll_last_error(void)
{return dlerror();
}
</span>

使用Simple Common Dll API开发的demo “dll_demo_com_dll_api.c”

dll_demo_com_dll_api.c

<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include "hello_dll.h"
#include "com_dll_api.h"void main(int argc, char **argv)
{void *dll_module;char *p_err_str;if (argc < 2) {printf("cmd fmt: <dll path>\n");return;}printf("start load library\n");dll_module = dll_open(argv[1]);if (dll_module) {printf("get function entry from dll by symbol name\n");hello_dll = dll_get_symbol(dll_module, "hello_dll");if (hello_dll) {hello_dll();} else {p_err_str = dll_last_error();printf("can't get valid function entry,""error code: %s\n", p_err_str);}dll_close(dll_module);} else {p_err_str = dll_last_error();printf("load library fail, error code: %s\n", p_err_str);}printf("\n__end__\n");
}</span>

这样无论windows的的msvc还是linux的gcc都可以用这套com_dll_api.h来进行dll的调用了。可以实现一份Code用msvc & linux gcc都能够使用。

测试代码和工程的整理

前面测试的代码是一边学,一边实践,一边改进,又跨了多个编译器和平台,有点乱乱的。

在这里整理一下。

测试工程结构如下:

study_dll

├─build

│  ├─linux

│  ├─mingw

│  └─msvc

│      ├─com_dll_api

│      ├─hello_dll

│      └─test_dll

├─doc

├─lib

├─src

│  ├─com_dll_api

│  └─hello_dll

└─tests

 

最终整理后打包的工程和测试代码可以到Water的网盘下载: 

http://pan.baidu.com/s/1sjDLDVn

也可以用Git到Water在Oschina上AudioKits中的项目下载:

http://git.oschina.net/webwater/AudioKits/tree/master/study_space/study_dll

学习笔记的PDF档案也可到Water的网盘下载:

http://pan.baidu.com/s/1zxd9s


参考文献

1. “VC++动态链接库(DLL)编程深入浅出”

http://pan.baidu.com/s/1jG46yhg

 

2. “LINUX系统中动态链接库的创建与使用 ”

http://www.cnblogs.com/ardar/articles/357321.html


这篇关于[NOTE] WindowsLinux动态链接库学习笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/663115

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件