0

我有一个 DLL 函数,它返回一个指向 ANSI 文本 (PAnsiChar) 的指针。我想将其分配给(unicode-)字符串(这是Delphi XE2。)。以下编译但我收到警告“W1057 Implicit String cast from 'AnsiChar' to 'string'”:

function TProj4.pj_strerrno(_ErrorCode: Integer): string;
var
  Err: PAnsiChar;
begin
  Err := Fpj_strerrno(_ErrorCode);
  Result := Err;
end;

编辑:有问题的文本是英文的错误消息,所以这里不太可能有任何转换问题。

我现在很想将 Err 显式类型转换为这样的字符串......

Result := String(Err);

..摆脱警告。这会出错吗?我应该改用临时 AnsiString 变量吗?

var
  s: AnsiString;
[...]
s := Err;
Result := String(s);

如果是,为什么?

或者我应该明确表示,代码首先将 PAnsiChar 转换为 AnsiString,然后将 AnsiString 转换为 String?

Result := String(AnsiString(Err));

当然我可以把它变成一个函数:

function PAnsicharToString(_a: PAnsiChar): string;
begin
   // one of the above conversion codes goes here
end;

所有这些选项都可以编译,但它们会起作用吗?这里的最佳做法是什么?

加分项:理想情况下,代码应该可以编译并与 Delphi 2007 和更新版本一起使用。

4

2 回答 2

5

如果文本是在用户当前语言环境中编码的,那么我想说写起来最简单:

var
  p: PAnsiChar;
  str: string;
....
str := string(p);

否则,如果您希望从特定代码页转换为 Unicode 字符串,那么您将使用UnicodeFromLocaleChars.

于 2015-01-09T09:39:05.993 回答
3

我认为一般的解决方案是将 c char 指针分配给 RawByteString,然后将其代码页设置为对应于 c 空终止字符串编码。

var
  bys :TBytes;
  rbstr :RawByteString;
  ustr :string;
  pastr :PAnsiChar;
begin

  SetLength(bys,5);
  bys[0] := $ca;
  bys[1] := $e9;
  bys[2] := $d2;
  bys[3] := $b5;
  bys[4] := 0;

  pastr := @bys[0]; // just simulate char* returned by c api


  rbstr := pastr; // assign PAnsiChar to RawByteString
  // assume text encoded as codepage 936
  // Note here: set 3rd param to false!
  SetCodePage(rbstr,936,false);

  ustr := string(rbstr);
  ShowMessage(ustr);
end;

另一个跨平台解决方案是(vcl,fmx,fmx with mobile platform)

function CString2TBytes(ptr :{$IFDEF NEXTGEN} MarshaledAString {$ELSE} PAnsiChar {$ENDIF}) :TBytes;
var
  pby :PByte;
  len :Integer;
begin
  pby := PByte(ptr);
  while pby^<>0 do Inc(pby);
  len := pby - ptr;
  SetLength(Result,len);
  if len>0 then Move(ptr^,Result[0],len);
end;

procedure TForm5.Button1Click(Sender: TObject);
var
  bys, cbys: TBytes;
  ustr: string;
  // PAnsiChar is undefined in mobile platform
  // remap param foo(outSting:PAnsiString) => foo(outString:MarshaledAString)
  ptr: {$IFDEF NEXTGEN} MarshaledAString {$ELSE} PAnsiChar {$ENDIF}; //
  encoding : TEncoding;
begin

  SetLength(bys, 5);
  bys[0] := $CA;
  bys[1] := $E9;
  bys[2] := $D2;
  bys[3] := $B5;
  bys[4] := 0;

  ptr := @bys[0]; // just simulate char* returned by c api

  cbys := CString2TBytes(ptr);

  // assume text encoded as codepage 936
  encoding := TEncoding.GetEncoding(936);
  try
    ustr := encoding.GetString(cbys);
    ShowMessage(ustr);
  finally
    encoding.Free;
  end;

end;
于 2015-01-10T07:31:42.927 回答