我是XE5用户。我有一个用D7编写的客户端/服务器应用程序。我已升级到XE5。因为D7不是unicode我使用了以下类型:
TRap = array[0..254] of AnsiChar;
我将通过tcpip将此数据发送到服务器。服务器具有相同的定义。现在我需要升级到unicode,但大小必须相同。因为我使用以下模式:
PMovieData = ^TMovieData;
TMovieData = packed record
rRap: TRap;
rKey: string[7];
iID: integer;
end;
我试图将TRap改为:
TRap2 = array[0..127] of WChar;
然而尺寸并不相同。 TRap是255,但TRap2是256.我不能改变大小,因为它应该与ex版本一起使用。你有什么建议吗?
答案 0 :(得分:1)
好吧,由于宽字符宽2个字节,因此宽字符数组的大小均匀。并且255不是偶数。因此,您无法在原始数组上覆盖宽字符数组。
我想你可以有127个宽字符和填充字节的数组:
TMovieData = packed record
rRap: array [0..126] of WideChar;
_reserved: Byte;
rKey: string[7];
iID: integer;
end;
我无法想象这会有多大帮助,因为旧组件会将宽字符数据解释为8位数据。哪会产生意想不到的结果。基本上文本会出现乱码。
您可以考虑其他一些选择:
答案 1 :(得分:1)
您展示的代码在XE5中的工作方式与在D7中完全相同。 AnsiChar
和短字符串仍然可用,仍然是8位Ansi,因此它们一直是相同的大小。你根本不必改变你的定义......
...除非你想为手机编译,在这种情况下AnsiChar
和短字符串不再可用(你可以安装RTL patch来取回它们),在这种情况下你可以将代码更改为以下内容以保持与服务器的兼容性:
TRap = array[0..254] of Byte;
PMovieData = ^TMovieData;
TMovieData = packed record
rRap: TRap;
rKey: array[0..7] of Byte; // put the string length in rKey[0]
iID: integer;
end;
答案 2 :(得分:1)
您在问题中提到过您要将此数组数据类型中保存的数据发送到服务器。
如果该服务器实现在您的控制之下并且也正在升级到Unicode,那么您只需确保数据交换的双方就数据内容达成一致。如果你需要一个数组来保存"字符串"长度最多255个字符(这是您的ANSI实现支持的),那么您的Unicode版本也需要支持255个字符。每个字符所需的数据量有多少变化 - 2个字节,而不是1个字节(它不是那么简单,但我假设你的ANSI实现没有处理MBCS问题,那个您的Unicode实现同样不会关注代理对(在影响有效"字符的数量方面")。
即。你的 TRap 数组应该是:
TRap = array[0..254] of WIDEChar;
但是,如果您的控制下服务器实现 NOT (您的观察结果暗示新代码必须继续使用旧版本),那么无论您做出什么更改在客户端应用程序中,服务器将继续期望255 ANSI 字符。在这种情况下,您的 TRAP 类型必须与以前保持一致(ANSIChar数组),您必须确保将WIDE字符串字符转换为ANSI(反之亦然) )当它们进出阵列时。
注意:没有必要转换为UTF-8到该阵列或任何其他设计只是为了使相同数量的字符#34;适合",除非旧版本的新代码将使用的服务器已经容纳了接收UTF-8编码的字符(根据要掌握的信息,它几乎肯定不会。)
回到服务器实现在您的控制之下的情况,您可以保留对ANSI TRap 类型的支持,并通过合并"魔术引入新的WIDE char实现饼干"在数据结构的新WIDE char版本中,允许服务器识别正在传递的数据结构类型并相应地进行调整。这些方面的东西:
TANSIRap = array[0..254] of ANSIChar;
TWIDERap = array[0..254] of WIDEChar;
// ANSIMovieData corresponds *exactly* to the old MovieData structure
PANSIMovieData = ^TANSIMovieData;
TANSIMovieData = packed record
rRap: TANSIRap;
rKey: string[7];
iID: integer;
end;
// WIDEMovieData adds a magic cookie "header" identifying the new structure type
PWIDEMovieData = ^TWIDEMovieData;
TWIDEMovieData = packed record
rCookie: Word;
rRap: TWIDERap;
rKey: string[7];
iID: integer;
end;
发送 TWIDEMovieData 时,将 rCookie 字段设置为某个常量值,该值不会出现在有效的 TANSIRap 数组中。例如如果"空" TRap 数组(即ANSI版本)全部为0,然后 $ 00FF 的cookie可能是合适的,因为没有有效的ANSI电影数据结构可以从一个领先的开始#0字符后紧跟#ff字符:
const
MOVIEDATA_WIDECOOKIE = $00FF;
// new client pseudo-code:
data: TANSIMovieData;
wdata: TWIDEMovieData;
if ANSI Server then
data... // init ANSI movie data (TANSIRap ANSI chars converted from WIDE)
SendToServer(data); // etc
else // WIDE server
wdata.rCookie := MOVIEDATA_WIDECOOKIE;
wdata..... // init WIDE movie data
SendToServer(wdata); // etc
// server pseudo-code:
var
data: PANSIMovieData;
wdata: PWIDEMovieData;
ReceiveDataIntoBuffer(data^);
wdata := PWIDEMovieData(data);
if wdata.rCookie = MOVIEDATA_WIDECOOKIE then
HandleWideData(wdata)
else
ExistingANSIDataHandler(data);
唯一的复杂因素是新客户端如何确定与之通信的服务器是否能够支持WIDE电影数据。但这只是一个问题,如果服务器实现在你的控制之下(如果没有那么你只能继续使用ANSI ),所以你应该能够设计一些识别服务器功能的机制这允许新客户端可靠地识别旧服务器。
绝对最坏的情况下,您可能需要一个客户端配置设置(并注意,如果您将客户端配置为使用ANSI,即使对于新服务器,它仍将继续工作,只是没有Unicode支持)。
New client / New server : client and server both use WIDE (but will also work with ANSI)
New client / Old server : client uses ANSI
Old client / New server : server detects ANSI
Old client / Old server : no change
根据服务器实现,您可能需要分阶段读取数据,读取前2个字节以获得前两个 TANSIRap 字符或 WIDECOOKIE ,具体取决于传递数据结构,然后根据您是否检测到cookie读取数据包中的剩余字节,但原理基本相同。