【问题标题】:Convert string to PAnsiChar in Delphi 2009在 Delphi 2009 中将字符串转换为 PAnsiChar
【发布时间】: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 获得完整的字符串?

【问题讨论】:

    标签: delphi delphi-2009


    【解决方案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;
    猜你喜欢
    • 2011-01-01
    • 2023-04-06
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    相关资源
    最近更新 更多