2016-11-15 12 views
0

インストーラがインストールするファイルのバージョンの詳細を問い合わせて、実行中のインストーラに存在する同じファイルのバージョンの詳細と比較しようとしています。実行時の実行ファイルからのバージョン情報の照会

ただし、これらのコードサンプルで使用されているデータタイプの一部は、Inno Setupでは動作しません。さらに、いくつかのサンプルおよび説明は、言語およびコードページ自体が配列であるが、一部のサンプルでは、​​言語およびコードページのエントリが1つしかないと仮定して使用することを示しているようである。 私は言語とコードページを見つけようとしていましたが、以下のコメントに基づいて、en-usのためにそれをハードコードしました。

私はInno Setup Pascalのコードサンプルがあるthis答えを参照していますが、lplpBufferCP変数に基づいていない言語とコードページの計算では、その正確性が疑わしいです。

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つの特性に興味を持っています)レジストリ内のインストールされたファイルのファイルプロパティを保存することで、新しいファイルのために静的にインストーラで利用可能なプロパティを持つことができます。

+0

@Jens A. Kochさんがコードを試しましたか? –

+0

実際に必要なのは何ですか?あなたの実行ファイルですよね?だからあなたはそのリソースにどのような言語とコードページが使用されているのか知っていますか? –

+0

質問をより明確にするために、実行可能ファイルのバージョン情報のダンプを表示することができます。 –

答えて

1

ファイルバージョン情報の最初の言語から文字列を取得する正しいコードは次のとおりです。コードはanswer by @Jens A. KochHow to write data to an installer on the server?

で構成されています。このコードでは、UnicodeバージョンのInno Setupが必要です。

function GetFileVersionInfoSize(lptstrFilename: String; lpdwHandle: Integer): Integer; 
    external '[email protected] stdcall delayload'; 

function GetFileVersionInfo(
    lptstrFilename: String; dwHandle, dwLen: Integer; var lpData: Byte): Boolean; 
    external '[email protected] stdcall delayload'; 

function VerQueryValue(
    var pBlock: Byte; lpSubBlock: String; var lplpBuffer: DWord; 
    var Len: Integer): Boolean; 
    external '[email protected] stdcall delayload'; 

procedure RtlMoveMemoryAsString(Dest: string; Source: DWord; Len: Integer); 
    external '[email protected] stdcall'; 

procedure RtlMoveMemoryAsBytes(Dest: array of Byte; Source: DWord; Len: Integer); 
    external '[email protected] stdcall'; 

function GetFileVerInfo(FileName, VerName: String): String; 
var 
    Len: Integer; 
    FileVerInfo: array of Byte; 
    Lang: array of Byte; 
    Buffer: DWord; 
    LangCodepage: string; 
    SubBlock: string; 
begin 
    Result := ''; 
    if FileExists(FileName) then 
    begin 
    Len := GetFileVersionInfoSize(FileName, 0); 
    if Len > 0 then 
    begin 
     SetArrayLength(FileVerInfo, Len); 
     if GetFileVersionInfo(FileName, 0, Len, FileVerInfo[0]) then 
     begin 
     if VerQueryValue(FileVerInfo[0], '\VarFileInfo\Translation', Buffer, Len) then 
     begin 
      if Len >= 4 then 
      begin 
      SetArrayLength(Lang, 4); 
      RtlMoveMemoryAsBytes(Lang, Buffer, 4); 
      LangCodepage := 
       Format('%.2x%.2x%.2x%.2x', [Lang[1], Lang[0], Lang[3], Lang[2]]); 
      SubBlock := Format('\%s\%s\%s', ['StringFileInfo', LangCodepage, VerName]); 
      if VerQueryValue(FileVerInfo[0], SubBlock, Buffer, Len) then 
      begin 
       SetLength(Result, Len - 1); 
       RtlMoveMemoryAsString(Result, Buffer, (Len - 1) * 2); 
      end; 
      end; 
     end; 
     end; 
    end; 
    end; 
end; 
+0

マーティンに感謝します。 Win32 APIのOUTパラメータからデータを取得する方法については他にも質問がありましたが、RtlMoveMemoryXXX()APIを使用して説明したものはありませんでした。 Lang [1]、Lang [0]、Lang [3]、Lang [2]を使用するFormat()呼び出しからは、エンディアン固有のようです。そうですか、それとも別のものですか? – Anand

+0

この目的のための 'RtlMoveMemory'の使用は私の"発明 "です+はい、それはエンディアンについてです。 –

関連する問題