将[字节数组]分配给不需要Unicode转换的变量。

3
考虑以下 Delphi XE2 的代码片段:
function PrepData(StrVal: string; Base64Val: AnsiString): OleVariant;
begin
  Result := VarArrayCreate([0, 1], varVariant);
  Result[0] := StrVal;
  Result[1] := Base64Val;
end;

Base64Val是一个以Base64编码的二进制值(因此没有null字节)。(OleVariant) Result 自动封送并在客户端应用程序和DataSnap服务器之间发送。

当我使用Wireshark捕获流量时,我看到StrValBase64Val都作为Unicode字符串传输。如果可以,我想避免对Base64Val进行Unicode转换。我查看了所有Variant类型,除了varString之外,没有看到其他可以传输字符数组的选项。

我找到了这个问题,展示了如何创建变体字节数组。我在想,我可以使用这种技术代替使用AnsiString。但我很好奇,是否有另一种方法可以将非Unicode字符数据数组分配给Variant而不进行转换为Unicode字符串?

2个回答

4
Delphi的实现支持使用自定义变体类型代码,在Variant中存储AnsiString和UnicodeString,这些代码是varString和varUString。
但是Interop通常会使用标准的OLE变量,而OLE字符串varOleStr是16位编码的。这似乎是您观察到的原因。
如果您确实希望避免将数据转换为16位文本,则需要将数据作为字节数组输入。这样做会使base64编码无意义。停止对有效负载进行base64编码,并以字节数组发送二进制数据。

这些代码是varString和varUString。据我所知,这是用于ShortString的。对于AnsiString,有varLString。另外,如果二进制流由于任何原因不可行且base64太重,则还有yEnc编码。 - Arioch 'The
@Arioch 不,那些是长字符串。 - David Heffernan
搞定了。它通过PVarArray发送二进制数据,使用OleVariant进行编组,而不使用Base64。我将单独发布答案,包括对David的其他答案的引用,他展示了如何完成大部分工作。 - James L.

2

按照问题中的示例,这是我如何使其工作的(使用David的答案中的代码和注释来自我问题的引用):

function PrepData(StrVal: string; Data: TBytes): OleVariant;
var
  SafeArray: PVarArray;
begin
  Result := VarArrayCreate([0, 1], varVariant);
  Result[0] := StrVal;
  Result[1] := VarArrayCreate([1, Length(Data)], varByte);
  SafeArray := VarArrayAsPSafeArray(Result[1]);
  Move(Pointer(Data)^, SafeArray.Data^, Length(Data));
end;

然后在 DataSnap 服务器上,我可以从 OleVariant 中提取二进制数据,假设 Value 是 OleVariant 中 Variant 数组中的 Result[1]

procedure GetBinaryData(Value: Variant; Result: TMemoryStream);
var
  SafeArray: PVarArray;
begin
  SafeArray := VarArrayAsPSafeArray(Value);
  Assert(SafeArray.ElementSize=1);
  Result.Clear;
  Result.WriteBuffer(SafeArray.Data^, SafeArray.Bounds[0].ElementCount);
end;

这里有一些轻微的不对称。第一段代码包括 SizeOf(),但第二段没有。实际上都不需要,因为你知道元素是大小为1的字节。但是你应该在第二段代码中添加一些合理性检查,因为编译器无法保证变量数组的内容。+1,感谢您早先已删除的评论,关于解释为什么很有价值。我会尽力而为,很高兴您注意到了。 :-) - David Heffernan
感谢@David - 我一直很感激你花时间解释“为什么”。我尝试按照你的建议添加了一个SizeOf(),但是无法弄清如何访问SafeArray.Data的元素。所以我在两个地方都添加了SizeOf(Byte)(保持一致)。虽然这也不完美... - James L.
你的问题是关于 AnsiString 的,而你的答案是关于 UnicodeString 的。可能我漏掉了什么… - Arioch 'The
@Arioch - 对于造成混淆我感到抱歉。问题是如何将非 Unicode 字符数组(实际上是字节流)存储在 Variant 中并避免在将 AnsiString 分配给 Variant 时发生 Unicode 转换。然后当然,如何再次获取它... - James L.
@JamesL. 你看... "字符" 不是 "字节",而是字节+字符集/代码页上下文。但如果 字节数组 对你来说合适的话那就没问题。 - Arioch 'The
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接