在 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】:

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;【参考方案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】:

WideCharToMultiByte 可以帮到你。

【讨论】:

WideCharToMultiByte 在一些 Delphi 的内部使用【参考方案6】:

我觉得你有点不对劲。 每个 Win32 API 函数都有一个对应的 unicode,如果它需要一个字符串的话。 尝试 MapAndLoadW 而不是 MapAndLoad...

【讨论】:

没有 MapAndLoadW。这是我看的第一件事。并非所有 Win32 API 都有对应的 unicode,大多数都有,但有些像这样的没有。

以上是关于在 Delphi 2009 中将字符串转换为 PAnsiChar的主要内容,如果未能解决你的问题,请参考以下文章

delphi2009(10,xe)下indy10发送utf8字符串

在 Delphi 中将宽字符代码点的十六进制字符串表示形式转换为宽字符

如何在 Delphi 中将浮点数转换为字符串,指定有效数字,而不是十进制数字(而不是 G 格式)

如何在 Delphi 中将浮点值显示为科学参数

在颤动中将字符串转换为日期时间

如何在 Delphi 中将带有图像的 RichText (RTF) 文档转换为 HTML?