2009-09-20 67 views
3

我有一些代碼與D7編譯良好,但與D2010失敗。 顯然,這是一個Unicode的問題:如何將以空字符結尾的字符串轉換爲AnsiString?

的編譯錯誤是: E2251歧義超載調用 '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; 

此功能僅提供向後兼容性。 要將以空字符結尾的字符串轉換爲AnsiString或本地的 Delphi語言字符串,請使用類型轉換或簽名。

所以問題是我應該刪除所有對StrPas的調用? 我有這樣的編譯的唯一方法是做一個hardcast到盤絲字符,如:

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

回答

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的數據類型是什麼?你是如何獲得Buffer的?

數據是否真的是指向(Ansi或Unicode)字符的指針?它不應該最終指向PVSFixedFileInfo嗎?

(一個側面的問題:爲什麼你的業務邏輯在UI內?如果你已經把邏輯分成了一個獨立的函數,你可能會有一個編譯例程,可以作爲你的問題的基礎。首先可能會回答這個問題)。

對於像您這樣的問題,我通常會看一下JCLJVCL中的單位。他們已經付出了很多努力來與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

+0

感謝您的回答和示例。我現在發佈了整個程序。爲了避免引入錯誤,我不想進行超出必要的修改。 – 2009-09-20 14:37:40

2

我覺得這裏的主要問題是數據的類型是Pointer而不是PChar

在任何情況下,演員都會爲你做所有的工作,所以如果你不得不改變代碼,那麼演員就和函數調用一樣好。

讓我改述一下。如果您的字符串是PCharPAnsiChar,則它與String分配兼容。你需要在這裏演員的原因是你輸入了Pointer

+1

換句話說:聲明VAR數據:PAnsiChar似乎是一個不錯的解決方案。 – 2009-09-20 08:38:23

+1

如果可以的話,但那麼,不會第一個方法調用不編譯,因爲它看起來像它使用數據的「var」參數? – 2009-09-20 08:59:45

1

轉換PAnsiChar到AnsiString類型,然後將Unicode字符串:

LabelProductName.Caption := String(AnsiString(PAnsiChar(Data))); 
相關問題