如何通过代码获取MSI/EXE安装项目文件的版本信息
解决MSI/EXE安装文件版本读取返回Null的问题
一、EXE文件的处理
调用FileVersionInfo.GetVersionInfo返回null,大概率是目标EXE未嵌入标准文件版本资源(比如部分自解压包、精简版安装引导程序),可尝试以下两种方案:
1. 直接解析PE文件头提取版本
通过读取PE文件的资源段获取版本信息,示例代码:
using System; using System.IO; using System.Runtime.InteropServices; public static string GetPeFileVersion(string filePath) { if (!File.Exists(filePath)) return null; using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); using var binaryReader = new BinaryReader(fileStream); // 跳过DOS头,定位PE头 fileStream.Position = 0x3C; int peHeaderPtr = binaryReader.ReadInt32(); fileStream.Position = peHeaderPtr; // 验证PE标识 uint peSignature = binaryReader.ReadUInt32(); if (peSignature != 0x00004550) // "PE\0\0" return null; // 跳转至版本信息字段 fileStream.Position += 0x12; int fileVersionPtr = peHeaderPtr + 0x40; fileStream.Position = fileVersionPtr; ushort major = binaryReader.ReadUInt16(); ushort minor = binaryReader.ReadUInt16(); ushort build = binaryReader.ReadUInt16(); ushort revision = binaryReader.ReadUInt16(); return $"{major}.{minor}.{build}.{revision}"; }
2. 确认是否为MSI引导程序
很多setup.exe只是MSI的启动器,实际版本信息存储在关联的MSI文件中(可能与exe同目录,或内嵌在exe内部),可尝试提取内嵌MSI后再读取版本。
二、MSI文件的处理
MSI的版本信息存储在数据库的Property表(ProductVersion属性)中,FileVersionInfo无法读取这类信息,需用Windows Installer相关方法:
方法1:使用WiX的Microsoft.Deployment.WindowsInstaller库
- 通过NuGet安装
Microsoft.Deployment.WindowsInstaller包 - 示例代码:
using Microsoft.Deployment.WindowsInstaller; public static string GetMsiVersion(string msiPath) { if (!File.Exists(msiPath)) return null; using var database = new Database(msiPath, DatabaseOpenMode.ReadOnly); return database.ExecuteScalar("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductVersion'") as string; }
方法2:无第三方库的原生API调用
无需引入外部库,直接调用Windows Installer API:
using System; using System.Text; using System.Runtime.InteropServices; public static string GetMsiVersionWithoutLibrary(string msiPath) { uint bufferSize = 256; StringBuilder versionBuffer = new StringBuilder((int)bufferSize); uint result = MsiGetFileVersion(msiPath, versionBuffer, ref bufferSize); return result == 0 ? versionBuffer.ToString() : null; } [DllImport("msi.dll", CharSet = CharSet.Unicode)] private static extern uint MsiGetFileVersion(string szFilePath, StringBuilder szVersion, ref uint pcchVersion);
三、常见排查点
- 确认文件路径正确,且当前程序有读取该文件的权限(比如系统目录下的文件需管理员权限)
- 若EXE经过压缩或加壳,需先脱壳才能读取版本信息
内容的提问来源于stack exchange,提问作者Dan D
相关产品推荐
相关产品推荐

