3

D7 では問題なくコンパイルできるが、D2010 では失敗するコードがいくつかあります。明らかに、これは Unicode の問題です。

コンパイル エラー: E2251 Ambiguous overloaded call to 'StrPas'

手順全体は次のとおりです。

procedure GetVersionInfo;
type
  PLangCharSetInfo = ^TLangCharSetInfo;
  TLangCharSetInfo = record
    Lang: Word;
    CharSet: Word;
  end;
var
  FileName: array [0..260] of Char;
  SubBlock: array [0..255] of Char;
  VerHandle: Cardinal;
  Size: Word;
  Buffer: Pointer;
  Data: Pointer;
  DataLen: LongWord;
  LangCharSetInfo: PLangCharSetInfo;
  LangCharSetString: string;
begin
  LabelComments.Caption := 'No version information for this program is available!';
  {Get size and allocate buffer for VerInfo}
  if GetModuleFileName(hInstance, FileName, SizeOf(FileName)) > 0 then
  begin
    Size := GetFileVersionInfoSize(FileName, VerHandle);
    if Size > 0 then
    begin
      GetMem(Buffer, Size);
      try
        if GetFileVersionInfo(FileName, VerHandle, Size, Buffer) then
        begin
          {Query first language and that language blocks version info}
          if VerQueryValue(Buffer, '\VarFileInfo\Translation', Pointer(LangCharSetInfo), DataLen) then
          begin
            LangCharSetString := IntToHex(LangCharSetInfo^.Lang, 4) +
                                 IntToHex(LangCharSetInfo^.CharSet, 4);
            if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\ProductName'), Data, DataLen) then
            begin
              LabelProductName.Caption := StrPas(Data);
              Caption := LabelProductName.Caption;
            end;
            if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\FileVersion'), Data, DataLen) then
              LabelVersion.Caption := StrPas(Data);
            if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\LegalCopyright'), Data, DataLen) then
              LabelCopyright.Caption := StrPas(Data);
            if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\Comments'), Data, DataLen) then
              LabelComments.Caption := StrPas(Data);
          end;
        end;
      finally
        FreeMem(Buffer, Size);
      end;
    end
  end;
end;

StrPasのドキュメントによると

function StrPas(const Str: PAnsiChar): AnsiString; overload;

この関数は、下位互換性のためにのみ提供されています。null で終わる文字列を AnsiString またはネイティブの Delphi 言語文字列に変換するには、型キャストまたは記号を使用します。

問題は、 StrPas へのすべての呼び出しを削除する必要があるかどうかです。これをコンパイルする唯一の方法は、次のように PAnsi char にハードキャストすることです。

LabelProductName.Caption := StrPas(PAnsiChar(Data));
4

4 に答える 4

4

関数呼び出しなしで文字列を正しく変換するように Delphi コンパイラが変更されたため、StrPas は Delphi 1 以降は必要ありません。参照: http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.objectpascal/2004-01/1793.html

したがって、次のように割り当てるだけです。

LabelProductName.Caption := PAnsiChar(Data);

はい、StrPas へのすべての呼び出しを削除する必要があります。それは役に立たず、D2010 で問題が発生するだけです。

于 2009-09-20T23:10:19.553 に答える
2

完全なコンパイル サンプルで質問を編集しました。良い!

これに JCL を使用すると、おそらく最も簡単です (リンクは下にあります)。次に、TJclFileVersionInfo を使用できます。これは、必要なすべてのことを行い、VersionInfo が保持できるいくつかの難解なことを考慮に入れます。

次に、ビジネス ロジックは次のようになります。

function GetStringFileInfo(
  const Buffer: Pointer; const SubBlock: PChar;
  const LangCharSetString: string; const Kind: string): string;
var
  QueryString: string;
  Data: Pointer;
  DataCharacters: PChar absolute Data;
  DataLen: LongWord;
begin
  Result := '';
  QueryString := Format('%s\StringFileInfo\%s\%s', [SubBlock, LangCharSetString, Kind]);
  if VerQueryValue(Buffer, PChar(QueryString), Data, DataLen) then
    Result := StrPas(DataCharacters);
end;

procedure GetVersionInfoStrings(var Comments: string; var ProductName: string;
  var Caption: string; var Version: string; var Copyright: string);
type
  PLangCharSetInfo = ^TLangCharSetInfo;
  TLangCharSetInfo = record
    Lang: Word;
    CharSet: Word;
  end;
var
  FileName: array [0 .. 260] of Char;
  SubBlock: array [0 .. 255] of Char;
  VerHandle: Cardinal;
  Size: Word;
  Buffer: Pointer;
  Data: Pointer;
  DataCharacters: PChar absolute Data;
  DataLen: LongWord;
  LangCharSetInfo: PLangCharSetInfo;
  LangCharSetString: string;
begin
  Comments := 'No version information for this program is available!';
  { Get size and allocate buffer for VerInfo }
  if GetModuleFileName(hInstance, FileName, SizeOf(FileName)) > 0 then
  begin
    Size := GetFileVersionInfoSize(FileName, VerHandle);
    if Size > 0 then
    begin
      GetMem(Buffer, Size);
      try
        if GetFileVersionInfo(FileName, VerHandle, Size, Buffer) then
        begin
          { Query first language and that language blocks version info }
          if VerQueryValue(Buffer, '\VarFileInfo\Translation', Pointer
              (LangCharSetInfo), DataLen) then
          begin
            LangCharSetString :=
              IntToHex(LangCharSetInfo^.Lang, 4) +
              IntToHex(LangCharSetInfo^.CharSet, 4);
            ProductName := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'ProductName');
            Version := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'FileVersion');
            Copyright := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'LegalCopyright');
            Comments := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'Comments');
            Caption := ProductName;
          end;
        end;
      finally
        FreeMem(Buffer, Size);
      end;
    end
  end;
end;

UI では、ビジネス ロジックを呼び出し、結果をさまざまなコントロールに入れる必要があります。

--jeroen

編集前の回答:

あなたのコードはそのままではコンパイルされないため、コンテキストがなければ、あなたの探求に答えることは困難です。

Buffer、SubBlock、LongCharSetString、DataLen のデータ型は何ですか? バッファはどのように入手しましたか?

Data は本当に (Ansi または Unicode) 文字へのポインタであることを意図していますか? 最終的には PVSFixedFileInfo を指すべきではないでしょうか。

(補足質問: ビジネス ロジックが UI 内にあるのはなぜですか? ロジックをどこかで別の関数に分割していた場合、おそらく、質問のベースとして機能するコンパイル ルーチンがあったはずです。そもそも質問)。

あなたのような質問に対して、私は通常、JCLまたはJVCLのユニットをのぞき見します。彼らは、Unicode と互換性を持つように多くの努力を払ってきました。

VerQueryValue を使用するコードは、ユニット JclFileUtils、メソッド VersionFixedFileInfo の次のコードです。

// Fixed Version Info routines
function VersionFixedFileInfo(const FileName: string; var FixedInfo: TVSFixedFileInfo): Boolean;
var
  Size, FixInfoLen: DWORD;
  Handle: THandle;
  Buffer: string;
  FixInfoBuf: PVSFixedFileInfo;
begin
  Result := False;
  Size := GetFileVersionInfoSize(PChar(FileName), Handle);
  if Size > 0 then
  begin
    SetLength(Buffer, Size);
    if GetFileVersionInfo(PChar(FileName), Handle, Size, Pointer(Buffer)) and
      VerQueryValue(Pointer(Buffer), DirDelimiter, Pointer(FixInfoBuf), FixInfoLen) and
      (FixInfoLen = SizeOf(TVSFixedFileInfo)) then
    begin
      Result := True;
      FixedInfo := FixInfoBuf^;
    end;
  end;
end;

これが解決策を見つけるきっかけになることを願っています。

--jeroen

于 2009-09-20T13:13:53.253 に答える
2

Pointerここでの主な問題は、 Data がではなくとして型付けされていることだと思いますPChar

いずれにせよ、キャストはすべての作業を行うため、とにかくコードを変更する必要がある場合、キャストは関数呼び出しと同じくらい優れています。

言い換えてみましょう。または に文字列があるPChar場合PAnsiChar、それは と代入互換Stringです。ここでキャストが必要な理由は、 として入力したからPointerです。

于 2009-09-20T08:30:54.323 に答える
1

PAnsiChar を AnsiString に変換してから Unicode 文字列に変換します。

LabelProductName.Caption := String(AnsiString(PAnsiChar(Data)));
于 2009-09-21T07:19:57.380 に答える