将我的项目从D7转换为XE4的问题

时间:2013-08-31 23:41:09

标签: delphi delphi-xe4

我现在决定将我的Delphi 7项目转换为XE4,但在我的一个代码行中我得到了一个女巫的问题我试图修复它但没有希望,所以我希望有人可以帮我修复它

问题在于:

在服务器和客户端应用程序(酒店客房管理系统)之间使用的共享单元中,我有这种记录类型:

      Type
      THotelClientDetails = packed record
      LSize:  Integer;
      ClientName:  array[0..25] of char;
      ClientRoomN:  Integer;
      RWithInternet: Boolean;
      RoomStatus    :Integer;
    //... etc 
      end;
          PHotelClientDetails = ^THotelClientDetails;

在客户端应用程序中,我使用以下过程:

procedure TCForm.SendClientDetailsClick(Sender: TObject);
  var
  pClientDetails: PHotelClientDetails;
  iSize: Integer;
  begin

  iSize:= SizeOf(THotelClientDetails)+Length(ClientNameEd.Text)+1;
  GetMem(pClientDetails,iSize);
  ZeroMemory(pClientDetails,iSize);
  pClientDetails.LSize := iSize;
  StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
  pClientDetails.ClientRoomN  :=StrToInt(ClientNEd.text);
  pClientDetails.RWithInternet:=ClientWInternet.Checked;
  pClientDetails.RoomStatus   :=ClientRoomStatus.ItemIndex;
  StrCopy(Pointer(Cardinal(pClientDetails)+SizeOf(THotelClientDetails)),
  PChar(ClientNameEd.Text));
  SendClientsBuffer(pClientDetails,iSize);// to the Server for Check
  FreeMem(pClientDetails);

  end;

在服务器应用程序中,我使用以下过程:

Procedure TSForm.GetClientDetails(pClientDetails:PHotelClientDetails; Cntx: Pointer);
  var
  ClientName: string;
  begin
  ClientName:=PChar(Cardinal(pClientDetails)+SizeOf(THotelClientDetails));
  //*** just a test to get the ClientName
  ShowMessage(ClientName);
  //***
  end;

所以我的问题是当使用Delphi 7时,我得到客户端应用程序发送的全名: 例如,如果我想将客户端“simon”或“matthew”发送到服务器

我得到了正确的名字:

ShowMessage(ClientName);//simon or matthew

但是当在XE4中使用相同的程序时,我总是得到

simon

sim matthew

matt

这意味着服务器没有像Delphi7项目那样接收完整的客户端名称。

虽然在两个项目中添加了单位“System.AnsiStrings;”。

那么请问我该如何解决这个问题?

非常感谢。

西蒙

2 个答案:

答案 0 :(得分:3)

Delphi 7使用ANSI字符串(单字节字符),而2009年版本的Delphi使用Unicode字符串(多字节字符)。

对您的代码最直接的解决方法是从Char更改为AnsiCharstring更改为AnsiString,将PChar更改为PAnsiChar

Type
  THotelClientDetails = packed record
    LSize:  Integer;
    ClientName:  array[0..25] of AnsiChar;
    ClientRoomN:  Integer;
    RWithInternet: Boolean;
    RoomStatus    :Integer;
    //... etc 
  end;

StrCopy(pClientDetails.ClientName, PAnsiChar(ClientNameEd.Text));
// and
StrCopy(Pointer(Cardinal(pClientDetails) + SizeOf(THotelClientDetails)),
        PAnsiChar(ClientNameEd.Text));

Procedure TSForm.GetClientDetails(pClientDetails:PHotelClientDetails; Cntx: Pointer);
var
  ClientName: string;
begin
  ClientName := PAnsiChar(Cardinal(pClientDetails)+SizeOf(THotelClientDetails));
  //*** just a test to get the ClientName
  ShowMessage(ClientName);
  //***
end;

有几十个(如果不是数百个)有关将Delphi代码从D2007及更早版本移植到D2009及更高版本的问题。您应该花一些时间在此处浏览标记。

答案 1 :(得分:1)

我发布这个作为答案,因为它比问题的评论更容易格式化。

关于你可能想要的事情的一些评论:

  1. 使用Delphi 2009及更高版本中的Unicode支持,不要认为Length将获得字符串的实际字节数。
  2. 在Delphi 7和XE4之间引入了记录中的概念方法(我认为在Delphi 2006中)。将逻辑SendClientDetailsClick的部分移动到THotelClientDetails
  3. 的方法中
  4. 由于THotelClientDetails.ClientName限制为26个字节(25 AnsiChar个字节字节加上一个空终止字节),因此不需要
      iSize:= SizeOf(THotelClientDetails)+Length(ClientNameEd.Text)+1;
    这意味着iSize:= SizeOf(THotelClientDetails)
  5. 你有一个指针pClientDetails: PHotelClientDetails的唯一原因就是你打电话   SendClientsBuffer(pClientDetails,iSize);// to the Server for Check
    哪个可以替换为   SendClientsBuffer(ClientDetails,iSize);// to the Server for Check
  6. 没有长度防护装置可防止复制超过25个字节 StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    在那里使用StrLCopy,而不是StrCopy
  7. 为什么要从ClientNameEd执行两次复制操作? StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    //...
    StrCopy(Pointer(Cardinal(pClientDetails)+SizeOf(THotelClientDetails)), PChar(ClientNameEd.Text));
  8. 如果您坚持使用指针,则FreeMem应位于finally区块内。
  9. 这样的事情更合适:

    procedure TCForm.SendClientDetailsClick(Sender: TObject);
    var
      ClientDetails: PHotelClientDetails;
      iSize: Integer;
    begin
      iSize := SizeOf(THotelClientDetails);
      ZeroMemory(@ClientDetails, iSize);
      ClientDetails.LSize := iSize;
      StrLCopy(ClientDetails.ClientName, PAnsiChar(ClientNameEd.Text), SizeOf(ClientDetails.ClientName)-1);
      pClientDetails.ClientRoomN   := StrToInt(ClientNEd.text);
      pClientDetails.RWithInternet := ClientWInternet.Checked;
      pClientDetails.RoomStatus    := ClientRoomStatus.ItemIndex;
      SendClientsBuffer(@ClientDetails,iSize); // to the Server for Check
    end;