Pergunta

Eu tenho algum código que compila bem com D7 mas falha com D2010. Obviamente, é uma questão Unicode:

O erro de compilação é: E2251 ambígua chamada sobrecarregado para 'StrPas'

Aqui está todo o procedimento:

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;

O doc para StrPas diz

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

Esta função é fornecida apenas retrocompatibilidade Fasor. Para converter uma string terminada em nulo para uma AnsiString ou nativa corda linguagem Delphi, usar um typecast ou um signment.

Portanto, a questão é que eu deveria remover todas as chamadas para StrPas? A única maneira que eu faço isso para compilação é fazer uma Hardcast para Pansi caractere como:

LabelProductName.Caption := StrPas(PAnsiChar(Data));
Foi útil?

Solução

Você editou sua pergunta com uma amostra compilação completa. Bom!

É provavelmente o mais fácil se você usar o JCL para isso (link está abaixo). Em seguida, você poderia usar TJclFileVersionInfo, que faz tudo o que quiser, e leva em conta algumas coisas isotéricos que o VersionInfo pode conter.

Em seguida, sua lógica de negócio se tornaria algo como isto:

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;

E na interface do usuário, você vai precisar ligar para a sua lógica de negócios, e colocar os resultados em vários controles.

- jeroen

Resposta antes de editar:

Seu código não compila como é, assim, sem mais contexto, é difícil de responder sua busca.

Quais são os tipos de dados de buffer, sub-bloco, LongCharSetString e DataLen? Como você obter tampão?

são dados realmente pretende ser um ponteiro para caracteres (ANSI ou Unicode)? não deve, em última análise ser de apontando para PVSFixedFileInfo?

(A questão lado: porque é que a lógica de negócios dentro da interface do usuário Se você tinha dividido a sua lógica em um algum lugar função separada, você provavelmente tem uma rotina de compilação que poderiam ter servido como base para a sua pergunta que pode?. ter respondido a pergunta, em primeiro lugar).

Para questões como a sua, eu costumo dar uma olhada em unidades no JCL ou < a href = "http://jvcl.delphi-jedi.org/" rel = "nofollow noreferrer"> JVCL . Eles colocaram um grande esforço naqueles para ser Unicode compatível.

O código que uso VerQueryValue é este em JclFileUtils unidade, método 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;

Espero que isso faz com que você começou a encontrar sua solução.

- jeroen

Outras dicas

StrPas não foi necessária uma vez que Delphi 1, uma vez que eles mudaram o compilador Delphi para converter a seqüência corretamente sem uma chamada de função. Veja: http: // coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.objectpascal/2004-01/1793.html

Então, basta atribuí-lo, como se segue:

LabelProductName.Caption := PAnsiChar(Data);

E sim, você deve remover todas as chamadas para StrPas. Ele não pode ajudar e só pode colocar você em problemas na D2010.

Eu acho que o principal problema aqui é que os dados são digitados como um Pointer e não um PChar.

Em qualquer caso, o elenco faz todo o trabalho para você, então se você tem que mudar o código de qualquer maneira, o elenco é tão boa como a chamada de função.

Deixe-me reformular isso. Se você tem a corda em um PChar ou PAnsiChar, é atribuição compatível com String. A razão que você precisa de um elenco aqui é que você digitou-lo como Pointer.

Converter PAnsiChar para AnsiString e, em seguida, a seqüência de caracteres Unicode:

LabelProductName.Caption := String(AnsiString(PAnsiChar(Data)));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top