3

How to convert a byte array to Variant? I have a WebService that should receive an array of byte, but it only accepts variable of type VARIANT, I wonder how to convert in order to pass it as parameter for Web Services.

thank you

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Jose Eduardo
  • 487
  • 9
  • 27
  • 1
    A variant can hold data in many different forms. What form does the web service want it in. – David Heffernan Oct 30 '12 at 16:21
  • The Web Service accepts parameter as a variable of type Variant, but she has to have the content with an Array of Byte, do not know the operation of the Web Service but informed me that it should be passed in this way, the intention is to send a file to it . – Jose Eduardo Oct 30 '12 at 16:31
  • Is it a `SAFEARRAY`? Remember that a `VARIANT` is just a container. You still need to know the expected format of the contents. – David Heffernan Oct 30 '12 at 16:32
  • No. I can also inform the separated format, my difficulty is to pass this array of Bytes being the only method accepts the parameter as Variant, if you know another way you can help me I thank very much. – Jose Eduardo Oct 30 '12 at 16:37
  • 1
    I guess you aren't understanding me. A `VARIANT` can contain data in many different formats. Knowing that the data is contained in a `VARIANT` is not enough information to specify the problem. Which format do you need it to be? Unless you can answer that question, you can't proceed. – David Heffernan Oct 30 '12 at 16:49
  • Probably what you need to do is call `V := VarArrayCreate([0, N-1], varByte)` and then populate the variant `V` using `V[i] := ...`. But perhaps the array bounds need to be `[1,N]`. Only you can know that. – David Heffernan Oct 30 '12 at 16:52
  • I'll try to explain my ultimate goal, I need to pass a file to Web Service. But the method of the Web Service only accepts Variant, so I assume that is of type Array of Byte. Transforming a File in Byte is simple, the problem this time to pass this Array pro Web Service which are accepted variant. Sorry if I could not explain. – Jose Eduardo Oct 30 '12 at 16:55
  • We are going round in circles now. Time for me to let somebody else have a go. – David Heffernan Oct 30 '12 at 16:56
  • Not seen your answer then I'll try, but if I recall, had already tried that. – Jose Eduardo Oct 30 '12 at 16:57
  • David, Thank you very arrived at the result he wanted. – Jose Eduardo Oct 30 '12 at 16:59

1 Answers1

7

According to the comment trail, you need to create a SAFEARRAY of bytes. Which is done like this in Delphi:

V := VarArrayCreate([0, N-1], varByte);

Or, if the SAFEARRAY needs 1-based indexing:

V := VarArrayCreate([1, N], varByte);

You can then populate the array in a loop using V[i] := ....

If you have a Delphi dynamic array of Byte, and the expected SAFEARRAY uses 0-based indexing, then you can simply write:

V := a;

If you have a lot of data to transfer then the element by element poking of the data that the RTL offers is pretty much hopeless. Even the simple v := a approach results in element by element copying which will be horribly slow for large amounts of data.

In your position, I'd blit the array in one go. Like this:

var
  i: Integer;
  a: array of Byte;
  V: Variant;
  SafeArray: PVarArray;
....
// populate a
V := VarArrayCreate([0,high(a)], varByte);
SafeArray := VarArrayAsPSafeArray(V);
Move(Pointer(a)^, SafeArray.Data^, Length(a)*SizeOf(a[0]));

Or, if you need to use 1-based indexing:

V := VarArrayCreate([1,Length(a)], varByte);
SafeArray := VarArrayAsPSafeArray(V);
Move(Pointer(a)^, SafeArray.Data^, Length(a)*SizeOf(a[0]));
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Once you have passed the VarArray of Bytes to another process, how do you access the data so you can write it to some sort of memory stream? I've been trying, but haven't been able to figure it out yet... – James L. Nov 22 '13 at 08:09
  • You can do it with VarArrayAsPSafeArray just as in the code here – David Heffernan Nov 22 '13 at 08:10
  • So, if you pass the SAFEARRAY Variant to `procedure SaveBytes(Data: Variant; var MS: TMemoryStream)`, would you do this (sorry for code in comment!)? `var SA: PVarArray; begin SA := VarArrayAsPSafeArray(Data); MS.Clear; MS.WriteBuffer(SafeArray.Data, VarArrayHighBound(Data, 1)); end;` – James L. Nov 22 '13 at 08:22
  • I guess it would go like that. Assuming the variant is received as a safe array. Your code assumes 0 based indices. And doesn't the PVarArray contain the bounds? – David Heffernan Nov 22 '13 at 08:26
  • Yes, and come to find out, it uses 1 based indices. All is working now. Again, thanks! So with the change, `MS.WriteBuffer(SA.Data^, SA.Bounds[0].ElementCount);` now works... Full example found here: http://stackoverflow.com/a/20141184/822072 – James L. Nov 22 '13 at 09:24