windows需用getfileversioninfo+verqueryvalue读dll资源段版本,路径须绝对且dll未被独占加载;linux so无内置版本字段,soname非语义版本;跨平台应由库自身提供get_library_version等c接口。

Windows下用GetFileVersionInfo读取DLL版本信息
Windows DLL的版本信息通常嵌在资源段里,不能靠文件属性或GetModuleFileName获取,必须调用Windows API解析资源数据。核心函数是GetFileVersionInfo和VerQueryValue,它们需要配合使用。
- 先用
GetFileVersionInfoSize获取所需缓冲区大小,否则GetFileVersionInfo大概率失败 - 路径必须是完整绝对路径(相对路径可能返回0字节数据),且DLL不能被其他进程独占加载(比如正被
LoadLibrary占用时会失败) - 版本字符串位于
"\StringFileInfo\%04x%04x\FileVersion"路径下,其中语言/字符集ID需从VerQueryValue第一次调用中提取,不能硬编码040904b0 - 常见错误是忽略
VS_FIXEDFILEINFO结构里的dwFileVersionMS/LS字段,它比字符串更可靠——字符串可能被篡改,而结构体字段由链接器生成
Linux下SO文件基本没有内置版本信息
ELF格式的SO文件本身不定义“版本号”字段,objdump -p libxxx.so | grep SONAME看到的是SONAME(如libfoo.so.2),这属于ABI标识,不是应用层语义版本(如1.2.3)。想查这个,得靠文件名约定或外部元数据。
-
readelf -d libxxx.so | grep SONAME能提取动态链接时使用的库名,但不等于版本号 - 有些项目会在SO里导出
get_version()这类符号,但这完全取决于开发者是否实现,不是标准机制 - 不要尝试用
file或strings搜"version"字样——结果不可靠,且不同构建工具写入位置不一致 - 若SO由CMake生成并启用了
VERSION和SOFIXED,则SONAME会包含主版本号(如libxxx.so.1),但次版本、修订号仍无处可查
跨平台方案:让DLL/SO自己暴露版本接口
依赖操作系统资源或文件命名规则终究不稳定。最可控的做法,是在库代码里显式提供版本查询函数,由调用方直接调用。
- C++推荐用
extern "C"导出纯C接口,避免name mangling问题:extern "C" const char* get_library_version() { return "1.4.2"; } - Windows DLL需在.def文件或
__declspec(dllexport)声明;Linux SO默认导出所有非static符号,但建议加__attribute__((visibility("default"))) - 调用时先
dlopen/LoadLibrary,再dlsym/GetProcAddress获取函数指针,失败即视为不支持版本查询 - 注意:C++类成员函数无法跨ABI调用,必须用C风格函数+简单返回类型(
const char*或int[4])
别把GetFileVersionInfo当万能解,尤其对注入/热更新场景
很多用户以为只要DLL在磁盘上,就能随时读到它的版本——但实际中,如果该DLL已被当前进程以LOAD_LIBRARY_AS_DATAFILE以外方式加载过,GetFileVersionInfo可能读到的是内存镜像而非磁盘文件,结果与预期不符。
- 安全做法是:先
GetModuleHandle检查是否已加载;若已加载,优先从模块句柄获取版本(用GetModuleFileName+GetFileVersionInfo组合) - 若未加载,再用磁盘路径读取——但要确保路径指向的是真正被加载的那个文件(比如重定向后的真实路径)
- 热更新时替换DLL文件后,旧版本仍在内存运行,此时磁盘版本和运行版本必然不一致,必须明确区分“文件版本”和“运行版本”
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











