将PAnsiChar分配给(unicode-)字符串的正确方法是什么?

时间:2015-01-09 09:31:25

标签: delphi unicode delphi-xe2 delphi-2007 pchar

我有一个DLL函数,它返回一个指向ANSI文本(PAnsiChar)的指针。我想将它分配给(unicode-)字符串(这是Delphi XE2。)。以下编译,但我收到警告 “W1057隐式字符串从'AnsiChar'转换为'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及更新版本一起编译和使用。

3 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:3)

我认为通用解决方案是将c char指针分配给RawByteString,然后将其代码页设置为对应于以null结尾的字符串编码。

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;

答案 2 :(得分:-1)

回到前Unicode时代,它是MultiByteToWideChar / WideCharToMultiByte,它是代码页和字符集转换的首选工具。 http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx 两者都要求您知道源/目标的CP。 更多信息:http://msdn.microsoft.com/en-us/library/windows/desktop/dd317752(v=vs.85).aspx