初めて質問させてもらいます。
とある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 です。
> ヘルプに載ってなくお手上げです
Windows APIですから。
http://www.microsoft.com/japan/msdn/library/ja/jpwinui/html/_win32_VerQueryValue.asp
>「言語」の欄に複数の言語が設定されているのがアヤシイ
「バージョン情報値の文字列」は正しく作成できているのでしょうか?
コードに正しい文字列を書いて取得できるか、試してみたらどうでしょう。
詳しく調べないと分かりませんが、
//バージョン情報値の文字列を作成
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'ですね。なんでだろ。
おおっ日本語だ。ふむふむ。
040904E4はUS.Englishでした。
さっきからずーっとやってたんですがどうしてもブランクしか取得できず、こりゃおかしいと思って
ネットで調べたら、ありました。
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
この辺を直入力するのがベストでしょうかねぇ。
参考までに
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;
お返事ありがとうございます。
>えーとさん
参照されたページを読んでみましたが、自分の乏しい知識では<lang-codepage>に入れるべき正しい値がわかりませんでした。
もっと勉強せねば・・・
>ママんさん
8を4に変えたら無事取得できました。
ファイルのプロパティの言語欄に英語(U.S)が無いのになんだか不思議ですね。
>VerQueryValueでも調べて結果を教えてください。
すみません。何を調べればいいのかいまいちわかりませんでした。
いろいろなexeファイルを試して、言語が日本語、外国語に関係なく、一つの言語が設定されているファイルはうまくいったのに、
複数の言語が設定されてるファイルだけ上手くいかなかったので、複数の言語が設定されている場合は特別な操作が必要なのかと思っていましたが、
一つなのか複数なのかはあまり関係ないみたいですね。
↑の返事を書いてる間に詳しい解説が追加されてる・・・
これからコードを解読して参考にさせてもらいます。ありがとうございます。
ツイート | ![]() |