惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
D
Docker
GbyAI
GbyAI
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Stack Overflow Blog
Stack Overflow Blog
WordPress大学
WordPress大学
小众软件
小众软件
Engineering at Meta
Engineering at Meta
酷 壳 – CoolShell
酷 壳 – CoolShell
I
InfoQ
B
Blog
H
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
A
About on SuperTechFans
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog

博客园 - 云起

ArcGISPro SDK Addin打包机制 一次 ArcGISPro Addin项本地化的排查实录 记一次arm机器装系统的经历 记一次vs中无法找到win sdk的问题 arcpy运行时,报错产品许可尚未初始化 Visual Studio 2022生成解决方案代码图报错“无法连接到指定的数据库” win10下定制文件夹 excel中,根据文件名查询文件路径 ArcGISPro SDK 3.1版本中使用QueuedTask的小问题 Compress-Archive压缩zip包的小瑕疵 Pro更新字段别名,重载数据后失效 在多个office文档内替换关键字 git日志分组 xlst处理时命名空间带来的小坑 更新压缩流 使用excel生成简单的日历 微软中文输入法带来的一点小坑,导致arcgispro输入中文异常 Pro更改启动界面 使用AES加密时,结果不一样 命令行程序读取注册表失败的分析 pg_index
使用C#获取文件详情
云起 · 2024-11-21 · via 博客园 - 云起

image
有对应的需求,需要获取文件的详细信息内容。该页面信息大部分来源于文件的版本信息,使用FileInfo类并不能获取到。

VERSIONINFO 资源 - Win32 apps | Microsoft Learn

信息格式:


1 VERSIONINFO
FILEVERSION 1,0,0,323
PRODUCTVERSION 1,0,0,0
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{
	BLOCK "000004B0"
	{
		VALUE "Comments", "这是一个示例库,由张三编写。"
		VALUE "CompanyName", "webre"
		VALUE "FileDescription", "webre"
		VALUE "FileVersion", "1.0.0.323"
		VALUE "InternalName", "webre.dll"
		VALUE "LegalCopyright", "版权所有 \xA9 2024 张三"
		VALUE "LegalTrademarks", ""
		VALUE "OriginalFilename", "webre.dll"
		VALUE "ProductName", "webre"
		VALUE "ProductVersion", "1.0.0"
		VALUE "Assembly Version", "1.0.0.323"
		VALUE "Test", "Test"//自定义属性
	}
}

BLOCK "VarFileInfo"
{
	VALUE "Translation", 0x0000 0x04B0  
}
}

为了获取versioninfo信息,需要使用version.dll内的api进行指定段内的信息获取。参考如下:

GetFileVersionInfoA function (winver.h) - Win32 apps | Microsoft Learn

GetFileVersionInfoSizeA function (winver.h) - Win32 apps | Microsoft Learn

VerQueryValueW function (winver.h) - Win32 apps | Microsoft Learn

调用代码如下:

//需要引入win32api
[DllImport("version.dll", CharSet = CharSet.Unicode)]
private static extern bool GetFileVersionInfo(string fileName, int handle, int len, byte[] data);

[DllImport("version.dll", CharSet = CharSet.Unicode)]
private static extern int GetFileVersionInfoSize(string fileName, out int handle);

[DllImport("version.dll", CharSet = CharSet.Unicode)]
private static extern bool VerQueryValue(byte[] data, string subBlock, out IntPtr buffer, out int len);

var attrs = new string[] {
"Comments","InternalName","ProductName",
"CompanyName","LegalCopyright","ProductVersion",
"FileDescription","LegalTrademarks","PrivateBuild",
"FileVersion","OriginalFilename","SpecialBuild","Test"
};

// 获取文件版本信息的大小
int handle;
int infoSize = GetFileVersionInfoSize(dllPath, out handle);
if (infoSize == 0)
{
    throw new Exception("Failed to get file version info size. Error: " + Marshal.GetLastWin32Error());
}

// 分配缓冲区
byte[] infoBuffer = new byte[infoSize];

// 获取文件版本信息
if (!GetFileVersionInfo(dllPath, 0, infoSize, infoBuffer))
{
    throw new Exception("Failed to get file version info. Error: " + Marshal.GetLastWin32Error());
}

// 获取所有语言代码
IntPtr buffer;
int len;
if (!VerQueryValue(infoBuffer, @"\VarFileInfo\Translation", out buffer, out len))
{
    throw new Exception("Failed to get language codes. Error: " + Marshal.GetLastWin32Error());
}

// 解析语言代码
List<string> languageCodes = new List<string>();
for (int i = 0; i < len / 4; i++)
{
    int langCode = Marshal.ReadInt16(buffer, i * 4);
    int subLangCode = Marshal.ReadInt16(buffer, i * 4 + 2);
    string languageCode = $"{langCode:X4}{subLangCode:X4}";//win下小端存储
    languageCodes.Add(languageCode);
}

// 输出所有语言代码
Console.WriteLine("Available Language Codes:");
foreach (string languageCode in languageCodes)
{
    Console.WriteLine(languageCode);
}

// 选择第一个语言代码
string selectedLanguageCode = languageCodes.Count > 0 ? languageCodes[0] : "040904B0";//默认为英文

foreach (var attr in attrs)
{
    if (!VerQueryValue(infoBuffer, $@"\StringFileInfo\{selectedLanguageCode}\{attr}", out buffer, out len))
    {
        Console.WriteLine($"Failed to get {attr}. Error: " + Marshal.GetLastWin32Error());
    }
    else
    {
        string value = Marshal.PtrToStringUni(buffer);
        Console.WriteLine($"{attr}: " + value);
    }
}

在调用VerQueryValue后,通过buffer获取到内存地址,观察一下内存数据。

image

version信息映射到一段连续内存中存储。

另外还有更简单的方式,通过封装好的FileVersionInfo类进行信息获取,通过各种属性即可获取版本信息。不过,自定义的属性就获取不到了。

FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(dllPath);

FileVersionInfo win平台的实现,内部也是调用了version.dll内的相关api,不过调用的都是Ex方法,并对codepage做了处理。