我有一些代码可以用D7编译好但是D2010失败了。 显然这是一个Unicode问题:
编译错误是: 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;
此功能仅提供fasor向后兼容性。 将以null结尾的字符串转换为AnsiString或native Delphi语言字符串,使用类型转换或签名。
所以问题是我应该删除对StrPas的所有调用吗? 我编译它的唯一方法是对PAnsi char执行硬编辑:
LabelProductName.Caption := StrPas(PAnsiChar(Data));
答案 0 :(得分:3)
自Delphi 1以来,StrPas并不是必需的,因为他们改变了Delphi编译器,无需函数调用就能正确转换字符串。请参阅:http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.objectpascal/2004-01/1793.html
所以只需分配它,如下:
LabelProductName.Caption := PAnsiChar(Data);
是的,您应该删除对StrPas的所有调用。它无能为力,只能让你在D2010遇到麻烦。
答案 1 :(得分:2)
我认为这里的主要问题是数据输入为Pointer
而不是PChar
。
在任何情况下,演员阵容都会为你完成所有工作,所以如果你不得不改变代码,演员阵容就像函数调用一样好。
让我重新说一下。如果您在PChar
或PAnsiChar
中包含字符串,则与String
分配兼容。你在这里需要演员的原因是你输入的是Pointer
。
答案 2 :(得分: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;
在用户界面中,您需要调用业务逻辑,并将结果放入各种控件中。
- 的Jeroen
编辑前回答:
您的代码不会按原样编译,因此如果没有更多上下文,很难回答您的任务。
Buffer,SubBlock,LongCharSetString和DataLen的数据类型是什么?你是如何获得缓冲区的?
数据真的是指向(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
答案 3 :(得分:1)
将PAnsiChar转换为AnsiString,然后转换为Unicode字符串:
LabelProductName.Caption := String(AnsiString(PAnsiChar(Data)));