I am trying to pass an array of bytes from VBscript to my windows Delphi Application and can't seem to find the correct syntax to interpret the passed data.
The requirement is fairly simple as the VBscript snippet below demonstrates
Dim inst,arr(5)
Sub Main
set inst=instruments.Find("EP1")
arr(0) = 0
arr(1) = 1
arr(2) = 2
arr(3) = 3
arr(4) = 4
inst.writebytes arr,5
end Sub
I can get the server to accept the olevariant passed by the script but the data seems garbled, my example server code is shown below and is based on the Stackoverflow question here How to use variant arrays in Delphi
procedure TInstrument.WriteBytes(Data: OleVariant; Length: Integer);
var i,n:integer; Pdat:Pbyte; Adata:PvarArray;
begin
if VarIsArray(data) then
begin
n:=TVarData(Data).VArray^.Bounds[0].ElementCount;
Adata:= VarArrayLock(Data);
Getmem(Pdat,length);
try
for i:=0 to length-1 do
Pdat[i]:=integerArray(Adata.data^)[i];
Finstrument.WriteBytes(Pdat,Length);
finally
freemem(Pdat)
end;
end;
end;
So the idea is to accept the integers passed by the script, convert it to the local data representation (array of byte) then pass it on to my function to use the data.
I have tried several different data types and methods to try and get some ungarbled data out of the variant all to no avail.
What is the correct method of extracting the array data from the passed variant?
Also, TVarData(Data).VArray^.Bounds[0].ElementCount has a value of zero, why would that be?
Arrays created in VBScript are
Dim arr(5)
is 6)When used in COM, they are passed as variant arrays of type varVariant
(as the Ondrej Kelle points out in his comment). To process such an array in your method you have to assert that:
You can write helper routine for that:
function ToBytes(const Data: Variant): TBytes;
var
Index, LowBound, HighBound: Integer;
ArrayData: Pointer;
begin
if not VarIsArray(Data) then
raise EArgumentException.Create('Variant array expected.');
if VarArrayDimCount(Data) <> 1 then
raise EArgumentException.Create('Single dimensional variant array expected.');
LowBound := VarArrayLowBound(Data, 1);
HighBound := VarArrayHighBound(Data, 1);
SetLength(Result, HighBound - LowBound + 1);
if TVarData(Data).VType = varArray or varByte then
begin
ArrayData := VarArrayLock(Data);
try
Move(ArrayData^, Result[0], Length(Result));
finally
VarArrayUnlock(Data);
end;
end
else
begin
for Index := LowBound to HighBound do
Result[Index - LowBound] := Data[Index];
end;
end;
for
loop in the routine will be horribly slow when processing large arrays, so there's optimization for special case (variant array of bytes) that uses Move
to copy bytes to result. But this will never happen with VBScript array. You might consider using VB.Net or PowerShell.
Using such a routine has downside of keeping 2 instances of the array in memory - as variant array and as byte array. Use it as a guide when applying it to your use case.