如何解释从 VBscript 传递到 Delphi COM 服务器应用程序的数组

Posted

技术标签:

【中文标题】如何解释从 VBscript 传递到 Delphi COM 服务器应用程序的数组【英文标题】:How to interpret arrays passed from VBscript to a Delphi COM server App 【发布时间】:2020-05-01 00:32:41 【问题描述】:

我正在尝试将字节数组从 VBscript 传递到我的 windows Delphi 应用程序,但似乎找不到正确的语法来解释传递的数据。

需求非常简单,如下面的 VBscript sn-p 所示

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

我可以让服务器接受脚本传递的 olevariant 但数据似乎是乱码,我的示例服务器代码如下所示,基于此处的 *** 问题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;

所以想法是接受脚本传递的整数,将其转换为本地数据表示(字节数组),然后将其传递给我的函数以使用数据。

我尝试了几种不同的数据类型和方法,试图从变体中获取一些无乱码的数据,但均无济于事。

从传递的变量中提取数组数据的正确方法是什么?

另外,TVarData(Data).VArray^.Bounds[0].ElementCount 的值为零,为什么会这样?

【问题讨论】:

1.您假设 VBScript 正在向您传递整数的变体数组,但它可能是变体的变体数组。 (检查VarType(Data))。 2.您应该使用变体访问API:检查VarArrayDimCount(Data) = 1,然后使用for I := VarArrayLowBound(Data, 1) to VarArrayHighBound(Data, 1) do ... VarArrayGet(Data, [I]) 谢谢,是的,帮助文件列出了 Variants 函数,但我很难找到有关如何使用它们的任何信息。它不直观。我会看看他们是否让我更进一步。 【参考方案1】:

在 VBScript 中创建的数组是

    从零开始 无类型 以上限声明(不是您假设的大小;声明为 Dim arr(5) 的数组大小为 6) 在其中包含维度信息(因此您无需将其与数组一起传递)

在 COM 中使用时,它们作为 varVariant 类型的变体数组传递(正如 Ondrej Kelle 在他的评论中指出的那样)。要在您的方法中处理这样的数组,您必须断言:

    值是一维数组 每个元素都可以转换为字节

您可以为此编写帮助程序:

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 在处理大型数组时,例程中的循环会非常慢,因此对使用Move 将字节复制到结果的特殊情况(字节变量数组)进行了优化。但这永远不会发生在 VBScript 数组中。您可以考虑使用 VB.Net 或 PowerShell。

使用这样的例程会在内存中保留数组的 2 个实例 - 作为变体数组和字节数组。将其应用于您的用例时,将其用作指南。

【讨论】:

以上是关于如何解释从 VBscript 传递到 Delphi COM 服务器应用程序的数组的主要内容,如果未能解决你的问题,请参考以下文章

delphi 如何将form2的值传递form1

Delphi中从一个窗体传参数到另一个窗体的办法都有哪些?

请大家解释一下Delphi的回调函数

Delphi x64:如何将本地过程作为过程参数(回调)传递

从 VBScript 调用任何带有俄语名称的文件/脚本失败

如何在VBScript中将循环结果存储到数组中?