概要
FileInfoクラスでは取得できないバージョン情報リソースを、Win32 APIを介して取得する方法を説明します。
リソースフォーマットの特徴
VERSIONINFOリソースは以下の構造を持ちます:
1 VERSIONINFO
FILEVERSION 1,0,0,323
PRODUCTVERSION 1,0,0,0
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{
BLOCK "000004B0"
{
VALUE "CompanyName", "Example Corp"
VALUE "ProductName", "Sample App"
VALUE "FileVersion", "1.0.0.323"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0000 0x04B0
}
}
実装コード
以下のコードはバージョン情報を取得するためのC#実装です。API呼び出しを最適化し、エラーハンドリングを強化しています。
// Win32 APIのラッパー
[DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool GetFileVersionInfo(string path, int handle, int size, byte[] buffer);
[DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetFileVersionInfoSize(string path, out int handle);
[DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool VerQueryValue(byte[] buffer, string subBlock, out IntPtr data, out int size);
public static Dictionary<string, string> ExtractVersionData(string filePath)
{
int versionSize = GetFileVersionInfoSize(filePath, out _);
if (versionSize <= 0) throw new Win32Exception(Marshal.GetLastWin32Error());
byte[] versionBuffer = new byte[versionSize];
if (!GetFileVersionInfo(filePath, 0, versionSize, versionBuffer))
throw new Win32Exception(Marshal.GetLastWin32Error());
// 言語コードの取得
IntPtr langPtr = IntPtr.Zero;
int langSize = 0;
if (!VerQueryValue(versionBuffer, @"\VarFileInfo\Translation", out langPtr, out langSize))
throw new Win32Exception(Marshal.GetLastWin32Error());
// デフォルト言語を設定(英語)
string languageTag = "040904B0";
if (langSize >= 4)
{
int langId = BitConverter.ToInt32(Marshal.PtrToStructure<int>(langPtr), 0);
languageTag = $"{langId:X8}";
}
// 必要なバージョン属性を取得
var result = new Dictionary<string, string>();
string[] requiredProps = { "CompanyName", "ProductName", "FileVersion" };
foreach (string prop in requiredProps)
{
if (VerQueryValue(versionBuffer, $@"\StringFileInfo\{languageTag}\{prop}", out IntPtr valuePtr, out int valueSize))
{
result[prop] = Marshal.PtrToStringUni(valuePtr);
}
}
return result;
}