複数の言語で設定されたexeファイルのバージョン情報を取得するには?

解決


coo  2005-10-15 22:26:38  No: 18106

初めて質問させてもらいます。
とあるexeファイルのバージョン情報を取得したいと思い、
「About Delphi」のサイトのTips「リソースにあるバージョン情報を取得したい。」を参考に以下のようなコードを書きました。ほとんどコピペしただけですが・・・

/////////////////////////ここから
function GetVerInfo(const FileName: String; KeyStr: String): String;
var
  Handle, InfoSize, Len: DWORD;
  Data, Value: PChar;
  Buffer: Pointer;
  s: String;
begin
  Result := '';
  //バージョン情報のサイズを取得
  Handle := 0;
  InfoSize := GetFileVersionInfoSize(PChar(FileName), Handle);
  if InfoSize > 0 then begin
    Data := AllocMem(InfoSize);
    try
      //バージョン情報の取得
      Win32Check(GetFileVersionInfo(PChar(FileName), Handle,
                                           InfoSize, Data));
      //言語識別子と文字セット識別子の取得
      Win32Check(VerQueryValue(Data,
                               PChar('\VarFileInfo\Translation'),
                               Buffer, Len));
      //バージョン情報値の文字列を作成
      s := Format('\StringFileInfo\%4.4x%4.4x\%s',
                  [LongRec(PDWORD(Buffer)^).Lo,
                   LongRec(PDWORD(Buffer)^).Hi,
                   KeyStr]);
      //バージョン情報取得
      if VerQueryValue(Data, PChar(s), Pointer(Value), Len) then begin
        Result := Value;
      end;
    finally
      FreeMem(Data, InfoSize);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FileName: String;
begin

  FileName := 'c:\hoge\hoge.exe';    *実際には目的のexeファイルにしてます*
  Memo1.Clear;
  with Memo1.Lines do begin
    Add('Comments='         + GetVerInfo(FileName, 'Comments'));
    Add('CompanyName='      + GetVerInfo(FileName, 'CompanyName'));
    Add('FileDescription='  + GetVerInfo(FileName, 'FileDescription'));
    Add('FileVersion='      + GetVerInfo(FileName, 'FileVersion'));
    Add('InternalName='     + GetVerInfo(FileName, 'InternalName'));
    Add('LegalCopyright='   + GetVerInfo(FileName, 'LegalCopyright'));
    Add('LegalTrademarks='  + GetVerInfo(FileName, 'LegalTrademarks'));
    Add('OriginalFilename=' + GetVerInfo(FileName, 'OriginalFilename'));
    Add('PrivateBuild='     + GetVerInfo(FileName, 'PrivateBuild'));
    Add('ProductName='      + GetVerInfo(FileName, 'ProductName'));
    Add('ProductVersion='   + GetVerInfo(FileName, 'ProductVersion'));
    Add('SpecialBuild='     + GetVerInfo(FileName, 'SpecialBuild'));
  end;
end;
/////////////////////////ここまで

ところが実行してみるとバージョン情報が表示されません。Comments=までは表示されますが、その値が空欄になります。(CompanyNameなども同様です)
ためしに他のexeファイルを対象にしたところ、情報を取得できるファイルとできないファイルがあるようです。
いろいろ調べたところ、取得できるのは「言語」に一つの言語が設定されているexeファイル、
できないのは「言語」に複数のの言語が設定されているexeファイルのようです。
次に、コードの各所にShowMessageを挟んでみたところ、複数の言語が設定されているファイルを対象にしたときは
if VerQueryValue(Data, PChar(s), Pointer(Value), Len) then begin
の部分でfalseが返されてそれ以降が実行されて無いようです。(2箇所の  Win32Check〜〜  の文はtrueを返しました)
そこでVerQueryValueをヘルプで調べようとしたのですが、ヘルプに載ってなくお手上げです。
複数の言語が設定されているexeファイルを対象にしても正常に実行されるようにするにはどうしたらいいのでしょうか?

長くなったのでまとめます。
1.あるexeファイルのバージョン情報を取得しようとしたが上手くいかない
2.情報を取得できないexeファイルを調べてみると、「言語」の欄に複数の言語が設定されているのがアヤシイ
3.情報を取得できないときは  if VerQueryValue(Data, PChar(s), Pointer(Value), Len) then  でfalseが返されてしまう
4.これを上手く実行させるにはどうしたらいいのでしょうか

ちなみにバージョン情報を取得したいと思っている対象のexeファイルは
http://64.simutrans.com/simuwin-86-10-4.zip
からダウンロードできます。
最後に、自分の環境は、
Delphi 6 Personal  +  Windows2000  です。


えーと  2005-10-16 23:51:38  No: 18107

> ヘルプに載ってなくお手上げです
Windows APIですから。

http://www.microsoft.com/japan/msdn/library/ja/jpwinui/html/_win32_VerQueryValue.asp

>「言語」の欄に複数の言語が設定されているのがアヤシイ
「バージョン情報値の文字列」は正しく作成できているのでしょうか?
コードに正しい文字列を書いて取得できるか、試してみたらどうでしょう。


ママん  2005-10-17 00:04:25  No: 18108

詳しく調べないと分かりませんが、
//バージョン情報値の文字列を作成
s := Format('\StringFileInfo\%4.4x%4.4x\%s',
            [LongRec(PDWORD(Buffer)^).Lo,
             LongRec(PDWORD(Buffer)^).Hi,
             KeyStr]);

s='\StringFileInfo\040?????\Comments';
'040'のはずが'080'と返ってるのが原因です。
ただし多くの場合'080'で取得可能なようです
s[16+2]:='4';
とすれば正常に取得できます。
VerQueryValueでも調べて結果を教えてください。
ぱっと海外のサンプルを見た限りでも'080'ですね。なんでだろ。


ママん  2005-10-17 00:13:14  No: 18109

おおっ日本語だ。ふむふむ。
040904E4はUS.Englishでした。


ママん  2005-10-17 02:33:47  No: 18110

さっきからずーっとやってたんですがどうしてもブランクしか取得できず、こりゃおかしいと思って
ネットで調べたら、ありました。
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+WinBatch/Functions+FileVerinfo~and~Language~Keys.txt
VerQueryValueでSDKのサンプルのように国情報を拾ってきて、UNICODEで文字列を得ようとしてもブランクしか返ってきません。(もしかしたら間違ってるかもしれないけど…)

;      040904E4       U.S. English   Windows Multilingual
;      040904B0       U.S. English   Unicode
;      000004E4       Neutral        Windows Multilingual
;      04090000       U.S. English   Neutral
;      00000000       Neutral        Neutral
この辺を直入力するのがベストでしょうかねぇ。


ママん  2005-10-17 02:42:38  No: 18111

参考までに
function GetFileVersionCountry(const FileName:string): string;
type
  PDWORD = ^DWORD;
  PLangAndCodePage = ^TLangAndCodePage;
  TLangAndCodePage = packed record
    wLanguage: WORD;
    wCodePage: WORD;
  end;
  PLangAndCodePageArray = ^TLangAndCodePageArray;
  TLangAndCodePageArray = array[0..0] of TLangAndCodePage;
var
  loc_InfoBufSize: DWORD;
  loc_InfoBuf: PChar;
  loc_VerBufSize: DWORD;
  loc_VerBuf: PChar;
  cbTranslate: DWORD;
  lpTranslate: PDWORD;
  i: DWORD;
  str,str2:string;
begin
  Result := '';
  if (Length(FileName) = 0) or (not Fileexists(FileName)) then
    Exit;
  loc_InfoBufSize := GetFileVersionInfoSize(PChar(FileName), loc_InfoBufSize);
  if loc_InfoBufSize > 0 then
  begin
    loc_VerBuf := nil;
    loc_InfoBuf := AllocMem(loc_InfoBufSize);
    try
      if not GetFileVersionInfo(PChar(FileName), 0, loc_InfoBufSize, loc_InfoBuf)
        then
        exit;
      if not VerQueryValue(loc_InfoBuf, '\VarFileInfo\Translation',
        Pointer(lpTranslate), DWORD(cbTranslate)) then
        exit;
      str2:='';
      for i := 0 to (cbTranslate div SizeOf(TLangAndCodePage)) - 1 do
      begin
        str:=          Format(
                       '%4.4x%4.4x',
                       [PLangAndCodePageArray(lpTranslate)[i].wLanguage,
                        PLangAndCodePageArray(lpTranslate)[i].wCodePage]);
        str2 := str + #13#10 + str2;
      end;
      Result:=str2;
    finally
      FreeMem(loc_InfoBuf, loc_InfoBufSize);
    end;
  end;
end;


coo  2005-10-17 02:45:00  No: 18112

お返事ありがとうございます。

>えーとさん
参照されたページを読んでみましたが、自分の乏しい知識では<lang-codepage>に入れるべき正しい値がわかりませんでした。
もっと勉強せねば・・・

>ママんさん
8を4に変えたら無事取得できました。
ファイルのプロパティの言語欄に英語(U.S)が無いのになんだか不思議ですね。
>VerQueryValueでも調べて結果を教えてください。
すみません。何を調べればいいのかいまいちわかりませんでした。

いろいろなexeファイルを試して、言語が日本語、外国語に関係なく、一つの言語が設定されているファイルはうまくいったのに、
複数の言語が設定されてるファイルだけ上手くいかなかったので、複数の言語が設定されている場合は特別な操作が必要なのかと思っていましたが、
一つなのか複数なのかはあまり関係ないみたいですね。


coo  2005-10-17 02:47:33  No: 18113

↑の返事を書いてる間に詳しい解説が追加されてる・・・
これからコードを解読して参考にさせてもらいます。ありがとうございます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加