Inno setup 在运行时从可执行文件查询版本信息

Inno setup 在运行时从可执行文件查询版本信息,inno-setup,Inno Setup,我试图查询安装程序安装的文件的版本详细信息,并将其与正在执行的安装程序中的同一文件的版本详细信息进行比较。详细信息不在FileVersion或ProductVersion字段中,但可以在InternalName等其他字段中 我看到了解决此问题的Win32 API,还有一些示例代码,如: 但是,这些代码示例中使用的某些数据类型不适用于Inno设置。此外,一些示例和描述似乎表明语言和代码页本身将是一个数组,但一些示例使用它时假设语言和代码页只有一个条目。 我一直在努力寻找语言和代码页,根据下

我试图查询安装程序安装的文件的版本详细信息,并将其与正在执行的安装程序中的同一文件的版本详细信息进行比较。详细信息不在FileVersion或ProductVersion字段中,但可以在InternalName等其他字段中

我看到了解决此问题的Win32 API,还有一些示例代码,如:

但是,这些代码示例中使用的某些数据类型不适用于Inno设置。此外,一些示例和描述似乎表明语言和代码页本身将是一个数组,但一些示例使用它时假设语言和代码页只有一个条目。 我一直在努力寻找语言和代码页,根据下面的评论,我为我们硬编码了它

我确实看到了答案,其中有Inno Setup Pascal的代码示例,但语言和代码页计算不基于LPBufferCP变量,这让我怀疑它的正确性

是否可以从Inno Setup Pascal脚本读取通用版本信息属性?如果是,请帮助了解如何查找语言和代码页值

下面列出了我基于上述解决方案编写的代码,并对有问题的部分给出了注释

#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的代码?您真正需要的是什么?这是你的可执行文件,对吗?所以你知道它的资源使用什么语言和代码页,不是吗?也许你可以展示一下