Delphi XE 和 Unicode

Delphi XE and Unicode

我有一个功能在 Delphi 6 中工作。现在我试图将旧项目迁移到 Delphi XE8,但是这个功能不能正常工作。

请帮帮我。

旧函数:

function ReadString(var P: Pointer): String;
var
  B: Byte;
begin
  B := Byte(P^);
  SetLength(Result, B);
  P := Pointer( Integer(P) + 1);
  Move(P^, Result[1], Integer(B));
  P := Pointer( Integer(P) + B );
end;

我尝试将其更改为取消编码,但它不起作用:

function ReadString(var P: Pointer): String;
var
  B: Byte;
  LResult: AnsiString;
begin
  B := Byte(P^);
  SetLength(LResult, B);
  P := Pointer( Integer(P) + 1);
  Move(P^, LResult[1], Integer(B));
  P := Pointer( Integer(P) + B );
  Result := String(LResult);
end

函数使用于:

GetIntfMetaData(Myobj 作为 IFController,IntfMD,True);

    procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData; MethodArrayOpt: TFillMethodArrayOpt);
var
  I, Offset: Integer;
  Methods: Integer;
  BaseRTTIMethods: Integer;
  HasRTTI: Integer;
  PP: PPTypeInfo;
  P: Pointer;
  SelfMethCount: Integer;
  IntfMethod: PIntfMethEntry;
begin
  P := Pointer(Info);
  IntfMD.Info := Info;
  { tkKind }
  ReadByte(P);
  IntfMD.Name := ReadString(P);
   { Interface flags }
  ReadByte(P);
  IntfMD.UnitName := ReadString(P);
  Methods := ReadWord(P);   { # methods }
  HasRTTI := ReadWord(P);   { $FFFF if no RTTI, # methods again if has RTTI }
  if HasRTTI = $FFFF then
    raise EInterfaceRTTIException.CreateFmt(SNoRTTI, [IntfMD.UnitName + '.' + IntfMd.Name]);
  { Save my method count }
  SelfMethCount := Methods;
    Offset := 0;
  { Size array and fill in information }
  SetLength(IntfMD.MDA, Methods);
  FillMethodArray(P, @IntfMD, Offset, SelfMethCount);
end;

procedure FillMethodArray(P: Pointer; IntfMD: PIntfMetaData; Offset, Methods: Integer);
var
  S: Ansistring;
  I, J, K, L: Integer;
  ParamCount: Integer;
  Kind, Flags: Byte;
  ParamInfo: PTypeInfo;
  ParamName: Ansistring;
  IntfMethod: PIntfMethEntry;
  IntfParam: PIntfParamEntry;
begin
  for I := 0 to Methods -1 do
  begin
    IntfMethod := @IntfMD.MDA[Offset];
    IntfMethod.Name := ReadString(P);
    Kind := ReadByte(P);           { tkKind }
    IntfMethod.CC := CCMap[ReadByte(P)];
    ParamCount := ReadByte(P);     { Param count including self }
    IntfMethod.ParamCount := ParamCount - 1;
    IntfMethod.Pos := Offset;
    IntfMethod.HasRTTI := True;

    SetLength(IntfMethod.Params, ParamCount);
    K := 0;
    for J := 0 to ParamCount - 1 do
    begin
      Flags := ReadByte(P);       { Flags }
      ParamName := ReadString(P); { Param name }
      S := ReadString(P);         { Param type name }
      L := ReadLong(P);           { Param Type Info }
      if L <> 0 then
        ParamInfo := PPTypeInfo(L)^
      else
        raise EInterfaceRTTIException.CreateFmt(SNoRTTIParam, [ParamName, IntfMethod.Name, IntfMD.UnitName + '.' + IntfMd.Name]);
      if J = 0 then
        IntfMethod.SelfInfo := ParamInfo
      else
      begin
        IntfParam := @IntfMethod.Params[K];
        IntfParam.Flags := TParamFlags(Flags);
        IntfParam.Name := ParamName;
        IntfParam.Info := ParamInfo;
        Inc(K);
      end;
    end;
    if Kind = Byte(mkFunction) then
    begin
      S := ReadString(P);
      IntfMethod.ResultInfo := PPTypeInfo(ReadLong(P))^;
    end;
    Inc(Offset);
  end;
end;

function ReadByte(var P: Pointer): Byte;
begin
  Result := Byte(P^);
  P := Pointer( Integer(P) + 1);
end;

如果要类型的名称通过PTypeInfo结构:

function GetName(p: Pointer): String;
begin
  Result := PTypeInfo(P)^.Name;
end;

或者更好地完全限定指针:

function GetName(p: PTypeInfo): String;
begin
  Result := P^.Name;
end;

或者使用内置函数: TypInfo.GetTypeName.


David 在评论中指出,TTypeInfo 记录以枚举 Kind 开头。接下来是 Name 字符串。此字段的偏移量最好留给编译器计算。


在您更新的问题中,很明显您在调用函数以获取名称之前将指针递增 1 (ReadByte)。不要那样做。 这样做:

IntfMD.Name := GetTypeName(Info);

现在,使用这些知识来处理 TTypeInfo 的方法,这也需要更新。

这是我在网上找到的解决方案,可以用(但不知道是否合适):

function ReadString(var P: Pointer): String;
var
  B: Byte;
{$IFDEF UNICODE}
{$IFDEF NEXTGEN}
  AStr: TBytes;
{$ELSE !NEXTGEN}
  AStr: AnsiString;
{$ENDIF NEXTGEN}
{$ENDIF}
begin
  B := Byte(P^);
{$IFDEF UNICODE}
  SetLength(AStr, B);
  P := Pointer(NativeInt(P)+1);
{$IFDEF NEXTGEN}
  Move(P^, AStr[0], Integer(B));
  Result := Tencoding.UTF8.GetString(AStr);
{$ELSE !NEXTGEN}
  Move(P^, AStr[1], Integer(B));
  Result := UTF8ToString(AStr);
{$ENDIF NEXTGEN}
{$ELSE}
  SetLength(Result, B);
  P := Pointer( NativeInt(P) + 1);
  Move(P^, Result[1], Integer(B));
{$ENDIF}
  P := Pointer( NativeInt(P) + B );
end;