2013-08-31 30 views
-2

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

这里的问题:

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

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

在客户端应用程序,我使用follwing步骤:

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时,我的问题是我得到的客户端应用程序发送的全名: 例如,如果我想送客户“西门”或“马太福音”到服务器

我得到正确的名称:

ShowMessage(ClientName);//simon or matthew 

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

SIM西蒙亚光马修

这意味着服务器没有收到完整的客户端的名称与Delphi7的项目。

尽管在两个项目中都添加了单位“System.AnsiStrings;”。

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

非常感谢。

西蒙

+3

'CMDCMDLINE:数组[0..25] ANSIChar一致的;' – bummi

+0

@bummi谢谢你,我用它,但我总是得到这个编译器错误: '代码 E2250没有可以通过这些参数调用'StrCopy'的重载版本' – user2736348

回答

3

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

为您的代码最简单的解决方法是从Char改变AnsiCharstringAnsiString,并PCharPAnsiChar

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; 

有字面上的有关移植德尔福的问题几十个(如果不是几百个)从D2007和更早的代码到D2009和稍后的代码。您应该花点时间浏览这里的标签。

+0

我应该将单元“System.AnsiStrings”添加到两个项目中吗? – user2736348

+0

快速测试似乎说你不需要它。 'var Test:AnsiString;开始SetLength(Test,10); StrCopy(PAnsiChar(Test),PAnsiChar('Tested')); ShowMessage(测试);结束;' –

+0

我编辑我的代码,因为你告诉我,但现在我得到S的西蒙和M马修...非常感谢您的帮助 – user2736348

1

我张贴此作为答案,因为它更容易格式化而不是评论的问题。

对一些事情的话,你可能想要做的:

  1. 随着2009年德尔福了Unicode支持,不要以为Length将让你一个字符串的字节的实际数量。
  2. 在Delphi 7和XE4之间,引入了记录的概念op方法(我认为在Delphi 2006中)。移动逻辑SendClientDetailsClick的一部分结合到的THotelClientDetails
  3. 方法由于THotelClientDetails.ClientName被限制为26个字节(25个AnsiChar字符字节加上一个空终止字节),也没有必要为
    iSize:= SizeOf(THotelClientDetails)+Length(ClientNameEd.Text)+1;
    这意味着iSize:= SizeOf(THotelClientDetails)
  4. 你有一个指针pClientDetails: PHotelClientDetails的唯一原因是,你叫 SendClientsBuffer(pClientDetails,iSize);// to the Server for Check
    您可以通过
    SendClientsBuffer(ClientDetails,iSize);// to the Server for Check
  5. 更换没有长卫,防止超过25个字节的复制在
    StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    使用StrLCopy那里,而不是StrCopy
  6. 为什么要从ClientNameEd执行两次复制操作?
    StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    //...
    StrCopy(Pointer(Cardinal(pClientDetails)+SizeOf(THotelClientDetails)), PChar(ClientNameEd.Text));
  7. 如果你坚持三分球,FreeMem应在finally块。

像这样的东西是比较合适的:

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;