我的一些 .dll 文件包含错误的版本号。我想用正确的值更新这些版本而不重建。我找到了这个 UpdateResource 函数,并尝试使用 Platform Invoke 来实现它。
这是我到目前为止所拥有的:
public class UpdateBinaryResource {
class VersionResourceUpdater
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool UpdateResource(IntPtr hUpdate, IntPtr lpType, IntPtr lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
[StructLayout(LayoutKind.Sequential)]
private struct VS_FIXEDFILEINFO
{
public uint dwSignature;
public uint dwStrucVersion;
public uint dwFileVersionMS;
public uint dwFileVersionLS;
public uint dwProductVersionMS;
public uint dwProductVersionLS;
public uint dwFileFlagsMask;
public uint dwFileFlags;
public uint dwFileOS;
public uint dwFileType;
public uint dwFileSubtype;
public uint dwFileDateMS;
public uint dwFileDateLS;
}
public static bool UpdateVersionInfo(string filePath, string productVersion, string fileVersion)
{
string[] fileVersionParts = fileVersion.Split('.');
string[] productVersionParts = productVersion.Split('.');
Console.WriteLine(fileVersionParts[0]);
// combine parts to 32-bit uInt
VS_FIXEDFILEINFO fileInfo = new VS_FIXEDFILEINFO
{
dwSignature = 0xFEEF04BD,
dwStrucVersion = 0x00010000,
dwFileVersionMS = (uint.Parse(fileVersionParts[0]) << 16) | uint.Parse(fileVersionParts[1]),
dwFileVersionLS = (uint.Parse(fileVersionParts[2]) << 16) | uint.Parse(fileVersionParts[3]),
dwProductVersionMS = (uint.Parse(productVersionParts[0]) << 16) | uint.Parse(productVersionParts[1]),
dwProductVersionLS = (uint.Parse(productVersionParts[2]) << 16) | uint.Parse(productVersionParts[3]),
dwFileFlagsMask = 0x3F,
dwFileFlags = 0,
dwFileOS = 0x40004,
dwFileType = 0x1,
dwFileSubtype = 0x0,
dwFileDateMS = 0,
dwFileDateLS = 0
};
Console.WriteLine(fileInfo.dwFileVersionMS);
var fileInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
Marshal.StructureToPtr(fileInfo, fileInfoPtr, false);
IntPtr hUpdate = BeginUpdateResource(filePath, false);
if (hUpdate == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(error, $"Failed to open file for updating: {filePath}. Error code: {error}");
}
byte[] fileInfoBytes = new byte[Marshal.SizeOf(fileInfo)];
Marshal.Copy(fileInfoPtr, fileInfoBytes, 0, fileInfoBytes.Length);
if (!UpdateResource(hUpdate, new IntPtr(16), new IntPtr(1), 0, fileInfoBytes, (uint)fileInfoBytes.Length))
{
int error = Marshal.GetLastWin32Error();
EndUpdateResource(hUpdate, false);
throw new System.ComponentModel.Win32Exception(error, $"Failed to update resource. Error code: {error}");
}
if (!EndUpdateResource(hUpdate, false))
{
int error = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(error, $"Failed to end resource update. Error code: {error}");
}
Marshal.FreeHGlobal(fileInfoPtr);
return true;
}
}
class Program
{
static void Main(string[] args)
{
string dllPath = @"C:\Users\user\Desktop\temp.dll";
string productVer = "23.0.3.0";
string fileVer = "23.0.3.1";
var UpdateBinaryResource = VersionResourceUpdater.UpdateVersionInfo(dllPath, productVer, fileVer);
Console.WriteLine("Success");
}
}
}
运行后,我检查了dll文件属性中的详细信息部分,发现它只删除了以前存在的值,而不是用新值更新版本。
是否可以在不重建的情况下更新版本号?如果可以,可以通过 C# 完成吗?
也需要这个。我发现的唯一解决方案是在内存中构建我自己的 VS_VERSION_INFO 数据结构并将缓冲区传递给
UpdateResource(hUpdate, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), languageID, &buffer, buffer.size());
这个日语博客上的代码对此进行了很好的解释(只需在浏览器中使用翻译):https://espresso3389.hatenablog.com/entry/20100907/1283788958