Domanda

Ho qualche codice che compila bene con D7, ma fallisce con D2010. Ovviamente si tratta di un problema Unicode:

L'errore di compilazione è: E2251 ambiguo chiamata overload per 'StrPas'

Qui è l'intera procedura:

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;

Il dottore per StrPas dice

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

Questa funzione viene fornita solo per compatibilità all'indietro fasor. Per convertire una stringa alla terminazione Null a un AnsiString o nativo stringa di linguaggio Delphi, utilizzare un typecast o un segnazione.

Quindi la domanda è dovrei rimuovere tutte le chiamate a StrPas? L'unico modo in cui faccio questo per compilare è quello di fare un Hardcast per Pansi char come:

LabelProductName.Caption := StrPas(PAnsiChar(Data));
È stato utile?

Soluzione

Hai modificato la tua domanda con un campione completo compilazione. Buona!

E 'probabilmente il più facile se si desidera utilizzare il JCL per questo (link è qui sotto). Allora si potrebbe utilizzare TJclFileVersionInfo, che fa tutto quello che volete, e prende in considerazione alcune cose esoterico che il VersionInfo può contenere.

Poi la logica di business sarebbe diventato qualcosa di simile:

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 nell'interfaccia utente, è necessario chiamare la logica di business, e mettere i risultati nei vari controlli.

- Jeroen

Risposta prima edit:

Il codice non viene compilato come è, quindi senza più contesto, è difficile rispondere alla sua missione.

Quali sono i tipi di dati di Tampone, blocco secondario, LongCharSetString e datalen? Come hai fatto a ottenere Buffer?

sono dati veramente destinata a essere un puntatore a (ANSI o Unicode) personaggi? Non dovrebbe infine essere di punta al PVSFixedFileInfo?

(Una domanda laterale: perché è la logica di business all'interno della interfaccia utente Se tu avessi dividere la logica in una funzione separata da qualche parte, si sarebbe probabilmente hanno una routine di compilazione che avrebbe potuto servire come base per la domanda che potrebbe. hanno risposto alla domanda, in primo luogo).

Per questioni come la vostra, io di solito dare uno sguardo a unità nel JCL o < a href = "http://jvcl.delphi-jedi.org/" rel = "nofollow noreferrer"> JVCL . Hanno messo un sacco di fatica in quelli per essere compatibile con Unicode.

Il loro codice che utilizzano VerQueryValue è questo in JclFileUtils unità, metodo 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;

Spero che questo si è iniziato a trovare la soluzione.

- Jeroen

Altri suggerimenti

StrPas non sono stati richiesti dal Delphi 1, dal momento che hanno cambiato il compilatore Delphi per convertire la stringa correttamente senza una chiamata di funzione. Vedere: http: // coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.objectpascal/2004-01/1793.html

Quindi, solo assegnarlo, come segue:

LabelProductName.Caption := PAnsiChar(Data);

E sì, è necessario rimuovere tutte le chiamate a StrPas. Non può aiutare e può solo finire nei guai in D2010.

Credo che il problema principale è che i dati viene data come Pointer e non un PChar.

In ogni caso, il cast fa tutto il lavoro per voi, quindi se si deve modificare il codice in ogni caso, il cast è altrettanto buono come la chiamata di funzione.

Mi permetta di riformulare questo. Se avete la stringa in un PChar o PAnsiChar, è l'assegnazione-compatibile con String. Il motivo è necessario un cast qui è che avete digitato come Pointer.

Convertire PAnsiChar a AnsiString e poi a stringa Unicode:

LabelProductName.Caption := String(AnsiString(PAnsiChar(Data)));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top