Inno setup 在运行时从可执行文件查询版本信息
我试图查询安装程序安装的文件的版本详细信息,并将其与正在执行的安装程序中的同一文件的版本详细信息进行比较。详细信息不在FileVersion或ProductVersion字段中,但可以在InternalName等其他字段中 我看到了解决此问题的Win32 API,还有一些示例代码,如:Inno setup 在运行时从可执行文件查询版本信息,inno-setup,Inno Setup,我试图查询安装程序安装的文件的版本详细信息,并将其与正在执行的安装程序中的同一文件的版本详细信息进行比较。详细信息不在FileVersion或ProductVersion字段中,但可以在InternalName等其他字段中 我看到了解决此问题的Win32 API,还有一些示例代码,如: 但是,这些代码示例中使用的某些数据类型不适用于Inno设置。此外,一些示例和描述似乎表明语言和代码页本身将是一个数组,但一些示例使用它时假设语言和代码页只有一个条目。 我一直在努力寻找语言和代码页,根据下
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function GetFileVersionInfoSize(lptstrFilename: String; lpdwHandle: Integer): Integer;
external 'GetFileVersionInfoSize{#AW}@version.dll stdcall delayload';
function GetFileVersionInfo(lptstrFilename: String; dwHandle, dwLen: Integer; var lpData: Byte): Boolean;
external 'GetFileVersionInfo{#AW}@version.dll stdcall delayload';
function VerQueryValue(var pBlock: Byte; lpSubBlock: String; var lplpBuffer: Byte; var puLen: Integer): Boolean;
external 'VerQueryValue{#AW}@version.dll stdcall delayload';
function GetFileVersionProperty(const FileName, PropertyName: String): String;
var
VerSize: Integer;
VerInfo: array of Byte;
Dummy: Integer;
InternalNameArr: array of Byte;
begin
Result := '';
if not FileExists(FileName) then
begin
Log('File ' + FileName + ' does not exist');
Exit;
end;
VerSize := GetFileVersionInfoSize(FileName, 0);
if not VerSize > 0 then
begin
Log('File ' + FileName + ' has no version information');
Exit;
end;
SetArrayLength(VerInfo, VerSize);
if not GetFileVersionInfo(FileName, 0, VerSize, VerInfo[0]) then
begin
Log('Failed to get version info for ' + FileName);
Exit;
end;
if not GetFileVersionInfo(FileName, 0, VerSize, VerInfo[0]) then
begin
Log('Failed to get version info for ' + FileName);
Exit;
end;
{ Getting 'Version size = 2156' }
Log(Format('Version size = %d', [VerSize]));
{ Hard coded value just for testing }
SetArrayLength(InternalNameArr, 512);
{ 040904E4 hard coded for en-us }
{ Is this the correct way of querying the details ? }
{ If not, what needs to be done here }
{ TODO : InternalName hard coded. Use parameter PropertyName }
if VerQueryValue(VerInfo[0], '\StringFileInfo\040904E4\InternalName', InternalNameArr[0], Dummy) then
begin
Log('Failed to query internal name of ' + FileName);
Exit;
end
else
begin
{ What needs to be done here to convert an array of byte to string ? }
{ Do I need to iterate over the array and do the conversion ?}
{ The following does not work because of SetString() being unavailable : }
{ InternalName = SetString(AnsiStr, PAnsiChar(@InternalNameArr[0]), Len);}
{ Getting 'ProductName = 0000' and 'Dummy = 0' }
Log(Format('ProductName = %d%d', [InternalNameArr[0], InternalNameArr[1], InternalNameArr[2], InternalNameArr[3]]));
Log(Format('Dummy = %d', [Dummy]));
end;
{ TODO : Populate Result with appropriate value }
end;
另一种方法是将已安装文件的文件属性保存在注册表中(我对其中1个文件的1个属性感兴趣),并使新文件的属性在安装程序中静态可用。下面是从文件版本信息的第一语言检索字符串的正确代码。该代码构建在to的基础上 该代码需要Unicode版本的Inno安装程序
函数getFileVersionInfo大小(lptstrFilename:String;lpdwHandle:Integer):整数;
外部的GetFileVersionInfoSizeW@version.dllstdcall delayload';
函数GetFileVersionInfo(
lptstrFilename:String;dwHandle,dwLen:Integer;var lpData:Byte):布尔值;
外部的GetFileVersionInfoW@version.dllstdcall delayload';
函数VerQueryValue(
var-pBlock:Byte;lpSubBlock:String;var-lpbuffer:DWord;
变量Len:Integer):布尔值;
外部的VerQueryValueW@version.dllstdcall delayload';
过程rtlmovemoryastring(Dest:string;Source:DWord;Len:Integer);
外部的RtlMoveMemory@kernel32.dllstdcall';
过程rtlmovemoryasbytes(Dest:Byte数组;Source:DWord;Len:Integer);
外部的RtlMoveMemory@kernel32.dllstdcall';
函数GetFileVerInfo(文件名,VerName:String):String;
变量
Len:整数;
FileVerInfo:字节数组;
Lang:字节数组;
缓冲区:DWord;
LangCodepage:字符串;
子块:字符串;
开始
结果:='';
如果文件存在(文件名),则
开始
Len:=getFileVersionInfo大小(文件名,0);
如果Len>0,则
开始
设置阵列长度(FileVerInfo,Len);
如果GetFileVersionInfo(文件名,0,Len,FileVerInfo[0]),则
开始
如果VerQueryValue(FileVerInfo[0],'\VarFileInfo\Translation',Buffer,Len),则
开始
如果Len>=4,则
开始
SetArrayLength(Lang,4);
rtlmovemoryasbytes(Lang,Buffer,4);
语言代码页:=
格式('.2x%.2x%.2x%.2x%.2x',[Lang[1],Lang[0],Lang[3],Lang[2]]);
子块:=格式('\%s\%s\%s',['StringFileInfo',LangCodepage,VerName]);
如果VerQueryValue(FileVerInfo[0],子块,缓冲区,Len),则
开始
设置长度(结果,Len-1);
rtlmovemoryastring(结果,缓冲区,(Len-1)*2);
结束;
结束;
结束;
结束;
结束;
结束;
结束;
从文件版本信息的第一语言检索字符串的正确代码如下。该代码构建在to的基础上
该代码需要Unicode版本的Inno安装程序
函数getFileVersionInfo大小(lptstrFilename:String;lpdwHandle:Integer):整数;
外部的GetFileVersionInfoSizeW@version.dllstdcall delayload';
函数GetFileVersionInfo(
lptstrFilename:String;dwHandle,dwLen:Integer;var lpData:Byte):布尔值;
外部的GetFileVersionInfoW@version.dllstdcall delayload';
函数VerQueryValue(
var-pBlock:Byte;lpSubBlock:String;var-lpbuffer:DWord;
变量Len:Integer):布尔值;
外部的VerQueryValueW@version.dllstdcall delayload';
过程rtlmovemoryastring(Dest:string;Source:DWord;Len:Integer);
外部的RtlMoveMemory@kernel32.dllstdcall';
过程rtlmovemoryasbytes(Dest:Byte数组;Source:DWord;Len:Integer);
外部的RtlMoveMemory@kernel32.dllstdcall';
函数GetFileVerInfo(文件名,VerName:String):String;
变量
Len:整数;
FileVerInfo:字节数组;
Lang:字节数组;
缓冲区:DWord;
LangCodepage:字符串;
子块:字符串;
开始
结果:='';
如果文件存在(文件名),则
开始
Len:=getFileVersionInfo大小(文件名,0);
如果Len>0,则
开始
设置阵列长度(FileVerInfo,Len);
如果GetFileVersionInfo(文件名,0,Len,FileVerInfo[0]),则
开始
如果VerQueryValue(FileVerInfo[0],'\VarFileInfo\Translation',Buffer,Len),则
开始
如果Len>=4,则
开始
SetArrayLength(Lang,4);
rtlmovemoryasbytes(Lang,Buffer,4);
语言代码页:=
格式('.2x%.2x%.2x%.2x%.2x',[Lang[1],Lang[0],Lang[3],Lang[2]]);
子块:=格式('\%s\%s\%s',['StringFileInfo',LangCodepage,VerName]);
如果VerQueryValue(FileVerInfo[0],子块,缓冲区,Len),则
开始
设置长度(结果,Len-1);
rtlmovemoryastring(结果,缓冲区,(Len-1)*2);
结束;
结束;
结束;
结束;
结束;
结束;
结束;
那么您是否尝试了@Jens A.Koch的代码?您真正需要的是什么?这是你的可执行文件,对吗?所以你知道它的资源使用什么语言和代码页,不是吗?也许你可以展示一下