バージョン情報取得についてさらに・・

解決


PE  2005-06-09 01:12:56  No: 15457

VerQueryValue  を使ってバージョンを取得しますが、
ここで使用する『041103A4』という数字についてですが

『0411』ってのはロケール番号で
『03A4』ってのはシフトJISを表すって
ことがわかったのですが・・・
って、ことは
OSが変わればこの部分も変わるってこと?
それに、OS以外にも地域オプションの設定内容によっても
変わるのでしょうか?

どのような場合でも対応できるようにしようと思ったら
どうすればよいのでしょうか?
ちなみに、メニューは日本語じゃなく英語(世界標準??)にしてます。
これって安易な考えなんでしょうか?


Basser  2005-06-09 02:01:13  No: 15458

私の場合は、\VarFileInfo\Translation で VerQueryValue が失敗した場合、
OSがサポートするロケール識別子とコードページを組み合わせてサーチしています。

ロケール情報は TLanguages で、
コードページ情報は EnumSystemCodePages(TLanguagesを真似てクラス化)で取得しています。


PE  2005-06-09 20:39:38  No: 15459

いろいろ試してみたのですが・・・
これでよいのでしょうか?
日本語OSでは問題ありませんでした。

function  LoadVersonInfo: String;
var
  ModuleName: array[0..255] of Char;
  nSize:      DWord;
  pBuffer:    PChar;
  pValue:      PDWord;
  nValue:      DWord;
  Str:        String;
  pRead:      PChar;
  nRead:      DWord;
  tsStrings:  TStringList;
begin
  //  パス付きDLLファイル名を取得
  GetModuleFilename(HInstance, ModuleName, SizeOf(ModuleName));
  //  バージョン情報のサイズを取得
  nSize := GetFileVersionInfoSize(ModuleName, nSize);

  if nSize > 0 then  begin
    pBuffer := AllocMem(nSize);
    try
      //  バージョン情報を取得する
      if GetFileVersionInfo(ModuleName, 0, nSize, pBuffer) then begin
        if VerQueryValue(pBuffer, PChar('VarFileInfo\Translation'),                          Pointer(pValue), nValue) then begin
          Str := Format('StringFileInfo\%04.4x%04.4x\FileVersion',
                        [LoWord(DWord(pValue^)), 
                         HiWord(DWord(pValue^))]);
          if VerQueryValue(  pBuffer, PChar(Str), Pointer(pRead), 
                             nRead) then begin
            tsStrings := TStringList.Create;
            try
              ExtractStrings(['.'], [], pRead, tsStrings);
              Result := pRead;
            finally
              tsStrings.Free;
            end;
          end;
        end;
      end;
    finally
      FreeMem(pBuffer, nSize);
    end;
  end;
end;


Basser  2005-06-09 23:41:02  No: 15460

私も日本語環境でしか確認していませんがPEさんあげられたコードのような場合、
Office97等のDLL(言語がニュートラルとなっている)で言語情報の取得に失敗していました。
その為、先に述べたような処理を何処かで見つけて解決しました。
一部、省かしてもらいますが下記のような感じです。

function GetFileVersionInfoString(const FileName, KeyName: String): String;
var
  dwHandle, dwSize, dwLen: DWORD;
  pVerInfo, pLocale: Pointer;
  dwLCID: LCID;

  function GetKeyRecord(LocaleID: LCID): String;
  var
    Buffer : Pointer;
    Mapping: String;
  begin
    Result := '';
    Buffer := nil;
    dwLen  := 0;
    Mapping:= Format('\StringFileInfo\%0.4x%0.4x\%s', [LOWORD(LocaleID), HIWORD(LocaleID), KeyName]);
    VerQueryValue(pVerInfo, PChar(Mapping), Buffer, dwLen);
    if (dwLen <> 0) then SetString(Result, PChar(Buffer), StrLen(PChar(Buffer)));
  end;

  function UnknownLCIDAsString: String;
  var
    I, J: Integer;
    Buffer: String;
    wLng  : TLanguages;
    wCP   : TCodePages; // 自作クラス 生成時に EnumSystemCodePages を実行しリスト化
  begin
    Result:= '';
    wLng:= TLanguages.Create; // ロケール情報リスト作成
    wCP := TCodePages.Create; // コードページ情報リスト作成
    try
      for I:= 0 to wCP.Count - 1 do
        for J:= 0 to wLng.Count - 1 do
        begin
          Buffer:= GetKeyRecord(wCP.CodePageID[I] shl 16 or wLng.LocaleID[J]);
          if (Buffer <> '') then
          begin
            Result:= Buffer;
            Exit;
          end;
        end;
    finally
      wCP.Free;
      wLng.Free;
    end;
  end;

begin

  //
  // バージョン情報リソース取得迄の処理がここに入ります
  //

  // 言語情報の取得
  if VerQueryValue(pVerInfo, '\VarFileInfo\Translation', pLocale, dwLen) then
      CopyMemory(@dwLCID, pLocale, dwLen) else
      dwLCID:= 0;

  // バージョン情報取得処理呼出
  if (dwLCID = 0) then
    Result:= UnknownLCIDAsString else
    Result:= GetKeyRecord(dwLCID);

  //
  // 確保したメモリの後始末がここに入ります
  //

end;

後述ですが、PEさんのソースコードの戻り値の代入部分は間違いではないでしょうか?
コンパイラに怒られそうです。

>            tsStrings := TStringList.Create;
>            try
>              ExtractStrings(['.'], [], pRead, tsStrings);
>              Result := pRead; //← ここ
>            finally
>              tsStrings.Free;
>            end;


PE  2005-06-10 21:00:56  No: 15461

Basser さん、どもです。

えっと、
pRead は var で PChar にしてます。
Result は String なので
キャスト変換なしで Result := pRead; は
コンパイルは通っちゃいます
もちろん実行後も期待通りのバージョンが取得できています。

ひょっとして、偶然?たまたま?
確信があって作ってるわけじゃなくって、
PChar にしたり  @や^つけたり、いろんなこと試して作って
やっとこさコンパイルが通り結果も同じのが出た
ってだけで、実は・・完璧に理解はできていません。


Basser  2005-06-10 22:32:50  No: 15462

本当ですね。今迄、互換性が無いと思っていました。
私の誤った思い込みでしたスミマセンm(_ _)m

tsStrings にバージョン番号を分解しているように見えるので、
こちらを戻り値にするのかなと解釈してました。


PE  2005-06-13 19:38:05  No: 15463

>ExtractStrings(['.'], [], pRead, tsStrings);
この部分は流用してきたプログラムそのままのこってて、
pRead を表示してやると目的のバージョンが得られたので
それを取得したんです。
未熟なものですみませんでした。

Basser さんどうもありがとうございました。
また、よろしくお願いします。


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

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






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