Question

Consider the following code snippet (in Delphi XE2):

function PrepData(StrVal: string; Base64Val: AnsiString): OleVariant;
begin
  Result := VarArrayCreate([0, 1], varVariant);
  Result[0] := StrVal;
  Result[1] := Base64Val;
end;

Base64Val is a binary value encoded as Base64 (so no null bytes). The (OleVariant) Result is automatically marshalled and sent between a client app and a DataSnap server.

When I capture the traffic with Wireshark, I see that both StrVal and Base64Val are transferred as Unicode strings. If I can, I would like to avoid the Unicode conversion for Base64Val. I've looked at all the Variant types and don't see anything other than varString that can transfer an array of characters.

I found this question that shows how to create a variant array of bytes. I'm thinking that I could use this technique instead of using an AnsiString. I'm curious though, is there another way to assign an array of non-Unicode character data to a Variant without a conversion to a Unicode string?

Was it helpful?

Solution

Delphi's implementation supports storing AnsiString and UnicodeString in a Variant, using custom variant type codes. These codes are varString and varUString.

But interop will typically use standard OLE variants and the OLE string, varOleStr, is 16 bit encoded. That would seem to be the reason for your observation.

You'll need to put the data in as an array of bytes if you do wish to avoid a conversion to 16 bit text. Doing so renders base64 encoding pointless. Stop base64 encoding the payload and send the binary in a byte array.

OTHER TIPS

Keeping with the example in the question, this is how I made it work (using code and comments from David's answer to another question as referenced in my question):

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;

Then on the DataSnap server, I can extract the binary data from the OleVariant like this, assuming Value is Result[1] from the Variant Array in the OleVariant:

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top