在 Delphi 2009 中将字符串转换为 PAnsiChar
Posted
技术标签:
【中文标题】在 Delphi 2009 中将字符串转换为 PAnsiChar【英文标题】:Convert string to PAnsiChar in Delphi 2009 【发布时间】:2010-09-21 23:26:19 【问题描述】:我正在将我的应用程序转换为 Delphi 2009,并遇到了一些需要将字符串(宽)转换为 AnsiString 的调用的有趣问题。
这是一个演示我遇到的问题的示例:
var
s: PAnsiChar;
...
s := PAnsiChar(Application.ExeName);
对于 Delphi 2007 和以前的版本,s := PChar(Application.ExeName) 将返回应用程序 exe 路径。
在 Delphi 2009 中,s := PAnsiChar(Application.ExeName) 仅返回“E”。
我的猜测是因为我正在将 unicode 字符串转换为 ansi 字符串,但是如何转换它以便 PAnsiChar 获得完整的字符串?
【问题讨论】:
【参考方案1】:我这里没有 Delphi 2009,所以无法查看。但也许你必须尝试:
s := PAnsiChar(AnsiString(Application.ExeName));
正如 gabr 已经指出的那样,这不是一个很好的做法,只有在 100% 确定时才会使用它。该字符串仅包含直接映射到 ANSI 范围的字符。
这就是您应该收到警告的原因,因为您正在将 Unicode 转换为 ANSI。
【讨论】:
您不应该这样做,因为它是显式转换。而且,是的,它应该可以工作。 我知道,但是转换成 PAnsiChar 也有点问题。 它确实以显式转换为代价。还有其他选择吗?我在下面的回复中解释了转换为 PAnsiChar。 问题是你总是有信息丢失的机会。将 PAnsiChar 更改为字符串可能会更好。 在 XE5 中,这个问题导致我调用 dll 失败,包括 shellexecute。简单地强制转换 PAnsiChar(myStringVar) 会导致不可检测和不可重现的错误,我很沮丧,直到外部 dll 发生同样的事情并且我找到了这个解决方案。现在工作正常。任何有 shell 执行问题的人也应该检查一下。【参考方案2】:不要使用String
,而是使用RawByteString
:
s: RawByteString;
s := LoadSomeRegularString(usually a string type);
PAnsiChar(s) <<< all fine.
【讨论】:
不,不要那样做。这完全是对RawByteString
的滥用。不要这样做,而是阅读RawByteString
的文档并找出它的真正用途。【参考方案3】:
WideCharToMultiByte 可以帮到你。
【讨论】:
WideCharToMultiByte 在 Delphi 的某些类型中内部使用【参考方案4】:我遇到了完全相同的问题。 PAnsiChar
仅指向第一个字符。我编写了以下函数来处理旧功能。
// This function converts a string to a PAnsiChar
// If the output is not the same, an exception is raised
// Author: nogabel@hotmail.com
function StringToPAnsiChar(stringVar : string) : PAnsiChar;
Var
AnsString : AnsiString;
InternalError : Boolean;
begin
InternalError := false;
Result := '';
try
if stringVar <> '' Then
begin
AnsString := AnsiString(StringVar);
Result := PAnsiChar(PAnsiString(AnsString));
end;
Except
InternalError := true;
end;
if InternalError or (String(Result) <> stringVar) then
begin
Raise Exception.Create('Conversion from string to PAnsiChar failed!');
end;
end;
【讨论】:
PAnsiChar(AnsiString(stringVar))
就是你所需要的。
AnsString 是一个局部变量会不会有问题,因此指向该变量的 Result 在函数退出后将不再可用?换句话说,等待中的访问冲突?【参考方案5】:
我觉得你有点不对劲。 每个 Win32 API 函数都有一个对应的 unicode,如果它需要一个字符串的话。 尝试 MapAndLoadW 而不是 MapAndLoad...
【讨论】:
没有 MapAndLoadW。这是我看的第一件事。并非所有 Win32 API 都有对应的 unicode,大多数都有,但有些像这样的没有。【参考方案6】:Gamecat 显式转换有效。我将在下面更详细地解释这个问题,以便有人可以指出更好的解决方案。
我正在使用以下函数来检索应用程序编译日期:
function LinkerTimeStamp(const FileName: string): TDateTime;
var
LI: TLoadedImage;
begin
$IFDEF UNICODE
Win32Check(MapAndLoad(PAnsiChar(AnsiString(FileName)), nil, @LI, False, True));
$ELSE
Win32Check(MapAndLoad(PChar(FileName), nil, @LI, False, True));
$ENDIF
Result := LI.FileHeader.FileHeader.TimeDateStamp / SecsPerDay + UnixDateDelta;
UnMapAndLoad(@LI);
end;
MapAndLoad 需要一个 PAnsiChar 作为 ImageName 参数,所以我需要转换 unicode 字符串。有没有其他方法可以先显式转换为 AnsiString?
【讨论】:
不,我认为没有 Unicode 版本。 CodeGear Imagehlp 单元将 MapAndLoad 声明为映射到 PAnsiChar 的 LPSTR。在 msdn 上也没有提及 Unicode 版本。 您可能应该添加一个注释,您为 Unicode 兼容性所做的更改,并完全删除 IFDEF - PAnsiChar 和 AnsiString 至少在 Delphi 4 中已经可用,并且类型转换在 Ansi 程序中不会受到伤害。代码越简单越好恕我直言。 这个 IFDEF 毫无意义。只需写PAnsiChar(AnsiString(FileName))
即可。当然,更好的解决方案是找到MapAndLoad
的替代方案,它不会那么蹩脚以至于需要 ANSI 输入。
更好的解决方案,因为您在执行模块上执行此操作,如下所示:Result := PImageNtHeaders(HInstance + PImageDosHeader(HInstance)^._lfanew)^.FileHeader.TimeDateStamp / SecsPerDay + UnixDateDelta;
以上是关于在 Delphi 2009 中将字符串转换为 PAnsiChar的主要内容,如果未能解决你的问题,请参考以下文章
delphi2009(10,xe)下indy10发送utf8字符串
在 Delphi 中将宽字符代码点的十六进制字符串表示形式转换为宽字符