我有Delphi 2006客户端应用程序。该客户端从COM服务器接收Olevariant类型的数据。该函数是:

procedure OnLimitsChanged(var SymbolsChanged: {??PSafeArray}OleVariant);

该函数返回一个字符串数组。我无法从delphi中读取OleVariant类型的数据。

从Excel VBA可以正常工作:
Private Sub g_Realtime_OnLimitsChanged(SymbolsChanged() As String)
    Dim i%
    Dim Salir As Boolean
    If UBound(SymbolsChanged) <> -1 Then
        i = 0: Salir = False
        While Not Salir
            If SymbolsChanged(i) = Simbolo Then
                LlamarALimites
                Salir = True
            Else
                i = i + 1
                If i > UBound(SymbolsChanged) Then Salir = True
            End If
        Wend
    End If
End Sub

我试图将OleVariant转换为Psafearray ...
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject;
  var ArrayTicks : Olevariant);
var
  Data : pSafeArray;
  i,iLow, iHigh : Integer;
  value : wideString;
begin
  Data:=PSafeArray(TVarData(ArrayTicks).VArray);
  SafeArrayGetLBound(Data,1,iLow);
  SafeArrayGetUBound(Data,1,iHigh);
  for i:=iLow to iHigh do
  begin
    SafeArrayGetElement(Data,i,Value);
    Showmessage(Value);
  end;

但我在这一行中收到一个异常(exception):
 SafeArrayGetLBound(Data,1,iLow);



任何意见和建议将不胜感激。

最佳答案

RTL具有VarArrayAsPSafeArray()函数,用于从PSafeArray中正确提取(Ole)Variant:

procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : OleVariant);
var
  Data : PVarArray; // RTL's version of PSafeArray
  //...
begin
  Data := VarArrayAsPSafeArray(ArrayTicks);
  //...
end;

如果(Ole)Variant不包含数组,则会引发异常。或者,您可以使用VarIsArray()手动对其进行检查:
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : OleVariant);
var
  Data : PVarArray;
  //...
begin
  if not VarIsArray(ArrayTicks) then Exit;
  Data := VarArrayAsPSafeArray(ArrayTicks);
  //...
end;

话虽这么说,(Ole)Variant具有访问PSafeArray元素数据的内置支持,所以您实际上并不需要直接访问PSafeArray(除非您希望获得额外的性能提升,在这种情况下,您需要先验证PSafeArray才能自己使用)访问其数据):
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : Olevariant);
var
  i : Integer;
  value : String;
begin
  if not VarIsArray(ArrayTicks) then Exit;
  for i := VarArrayLowBound(ArrayTicks, 1) to VarArrayHighBound(ArrayTicks, 1) do
  begin
    Value := ArrayTicks[i];
    ShowMessage(Value);
  end;

10-08 04:48